C++ 用FFmpeg寻找mp4容器中h264编解码器的视频帧。数据包pts始终为0

C++ 用FFmpeg寻找mp4容器中h264编解码器的视频帧。数据包pts始终为0,c++,video,ffmpeg,h.264,C++,Video,Ffmpeg,H.264,我试图用FFmpeg搜索到特定帧的最近关键帧,但每当我在搜索后用av_read_frame获得下一帧时,数据包pts或dts始终为0。这仅适用于h264/mp4视频,因为它适用于.avi容器中的某些编解码器 我尝试过使用avformat\u seek\u file和av\u seek\u frame但它们给出了相同的结果 我还读到,我不应该从数据包中读取时间戳,因此我尝试先使用avcodec\u decode\u video2解码数据包,然后读取AVFrame->pts信息,但该值对于h264/

我试图用FFmpeg搜索到特定帧的最近关键帧,但每当我在搜索后用av_read_frame获得下一帧时,数据包pts或dts始终为0。这仅适用于h264/mp4视频,因为它适用于.avi容器中的某些编解码器

我尝试过使用avformat\u seek\u fileav\u seek\u frame但它们给出了相同的结果

我还读到,我不应该从数据包中读取时间戳,因此我尝试先使用avcodec\u decode\u video2解码数据包,然后读取AVFrame->pts信息,但该值对于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 */
/*与标题相关*/
AVCodecContext-pCodecCtx;
AVFormatContext*pFormatCtx;
int视频流索引;
int类::getFrame(int desiredFrame,bool seek)
如果(搜索)
{
/*我们寻找选定的帧*/
如果(avformat_seek_文件(pFormatCtx,videoStreamIndex,0,desiredFrame,desiredFrame,AVSEEK_FLAG_BACKWARD)<0)
//如果(av搜索帧(PFormatCx、mVideoStream、desiredFrame、AVSEEK标志向后)<0)
{
//错误管理
}
avcodec_刷新_缓冲区(PCODECTX);
}
数据包;
int框架完成;
/*循环直到找到下一个视频帧*/
而(av_读取_帧(pFormatCtx和数据包)>=0)
{
if(packet.stream_index==videoStreamIndex)
{
avcodec_decode_video2(pCodecCtx、pFrame、frameFinished和packet);
int pcktPts;
/***使用av\u帧\u获取\u最大努力\u时间戳()管理此处的其他编解码器***/
/*通过这种方法,在多次av_读取_帧循环之后,我得到了正确的pts信息*/
if(pCodecCtx->codec->id==AV\u codec\u id\u H264&&videoPath.toLower().endsWith(“.mp4”))
{
pcktPts=av\u rescale\u q(packet.pts,//pFrame->pts在这里始终无效
pFormatCtx->streams[videoStreamIndex]->时基,
pFormatCtx->流[videoStreamIndex]->编解码器->时基);
pcktPts=(pcktPts/pCodecCtx->ticks\u/帧);
}
如果(pcktPts==desiredFrame)。。。。
/*用于读取、转换帧等的更多无关代码*/
也许我处理这种编解码器的方法不正确,任何想法都将受到高度赞赏


请注意,我只对视频帧感兴趣。

好的,我想我得到了一些东西

似乎avformat\u seek\u file实际上想要查找的是数据包的pts,而不是帧数,因此,由于我使用av\u rescale\u q将数据包pts转换为实际帧数,我想我必须执行相反的操作,将所需的帧数转换为数据包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; 
目前看来,这似乎如预期的那样有效。但我还是会接受任何建议,因为这是我想到的第一个解决方案,可能有点幼稚,我不确定它是否适用于所有情况