mpeg2coder.cc
来自「Motion JPEG编解码器源代码」· CC 代码 · 共 874 行 · 第 1/2 页
CC
874 行
/* mpeg2coder.hh - MPEG2 packed bit / VLC syntax coding engine *//* (C) 2003 Andrew Stevens *//* This Software and modifications to existing software are free * software; you can redistribute them and/or modify it under the terms * of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * *//* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. *//* * Disclaimer of Warranty * * These software programs are available to the user without any license fee or * royalty on an "as is" basis. The MPEG Software Simulation Group 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. * * The MPEG Software Simulation Group does not represent or warrant that the * programs furnished hereunder are free of infringement of any third-party * patents. * * Commercial implementations of MPEG-1 and MPEG-2 video, 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. * */#include <config.h>#include <stdio.h>#include <math.h>#include <cassert>#include "mpeg2syntaxcodes.h"#include "tables.h"#include "mpeg2coder.hh"#include "elemstrmwriter.hh"#include "mpeg2encoder.hh"#include "picture.hh"MPEG2CodingBuf::MPEG2CodingBuf( EncoderParams &_encparams, ElemStrmWriter &_writer ) : ElemStrmFragBuf( _writer ), encparams( _encparams ){}/* convert frame number to time_code * * drop_frame not implemented */int MPEG2CodingBuf::FrameToTimeCode(int gop_timecode0_frame){ int frame = gop_timecode0_frame; int fps, pict, sec, minute, hour, tc; /* Note: no drop_frame_flag support here, so we're simply rounding the frame rate as per 6.3.8 13818-2 */ fps = (int)(encparams.decode_frame_rate+0.5); pict = frame%fps; frame = (frame-pict)/fps; sec = frame%60; frame = (frame-sec)/60; minute = frame%60; frame = (frame-minute)/60; hour = frame%24; tc = (hour<<19) | (minute<<13) | (1<<12) | (sec<<6) | pict; return tc;}/**************** * * generate sequence header (6.2.2.1, 6.3.3) * ***************/void MPEG2CodingBuf::PutSeqHdr(){ int i; assert( Aligned() ); PutBits(SEQ_START_CODE,32); /* sequence_header_code */ PutBits(encparams.horizontal_size,12); /* horizontal_size_value */ PutBits(encparams.vertical_size,12); /* vertical_size_value */ PutBits(encparams.aspectratio,4); /* aspect_ratio_information */ PutBits(encparams.frame_rate_code,4); /* frame_rate_code */ /* MPEG-1 VBR is FFFF rate code. MPEG-2 VBR is a matter of mux-ing. The ceiling bit_rate is always sent */ if(encparams.mpeg1 && (encparams.quant_floor != 0 || encparams.still_size > 0) ) { PutBits(0xfffff,18); } else { PutBits((int)ceil(encparams.bit_rate/400.0),18); /* bit_rate_value */ } PutBits(1,1); /* marker_bit */ PutBits(encparams.vbv_buffer_code,10); /* vbv_buffer_size_value */ PutBits(encparams.constrparms,1); /* constrained_parameters_flag */ PutBits(encparams.load_iquant,1); /* load_intra_quantizer_matrix */ if (encparams.load_iquant) for (i=0; i<64; i++) /* matrices are always downloaded in zig-zag order */ PutBits(encparams.intra_q[zig_zag_scan[i]],8); /* intra_quantizer_matrix */ PutBits(encparams.load_niquant,1); /* load_non_intra_quantizer_matrix */ if (encparams.load_niquant) for (i=0; i<64; i++) PutBits(encparams.inter_q[zig_zag_scan[i]],8); /* non_intra_quantizer_matrix */ if (!encparams.mpeg1) { PutSeqExt(); PutSeqDispExt(); } AlignBits();}/************************** * * generate sequence extension (6.2.2.3, 6.3.5) header (MPEG-2 only) * *************************/void MPEG2CodingBuf::PutSeqExt(){ assert( Aligned() ); PutBits(EXT_START_CODE,32); /* extension_start_code */ PutBits(SEQ_ID,4); /* extension_start_code_identifier */ PutBits((encparams.profile<<4)|encparams.level,8); /* profile_and_level_indication */ PutBits(encparams.prog_seq,1); /* progressive sequence */ PutBits(CHROMA420,2); /* chroma_format */ PutBits(encparams.horizontal_size>>12,2); /* horizontal_size_extension */ PutBits(encparams.vertical_size>>12,2); /* vertical_size_extension */ PutBits(((int)ceil(encparams.bit_rate/400.0))>>18,12); /* bit_rate_extension */ PutBits(1,1); /* marker_bit */ PutBits(encparams.vbv_buffer_code>>10,8); /* vbv_buffer_size_extension */ PutBits(0,1); /* low_delay -- currently not implemented */ PutBits(0,2); /* frame_rate_extension_n */ PutBits(0,5); /* frame_rate_extension_d */ AlignBits();}/***************************** * * generate sequence display extension (6.2.2.4, 6.3.6) * ****************************/void MPEG2CodingBuf::PutSeqDispExt(){ assert(Aligned() ); PutBits(EXT_START_CODE,32); /* extension_start_code */ PutBits(DISP_ID,4); /* extension_start_code_identifier */ PutBits(encparams.video_format,3); /* video_format */ PutBits(1,1); /* colour_description */ PutBits(encparams.color_primaries,8); /* colour_primaries */ PutBits(encparams.transfer_characteristics,8); /* transfer_characteristics */ PutBits(encparams.matrix_coefficients,8); /* matrix_coefficients */ PutBits(encparams.display_horizontal_size,14); /* display_horizontal_size */ PutBits(1,1); /* marker_bit */ PutBits(encparams.display_vertical_size,14); /* display_vertical_size */ AlignBits();}/******************************** * * Output user data (6.2.2.2.2, 6.3.4.1) * * TODO: string must not embed start codes 0x00 0x00 0x00 0xXX * *******************************/void MPEG2CodingBuf::PutUserData(const uint8_t *userdata, int len){ int i; assert( Aligned() ); PutBits(USER_START_CODE,32); /* user_data_start_code */ for( i =0; i < len; ++i ) PutBits(userdata[i],8);}/* generate group of pictures header (6.2.2.6, 6.3.9) * * uses tc0 (timecode of first frame) and frame0 (number of first frame) */void MPEG2CodingBuf::PutGopHdr(int frame,int closed_gop ){ int tc; AlignBits(); PutBits(GOP_START_CODE,32); /* group_start_code */ tc = FrameToTimeCode(frame); PutBits(tc,25); /* time_code */ PutBits(closed_gop,1); /* closed_gop */ PutBits(0,1); /* broken_link */ AlignBits();}/* generate sequence_end_code (6.2.2) */void MPEG2CodingBuf::PutSeqEnd(void){ AlignBits(); PutBits(SEQ_END_CODE,32);}/* generate variable length codes for an intra-coded block (6.2.6, 6.3.17) */void MPEG2CodingBuf::PutIntraBlk(Picture *picture, int16_t *blk, int cc){ int n, dct_diff, run, signed_level; /* DC coefficient (7.2.1) */ dct_diff = blk[0] - picture->dc_dct_pred[cc]; /* difference to previous block */ picture->dc_dct_pred[cc] = blk[0]; if (cc==0) PutDClum(dct_diff); else PutDCchrom(dct_diff); /* AC coefficients (7.2.2) */ run = 0; const uint8_t *scan_tbl = (picture->altscan ? alternate_scan : zig_zag_scan); for (n=1; n<64; n++) { /* use appropriate entropy scanning pattern */ signed_level = blk[scan_tbl[n]]; if (signed_level!=0) { PutAC(run,signed_level,picture->intravlc); run = 0; } else run++; /* count zero coefficients */ } /* End of Block -- normative block punctuation */ if (picture->intravlc) PutBits(6,4); /* 0110 (Table B-15) */ else PutBits(2,2); /* 10 (Table B-14) */}/* generate variable length codes for a non-intra-coded block (6.2.6, 6.3.17) */void MPEG2CodingBuf::PutNonIntraBlk(Picture *picture, int16_t *blk){ int n, run, signed_level, first; run = 0; first = 1; for (n=0; n<64; n++) { /* use appropriate entropy scanning pattern */ signed_level = blk[(picture->altscan ? alternate_scan : zig_zag_scan)[n]]; if (signed_level!=0) { if (first) { /* first coefficient in non-intra block */ PutACfirst(run,signed_level); first = 0; } else PutAC(run,signed_level,0); run = 0; } else run++; /* count zero coefficients */ } /* End of Block -- normative block punctuation */ PutBits(2,2);}/* generate variable length code for a motion vector component (7.6.3.1) */void MPEG2CodingBuf::PutMV(int dmv, int f_code){ int r_size, f, vmin, vmax, dv, temp, motion_code, motion_residual; r_size = f_code - 1; /* number of fixed length code ('residual') bits */ f = 1<<r_size; vmin = -16*f; /* lower range limit */ vmax = 16*f - 1; /* upper range limit */ dv = 32*f; /* fold vector difference into [vmin...vmax] */ if (dmv>vmax) dmv-= dv; else if (dmv<vmin) dmv+= dv; /* check value */ if (dmv<vmin || dmv>vmax) { fprintf(stderr,"Too large MV %03d not in [%04d..:%03d]\n", dmv, vmin, vmax); exit(1); } /* split dmv into motion_code and motion_residual */ temp = ((dmv<0) ? -dmv : dmv) + f - 1; motion_code = temp>>r_size; if (dmv<0) motion_code = -motion_code; motion_residual = temp & (f-1); PutMotionCode(motion_code); /* variable length code */ if (r_size!=0 && motion_code!=0) PutBits(motion_residual,r_size); /* fixed length code */}/* generate variable length code for DC coefficient (7.2.1) */void MPEG2CodingBuf::PutDC(const sVLCtable *tab, int val){ int absval, size; absval = abs(val); assert(absval<=encparams.dctsatlim); /* compute dct_dc_size */ size = 0; while (absval) { absval >>= 1; size++; } /* generate VLC for dct_dc_size (Table B-12 or B-13) */ PutBits(tab[size].code,tab[size].len); /* append fixed length code (dc_dct_differential) */ if (size!=0) { if (val>=0) absval = val; else absval = val + (1<<size) - 1; /* val + (2 ^ size) - 1 */ PutBits(absval,size); }}/* generate variable length code for DC coefficient (7.2.1) */int MPEG2CodingBuf::DC_bits(const sVLCtable *tab, int val){ int absval, size; absval = abs(val); /* compute dct_dc_size */ size = 0; while (absval) { absval >>= 1; size++; } /* generate VLC for dct_dc_size (Table B-12 or B-13) */ return tab[size].len+size;}/* generate variable length code for first coefficient * of a non-intra block (7.2.2.2) */void MPEG2CodingBuf::PutACfirst(int run, int val){ if (run==0 && (val==1 || val==-1)) /* these are treated differently */ PutBits(2|(val<0),2); /* generate '1s' (s=sign), (Table B-14, line 2) */ else PutAC(run,val,0); /* no difference for all others */}/* generate variable length code for other DCT coefficients (7.2.2) */void MPEG2CodingBuf::PutAC(int run, int signed_level, int vlcformat){ int level, len; const VLCtable *ptab = NULL; level = abs(signed_level); /* make sure run and level are valid */ if (run<0 || run>63 || level==0 || level>encparams.dctsatlim) { assert( signed_level == -(encparams.dctsatlim+1)); /* Negative range is actually 1 more */ } len = 0; if (run<2 && level<41) { /* vlcformat selects either of Table B-14 / B-15 */ if (vlcformat) ptab = &dct_code_tab1a[run][level-1]; else ptab = &dct_code_tab1[run][level-1]; len = ptab->len; } else if (run<32 && level<6) { /* vlcformat selects either of Table B-14 / B-15 */ if (vlcformat) ptab = &dct_code_tab2a[run-2][level-1]; else ptab = &dct_code_tab2[run-2][level-1]; len = ptab->len; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?