2015-04-28 2 views
2

Я пытаюсь обратиться к ближайшему ключевому кадру конкретного кадра с FFmpeg, но всякий раз, когда я получаю следующий кадр с av_read_frame после ищу пакетный PTS или DTS всегда только 0. происходит с видео h264/mp4, так как он корректно работает для некоторых кодеков в контейнере .avi.Ищет видеокадр кодека h264 в контейнере mp4 с FFmpeg. Пакетные PTS всегда 0

Я попытался с помощью avformat_seek_file и av_seek_frame, но они дают мне один и тот же результат.

Я также читал, что я не должен читать метки из пакета, поэтому я попытался декодированием пакета первого с avcodec_decode_video2 и чтением AVFrame-> Очками информации, но это значение всегда недействительно для h264/mp4 видео.

Это соответствующий код, что я пытаюсь сделать:

/*Relevant from header*/ 
AVCodecContext pCodecCtx; 
AVFormatContext *pFormatCtx; 
int videoStreamIndex; 

int Class::getFrame(int desiredFrame, bool seek) 
if(seek) 
{ 
    /* We seek to the selected frame */ 
    if(avformat_seek_file(pFormatCtx, videoStreamIndex, 0, desiredFrame, desiredFrame, AVSEEK_FLAG_BACKWARD) < 0) 
    //if(av_seek_frame(pFormatCtx, mVideoStream, desiredFrame, AVSEEK_FLAG_BACKWARD) < 0) 
    { 
    // error management 
    } 
    avcodec_flush_buffers(pCodecCtx); 
} 

AVPacket packet; 
int frameFinished; 
/* Loop until we find the next video frame */ 
while(av_read_frame(pFormatCtx, &packet) >= 0) 
{ 
    if(packet.stream_index == videoStreamIndex) 
    { 
     avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 
     int pcktPts; 

     /*** management of other codecs here using av_frame_get_best_effort_timestamp() ***/ 


     /* With this approach I have been getting correct pts info after many av_read_frame loops */ 
     if(pCodecCtx->codec->id == AV_CODEC_ID_H264 && videoPath.toLower().endsWith(".mp4")) 
     { 
      pcktPts = av_rescale_q(packet.pts, //pFrame->pts always invalid here 
             pFormatCtx->streams[videoStreamIndex]->time_base, 
             pFormatCtx->streams[videoStreamIndex]->codec->time_base); 
      pcktPts = (pcktPts/pCodecCtx->ticks_per_frame); 
     } 

     if(pcktPts == desiredFrame) .... 
     /* more irrelevant code for reading, converting frame, etc */ 

Возможно, я имею дело с таким родом кодек некорректен, любая идея будет высоко оценен.

В качестве примечания, меня интересуют только видеокадры.

ответ

2

Хорошо, я думаю, что у меня что-то есть.

Похоже avformat_seek_file действительно хочет, МВП пакета, который вы хотите, чтобы стремиться, а не количество кадра, так что с тех пор я использую av_rescale_q для преобразования пакетов PTS к фактическому номеру кадра Я предположил, что должен был выполнить противоположную операцию, чтобы преобразовать нужный номер кадра в пакетные точки.

Теперь, прежде чем искать, я преобразовать нужный номер кадра, как это:

int target = desiredFrame * 
      (pFormatCtx->streams[videoStreamIndex]->time_base.den/
       pFormatCtx->streams[videoStreamIndex]->time_base.num)/
      (pFormatCtx->streams[videoStreamIndex]->codec->time_base.den/
       pFormatCtx->streams[videoStreamIndex]->codec->time_base.num)* 
       pCodecCtx->ticks_per_frame; 

И теперь, кажется, работает, как ожидалось. Тем не менее, я хотел бы принять любые предложения, поскольку это первое решение, о котором я думал, и может быть немного наивным, и я не уверен, что он будет работать для всех случаев.

+0

Не могли бы вы заглянуть в https://stackoverflow.com/questions/48055979/mux-audio-and-video-ffmpeg-c – Valgrind1691

Смежные вопросы