Jm 18.4 MVC 报告一
JM18.4 支持双目视差结构的立体视频,ProfileIDC = 128为Stereo High Profile。 两视点的.yuv文件经JM18.4编码生成的是一个.264文件。
提到High Profile H.264解码许多人并不了解,那么到底什么是High Profile H.264解码?其应用效果又是如何呢?
作为行业标准,H.264编码体系定义了4种不同的Profile(类):Baseline(基线类), Main(主要类), Extended(扩展类)和High Profile(高端类)(它们各自下分成许多个层):
Baseline Profile 提供I/P帧,仅支持progressive(逐行扫描)和CAVLC;
MVC报告一
视频ballroom的帧数为250帧,这里只对每个YUV视频的前13帧编码压缩的具有26帧的264文件进行解码。
264文件大小:97.3KB 解码成两个5.71M的YUV文件
一、MVC解码配置文件
首先,配置文件.cfg 的选择,为bin 目录下的decoder_stereo.cfg文件
在工程中配置如下:属性-》调试-》命令参数和工作目录:
打开decoder_stereo.cfg 文件看看参数的设置
InputFile = "ballroom.264" # H.264/AVC coded bitstream
OutputFile = "ballroom_dec.yuv" # Output file, YUV/RGB
RefFile = “ballroom_rec.yuv” # Ref sequence (for SNR)
Decode.cfg中: 2D
DecodeAllLayers = 0 # Decode all views (-mpr)
decoder_stereo.cfg中:MVC 3D
DecodeAllLayers = 1 # Decode all views (-mpr)
这里的1是指解码所有的视点
这里的视点只有viewId0 和 viewId1 两个视点
JM只能对双视点视频进行编码,因此在JM对264文件进行解码的时候,解码出来的也是两个YUV文件。
二、JM代码
这里我是单步跟踪,对代码中不明白的地方进行百度,然后注释,所以看的比较慢。截止到昨天晚上我看到的地方是parset.c 文件中InterpretSPS 函数。在跟踪的过程中对MVC有关的地方都挑了出来。
暂时对预测模式等部分代码还没有看到,还不熟。
进入decoder_test.c 文件,单步到iRet = OpenDecoder(&InputParams);进入:
在int OpenDecoder(InputParameters *p_Inp)中
if (p_Inp->DecodeAllLayers == 1)
//DecodeAllLayers == 1表示输入的视频是MVC多视点视频
{
OpenOutputFiles(p_Vid, 0, 1);//MVC
}
注意这里传递的参数:0,1 分别表示:视点0 和 视点1
这里是进行MVC输出设置
单步进入:OpenOutputFiles(p_Vid, 0, 1)
在ldecod.c文件中:
#if (MVC_EXTENSION_ENABLE)
//#define MVC_EXTENSION_ENABLE 1 //defines.h(49):# enable support for the Multiview High Profile 支持多视点高端类
void OpenOutputFiles(VideoParameters *p_Vid, int view0_id, int view1_id)
//JM18.4中MVC两路视频view0,view1
{
char out_ViewFileName[2][FILE_NAME_SIZE],
//输出视点文件名
sprintf(out_ViewFileName[0], "%s_ViewId%04d.yuv", chBuf, view0_id);
//视点 0 %04d :表示view0_id的值占四位:不足四位用填充。
sprintf(out_ViewFileName[1], "%s_ViewId%04d.yuv", chBuf, view1_id);
//视点1
}
#endif
然后就是回到decoder_test.c 文件,开始解码:
DecodeOneFrame(&pDecPicList);
do
{
iRet = Dec
decodeOneFrame(&pDecPicList);
}
int decode_one_frame(DecoderParams *pDecoder)
{
current_header = read_new_slice(currSlice);
}
int read_new_slice(Slice *currSlice)
{
for (;;)
{
if (0 == read_next_nalu(p_Vid, nalu))
return EOS;
{
int read_next_nalu(VideoParameters *p_Vid, NALU_t *nalu)
{
switch( p_Inp->FileFormat {
case PAR_OF_ANNEXB:
ret = get_annex_b_NALU(p_Vid, nalu, p_Vid->annex_b);
break;
{
int get_annex_b_NALU (VideoParameters *p_Vid, NALU_t *nalu, ANNEXB_t *annex_b)
{//此函数的主要作用是:从一个NAL单元中识别出startcodeprefix,通过去除这些信息从而剥离出NAL单元中真正有用的码流部分,并存储,最后返回整个NAL码流文件的长度。
nalu->len = pos - LeadingZero8BitsCount;//10=14-4
fast_memcpy (nalu->buf, annex_b->Buf + LeadingZero8BitsCount, nalu->len);
//00 00 00 01 _g _d _ _ _ _ _ _ _ _
nalu->forbidden_bit = (*(nalu->buf) >> 7) & 1;//*(nalu->buf) =‘g’=01100111
nalu->nal_unit_type = (NaluType) ((*(nalu->buf)) & 0x1f);
//nalucommon.h NALU_TYPE_SPS = 7,
结论:因此:解码比特流时,首先需要解码的SPS中的句法元素。
process_nalu:
switch (nalu->nal_unit_type)
{/*
switch 语句中包括对一般slice 的处理对IDR 的处理对DP1、DPB、DPC 的处理包括对SPS、PPS 的处理
解码器现在遇到的第一个NALU 是SPS 因此解码器经过解析之后的nal_unit_type 的值必然为7 解码器就会跳转到case NALU_TYPE_SPS
case NALU_TYPE_SPS:
ProcessSPS(p_Vid, nalu);
//该函数中最重要的函数是InterpretSPS
{
void ProcessSPS (VideoParameters *p_Vid, NALU_t *nalu)
{
InterpretSPS (p_Vid, dp, sps);
{
int InterpretSPS (VideoParameters *p_Vid, DataPartition *p, seq_parameter_set_rbsp_t *sps)
{
sps->profile_idc = read_u_v (8, "SPS: profile_idc" , s, &p_Dec->UsedBits);//序列参数集的语义:profile_idc指明所用的profile
// sps->profile_idc = 100 = FREXT_HP :HP:high profile 高端类
按照规定的顺序挨着解码每个语法元素
sps->constrained_set0_flag = read_u_1 ( "SPS: constrained_set0_flag" , s, &p_Dec->UsedBits);//UsedBits=8
sps->constrained_set1_flag = read_u_1 ( "SPS: constrained_set1_flag" , s, &p_Dec->UsedBits);//UsedBits=9
}
这个过程就和解码普通的AVC视频差不多了。这周由于边看边注释,所以只能搞到这了。下周再接再厉。。。
补充:综合编程 , 其他综合 ,