void CJOCh264bitstream::add4bytesnoemulationprevention (unsigned int nVal, bool bDoAlign) { //Used to add NAL header stream //Remember: NAL header is byte oriented if (bDoAlign == true) dobytealign(); if ((m_nLastbitinbuffer % 8) != 0) throw "Error: Save to file must be byte aligned"; while (m_nLastbitinbuffer != 0) savebufferbyte(); unsigned char cbyte = (nVal & 0xFF000000)>>24; fwrite(&cbyte, 1, 1, m_pOutFile); cbyte = (nVal & 0x00FF0000)>>16; fwrite(&cbyte, 1, 1, m_pOutFile); cbyte = (nVal & 0x0000FF00)>>8; fwrite(&cbyte, 1, 1, m_pOutFile); cbyte = (nVal & 0x000000FF); fwrite(&cbyte, 1, 1, m_pOutFile); }
//Creates and saves the NAL PPS (one per file) void CJOCh264encoder::create_pps () { add4bytesnoemulationprevention (0x000001); // NAL header addbits (0x0,1); // forbidden_bit addbits (0x3,2); // nal_ref_idc addbits (0x8,5); // nal_unit_type : 8 ( PPS ) addexpgolombunsigned(0); // pic_parameter_set_id addexpgolombunsigned(0); // seq_parameter_set_id addbits (0x0,1); // entropy_coding_mode_flag addbits (0x0,1); // bottom_field_pic_order_in frame_present_flag addexpgolombunsigned(0); // nun_slices_groups_minus1 addexpgolombunsigned(0); // num_ref_idx10_default_active_minus addexpgolombunsigned(0); // num_ref_idx11_default_active_minus addbits (0x0,1); // weighted_pred_flag addbits (0x0,2); // weighted_bipred_idc addexpgolombsigned(0); // pic_init_qp_minus26 addexpgolombsigned(0); // pic_init_qs_minus26 addexpgolombsigned(0); // chroma_qp_index_offset addbits (0x0,1); //deblocking_filter_present_flag addbits (0x0,1); // constrained_intra_pred_flag addbits (0x0,1); //redundant_pic_ent_present_flag addbits(0x1,1); // rbsp stop bit dobytealign(); }
void CJOCh264bitstream::close() { //Flush the data in stream buffer dobytealign(); while (m_nLastbitinbuffer != 0) savebufferbyte(); }
//Codifies & save the video frame (it only uses 16x16 intra PCM -> NO COMPRESSION!) void CJOCh264encoder::CodeAndSaveFrame() { //The slice header is not byte aligned, so the first macroblock header is not byte aligned create_slice_header (m_lNumFramesAdded); //Loop over macroblock size unsigned int y,x; for (y = 0; y < m_frame.nYheight / m_frame.nYmbheight; y++) { for (x = 0; x < m_frame.nYwidth / m_frame.nYmbwidth; x++) { create_macroblock(y, x); } } create_slice_footer(); dobytealign(); m_lNumFramesAdded++; }
//Creates & saves a macroblock (coded INTRA 16x16) void CJOCh264encoder::create_macroblock(unsigned int nYpos, unsigned int nXpos) { unsigned int x,y; create_macroblock_header(); dobytealign(); //Y unsigned int nYsize = m_frame.nYwidth * m_frame.nYheight; for(y = nYpos * m_frame.nYmbheight; y < (nYpos+1) * m_frame.nYmbheight; y++) { for (x = nXpos * m_frame.nYmbwidth; x < (nXpos+1) * m_frame.nYmbwidth; x++) { addbyte (m_frame.yuv420pframe.pYCbCr[(y * m_frame.nYwidth + x)]); } } //Cb unsigned int nCsize = m_frame.nCwidth * m_frame.nCheight; for(y = nYpos * m_frame.nCmbheight; y < (nYpos+1) * m_frame.nCmbheight; y++) { for (x = nXpos * m_frame.nCmbwidth; x < (nXpos+1) * m_frame.nCmbwidth; x++) { addbyte(m_frame.yuv420pframe.pYCbCr[nYsize + (y * m_frame.nCwidth + x)]); } } //Cr for(y = nYpos * m_frame.nCmbheight; y < (nYpos+1) * m_frame.nCmbheight; y++) { for (x = nXpos * m_frame.nCmbwidth; x < (nXpos+1) * m_frame.nCmbwidth; x++) { addbyte(m_frame.yuv420pframe.pYCbCr[nYsize + nCsize + (y * m_frame.nCwidth + x)]); } } }
//Creates and saves the NAL SPS (including VUI) (one per file) void CJOCh264encoder::create_sps (int nImW, int nImH, int nMbW, int nMbH, int nFps, int nSARw, int nSARh) { add4bytesnoemulationprevention (0x000001); // NAL header addbits (0x0,1); // forbidden_bit addbits (0x3,2); // nal_ref_idc addbits (0x7,5); // nal_unit_type : 7 ( SPS ) addbits (0x42,8); // profile_idc = baseline ( 0x42 ) addbits (0x0,1); // constraint_set0_flag addbits (0x0,1); // constraint_set1_flag addbits (0x0,1); // constraint_set2_flag addbits (0x0,1); // constraint_set3_flag addbits (0x0,1); // constraint_set4_flag addbits (0x0,1); // constraint_set5_flag addbits (0x0,2); // reserved_zero_2bits /* equal to 0 */ addbits (0x0a,8); // level_idc: 3.1 (0x0a) addexpgolombunsigned(0); // seq_parameter_set_id addexpgolombunsigned(0); // log2_max_frame_num_minus4 addexpgolombunsigned(0); // pic_order_cnt_type addexpgolombunsigned(0); // log2_max_pic_order_cnt_lsb_minus4 addexpgolombunsigned(0); // max_num_refs_frames addbits(0x0,1); // gaps_in_frame_num_value_allowed_flag int nWinMbs = nImW / nMbW; addexpgolombunsigned(nWinMbs-1); // pic_width_in_mbs_minus_1 int nHinMbs = nImH / nMbH; addexpgolombunsigned(nHinMbs-1); // pic_height_in_map_units_minus_1 addbits(0x1,1); // frame_mbs_only_flag addbits(0x0,1); // direct_8x8_interfernce addbits(0x0,1); // frame_cropping_flag addbits(0x1,1); // vui_parameter_present //VUI parameters (AR, timming) addbits(0x1,1); //aspect_ratio_info_present_flag addbits(0xFF,8); //aspect_ratio_idc = Extended_SAR //AR addbits(nSARw, 16); //sar_width addbits(nSARh, 16); //sar_height addbits(0x0,1); //overscan_info_present_flag addbits(0x0,1); //video_signal_type_present_flag addbits(0x0,1); //chroma_loc_info_present_flag addbits(0x1,1); //timing_info_present_flag unsigned int nnum_units_in_tick = TIME_SCALE_IN_HZ / (2*nFps); addbits(nnum_units_in_tick,32); //num_units_in_tick addbits(TIME_SCALE_IN_HZ,32); //time_scale addbits(0x1,1); //fixed_frame_rate_flag addbits(0x0,1); //nal_hrd_parameters_present_flag addbits(0x0,1); //vcl_hrd_parameters_present_flag addbits(0x0,1); //pic_struct_present_flag addbits(0x0,1); //bitstream_restriction_flag //END VUI addbits(0x0,1); // frame_mbs_only_flag addbits(0x1,1); // rbsp stop bit dobytealign(); }