Mp4v2封裝H264+AAC爲MP4

本文介紹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 


Mux.cpp調用

/********************************************************************
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大小,不太適合個別嵌入式項目,正在做相應的裁剪工作,大家若有相關資料,希望能夠分享一下!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章