写在前面
Abdullah A. Muhit等人在2012年发表的论文[1],[2]。并发布了开源H.264 matlab版的代码。笔者会就着这套源码进行分解讲解。一方面为了加强自己的理解,另一方面也给学习这套源码的同学提供参考。笔者水平有限,难免会有一些错误,请各位读者批评指正。
注:这里的代码笔者进行了一些修改,剔除了一些与编码关系不大的代码。属于伪代码。
Main 函数总览
一、预操作
读入视频序列
obj=VideoReader('formancif.mov'); %obj 类中基本包含了一个视频的所有信息。
获取需要进行编码的视频序列mov
for k = 1 : nFrames %获取obj类的视频序列存入mov
mov(k).cdata = read(Obj, k);
end
设置需要编码的GOP组
// 设置需要编码的一个GOP(group of picture)组
%% Encoding Video Paramiters
Frame_start = 1; % I frame
Frame_end = 5; % Following P frames
NumberOfFrames=Frame_start+Frame_end;
由于进行压缩编码的部分通常为Y分量,所以对读入的视频序列,还要转YUV。
Resize(mov,Frame_start,Frame_end,Videow,Videoh)%1色彩空间的转换,2修改大小(不是必要的)
设置最终将会输出的比特流
bitstream = ''; % Initialize output bitstream
对比特流头部施加标记1111,代表将进行I帧编码
bitstream = [bitstream '1111']; % Appending I-Frame header ('1111')
小节总结:
进行到此,基本有了:
1、需要进行编码的视频序列 mov 为了后续方便识别记作Seq
2、一个附加了头部信息1111的比特流 bitstream=1111
3、一个GOP组,起始帧和结束帧 Frame_start = 1; Frame_end = 5;
二、设置参考帧+I帧编码(后续博客详细介绍,这里是介绍整体框架)
由于进行编码的帧格式为 IPPP格式,也就是说第一个帧是I帧,后续的都是P帧。
所以设置第一帧参考帧X为自身:
X(:,:,1)=Seq(:,:,1) %解释一下Seq为啥是3维数组,前两位代表每个帧的像素值,最后一位代表是第几帧
进行I帧编码(这个函数下一篇博客详细介绍,这次主要从整体把握编码框架)
[Seq_r(:,:,1),bits] = encode_i_frame(Seq(:,:,1),QP); % Encoding
%encode_i_frame函数是编码I帧的函数,
%函数内主要操作为:熵编码,残差块,预测等
%QP为质量因子
%返回的结果Seq_r为重构帧,bits为进行编码后的比特流
三、比特流拼接
将获得的bits与先前的bitstream进行拼接。
bitstream = [bitstream bits]; % Appending I-Frame bitstream
现在的bitstream是:1111bits。(bits是一堆01序列)
多提一嘴:最后进行解码,传输的也是bitsteam.
由bitstream足以还原出重构帧seq_r。
四、设置新的参考帧,为下一次的P帧编码做准备
X(:,:,1) = Seq_r(:,:,1);%用重构帧进行后续的参考
五、P帧编码(后续博客详细介绍,这里是介绍整体框架)
理解了I帧编码的整体架构,P帧编码的架构也是类似的。
由于是IPPP结构,所以后续的帧都是P帧。这里放上P帧编码部分的伪代码。
for K = 2:Frame_end
k = K-1;
bitstream = [bitstream '0000']; % Appending P-Frame header ('0000')
X(:,:,2) = Seq(:,:,2); % X[2]: Rnter coded Frame (P-Frames)
[Seq_r(:,:,2),bits] = encode_p_frame(X,QP,ext,block_size); % Encoding
bitstream = [bitstream bits]; % Appending P-Frame bitstream ('1100...')
X(:,:,1) = Seq_r(:,:,2); % X[1]: Refrence Frame (for the next P-Frames)
end
六、保存最终的比特流+解码
save(‘BitStream.mat’,‘bitstream’);
解码部分就是根据bitstream与先前附加的头标记,来判断哪部分是I帧,哪部分是P帧,解码部分就是编码的逆过程。核心还是在encode_i_frame,encode_p_frame函数里面。
七、参考文献
[1] A A Muhit, M R Pickering, M R Frater and J F Arnold, Video Coding using Elastic Motion Model and Larger Blocks,IEEE Trans. Circ. And Syst. for Video Technology, vol. 20, no. 5, pp. 661-672, 2010.
[2] A A Muhit, M R Pickering, M R Frater and J F Arnold, Video Coding using Geometry Partitioning and an Elastic Motion Model,accepted for publication in Journal of Visual Communication and Image Representation.