2012-10-07 29 views
16

He extraído fotogramas de un video usando MetadataRetriever y he almacenado todas las imágenes en ArrayList<Bitmap>. Quiero almacenarlos todos en una tarjeta SD (solo para fines de prueba).MediaMetadataRetriever.getFrameAtTime() devuelve solo el primer fotograma

Pero cuando saco una carpeta del emulador y miro las imágenes guardadas, todas las imágenes eran solo del primer fotograma del video.

Éste es cómo extraer los cuadros del vídeo:

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

y así es como yo los estoy ahorrando (Voy a llamar a este método y pasar el ArrayList de mapa de bits):

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

} 

Cuando saco una carpeta para ver todos los marcos, todas las imágenes eran del primer cuadro de video. ¿Puede alguien por favor explicarme qué está pasando?

ACTUALIZACIÓN:

he intentado con otro video. Descubrí que no obtengo imágenes en blanco, pero siempre devuelve el primer cuadro solamente.

MediaMetadataRetriever.getFrameAtTime(long timeUS) devuelve solo el primer fotograma, pero quiero recuperar todos los fotogramas. ¿Qué cambios debo hacer?

¿Cómo me ocupo de esto?

+0

Había probado el código anterior para conseguir los fotogramas de vídeo, pero para mí se repite el primer marco para el resto de cuadros. – Manoj

+0

He intentado su código anterior para obtener los cuadros de video pero para mí repite el primer cuadro para el resto de cuadros. Mi duración de archivo fue 127040 (2: 07sec) aquí dividí mi video para 32 fotogramas, puedo ver todos los 32 imágenes, pero como las mismas imágenes que he intentado corregir, pero no sirve, no sé dónde va mal, ¿me pueden ayudar con su código de éxito completo para obtener diferentes imágenes sin la ayuda de ffmpeg – Manoj

+0

si incluyo algo en AndroidManifest – Manoj

Respuesta

33

El método getFrameAt toma en microsegundos (1/1000000th de segundo) en lugar de milisegundos, por lo que en su caso siempre está redondeando al primer fotograma.

+3

ha agregado siete 0 en lugar de 6 @breenger, Micro 10^-6 – Nepster

+5

Los SOB deberían haberlo documentado. Cada vez que vemos la marca de tiempo en 'long' suponemos que es milisegundos. El documento de método debería haber dicho que es diferente. +1 gracias. – learner

+0

Esto debería ser una respuesta. Gracias @breenger! –

-1

Pruebe esto en su a/loop:

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

estoy tomando tiempo en microsegundos y em conseguir la duración del reproductor de medios como:

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


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

Mi velocidad de fotogramas es 12 marco/seg así que dividí 1/12 = 0.083333 y esta es la parte del segundo de un cuadro y que convierto mi marco sec a microsegundo para que se convierta en 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

¿Cómo puedo obtener el tiempo de ejecución de la velocidad de fotogramas? –

+0

Haz otra pregunta y comparte el enlace para que pueda responderte sobre eso. –

+0

Ahora esta es una nueva pregunta. por eso esto. http://stackoverflow.com/questions/42204944/how-to-get-frame-rate-of-video-in-android-os –

7

Sólo convertir sus milisegundos a las micro porque getFrameAt obtener datos en milisegundos

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

entonces su problema se resuelve ..

he creado de acuerdo a mi necesidad.

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

su código funciona, pero ¿cómo puedo modificarlo para obtener todos los marcos comenzando desde el primero uno hasta el último? .Gracias mucho –

+0

@DonnieIbiyemi he creado marcos como este. Modifíquelo según su necesidad. – Nepster

+0

y qué hay de OOM! incluso en videos pequeños arroja OOM para la lista de arreglos cuando se establece el incremento en 1000 !!!!! –

Cuestiones relacionadas