2013-03-27 2 views
5

나는 recored 비디오에서 여러 클립을 자르기 위해 mp4parser 라이브러리를 사용하고 있습니다. 비디오에서 한 부분을 자르면 잘 작동합니다. 그러나 비디오에서 여러 클립을 자르려고하면 첫 번째 클립 만 제대로 자릅니다. 기타는 단지 0 또는 1 초입니다. 내 코드는 다음과 같습니다mp4parser 라이브러리를 사용하여 동영상에서 여러 클립 자르기 관련 문제

import android.app.ProgressDialog; 
import android.content.Context; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 
import android.widget.Toast; 

import com.coremedia.iso.IsoFile; 
import com.coremedia.iso.boxes.TimeToSampleBox; 
import com.googlecode.mp4parser.authoring.Movie; 
import com.googlecode.mp4parser.authoring.Track; 
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder; 
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator; 
import com.googlecode.mp4parser.authoring.tracks.CroppedTrack; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.nio.channels.FileChannel; 
import java.text.SimpleDateFormat; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Date; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

import uk.org.humanfocus.hfi.Beans.TrimPoint; 
import uk.org.humanfocus.hfi.Utils.Constants; 
import uk.org.humanfocus.hfi.Utils.SimpleThreadFactory; 
import uk.org.humanfocus.hfi.Utils.Ut; 

/** 
* Shortens/Crops a track 
*/ 
public class ShortenExample { 

    private static final String TAG = "ShortenExample"; 
    private final Context mCxt; 
    private ExecutorService mThreadExecutor = null; 
    private SimpleInvalidationHandler mHandler; 
    private ProgressDialog mProgressDialog; 
    String filePath; 
    ArrayList<TrimPoint> mTrimPoints; 
    int videoLength; 
    ArrayList<String> trimVideos; 
    private class SimpleInvalidationHandler extends Handler { 

     @Override 
     public void handleMessage(final Message msg) { 
      switch (msg.what) { 
      case R.id.shorten: 
       mProgressDialog.dismiss(); 

       if (msg.arg1 == 0) 
        Toast.makeText(mCxt, 
          mCxt.getString(R.string.message_error) + " " + (String) msg.obj, 
          Toast.LENGTH_LONG).show(); 
       else 
        Toast.makeText(mCxt, 
          mCxt.getString(R.string.message_shortened) + " " + (String) msg.obj, 
          Toast.LENGTH_LONG).show(); 
       break; 
      } 
     } 
    } 

    public ShortenExample(Context context) { 
     mCxt = context; 
     mHandler = new SimpleInvalidationHandler(); 
     //mProgressDialog = new ProgressDialog(mCxt); 
     //mProgressDialog.setMessage("Wait Saving.."); 
     //mProgressDialog.setCancelable(false); 
    } 

    public void shorten(String filePath,ArrayList<TrimPoint> trimPoints, int endTime) { 
     trimVideos = new ArrayList<String>(); 
     this.filePath = filePath; 
     this.videoLength = endTime; 
     this.mTrimPoints = trimPoints; 
     Log.d(Constants.TAG,"End Time: "+endTime+" Trim Points: "+mTrimPoints.size()); 
     for (int i=0;i<trimPoints.size();i++){ 
      TrimPoint point = trimPoints.get(i); 
      int start=0; 
      int end = 0; 
      if(point.getTime()-5<0){ 
       start = 0; 
      }else{ 
       start = point.getTime()-5; 
      } 

      if(point.getTime()+5>videoLength){ 
       end = videoLength-1; 
      }else { 
       end = point.getTime() + 5; 
      } 
      Log.d(Constants.TAG,"Clip: "+start+" : "+end); 
      doShorten(start,end); 
     } 
     Log.d(Constants.TAG,"Done: "+trimVideos.size()); 
    } 

    private void doShorten(final int _startTime, final int _endTime) { 
     //mProgressDialog = Ut.ShowWaitDialog(mCxt, 0); 

     //mProgressDialog.show(); 


     if(mThreadExecutor == null) 
      mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("doShorten")); 

