2011-03-10 8 views
14

Arama, FFmpeg'de saniyeler (veya milisaniye) cinsinden arama yapmayı bilen var mı? Şu anda av_read_frame() kullanarak bir videonun kareleri boyunca çalışan bir döngü var ve bu çerçevenin saniye cinsinden kaçta olması gerektiğini belirlemek istiyorum. Belirli bir noktaya gelirse, o zaman videoda daha sonraki bir noktaya bakmak istiyorum. Bu arada bir video oynatıcı değil, sadece çerçeveleri işliyor. Ive, paketten dts veya pts alabilmem gerektiğini duymuştum ama her zaman geri dönüyor. 0FFmpeg'de nasıl arama yapılır C/C++

+0

olmayan bir codec unutmayın sahip bir örnekten bazı kodudur "Ben sadece Çerçeve," Eğer ilk birkaç için çöp alabilirsiniz Ffmpeg tam bir çerçeve vermek için yeterli bilgi alır kadar arama sonra çerçeveler. Denediğimden beri bir süre geçti, ama AFAIK, bu hala geçerli. ffmpeg, bir oyuncu olduğunuzu varsayar ve birkaç karenin yanlış gitmesini umursamıyor ya da düz bir şekilde işliyor ve tüm çerçeveleri sırayla alıyorsunuz. Bu durumda değilse, MPEG4 gibi konularda sorun yaşayabilirsiniz. – wrosecrans

+0

@wrosecrans Bu bilgi için çok teşekkürler. Açıkladığın gibi bir tuhaflıkla karşılaştım ve anahtar bir çerçeveyi aramaya çalışmanın yolunun gitmesi olduğunu öğrendim. Videonun bir bölümünü anahtar karesi olmayan bir parçası aramaya çalışırsanız, bir saniyeliğine biraz garip bir çıktı elde edersiniz. – DRiFTy

cevap

12

NOT: Bu, güncel değil, hala çalışıyor olmalı ama şimdi av_seek_frame() var.

Burada bunu yazmak ama vermedi ben

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

Harika! Cevap için teşekkürler! Sanırım işe yarayacak gibi görünüyor. Bilgisayarıma dönüp sonuçlarımı geri yükler göndermez deneyeceğim. Avformat_seek_file hakkında bilgi sahibi değildim, av_seek_frame kullanıyordum ... Farkın herhangi bir ihtimalden ne olduğunu biliyor musun? – DRiFTy

+0

Üzgünüm - Sadece videonun kodunu yazarak yaptım, okuyucuyu bile test etmedim. –

+1

Martin Beckett'in yayınladığı yöntem işe yaradı ve videoda milisaniye bazında belirli bir kareye doğru ilerlememi sağladı. – DRiFTy