如何在 libavcodec 中设置解码像素格式?

Posted

技术标签:

【中文标题】如何在 libavcodec 中设置解码像素格式?【英文标题】:How to set decode pixel format in libavcodec? 【发布时间】:2012-03-28 00:11:24 【问题描述】:

我通过 libavcodec 解码视频,使用以下代码:

//Open input file
if(avformat_open_input(&ctx, filename, NULL, NULL)!=0)
    return FALSE; // Couldn't open file
if(avformat_find_stream_info(ctx, NULL)<0)
    return FALSE; // Couldn't find stream information
videoStream = -1;
//find video stream
for(i=0; i<ctx->nb_streams; i++)
       
    if((ctx->streams[i])->codec->codec_type==AVMEDIA_TYPE_VIDEO)
    
        videoStream=i;
        break;
    

if (videoStream == -1)
    return FALSE; // Didn't find a video stream
video_codec_ctx=ctx->streams[videoStream]->codec;
//find decoder
video_codec=avcodec_find_decoder(video_codec_ctx->codec_id);
if(video_codec==NULL)
    return FALSE; // Codec not found
if(avcodec_open(video_codec_ctx, video_codec)<0)
    return -1; // Could not open codec
video_frame=avcodec_alloc_frame();
scaled_frame=avcodec_alloc_frame();
static struct SwsContext *img_convert_ctx; 
if(img_convert_ctx == NULL) 

      int w = video_codec_ctx->width;
      int h = video_codec_ctx->height;
      img_convert_ctx = sws_getContext(w, h, 
                        video_codec_ctx->pix_fmt, 
                        w, h, dst_pix_fmt, SWS_BICUBIC, 
                        NULL, NULL, NULL);
      if(img_convert_ctx == NULL) 
        fprintf(stderr, "Cannot initialize the conversion context!\n");
        return FALSE;
      

while(b_play) 

    if (av_read_frame(ctx, &packet) < 0)
    
        break;
    
    if(packet.stream_index==videoStream) 
    // Decode video frame   
        avcodec_decode_video2(video_codec_ctx, video_frame, &frameFinished,
                         &packet);
        // Did we get a video frame?
        if(frameFinished) 
        
            if (video_codec_ctx->pix_fmt != dst_pix_fmt)
                                   
                if (video_codec_ctx->pix_fmt != dst_pix_fmt)            
                     sws_scale(img_convert_ctx, video_frame->data, 
                              video_frame->linesize, 0, 
                              video_codec_ctx->height, 
                              scaled_frame->data, scaled_frame->linesize);              
                       
        

av_free_packet(&packet);

代码可以正常工作,但需要将每一帧转换为所需的格式。 是否可以在没有sws_scale的情况下设置解码的像素格式以获得正确的格式?

非常感谢您的回答。

【问题讨论】:

【参考方案1】:

ffmpegAVCodec 实例(静态解码器“工厂”对象)每个都定义了它们支持的像素格式数组,以值 -1 终止。

AVCodecContext(解码器实例)对象有一个名为 get_format 的回调函数指针:它是该结构中的一个函数指针。

这个回调函数在编解码器初始化的某个时刻被调用,使用AVCodec工厂对象的支持格式数组,并且回调应该从该数组中选择一种格式(有点像“选择一个卡,任何卡”)并返回该值。这个get_format 回调的默认实现是一个名为avcodec_default_get_format 的函数。 (这是安装avcodec_get_context_defaults2)。这个默认函数非常简单地实现了“选择格式”逻辑:它选择数组的第一个元素,它不是仅硬件加速的像素格式。

如果您希望编解码器使用不同的像素格式,您可以将自己的get_format 回调安装到上下文对象中。但是,回调必须返回数组中的一个值(例如从菜单中选择)。它不能返回任意值。编解码器将仅支持它在数组中指定的格式。

浏览一系列可用格式并选择最佳格式。如果幸运的话,这正是您真正想要的,sws_scale 函数不必进行像素格式转换。 (另外,如果您不请求缩放或裁剪图片,sws_scale 应该会识别出转换是一个 noop。)

【讨论】:

P.S.插入覆盖回调的位置将在avcodec_open 之前。请注意,我已经有一段时间没有看到这些东西了。

以上是关于如何在 libavcodec 中设置解码像素格式?的主要内容,如果未能解决你的问题,请参考以下文章

在 libavcodec/ffmpeg 中使用并行解码器

Qt之FFMpeg 实现视频解码编码转码流程详解

ffmpeg/Libavcodec 找不到编解码器

如何在 RSAParameters 中设置公钥 [重复]

如何在Android用FFmpeg解码图像

在python中设置隐式默认编码解码错误处理