织梦CMS - 轻松建站从此开始!

罗索

一步一步设计SVC解码器1-解码器总体设计思路

jackyhwei 发布于 2010-01-29 13:27 点击:次 
最近的文章将探讨如何设计H.264/SVC解码器。由于SVC是在H.264AVC的基础上扩展起来的,所以,要想解码SVC必须首先解出AVC的普通H.264码流,这方面的开源解码器,处理相关的JM验证模型,还有P264和FFMPEG的H.264解码部分。
TAG:

最近的文章将探讨如何设计H.264/SVC解码器。由于SVC是在H.264AVC的基础上扩展起来的,所以,要想解码SVC必须首先解出AVC的普通H.264码流,这方面的开源解码器,处理相关的JM验证模型,还有P264和FFMPEG的H.264解码部分。其中P264是中国的李世平依据X.264代码提炼完善的,可惜已经很久没有更新维护。这里假想要做一个类似X264架构的解码器:

1. 设计和FFMPEG接口,重用上下文结构

由于FFMPEG的灵活注册架构,使得很多编解码器软件易于被其注册整合,在设计编解码器的时候,我们可以利用FFMPEG的成熟架构来统一API,使得预定的编解码器有良好的用户接口。看看在FFMPEG中的h264_decoder结构如下:
AVCodec h264_decoder = {
    "h264",
    CODEC_TYPE_VIDEO,
    CODEC_ID_H264,
    sizeof(H264Context),
    decode_init,
    NULL,
    decode_end,
    decode_frame,
    /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY,
    .flush= flush_dpb,
    .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),
    .pix_fmts= ff_hwaccel_pixfmt_list_420,
};

decode_init,decode_end和decode_frame构成了这里的解码基本API,那么相应的可以在代码中设计如下仿照X264设计如下接口:

int zsvc_nal_decode( void *, int *, int b_annexeb, zsvc_nal_t *nal );

/****************************************************************************
 * Decoder functions:
 ****************************************************************************/
zsvc_t *zsvc_decoder_open   ( zsvc_param_t * );
int     zsvc_encoder_reconfig( zsvc_t *, zsvc_param_t * );
int     zsvc_encoder_headers( zsvc_t *, zsvc_nal_t **, int * );
int     zsvc_encoder_encode ( zsvc_t *, zsvc_nal_t **, int *, zsvc_picture_t *, zsvc_picture_t * );
void    zsvc_encoder_close  ( zsvc_t * );

在FFMPEG调用X264的上下文数据中,分别使用x264_param_t、x264_t和x264_picture_t三个结构,在假想的解码器重可以沿用这些结构体,以后根据实际使用情况进行增减。

2. 编解码器对比

让我们来看看编解码器的结构,如下图所示,可以重复利用的部分都已经用灰色标明。由此可见,从X264基础来改造一个解码器有很多重用部分,需要自我实现的部分是解码API和熵解码(包括SPS,PPS和残差等各语法单元)。其它部分均可以从编码器中分离得到,由此可见实现解码器是编码器的基础,两者有许多公用部分,究其原因是编码过程中的参考帧不是直接的YUV数据,而是经过变换和量化,并做运动补偿的重构帧,因此重构过程包括了除了熵解码外的整个解码过程。


3. 基本解码框架

当从.264的已编码文件中读出每个NAL,然后将根据nalType如下分别读取解析数据,整个过程包括对SPS和PPS的处理,还有具体的VCL帧处理,其中对IDR帧和非IDR帧解码的区别就是多了一个参考帧队列的初始化过程。

switch( nal->i_type )
    {
        case NAL_SPS:
            if( ( i_ret = zsvc_sps_read( &bs, h->sps_array ) ) < 0 )
            {
                fprintf( stderr, "zsvc: zsvc_sps_read failed\n" );
            }
            break;

        case NAL_PPS:
            if( ( i_ret = zsvc_pps_read( &bs, h->pps_array ) ) < 0 )
            {
                fprintf( stderr, "zsvc: zsvc_pps_read failed\n" );
            }
            break;

        case NAL_SLICE_IDR:
        //fprintf( stderr, "zsvc: NAL_SLICE_IDR\n" );
             zsvc_slice_idr( h ); //note: then do below
        case NAL_SLICE:
            if( ( i_ret = zsvc_slice_decode( h, &bs, nal ) ) < 0 )
            {
                 fprintf( stderr, "zsvc: zsvc_slice_decode failed\n" );
            }
            else if(h->b_pic_output)
            {
                *pic_out = h->pic_dec;
            }
            break;

        case NAL_SLICE_DPA:
        case NAL_SLICE_DPB:
        case NAL_SLICE_DPC:
            fprintf( stderr, "partitioned stream unsupported\n" );
            i_ret = -1;
            break;

       case NAL_SEI:
       default:
           break;
    }

本文一般性探讨了一个H.264解码器的基本框架,具体模块化合实现还有很多工作要做,留待以后继续探索。

(罗索客)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201001/8435.html]
本文出处:网络博客 作者:罗索客
顶一下
(2)
66.7%
踩一下
(1)
33.3%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容