2012-08-03 64 views

回答

5

我認爲正確的答案是http://code.google.com/p/mp4parser/

的isoparser API可以讀取和寫入的MP4文件結構。它是一個處理所謂盒子的低級別工具,但它可以處理音軌和電影之類的結構。

尼斯API和方法比ffmpeg的龐然大物快得多

+0

是的,但isoparser不包含解碼器/編碼器來創建位圖的盒子的mdat節 – Nativ 2013-11-12 09:47:05

9

對於一個優雅的解決方案,看起來好像你需要使用ffmpeg for android來實現這一點。其他人試過這種方式:How to get the frame from video file in android;並被建議使用ffmpeg。

我檢查了參考手冊,但只能使用MediaMetadataRetriever()找到一種方式來獲得一個關鍵幀本身(不包括時間戳)相對於給定位置在時間解釋這裏:http://developer.android.com/reference/android/media/MediaMetadataRetriever.html#extractMetadata%28int%29

如果你不」不想使用的ffmpeg,你可以嘗試以下方法:

private ArrayList<int> getKeyFrameTimestamps(String filename) { 
    ArrayList<int> timeStamps = new ArrayList<int>(); 

    try { 
    MediaMetadataRetriever mRetriever = new MediaMetadataRetriever(); 
    mRetriever.setDataSource(getDataSource(filename)); 
    mRetriever.getFrameAtTime(i, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); 

    Bitmap lastFame = mRetriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_NEXT_SYNC); 
    result.add(0); 

    for(int time=1; frame ; ++time) { 
     Bitmap frame = mRetriever.getFrameAtTime(time, MediaMetadataRetriever.OPTION_PREVIOUS_SYNC); 
     if (frame && !frame.sameAs(lastFrame)) { 
     result.add(time); 
     lastFrame = frame; 
     } 
    } 
    } catch (Exception e) { /* TODO: HANDLE THIS */ } 

    return timeStamps; 
} 

當然,這是不是很優雅,但可能會毫不費力的工作,安裝的ffmpeg ...這可能也相當慢(我不知道) 。但也許這正是你需要的。

PS:適合你的問題的ffmpeg的教程可以在這裏找到:http://dranger.com/ffmpeg/tutorial07.html

+1

斯特凡您好,感謝你的努力,但我已經嘗試過這種解決方案,它的工作原理該死的慢,並提供奇怪的結果。我將進一步調查(例如ffmpeg/ffprobe)並保持此線程更新。 – 2012-08-17 08:51:49

+0

這就是我所期望的。一個想法加快一點就是嘗試'time + = lastdistance;'在哪裏使用set lastdistance = lastFrameTime - time;如果找到關鍵幀,檢查'lastFrameTime + lastdistance - 1'是否仍然是最後一幀。如果是這樣,繼續...否則使用「慢搜索」找到下一幀 – SDwarfs 2012-08-17 09:03:48

+1

交叉編譯ffmpeg到android上。使用ffprobe命令和-show_frames選項來獲取I圖片列表。這應該適用於所有類型的視頻,並且速度非常快。首先在PC上檢查它。 [如果你已經安裝了ffmpeg,你應該也有ffprobe]。你會得到你需要的所有信息。如果你想知道的是參考與非參考幀,則有-show_packets更快,並且可以證明是足夠的。 – av501 2012-08-20 10:39:23

0

4.1+ - 因爲在本地下做得比mp4parser更快,代碼更乾淨

mp4parser你算算從getsyncsamples時間戳+ getsampledurations這也是煩人的,他們不匹配ffprobe。這得到準確的結果

MediaExtractor extractor = new MediaExtractor(); 
extractor.setDataSource(getVideoPath()); 

int trackindex = MediaExtractorUtil.selectVideoTrack(extractor); 
extractor.selectTrack(trackindex); 

while (extractor.getSampleTime() != -1) { 
    long sampleTime = extractor.getSampleTime(); 

    // check not really necessary but JIC 
    if ((extractor.getSampleFlags() & MediaExtractor.SAMPLE_FLAG_SYNC) > 0) { 
     mKeyframeTimestampsMS.add(sampleTime/1000); 
    } 

    extractor.seekTo(sampleTime + 1, MediaExtractor.SEEK_TO_NEXT_SYNC); 
} 
+0

感謝您的回覆,我會檢查一旦我回到這個項目 – 2015-04-14 14:04:16

0

使用MediaExtractor,你可以擁有所有關鍵(同步)在任何需要的時間框架時間和/或任何特定的關鍵幀。 +一些更有用的數據。

然後通過MediaMetadataRetriever - > getFrameAtTime你可以獲得幀位圖。

這裏是一個示例代碼使用MediaExtractor:

mediaExtractor = new MediaExtractor() ; 
    mediaExtractor.setDataSource(mediaPath); 
    int numTracks = mediaExtractor.getTrackCount(); 
    for (int i = 0; i < numTracks; ++i) { 
     MediaFormat format = mediaExtractor.getTrackFormat(i); 
     String mime = format.getString(MediaFormat.KEY_MIME); 
     if (mime.startsWith("video")) { 
      mediaExtractor.selectTrack(i); 
     } 
     Log.i("LOG_Extractor" , "track "+i+" "+mime); 
    } 

    currentTime = mediaPlayer.getCurrentPosition(); 
    mediaExtractor.seekTo((long)currentTime*1000 , MediaExtractor.SEEK_TO_PREVIOUS_SYNC); 
    previousKeyFrameTimeMilis = mediaExtractor.getSampleTime() /1000 ;