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

15
我使用以下代码通过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个回答

23

ffmpegAVCodec实例(静态解码器“工厂”对象)每个定义一个像素格式数组,表示支持的格式,并以值-1结束。

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

这个回调函数在某个时刻被调用,使用AVCodec工厂对象支持的格式数组,并且回调应该从该数组中选择一个格式(有点像"选一张卡牌"),并返回该值。这个get_format回调的默认实现是一个叫做avcodec_default_get_format的函数。(这是通过avcodec_get_context_defaults2安装的)。这个默认函数简单地实现了"选择格式"逻辑:它选择不是仅硬件加速的像素格式数组的第一个元素。

如果你想让编解码器使用不同的像素格式,你可以将自己的get_format回调安装到上下文对象中。然而,回调必须返回数组中的一个值(就像从菜单中选择一样)。它不能返回任意值。编解码器只支持它在数组中指定的格式。

遍历可用的格式数组并选择最佳的一个。如果你很幸运,它会是你实际想要的确切格式,sws_scale函数就不需要进行像素格式转换。(如果另外,你不请求缩放或裁剪图片,sws_scale应该认识到转换是无操作的)


3
请注意,在avcodec_open之前插入重写回调函数的位置。但要注意,我已经有一段时间没有查看这些内容了。 - Kaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接