2012-10-07 177 views
16

我已經使用MetadataRetriever從視頻中提取了幀,並將所有圖像存儲在ArrayList<Bitmap>中。我想將它們全部存儲在SD卡上(僅用於測試目的)。MediaMetadataRetriever.getFrameAtTime()僅返回第一幀

但是,當我從模擬器中拉出一個文件夾並查看保存的圖像時,所有圖像僅爲視頻的第一幀。

這是我從視頻中提取幀:

File videoFile=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/videos","sample_mpeg4.mp4"); 

Uri videoFileUri=Uri.parse(videoFile.toString()); 

MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 
retriever.setDataSource(videoFile.getAbsolutePath()); 
ArrayList<Bitmap> rev=new ArrayList<Bitmap>(); 

//Create a new Media Player 
MediaPlayer mp = MediaPlayer.create(getBaseContext(), videoFileUri); 

int millis = mp.getDuration(); 
for(int i=0;i<millis;i+=100){ 
    Bitmap bitmap=retriever.getFrameAtTime(i,OPTION_CLOSEST_SYNC); 
    rev.add(bitmap); 
} 

這就是我如何保存它們(我調用這個方法,並把位圖的ArrayList):

public void saveFrames(ArrayList<Bitmap> saveBitmapList) throws IOException{ 
    Random r = new Random(); 
    int folder_id = r.nextInt(1000) + 1; 

    String folder = Environment.getExternalStorageDirectory()+"/videos/frames/"+folder_id+"/"; 
    File saveFolder=new File(folder); 
    if(!saveFolder.exists()){ 
     saveFolder.mkdirs(); 
    } 

    int i=1; 
    for (Bitmap b : saveBitmapList){ 
     ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 
     b.compress(Bitmap.CompressFormat.JPEG, 40, bytes); 

     File f = new File(saveFolder,("frame"+i+".jpg")); 

     f.createNewFile(); 

     FileOutputStream fo = new FileOutputStream(f); 
     fo.write(bytes.toByteArray()); 

      fo.flush(); 
      fo.close(); 

     i++; 
    } 
    Toast.makeText(getApplicationContext(),"Folder id : "+folder_id, Toast.LENGTH_LONG).show(); 

} 

當我拉出一個文件夾來查看所有幀時,所有圖像都是第一幀視頻。有人可以向我解釋發生了什麼事嗎?

UPDATE:

我試圖與另一視頻。我發現我沒有看到空白圖像,但它總是隻返回第一幀。

MediaMetadataRetriever.getFrameAtTime(long timeUS)只返回第一幀,但我想檢索所有幀。我應該做什麼改變?

我該如何解決這個問題?

+0

我試過你上面的代碼包含用於獲取視頻幀,但對我來說,重複所有,其餘的第一幀的幀。 – Manoj

+0

我已經試過你的上述代碼從視頻獲取幀,但對我來說,它重複frames.frame文件的所有其餘的第一幀。我的文件持續時間是127040(2:07秒)在這裏我分裂我的視頻爲32幀可以查看所有32圖像,但作爲相同的圖像我想了很多修復,但沒有用我不知道它出了什麼地方,你可以幫我通過你的成功完整的代碼獲得不同的圖像沒有ffmpeg – Manoj

+0

幫助我應該包括任何東西在AndroidManifest – Manoj

回答

33

MediaMetadataRetrievergetFrameAt方法需要微秒(1/1000000秒)而不是毫秒,所以在你的情況下,它總是舍入到第一幀。

+3

你已經添加了七個0而不是6 @breenger,Micro 10^-6 – Nepster

+5

SOB應該記錄下來。每當我們看到'long'的時間戳時,我們認爲它是毫秒。方法文件應該說它是不同的。 +1謝謝。 – learner

+0

這應該是一個答案。謝謝@breenger! –

-1

試試這個對你的/循環:

Bitmap bitmap = retriever.getFrameAtTime(
    TimeUnit.MICROSECONDS.convert(i, TimeUnit.MILLISECONDS), 
    retriever.OPTION_CLOSEST_SYNC); 
1
long time; 

    String formattedFileCount; 
    FileOutputStream fos; 
    BufferedOutputStream bos; 

    NumberFormat fileCountFormatter = new DecimalFormat("00000"); 
    int fileCount = 0; 
    File jpegFile; 
    ArrayList<Bitmap> bArray = null; 
    Bitmap lastbitmap = null; 
    bArray = new ArrayList<Bitmap>(); 

我花時間在微秒和EM得到持續時間從媒體播放器,如:

time = mp.getDuration()*1000; 
Log.e("Timeeeeeeee", time); 


       bArray.clear(); 
       MediaMetadataRetriever mRetriever = new MediaMetadataRetriever(); 
       mRetriever.setDataSource(path); 
       int j=0; 

我的幀率爲12幀/秒,所以我劃分1/12 = 0.083333,這是一個幀的第二部分,並且我將幀秒轉換爲微秒,因此它變成83333

   for (int i = 833333; i <= time; i=i+83333) { 
        bArray.add(mRetriever.getFrameAtTime(i, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)); 



        formattedFileCount = fileCountFormatter.format(fileCount); 
        lastbitmap = bArray.get(j); 
        j++; 
        // image is the bitmap 
         jpegFile = new File(Environment.getExternalStorageDirectory().getPath() + "/frames/frame_" + formattedFileCount + ".jpg"); 
         fileCount++; 

         try { 
          fos = new FileOutputStream(jpegFile); 
          bos = new BufferedOutputStream(fos); 
          lastbitmap.compress(Bitmap.CompressFormat.JPEG, 15, bos); 

          bos.flush(); 
          bos.close(); 
         } catch (FileNotFoundException e) { 

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

          e.printStackTrace(); 
         } 

       } 

      } catch (Exception e) { 


      } 
+0

我如何獲得幀率運行時間? –

+0

請問另一個問題,並分享我的鏈接,所以我可以給你答案呢? –

+0

現在這是新的問題。 plz答這個。 http://stackoverflow.com/questions/42204944/how-to-get-frame-rate-of-video-in-android-os –

7

只需將您毫秒到微因爲getFrameAt以毫秒爲單位

1 miliseconds have 1000 microseconds.. 


for(int i=1000000;i<millis*1000;i+=1000000){ 
    Bitmap bitmap=retriever.getFrameAtTime(i,OPTION_CLOSEST_SYNC); 
    rev.add(bitmap); 
} 

那麼你的問題就解決了獲取數據..

我根據我的需求創造了它。

public class MainActivity extends Activity 
{ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     File videoFile=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/screenshots/","myvideo.mp4"); 

     Uri videoFileUri=Uri.parse(videoFile.toString()); 

     MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 
     retriever.setDataSource(videoFile.getAbsolutePath()); 
     ArrayList<Bitmap> rev=new ArrayList<Bitmap>(); 

     //Create a new Media Player 
     MediaPlayer mp = MediaPlayer.create(getBaseContext(), videoFileUri); 

     int millis = mp.getDuration(); 

     for(int i=1000000;i<millis*1000;i+=1000000) 
     { 
      Bitmap bitmap=retriever.getFrameAtTime(i,MediaMetadataRetriever.OPTION_CLOSEST_SYNC); 
      rev.add(bitmap); 
     } 
    } 
} 
+0

你的代碼的作品,但我怎麼修改它,以獲得從第一個開始的所有幀一個到最後一個?。謝謝很多 –

+0

@DonnieIbiyemi我已經創建了這樣的框架。根據您的需要修改它。 – Nepster

+0

和OOM有什麼關係!即使在小視頻中,當將增量設置爲1000時,它也會向數組列表拋出OOM! –