FFMPEG - avcodec_decode_video2返回“无效的帧维度0x0”

时间:2013-11-18 13:09:27

标签: ffmpeg video-streaming

我正在尝试使用ffmpeg / doc / example / decoding__encoding_8c-source.html在ANDROID上构建一个简单的FFMPEG MPEG2视频PES解码器。

我正在使用FFMPEG版本2.0!

我使用以下代码初始化ffmpeg系统:

int VideoPlayer::_setupFFmpeg()
{
    int rc;
    AVCodec *codec;

    av_register_all();
    codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
    if(NULL == codec){
        LOGE("_setupFFmpeg. No codec!");
        return -1;
    }
    LOGI("found: %p. name: %s", codec, codec->name);

    _video_dec_ctx = avcodec_alloc_context3(codec);
    if(NULL == _video_dec_ctx){
        LOGE("_setupFFmpeg. Could not allocate codec context space!");
        return -1;
    }
    _video_dec_ctx->debug = FF_DEBUG_PICT_INFO;
    if(codec->capabilities & CODEC_CAP_TRUNCATED) _video_dec_ctx->flags |= CODEC_FLAG_TRUNCATED;

    rc = avcodec_open2(_video_dec_ctx, codec, NULL);
    if(rc < 0) {
        LOGE("_setupFFmpeg. Could not open the codec: %s!", _video_dec_ctx->codec->name);
        return -1;
    }

    av_init_packet(&_avpkt);

    if(NULL == _video_frame) _video_frame = avcodec_alloc_frame();
    if(NULL == _video_frame){
        LOGE("_setupFFmpeg. Could not allocate memory for the video frame!");
        return -1;
    }

    LOGI("_setupFFmpeg(exit)");
    return 0;
}

然后只有一个循环在解码器上不断发送PES数据包调用此函数:

int VideoPlayer::_playVideoPacket(PesPacket *packet)
{
    int len, frameReady;
    _avpkt.data = packet->buf;
    _avpkt.size = packet->info.bufferSize;
    while(_avpkt.size){
        len = avcodec_decode_video2(_video_dec_ctx, _video_frame, &frameReady, &_avpkt);
        if(len < 0){
            LOGE("FFW_decodeVideo");
            return len;
        }
        if(frameReady){
            //Draw the picture...
        }
        _avpkt.size -= len;
        _avpkt.data += len;
    }
    return 1;
}

但是当我运行代码时,我得到: 调用avcodec_decode_video2()后,FFMPEG出现“无效的帧维度0x0”错误。

似乎我没有正确设置编解码器。 mpeg12dec.c中Mpeg1Context中的MpegEncContext未正确设置。如何正确设置MpegEncContext?

2 个答案:

答案 0 :(得分:0)

根据您的变量名称判断,您将pes数据包传递给decode_video。这是错的。您必须传入原始ES数据包(无pes标头)最简单的方法是使用avformat和av_read_frame()为您填充AVPacket。如果您使用自己的格式分离器,则必须进入Raw ES层。您可能还需要设置PTS DTS值。

注意:我不太了解mpeg2,但是有些codecas还要求你在编解码器上下文中配置extradata值。

答案 1 :(得分:0)

独立示例

刚刚创建了一个独立的代码片段,我们在本地使用它来包装libav以进行视频解码(有一些新的hwacceleration部分有错误/在测试中,随时可以将这些东西拉出来)

以下是包装类标题的示例:

class SchneiderVideoAV {
public:
    SchneiderVideoAV();
    SchneiderVideoAV(const string &fileName);

    ~SchneiderVideoAV();
    void cleanUp();

    int initialize(const string &fileName);
    // loads cube from framestart->end, defaults -1,-1 load entire video into cube
    int loadCube(CSCubeBGRA *pCube, int frameStart=-1, int frameEnd=-1);
    int loadFrame(CSFrameBGRA *pFrame, int frameIndex);

    AVFormatContext    *m_pFormatCtx;
    AVCodecContext     *m_pCodecCtx;
    AVCodec            *m_pCodec;
    AVFrame            *m_pFrame; 
    AVFrame            *m_pFrameBGRA;
    int                 m_numBytes;
    uint8_t            *m_pBuffer;
    int                 m_VideoStream;
    int64_t             m_TimeBase;


