ffmpeg avcodec_encode_video2 hangs when using Quick Sync h264_qsv encoder

被刻印的时光 ゝ 提交于 2020-06-14 06:33:47

问题


When I use the mpeg4 or h264 encoders, I am able to successfully encode images to make a valid AVI file using the API for ffmpeg 3.1.0. However, when I use the Quick Sync encoder (h264_qsv), avcodec_encode_video2 will hang some of the time. I found that when using images that are 1920x1080, it was rare that avcodec_encode_video2 would hang. When using 256x256 images, it was very likely that the function would hang.

I have created the test code below that demonstrates the hang of avcodec_encode_video2. The code will create a 1000 frame, 256x256 AVI with a bit rate of 400000. The frames are simply allocated, so the output video should just be green frames.

The problem was observed using Windows 7 and Windows 10, using the 32-bit or 64-bit test application.

If anyone has any idea on how I can avoid the avcodec_encode_video2 hang I would be very grateful! Thanks in advance for any assistance.

extern "C"
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include "avcodec.h"
#include "avformat.h"
#include "swscale.h"
#include "avutil.h"
#include "imgutils.h"
#include "opt.h"
#include <rational.h>
}

#include <iostream>


// Globals
AVCodec* m_pCodec = NULL;
AVStream *m_pStream = NULL;
AVOutputFormat* m_pFormat = NULL;
AVFormatContext* m_pFormatContext = NULL;
AVCodecContext* m_pCodecContext = NULL;
AVFrame* m_pFrame = NULL;
int m_frameIndex;

// Output format
AVPixelFormat m_pixType = AV_PIX_FMT_NV12;
// Use for mpeg4
//AVPixelFormat m_pixType = AV_PIX_FMT_YUV420P;

// Output frame rate
int m_frameRate = 30;
// Output image dimensions
int m_imageWidth = 256;
int m_imageHeight = 256;
// Number of frames to export
int m_frameCount = 1000;
// Output file name
const char* m_fileName = "c:/test/test.avi";
// Output file type
const char* m_fileType = "AVI";
// Codec name used to encode
const char* m_encoderName = "h264_qsv";
// use for mpeg4
//const char* m_encoderName = "mpeg4";
// Target bit rate
int m_targetBitRate = 400000;

void addVideoStream()
{
    m_pStream = avformat_new_stream( m_pFormatContext, m_pCodec );
    m_pStream->id = m_pFormatContext->nb_streams - 1;
    m_pStream->time_base = m_pCodecContext->time_base;
    m_pStream->codec->pix_fmt = m_pixType;
    m_pStream->codec->flags = m_pCodecContext->flags;
    m_pStream->codec->width = m_pCodecContext->width;
    m_pStream->codec->height = m_pCodecContext->height;
    m_pStream->codec->time_base = m_pCodecContext->time_base;
    m_pStream->codec->bit_rate = m_pCodecContext->bit_rate;
}

AVFrame* allocatePicture( enum AVPixelFormat pix_fmt, int width, int height )
{
    AVFrame *frame;

    frame = av_frame_alloc();

    if ( !frame )
    {
        return NULL;
    }

    frame->format = pix_fmt;
    frame->width  = width;
    frame->height = height;

    int checkImage = av_image_alloc( frame->data, frame->linesize, width, height, pix_fmt, 32 );

    if ( checkImage < 0 )
    {
        return NULL;
    }

    return frame;
}

bool initialize()
{
    AVRational frameRate;
    frameRate.den = m_frameRate;
    frameRate.num = 1;

    av_register_all();

    m_pCodec = avcodec_find_encoder_by_name(m_encoderName);

    if( !m_pCodec )
    {
        return false;
    }

    m_pCodecContext = avcodec_alloc_context3( m_pCodec );
    m_pCodecContext->width = m_imageWidth;
    m_pCodecContext->height = m_imageHeight;
    m_pCodecContext->time_base = frameRate;
    m_pCodecContext->gop_size = 0;
    m_pCodecContext->pix_fmt = m_pixType;
    m_pCodecContext->codec_id = m_pCodec->id;
    m_pCodecContext->bit_rate = m_targetBitRate;

    av_opt_set( m_pCodecContext->priv_data, "+CBR", "", 0 );

    return true;
}

