您的位置:首页 > 其它

Mp4v2封装H264+AAC为MP4

2016-08-04 16:23 92 查看
本文介绍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<nBuffe
4000
rSize)
{
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
fe64
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大小,不太适合个别嵌入式项目,正在做相应的裁剪工作,大家若有相关资料,希望能够分享一下!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Mp4v2 h264+aac mp4