     //this.mThreadExecutor.execute(new Runnable() { 
     // public void run() { 
       try { 
        File folder = Ut.getTestMp4ParserVideosDir(mCxt); 
        //File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),"HFVideos"+File.separator+"TEMP"); 
        //Log.d(Constants.TAG, folder.toString()); 
        if (!folder.exists()) { 
         Log.d(TAG, "failed to create directory"); 
        } 

        //Movie movie = new MovieCreator().build(new RandomAccessFile("/home/sannies/suckerpunch-distantplanet_h1080p/suckerpunch-distantplanet_h1080p.mov", "r").getChannel()); 
//     Movie movie = MovieCreator.build(new FileInputStream("/home/sannies/CSI.S13E02.HDTV.x264-LOL.mp4").getChannel()); 
        Movie movie = MovieCreator.build(new FileInputStream(new File(filePath)).getChannel()); 
        //Log.d(Constants.TAG,"Movie: "+movie.toString()); 
        List<Track> tracks = movie.getTracks(); 
        movie.setTracks(new LinkedList<Track>()); 
        // remove all tracks we will create new tracks from the old 

        double startTime = _startTime; 
        double endTime = _endTime;//(double) getDuration(tracks.get(0))/tracks.get(0).getTrackMetaData().getTimescale(); 

        boolean timeCorrected = false; 

        // Here we try to find a track that has sync samples. Since we can only start decoding 
        // at such a sample we SHOULD make sure that the start of the new fragment is exactly 
        // such a frame 
        for (Track track : tracks) { 
         if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { 
          if (timeCorrected) { 
           // This exception here could be a false positive in case we have multiple tracks 
           // with sync samples at exactly the same positions. E.g. a single movie containing 
           // multiple qualities of the same video (Microsoft Smooth Streaming file) 

           throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported."); 
          } 
          startTime = correctTimeToSyncSample(track, startTime, false); 
          endTime = correctTimeToSyncSample(track, endTime, true); 
          timeCorrected = true; 
         } 
        } 

        for (Track track : tracks) { 
         long currentSample = 0; 
         double currentTime = 0; 
         long startSample = -1; 
         long endSample = -1; 

         for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { 
          TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i); 
          for (int j = 0; j < entry.getCount(); j++) { 
           // entry.getDelta() is the amount of time the current sample covers. 

           if (currentTime <= startTime) { 
            // current sample is still before the new starttime 
            startSample = currentSample; 
           } 
           if (currentTime <= endTime) { 
            // current sample is after the new start time and still before the new endtime 
            endSample = currentSample; 
           } else { 
            // current sample is after the end of the cropped video 
            break; 
           } 
           currentTime += (double) entry.getDelta()/(double) track.getTrackMetaData().getTimescale(); 
           currentSample++; 
          } 
         } 
         movie.addTrack(new CroppedTrack(track, startSample, endSample)); 
        } 
        long start1 = System.currentTimeMillis(); 
        IsoFile out = new DefaultMp4Builder().build(movie); 
        long start2 = System.currentTimeMillis(); 

//     FileOutputStream fos = new FileOutputStream(String.format("output-%f-%f.mp4", startTime, endTime)); 
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
        String filename = folder.getPath() + File.separator + String.format("TMP4_APP_OUT-%f-%f", startTime, endTime) + "_" + timeStamp + ".mp4"; 
        trimVideos.add(filename); 
        FileOutputStream fos = new FileOutputStream(filename); 

        FileChannel fc = fos.getChannel(); 
        out.getBox(fc); 
        fc.close(); 
        fos.close(); 
        long start3 = System.currentTimeMillis(); 
        System.err.println("Building IsoFile took : " + (start2 - start1) + "ms"); 
        System.err.println("Writing IsoFile took : " + (start3 - start2) + "ms"); 
        System.err.println("Writing IsoFile speed : " + (new File(String.format("TMP4_APP_OUT-%f-%f", startTime, endTime)).length()/(start3 - start2)/1000) + "MB/s"); 

        Message.obtain(mHandler, R.id.shorten, 1, 0, filename).sendToTarget(); 
       } catch (FileNotFoundException e) { 
        Message.obtain(mHandler, R.id.shorten, 0, 0, e.getMessage()).sendToTarget(); 
        e.printStackTrace(); 
       } catch (IOException e) { 
        Message.obtain(mHandler, R.id.shorten, 0, 0, e.getMessage()).sendToTarget(); 
        e.printStackTrace(); 
       } 
       //mProgressDialog.dismiss(); 
     // } 
     //}); 

    } 

    protected static long getDuration(Track track) { 
     long duration = 0; 
     for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) { 
      duration += entry.getCount() * entry.getDelta(); 
     } 
     return duration; 
    } 

    private static double correctTimeToSyncSample(Track track, double cutHere, boolean next) { 
     double[] timeOfSyncSamples = new double[track.getSyncSamples().length]; 
     long currentSample = 0; 
     double currentTime = 0; 
     for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { 
      TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i); 
      for (int j = 0; j < entry.getCount(); j++) { 
       if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) { 
        // samples always start with 1 but we start with zero therefore +1 
        timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime; 
       } 
       currentTime += (double) entry.getDelta()/(double) track.getTrackMetaData().getTimescale(); 
       currentSample++; 
      } 
     } 
     double previous = 0; 
     for (double timeOfSyncSample : timeOfSyncSamples) { 
      if (timeOfSyncSample > cutHere) { 
       if (next) { 
        return timeOfSyncSample; 
       } else { 
        return previous; 
       } 
      } 
      previous = timeOfSyncSample; 
     } 
     return timeOfSyncSamples[timeOfSyncSamples.length - 1]; 
    } 


} 
+0

사용한 mp4parser의 버전 번호는 무엇입니까? http://mvnrepository.com/artifact/com.googlecode.mp4parser/isoparser/1.1.18 현재 사용 가능한 최신 버전입니다. 그러나 클래스 'ShortenExample'에 몇 가지 메소드가 포함되어 있지 않습니다. –

답변

3

에만 문제가 에뮬레이터에 있었다. 에뮬레이터에 비디오를 녹화하면 실제 시간보다 적은 초를 기록합니다. 실제 장치에서 작동하는 코드입니다.

0

알아두기, 시간 단위로 나누어야합니다. 엔트리 (또는 샘플) 카운트는 오디오와 비디오 트랙이 같은 기간 동안 다양하다는 것을 알았습니다. 하지만 나는 완전히 멍청한 행동이다. 내 말을 듣지 마라.

protected static double getDuration(Track track) { 
    double duration = 0; 
    for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) { 
     duration += entry.getCount() * entry.getDelta()/(double) track.getTrackMetaData().getTimescale(); 
    } 
    return duration; 
}