bool startExport()
{
    m_frameIndex = 0;
    char fakeFileName[512]; 
    int checkAllocContext = avformat_alloc_output_context2( &m_pFormatContext, NULL, m_fileType, fakeFileName );

    if ( checkAllocContext < 0 )
    {
        return false;
    }

    if ( !m_pFormatContext ) 
    {
        return false;
    }

    m_pFormat = m_pFormatContext->oformat;

    if ( m_pFormat->video_codec != AV_CODEC_ID_NONE ) 
    {
        addVideoStream();

        int checkOpen = avcodec_open2( m_pCodecContext, m_pCodec, NULL );

        if ( checkOpen < 0 )
        {
            return false;
        }

        m_pFrame = allocatePicture( m_pCodecContext->pix_fmt, m_pCodecContext->width, m_pCodecContext->height );                
        if( !m_pFrame ) 
        {
            return false;
        }
        m_pFrame->pts = 0;
    }

    int checkOpen = avio_open( &m_pFormatContext->pb, m_fileName, AVIO_FLAG_WRITE );
    if ( checkOpen < 0 )
    {
        return false;
    }

    av_dict_set( &(m_pFormatContext->metadata), "title", "QS Test", 0 );

    int checkHeader = avformat_write_header( m_pFormatContext, NULL );
    if ( checkHeader < 0 )
    {
        return false;
    }

    return true;
}

int processFrame( AVPacket& avPacket )
{
    avPacket.stream_index = 0;
    avPacket.pts = av_rescale_q( m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base );
    avPacket.dts = av_rescale_q( m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base );
    m_pFrame->pts++;

    int retVal = av_interleaved_write_frame( m_pFormatContext, &avPacket );
    return retVal;
}

bool exportFrame()
{
    int success = 1;
    int result = 0;

    AVPacket avPacket;

    av_init_packet( &avPacket );
    avPacket.data = NULL;
    avPacket.size = 0;

    fflush(stdout);

    std::cout << "Before avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;
    success = avcodec_encode_video2( m_pCodecContext, &avPacket, m_pFrame, &result );
    std::cout << "After avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;

    if( result )
    { 
        success = processFrame( avPacket );
    }

    av_packet_unref( &avPacket );

    m_frameIndex++;
    return ( success == 0 );
}

void endExport()
{
    int result = 0;
    int success = 0;

    if (m_pFrame)
    {
        while ( success == 0 )
        {
            AVPacket avPacket;
            av_init_packet( &avPacket );
            avPacket.data = NULL;
            avPacket.size = 0;

            fflush(stdout);
            success = avcodec_encode_video2( m_pCodecContext, &avPacket, NULL, &result );

            if( result )
            { 
                success = processFrame( avPacket );
            }
            av_packet_unref( &avPacket );

            if (!result)
            {
                break;
            }
        }
    }

    if (m_pFormatContext)
    {
        av_write_trailer( m_pFormatContext );

        if( m_pFrame )
        {
            av_frame_free( &m_pFrame );
        }

        avio_closep( &m_pFormatContext->pb );
        avformat_free_context( m_pFormatContext );
        m_pFormatContext = NULL;
    }
}

void cleanup()
{
    if( m_pFrame || m_pCodecContext )
    {
        if( m_pFrame )
        {
            av_frame_free( &m_pFrame );
        }

        if( m_pCodecContext )
        {
            avcodec_close( m_pCodecContext );
            av_free( m_pCodecContext );
        }
    }
}

int main()
{
    bool success = true;
    if (initialize())
    {
        if (startExport())
        {
            for (int loop = 0; loop < m_frameCount; loop++)
            {
                if (!exportFrame())
                {
                    std::cout << "Failed to export frame\n";
                    success = false;
                    break;
                }
            }
            endExport();
        }
        else
        {
            std::cout << "Failed to start export\n";
            success = false;
        }

        cleanup();
    }
    else
    {
        std::cout << "Failed to initialize export\n";
        success = false;
    }

    if (success)
    {
        std::cout << "Successfully exported file\n";
    }
    return 1;
}

回答1:


The problem no longer occurs now that I have updated to the latest Intel® Graphics Driver (version 15.45.10.4542)



来源:https://stackoverflow.com/questions/38109576/ffmpeg-avcodec-encode-video2-hangs-when-using-quick-sync-h264-qsv-encoder

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!