    AVDictionary       *m_pOptionsDict;
    struct SwsContext  *m_pSWSCtx;
    string              m_FileName;
    int                 m_Width;
    int                 m_Height;
    int                 m_MaxFrames;
    int                 m_Good;
    float               m_FPS;
    double              m_StartTime;
    double              m_RotationDegrees;
};

和实施:

SchneiderVideoAV::SchneiderVideoAV()
{
    m_Good          = 0;

    m_pFormatCtx    = NULL;
    m_pCodecCtx     = NULL;
    m_pCodec        = NULL;
    m_pFrame        = NULL; 
    m_pFrameBGRA    = NULL;
    m_pBuffer       = NULL;
    m_pOptionsDict  = NULL;
    m_pSWSCtx       = NULL;
    m_VideoStream   = -1;

    m_Width = m_Height = m_MaxFrames = m_numBytes = 0;
}


SchneiderVideoAV::SchneiderVideoAV(const string &fileName)
{
    initialize(fileName);
}


SchneiderVideoAV::~SchneiderVideoAV()
{
    cleanUp();
}

void SchneiderVideoAV::cleanUp()
{
    // Register all formats and codecs
    av_register_all();     

    // Free the RGB image
    if (m_pBuffer) av_free(m_pBuffer);
    if (m_pFrameBGRA) av_free(m_pFrameBGRA);

    // Free the YUV? frame
    if (m_pFrame) av_free(m_pFrame);

    // Close the codec
    if (m_pCodecCtx) avcodec_close(m_pCodecCtx);

    // Close the video file
    if (m_pFormatCtx) avformat_close_input(&m_pFormatCtx);

    // free dictionary
    if (m_pOptionsDict) av_dict_free(&m_pOptionsDict);

    m_pBuffer       = NULL;
    m_pFrameBGRA    = NULL;
    m_pFrame        = NULL; 
    m_pCodecCtx     = NULL;
    m_pFormatCtx    = NULL;
    m_pOptionsDict  = NULL;

    m_Width = m_Height = m_MaxFrames = m_numBytes = 0;    

}

