2011-03-10 19 views
14

¿Alguien sabe cómo implementar la búsqueda por segundos (o milisegundos) en FFmpeg. Actualmente tengo un bucle corriendo a través de los marcos de un video usando av_read_frame() y quiero determinar a qué hora debería estar este fotograma en segundos. Si llega a cierto punto, entonces quiero buscar un punto posterior en el video. Por cierto, no es un reproductor de video, solo procesa los cuadros. He escuchado que debería poder obtener los puntos o puntos del paquete, pero siempre devuelve 0.Cómo buscar en FFmpeg C/C++

+0

Tenga en cuenta que en un códec que no es "I Chasis única", es posible obtener la basura durante los primeros marcos después de una búsqueda hasta que ffmpeg obtenga suficiente información para darle un cuadro completo. Ha pasado un tiempo desde que lo intenté, pero AFAIK, esto sigue siendo cierto. ffmpeg supone que eres un jugador, y no te importa que algunos fotogramas salgan mal, o que estás procesando directamente y obteniendo todos los fotogramas secuencialmente. Si ese no es el caso, puede encontrarse con problemas en cosas como MPEG4. – wrosecrans

+0

@wrosecrans Muchas gracias por esa información. Encontré algunas rarezas como las que me explicaste y aprendí que tratar de buscar un fotograma clave era el camino a seguir. Si intentas buscar parte del video que no es un fotograma clave, obtienes una salida extraña por un segundo. – DRiFTy

Respuesta

12

NOTA: Esto no está actualizado, todavía debería funcionar pero ahora hay av_seek_frame() para hacerlo oficialmente.

que no he escrito esto, pero aquí está un cierto código de una muestra Tengo

bool seekMs(int tsms) 
{ 
    //printf("**** SEEK TO ms %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d\n",tsms,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk); 

    // Convert time into frame number 
    DesiredFrameNumber = ffmpeg::av_rescale(tsms,pFormatCtx->streams[videoStream]->time_base.den,pFormatCtx->streams[videoStream]->time_base.num); 
    DesiredFrameNumber/=1000; 

    return seekFrame(DesiredFrameNumber); 
} 

bool seekFrame(ffmpeg::int64_t frame) 
{ 

    //printf("**** seekFrame to %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d\n",(int)frame,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk); 

    // Seek if: 
    // - we don't know where we are (Ok=false) 
    // - we know where we are but: 
    // - the desired frame is after the last decoded frame (this could be optimized: if the distance is small, calling decodeSeekFrame may be faster than seeking from the last key frame) 
    // - the desired frame is smaller or equal than the previous to the last decoded frame. Equal because if frame==LastLastFrameNumber we don't want the LastFrame, but the one before->we need to seek there 
    if((LastFrameOk==false) || ((LastFrameOk==true) && (frame<=LastLastFrameNumber || frame>LastFrameNumber))) 
    { 
     //printf("\t avformat_seek_file\n"); 
     if(ffmpeg::avformat_seek_file(pFormatCtx,videoStream,0,frame,frame,AVSEEK_FLAG_FRAME)<0) 
     return false; 

     avcodec_flush_buffers(pCodecCtx); 

     DesiredFrameNumber = frame; 
     LastFrameOk=false; 
    } 
    //printf("\t decodeSeekFrame\n"); 

    return decodeSeekFrame(frame); 

    return true; 
} 
+1

¡Impresionante! ¡Gracias por la respuesta! Creo que esto parece que debería funcionar. Lo probaré tan pronto como vuelva a mi computadora y publicaré mis resultados. No sabía sobre avformat_seek_file, estaba usando av_seek_frame ... ¿sabes cuál es la diferencia por casualidad? – DRiFTy

+0

Lo siento, acabo de hacer el video escribiendo parte del código, ni siquiera he probado el lector. –

+1

El método que publicó Martin Beckett funcionó, y me permitió buscar el video en un marco específico basado en milisegundos. – DRiFTy