2012-08-03 13 views

Respuesta

5

Creo que la respuesta correcta es http://code.google.com/p/mp4parser/

La API isoparser puede leer y escribir la estructura de archivos MP4. Es una herramienta de bajo nivel que se ocupa de los denominados recuadros, pero también trata con estructuras como pistas y películas.

Niza activos y de maneras mucho más rápido que ffmpeg gigante

+0

sí, pero isoparser no contiene decodificador/codificador para crear mapas de bits a partir de la sección mdat de las cajas – Nativ

9

Para una solución elegante, parece como si tuviera que usar ffmpeg para Android para lograr esto. Alguien más lo intentó de esta manera: How to get the frame from video file in android; y se sugirió usar ffmpeg.

he comprobado el manual de referencia, pero sólo pudo encontrar una manera de conseguir un fotograma clave en sí (sin marca de tiempo) en relación con una posición determinada en el tiempo mediante el MediaMetadataRetriever(), como se explica aquí: http://developer.android.com/reference/android/media/MediaMetadataRetriever.html#extractMetadata%28int%29

si no' t desea utilizar ffmpeg puede probar lo siguiente:

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

Esto por supuesto no es muy elegante, pero probablemente funcionaría sin problemas para instalar ffmpeg ... es probablemente también bastante lento (no sé) . Pero tal vez es justo lo que necesitas.

PD: Un tutorial ffmpeg que se adapte a su problema se puede encontrar aquí: http://dranger.com/ffmpeg/tutorial07.html

+1

Hola Stefan, gracias por sus esfuerzos, pero ya han probado esta solución y funciona maldita lento y ofrece resultados extraños. Investigaré más a fondo (por ejemplo, ffmpeg/ffprobe) y mantendré este hilo actualizado. –

+0

Eso es lo que esperaba. Una idea para acelerar esto es intentar 'time + = lastdistance;' Donde use set 'lastdistance = lastFrameTime - time;' si se encuentra un fotograma clave, verifique si 'lastFrameTime + lastdistance - 1' sigue siendo el último fotograma. Si es así, continúe ... else use la "búsqueda lenta" para encontrar el siguiente fotograma – SDwarfs

+1

compilación cruzada ffmpeg en android. use el comando ffprobe con la opción -show_frames para obtener la lista de I imágenes. Esto debería funcionar para todo tipo de videos y es bastante rápido. Compruébalo en la PC primero. [Si ha instalado ffmpeg, también debería tener ffprobe]. Obtendrás toda la información que necesitas. Hay -show_packets que es aún más rápido y puede ser suficiente si todo lo que quiere saber es referencia vs marcos de referencia. – av501

0

4.1+ - más rápido que mp4parser porque hace en nativa debajo y el código es más limpio

mp4parser tienes que calcular las marcas de tiempo de los getsyncsamples + getsampledurations que también es molesto y no coinciden con ffprobe. esto da resultados precisos

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

gracias por su respuesta, lo comprobaría tan pronto como regrese a este proyecto –

0

Usando MediaExtractor, puede hacer que toda la llave (sincronización) marcos de tiempos y/o cualquier fotograma clave específica en cualquier momento deseado. + algunos datos más útiles.

Luego, mediante MediaMetadataRetriever -> getFrameAtTime puede obtener marcos Bitmaps.

aquí es un código de ejemplo para utilizar 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 ; 
Cuestiones relacionadas