int SchneiderVideoAV::initialize(const string &fileName)
{
    LogStream mout(LOG_DEBUG,"SchneiderVideoAV.initialize.ccode");

    m_FileName          = fileName;
    m_Good              = 1;

    m_pFormatCtx        = NULL;
    m_pCodecCtx         = NULL;
    m_pCodec            = NULL;
    m_pFrame            = NULL; 
    m_pFrameBGRA        = NULL;
    m_pBuffer           = NULL;
    m_pOptionsDict      = NULL;
    m_pSWSCtx           = NULL;
    m_VideoStream       = -1;
    m_RotationDegrees   = 0.0;

    m_Width = m_Height = m_MaxFrames = m_numBytes = 0;


    // Register all formats and codecs
    av_register_all();

    // Open video file
    if(avformat_open_input(&m_pFormatCtx, m_FileName.c_str(), NULL, NULL)!=0) {
        m_Good = 0;
        return VID_PROCESS_FAIL; // Couldn't open file
    }

    // Retrieve stream information
    if(avformat_find_stream_info(m_pFormatCtx, NULL)<0) {
        m_Good = 0;
        return VID_PROCESS_FAIL; // Couldn't find stream information
    }

    // Dump information about file onto standard error
    int64_t durationInt = m_pFormatCtx->duration;
    double durationSeconds = (double)durationInt / AV_TIME_BASE;

    // av_dump_format(m_pFormatCtx, 0, m_FileName.c_str(), 0);

    int i = 0;

    // Find the first video stream
    for(i=0; i< (int) m_pFormatCtx->nb_streams; i++) {
        // cout << "checking streams for video " << m_pFormatCtx->streams[i]->codec->codec_type;
        // cout << " av media type " << AVMEDIA_TYPE_VIDEO << endl;
        if(m_pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
            if (m_VideoStream == -1) {
                m_VideoStream=i;
                // av_dump_format(m_pFormatCtx, 0, m_FileName.c_str(), 0);
                AVDictionaryEntry *pDictEntry = av_dict_get(m_pFormatCtx->streams[i]->metadata, "rotate", NULL, 0);
                if (pDictEntry) m_RotationDegrees = atof(pDictEntry->value);
                // cout << "Dict_entry for rotate from metatdata in stream " << pDictEntry->value << " rotation degrees " << m_RotationDegrees << endl;
            }
            if (VERBOSE_LOGGING) mout << "found a video stream " << i << LogStream::endl;
            // break;
        }
    }
    if(m_VideoStream==-1) {
        m_Good = 0;
        return VID_PROCESS_FAIL; // Didn't find a video stream
    }

    // Get a pointer to the codec context for the video stream
    m_pCodecCtx=m_pFormatCtx->streams[m_VideoStream]->codec;
    m_FPS = av_q2d(m_pFormatCtx->streams[m_VideoStream]->avg_frame_rate);
    // cout << "duration seconds " << durationSeconds << " frame # ";

    int frameCount = 0;
    if (m_pFormatCtx->streams[m_VideoStream]->nb_frames > 0) {
        frameCount = m_pFormatCtx->streams[m_VideoStream]->nb_frames;
    }
    else {
        frameCount = floor(durationSeconds * m_FPS);
    } 
    // cout << "frameCount " << frameCount << endl;

    m_TimeBase = (int64_t(m_pCodecCtx->time_base.num) * AV_TIME_BASE) / int64_t(m_pCodecCtx->time_base.den);

    m_Width     = m_pCodecCtx->width;
    m_Height    = m_pCodecCtx->height;
    m_MaxFrames = frameCount;

    // cout << " avg fps " << m_FPS << endl;

    // Find the decoder for the video stream
    AVPixelFormat usedPixelFormat;
    if (m_pCodecCtx->codec_id == CODEC_ID_H264) {
        m_pCodec=avcodec_find_decoder_by_name("h264_vda");
        usedPixelFormat = AV_PIX_FMT_VDA;
        m_pCodecCtx->pix_fmt = usedPixelFormat;
    }
    else {
        m_pCodec=avcodec_find_decoder(m_pCodecCtx->codec_id);
        usedPixelFormat = m_pCodecCtx->pix_fmt;
    }

    // ignore this if you are not messing with hwaccel decoding
    cout << "about to call ff_find_hwaccel codec, id, pix_fmt name, value " << m_pCodec->name << "," << m_pCodecCtx->codec_id;
    cout << "," << pixFmt2String(usedPixelFormat) << "," << usedPixelFormat << endl;
    m_pCodecCtx->hwaccel = ff_find_hwaccel(m_pCodecCtx->codec_id,usedPixelFormat);

    if(m_pCodec==NULL) {
        mout.setLog(LOG_ERR);
        mout << "SchneiderVideoAV::initialize Unsupported codec!" << LogStream::endl;
        mout.setLog(LOG_DEBUG);
        m_Good = 0;
        return VID_PROCESS_FAIL; // Codec not found
    }


    // Open codec
    if(avcodec_open2(m_pCodecCtx, m_pCodec, &m_pOptionsDict)<0) {
        mout.setLog(LOG_ERR);
        mout << "SchneiderVideoAV::initialize Unable to open codec" << LogStream::endl;
        mout.setLog(LOG_DEBUG);
        m_Good = 0;        
        return VID_PROCESS_FAIL; // Could not open codec
    }

    // Allocate video frame
    m_pFrame=av_frame_alloc();

    // Allocate an AVFrame structure
    m_pFrameBGRA=av_frame_alloc();
    if(m_pFrameBGRA==NULL) {
        m_Good = 0;        
        return VID_PROCESS_FAIL;
    }


    // Determine required buffer size and allocate buffer
    m_numBytes=avpicture_get_size(PIX_FMT_BGRA, m_pCodecCtx->width,
                                    m_pCodecCtx->height);

    m_pBuffer=(uint8_t *)av_malloc(m_numBytes*sizeof(uint8_t));


    if (VERBOSE_LOGGING) mout << "ZOMG right before m_pSWSCtx, and sws_getContext m_pCodecCtx width, height, FrameCount " << m_pCodecCtx->width << " , " << m_pCodecCtx->height << " pix_fmt " << m_pCodecCtx->pix_fmt << LogStream::endl;
    if (m_pCodecCtx->hwaccel == NULL) {
        m_pSWSCtx = sws_getContext
            (
                m_pCodecCtx->width,
                m_pCodecCtx->height,
                m_pCodecCtx->pix_fmt,
                // usedPixelFormat,
                m_pCodecCtx->width,
                m_pCodecCtx->height,
                PIX_FMT_BGRA,
                SWS_BILINEAR,
                NULL,
                NULL,
                NULL
            );
    }

    // cout << "m_pCodecCtx width,height pix_fmt " << m_pCodecCtx->width;
    // cout << "," << m_pCodecCtx->height << " pix_fmt " << m_pCodecCtx->pix_fmt;
    // cout << " PIX_FMT_BGRA " << PIX_FMT_BGRA << endl; 


    VIDEO_IO_MUTEX.unlock();

    return VID_PROCESS_OK;
}

