2013-07-31 70 views
3

我正在編寫一個Android應用程序,我有一堆5-15秒.mp4文件,我想要剪輯。我一直試圖使用Sebastian Annies'mp4parser來做到這一點,遵循這裏給出的示例代碼:ShortenExample用mp4parser剪下mp4s。無法通過SyncSample修正時間

這裏是我使用的代碼(類似於大量的示例代碼以上):

public static void clip(Sprinkle sprinkle, double start, double end) throws IOException { 
    Movie movie = MovieCreator.build(sprinkle.getLocalVideoPath()); 

    // Save all tracks then remove them from movie 
    List<Track> tracks = movie.getTracks(); 
    movie.setTracks(new LinkedList<Track>()); 

    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) 
       Log.v("clip", "track.getSyncSamples().length: " + track.getSyncSamples().length); 
       throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported."); 
      } 
      Log.v("syncSample", "start before: " + start); 
      Log.v("syncSample", "end before: " + end); 
      start = correctTimeToSyncSample(track, start, false); 
      end = correctTimeToSyncSample(track, end, true); 
      Log.v("syncSample", "start after: " + start); 
      Log.v("syncSample", "end after: " + end); 
      timeCorrected = true; 
     } 
    } 

    for (Track track : tracks) { 
     long currentSample = 0; 
     double currentTime = 0; 
     double lastTime = 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++) { 
       if (currentTime > lastTime && currentTime <= start) { 
        // current sample is still before the new starttime 
        startSample = currentSample; 
       } 
       if (currentTime > lastTime && currentTime <= end) { 
        // current sample is after the new start time and still before the new endtime 
        endSample = currentSample; 
       } 
       lastTime = currentTime; 
       currentTime += (double) entry.getDelta()/(double) track.getTrackMetaData().getTimescale(); 
       currentSample++; 
      } 
     } 
     movie.addTrack(new AppendTrack(new CroppedTrack(track, startSample, endSample))); 
    } 

    long start1 = System.currentTimeMillis(); 
    Container out = new DefaultMp4Builder().build(movie); 
    long start2 = System.currentTimeMillis(); 
    File file = Constants.getEditsDir(); 
    FileOutputStream fos = new FileOutputStream(file.getPath() + String.format("output-%f-%f.mp4", start, end)); 
    FileChannel fc = fos.getChannel(); 
    out.writeContainer(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("output-%f-%f.mp4", start, end)).length()/(start3 - start2)/1000) + "MB/s"); 

} 

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]; 
} 

我似乎無法阻止錯誤「的開始時間已經與SyncSample另一軌道修正沒有。支持的。」從發生。當我記錄正在循環播放的曲目時,getHandler()返回「vide」,「soun」,然後在「提示」時崩潰。如果我評論這一部分了:

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) 
      Log.v("clip", "track.getSyncSamples().length: " + track.getSyncSamples().length); 
      throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported."); 
     } 

那麼程序只是一個索引崩潰了界失誤時,它得到的線

Container out = new DefaultMp4Builder().build(movie); 

我在做什麼錯?

回答

2

使用start值小於剪輯處理達到

Container out = new DefaultMp4Builder().build(movie); 

在我的例子,當你得到一個IndexOutOfBoundsException異常,因爲無論你的startSample或您endSample有一個錯誤值(例如仍-1) 2秒導致if (currentTime > lastTime && currentTime <= start)從未達到真實值,因此startSample未從其初始值-1更新。對此的一個解決方案是將startSample的初始值從-1更改爲0.

1

使用此iso分析器庫。 https://code.google.com/p/mp4parser/downloads/detail?name=isoviewer-1.0-RC-28.jar&can=2&q=

private void doShorten(final int _startTime, final int _endTime) { 

    try { 
     File folder = new File(VideoPath); 
     Movie movie = MovieCreator.build(VideoPath); 
     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(); 
     Container out = new DefaultMp4Builder().build(movie); 
     long start2 = System.currentTimeMillis(); 

     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") 
       .format(new Date()); 
     String filename = "TrimVideo"+System.currentTimeMillis()+".mp4"; 

     RandomAccessFile fc = new RandomAccessFile(
       Environment.getExternalStorageDirectory()+"/myfolder/"+filename, 
       "rw"); 

     FileChannel fc2 = fc.getChannel(); 
     out.writeContainer(fc2); 
     fc2.close(); 


     AddVideoInfo(filename); 




     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"); 

    } catch (FileNotFoundException e) { 

     e.printStackTrace(); 
    } catch (IOException e) { 

     e.printStackTrace(); 

    } 

} 

private void AddVideoInfo(String filename) { 
    // TODO Auto-generated method stub 
    File f = new File(Environment.getExternalStorageDirectory() 
      + "/TotalRecall/"+filename); 

    EvientVideosListActivity.mVideoNamesList.add(f.getAbsolutePath()); 

    Date lastModDate = new Date(f.lastModified()); 
    SimpleDateFormat sdf = new SimpleDateFormat(
      "MMM dd, yyyy hh:mm"); 
    String date = sdf.format(lastModDate); 
    EvientVideosListActivity.mVideoDateList.add(date); 


    Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(
      f.getAbsolutePath(), 
      MediaStore.Video.Thumbnails.MINI_KIND); 

    EvientVideosListActivity.mVideoThumbsList.add(bitmap); 
    Global.mVideoCheckList.add(false); 

} 

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

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]; 
}