http://blog.csdn.net/u011298831/article/details/52119948
本文介绍Mp4v2的使用,成功将H264 ES文件和AAC文件封装成MP4文件
1. Mp4V2使用VS2013编译
studio9.0\下打开方案
一般情况,编译会出现错误
原因是缺少几个关键文件:vstudio9.0\libmp4v2\Version.rc
Libplatform\platform_win32_impl.h Libplatform\platform_win32.cpp
点击下载缺失文件(http://download.csdn.NET/download/u011298831/9594523):点击打开链接
下载文件放入响应位置即可成功编译,生成bin\目录下的相关文件
2. 新建项目Mux
这里给出一个MP4Encoder的封装类- /********************************************************************
- filename: MP4Encoder.h
- created: 2016-08-06
- author: Donyj
- purpose: MP4编码器,基于开源库mp4v2实现(https://code.google.com/p/mp4v2/)。
- *********************************************************************/
- #pragma once
- #include "mp4v2\mp4v2.h"
- // NALU单元
- typedef struct _MP4ENC_NaluUnit
- {
- int type;
- int size;
- unsigned char *data;
- }MP4ENC_NaluUnit;
- typedef struct _MP4ENC_Metadata
- {
- // video, must be h264 type
- unsigned int nSpsLen;
- unsigned char Sps[1024];
- unsigned int nPpsLen;
- unsigned char Pps[1024];
- } MP4ENC_Metadata, *LPMP4ENC_Metadata;
- class MP4Encoder
- {
- public:
- MP4Encoder(void);
- ~MP4Encoder(void);
- public:
- // open or creat a mp4 file.
- bool MP4FileOpen(const char *fileName, int width, int height, int timeScale = 90000, int frameRate = 25);
- // wirte 264 metadata in mp4 file.
- bool Write264Metadata(MP4FileHandle hMp4File, LPMP4ENC_Metadata lpMetadata);
- // wirte 264 data, data can contain multiple frame.
- int WriteH264Data(MP4FileHandle hMp4File, const unsigned char* pData, int size);
- // close mp4 file.
- void MP4FileClose();
- // convert H264 file OR aac file to mp4 file.
- bool MP4FileWrite(int(*read_h264)(unsigned char *buf, int buf_size), int(*read_aac)(unsigned char *buf, int buf_size));
- // Prase H264 metamata from H264 data frame
- static bool PraseMetadata(const unsigned char* pData, int size, MP4ENC_Metadata &metadata);
- private:
- // read one nalu from H264 data buffer
- static int ReadOneNaluFromBuf(const unsigned char *buffer, unsigned int nBufferSize, unsigned int offSet, MP4ENC_NaluUnit &nalu);
- private:
- int m_nWidth;
- int m_nHeight;
- double m_nFrameRate;
- int m_nTimeScale;
- MP4FileHandle m_hMp4File;
- MP4TrackId m_videoId;
- MP4TrackId m_audioId;
- };
本例存在使用默认已知参数的情况,读者可根据自己的情况修改参数,或者实时从数据中解析出来进行设置;一下是完整cpp文件:
- /********************************************************************
- filename: MP4Encoder.h
- created: 2016-08-06
- author: Donyj
- purpose: MP4编码器,基于开源库mp4v2实现(https://code.google.com/p/mp4v2/)。
- *********************************************************************/
- #include "MP4Encoder.h"
- //#include "sps_decode.h"
- #include <string.h>
- #include "sps_pps_parser.h"
- #include <stdio.h>
- #include <Windows.h>
- static double audio_tick_gap = (1024000.0) / (48000.0);
- static double video_tick_gap = (1000.0 + 1.0) / 30.0;
- static int sps_wt = 0; //确保sps已经 MP4AddH264SequenceParameterSet
- static int pps_wt = 0; //确保pps已经 MP4AddH264PictureParameterSet
- #define BUFFER_SIZE (1024*1024)
- #define FRAME_FRATE (30)
- #define TIME_SCALE (90000)
- MP4Encoder::MP4Encoder(void) :
- m_videoId(NULL),
- m_nWidth(0),
- m_nHeight(0),
- m_nTimeScale(TIME_SCALE),
- m_nFrameRate(FRAME_FRATE)
- {
- m_hMp4File = NULL;
- m_audioId = NULL;
- }
- MP4Encoder::~MP4Encoder(void)
- {
- if (m_hMp4File != NULL)
- {
- MP4Close(m_hMp4File);
- m_hMp4File = NULL;
- }
- }
- bool MP4Encoder::MP4FileOpen(const char *pFileName, int width, int height, int timeScale/* = 90000*/, int frameRate/* = 25*/)
- {
- if (pFileName == NULL)
- {
- return false;
- }
- // create mp4 file
- m_hMp4File = MP4Create(pFileName);
- if (m_hMp4File == MP4_INVALID_FILE_HANDLE)
- {
- printf("ERROR:Open file fialed.\n");
- return false;
- }
- m_nWidth = width;
- m_nHeight = height;
- m_nTimeScale = TIME_SCALE;
- m_nFrameRate = FRAME_FRATE;
- MP4SetTimeScale(m_hMp4File, m_nTimeScale);
- return true;
- }
- bool MP4Encoder::Write264Metadata(MP4FileHandle hMp4File, LPMP4ENC_Metadata lpMetadata)
- {
- m_videoId = MP4AddH264VideoTrack
- (hMp4File,
- m_nTimeScale,
- m_nTimeScale / m_nFrameRate,
- m_nWidth, // width
- m_nHeight,// height
- lpMetadata->Sps[1], // sps[1] AVCProfileIndication
- lpMetadata->Sps[2], // sps[2] profile_compat
- lpMetadata->Sps[3], // sps[3] AVCLevelIndication
- 3); // 4 bytes length before each NAL unit
- if (m_videoId == MP4_INVALID_TRACK_ID)
- {
- printf("add video track failed.\n");
- return false;
- }
- MP4SetVideoProfileLevel(hMp4File, 0x03); // Simple Profile @ Level 3
- // write sps
- MP4AddH264SequenceParameterSet(hMp4File, m_videoId, lpMetadata->Sps, lpMetadata->nSpsLen);
- // write pps
- MP4AddH264PictureParameterSet(hMp4File, m_videoId, lpMetadata->Pps, lpMetadata->nPpsLen);
- return true;
- }
- int MP4Encoder::WriteH264Data(MP4FileHandle hMp4File, const unsigned char* pData, int size)
- {
- if (hMp4File == NULL)
- {
- return -1;
- }
- if (pData == NULL)
- {
- return -1;
- }
- MP4ENC_NaluUnit nalu;
- int pos = 0, len = 0;
- int wt_frame = 0; //测试 - 单帧单Nalu发送
- while (len = ReadOneNaluFromBuf(pData, size, pos, nalu))
- {
- if (nalu.type == 0x07 && sps_wt == 0) // sps
- {
- //从sps pps中获取信息
- float fps = 0.0;
- //int ret = h264_decode_sps(nalu.data, nalu.size, &m_nWidth, &m_nHeight, &fps);
- get_bit_context buffer;
- memset(&buffer, 0, sizeof(get_bit_context));
- SPS _sps;
- buffer.buf = nalu.data + 1;
- buffer.buf_size = nalu.size - 1;
- int ret = h264dec_seq_parameter_set(&buffer, &_sps);
- m_nWidth = h264_get_width(&_sps);
- m_nHeight = h264_get_height(&_sps);
- ret = h264_get_framerate(&fps, &_sps);
- if (ret == 0)
- {
- m_nFrameRate = (double)fps;
- }
- video_tick_gap = (1000.0 + 1.0) / m_nFrameRate;
- // 添加h264 track
- m_videoId = MP4AddH264VideoTrack
- (hMp4File,
- m_nTimeScale,
- (double)m_nTimeScale / m_nFrameRate,
- m_nWidth, // width
- m_nHeight, // height
- nalu.data[1], // sps[1] AVCProfileIndication
- nalu.data[2], // sps[2] profile_compat
- nalu.data[3], // sps[3] AVCLevelIndication
- 3); // 4 bytes length before each NAL unit
- if (m_videoId == MP4_INVALID_TRACK_ID)
- {
- printf("add video track failed.\n");
- return 0;
- }
- MP4SetVideoProfileLevel(hMp4File, 1); // Simple Profile @ Level 3
- MP4AddH264SequenceParameterSet(hMp4File, m_videoId, nalu.data, nalu.size);
- sps_wt = 1;
- }
- else if (nalu.type == 0x08 && pps_wt == 0) // pps
- {
- MP4AddH264PictureParameterSet(hMp4File, m_videoId, nalu.data, nalu.size);
- pps_wt = 1;
- }
- else if (nalu.type == 0x01 || nalu.type == 0x05)
- {
- int datalen = nalu.size + 4;
- unsigned char *data = new unsigned char[datalen];
- // MP4 Nalu前四个字节表示Nalu长度
- data[0] = nalu.size >> 24;
- data[1] = nalu.size >> 16;
- data[2] = nalu.size >> 8;
- data[3] = nalu.size & 0xff;
- memcpy(data + 4, nalu.data, nalu.size);
- bool syn = 0;
- if (nalu.type == 0x05)
- {
- syn = 1;
- }
- //if (!MP4WriteSample(hMp4File, m_videoId, data, datalen, MP4_INVALID_DURATION, 0, syn))
- if (!MP4WriteSample(hMp4File, m_videoId, data, datalen, 90000 / 30, 0, syn))
- {
- return 0;
- }
- delete[] data;
- wt_frame++;
- }
- pos += len;
- if (wt_frame > 0)
- {
- break;
- }
- }
- return pos;
- }
- int MP4Encoder::ReadOneNaluFromBuf(const unsigned char *buffer, unsigned int nBufferSize, unsigned int offSet, MP4ENC_NaluUnit &nalu)
- {
- int i = offSet;
- while (i<nBufferSize)
- {
- if (buffer[i++] == 0x00 &&
- buffer[i++] == 0x00 &&
- buffer[i++] == 0x00 &&
- buffer[i++] == 0x01
- )
- {
- int pos = i;
- while (pos<nBufferSize)
- {
- if (buffer[pos++] == 0x00 &&
- buffer[pos++] == 0x00 &&
- buffer[pos++] == 0x00 &&
- buffer[pos++] == 0x01
- )
- {
- break;
- }
- }
- if (pos == nBufferSize)
- {
- nalu.size = pos - i;
- }
- else
- {
- nalu.size = (pos - 4) - i;
- }
- nalu.type = buffer[i] & 0x1f;
- nalu.data = (unsigned char*)&buffer[i];
- return (nalu.size + i - offSet);
- }
- }
- return 0;
- }
- void MP4Encoder::MP4FileClose()
- {
- if (m_hMp4File)
- {
- MP4Close(m_hMp4File);
- m_hMp4File = NULL;
- }
- }
- bool MP4Encoder::MP4FileWrite(int(*read_h264)(unsigned char *buf, int buf_size), int(*read_aac)(unsigned char *buf, int buf_size))
- {
- //添加aac音频 -- default init, you can get config information by parsering aac data if you want
- m_audioId = MP4AddAudioTrack(m_hMp4File, 48000, 1024, MP4_MPEG4_AUDIO_TYPE); //1024??? 这里不明白为什么用1024 希望有大神解释下
- if (m_audioId == MP4_INVALID_TRACK_ID)
- {
- printf("add audio track failed.\n");
- return false;
- }
- MP4SetAudioProfileLevel(m_hMp4File, 0x2);
- uint8_t buf3[2] = { 0x11, 0x88 }; //important! AAC config infomation; 读者应该根据使用的AAC数据分析出此数据,
- MP4SetTrackESConfiguration(m_hMp4File, m_audioId, buf3, 2);
- //--------------------------------------------------------------------
- unsigned char *buffer = new unsigned char[BUFFER_SIZE];
- unsigned char audioBuf[1024];
- int pos = 0;
- int readlen = 0;
- int writelen = 0;
- //--------------------------------------------------------------------
- uint32_t audio_tick_now, video_tick_now, last_update;
- unsigned int tick = 0;
- unsigned int audio_tick = 0;
- unsigned int video_tick = 0;
- uint32_t tick_exp_new = 0;
- uint32_t tick_exp = 0;
- //--------------------------------------------------------------------
- audio_tick_now = video_tick_now = GetTickCount();
- /*
- 尝试时间音视频间隔内去取得视频或者音频数据进行Write
- */
- while (1)
- {
- last_update = GetTickCount();
- //时间溢出情况处理
- if (read_h264 != NULL)
- {
- if (last_update - video_tick_now > video_tick_gap - tick_exp)
- {
- printf("now:%lld last_update:%lld video_tick:%d tick_exp:%d\n", video_tick_now, last_update, video_tick, tick_exp);
- video_tick += video_tick_gap;
- ///
- //-- 这里针对单帧单Nalu的情况处理, 若有差异,请读者自行修改
- readlen = read_h264(buffer + pos, BUFFER_SIZE - pos);
- if (readlen <= 0 && pos == 0)
- {
- break;
- }
- readlen += pos;
- //查找开始位 -- 确保存在Nalu起始位
- writelen = 0;
- for (int i = readlen; i >= 4; i--)
- {
- if (buffer[i - 1] == 0x01 &&
- buffer[i - 2] == 0x00 &&
- buffer[i - 3] == 0x00 &&
- buffer[i - 4] == 0x00
- )
- {
- writelen = i - 4; //???
- break;
- }
- }
- //单个NALU
- writelen = WriteH264Data(m_hMp4File, buffer, writelen);
- if (writelen <= 0)
- {
- break;
- }
- //剩余数据
- memcpy(buffer, buffer + writelen, readlen - writelen);
- pos = readlen - writelen;
- if (pos == 0)
- {
- break;
- }
- ///
- video_tick_now = GetTickCount();
- }
- }
- if (read_aac != NULL)
- {
- if (last_update - audio_tick_now > audio_tick_gap - tick_exp)
- {
- printf("now:%lld last_update:%lld audio_tick:%d tick_exp:%d\n", audio_tick_now, last_update, audio_tick, tick_exp);
- audio_tick += audio_tick_gap;
- /
- int audio_len = read_aac(audioBuf, 1024); //get aac header if you want , so that you can get aac config info
- if (audio_len <= 0)
- {
- break;
- }
- MP4WriteSample(m_hMp4File, m_audioId, audioBuf, audio_len, MP4_INVALID_DURATION, 0, 1);
- /
- audio_tick_now = GetTickCount();
- }
- }
- tick_exp_new = GetTickCount();
- tick_exp = tick_exp_new - last_update;
- //sleep
- }
- }
- bool MP4Encoder::PraseMetadata(const unsigned char* pData, int size, MP4ENC_Metadata &metadata)
- {
- if (pData == NULL || size<4)
- {
- return false;
- }
- MP4ENC_NaluUnit nalu;
- int pos = 0;
- bool bRet1 = false, bRet2 = false;
- while (int len = ReadOneNaluFromBuf(pData, size, pos, nalu))
- {
- if (nalu.type == 0x07)
- {
- memcpy(metadata.Sps, nalu.data, nalu.size);
- metadata.nSpsLen = nalu.size;
- bRet1 = true;
- }
- else if ((nalu.type == 0x08))
- {
- memcpy(metadata.Pps, nalu.data, nalu.size);
- metadata.nPpsLen = nalu.size;
- bRet2 = true;
- }
- pos += len;
- }
- if (bRet1 && bRet2)
- {
- return true;
- }
- return false;
- }
为了获取H264视频的帧率和分辨率,这里给出SPS解析的源码( 存在部分H264 ES文件无framerate 描述是,采用默认帧率进行处理 )
- /********************************************************************
- filename: sps_pps_parser.h
- created: 2016-08-06
- author: Donyj
- *********************************************************************/
- #ifndef _sps_pps_H_
- #define _sps_pps_H_
- //#include <stdint.h>
- #if defined (__cplusplus)
- extern "C" {
- #endif
- /***
- * Sequence parameter set
- * 可参考H264标准第7节和附录D E
- */
- #define Extended_SAR 255
- typedef struct vui_parameters{
- int aspect_ratio_info_present_flag; //0 u(1)
- int aspect_ratio_idc; //0 u(8)
- int sar_width; //0 u(16)
- int sar_height; //0 u(16)
- int overscan_info_present_flag; //0 u(1)
- int overscan_appropriate_flag; //0 u(1)
- int video_signal_type_present_flag; //0 u(1)
- int video_format; //0 u(3)
- int video_full_range_flag; //0 u(1)
- int colour_description_present_flag; //0 u(1)
- int colour_primaries; //0 u(8)
- int transfer_characteristics; //0 u(8)
- int matrix_coefficients; //0 u(8)
- int chroma_loc_info_present_flag; //0 u(1)
- int chroma_sample_loc_type_top_field; //0 ue(v)
- int chroma_sample_loc_type_bottom_field; //0 ue(v)
- int timing_info_present_flag; //0 u(1)
- uint32_t num_units_in_tick; //0 u(32)
- uint32_t time_scale; //0 u(32)
- int fixed_frame_rate_flag; //0 u(1)
- int nal_hrd_parameters_present_flag; //0 u(1)
- int cpb_cnt_minus1; //0 ue(v)
- int bit_rate_scale; //0 u(4)
- int cpb_size_scale; //0 u(4)
- int bit_rate_value_minus1[16]; //0 ue(v)
- int cpb_size_value_minus1[16]; //0 ue(v)
- int cbr_flag[16]; //0 u(1)
- int initial_cpb_removal_delay_length_minus1; //0 u(5)
- int cpb_removal_delay_length_minus1; //0 u(5)
- int dpb_output_delay_length_minus1; //0 u(5)
- int time_offset_length; //0 u(5)
- int vcl_hrd_parameters_present_flag; //0 u(1)
- int low_delay_hrd_flag; //0 u(1)
- int pic_struct_present_flag; //0 u(1)
- int bitstream_restriction_flag; //0 u(1)
- int motion_vectors_over_pic_boundaries_flag; //0 ue(v)
- int max_bytes_per_pic_denom; //0 ue(v)
- int max_bits_per_mb_denom; //0 ue(v)
- int log2_max_mv_length_horizontal; //0 ue(v)
- int log2_max_mv_length_vertical; //0 ue(v)
- int num_reorder_frames; //0 ue(v)
- int max_dec_frame_buffering; //0 ue(v)
- }vui_parameters_t;
- typedef struct SPS
- {
- int profile_idc;
- int constraint_set0_flag;
- int constraint_set1_flag;
- int constraint_set2_flag;
- int constraint_set3_flag;
- int reserved_zero_4bits;
- int level_idc;
- int seq_parameter_set_id; //ue(v)
- int chroma_format_idc; //ue(v)
- int separate_colour_plane_flag; //u(1)
- int bit_depth_luma_minus8; //0 ue(v)
- int bit_depth_chroma_minus8; //0 ue(v)
- int qpprime_y_zero_transform_bypass_flag; //0 u(1)
- int seq_scaling_matrix_present_flag; //0 u(1)
- int seq_scaling_list_present_flag[12];
- int UseDefaultScalingMatrix4x4Flag[6];
- int UseDefaultScalingMatrix8x8Flag[6];
- int ScalingList4x4[6][16];
- int ScalingList8x8[6][64];
- int log2_max_frame_num_minus4; //0 ue(v)
- int pic_order_cnt_type; //0 ue(v)
- int log2_max_pic_order_cnt_lsb_minus4; //
- int delta_pic_order_always_zero_flag; //u(1)
- int offset_for_non_ref_pic; //se(v)
- int offset_for_top_to_bottom_field; //se(v)
- int num_ref_frames_in_pic_order_cnt_cycle; //ue(v)
- int offset_for_ref_frame_array[16]; //se(v)
- int num_ref_frames; //ue(v)
- int gaps_in_frame_num_value_allowed_flag; //u(1)
- int pic_width_in_mbs_minus1; //ue(v)
- int pic_height_in_map_units_minus1; //u(1)
- int frame_mbs_only_flag; //0 u(1)
- int mb_adaptive_frame_field_flag; //0 u(1)
- int direct_8x8_inference_flag; //0 u(1)
- int frame_cropping_flag; //u(1)
- int frame_crop_left_offset; //ue(v)
- int frame_crop_right_offset; //ue(v)
- int frame_crop_top_offset; //ue(v)
- int frame_crop_bottom_offset; //ue(v)
- int vui_parameters_present_flag; //u(1)
- vui_parameters_t vui_parameters;
- }SPS;
- /***
- * Picture parameter set
- */
- typedef struct PPS
- {
- int pic_parameter_set_id;
- int seq_parameter_set_id;
- int entropy_coding_mode_flag;
- int pic_order_present_flag;
- int num_slice_groups_minus1;
- int slice_group_map_type;
- int run_length_minus1[32];
- int top_left[32];
- int bottom_right[32];
- int slice_group_change_direction_flag;
- int slice_group_change_rate_minus1;
- int pic_size_in_map_units_minus1;
- int slice_group_id[32];
- int num_ref_idx_10_active_minus1;
- int num_ref_idx_11_active_minus1;
- int weighted_pred_flag;
- int weighted_bipred_idc;
- int pic_init_qp_minus26;
- int pic_init_qs_minus26;
- int chroma_qp_index_offset;
- int deblocking_filter_control_present_flag;
- int constrained_intra_pred_flag;
- int redundant_pic_cnt_present_flag;
- int transform_8x8_mode_flag;
- int pic_scaling_matrix_present_flag;
- int pic_scaling_list_present_flag[32];
- int second_chroma_qp_index_offset;
- int UseDefaultScalingMatrix4x4Flag[6];
- int UseDefaultScalingMatrix8x8Flag[6];
- int ScalingList4x4[6][16];
- int ScalingList8x8[2][64];
- }PPS;
- typedef struct get_bit_context
- {
- uint8_t *buf; /*指向SPS start*/
- int buf_size; /*SPS 长度*/
- int bit_pos; /*bit已读取位置*/
- int total_bit; /*bit总长度*/
- int cur_bit_pos; /*当前读取位置*/
- }get_bit_context;
- int h264dec_seq_parameter_set(void *buf, SPS *sps_ptr);
- int h264dec_picture_parameter_set(void *buf, PPS *pps_ptr);
- int h264_get_width(SPS *sps_ptr);
- int h264_get_height(SPS *sps_ptr);
- int h264_get_format(SPS *sps_ptr);
- int h264_get_framerate(float *framerate, SPS *sps_ptr);
- typedef struct _sequence_header_
- {
- unsigned int sequence_header_code; // 0x000001b3
- unsigned int frame_rate_code : 4;
- unsigned int aspect_ratio_information : 4;
- unsigned int vertical_size_value : 12;
- unsigned int horizontal_size_value : 12;
- unsigned int marker_bit : 2;
- unsigned int bit_rate_value : 30;
- }sequence_header;
- // sequence extension
- typedef struct _sequence_extension_
- {
- unsigned int sequence_header_code; // 0x000001b5
- unsigned int marker_bit : 1;
- unsigned int bit_rate_extension : 12;
- unsigned int vertical_size_extension : 2;
- unsigned int horizontal_size_extension : 2;
- unsigned int chroma_format : 2;
- unsigned int progressive_sequence : 1;
- unsigned int profile_and_level_indication : 8;
- unsigned int extension_start_code : 4;
- }sequence_extension;
- void memcpy_sps_data(uint8_t *dst, uint8_t *src, int len);
- #if defined (__cplusplus)
- }
- #endif
- #endif
- /********************************************************************
- filename: sps_pps_parser.c
- created: 2016-08-06
- author: Donyj
- *********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdint.h> /* for uint32_t, etc */
- #include "sps_pps_parser.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* report level */
- #define RPT_ERR (1) // error, system error
- #define RPT_WRN (2) // warning, maybe wrong, maybe OK
- #define RPT_INF (4) // important information
- #define RPT_DBG (8) // debug information
- static int rpt_lvl = RPT_ERR; /* report level: ERR, WRN, INF, DBG */
- /* report micro */
- #define RPT(lvl, ...) \
- do {\
- if (lvl & rpt_lvl) {\
- switch (lvl) {\
- case RPT_ERR: \
- fprintf(stderr, "\"%s\" line %d [err]: ", __FILE__, __LINE__); \
- break; \
- case RPT_WRN: \
- fprintf(stderr, "\"%s\" line %d [wrn]: ", __FILE__, __LINE__); \
- break; \
- case RPT_INF: \
- fprintf(stderr, "\"%s\" line %d [inf]: ", __FILE__, __LINE__); \
- break; \
- case RPT_DBG: \
- fprintf(stderr, "\"%s\" line %d [dbg]: ", __FILE__, __LINE__); \
- break; \
- default: \
- fprintf(stderr, "\"%s\" line %d [???]: ", __FILE__, __LINE__); \
- break; \
- } \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } \
- } while (0)
- #define SPS_PPS_DEBUG
- #undef SPS_PPS_DEBUG
- #define MAX_LEN 32
- /**
- * @brief Function get_1bit() 读1个bit
- * @param[in] h get_bit_context structrue
- * @retval 0: success, -1 : failure
- * @pre
- * @post
- */
- static int get_1bit(void *h)
- {
- get_bit_context *ptr = (get_bit_context *)h;
- int ret = 0;
- uint8_t *cur_char = NULL;
- uint8_t shift;
- if (NULL == ptr)
- {
- RPT(RPT_ERR, "NULL pointer");
- ret = -1;
- goto exit;
- }
- cur_char = ptr->buf + (ptr->bit_pos >> 3);
- shift = 7 - (ptr->cur_bit_pos);
- ptr->bit_pos++;
- ptr->cur_bit_pos = ptr->bit_pos & 0x7;
- ret = ((*cur_char) >> shift) & 0x01;
- exit:
- return ret;
- }
- /**
- * @brief Function get_bits() 读n个bits,n不能超过32
- * @param[in] h get_bit_context structrue
- * @param[in] n how many bits you want?
- * @retval 0: success, -1 : failure
- * @pre
- * @post
- */
- static int get_bits(void *h, int n)
- {
- get_bit_context *ptr = (get_bit_context *)h;
- uint8_t temp[5] = { 0 };
- uint8_t *cur_char = NULL;
- uint8_t nbyte;
- uint8_t shift;
- uint32_t result;
- uint64_t ret = 0;
- if (NULL == ptr)
- {
- RPT(RPT_ERR, "NULL pointer");
- ret = -1;
- goto exit;
- }
- if (n > MAX_LEN)
- {
- n = MAX_LEN;
- }
- if ((ptr->bit_pos + n) > ptr->total_bit)
- {
- n = ptr->total_bit - ptr->bit_pos;
- }
- cur_char = ptr->buf + (ptr->bit_pos >> 3);
- nbyte = (ptr->cur_bit_pos + n + 7) >> 3;
- shift = (8 - (ptr->cur_bit_pos + n)) & 0x07;
- if (n == MAX_LEN)
- {
- RPT(RPT_DBG, "12(ptr->bit_pos(:%d) + n(:%d)) > ptr->total_bit(:%d)!!! ", \
- ptr->bit_pos, n, ptr->total_bit);
- RPT(RPT_DBG, "0x%x 0x%x 0x%x 0x%x", (*cur_char), *(cur_char + 1), *(cur_char + 2), *(cur_char + 3));
- }
- memcpy(&temp[5 - nbyte], cur_char, nbyte);
- ret = (uint32_t)temp[0] << 24;
- ret = ret << 8;
- ret = ((uint32_t)temp[1] << 24) | ((uint32_t)temp[2] << 16)\
- | ((uint32_t)temp[3] << 8) | temp[4];
- ret = (ret >> shift) & (((uint64_t)1 << n) - 1);
- result = ret;
- ptr->bit_pos += n;
- ptr->cur_bit_pos = ptr->bit_pos & 0x7;
- exit:
- return result;
- }
- /**
- * @brief Function parse_codenum() 指数哥伦布编码解析,参考h264标准第9节
- * @param[in] buf
- * @retval code_num
- * @pre
- * @post
- */
- static int parse_codenum(void *buf)
- {
- uint8_t leading_zero_bits = -1;
- uint8_t b;
- uint32_t code_num = 0;
- for (b = 0; !b; leading_zero_bits++)
- {
- b = get_1bit(buf);
- }
- code_num = ((uint32_t)1 << leading_zero_bits) - 1 + get_bits(buf, leading_zero_bits);
- return code_num;
- }
- /**
- * @brief Function parse_ue() 指数哥伦布编码解析 ue(),参考h264标准第9节
- * @param[in] buf sps_pps parse buf
- * @retval code_num
- * @pre
- * @post
- */
- static int parse_ue(void *buf)
- {
- return parse_codenum(buf);
- }
- /**
- * @brief Function parse_se() 指数哥伦布编码解析 se(), 参考h264标准第9节
- * @param[in] buf sps_pps parse buf
- * @retval code_num
- * @pre
- * @post
- */
- static int parse_se(void *buf)
- {
- int ret = 0;
- int code_num;
- code_num = parse_codenum(buf);
- ret = (code_num + 1) >> 1;
- ret = (code_num & 0x01) ? ret : -ret;
- return ret;
- }
- /**
- * @brief Function get_bit_context_free() 申请的get_bit_context结构内存释放
- * @param[in] buf get_bit_context buf
- * @retval none
- * @pre
- * @post
- */
- static void get_bit_context_free(void *buf)
- {
- get_bit_context *ptr = (get_bit_context *)buf;
- if (ptr)
- {
- if (ptr->buf)
- {
- free(ptr->buf);
- }
- free(ptr);
- }
- }
- static void *de_emulation_prevention(void *buf)
- {
- get_bit_context *ptr = NULL;
- get_bit_context *buf_ptr = (get_bit_context *)buf;
- int i = 0, j = 0;
- uint8_t *tmp_ptr = NULL;
- int tmp_buf_size = 0;
- int val = 0;
- if (NULL == buf_ptr)
- {
- RPT(RPT_ERR, "NULL ptr");
- goto exit;
- }
- ptr = (get_bit_context *)malloc(sizeof(get_bit_context));
- if (NULL == ptr)
- {
- RPT(RPT_ERR, "NULL ptr");
- goto exit;
- }
- memcpy(ptr, buf_ptr, sizeof(get_bit_context));
- printf("fun = %s line = %d ptr->buf_size=%d \n", __FUNCTION__, __LINE__, ptr->buf_size);
- ptr->buf = (uint8_t *)malloc(ptr->buf_size);
- if (NULL == ptr->buf)
- {
- RPT(RPT_ERR, "NULL ptr ");
- goto exit;
- }
- memcpy(ptr->buf, buf_ptr->buf, buf_ptr->buf_size);
- tmp_ptr = ptr->buf;
- tmp_buf_size = ptr->buf_size;
- for (i = 0; i<(tmp_buf_size - 2); i++)
- {
- /*检测0x000003*/
- val = (tmp_ptr[i] ^ 0x00) + (tmp_ptr[i + 1] ^ 0x00) + (tmp_ptr[i + 2] ^ 0x03);
- if (val == 0)
- {
- /*剔除0x03*/
- for (j = i + 2; j<tmp_buf_size - 1; j++)
- {
- tmp_ptr[j] = tmp_ptr[j + 1];
- }
- /*相应的bufsize要减小*/
- ptr->buf_size--;
- }
- }
- /*重新计算total_bit*/
- ptr->total_bit = ptr->buf_size << 3;
- return (void *)ptr;
- exit:
- get_bit_context_free(ptr);
- return NULL;
- }
- /**
- * @brief Function get_bit_context_free() VUI_parameters 解析,原理参考h264标准
- * @param[in] buf get_bit_context buf
- * @param[in] vui_ptr vui解析结果
- * @retval 0: success, -1 : failure
- * @pre
- * @post
- */
- static int vui_parameters_set(void *buf, vui_parameters_t *vui_ptr)
- {
- int ret = 0;
- int SchedSelIdx = 0;
- if (NULL == vui_ptr || NULL == buf)
- {
- RPT(RPT_ERR, "ERR null pointer\n");
- ret = -1;
- goto exit;
- }
- vui_ptr->aspect_ratio_info_present_flag = get_1bit(buf);
- if (vui_ptr->aspect_ratio_info_present_flag)
- {
- vui_ptr->aspect_ratio_idc = get_bits(buf, 8);
- if (vui_ptr->aspect_ratio_idc == Extended_SAR)
- {
- vui_ptr->sar_width = get_bits(buf, 16);
- vui_ptr->sar_height = get_bits(buf, 16);
- }
- }
- vui_ptr->overscan_info_present_flag = get_1bit(buf);
- if (vui_ptr->overscan_info_present_flag)
- {
- vui_ptr->overscan_appropriate_flag = get_1bit(buf);
- }
- vui_ptr->video_signal_type_present_flag = get_1bit(buf);
- if (vui_ptr->video_signal_type_present_flag)
- {
- vui_ptr->video_format = get_bits(buf, 3);
- vui_ptr->video_full_range_flag = get_1bit(buf);
- vui_ptr->colour_description_present_flag = get_1bit(buf);
- if (vui_ptr->colour_description_present_flag)
- {
- vui_ptr->colour_primaries = get_bits(buf, 8);
- vui_ptr->transfer_characteristics = get_bits(buf, 8);
- vui_ptr->matrix_coefficients = get_bits(buf, 8);
- }
- }
- vui_ptr->chroma_loc_info_present_flag = get_1bit(buf);
- if (vui_ptr->chroma_loc_info_present_flag)
- {
- vui_ptr->chroma_sample_loc_type_top_field = parse_ue(buf);
- vui_ptr->chroma_sample_loc_type_bottom_field = parse_ue(buf);
- }
- vui_ptr->timing_info_present_flag = get_1bit(buf);
- if (vui_ptr->timing_info_present_flag)
- {
- vui_ptr->num_units_in_tick = get_bits(buf, 32);
- vui_ptr->time_scale = get_bits(buf, 32);
- vui_ptr->fixed_frame_rate_flag = get_1bit(buf);
- }
- vui_ptr->nal_hrd_parameters_present_flag = get_1bit(buf);
- if (vui_ptr->nal_hrd_parameters_present_flag)
- {
- vui_ptr->cpb_cnt_minus1 = parse_ue(buf);
- vui_ptr->bit_rate_scale = get_bits(buf, 4);
- vui_ptr->cpb_size_scale = get_bits(buf, 4);
- for (SchedSelIdx = 0; SchedSelIdx <= vui_ptr->cpb_cnt_minus1; SchedSelIdx++)
- {
- vui_ptr->bit_rate_value_minus1[SchedSelIdx] = parse_ue(buf);
- vui_ptr->cpb_size_value_minus1[SchedSelIdx] = parse_ue(buf);
- vui_ptr->cbr_flag[SchedSelIdx] = get_1bit(buf);
- }
- vui_ptr->initial_cpb_removal_delay_length_minus1 = get_bits(buf, 5);
- vui_ptr->cpb_removal_delay_length_minus1 = get_bits(buf, 5);
- vui_ptr->dpb_output_delay_length_minus1 = get_bits(buf, 5);
- vui_ptr->time_offset_length = get_bits(buf, 5);
- }
- vui_ptr->vcl_hrd_parameters_present_flag = get_1bit(buf);
- if (vui_ptr->vcl_hrd_parameters_present_flag)
- {
- vui_ptr->cpb_cnt_minus1 = parse_ue(buf);
- vui_ptr->bit_rate_scale = get_bits(buf, 4);
- vui_ptr->cpb_size_scale = get_bits(buf, 4);
- for (SchedSelIdx = 0; SchedSelIdx <= vui_ptr->cpb_cnt_minus1; SchedSelIdx++)
- {
- vui_ptr->bit_rate_value_minus1[SchedSelIdx] = parse_ue(buf);
- vui_ptr->cpb_size_value_minus1[SchedSelIdx] = parse_ue(buf);
- vui_ptr->cbr_flag[SchedSelIdx] = get_1bit(buf);
- }
- vui_ptr->initial_cpb_removal_delay_length_minus1 = get_bits(buf, 5);
- vui_ptr->cpb_removal_delay_length_minus1 = get_bits(buf, 5);
- vui_ptr->dpb_output_delay_length_minus1 = get_bits(buf, 5);
- vui_ptr->time_offset_length = get_bits(buf, 5);
- }
- if (vui_ptr->nal_hrd_parameters_present_flag \
- || vui_ptr->vcl_hrd_parameters_present_flag)
- {
- vui_ptr->low_delay_hrd_flag = get_1bit(buf);
- }
- vui_ptr->pic_struct_present_flag = get_1bit(buf);
- vui_ptr->bitstream_restriction_flag = get_1bit(buf);
- if (vui_ptr->bitstream_restriction_flag)
- {
- vui_ptr->motion_vectors_over_pic_boundaries_flag = get_1bit(buf);
- vui_ptr->max_bytes_per_pic_denom = parse_ue(buf);
- vui_ptr->max_bits_per_mb_denom = parse_ue(buf);
- vui_ptr->log2_max_mv_length_horizontal = parse_ue(buf);
- vui_ptr->log2_max_mv_length_vertical = parse_ue(buf);
- vui_ptr->num_reorder_frames = parse_ue(buf);
- vui_ptr->max_dec_frame_buffering = parse_ue(buf);
- }
- exit:
- return ret;
- }
- /*SPS 信息打印,调试使用*/
- #ifdef SPS_PPS_DEBUG
- static void sps_info_print(SPS* sps_ptr)
- {
- if (NULL != sps_ptr)
- {
- RPT(RPT_DBG, "profile_idc: %d", sps_ptr->profile_idc);
- RPT(RPT_DBG, "constraint_set0_flag: %d", sps_ptr->constraint_set0_flag);
- RPT(RPT_DBG, "constraint_set1_flag: %d", sps_ptr->constraint_set1_flag);
- RPT(RPT_DBG, "constraint_set2_flag: %d", sps_ptr->constraint_set2_flag);
- RPT(RPT_DBG, "constraint_set3_flag: %d", sps_ptr->constraint_set3_flag);
- RPT(RPT_DBG, "reserved_zero_4bits: %d", sps_ptr->reserved_zero_4bits);
- RPT(RPT_DBG, "level_idc: %d", sps_ptr->level_idc);
- RPT(RPT_DBG, "seq_parameter_set_id: %d", sps_ptr->seq_parameter_set_id);
- RPT(RPT_DBG, "chroma_format_idc: %d", sps_ptr->chroma_format_idc);
- RPT(RPT_DBG, "separate_colour_plane_flag: %d", sps_ptr->separate_colour_plane_flag);
- RPT(RPT_DBG, "bit_depth_luma_minus8: %d", sps_ptr->bit_depth_luma_minus8);
- RPT(RPT_DBG, "bit_depth_chroma_minus8: %d", sps_ptr->bit_depth_chroma_minus8);
- RPT(RPT_DBG, "qpprime_y_zero_transform_bypass_flag: %d", sps_ptr->qpprime_y_zero_transform_bypass_flag);
- RPT(RPT_DBG, "seq_scaling_matrix_present_flag: %d", sps_ptr->seq_scaling_matrix_present_flag);
- //RPT(RPT_INF, "seq_scaling_list_present_flag:%d", sps_ptr->seq_scaling_list_present_flag);
- RPT(RPT_DBG, "log2_max_frame_num_minus4: %d", sps_ptr->log2_max_frame_num_minus4);
- RPT(RPT_DBG, "pic_order_cnt_type: %d", sps_ptr->pic_order_cnt_type);
- RPT(RPT_DBG, "num_ref_frames: %d", sps_ptr->num_ref_frames);
- RPT(RPT_DBG, "gaps_in_frame_num_value_allowed_flag: %d", sps_ptr->gaps_in_frame_num_value_allowed_flag);
- RPT(RPT_DBG, "pic_width_in_mbs_minus1: %d", sps_ptr->pic_width_in_mbs_minus1);
- RPT(RPT_DBG, "pic_height_in_map_units_minus1: %d", sps_ptr->pic_height_in_map_units_minus1);
- RPT(RPT_DBG, "frame_mbs_only_flag: %d", sps_ptr->frame_mbs_only_flag);
- RPT(RPT_DBG, "mb_adaptive_frame_field_flag: %d", sps_ptr->mb_adaptive_frame_field_flag);
- RPT(RPT_DBG, "direct_8x8_inference_flag: %d", sps_ptr->direct_8x8_inference_flag);
- RPT(RPT_DBG, "frame_cropping_flag: %d", sps_ptr->frame_cropping_flag);
- RPT(RPT_DBG, "frame_crop_left_offset: %d", sps_ptr->frame_crop_left_offset);
- RPT(RPT_DBG, "frame_crop_right_offset: %d", sps_ptr->frame_crop_right_offset);
- RPT(RPT_DBG, "frame_crop_top_offset: %d", sps_ptr->frame_crop_top_offset);
- RPT(RPT_DBG, "frame_crop_bottom_offset: %d", sps_ptr->frame_crop_bottom_offset);
- RPT(RPT_DBG, "vui_parameters_present_flag: %d", sps_ptr->vui_parameters_present_flag);
- if (sps_ptr->vui_parameters_present_flag)
- {
- RPT(RPT_DBG, "aspect_ratio_info_present_flag: %d", sps_ptr->vui_parameters.aspect_ratio_info_present_flag);
- RPT(RPT_DBG, "aspect_ratio_idc: %d", sps_ptr->vui_parameters.aspect_ratio_idc);
- RPT(RPT_DBG, "sar_width: %d", sps_ptr->vui_parameters.sar_width);
- RPT(RPT_DBG, "sar_height: %d", sps_ptr->vui_parameters.sar_height);
- RPT(RPT_DBG, "overscan_info_present_flag: %d", sps_ptr->vui_parameters.overscan_info_present_flag);
- RPT(RPT_DBG, "overscan_info_appropriate_flag: %d", sps_ptr->vui_parameters.overscan_appropriate_flag);
- RPT(RPT_DBG, "video_signal_type_present_flag: %d", sps_ptr->vui_parameters.video_signal_type_present_flag);
- RPT(RPT_DBG, "video_format: %d", sps_ptr->vui_parameters.video_format);
- RPT(RPT_DBG, "video_full_range_flag: %d", sps_ptr->vui_parameters.video_full_range_flag);
- RPT(RPT_DBG, "colour_description_present_flag: %d", sps_ptr->vui_parameters.colour_description_present_flag);
- RPT(RPT_DBG, "colour_primaries: %d", sps_ptr->vui_parameters.colour_primaries);
- RPT(RPT_DBG, "transfer_characteristics: %d", sps_ptr->vui_parameters.transfer_characteristics);
- RPT(RPT_DBG, "matrix_coefficients: %d", sps_ptr->vui_parameters.matrix_coefficients);
- RPT(RPT_DBG, "chroma_loc_info_present_flag: %d", sps_ptr->vui_parameters.chroma_loc_info_present_flag);
- RPT(RPT_DBG, "chroma_sample_loc_type_top_field: %d", sps_ptr->vui_parameters.chroma_sample_loc_type_top_field);
- RPT(RPT_DBG, "chroma_sample_loc_type_bottom_field: %d", sps_ptr->vui_parameters.chroma_sample_loc_type_bottom_field);
- RPT(RPT_DBG, "timing_info_present_flag: %d", sps_ptr->vui_parameters.timing_info_present_flag);
- RPT(RPT_DBG, "num_units_in_tick: %d", sps_ptr->vui_parameters.num_units_in_tick);
- RPT(RPT_DBG, "time_scale: %d", sps_ptr->vui_parameters.time_scale);
- RPT(RPT_DBG, "fixed_frame_rate_flag: %d", sps_ptr->vui_parameters.fixed_frame_rate_flag);
- RPT(RPT_DBG, "nal_hrd_parameters_present_flag: %d", sps_ptr->vui_parameters.nal_hrd_parameters_present_flag);
- RPT(RPT_DBG, "cpb_cnt_minus1: %d", sps_ptr->vui_parameters.cpb_cnt_minus1);
- RPT(RPT_DBG, "bit_rate_scale: %d", sps_ptr->vui_parameters.bit_rate_scale);
- RPT(RPT_DBG, "cpb_size_scale: %d", sps_ptr->vui_parameters.cpb_size_scale);
- RPT(RPT_DBG, "initial_cpb_removal_delay_length_minus1: %d", sps_ptr->vui_parameters.initial_cpb_removal_delay_length_minus1);
- RPT(RPT_DBG, "cpb_removal_delay_length_minus1: %d", sps_ptr->vui_parameters.cpb_removal_delay_length_minus1);
- RPT(RPT_DBG, "dpb_output_delay_length_minus1: %d", sps_ptr->vui_parameters.dpb_output_delay_length_minus1);
- RPT(RPT_DBG, "time_offset_length: %d", sps_ptr->vui_parameters.time_offset_length);
- RPT(RPT_DBG, "vcl_hrd_parameters_present_flag: %d", sps_ptr->vui_parameters.vcl_hrd_parameters_present_flag);
- RPT(RPT_DBG, "low_delay_hrd_flag: %d", sps_ptr->vui_parameters.low_delay_hrd_flag);
- RPT(RPT_DBG, "pic_struct_present_flag: %d", sps_ptr->vui_parameters.pic_struct_present_flag);
- RPT(RPT_DBG, "bitstream_restriction_flag: %d", sps_ptr->vui_parameters.bitstream_restriction_flag);
- RPT(RPT_DBG, "motion_vectors_over_pic_boundaries_flag: %d", sps_ptr->vui_parameters.motion_vectors_over_pic_boundaries_flag);
- RPT(RPT_DBG, "max_bytes_per_pic_denom: %d", sps_ptr->vui_parameters.max_bytes_per_pic_denom);
- RPT(RPT_DBG, "max_bits_per_mb_denom: %d", sps_ptr->vui_parameters.max_bits_per_mb_denom);
- RPT(RPT_DBG, "log2_max_mv_length_horizontal: %d", sps_ptr->vui_parameters.log2_max_mv_length_horizontal);
- RPT(RPT_DBG, "log2_max_mv_length_vertical: %d", sps_ptr->vui_parameters.log2_max_mv_length_vertical);
- RPT(RPT_DBG, "num_reorder_frames: %d", sps_ptr->vui_parameters.num_reorder_frames);
- RPT(RPT_DBG, "max_dec_frame_buffering: %d", sps_ptr->vui_parameters.max_dec_frame_buffering);
- }
- }
- }
- #endif
- /**
- * @brief Function h264dec_seq_parameter_set() h264 SPS infomation 解析
- * @param[in] buf buf ptr, 需同步00 00 00 01 X7后传入
- * @param[in] sps_ptr sps指针,保存SPS信息
- * @retval 0: success, -1 : failure
- * @pre
- * @post
- */
- int h264dec_seq_parameter_set(void *buf_ptr, SPS *sps_ptr)
- {
- SPS *sps = sps_ptr;
- int ret = 0;
- int profile_idc = 0;
- int i, j, last_scale, next_scale, delta_scale;
- void *buf = NULL;
- if (NULL == buf_ptr || NULL == sps)
- {
- RPT(RPT_ERR, "ERR null pointer\n");
- ret = -1;
- goto exit;
- }
- memset((void *)sps, 0, sizeof(SPS));
- buf = de_emulation_prevention(buf_ptr);
- if (NULL == buf)
- {
- RPT(RPT_ERR, "ERR null pointer\n");
- ret = -1;
- goto exit;
- }
- sps->profile_idc = get_bits(buf, 8);
- sps->constraint_set0_flag = get_1bit(buf);
- sps->constraint_set1_flag = get_1bit(buf);
- sps->constraint_set2_flag = get_1bit(buf);
- sps->constraint_set3_flag = get_1bit(buf);
- sps->reserved_zero_4bits = get_bits(buf, 4);
- sps->level_idc = get_bits(buf, 8);
- sps->seq_parameter_set_id = parse_ue(buf);
- profile_idc = sps->profile_idc;
- if ((profile_idc == 100) || (profile_idc == 110) || (profile_idc == 122) || (profile_idc == 244)
- || (profile_idc == 44) || (profile_idc == 83) || (profile_idc == 86) || (profile_idc == 118) || \
- (profile_idc == 128))
- {
- sps->chroma_format_idc = parse_ue(buf);
- if (sps->chroma_format_idc == 3)
- {
- sps->separate_colour_plane_flag = get_1bit(buf);
- }
- sps->bit_depth_luma_minus8 = parse_ue(buf);
- sps->bit_depth_chroma_minus8 = parse_ue(buf);
- sps->qpprime_y_zero_transform_bypass_flag = get_1bit(buf);
- sps->seq_scaling_matrix_present_flag = get_1bit(buf);
- if (sps->seq_scaling_matrix_present_flag)
- {
- for (i = 0; i < ((sps->chroma_format_idc != 3) ? 8 : 12); i++)
- {
- sps->seq_scaling_list_present_flag[i] = get_1bit(buf);
- if (sps->seq_scaling_list_present_flag[i])
- {
- if (i < 6)
- {
- for (j = 0; j < 16; j++)
- {
- last_scale = 8;
- next_scale = 8;
- if (next_scale != 0)
- {
- delta_scale = parse_se(buf);
- next_scale = (last_scale + delta_scale + 256) % 256;
- sps->UseDefaultScalingMatrix4x4Flag[i] = ((j == 0) && (next_scale == 0));
- }
- sps->ScalingList4x4[i][j] = (next_scale == 0) ? last_scale : next_scale;
- last_scale = sps->ScalingList4x4[i][j];
- }
- }
- else
- {
- int ii = i - 6;
- next_scale = 8;
- last_scale = 8;
- for (j = 0; j < 64; j++)
- {
- if (next_scale != 0)
- {
- delta_scale = parse_se(buf);
- next_scale = (last_scale + delta_scale + 256) % 256;
- sps->UseDefaultScalingMatrix8x8Flag[ii] = ((j == 0) && (next_scale == 0));
- }
- sps->ScalingList8x8[ii][j] = (next_scale == 0) ? last_scale : next_scale;
- last_scale = sps->ScalingList8x8[ii][j];
- }
- }
- }
- }
- }
- }
- sps->log2_max_frame_num_minus4 = parse_ue(buf);
- sps->pic_order_cnt_type = parse_ue(buf);
- if (sps->pic_order_cnt_type == 0)
- {
- sps->log2_max_pic_order_cnt_lsb_minus4 = parse_ue(buf);
- }
- else if (sps->pic_order_cnt_type == 1)
- {
- sps->delta_pic_order_always_zero_flag = get_1bit(buf);
- sps->offset_for_non_ref_pic = parse_se(buf);
- sps->offset_for_top_to_bottom_field = parse_se(buf);
- sps->num_ref_frames_in_pic_order_cnt_cycle = parse_ue(buf);
- for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
- {
- sps->offset_for_ref_frame_array[i] = parse_se(buf);
- }
- }
- sps->num_ref_frames = parse_ue(buf);
- sps->gaps_in_frame_num_value_allowed_flag = get_1bit(buf);
- sps->pic_width_in_mbs_minus1 = parse_ue(buf);
- sps->pic_height_in_map_units_minus1 = parse_ue(buf);
- sps->frame_mbs_only_flag = get_1bit(buf);
- if (!sps->frame_mbs_only_flag)
- {
- sps->mb_adaptive_frame_field_flag = get_1bit(buf);
- }
- sps->direct_8x8_inference_flag = get_1bit(buf);
- sps->frame_cropping_flag = get_1bit(buf);
- if (sps->frame_cropping_flag)
- {
- sps->frame_crop_left_offset = parse_ue(buf);
- sps->frame_crop_right_offset = parse_ue(buf);
- sps->frame_crop_top_offset = parse_ue(buf);
- sps->frame_crop_bottom_offset = parse_ue(buf);
- }
- sps->vui_parameters_present_flag = get_1bit(buf);
- if (sps->vui_parameters_present_flag)
- {
- vui_parameters_set(buf, &sps->vui_parameters);
- }
- #ifdef SPS_PPS_DEBUG
- sps_info_print(sps);
- #endif
- exit:
- get_bit_context_free(buf);
- return ret;
- }
- /**
- * @brief Function more_rbsp_data() 计算pps串最后一个为1的比特位及其后都是比特0的个数
- * @param[in] buf get_bit_context structure
- * @retval
- * @pre
- * @post
- * @note 这段代码来自网友的帮助,并没有验证,使用时需注意
- */
- static int more_rbsp_data(void *buf)
- {
- get_bit_context *ptr = (get_bit_context *)buf;
- get_bit_context tmp;
- if (NULL == buf)
- {
- RPT(RPT_ERR, "NULL pointer, err");
- return -1;
- }
- memset(&tmp, 0, sizeof(get_bit_context));
- memcpy(&tmp, ptr, sizeof(get_bit_context));
- for (tmp.bit_pos = ptr->total_bit - 1; tmp.bit_pos > ptr->bit_pos; tmp.bit_pos -= 2)
- {
- if (get_1bit(&tmp))
- {
- break;
- }
- }
- return tmp.bit_pos == ptr->bit_pos ? 0 : 1;
- }
- /**
- * @brief Function h264dec_picture_parameter_set() h264 PPS infomation 解析
- * @param[in] buf buf ptr, 需同步00 00 00 01 X8后传入
- * @param[in] pps_ptr pps指针,保存pps信息
- * @retval 0: success, -1 : failure
- * @pre
- * @post
- * @note: 用法参考sps解析
- */
- int h264dec_picture_parameter_set(void *buf_ptr, PPS *pps_ptr)
- {
- PPS *pps = pps_ptr;
- int ret = 0;
- void *buf = NULL;
- int iGroup = 0;
- int i, j, last_scale, next_scale, delta_scale;
- if (NULL == buf_ptr || NULL == pps_ptr)
- {
- RPT(RPT_ERR, "NULL pointer\n");
- ret = -1;
- goto exit;
- }
- memset((void *)pps, 0, sizeof(PPS));
- buf = de_emulation_prevention(buf_ptr);
- if (NULL == buf)
- {
- RPT(RPT_ERR, "ERR null pointer\n");
- ret = -1;
- goto exit;
- }
- pps->pic_parameter_set_id = parse_ue(buf);
- pps->seq_parameter_set_id = parse_ue(buf);
- pps->entropy_coding_mode_flag = get_1bit(buf);
- pps->pic_order_present_flag = get_1bit(buf);
- pps->num_slice_groups_minus1 = parse_ue(buf);
- if (pps->num_slice_groups_minus1 > 0)
- {
- pps->slice_group_map_type = parse_ue(buf);
- if (pps->slice_group_map_type == 0)
- {
- for (iGroup = 0; iGroup <= pps->num_slice_groups_minus1; iGroup++)
- {
- pps->run_length_minus1[iGroup] = parse_ue(buf);
- }
- }
- else if (pps->slice_group_map_type == 2)
- {
- for (iGroup = 0; iGroup <= pps->num_slice_groups_minus1; iGroup++)
- {
- pps->top_left[iGroup] = parse_ue(buf);
- pps->bottom_right[iGroup] = parse_ue(buf);
- }
- }
- else if (pps->slice_group_map_type == 3 \
- || pps->slice_group_map_type == 4\
- || pps->slice_group_map_type == 5)
- {
- pps->slice_group_change_direction_flag = get_1bit(buf);
- pps->slice_group_change_rate_minus1 = parse_ue(buf);
- }
- else if (pps->slice_group_map_type == 6)
- {
- pps->pic_size_in_map_units_minus1 = parse_ue(buf);
- for (i = 0; i<pps->pic_size_in_map_units_minus1; i++)
- {
- /*这地方可能有问题,对u(v)理解偏差*/
- pps->slice_group_id[i] = get_bits(buf, pps->pic_size_in_map_units_minus1);
- }
- }
- }
- pps->num_ref_idx_10_active_minus1 = parse_ue(buf);
- pps->num_ref_idx_11_active_minus1 = parse_ue(buf);
- pps->weighted_pred_flag = get_1bit(buf);
- pps->weighted_bipred_idc = get_bits(buf, 2);
- pps->pic_init_qp_minus26 = parse_se(buf); /*relative26*/
- pps->pic_init_qs_minus26 = parse_se(buf); /*relative26*/
- pps->chroma_qp_index_offset = parse_se(buf);
- pps->deblocking_filter_control_present_flag = get_1bit(buf);
- pps->constrained_intra_pred_flag = get_1bit(buf);
- pps->redundant_pic_cnt_present_flag = get_1bit(buf);
- if (more_rbsp_data(buf))
- {
- pps->transform_8x8_mode_flag = get_1bit(buf);
- pps->pic_scaling_matrix_present_flag = get_1bit(buf);
- if (pps->pic_scaling_matrix_present_flag)
- {
- for (i = 0; i<6 + 2 * pps->transform_8x8_mode_flag; i++)
- {
- pps->pic_scaling_list_present_flag[i] = get_1bit(buf);
- if (pps->pic_scaling_list_present_flag[i])
- {
- if (i<6)
- {
- for (j = 0; j<16; j++)
- {
- next_scale = 8;
- last_scale = 8;
- if (next_scale != 0)
- {
- delta_scale = parse_se(buf);
- next_scale = (last_scale + delta_scale + 256) % 256;
- pps->UseDefaultScalingMatrix4x4Flag[i] = ((j == 0) && (next_scale == 0));
- }
- pps->ScalingList4x4[i][j] = (next_scale == 0) ? last_scale : next_scale;
- last_scale = pps->ScalingList4x4[i][j];
- }
- }
- else
- {
- int ii = i - 6;
- next_scale = 8;
- last_scale = 8;
- for (j = 0; j<64; j++)
- {
- if (next_scale != 0)
- {
- delta_scale = parse_se(buf);
- next_scale = (last_scale + delta_scale + 256) % 256;
- pps->UseDefaultScalingMatrix8x8Flag[ii] = ((j == 0) && (next_scale == 0));
- }
- pps->ScalingList8x8[ii][j] = (next_scale == 0) ? last_scale : next_scale;
- last_scale = pps->ScalingList8x8[ii][j];
- }
- }
- }
- }
- pps->second_chroma_qp_index_offset = parse_se(buf);
- }
- }
- exit:
- get_bit_context_free(buf);
- return ret;
- }
- // calculation width height and framerate
- int h264_get_width(SPS *sps_ptr)
- {
- return (sps_ptr->pic_width_in_mbs_minus1 + 1) * 16;
- }
- int h264_get_height(SPS *sps_ptr)
- {
- printf("fun = %s line = %d sps_ptr->frame_mbs_only_flag=%d \n", __FUNCTION__, __LINE__, sps_ptr->frame_mbs_only_flag);
- return (sps_ptr->pic_height_in_map_units_minus1 + 1) * 16 * (2 - sps_ptr->frame_mbs_only_flag);
- }
- int h264_get_format(SPS *sps_ptr)
- {
- return sps_ptr->frame_mbs_only_flag;
- }
- int h264_get_framerate(float *framerate, SPS *sps_ptr)
- {
- int fr;
- int fr_int = 0;
- if (sps_ptr->vui_parameters.timing_info_present_flag)
- {
- if (sps_ptr->frame_mbs_only_flag)
- {
- //*framerate = (float)sps_ptr->vui_parameters.time_scale / (float)sps_ptr->vui_parameters.num_units_in_tick;
- *framerate = (float)sps_ptr->vui_parameters.time_scale / (float)sps_ptr->vui_parameters.num_units_in_tick / 2.0;
- //fr_int = sps_ptr->vui_parameters.time_scale / sps_ptr->vui_parameters.num_units_in_tick;
- }
- else
- {
- *framerate = (float)sps_ptr->vui_parameters.time_scale / (float)sps_ptr->vui_parameters.num_units_in_tick / 2.0;
- //fr_int = sps_ptr->vui_parameters.time_scale / sps_ptr->vui_parameters.num_units_in_tick / 2;
- }
- return 0;
- }
- else
- {
- return 1;
- }
- }
- void memcpy_sps_data(uint8_t *dst, uint8_t *src, int len)
- {
- int tmp;
- for (tmp = 0; tmp < len; tmp++)
- {
- //printf("0x%02x ", src[tmp]);
- dst[(tmp / 4) * 4 + (3 - (tmp % 4))] = src[tmp];
- }
- }
- /*_*/
- #ifdef __cplusplus
- }
- #endif
- /********************************************************************
- filename: Mux.cpp
- created: 2016-08-06
- author: Donyj
- purpose: MP4编码器,基于开源库mp4v2实现(https://code.google.com/p/mp4v2/)。
- *********************************************************************/
- #include <stdio.h>
- #include<Winsock2.h>
- #pragma comment(lib,"ws2_32.lib")
- #include "MP4Encoder.h"
- FILE *fp_h264;
- FILE *fp_AAC;
- static int count_audio = 0;
- int read_h264(unsigned char *buf, int buf_size)
- {
- int true_size = fread(buf, 1, buf_size, fp_h264);
- if (true_size > 0){
- return true_size;
- }
- else{
- //fseek(fp_AAC, 0L, SEEK_SET);
- //return read_aac(buf, buf_size);
- return 0;
- }
- }
- int read_aac(unsigned char *buf, int buf_size)
- {
- unsigned char aac_header[7];
- int true_size = 0;
- true_size = fread(aac_header, 1, 7, fp_AAC);
- if (true_size <= 0)
- {
- fseek(fp_AAC, 0L, SEEK_SET);
- return read_aac(buf, buf_size);
- }
- else
- {
- unsigned int body_size = *(unsigned int *)(aac_header + 3);
- body_size = ntohl(body_size); //Little Endian
- body_size = body_size << 6;
- body_size = body_size >> 19;
- true_size = fread(buf, 1, body_size - 7, fp_AAC);
- return true_size;
- }
- }
- int main(int argc, char** argv)
- {
- //fp_h264 = fopen("test.h264", "rb");
- //fp_h264 = fopen("1080.h264", "rb");
- fp_h264 = fopen("bitstream.h264", "rb");
- fp_AAC = fopen("test.aac", "rb");
- MP4Encoder mp4Encoder;
- // convert H264 file to mp4 file
- mp4Encoder.MP4FileOpen("test.mp4", 1, 1);
- mp4Encoder.MP4FileWrite(read_h264, read_aac);
- mp4Encoder.MP4FileClose();
- fclose(fp_h264);
- fclose(fp_AAC);
- }
这里是在Windows平台的代码,MP4V2库编译完成后需要对新建的Mux工作做库和头文件的引入,这里不做介绍。
若是应用平台,请做响应修改!
我的疑问:我在Linux编译成so库,strip后仍然有1M大小,不太适合个别嵌入式项目,正在做相应的裁剪工作,大家若有相关资料,希望能够分享一下!