1、GPAC模块下载链接https://github.com/gpac/gpac或https://gpac.wp.imt.fr/downloads/
2、编译指导https://github.com/gpac/gpac/wiki/Build-Introduction
Windows:https://github.com/gpac/gpac/wiki/GPAC-Build-Guide-for-Windows
Linux:https://github.com/gpac/gpac/wiki/GPAC-Build-Guide-for-Linux
OSX:https://github.com/gpac/gpac/wiki/GPAC-Build-Guide-for-OSX
IOS:https://github.com/gpac/gpac/wiki/GPAC-Build-Guide-for-iOS
Android:https://github.com/gpac/gpac/wiki/GPAC-Build-Guide-for-Android
3、接口定义
头文件声明
-
#ifndef _MP4WRITER_H_
-
#define _MP4WRITER_H_
-
-
#define GPAC_MP4BOX_MINI
-
#include "gpac/setup.h"
-
-
-
-
#define MP4_AUDIO_TYPE_INVALID 0
-
#define MP4_AUDIO_TYPE_AAC_MAIN 1
-
#define MP4_AUDIO_TYPE_AAC_LC 2
-
#define MP4_AUDIO_TYPE_AAC_SSR 3
-
#define MP4_AUDIO_TYPE_AAC_LD 23
-
-
-
-
-
#ifdef __cplusplus
-
extern
"C" {
-
#endif
-
-
void* MP4_Init();
-
s32 MP4_CreatFile(void *pCMP4Writer, char *strFileName);
-
s32 MP4_InitVideo265(void *pCMP4Writer, u32 TimeScale);
-
s32 MP4_Write265Sample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
-
s32 MP4_InitVideo264(void *pCMP4Writer, u32 TimeScale);
-
s32 MP4_Write264Sample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
-
s32 MP4_InitAudioAAC(void *pCMP4Writer, u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale);
-
s32 MP4_WriteAACSample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
-
void MP4_CloseFile(void *pCMP4Writer);
-
void MP4_Exit(void *pCMP4Writer);
-
-
-
#ifdef __cplusplus
-
}
-
#endif
-
-
-
-
#endif
源码实现:
-
#include "MP4Writer.h"
-
-
#include <Winsock2.h>
-
-
-
extern
"C" {
-
#include "gpac/isomedia.h"
-
#include "gpac/constants.h"
-
#include "gpac/internal/media_dev.h"
-
}
-
-
-
#define INIT_STATUS 0
-
#define CONFIG_STATUS 1
-
#define CONFIG_FINISH 2
-
-
-
static s8 GetSampleRateID(u32 SamplRate)
-
{
-
switch (SamplRate)
-
{
-
case
96000:
return
0;
-
case
88200:
return
1;
-
case
64000:
return
2;
-
case
48000:
return
3;
-
case
44100:
return
4;
-
case
32000:
return
5;
-
case
24000:
return
6;
-
case
22050:
return
7;
-
case
16000:
return
8;
-
case
12000:
return
9;
-
case
11025:
return
10;
-
case
8000 :
return
11;
-
case
7350 :
return
12;
-
default:
return
-1;
-
}
-
}
-
-
-
//gf_m4a_get_profile
-
static u8 GetAACProfile(u8 AudioType, u32 SampleRate, u8 Channel)
-
{
-
switch (AudioType)
-
{
-
case
2:
/* AAC LC */
-
{
-
if (Channel <=
2)
return (SampleRate <=
24000) ?
0x28 :
0x29;
/* LC@L1 or LC@L2 */
-
if (Channel <=
5)
return (SampleRate <=
48000) ?
0x2A :
0x2B;
/* LC@L4 or LC@L5 */
-
return (SampleRate <=
48000) ?
0x50 :
0x51;
/* LC@L4 or LC@L5 */
-
}
-
case
5:
/* HE-AAC - SBR */
-
{
-
if (Channel <=
2)
return (SampleRate <=
24000) ?
0x2C :
0x2D;
/* HE@L2 or HE@L3 */
-
if (Channel <=
5)
return (SampleRate <=
48000) ?
0x2E :
0x2F;
/* HE@L4 or HE@L5 */
-
return (SampleRate <=
48000) ?
0x52 :
0x53;
/* HE@L6 or HE@L7 */
-
}
-
case
29:
/*HE-AACv2 - SBR+PS*/
-
{
-
if (Channel <=
2)
return (SampleRate <=
24000) ?
0x30 :
0x31;
/* HE-AACv2@L2 or HE-AACv2@L3 */
-
if (Channel <=
5)
return (SampleRate <=
48000) ?
0x32 :
0x33;
/* HE-AACv2@L4 or HE-AACv2@L5 */
-
return (SampleRate <=
48000) ?
0x54 :
0x55;
/* HE-AACv2@L6 or HE-AACv2@L7 */
-
}
-
default:
/* default to HQ */
-
{
-
if (Channel <=
2)
return (SampleRate <
24000) ?
0x0E :
0x0F;
/* HQ@L1 or HQ@L2 */
-
return
0x10;
/* HQ@L3 */
-
}
-
}
-
}
-
-
static
void GetAudioSpecificConfig(u8 AudioType, u8 SampleRateID, u8 Channel, u8 *pHigh, u8 *pLow)
-
{
-
u16 Config;
-
-
Config = (AudioType &
0x1f);
-
Config <<=
4;
-
Config |= SampleRateID &
0x0f;
-
Config <<=
4;
-
Config |= Channel &
0x0f;
-
Config <<=
3;
-
-
*pLow = Config &
0xff;
-
Config >>=
8;
-
*pHigh = Config &
0xff;
-
}
-
-
/* 返回的数据包括起始的4个字节0x00000001 */
-
static u8* FindNalu(u8 *pStart, u32 Size, u8 *pNaluType, u32 *pNaluSize)
-
{
-
u8 *pEnd;
-
u8 *pCur;
-
u8 *pOut;
-
u8 NaluType;
-
-
if (
4 >= Size)
-
return
NULL;
-
-
/* 找第一个0x00000001 */
-
pCur = pStart;
-
pEnd = pStart + Size -
4;
-
while (pCur < pEnd)
-
{
-
if ( (
0 == pCur[
0]) && (
0 == pCur[
1]) && (
0 == pCur[
2]) && (
1 == pCur[
3]) )
-
break;
-
pCur++;
-
}
-
if (pCur >= pEnd)
-
return
NULL;
-
-
NaluType = (pCur[
4] >>
1) &
0x3f;
-
*pNaluType = NaluType;
-
-
if (
1 == NaluType ||
19 == NaluType)
/* P帧、I帧, 假设每一包里P帧I帧都是最后一个 */
-
{
-
*pNaluSize = Size - (pCur - pStart);
-
return pCur;
-
}
-
-
pOut = pCur;
-
-
/* 找第二个0x00000001 */
-
pCur +=
5;
-
while (pCur <= pEnd)
-
{
-
if ( (
0 == pCur[
0]) && (
0 == pCur[
1]) && (
0 == pCur[
2]) && (
1 == pCur[
3]) )
-
break;
-
pCur++;
-
}
-
if (pCur <= pEnd)
-
{
-
*pNaluSize = pCur - pOut;
-
return pOut;
-
}
-
-
*pNaluSize = Size - (pOut - pStart);
-
return pOut;
-
}
-
-
/* 返回的数据包括起始的4个字节0x00000001 */
-
static u8* FindNalu264(u8 *pStart, u32 Size, u8 *pNaluType, u32 *pNaluSize)
-
{
-
u8 *pEnd;
-
u8 *pCur;
-
u8 *pOut;
-
u8 NaluType;
-
-
if (
4 >= Size)
-
return
NULL;
-
-
/* 找第一个0x00000001 */
-
pCur = pStart;
-
pEnd = pStart + Size -
4;
-
while (pCur < pEnd)
-
{
-
if ((
0 == pCur[
0]) && (
0 == pCur[
1]) && (
0 == pCur[
2]) && (
1 == pCur[
3]))
-
break;
-
pCur++;
-
}
-
if (pCur >= pEnd)
-
return
NULL;
-
-
NaluType = (pCur[
4]) &
0x1f;
-
*pNaluType = NaluType;
-
-
if (
1 == NaluType ||
5 == NaluType)
/* P帧、I帧, 假设每一包里P帧I帧都是最后一个 */
-
{
-
*pNaluSize = Size - (pCur - pStart);
-
return pCur;
-
}
-
-
pOut = pCur;
-
-
/* 找第二个0x00000001 */
-
pCur +=
5;
-
while (pCur <= pEnd)
-
{
-
if ((
0 == pCur[
0]) && (
0 == pCur[
1]) && (
0 == pCur[
2]) && (
1 == pCur[
3]))
-
break;
-
pCur++;
-
}
-
if (pCur <= pEnd)
-
{
-
*pNaluSize = pCur - pOut;
-
return pOut;
-
}
-
-
*pNaluSize = Size - (pOut - pStart);
-
return pOut;
-
}
-
-
-
// aac数据时记得除掉adts头
-
static
int AdtsDemux(unsigned char * data, unsigned
int size, unsigned char** raw,
int* raw_size)
-
{
-
int ret =
1;
-
if (size <
7) {
-
ttf_human_trace(
"adts: demux size too small");
-
return
0;
-
}
-
unsigned char* p = data;
-
unsigned char* pend = data + size;
-
//unsigned char* startp = 0;
-
-
while (p < pend) {
-
-
// decode the ADTS.
-
// @see aac-iso-13818-7.pdf, page 26
-
// 6.2 Audio Data Transport Stream, ADTS
-
// @see https://github.com/ossrs/srs/issues/212#issuecomment-64145885
-
// byte_alignment()
-
-
// adts_fixed_header:
-
// 12bits syncword,
-
// 16bits left.
-
// adts_variable_header:
-
// 28bits
-
// 12+16+28=56bits
-
// adts_error_check:
-
// 16bits if protection_absent
-
// 56+16=72bits
-
// if protection_absent:
-
// require(7bytes)=56bits
-
// else
-
// require(9bytes)=72bits
-
-
//startp = p;
-
-
// for aac, the frame must be ADTS format.
-
/*if (p[0] != 0xff || (p[1] & 0xf0) != 0xf0) {
-
ttf_human_trace("adts: not this format.");
-
return 0;
-
}*/
-
-
// syncword 12 bslbf
-
p++;
-
// 4bits left.
-
// adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS
-
// ID 1 bslbf
-
// layer 2 uimsbf
-
// protection_absent 1 bslbf
-
int8_t pav = (*p++ &
0x0f);
-
//int8_t id = (pav >> 3) & 0x01;
-
/*int8_t layer = (pav >> 1) & 0x03;*/
-
int8_t protection_absent = pav &
0x01;
-
-
/**
-
* ID: MPEG identifier, set to '1' if the audio data in the ADTS stream are MPEG-2 AAC (See ISO/IEC 13818-7)
-
* and set to '0' if the audio data are MPEG-4. See also ISO/IEC 11172-3, subclause 2.4.2.3.
-
*/
-
//if (id != 0x01) {
-
// //ttf_human_trace("adts: id must be 1(aac), actual 0(mp4a).");
-
-
// // well, some system always use 0, but actually is aac format.
-
// // for example, houjian vod ts always set the aac id to 0, actually 1.
-
// // we just ignore it, and alwyas use 1(aac) to demux.
-
// id = 0x01;
-
//}
-
//else {
-
// //ttf_human_trace("adts: id must be 1(aac), actual 1(mp4a).");
-
//}
-
-
//int16_t sfiv = (*p << 8) | (*(p + 1));
-
p +=
2;
-
// profile 2 uimsbf
-
// sampling_frequency_index 4 uimsbf
-
// private_bit 1 bslbf
-
// channel_configuration 3 uimsbf
-
// original/copy 1 bslbf
-
// home 1 bslbf
-
//int8_t profile = (sfiv >> 14) & 0x03;
-
//int8_t sampling_frequency_index = (sfiv >> 10) & 0x0f;
-
/*int8_t private_bit = (sfiv >> 9) & 0x01;*/
-
//int8_t channel_configuration = (sfiv >> 6) & 0x07;
-
/*int8_t original = (sfiv >> 5) & 0x01;*/
-
/*int8_t home = (sfiv >> 4) & 0x01;*/
-
//int8_t Emphasis; @remark, Emphasis is removed, @see https://github.com/ossrs/srs/issues/212#issuecomment-64154736
-
// 4bits left.
-
// adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS
-
// copyright_identification_bit 1 bslbf
-
// copyright_identification_start 1 bslbf
-
/*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/
-
/*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/
-
// frame_length 13 bslbf: Length of the frame including headers and error_check in bytes.
-
// use the left 2bits as the 13 and 12 bit,
-
// the frame_length is 13bits, so we move 13-2=11.
-
//int16_t frame_length = (sfiv << 11) & 0x1800;
-
-
//int32_t abfv = ((*p) << 16)
-
// | ((*(p + 1)) << 8)
-
// | (*(p + 2));
-
p +=
3;
-
// frame_length 13 bslbf: consume the first 13-2=11bits
-
// the fh2 is 24bits, so we move right 24-11=13.
-
//frame_length |= (abfv >> 13) & 0x07ff;
-
// adts_buffer_fullness 11 bslbf
-
/*int16_t fh_adts_buffer_fullness = (abfv >> 2) & 0x7ff;*/
-
// number_of_raw_data_blocks_in_frame 2 uimsbf
-
/*int16_t number_of_raw_data_blocks_in_frame = abfv & 0x03;*/
-
// adts_error_check(), 1.A.2.2.3 Error detection
-
if (!protection_absent) {
-
if (size <
9) {
-
ttf_human_trace(
"adts: protection_absent disappare.");
-
return
0;
-
}
-
// crc_check 16 Rpchof
-
/*int16_t crc_check = */p +=
2;
-
}
-
-
// TODO: check the sampling_frequency_index
-
// TODO: check the channel_configuration
-
-
// raw_data_blocks
-
/*int adts_header_size = p - startp;
-
int raw_data_size = frame_length - adts_header_size;
-
if (raw_data_size > pend - p) {
-
ttf_human_trace("adts: raw data size too little.");
-
return 0;
-
}*/
-
-
//adts_codec_.protection_absent = protection_absent;
-
//adts_codec_.aac_object = srs_codec_aac_ts2rtmp((SrsAacProfile)profile);
-
//adts_codec_.sampling_frequency_index = sampling_frequency_index;
-
//adts_codec_.channel_configuration = channel_configuration;
-
//adts_codec_.frame_length = frame_length;
-
-
@see srs_audio_write_raw_frame().
-
TODO: FIXME: maybe need to resample audio.
-
//adts_codec_.sound_format = 10; // AAC
-
//if (sampling_frequency_index <= 0x0c && sampling_frequency_index > 0x0a) {
-
// adts_codec_.sound_rate = SrsCodecAudioSampleRate5512;
-
//}
-
//else if (sampling_frequency_index <= 0x0a && sampling_frequency_index > 0x07) {
-
// adts_codec_.sound_rate = SrsCodecAudioSampleRate11025;
-
//}
-
//else if (sampling_frequency_index <= 0x07 && sampling_frequency_index > 0x04) {
-
// adts_codec_.sound_rate = SrsCodecAudioSampleRate22050;
-
//}
-
//else if (sampling_frequency_index <= 0x04) {
-
// adts_codec_.sound_rate = SrsCodecAudioSampleRate44100;
-
//}
-
//else {
-
// adts_codec_.sound_rate = SrsCodecAudioSampleRate44100;
-
// //srs_warn("adts invalid sample rate for flv, rate=%#x", sampling_frequency_index);
-
//}
-
//adts_codec_.sound_type = srs_max(0, srs_min(1, channel_configuration - 1));
-
TODO: FIXME: finger it out the sound size by adts.
-
//adts_codec_.sound_size = 1; // 0(8bits) or 1(16bits).
-
-
// frame data.
-
*raw = p;
-
*raw_size = pend - p;
-
-
break;
-
}
-
-
return ret;
-
}
-
-
class MP4Writer
-
{
-
public:
-
MP4Writer();
-
~MP4Writer();
-
-
s32 CreatFile(char *strFileName);
-
s32 Init265(u32 TimeScale);
-
s32 Write265Sample(u8 *pData, u32 Size, u64 TimeStamp);
-
s32 Init264(u32 TimeScale);
-
s32 Write264Sample(u8 *pData, u32 Size, u64 TimeStamp);
-
s32 InitAAC(u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale);
-
s32 WriteAACSample(u8 *pData, u32 Size, u64 TimeStamp);
-
void CloseFile();
-
-
private:
-
GF_ISOFile *m_ptFile;
-
-
u32 m_265TrackIndex;
-
u32 m_265StreamIndex;
-
u8 m_Video265Statue;
-
u32 m_264TrackIndex;
-
u32 m_264StreamIndex;
-
u8 m_Video264Statue;
-
s64 m_VideoTimeStampStart;
-
-
GF_HEVCConfig *m_ptHEVCConfig;
-
GF_HEVCParamArray* m_tHEVCNaluParam_VPS;
-
GF_HEVCParamArray* m_tHEVCNaluParam_SPS;
-
GF_HEVCParamArray* m_tHEVCNaluParam_PPS;
-
GF_AVCConfigSlot* m_tAVCConfig_VPS;
-
GF_AVCConfigSlot* m_tAVCConfig_SPS;
-
GF_AVCConfigSlot* m_tAVCConfig_PPS;
-
-
GF_AVCConfigSlot* m_tAVCConfig_SPS264;
-
GF_AVCConfigSlot* m_tAVCConfig_PPS264;
-
-
GF_AVCConfig *m_ptAVCConfig;
-
-
HEVCState *m_ptHEVCState;
-
AVCState *m_ptAVCState;
-
-
u32 m_AACTrackIndex;
-
u32 m_AACStreamIndex;
-
u8 m_AudioAACStatue;
-
s64 m_AudioTimeStampStart;
-
bool findfirsidr_;
-
-
-
void FreeAllMem();
-
};
-
-
-
MP4Writer::MP4Writer()
-
{
-
m_ptFile =
NULL;
-
m_ptHEVCConfig =
NULL;
-
m_ptAVCConfig =
NULL;
-
-
m_Video265Statue = INIT_STATUS;
-
m_AudioAACStatue = INIT_STATUS;
-
m_Video264Statue = INIT_STATUS;
-
-
m_tHEVCNaluParam_VPS =
NULL;
-
m_tHEVCNaluParam_SPS =
NULL;
-
m_tHEVCNaluParam_PPS =
NULL;
-
m_tAVCConfig_VPS =
NULL;
-
m_tAVCConfig_SPS =
NULL;
-
m_tAVCConfig_PPS =
NULL;
-
-
m_tAVCConfig_SPS264 =
NULL;
-
m_tAVCConfig_PPS264 =
NULL;
-
-
m_ptHEVCState =
NULL;
-
m_ptAVCState =
NULL;
-
-
findfirsidr_ =
false;
-
}
-
-
MP4Writer::~MP4Writer()
-
{
-
CloseFile();
-
}
-
-
s32 MP4Writer::CreatFile(char *strFileName)
-
{
-
if (
NULL != m_ptFile)
-
{
-
return
-1;
-
}
-
-
m_ptFile = gf_isom_open(strFileName, GF_ISOM_OPEN_WRITE,
NULL);
-
if (
NULL == m_ptFile)
-
{
-
return
-1;
-
}
-
-
gf_isom_set_brand_info(m_ptFile, GF_ISOM_BRAND_MP42,
0);
-
-
return
0;
-
}
-
-
-
void MP4Writer::CloseFile()
-
{
-
if (m_ptFile)
-
{
-
gf_isom_close(m_ptFile);
-
m_ptFile =
NULL;
-
-
FreeAllMem();
-
}
-
}
-
-
void MP4Writer::FreeAllMem()
-
{
-
-
if (m_ptHEVCConfig)
-
{
-
gf_odf_hevc_cfg_del(m_ptHEVCConfig);
-
//gf_list_del(m_ptHEVCConfig->param_array);
-
//free(m_ptHEVCConfig);
-
m_ptHEVCConfig =
NULL;
-
}
-
-
if (m_ptAVCConfig) {
-
gf_odf_avc_cfg_del(m_ptAVCConfig);
-
//gf_list_del(m_ptAVCConfig->param_array);
-
//free(m_ptAVCConfig);
-
m_ptAVCConfig =
NULL;
-
}
-
-
if (m_ptHEVCState) {
-
free(m_ptHEVCState);
-
m_ptHEVCState =
NULL;
-
}
-
-
if (m_ptAVCState) {
-
free(m_ptAVCState);
-
m_ptAVCState =
NULL;
-
}
-
-
m_tHEVCNaluParam_VPS =
NULL;
-
m_tHEVCNaluParam_SPS =
NULL;
-
m_tHEVCNaluParam_PPS =
NULL;
-
m_tAVCConfig_VPS =
NULL;
-
m_tAVCConfig_SPS =
NULL;
-
m_tAVCConfig_PPS =
NULL;
-
-
m_tAVCConfig_SPS264 =
NULL;
-
m_tAVCConfig_PPS264 =
NULL;
-
-
m_Video265Statue = INIT_STATUS;
-
m_AudioAACStatue = INIT_STATUS;
-
m_Video264Statue = INIT_STATUS;
-
-
findfirsidr_ =
false;
-
-
}
-
-
s32 MP4Writer::Init265(u32 TimeScale)
-
{
-
if (
NULL == m_ptFile || INIT_STATUS != m_Video265Statue)
-
return
-1;
-
-
-
m_VideoTimeStampStart =
-1;
-
-
/* 创建Track */
-
m_265TrackIndex = gf_isom_new_track(m_ptFile,
0, GF_ISOM_MEDIA_VISUAL, TimeScale);
-
if (
0 == m_265TrackIndex)
-
return
-1;
-
if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_265TrackIndex,
1))
-
return
-1;
-
-
-
/* 创建流 */
-
m_ptHEVCConfig = gf_odf_hevc_cfg_new();
-
if (
NULL == m_ptHEVCConfig)
-
return
-1;
-
m_ptHEVCConfig->nal_unit_size =
4;
-
m_ptHEVCConfig->configurationVersion =
1;
-
-
if (GF_OK != gf_isom_hevc_config_new(m_ptFile, m_265TrackIndex, m_ptHEVCConfig,
NULL,
NULL, &m_265StreamIndex))
-
return
-1;
-
-
-
-
/* 初始化流的配置结构 */
-
GF_SAFEALLOC(m_tHEVCNaluParam_VPS, GF_HEVCParamArray);
-
GF_SAFEALLOC(m_tHEVCNaluParam_SPS, GF_HEVCParamArray);
-
GF_SAFEALLOC(m_tHEVCNaluParam_PPS, GF_HEVCParamArray);
-
GF_SAFEALLOC(m_tAVCConfig_VPS, GF_AVCConfigSlot);
-
GF_SAFEALLOC(m_tAVCConfig_SPS, GF_AVCConfigSlot);
-
GF_SAFEALLOC(m_tAVCConfig_PPS, GF_AVCConfigSlot);
-
-
if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_VPS))
-
return
-1;
-
if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_SPS))
-
return
-1;
-
if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_PPS))
-
return
-1;
-
-
m_tHEVCNaluParam_VPS->nalus = gf_list_new();
-
if (
NULL == m_tHEVCNaluParam_VPS->nalus)
-
return
-1;
-
m_tHEVCNaluParam_SPS->nalus = gf_list_new();
-
if (
NULL == m_tHEVCNaluParam_SPS->nalus)
-
return
-1;
-
m_tHEVCNaluParam_PPS->nalus = gf_list_new();
-
if (
NULL == m_tHEVCNaluParam_PPS->nalus)
-
return
-1;
-
m_tHEVCNaluParam_VPS->type = GF_HEVC_NALU_VID_PARAM;
-
m_tHEVCNaluParam_SPS->type = GF_HEVC_NALU_SEQ_PARAM;
-
m_tHEVCNaluParam_PPS->type = GF_HEVC_NALU_PIC_PARAM;
-
m_tHEVCNaluParam_VPS->array_completeness =
1;
-
m_tHEVCNaluParam_SPS->array_completeness =
1;
-
m_tHEVCNaluParam_PPS->array_completeness =
1;
-
-
if (GF_OK != gf_list_add(m_tHEVCNaluParam_VPS->nalus, m_tAVCConfig_VPS))
-
return
-1;
-
if (GF_OK != gf_list_add(m_tHEVCNaluParam_SPS->nalus, m_tAVCConfig_SPS))
-
return
-1;
-
if (GF_OK != gf_list_add(m_tHEVCNaluParam_PPS->nalus, m_tAVCConfig_PPS))
-
return
-1;
-
-
-
m_ptHEVCState = (HEVCState *)malloc(sizeof(HEVCState));
//gf_malloc
-
if (
NULL == m_ptHEVCState)
-
return
-1;
-
memset(m_ptHEVCState,
0, sizeof(HEVCState));
-
-
-
m_Video265Statue = CONFIG_STATUS;
-
-
return
0;
-
}
-
-
-
s32 MP4Writer::Write265Sample(u8 *pData, u32 Size, u64 TimeStamp)
-
{
-
u8 *pStart = pData;
-
u8 NaluType;
-
u32 NaluSize =
0;
-
s32 ID;
-
-
GF_ISOSample tISOSample;
-
-
/* 265还未初始化 */
-
if (INIT_STATUS == m_Video265Statue)
-
return
-1;
-
-
while (
1)
-
{
-
pData = FindNalu(pData + NaluSize, Size - (u32)(pData - pStart) - NaluSize, &NaluType, &NaluSize);
-
if (
NULL == pData)
-
break;
-
-
/* 配置完成后只处理IP帧 */
-
if (CONFIG_FINISH == m_Video265Statue)
-
{
-
if (
1 != NaluType &&
19 != NaluType)
/* P帧 I帧 */
-
continue;
-
-
if (
-1 == m_VideoTimeStampStart)
-
m_VideoTimeStampStart = TimeStamp;
-
-
*((u32 *)pData) = htonl(NaluSize -
4);
/* 这里的长度不能包括前四个字节的头! */
-
tISOSample.data = (char *)pData;
-
tISOSample.dataLength = NaluSize;
-
tISOSample.IsRAP = (
19 == NaluType)? RAP: RAP_NO;
-
tISOSample.DTS = TimeStamp - m_VideoTimeStampStart;
-
tISOSample.CTS_Offset =
0;
-
if (GF_OK != gf_isom_add_sample(m_ptFile, m_265TrackIndex, m_265StreamIndex, &tISOSample))
-
{
-
*((u32 *)pData) = htonl(
1);
/* 恢复0x00000001的头 */
-
return
-1;
-
}
-
-
*((u32 *)pData) = htonl(
1);
/* 恢复0x00000001的头 */
-
}
-
/* 配置未完成时只处理vps sps pps头 */
-
else
if (CONFIG_STATUS == m_Video265Statue)
-
{
-
pData +=
4;
-
NaluSize -=
4;
-
-
if (
32 == NaluType &&
NULL == m_tAVCConfig_VPS->data)
/* VPS */
-
{
-
ID = gf_media_hevc_read_vps((char *)pData , NaluSize, m_ptHEVCState);
-
m_ptHEVCConfig->avgFrameRate = m_ptHEVCState->vps[ID].rates[
0].avg_pic_rate;
-
m_ptHEVCConfig->temporalIdNested = m_ptHEVCState->vps[ID].temporal_id_nesting;
-
m_ptHEVCConfig->constantFrameRate = m_ptHEVCState->vps[ID].rates[
0].constand_pic_rate_idc;
-
m_ptHEVCConfig->numTemporalLayers = m_ptHEVCState->vps[ID].max_sub_layers;
-
m_tAVCConfig_VPS->id = ID;
-
m_tAVCConfig_VPS->size = (u16)NaluSize;
-
m_tAVCConfig_VPS->data = (char *)malloc(NaluSize);
-
if (
NULL == m_tAVCConfig_VPS->data)
-
continue;
-
memcpy(m_tAVCConfig_VPS->data, pData, NaluSize);
-
}
-
else
if (
33 == NaluType &&
NULL == m_tAVCConfig_SPS->data)
/* SPS */
-
{
-
ID = gf_media_hevc_read_sps((char *)pData, NaluSize, m_ptHEVCState);
-
m_ptHEVCConfig->tier_flag = m_ptHEVCState->sps[ID].ptl.tier_flag;
-
m_ptHEVCConfig->profile_idc = m_ptHEVCState->sps[ID].ptl.profile_idc;
-
m_ptHEVCConfig->profile_space = m_ptHEVCState->sps[ID].ptl.profile_space;
-
m_tAVCConfig_SPS->id = ID;
-
m_tAVCConfig_SPS->size = (u16)NaluSize;
-
m_tAVCConfig_SPS->data = (char *)malloc(NaluSize);
-
if (
NULL == m_tAVCConfig_SPS->data)
-
continue;
-
memcpy(m_tAVCConfig_SPS->data, pData, NaluSize);
-
-
gf_isom_set_visual_info(m_ptFile, m_265TrackIndex, m_265StreamIndex, m_ptHEVCState->sps[ID].width, m_ptHEVCState->sps[ID].height);
-
}
-
else
if (
34 == NaluType &&
NULL == m_tAVCConfig_PPS->data)
/* PPS */
-
{
-
m_tAVCConfig_PPS->id = ID;
-
m_tAVCConfig_PPS->size = (u16)NaluSize;
-
m_tAVCConfig_PPS->data = (char *)malloc(NaluSize);
-
if (
NULL == m_tAVCConfig_PPS->data)
-
continue;
-
memcpy(m_tAVCConfig_PPS->data, pData, NaluSize);
-
}
-
else
-
{
-
continue;
-
}
-
-
if (m_tAVCConfig_VPS->data && m_tAVCConfig_SPS->data && m_tAVCConfig_PPS->data)
-
{
-
gf_isom_hevc_config_update(m_ptFile, m_265TrackIndex, m_265StreamIndex, m_ptHEVCConfig);
-
m_Video265Statue = CONFIG_FINISH;
-
if (m_ptHEVCState) {
-
free(m_ptHEVCState);
-
m_ptHEVCState =
NULL;
-
}
-
}
-
}
-
}
-
-
return
0;
-
}
-
-
s32 MP4Writer::Init264(u32 TimeScale)
-
{
-
if (
NULL == m_ptFile || INIT_STATUS != m_Video265Statue)
-
return
-1;
-
-
-
m_VideoTimeStampStart =
-1;
-
-
/* 创建Track */
-
m_264TrackIndex = gf_isom_new_track(m_ptFile,
0, GF_ISOM_MEDIA_VISUAL, TimeScale);
-
if (
0 == m_264TrackIndex)
-
return
-1;
-
if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_264TrackIndex,
1))
-
return
-1;
-
-
-
/* 创建流 */
-
m_ptAVCConfig = gf_odf_avc_cfg_new();
-
if (
NULL == m_ptAVCConfig)
-
return
-1;
-
//m_ptAVCConfig->nal_unit_size = 4;
-
m_ptAVCConfig->configurationVersion =
1;
-
-
if (GF_OK != gf_isom_avc_config_new(m_ptFile, m_264TrackIndex, m_ptAVCConfig,
NULL,
NULL, &m_264StreamIndex))
-
return
-1;
-
-
/* 初始化流的配置结构 */
-
GF_SAFEALLOC(m_tAVCConfig_SPS264, GF_AVCConfigSlot);
-
GF_SAFEALLOC(m_tAVCConfig_PPS264, GF_AVCConfigSlot);
-
-
gf_list_add(m_ptAVCConfig->sequenceParameterSets, m_tAVCConfig_SPS264);
-
gf_list_add(m_ptAVCConfig->pictureParameterSets, m_tAVCConfig_PPS264);
-
-
m_ptAVCState = (AVCState *)malloc(sizeof(AVCState));
//gf_malloc
-
if (
NULL == m_ptAVCState)
-
return
-1;
-
memset(m_ptAVCState,
0, sizeof(AVCState));
-
-
-
m_Video264Statue = CONFIG_STATUS;
-
-
return
0;
-
}
-
-
-
s32 MP4Writer::Write264Sample(u8 *pData, u32 Size, u64 TimeStamp)
-
{
-
u8 *pStart = pData;
-
u8 NaluType;
-
u32 NaluSize =
0;
-
s32 ID;
-
-
GF_ISOSample tISOSample;
-
-
/* 265还未初始化 */
-
if (INIT_STATUS == m_Video264Statue)
-
return
-1;
-
-
while (
1)
-
{
-
pData = FindNalu264(pData + NaluSize, Size - (u32)(pData - pStart) - NaluSize, &NaluType, &NaluSize);
-
if (
NULL == pData)
-
break;
-
-
/* 配置完成后只处理IP帧 */
-
if (CONFIG_FINISH == m_Video264Statue)
-
{
-
if (!findfirsidr_) {
-
if (
5 != NaluType)
-
continue;
-
else
-
findfirsidr_ =
true;
-
}
-
-
if (
1 != NaluType &&
5 != NaluType)
/* P帧 I帧 */
-
continue;
-
-
if (
-1 == m_VideoTimeStampStart)
-
m_VideoTimeStampStart = TimeStamp;
-
-
*((u32 *)pData) = htonl(NaluSize -
4);
/* 这里的长度不能包括前四个字节的头! */
-
tISOSample.data = (char *)pData;
-
tISOSample.dataLength = NaluSize;
-
tISOSample.IsRAP = (
5 == NaluType) ? RAP : RAP_NO;
-
tISOSample.DTS = TimeStamp - m_VideoTimeStampStart;
-
tISOSample.CTS_Offset =
0;
-
tISOSample.nb_pack =
0;
-
int ret = gf_isom_add_sample(m_ptFile, m_264TrackIndex, m_264StreamIndex, &tISOSample);
-
if (GF_OK != ret)
-
{
-
-
//*((u32 *)pData) = htonl(1); /* 恢复0x00000001的头 */
-
return
-1;
-
}
-
-
//*((u32 *)pData) = htonl(1); /* 恢复0x00000001的头 */
-
}
-
/* 配置未完成时只处理vps sps pps头 */
-
else
if (CONFIG_STATUS == m_Video264Statue)
-
{
-
pData +=
4;
-
NaluSize -=
4;
-
-
if (
7 == NaluType &&
NULL == m_tAVCConfig_SPS264->data)
/* SPS */
-
{
-
ID = gf_media_avc_read_sps((char *)pData, NaluSize, m_ptAVCState,
0,
NULL);
-
m_ptAVCConfig->AVCProfileIndication = m_ptAVCState->sps[ID].profile_idc;
-
m_ptAVCConfig->profile_compatibility = m_ptAVCState->sps[ID].prof_compat;
-
m_ptAVCConfig->AVCLevelIndication = m_ptAVCState->sps[ID].level_idc;
-
m_tAVCConfig_SPS264->id = ID;
-
m_tAVCConfig_SPS264->size = (u16)NaluSize;
-
m_tAVCConfig_SPS264->data = (char *)malloc(NaluSize);
-
if (
NULL == m_tAVCConfig_SPS264->data)
-
continue;
-
memcpy(m_tAVCConfig_SPS264->data, pData, NaluSize);
-
-
gf_isom_set_visual_info(m_ptFile, m_264TrackIndex, m_264StreamIndex, m_ptAVCState->sps[ID].width, m_ptAVCState->sps[ID].height);
-
}
-
else
if (
8 == NaluType &&
NULL == m_tAVCConfig_PPS264->data)
/* PPS */
-
{
-
m_tAVCConfig_PPS264->id = ID;
-
m_tAVCConfig_PPS264->size = (u16)NaluSize;
-
m_tAVCConfig_PPS264->data = (char *)malloc(NaluSize);
-
if (
NULL == m_tAVCConfig_PPS264->data)
-
continue;
-
memcpy(m_tAVCConfig_PPS264->data, pData, NaluSize);
-
}
-
else
-
{
-
continue;
-
}
-
-
if (m_tAVCConfig_SPS264->data && m_tAVCConfig_PPS264->data)
-
{
-
gf_isom_avc_config_update(m_ptFile, m_264TrackIndex, m_264StreamIndex, m_ptAVCConfig);
-
m_Video264Statue = CONFIG_FINISH;
-
if (m_ptAVCState) {
-
free(m_ptAVCState);
-
m_ptAVCState =
NULL;
-
}
-
}
-
}
-
}
-
-
return
0;
-
}
-
-
-
s32 MP4Writer::InitAAC(u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale)
-
{
-
GF_ESD *ptStreamDesc;
-
s8 SampleRateID;
-
u16 AudioConfig =
0;
-
u8 AACProfile;
-
s32 res =
0;
-
-
-
if (
NULL == m_ptFile || INIT_STATUS != m_AudioAACStatue)
-
return
-1;
-
-
-
m_AudioTimeStampStart =
-1;
-
-
/* 创建Track */
-
m_AACTrackIndex = gf_isom_new_track(m_ptFile,
0, GF_ISOM_MEDIA_AUDIO, TimeScale);
-
if (
0 == m_AACTrackIndex)
-
return
-1;
-
-
if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_AACTrackIndex,
1))
-
return
-1;
-
-
-
/* 创建并配置流 */
-
SampleRateID = GetSampleRateID(SampleRate);
-
if (
0 > SampleRateID)
-
return
-1;
-
GetAudioSpecificConfig(AudioType, (u8)SampleRateID, Channel, (u8*)(&AudioConfig), ((u8*)(&AudioConfig))+
1);
-
-
ptStreamDesc = gf_odf_desc_esd_new(SLPredef_MP4);
-
ptStreamDesc->slConfig->timestampResolution = TimeScale;
-
ptStreamDesc->decoderConfig->streamType = GF_STREAM_AUDIO;
-
//ptStreamDesc->decoderConfig->bufferSizeDB = 20; //这参数干什么的
-
ptStreamDesc->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4;
-
ptStreamDesc->decoderConfig->decoderSpecificInfo->dataLength =
2;
-
ptStreamDesc->decoderConfig->decoderSpecificInfo->data = (char *)&AudioConfig;
-
ptStreamDesc->ESID = gf_isom_get_track_id(m_ptFile, m_AACTrackIndex);
-
if (GF_OK != gf_isom_new_mpeg4_description(m_ptFile, m_AACTrackIndex, ptStreamDesc,
NULL,
NULL, &m_AACStreamIndex))
-
{
-
res =
-1;
-
goto ERR;
-
}
-
-
if (gf_isom_set_audio_info(m_ptFile, m_AACTrackIndex, m_AACStreamIndex, SampleRate, Channel,
16, GF_IMPORT_AUDIO_SAMPLE_ENTRY_NOT_SET))
-
{
-
res =
-1;
-
goto ERR;
-
}
-
-
AACProfile = GetAACProfile(AudioType, SampleRate, Channel);
-
gf_isom_set_pl_indication(m_ptFile, GF_ISOM_PL_AUDIO, AACProfile);
-
-
m_AudioAACStatue = CONFIG_FINISH;
-
-
-
ERR:
-
ptStreamDesc->decoderConfig->decoderSpecificInfo->data =
NULL;
-
gf_odf_desc_del((GF_Descriptor *)ptStreamDesc);
-
-
return res;
-
}
-
-
-
s32 MP4Writer::WriteAACSample(u8 *pData, u32 Size, u64 TimeStamp)
-
{
-
GF_ISOSample tISOSample;
-
-
if (CONFIG_FINISH != m_AudioAACStatue)
-
return
0;
-
-
if (!findfirsidr_) {
-
return
0;
-
}
-
-
if (
-1 == m_AudioTimeStampStart)
-
m_AudioTimeStampStart = TimeStamp;
-
-
tISOSample.IsRAP = RAP;
-
tISOSample.dataLength = Size;
-
tISOSample.data = (char *)pData;
-
tISOSample.DTS = TimeStamp - m_AudioTimeStampStart;
-
tISOSample.CTS_Offset =
0;
-
tISOSample.nb_pack =
0;
-
if (GF_OK != gf_isom_add_sample(m_ptFile, m_AACTrackIndex, m_AACStreamIndex, &tISOSample))
-
return
-1;
-
-
return
0;
-
}
-
-
-
-
-
extern
"C" {
-
-
-
void* MP4_Init()
-
{
-
return (
void *)(
new MP4Writer());
-
}
-
-
s32 MP4_CreatFile(
void *pCMP4Writer, char *strFileName)
-
{
-
if (
NULL == pCMP4Writer)
-
return
-1;
-
-
return ((MP4Writer *)pCMP4Writer)->CreatFile(strFileName);
-
}
-
-
s32 MP4_InitVideo265(
void *pCMP4Writer, u32 TimeScale)
-
{
-
if (
NULL == pCMP4Writer)
-
return
-1;
-
-
return ((MP4Writer *)pCMP4Writer)->Init265(TimeScale);
-
}
-
-
s32 MP4_Write265Sample(
void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp)
-
{
-
if (
NULL == pCMP4Writer)
-
return
-1;
-
-
return ((MP4Writer *)pCMP4Writer)->Write265Sample(pData, Size, TimeStamp);
-
}
-
-
s32 MP4_InitVideo264(
void * pCMP4Writer, u32 TimeScale)
-
{
-
if (
NULL == pCMP4Writer)
-
return
-1;
-
-
return ((MP4Writer *)pCMP4Writer)->Init264(TimeScale);
-
}
-
-
s32 MP4_Write264Sample(
void * pCMP4Writer, u8 * pData, u32 Size, u64 TimeStamp)
-
{
-
if (
NULL == pCMP4Writer)
-
return
-1;
-
-
return ((MP4Writer *)pCMP4Writer)->Write264Sample(pData, Size, TimeStamp);
-
}
-
-
s32 MP4_InitAudioAAC(
void *pCMP4Writer, u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale)
-
{
-
if (
NULL == pCMP4Writer)
-
return
-1;
-
-
return ((MP4Writer *)pCMP4Writer)->InitAAC(AudioType, SampleRate, Channel, TimeScale);
-
}
-
-
s32 MP4_WriteAACSample(
void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp)
-
{
-
if (
NULL == pCMP4Writer)
-
return
-1;
-
-
return ((MP4Writer *)pCMP4Writer)->WriteAACSample(pData, Size, TimeStamp);
-
}
-
-
void MP4_CloseFile(
void *pCMP4Writer)
-
{
-
if (
NULL == pCMP4Writer)
-
return;
-
-
((MP4Writer *)pCMP4Writer)->CloseFile();
-
}
-
-
void MP4_Exit(
void *pCMP4Writer)
-
{
-
if (
NULL == pCMP4Writer)
-
return;
-
-
delete pCMP4Writer;
-
}
-
-
-
}
AudioType类型值如下:
-
GF_M4A_AAC_MAIN =
1, // Main主规格
-
GF_M4A_AAC_LC =
2, // LC低复杂度规格(Low Complexity)
-
GF_M4A_AAC_SSR =
3, // SSR可变采样率规格(Scaleable Sample Rate)
-
GF_M4A_AAC_LTP =
4, // LTP长时期预测规格(Long Term Predicition)
-
GF_M4A_AAC_SBR =
5, // SBR (Spectral Band Replication)
-
GF_M4A_AAC_SCALABLE =
6,
-
GF_M4A_TWINVQ =
7,
-
GF_M4A_CELP =
8,
-
GF_M4A_HVXC =
9,
-
GF_M4A_TTSI =
12,
-
GF_M4A_MAIN_SYNTHETIC =
13,
-
GF_M4A_WAVETABLE_SYNTHESIS =
14,
-
GF_M4A_GENERAL_MIDI =
15,
-
GF_M4A_ALGO_SYNTH_AUDIO_FX =
16,
-
GF_M4A_ER_AAC_LC =
17,
-
GF_M4A_ER_AAC_LTP =
19,
-