int SchneiderVideoAV::loadCube(CSCubeBGRA *pCube, int frameStart, int frameEnd)
{
    // cout << "SchneiderVideoAV::loadCube frameStart,frameEnd " << frameStart << "," << frameEnd << endl;

    cleanUp();
    initialize(m_FileName);

    LogStream mout(LOG_DEBUG,"SchneiderVideoAV.loadCube.ccode");
    if (m_Good) {
        // cout << "max frames " << m_MaxFrames << endl;
        if (frameEnd >= m_MaxFrames) frameEnd = m_MaxFrames - 1;
        if (frameEnd < 0) frameEnd = m_MaxFrames - 1;
        if (frameStart > frameEnd) frameStart = frameEnd;
        if (frameStart < 0) frameStart = 0;
        int frameCount = frameEnd - frameStart + 1;

        // cout << "SchneiderVideoAV::loadCube width,height,frameCount " << m_Width << "," << m_Height << "," << frameCount << endl;
        pCube->Set(m_Width,m_Height,frameCount,m_FPS);

        // Assign appropriate parts of buffer to image planes in m_pFrameRGB
        // Note that m_pFrameRGB is an AVFrame, but AVFrame is a superset
        // of AVPicture
        avpicture_fill((AVPicture *)m_pFrameBGRA, m_pBuffer, PIX_FMT_BGRA,
                     m_pCodecCtx->width, m_pCodecCtx->height);

        // couldn't get seek to work, need to keep track of key/iFrames and read up to desired frame
        // if (frameStart > 0) {
        //     int64_t seekTarget = int64_t(frameStart) * m_TimeBase;

        //     if(av_seek_frame(m_pFormatCtx, -1, seekTarget, AVSEEK_FLAG_ANY) < 0) {
        //         mout << "averror av_seek_frame failed for file " << m_FileName.c_str() << LogStream::endl;            
        //         return -1;
        //     }
        // }

        int iFrame = 0;
        int iAbsoluteFrame = 0;

        int count_errs=0,skip_packets=0;
        const int max_number_of_attempts = 200;
        const int max_skipped_packets=10000;
        int frameFinished;

        bool FinishedReading = false;
        while(!FinishedReading) {
            AVPacket packet;
            int ret = av_read_frame(m_pFormatCtx, &packet);

            if (ret == AVERROR(EAGAIN) ) {
                skip_packets++;
                if (skip_packets > max_skipped_packets) {
                    mout << "averror exceeded max number of for file " << m_FileName.c_str() << LogStream::endl;
                    av_dump_format(m_pFormatCtx,0,m_FileName.c_str(),0); 
                    break;
                }
                continue;
            }

            // if (packet.stream_index == m_VideoStream) cout << "m_VideoStream " << m_VideoStream << " packet.stream_index " << packet.stream_index << " skip packets " << skip_packets << endl;

            if( packet.stream_index != m_VideoStream )
            {
                av_free_packet (&packet);
                // cout << "this packet isn't a m_VideoStream " << packet.stream_index << " skipped packets " << skip_packets;
                // cout << " frames " << frameCount << " nb_frames " << (unsigned long)(m_pFormatCtx->streams[m_VideoStream]->nb_frames) << endl;
                skip_packets++;
                if (skip_packets > max_skipped_packets) {
                    mout << "skipped packets (non Video Stream packets) exceeded max number of skipped packets for file " << m_FileName.c_str() << LogStream::endl;
                    av_dump_format(m_pFormatCtx,0,m_FileName.c_str(),0); 
                    break;
                }
                continue;
            }

            // Decode video frame
            avcodec_decode_video2(m_pCodecCtx, m_pFrame, &frameFinished, 
                         &packet);

            // Did we get a video frame?
            if(frameFinished) {

                iAbsoluteFrame++;
                if (iAbsoluteFrame > frameStart && iFrame < frameCount) { // skip frames until frameStart

                    // Convert the image from its native format to BGRA
                    if (m_pCodecCtx->hwaccel) {
                        m_pSWSCtx = sws_getCachedContext
                            (
                                m_pSWSCtx,
                                m_pCodecCtx->width,
                                m_pCodecCtx->height,
                                m_pCodecCtx->pix_fmt,
                                m_pCodecCtx->width,
                                m_pCodecCtx->height,
                                PIX_FMT_BGRA,
                                SWS_BILINEAR,
                                NULL,
                                NULL,
                                NULL                                
                            );
                    }
                    if (!m_pFrame->data[0]) {
                        cout << "skip this frame its not ready to be scaled" << endl;
                    }
                    else {

                        sws_scale
                        (
                                m_pSWSCtx,
                                (uint8_t const * const *)m_pFrame->data,
                                m_pFrame->linesize,
                                0,
                                m_pCodecCtx->height,
                                m_pFrameBGRA->data,
                                m_pFrameBGRA->linesize
                        );


                        if (!m_pFrameBGRA->data[0]) {
                            mout << "averror unable to get libav frame data = NULL done reading file " << m_FileName.c_str() << LogStream::endl;
                            FinishedReading = true;
                        }
                        else {
                            // Dump the frame to the console rgba order
                            // DumpFrame(m_pFrameBGRA, m_pCodecCtx->width, m_pCodecCtx->height);

                            // cout << "about to set frame " << iFrame << endl;
                            // bool usedPacket = false;
                            int64_t pts = packet.pts;
                            double frameTime = 0.0;
                            if (iFrame) frameTime = pCube->m_FrameTimes[iFrame-1] + 1.0/m_FPS;
                            if (pts != AV_NOPTS_VALUE) {
                                if (packet.stream_index == m_VideoStream) {
                                    AVRational *pTimeBase = &m_pFormatCtx->streams[packet.stream_index]->time_base;
                                    if (!iFrame) m_StartTime = av_q2d(*pTimeBase) * packet.pts;
                                    frameTime = av_q2d(*pTimeBase) * packet.pts - m_StartTime;
                                    // usedPacket = true;
                                }
                            }
                            // m_pFrameBGRA->data[0] is a pointer to a BGRA frame
                            pCube->m_FrameTimes[iFrame] = frameTime;
                            pCube->SetFrame(iFrame++,m_pFrameBGRA->data[0]);

                            bool lastFrame = false;
                            if (frameEnd >= 0 && iAbsoluteFrame > frameEnd) lastFrame = true;

                            if( iFrame >= frameCount || lastFrame ) {
                                FinishedReading = true;
                            }
                        }
                    }
                }

            }
            else {
                count_errs++;
                if (count_errs > max_number_of_attempts) {
                    mout << "unable to read video file " << m_FileName.c_str() << " dumping metadata to std out from av function" << LogStream::endl;
                    av_dump_format(m_pFormatCtx,0,m_FileName.c_str(),0); 
                    break;
                }
            }

            // Free the packet that was allocated by av_read_frame
            av_free_packet(&packet);
        }


        if (count_errs > max_number_of_attempts) {
            return -1;
        }

        if (skip_packets > max_skipped_packets) {
            return -1;
        }

    }
    else { // no good return failure
        return VID_PROCESS_FAIL;
    }
    return VID_PROCESS_OK;
}

int SchneiderVideoAV::loadFrame(CSFrameBGRA *pFrame, int frameIndex)
{   

    CSCubeBGRA temp;
    int status = loadCube(&temp,frameIndex,frameIndex);

    if (status != VID_PROCESS_OK) {
        return VID_PROCESS_FAIL;
    }

    pFrame->Set(temp.m_Width,temp.m_Height,temp.pFrameData(0));
    return VID_PROCESS_OK;
} 

gist