2012-10-07 10 views
16

Ho estratto i fotogrammi da un video utilizzando MetadataRetriever e ho memorizzato tutte le immagini in un ArrayList<Bitmap>. Voglio memorizzarli tutti su una scheda SD (solo a scopo di test).MediaMetadataRetriever.getFrameAtTime() restituisce solo il primo fotogramma

Ma quando estraggo una cartella dall'emulatore e guardo le immagini salvate, tutte le immagini erano solo del primo fotogramma del video.

Questo è quanto ho estrarre i fotogrammi del video:

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

E questo è come io li sto salvando (sto chiamando questo metodo e passando l'ArrayList bitmap):

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

} 

Quando estraggo una cartella per vedere tutti i fotogrammi, tutte le immagini erano del primo fotogramma del video. Qualcuno può spiegarmi cosa sta succedendo?

UPDATE:

ho provato con un altro video. Ho scoperto che non sto ottenendo immagini vuote, ma restituisce sempre solo il primo fotogramma.

MediaMetadataRetriever.getFrameAtTime(long timeUS) restituisce solo il primo frame, ma voglio recuperare tutti i frame. Quali cambiamenti dovrei apportare?

Come si affronta questo?

+0

Avevo provato il codice qui sopra per ottenere i fotogrammi da video, ma per me ripete il primo fotogramma per tutto il resto di cornici. – Manoj

+0

Avevo provato il codice precedente per ottenere i fotogrammi dal video ma per me ripete il primo fotogramma per tutti gli altri fotogrammi. La durata del mio file era 127040 (2: 07sec) qui ho diviso il mio video per 32 fotogrammi in grado di visualizzare tutti i 32 le immagini ma come le stesse immagini avevo provato molto da sistemare ma non uso non so dove va male puoi aiutarmi con il tuo codice completo di successo per ottenere immagini diverse senza l'aiuto di ffmpeg – Manoj

+0

dovrei includere qualcosa in AndroidManifest – Manoj

risposta

33

MediaMetadataRetriever Il metodo getFrameAt impiega in microsecondi (1/1000000 di secondo) invece di millisecondi, quindi nel tuo caso è sempre arrotondato per difetto al primo fotogramma.

+3

hai aggiunto sette 0 anziché 6 @breenger, Micro 10^-6 – Nepster

+5

I SOB dovrebbero averlo documentato. Ogni volta che vediamo il timestamp in 'long', assumiamo che sia in millisecondi. Il documento del metodo dovrebbe aver detto che è diverso. +1 grazie. – learner

+0

Questa dovrebbe essere una risposta. Grazie @breenger! –

-1

Prova questo sul vostro per/ciclo:

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

sto prendendo tempo in microsecondi e em ottenere durata dalla Mediaplayer come:

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


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

mio frame rate è 12 cornice/sec quindi ho diviso 1/12 = 0.083333 e questa è la parte seconda di un frame e quindi converto il mio frame sec in microsecondo in modo che diventi 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

Come posso ottenere il runtime del frame rate? –

+0

Per favore fai un'altra domanda e condividi il link così posso darti una risposta su questo? –

+0

Ora questa è una nuova domanda. questo è il motivo http://stackoverflow.com/questions/42204944/how-to-get-frame-rate-of-video-in-android-os –

7

Basta convertire il vostro millisecondi per micro perché getFrameAt ottenere i dati in millisecondi

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

allora il problema è risolto ..

ho creato secondo le mie necessità.

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

il tuo codice funziona ma come posso modificarlo per ottenere tutti i frame a partire dal primo uno all'ultimo?. Grazie mille –

+0

@DonnieIbiyemi ho creato fotogrammi come questo. Modificalo seguendo le tue necessità. – Nepster

+0

e che dire di OOM! anche nei piccoli video lancia OOM per la lista di array quando si imposta l'incremento a 1000 !!!!! –