|
Posted on 2008-09-03 09:26 猫头鹰 阅读(2802) 评论(9) 编辑 收藏 引用 所属分类: 视频学习之路
最近这几天研究H.263编码,前几天把标准H.263解码库TMNDEC2.0理解了,这两天把H.263的标准编码库研究了一下,编码库的使用明显比解码库要复杂,一眼看上去好你多了很多的代码,令的有点眼花。花了点时间,注释了代码,发现比解码多出来的,主要是进行码率的控制的。而且还使用了两种方法,其它多出来的,就是很多的编码参数(它都弄成全局变量了)。过几天弄一个固定帧率(变码率)的精简版本DEMO出来。 ![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//************************************************************************9
*
* main.c, main module of tmn (TMN encoder).
* tmn is an H.263 encoder somewhat based on the Test Model Near-term
* (TMN5) in the ITU-T LBC Experts Group.
*
* Copyright (C) 1995, 1996 Telenor R&D, Norway
* Karl Olav Lillevold <Karl.Lillevold@nta.no>
*
* Contacts:
* Karl Olav Lillevold <Karl.Lillevold@nta.no>, or
* Robert Danielsen <Robert.Danielsen@nta.no>
*
* Telenor Research and Development http://www.nta.no/brukere/DVC/
* P.O.Box 83 tel.: +47 63 84 84 00
* N-2007 Kjeller, Norway fax.: +47 63 81 00 76
*
************************************************************************/
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//*
* Disclaimer of Warranty
*
* These software programs are available to the user without any
* license fee or royalty on an "as is" basis. Telenor Research and
* Development disclaims any and all warranties, whether express,
* implied, or statuary, including any implied warranties or
* merchantability or of fitness for a particular purpose. In no
* event shall the copyright-holder be liable for any incidental,
* punitive, or consequential damages of any kind whatsoever arising
* from the use of these programs.
*
* This disclaimer of warranty extends to the user of these programs
* and user's customers, employees, agents, transferees, successors,
* and assigns.
*
* Telenor Research and Development does not represent or warrant that
* the programs furnished hereunder are free of infringement of any
* third-party patents.
*
* Commercial implementations of H.263, including shareware, are
* subject to royalty fees to patent holders. Many of these patents
* are general enough such that they are unavoidable regardless of
* implementation design.
* */
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//* 修改:
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
修改人: Tinnal<www.cnitblog.com/tinnal/>
目期: 2008-9-1
改动: 增加中文注释
*/
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
#include"sim.h"
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
FILE *streamfile;
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
void main(int argc, char *argv[])
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cnitblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
PictImage *prev_image = NULL;
PictImage *curr_image = NULL;
PictImage *curr_recon = NULL;
PictImage *prev_recon = NULL;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* PB-frame specific */
PictImage *B_recon = NULL;
PictImage *B_image = NULL;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
Pict *pic = (Pict *)malloc(sizeof(Pict));
unsigned char *image;
FILE *cleared;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
int i;
float mean_frame_rate, ref_frame_rate, frame_rate, seconds;
int first_loop_finished=0;
int total_frames_passed, PPFlag = 0, targetrate;
int frames,bframes,pframes,wcopies,icopies, write_repeated,pdist=0,bdist=0;
int start, end, frame_no, writediff;
int first_frameskip, chosen_frameskip, orig_frameskip, frameskip;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
int QP, QPI;
Bits *bits = (Bits *)malloc(sizeof(Bits));
Bits *total_bits = (Bits *)malloc(sizeof(Bits));
Bits *intra_bits = (Bits *)malloc(sizeof(Bits));
Results *res = (Results *)malloc(sizeof(Results));
Results *total_res = (Results *)malloc(sizeof(Results));
Results *b_res = (Results *)malloc(sizeof(Results));
char *seqfilename = (char *)malloc(sizeof(char)*100);
char *streamname = (char *)malloc(sizeof(char)*100);
char *outputfile = (char *)malloc(sizeof(char)*100);
char *diff_filename=DEF_DIFFILENAME;
char *tracefile = (char *)malloc(sizeof(char)*100);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
#ifndef OFFLINE_RATE_CONTROL
// 码率控制用的变量
float DelayBetweenFramesInSeconds;
int CommBacklog;
#else
PictImage *stored_image = NULL;
int start_rate_control;
#endif
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
extern int arith_used;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf (stdout,"\nTMN (H.263) coder version 2.0, Copyright (C) 1995, 1996 Telenor R&D, Norway\n");
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
headerlength = DEF_HEADERLENGTH;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
#ifndef FASTIDCT
init_idctref();
#endif
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Default variable values */
// 是否采用先进预测模式
advanced = DEF_ADV_MODE;
// 是否采用算术编码而不是哈夫曼编码
syntax_arith_coding = DEF_SAC_MODE;
// 是否采用无限制向量长度模式
pic->unrestricted_mv_mode = DEF_UMV_MODE;
mv_outside_frame = DEF_UMV_MODE || DEF_ADV_MODE;
long_vectors = DEF_UMV_MODE;
// 是否采用PB模式
pb_frames = DEF_PBF_MODE;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// P帧量化矩阵参数
QP = DEF_INTER_QUANT;
// I帧量化矩阵参数
QPI = DEF_INTRA_QUANT;
// B帧量化矩阵参数
pic->BQUANT = DEF_BQUANT;
// 编码类型(one of SF_SQCIF, SF_QCIF, SF_CIF, SF_4CIF, SF_16CIF)
pic->source_format = DEF_CODING_FORMAT;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 参考帧频(Main内部用于控制帧率)
ref_frame_rate = (float)DEF_REF_FRAME_RATE;
// 相对于原帧的丢帧率(也就是编码时丢弃视频输入文件帧的速度)
chosen_frameskip = DEF_FRAMESKIP + 1;
// 相对于30fps参考帧率的原帧的丢帧率
// orig_frameskip * 30 fps = 视频输入文件的帧率,
// 这个帧率又叫原帧(original sequence)率
orig_frameskip = DEF_ORIG_SKIP + 1;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//<! 帧率控制方法
#ifdef OFFLINE_RATE_CONTROL
start_rate_control = DEF_START_RATE_CONTROL;
#else
//<! 目标输出帧率, DEF_TARGET_FRAME_RATE =
pic->target_frame_rate = (float)DEF_TARGET_FRAME_RATE;
#endif
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
seqfilename[0] = '\0';
strcpy(streamname, DEF_STREAMNAME);
strcpy(outputfile, DEF_OUTFILENAME);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//<! 是否保存原帧和重建帧的差异
writediff = DEF_WRITE_DIFF;
//<! 是否TRACE运行过程
trace = DEF_WRITE_TRACE;
//<! 在存在丢帧的情况下是否通过拷贝补全重建帧
write_repeated = DEF_WRITE_REPEATED;
//<! 向量估算的长度
pic->seek_dist = DEF_SEEK_DIST;
//<! 多少个编GOB后插入一个同步头,0为不再插入
pic->use_gobsync = DEF_INSERT_SYNC;
//<! 从那一帧开始到那一帧结束帧率控制
start = DEF_START_FRAME;
end = DEF_STOP_FRAME;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 期望的码率, 0代表不控制
targetrate = 0;
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* default is variable bit rate (fixed quantizer) will be used */
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 一些用于帧率控制的辅助统计参数
frames = 0; //I后以后的帧总数
pframes = 0; //P帧总数
bframes = 0; //B帧总数
total_frames_passed = 0;//经过的帧数,包括被丢的帧
pic->PB = 0;
wcopies = icopies = 1; //因丢弃B或P帧而复制的数量 和 因丢弃I帧而复制的数量
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
pic->TR = 0;
pic->QP_mean = (float)0.0;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Process arguments */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for (i = 1; i < argc; i++) {
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (*(argv[i]) == '-') {
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) switch(*(++argv[i])) {
case 'a':
start = atoi(argv[++i]);
break;
case 'b':
end = atoi(argv[++i]);
break;
case 'S':
chosen_frameskip = atoi(argv[++i]) + 1;
break;
case 'O':
orig_frameskip = atoi(argv[++i]) + 1;
break;
case 's':
pic->seek_dist = atoi(argv[++i]);
break;
case 'o':
strcpy(outputfile, argv[++i]);
break;
case 'e':
headerlength = atoi(argv[++i]);
break;
case 'm':
write_repeated = ON;
break;
case 'i':
strcpy(seqfilename, argv[++i]);
break;
case 'q':
QP = atoi(argv[++i]);
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (QP > 31 || QP < 0) {
fprintf(stderr,"QP out of range - clipping it\n");
QP = mmin(31,mmax(0,QP));
}
break;
case 'I':
QPI = atoi(argv[++i]);
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (QPI > 31 || QPI < 0) {
fprintf(stderr,"QP out of range - clipping it\n");
QPI = mmin(31,mmax(0,QPI));
}
break;
case 'w':
writediff = ON;
break;
case 'B':
strcpy(streamname, argv[++i]);
break;
case 'h':
Help();
exit(0);
break;
case 'H':
AdvancedHelp();
exit(0);
break;
case 't':
trace = 1;
break;
case 'g':
pic->use_gobsync = atoi(argv[++i]);;
break;
case 'D':
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* note that the Unrestricted Motion Vector mode turns on
both long_vectors and mv_outside_frame */
pic->unrestricted_mv_mode = ON;
mv_outside_frame = ON;
long_vectors = ON;
break;
case 'E':
syntax_arith_coding = ON;
break;
case 'F':
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* note that the Advanced Prediction mode turns on both
advanced (8x8 vectors and OBMC) and mv_outside_frame */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* the Extended Motion Vector mode is included in the
Unrestricted Motion Vector mode, which of course can be
use together with the Advanced Prediction mode */
advanced = ON;
mv_outside_frame = ON;
break;
case 'G':
pb_frames = ON;
break;
case 'Q':
pic->BQUANT = atoi(argv[++i]);
break;
case 'r':
targetrate = atoi(argv[++i]);
break;
#ifdef OFFLINE_RATE_CONTROL
case 'R':
start_rate_control = atoi(argv[++i]);
break;
#else
case 'R':
pic->target_frame_rate = (float)atof(argv[++i]);
break;
#endif
case 'Z':
ref_frame_rate = (float)atoi(argv[++i]);
break;
case 'x':
pic->source_format = atoi(argv[++i]);
break;
default:
fprintf(stderr,"Illegal option: %c\n",*argv[i]);
Help();
exit(-1);
break;
}
}
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) switch (pic->source_format) {
case (SF_SQCIF):
fprintf(stdout, "Encoding format: SQCIF (128x96)\n");
pels = 128;
lines = 96;
break;
case (SF_QCIF):
fprintf(stdout, "Encoding format: QCIF (176x144)\n");
pels = 176;
lines = 144;
break;
case (SF_CIF):
fprintf(stdout, "Encoding format: CIF (352x288)\n");
pels = 352;
lines = 288;
break;
case (SF_4CIF):
fprintf(stdout, "Encoding format: 4CIF (704x576)\n");
pels = 704;
lines = 576;
break;
case (SF_16CIF):
fprintf(stdout, "Encoding format: 16CIF (1408x1152)\n");
pels = 1408;
lines = 1152;
break;
default:
fprintf(stderr,"Illegal coding format\n");
exit(-1);
}
cpels = pels/2;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (seqfilename[0] == '\0') {
fprintf(stderr,"Required input parameter \'-i <filename>\' missing\n");
Help();
exit(-1);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
#ifndef OFFLINE_RATE_CONTROL
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* rate control variables */
// 要控制到达的码率
pic->bit_rate = targetrate;
// 编码器源帧率,换句话说,也就是我们输入的文件的帧率
pic->src_frame_rate = (int)(ref_frame_rate / orig_frameskip);
// 编码器的编码周期(Second/Frame)
DelayBetweenFramesInSeconds = (float) 1.0/(float)pic->src_frame_rate;
InitializeRateControl();
#endif
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (QP == 0 || QPI == 0) {
fprintf(stderr,"Warning:");
fprintf(stderr,"QP is zero. Bitstream will not be correctly decodable\n");
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (ref_frame_rate != 25.0 && ref_frame_rate != 30.0) {
fprintf(stderr,"Warning: Reference frame rate should be 25 or 30 fps\n");
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// frame_rate为期望输出的码率
frame_rate = ref_frame_rate / (float)(orig_frameskip * chosen_frameskip);
#ifdef OFFLINE_RATE_CONTROL
fprintf(stdout,"Encoding frame rate : %.2f\n", frame_rate);
#else
if (pic->bit_rate == 0)
fprintf(stdout,"Encoding frame rate : %.2f\n", frame_rate);
else
fprintf(stdout,"Encoding frame rate : variable\n");
#endif
fprintf(stdout,"Reference frame rate : %.2f\n", ref_frame_rate);
fprintf(stdout,"Orig. seq. frame rate: %.2f\n\n",
ref_frame_rate / (float)orig_frameskip);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Open stream for writing */
streamfile = fopen (streamname, "wb");
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (streamname == NULL) {
fprintf(stderr,"Unable to open streamfile\n");
exit(-1);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Initialize bitcounters */
initbits ();
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (trace) {
strcpy(tracefile, "trace.intra");
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Open trace-file for writing */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if ((tf = fopen(tracefile,"w")) == NULL) {
fprintf(stderr,"Unable to open tracefile (intra)\n");
exit(-1);
}
}
// 下面这个文件是用于输出从编码帧重建后的重建帧的.
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Clear output files */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if ((cleared = fopen(outputfile,"wb")) == NULL) {
fprintf(stderr,"Couldn't open outputfile: %s\n",outputfile);
exit(-1);
}
else
fclose(cleared);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 这个文件是用于保存原帧和重建帧差异的.
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (writediff) {
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if ((cleared = fopen(diff_filename,"wb")) == NULL) {
fprintf(stderr,"Couldn't open diff-file: %s\n",diff_filename);
exit(-1);
}
else
fclose(cleared);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 读第一个原帧,这个帧必须采用帧内编码(I帧)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Intra image */
image = ReadImage(seqfilename,start,headerlength);
fprintf(stderr,"Coding \n");
// 从读进来的数据填充pict_image结构.
curr_image = FillImage(image);
// 选择编码格式的帧人编码
pic->picture_coding_type = PCT_INTRA;
// 用设定的帧内编码量化矩阵参数给QUANT初始化
// 这个赋值我认为没用,因为CodeOneIntra函数也会通过参数给它赋值
pic->QUANT = QPI;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 进行I帧的编码,并输出重建帧
curr_recon = CodeOneIntra(curr_image, QPI, bits, pic);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 如果使用的算术编吗,应该要进行一些额外操作
// arith_used这个变量也是定义在算术编码的.c文件当中的,
// 这里只是引用,我不去研究他,因为我只会用它的哈夫曼编码
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (arith_used) {
bits->header += encoder_flush();
arith_used = 0;
}
// 填充数据使之字对齐
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) bits->header += alignbits (); /**//* pictures shall be byte aligned */
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"Finished INTRA\n");
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 从原帧和重建帧进行信噪比测试,并输出相应的结果(res)或文件(writediff)
// 这种信息不一定每个程序都需要
ComputeSNR(curr_image, curr_recon, res, writediff);
// 调整bits内部的比特统计数据(由各个部份的比特数累加得到总的比特数)
AddBitsPicture(bits);
// 把信噪比信息输出到屏幕
PrintSNR(res, 1);
// 把比特信息输出到屏幕
PrintResult(bits, 1, 1);
// 把当前比特信息拷贝到I帧专用的比特信息变量intra_bits
memcpy(intra_bits,bits,sizeof(Bits));
// 清零总比特,总的结果和B帧结果变量total_bits,total_res,b_res
ZeroBits(total_bits);
ZeroRes(total_res);
ZeroRes(b_res);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* number of seconds to encode */
// 计算编码一共需要的理论时间
//(end - start + chosen_frameskip): ??
//是因为下面这条first_frameskip = chosen_frameskip语句吗?
//那也应该是'-'才对呀,因为从start到start+chosen_frameskip帧从后面
//的程序看来是不编码的,想不明白.
//
//orig_frameskip/ref_frame_rate: 编码器编码的周期
//因些 seconds 为编码需要的时间
seconds = (end - start + chosen_frameskip) * orig_frameskip/ ref_frame_rate;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (trace) {
strcpy(tracefile, "trace");
fclose(tf);
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Open trace-file for writing */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if ((tf = fopen(tracefile,"w")) == NULL) {
fprintf(stderr,"Unable to open tracefile (non-intra)\n");
exit(-1);
}
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* compute first frameskip */
#ifdef OFFLINE_RATE_CONTROL
first_frameskip = chosen_frameskip;
frameskip = chosen_frameskip;
#else
// intra_bits->total: 编码帧的实际比特数
// DelayBetweenFramesInSeconds * pic->bit_rate: 根据计算的理论帧比特数
// 如果CommBacklog > 0 我们就得控制了,呵呵,当然~,也不能这么"眼浅".
CommBacklog = intra_bits->total -
(int)(DelayBetweenFramesInSeconds * pic->bit_rate);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pic->bit_rate == 0) {
// 如果没有流控,frameskip为chosen_frameskip
frameskip = chosen_frameskip;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) else { /**//* rate control is used */
// 如果存在流控,则计算这编码帧后为了保证码率而要丢掉的帧数
frameskip = 1;
// 增加丢帧率直到比特差值CommBacklog小于一个理论帧比特数.
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) while ( (int)(DelayBetweenFramesInSeconds*pic->bit_rate) <= CommBacklog) {
CommBacklog -= (int) ( DelayBetweenFramesInSeconds * pic->bit_rate );
frameskip += 1;
}
}
//设定第一个I帧的后丢掉的帧数
first_frameskip = frameskip;
#endif
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//如果由于码率要求而丢太多编码帧就没有意义了.
if (first_frameskip > 256)
fprintf(stderr,"Warning: frameskip > 256\n");
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//好了,下面的编码类型全部选定的P帧,也就是向前预测编码.
pic->picture_coding_type = PCT_INTER;
//量化矩阵参数也选择P帧的,当然,也可能和I帧用一样的.
pic->QUANT = QP;
bdist = chosen_frameskip;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* always encode the first frame after intra as P frame.
This is not necessary, but something we chose to make
the adaptive PB frames calculations a bit simpler */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pb_frames) {
pic->PB = 0;
pdist = 2*chosen_frameskip - bdist;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
if (write_repeated)
icopies = chosen_frameskip; //是否icopies = first_frameskip 更合理
//如果设了write_repeated,编译帧被丢的部份会通过拷贝保持未丢前水平.
for (i = 0; i < icopies; i++)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) WriteImage(curr_recon,outputfile); /**//* write wcopies frames to disk */
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//***** Main loop *****/
//接下来就进行发送PB帧的循环内
//第一个frame应该是frame_no = start + first_frameskip
//其中start是我们指定的,first_frameskip为了补偿第一个已经发出去的I帧产生的码率增大的.
//增量为frameskip,因为现在我们还不知道其它帧的码率如何,只能引用I帧的情况,一会再调整.
for (frame_no = start + first_frameskip; frame_no <= end;
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) frame_no += frameskip) {
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//更新上一原帧和上一重建帧
prev_image = curr_image;
prev_recon = curr_recon;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Set QP to pic->QUANT from previous encoded picture */
QP = pic->QUANT;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
// 当已经编码过一个P帧后PPFlag为真
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (!PPFlag) {
//PB模式我们暂时不看
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pic->PB) {
bdist = frameskip;
pdist = 2*frameskip - bdist;
pic->TRB = bdist * orig_frameskip;
if (pic->TRB > 8)
fprintf(stdout,"distance too large for B-frame\n");
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Read the frame to be coded as B */
image = ReadImage(seqfilename,frame_no,headerlength);
B_image = FillImage(image);
first_loop_finished = 1;
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (frame_no + pdist <= end) {
image = ReadImage(seqfilename,frame_no + pdist,headerlength);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) else {
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) pic->PB = 0; /**//* end of sequence, encode as P */
image = ReadImage(seqfilename,frame_no,headerlength);
}
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) else {
//读取目标源帧
image = ReadImage(seqfilename,frame_no,headerlength);
}
//填充pict_image结够
curr_image = FillImage(image);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//不看PB
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pic->PB) {
if (pic->TRB > 8 || !NextTwoPB(curr_image, B_image, prev_image,
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) bdist, pdist, pic->seek_dist)) {
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* curr_image and B_image were not suitable to be coded
as a PB-frame - encoding as two P-frames instead */
pic->PB = 0;
#ifdef OFFLINE_RATE_CONTROL
stored_image = curr_image;
#else
FreeImage(curr_image);
#endif
frameskip = bdist;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
curr_image = B_image;
PPFlag = 1;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) else {
frame_no += pdist;
}
}
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) else {
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* PPFlag is set when the second of the two P-frames
is due to be coded */
//这已经是第二以上编采用用P帧编码了.
//其实我们可以看到,做了这么多的判断都是因为有了PB帧,不然很简单
#ifdef OFFLINE_RATE_CONTROL
curr_image = stored_image;
#else
//还是读源帧,然后填充
image = ReadImage(seqfilename,frame_no,headerlength);
curr_image = FillImage(image);
#endif
pic->PB = 0;
PPFlag = 0;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Temporal Reference is the distance between encoded frames compared
the reference picture rate which is 25.0 or 30 fps */
//TR为当前编码帧对于参考帧率(30或25fps)的距离.
//不考率B帧的情况下.
// TR+= frameskip * orig_frameskip;
pic->TR += (( (frameskip+(pic->PB?pdist:0)) *orig_frameskip) % 256);
if (frameskip+(pic->PB?pdist:0) > 256)
fprintf(stdout,"Warning: frameskip > 256\n");
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//调整帧的统计值
frames += (pic->PB ? 2: 1);
bframes += (pic->PB ? 1 : 0);
pframes += 1;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pic->PB) { /**//* Code two frames as a PB-frame */
B_recon = InitImage(pels*lines);
fprintf(stdout,"Coding PB frames %d and %d ",
frame_no - pdist, frame_no);
fflush(stdout);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) else { /**//* Code the next frame as a normal P-frame */
fprintf(stdout,"Coding P frame %d ", frame_no);
fflush(stdout);
}
//初始化curr_recon.分配空间??
curr_recon = InitImage(pels*lines);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//开始进行编码.
CodeOneOrTwo(curr_image, B_image, prev_image, prev_recon,
QP, (bdist+pdist)*orig_frameskip, bits, pic,
B_recon, curr_recon);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"done\n");
if (targetrate != 0)
fprintf(stdout,"Inter QP: %d\n", QP);
fflush(stdout);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (arith_used) {
bits->header += encoder_flush();
arith_used = 0;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) bits->header += alignbits (); /**//* pictures shall be byte aligned */
AddBitsPicture(bits);
AddBits(total_bits, bits);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
#ifndef OFFLINE_RATE_CONTROL
//重新计算码率的各控制参数
if (pic->bit_rate != 0 && pic->PB)
CommBacklog -= (int)
( DelayBetweenFramesInSeconds*pic->bit_rate ) * pdist;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pic->bit_rate != 0) {
//根据TMN5 文档进行码率控制,文档我Google了半天都找不到.:-(
//应该是调整量化矩阵
UpdateRateControl(bits->total);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//先算出超出来的部分
CommBacklog += bits->total;
frameskip = 1;
CommBacklog -= (int)
(frameskip * DelayBetweenFramesInSeconds *pic->bit_rate);
//再来算跳过几个帧才能把超出的比特跳过多少个帧来能补回来
while ( (int)(DelayBetweenFramesInSeconds*pic->bit_rate) <= CommBacklog)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
CommBacklog -= (int) ( DelayBetweenFramesInSeconds * pic->bit_rate );
frameskip += 1;
}
}
#else
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Aim for the targetrate with a once per frame rate control scheme */
if (targetrate != 0)
if (frame_no - start > (end - start) * start_rate_control/100.0)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* when generating the MPEG-4 anchors, rate control was started
after 70% of the sequence was finished.
Set start_rate_control with option "-R <n>" */
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
pic->QUANT = FrameUpdateQP(total_bits->total + intra_bits->total,
bits->total / (pic->PB?2:1),
(end-frame_no) / chosen_frameskip + PPFlag,
QP, targetrate, seconds);
frameskip = chosen_frameskip;
#endif
//先不看PB
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pic->PB) {
if (write_repeated)
wcopies = pdist;
for (i = 0; i < wcopies; i++)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) WriteImage(B_recon,outputfile); /**//* write wcopies frames to disk */
ComputeSNR(B_image, B_recon, res, writediff);
fprintf(stdout,"Results for B-frame:\n");
AddRes(b_res,res,pic);
PrintSNR(res, 1);
FreeImage(B_image);
FreeImage(B_recon);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//跳过的帧在写输出文件时拷贝回来.
if (write_repeated)
wcopies = (pb_frames ? bdist : frameskip);
for (i = 0; i < wcopies; i++)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) WriteImage(curr_recon,outputfile); /**//* write wcopies frames to disk */
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
if (pb_frames)
pic->PB = 1;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//计算信噪比登参数
ComputeSNR(curr_image, curr_recon, res, writediff);
fprintf(stdout,"Results for P-frame:\n");
AddRes(total_res,res,pic);
PrintSNR(res, 1);
PrintResult(bits, 1, 1);
FreeImage(prev_image);
FreeImage(prev_recon);
fflush(stdout);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//***** end of main loop *****/
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Closing files */
fclose (streamfile);
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (trace) {
fclose(tf);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Print total results */
//total_frames_passed是这么吗,扣掉first_frameskip,
//那中间那些被跳过的帧呢?
//这一条和上面的那一条
//"seconds = (end - start + chosen_frameskip) * orig_frameskip/ ref_frame_rate;"
//都想不明白.
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//从fprintf(stdout,"Frames saved : %d predicted + %d intra\n",
// total_frames_passed,icopies);
//这名话推测total_frames_passed是没有包话前面的I帧以及它的拷贝帧的.
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
//要如下的数合理,只能是frames, bframes, pframes, total_frames_passed 都按重0算起
total_frames_passed = frame_no - start - first_frameskip;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"\n==== TOTAL ====\n");
fprintf(stdout,"for %d images of %s\n", frames, seqfilename);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (frames != 0) {
if (write_repeated)
fprintf(stdout,"Frames saved : %d predicted + %d intra\n",
total_frames_passed,icopies);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"--------------\n");
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (pb_frames && bframes != 0) {
fprintf(stdout,"SNR for %d B-frames:\n",bframes);
PrintSNR(b_res,bframes);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"SNR for %d P-frames:\n",pframes);
PrintSNR(total_res,pframes);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
PrintResult(total_bits, pframes, frames);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
if (targetrate != 0 || pic->bit_rate != 0)
fprintf(stdout,"Original seq time: %.2f (%.2f) sec\n",
(total_frames_passed + first_frameskip) /
ref_frame_rate * orig_frameskip,
total_frames_passed /
ref_frame_rate * orig_frameskip);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"Mean quantizer : %.2f\n", total_res->QP_mean/pframes);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
#if 0
fprintf(stdout,"Total frames : %3d (%3d)\n",
total_frames_passed + first_frameskip,
total_frames_passed);
#endif
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"Encoded frames : %3d (%3d)\n",
frames + 1,
frames);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
mean_frame_rate = frames / (float)total_frames_passed *
ref_frame_rate / (float)orig_frameskip;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"Mean frame rate : %.2f Hz\n", mean_frame_rate);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
if (targetrate != 0)
fprintf(stdout,"Target bit rate : %.2f kbit/sec\n",
targetrate/1000.0);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"Obtained bit rate: %.2f (%.2f) kbit/sec\n",
(total_bits->total + intra_bits->total) /
((total_frames_passed + first_frameskip) /
ref_frame_rate * orig_frameskip)/1000.0,
(total_bits->total / (float)frames) * mean_frame_rate/1000.0);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
fprintf(stdout,"============================================\n");
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
}
#if 0
fprintf(stdout,"Total number of bits: %d (%d)\n",
total_bits->total + intra_bits->total,
(total_bits->total + intra_bits->total) / 8);
#endif
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Free memory */
FreeImage(curr_recon);
FreeImage(curr_image);
free(streamname);
free(seqfilename);
free(outputfile);
free(tracefile);
free(bits);
free(total_bits);
free(intra_bits);
free(res);
free(total_res);
free(b_res);
free(pic);
exit(0);
}
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//**********************************************************************
*
* Name: NextTwoPB
* Description: Decides whether or not to code the next
* two images as PB
* Speed: This is not a very smart solution considering
* the encoding speed, since motion vectors
* have to be calculation several times. It
* can be done together with the normal
* motion vector search, or a tree search
* instead of a full search can be used.
*
* Input: pointers to previous image, potential B-
* and P-image, frame distances
* Returns: 1 for yes, 0 otherwise
* Side effects:
*
* Date: 950824 Author: Karl.Lillevold@nta.no
*
***********************************************************************/
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
int NextTwoPB(PictImage *next2, PictImage *next1, PictImage *prev,
int bskip, int pskip, int seek_dist)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cnitblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
int adv_is_on = 0, mof_is_on = 0, lv_is_on = 0;
int psad1, psad2, bsad, psad;
MotionVector *MV[6][MBR+1][MBC+2];
MotionVector *mvp, *mvbf, *mvbb;
int x,y;
int i,j,k,tmp;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Temporarily disable some options to simplify motion estimation */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (advanced) {
advanced = OFF;
adv_is_on = ON;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (mv_outside_frame) {
mv_outside_frame = OFF;
mof_is_on = ON;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (long_vectors) {
long_vectors = OFF;
lv_is_on = ON;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
for (j = 1; j <= (lines>>4); j++)
for (i = 1; i <= (pels>>4); i++)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for (k = 0; k < 3; k++) {
MV[k][j][i] = (MotionVector *)calloc(1,sizeof(MotionVector));
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* calloc to avoid Checker warnings about reading of
unitizalized memory in the memcpy's below */
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
mvbf = (MotionVector *)malloc(sizeof(MotionVector));
mvbb = (MotionVector *)malloc(sizeof(MotionVector));
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
psad = 0;
psad1 = 0;
psad2 = 0;
bsad = 0;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* Integer motion estimation */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for ( j = 1; j < lines/MB_SIZE - 1; j++) {
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) for ( i = 1; i < pels/MB_SIZE - 1 ; i++) {
x = i*MB_SIZE;
y = j*MB_SIZE;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* picture order: prev -> next1 -> next2 */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* next1 and next2 can be coded as PB or PP */
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* prev is the previous encoded picture */
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* computes vectors (prev <- next2) */
MotionEstimation(next2->lum,prev->lum,x,y,0,0,seek_dist,MV,&tmp);
if (MV[0][j+1][i+1]->x == 0 && MV[0][j+1][i+1]->y == 0)
MV[0][j+1][i+1]->min_error += PREF_NULL_VEC;
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* not necessary to prefer zero vector here */
memcpy(MV[2][j+1][i+1],MV[0][j+1][i+1],sizeof(MotionVector));
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* computes sad(prev <- next1) */
MotionEstimation(next1->lum,prev->lum,x,y,0,0,seek_dist,MV,&tmp);
if (MV[0][j+1][i+1]->x == 0 && MV[0][j+1][i+1]->y == 0)
MV[0][j+1][i+1]->min_error += PREF_NULL_VEC;
memcpy(MV[1][j+1][i+1],MV[0][j+1][i+1],sizeof(MotionVector));
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* computes vectors for (next1 <- next2) */
MotionEstimation(next2->lum,next1->lum,x,y,0,0,seek_dist,MV,&tmp);
if (MV[0][j+1][i+1]->x == 0 && MV[0][j+1][i+1]->y == 0)
MV[0][j+1][i+1]->min_error += PREF_NULL_VEC;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* scales vectors for (prev <- next2 ) */
mvp = MV[2][j+1][i+1];
mvbf->x = bskip * mvp->x / (bskip + pskip);
mvbb->x = - pskip * mvp->x / (bskip + pskip);
mvbf->y = bskip * mvp->y / (bskip + pskip);
mvbb->y = - pskip * mvp->y / (bskip + pskip);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
psad1 += MV[0][j+1][i+1]->min_error;
psad2 += MV[1][j+1][i+1]->min_error;
psad += mvp->min_error;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* computes sad(prev <- next1 -> next2) */
bsad += SAD_MB_Bidir(next1->lum + x + y*pels,
next2->lum + x + mvbb->x + (y + mvbb->y)*pels,
prev->lum + x + mvbf->x + (y + mvbf->y)*pels,
pels, INT_MAX);
}
}
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
for (j = 1; j <= (lines>>4); j++)
for (i = 1; i <= (pels>>4); i++)
for (k = 0; k < 3; k++)
free(MV[k][j][i]);
free(mvbf);
free(mvbb);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* restore advanced parameters */
advanced = adv_is_on;
mv_outside_frame = mof_is_on;
long_vectors = lv_is_on;
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//* do the decision */
if (bsad < (psad1+psad2)/2)
fprintf(stdout,"Chose PB - bsad %d, psad %d\n",
bsad, (psad1+psad2)/2);
else
fprintf(stdout,"Chose PP - bsad %d, psad %d\n",
bsad, (psad1+psad2)/2);
![](http://www.cnitblog.com/Images/OutliningIndicators/InBlock.gif)
if (bsad < (psad1 + psad2)/2)
return 1;
else
return 0;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//**********************************************************************
*
* Name: Help
* Description: Prints usage
*
*
***********************************************************************/
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
void Help()
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cnitblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
fprintf(stdout,"Usage:\ttmn [options] -i <filename> [more options]\n");
fprintf(stdout,"Options:\n");
fprintf(stdout,"\t-i <filename> original sequence [required parameter]\n");
fprintf(stdout,"\t-o <filename> reconstructed frames [%s]\n",
DEF_OUTFILENAME);
fprintf(stdout,"\t-B <filename> filename for bitstream [%s]\n",
DEF_STREAMNAME);
fprintf(stdout,"\t-a <n> image to start at [%d]\n",
DEF_START_FRAME);
fprintf(stdout,"\t-b <n> image to stop at [%d]\n",
DEF_STOP_FRAME);
fprintf(stdout,"\t-x <n> coding format [%d]\n",DEF_CODING_FORMAT);
fprintf(stdout,"\t-q <n> (1..31) quantization parameter QP [%d]\n",
DEF_INTER_QUANT);
fprintf(stdout,"\t-I <n> (1..31) QP for first frame [%d]\n",
DEF_INTRA_QUANT);
fprintf(stdout,"\t-r <n> target bitrate in bits/s, default is variable bitrate\n");
fprintf(stdout,"\t-S <n> frames to skip between each encoded frame [%d]\n",
DEF_FRAMESKIP);
fprintf(stdout,"\t-D use unrestricted motion vector mode (annex D) [%s]\n",
DEF_UMV_MODE ? "ON" : "OFF");
fprintf(stdout,"\t-E use syntax-based arithmetic coding (annex E) [%s]\n",
DEF_SAC_MODE ? "ON" : "OFF");
fprintf(stdout,"\t-F use advanced prediction mode (annex F) [%s]\n",
DEF_ADV_MODE ? "ON" : "OFF");
fprintf(stdout,"\t-G use PB-frames (annex G) [%s]\n",
DEF_PBF_MODE ? "ON" : "OFF");
fprintf(stdout,"\t-h Prints simple help\n");
fprintf(stdout,"\t-H Prints advanced help\n");
fprintf(stdout,"\n\tDefault filenames and other options in square brackets \n\tare chosen in config.h\n");
return;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
void AdvancedHelp()
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cnitblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
fprintf(stdout,"Usage:\ttmn [options] -i <filename> [more options]\n");
fprintf(stdout,"Options:\n");
fprintf(stdout,"\t-i <filename> original sequence [required parameter]\n");
fprintf(stdout,"\t-o <filename> reconstructed frames [%s]\n",
DEF_OUTFILENAME);
fprintf(stdout,"\t-B <filename> filename for bitstream [%s]\n",
DEF_STREAMNAME);
fprintf(stdout,"\t-a <n> image to start at [%d]\n",
DEF_START_FRAME);
fprintf(stdout,"\t-b <n> image to stop at [%d]\n",
DEF_STOP_FRAME);
fprintf(stdout,"\t-x <n> coding format [%d]\n",DEF_CODING_FORMAT);
fprintf(stdout,"\t n=1: SQCIF n=2: QCIF n=3: CIF n=4: 4CIF n=5: 16CIF\n");
fprintf(stdout,"\t 128x96 176x144 352x288 704x576 1408x1152\n");
fprintf(stdout,"\t-s <n> (0..15) integer pel search window [%d]\n",
DEF_SEEK_DIST);
fprintf(stdout,"\t-q <n> (1..31) quantization parameter QP [%d]\n",
DEF_INTER_QUANT);
fprintf(stdout,"\t-I <n> (1..31) QP for first frame [%d]\n",
DEF_INTRA_QUANT);
fprintf(stdout,"\t-r <n> target bitrate in bits/s, default is variable bitrate\n");
#ifdef OFFLINE_RATE_CONTROL
fprintf(stdout,"\t -R <n> start rate control after n%% of sequence [%d]\n",
DEF_START_RATE_CONTROL);
#else
fprintf(stdout,"\t -R <f> target frame rate [%.2f]\n",
DEF_TARGET_FRAME_RATE);
#endif
fprintf(stdout,"\t-S <n> frames to skip between each encoded frame [%d]\n",
DEF_FRAMESKIP);
fprintf(stdout,"\t-Z <n> reference frame rate (25 or 30 fps) [%.1f]\n",
DEF_REF_FRAME_RATE);
fprintf(stdout,"\t-O <n> frames skipped in original compared to reference frame rate [%d]\n", DEF_ORIG_SKIP);
fprintf(stdout,"\t-e <n> original sequence has n bytes header [%d]\n",
DEF_HEADERLENGTH);
fprintf(stdout,"\t-g <n> insert sync after each n GOB (slice) [%d]\n",
DEF_INSERT_SYNC);
fprintf(stdout,"\t zero above means no extra syncs inserted\n");
fprintf(stdout,"\t-w write difference image to file \"%s\" [%s]\n",
DEF_DIFFILENAME,
DEF_WRITE_DIFF ? "ON" : "OFF");
fprintf(stdout,"\t-m write repeated reconstructed frames to disk [%s]\n",
DEF_WRITE_REPEATED ? "ON" : "OFF");
fprintf(stdout,"\t-t write trace to tracefile trace.intra/trace [%s]\n",
DEF_WRITE_TRACE ? "ON" : "OFF");
fprintf(stdout,"\t-D use unrestricted motion vector mode (annex D) [%s]\n",
DEF_UMV_MODE ? "ON" : "OFF");
fprintf(stdout,"\t-E use syntax-based arithmetic coding (annex E) [%s]\n",
DEF_SAC_MODE ? "ON" : "OFF");
fprintf(stdout,"\t-F use advanced prediction mode (annex F) [%s]\n",
DEF_ADV_MODE ? "ON" : "OFF");
fprintf(stdout,"\t-G use PB-frames (annex G) [%s]\n",
DEF_PBF_MODE ? "ON" : "OFF");
fprintf(stdout,"\t -Q <n> (0..3) BQUANT parameter [%d]\n",DEF_BQUANT);
fprintf(stdout,"\t-h Prints simple help\n");
fprintf(stdout,"\t-H Prints advanced help\n");
fprintf(stdout,"\n\tDefault filenames and other options in square brackets \n\tare chosen in config.h\n");
return;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) /**//**********************************************************************
*
* Name: PrintResult
* Description: add bits and prints results
*
* Input: Bits struct
*
* Returns:
* Side effects:
*
* Date: 940116 Author: Karl.Lillevold@nta.no
*
***********************************************************************/
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
void PrintResult(Bits *bits,int num_units, int num)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cnitblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
fprintf(stdout,"# intra : %d\n", bits->no_intra/num_units);
fprintf(stdout,"# inter : %d\n", bits->no_inter/num_units);
fprintf(stdout,"# inter4v : %d\n", bits->no_inter4v/num_units);
fprintf(stdout,"--------------\n");
fprintf(stdout,"Coeff_Y: %d\n", bits->Y/num);
fprintf(stdout,"Coeff_C: %d\n", bits->C/num);
fprintf(stdout,"Vectors: %d\n", bits->vec/num);
fprintf(stdout,"CBPY : %d\n", bits->CBPY/num);
fprintf(stdout,"MCBPC : %d\n", bits->CBPCM/num);
fprintf(stdout,"MODB : %d\n", bits->MODB/num);
fprintf(stdout,"CBPB : %d\n", bits->CBPB/num);
fprintf(stdout,"COD : %d\n", bits->COD/num);
fprintf(stdout,"DQUANT : %d\n", bits->DQUANT/num);
fprintf(stdout,"header : %d\n", bits->header/num);
fprintf(stdout,"==============\n");
fprintf(stdout,"Total : %d\n", bits->total/num);
fprintf(stdout,"\n");
return;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
void PrintSNR(Results *res, int num)
![](http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cnitblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
fprintf(stdout,"SNR_Y : %.2f\n", res->SNR_l/num);
fprintf(stdout,"SNR_Cb : %.2f\n", res->SNR_Cb/num);
fprintf(stdout,"SNR_Cr : %.2f\n", res->SNR_Cr/num);
fprintf(stdout,"--------------\n");
return;
}
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cnitblog.com/Images/OutliningIndicators/None.gif)
Feedback
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2008-11-27 23:37 by
你好,看了你这篇.我是用的tmn3.0的编译后对其中的一个yuv文件编码得到的263文件播放没有任何东西,还有想问下,用这个编码后的我想保存为一个通用文件格式,比如3gp,不知你有没有什么好的方法
email :liyigang86@163.com
没有找到你的邮箱不好意思
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2008-12-04 11:19 by
@李肖
用tmn编码后,你得到的只是H263编码流,和我们一般说的视频文件还是有差别的,视频文件会对编码流再封装。当前流行的播放器好像都不能直接播发H263,H263一般只用在网络视频转输上,如VOIP等网络视频应用。看到你的回复后,我查了查3GP格式,现在H263转3GP的你能用FFMPEG来转。因为H263(或者H264编码流)一般不会直接保存为通用视频文件格式,所以它的转换器是很少的,或者说没有。我不知道你最终想研究的是H263还是3GP,如果是H263的话,一般不会找所谓的播放器,而是自己做软件,解码你可以用TMNDEC库。
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2008-12-04 22:58 by
我正在做的是个录像的,在wince下的,只找到h263这个能在这个平台下用的,其他的编码库像xvid,以及你说的ffmpeg我都没有移植成功(编译是过了,但没办法调用生成的库,呵呵).
h263的我只找到一个是这个tmn3.0的,还有一个是libr263的,但都没有编码成功,特别是tmn3.0的用那个demo程序在vc下编译运行生成的文件没有任何东西,不知是什么原因,能否说下
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释[未登录] 回复 更多评论
2008-12-14 21:35 by
@李肖
我window下我们一般会用Direct X进行视频开发的,我不知Win
CE是否这样。我是用linux的,不好意思。“特别是tmn3.0的用那个demo程序在vc下编译运行生成的文件没有任何东西”你是指生成不了程序还是生成的程序不能用?
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2008-12-14 22:52 by
没有任何东西我是指对一个原始的码流编码生成的.263文件,是空的,可否把你在linux下的用的makfile文件发给我看下吗,不过如果可以的话,最好能把你用的这个版本也的源码也发过来用下,因为我手上是3.0的,我比较了下,有点不一样
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2009-03-30 20:34 by
你好,我在研究TMN2.0时候发现encode中的io.c文件似乎有问题,类似
im_file = fopen(tmp_Y,"rb");
这样的语句在逻辑和语言上都有问题,如果有时间,希望能得要你的看法.
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2009-04-27 21:04 by
@GKK
我的TMN2.0代码没有encode这个文件夹呀,io.c也没有这条语句。一方面你看看你你的代码是不是官方的。另外一方面我再找找原码包看看(我现在看的时原来解在好的).
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2009-09-10 16:54 by
刚刚接触h.263,请问yuv视频流,用tmn3 encode编码成什么格式的文件才能用tmn decode 解码?谢谢!
# re: H.263 视频 标准编码库 TMN2.0EDemo程序中文注释 回复 更多评论
2009-12-21 15:43 by
看到楼主的 文章 很有用~
最近 在研究Mobile ppc 摄像头拍摄后直接编码成h263
请问楼主 或者其他朋友能提供一个 Tmn/tmndec2.0库源码下载地址么? email给我也行 先谢谢了 email:cnp12@163.com
|