当使用快速同步h264_qsv编码器时,ffmpeg avcodec_encode_video2挂起



当我使用mpeg4或h264编码器时,我能够使用ffmpeg 3.1.0的API成功地编码图像以制作有效的AVI文件。然而,当我使用快速同步编码器(h264_qsv), avcodec_encode_video2将悬挂一些时间。我发现当使用1920x1080的图像时,avcodec_encode_video2很少会挂起。当使用256x256的图像时,该函数很可能会挂起。

我已经创建了下面的测试代码来演示avcodec_encode_video2的挂起。代码将创建一个1000帧,256x256的AVI,比特率为400000。帧是简单分配的,所以输出的视频应该只有绿色帧。

使用Windows 7和Windows 10,使用32位或64位测试应用程序观察到这个问题。

如果有人有任何想法,我如何才能避免avcodec_encode_video2挂我将非常感激!事先感谢您的帮助。

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 framen";
                    success = false;
                    break;
                }
            }
            endExport();
        }
        else
        {
            std::cout << "Failed to start exportn";
            success = false;
        }
        cleanup();
    }
    else
    {
        std::cout << "Failed to initialize exportn";
        success = false;
    }
    if (success)
    {
        std::cout << "Successfully exported filen";
    }
    return 1;
}

问题不再发生,现在我已经更新到最新的英特尔®图形驱动程序(版本15.45.10.4542)

相关内容

  • 没有找到相关文章

最新更新