转载:GPAC MP4文件写入(支持H264、H265)

1、GPAC模块下载链接https://github.com/gpac/gpachttps://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、接口定义

头文件声明


  
  
  1. #ifndef _MP4WRITER_H_
  2. #define _MP4WRITER_H_
  3. #define GPAC_MP4BOX_MINI
  4. #include "gpac/setup.h"
  5. #define MP4_AUDIO_TYPE_INVALID 0
  6. #define MP4_AUDIO_TYPE_AAC_MAIN 1
  7. #define MP4_AUDIO_TYPE_AAC_LC 2
  8. #define MP4_AUDIO_TYPE_AAC_SSR 3
  9. #define MP4_AUDIO_TYPE_AAC_LD 23
  10. #ifdef __cplusplus
  11. extern "C" {
  12. #endif
  13. void* MP4_Init();
  14. s32 MP4_CreatFile(void *pCMP4Writer, char *strFileName);
  15. s32 MP4_InitVideo265(void *pCMP4Writer, u32 TimeScale);
  16. s32 MP4_Write265Sample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
  17. s32 MP4_InitVideo264(void *pCMP4Writer, u32 TimeScale);
  18. s32 MP4_Write264Sample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
  19. s32 MP4_InitAudioAAC(void *pCMP4Writer, u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale);
  20. s32 MP4_WriteAACSample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
  21. void MP4_CloseFile(void *pCMP4Writer);
  22. void MP4_Exit(void *pCMP4Writer);
  23. #ifdef __cplusplus
  24. }
  25. #endif
  26. #endif

源码实现:


  
  
  1. #include "MP4Writer.h"
  2. #include <Winsock2.h>
  3. extern "C" {
  4. #include "gpac/isomedia.h"
  5. #include "gpac/constants.h"
  6. #include "gpac/internal/media_dev.h"
  7. }
  8. #define INIT_STATUS 0
  9. #define CONFIG_STATUS 1
  10. #define CONFIG_FINISH 2
  11. static s8 GetSampleRateID(u32 SamplRate)
  12. {
  13. switch (SamplRate)
  14. {
  15. case 96000: return 0;
  16. case 88200: return 1;
  17. case 64000: return 2;
  18. case 48000: return 3;
  19. case 44100: return 4;
  20. case 32000: return 5;
  21. case 24000: return 6;
  22. case 22050: return 7;
  23. case 16000: return 8;
  24. case 12000: return 9;
  25. case 11025: return 10;
  26. case 8000 : return 11;
  27. case 7350 : return 12;
  28. default: return -1;
  29. }
  30. }
  31. //gf_m4a_get_profile
  32. static u8 GetAACProfile(u8 AudioType, u32 SampleRate, u8 Channel)
  33. {
  34. switch (AudioType)
  35. {
  36. case 2: /* AAC LC */
  37. {
  38. if (Channel <= 2) return (SampleRate <= 24000) ? 0x28 : 0x29; /* LC@L1 or LC@L2 */
  39. if (Channel <= 5) return (SampleRate <= 48000) ? 0x2A : 0x2B; /* LC@L4 or LC@L5 */
  40. return (SampleRate <= 48000) ? 0x50 : 0x51; /* LC@L4 or LC@L5 */
  41. }
  42. case 5: /* HE-AAC - SBR */
  43. {
  44. if (Channel <= 2) return (SampleRate <= 24000) ? 0x2C : 0x2D; /* HE@L2 or HE@L3 */
  45. if (Channel <= 5) return (SampleRate <= 48000) ? 0x2E : 0x2F; /* HE@L4 or HE@L5 */
  46. return (SampleRate <= 48000) ? 0x52 : 0x53; /* HE@L6 or HE@L7 */
  47. }
  48. case 29: /*HE-AACv2 - SBR+PS*/
  49. {
  50. if (Channel <= 2) return (SampleRate <= 24000) ? 0x30 : 0x31; /* HE-AACv2@L2 or HE-AACv2@L3 */
  51. if (Channel <= 5) return (SampleRate <= 48000) ? 0x32 : 0x33; /* HE-AACv2@L4 or HE-AACv2@L5 */
  52. return (SampleRate <= 48000) ? 0x54 : 0x55; /* HE-AACv2@L6 or HE-AACv2@L7 */
  53. }
  54. default: /* default to HQ */
  55. {
  56. if (Channel <= 2) return (SampleRate < 24000) ? 0x0E : 0x0F; /* HQ@L1 or HQ@L2 */
  57. return 0x10; /* HQ@L3 */
  58. }
  59. }
  60. }
  61. static void GetAudioSpecificConfig(u8 AudioType, u8 SampleRateID, u8 Channel, u8 *pHigh, u8 *pLow)
  62. {
  63. u16 Config;
  64. Config = (AudioType & 0x1f);
  65. Config <<= 4;
  66. Config |= SampleRateID & 0x0f;
  67. Config <<= 4;
  68. Config |= Channel & 0x0f;
  69. Config <<= 3;
  70. *pLow = Config & 0xff;
  71. Config >>= 8;
  72. *pHigh = Config & 0xff;
  73. }
  74. /* 返回的数据包括起始的4个字节0x00000001 */
  75. static u8* FindNalu(u8 *pStart, u32 Size, u8 *pNaluType, u32 *pNaluSize)
  76. {
  77. u8 *pEnd;
  78. u8 *pCur;
  79. u8 *pOut;
  80. u8 NaluType;
  81. if ( 4 >= Size)
  82. return NULL;
  83. /* 找第一个0x00000001 */
  84. pCur = pStart;
  85. pEnd = pStart + Size - 4;
  86. while (pCur < pEnd)
  87. {
  88. if ( ( 0 == pCur[ 0]) && ( 0 == pCur[ 1]) && ( 0 == pCur[ 2]) && ( 1 == pCur[ 3]) )
  89. break;
  90. pCur++;
  91. }
  92. if (pCur >= pEnd)
  93. return NULL;
  94. NaluType = (pCur[ 4] >> 1) & 0x3f;
  95. *pNaluType = NaluType;
  96. if ( 1 == NaluType || 19 == NaluType) /* P帧、I帧, 假设每一包里P帧I帧都是最后一个 */
  97. {
  98. *pNaluSize = Size - (pCur - pStart);
  99. return pCur;
  100. }
  101. pOut = pCur;
  102. /* 找第二个0x00000001 */
  103. pCur += 5;
  104. while (pCur <= pEnd)
  105. {
  106. if ( ( 0 == pCur[ 0]) && ( 0 == pCur[ 1]) && ( 0 == pCur[ 2]) && ( 1 == pCur[ 3]) )
  107. break;
  108. pCur++;
  109. }
  110. if (pCur <= pEnd)
  111. {
  112. *pNaluSize = pCur - pOut;
  113. return pOut;
  114. }
  115. *pNaluSize = Size - (pOut - pStart);
  116. return pOut;
  117. }
  118. /* 返回的数据包括起始的4个字节0x00000001 */
  119. static u8* FindNalu264(u8 *pStart, u32 Size, u8 *pNaluType, u32 *pNaluSize)
  120. {
  121. u8 *pEnd;
  122. u8 *pCur;
  123. u8 *pOut;
  124. u8 NaluType;
  125. if ( 4 >= Size)
  126. return NULL;
  127. /* 找第一个0x00000001 */
  128. pCur = pStart;
  129. pEnd = pStart + Size - 4;
  130. while (pCur < pEnd)
  131. {
  132. if (( 0 == pCur[ 0]) && ( 0 == pCur[ 1]) && ( 0 == pCur[ 2]) && ( 1 == pCur[ 3]))
  133. break;
  134. pCur++;
  135. }
  136. if (pCur >= pEnd)
  137. return NULL;
  138. NaluType = (pCur[ 4]) & 0x1f;
  139. *pNaluType = NaluType;
  140. if ( 1 == NaluType || 5 == NaluType) /* P帧、I帧, 假设每一包里P帧I帧都是最后一个 */
  141. {
  142. *pNaluSize = Size - (pCur - pStart);
  143. return pCur;
  144. }
  145. pOut = pCur;
  146. /* 找第二个0x00000001 */
  147. pCur += 5;
  148. while (pCur <= pEnd)
  149. {
  150. if (( 0 == pCur[ 0]) && ( 0 == pCur[ 1]) && ( 0 == pCur[ 2]) && ( 1 == pCur[ 3]))
  151. break;
  152. pCur++;
  153. }
  154. if (pCur <= pEnd)
  155. {
  156. *pNaluSize = pCur - pOut;
  157. return pOut;
  158. }
  159. *pNaluSize = Size - (pOut - pStart);
  160. return pOut;
  161. }
  162. // aac数据时记得除掉adts头
  163. static int AdtsDemux(unsigned char * data, unsigned int size, unsigned char** raw, int* raw_size)
  164. {
  165. int ret = 1;
  166. if (size < 7) {
  167. ttf_human_trace( "adts: demux size too small");
  168. return 0;
  169. }
  170. unsigned char* p = data;
  171. unsigned char* pend = data + size;
  172. //unsigned char* startp = 0;
  173. while (p < pend) {
  174. // decode the ADTS.
  175. // @see aac-iso-13818-7.pdf, page 26
  176. // 6.2 Audio Data Transport Stream, ADTS
  177. // @see https://github.com/ossrs/srs/issues/212#issuecomment-64145885
  178. // byte_alignment()
  179. // adts_fixed_header:
  180. // 12bits syncword,
  181. // 16bits left.
  182. // adts_variable_header:
  183. // 28bits
  184. // 12+16+28=56bits
  185. // adts_error_check:
  186. // 16bits if protection_absent
  187. // 56+16=72bits
  188. // if protection_absent:
  189. // require(7bytes)=56bits
  190. // else
  191. // require(9bytes)=72bits
  192. //startp = p;
  193. // for aac, the frame must be ADTS format.
  194. /*if (p[0] != 0xff || (p[1] & 0xf0) != 0xf0) {
  195. ttf_human_trace("adts: not this format.");
  196. return 0;
  197. }*/
  198. // syncword 12 bslbf
  199. p++;
  200. // 4bits left.
  201. // adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS
  202. // ID 1 bslbf
  203. // layer 2 uimsbf
  204. // protection_absent 1 bslbf
  205. int8_t pav = (*p++ & 0x0f);
  206. //int8_t id = (pav >> 3) & 0x01;
  207. /*int8_t layer = (pav >> 1) & 0x03;*/
  208. int8_t protection_absent = pav & 0x01;
  209. /**
  210. * ID: MPEG identifier, set to '1' if the audio data in the ADTS stream are MPEG-2 AAC (See ISO/IEC 13818-7)
  211. * and set to '0' if the audio data are MPEG-4. See also ISO/IEC 11172-3, subclause 2.4.2.3.
  212. */
  213. //if (id != 0x01) {
  214. // //ttf_human_trace("adts: id must be 1(aac), actual 0(mp4a).");
  215. // // well, some system always use 0, but actually is aac format.
  216. // // for example, houjian vod ts always set the aac id to 0, actually 1.
  217. // // we just ignore it, and alwyas use 1(aac) to demux.
  218. // id = 0x01;
  219. //}
  220. //else {
  221. // //ttf_human_trace("adts: id must be 1(aac), actual 1(mp4a).");
  222. //}
  223. //int16_t sfiv = (*p << 8) | (*(p + 1));
  224. p += 2;
  225. // profile 2 uimsbf
  226. // sampling_frequency_index 4 uimsbf
  227. // private_bit 1 bslbf
  228. // channel_configuration 3 uimsbf
  229. // original/copy 1 bslbf
  230. // home 1 bslbf
  231. //int8_t profile = (sfiv >> 14) & 0x03;
  232. //int8_t sampling_frequency_index = (sfiv >> 10) & 0x0f;
  233. /*int8_t private_bit = (sfiv >> 9) & 0x01;*/
  234. //int8_t channel_configuration = (sfiv >> 6) & 0x07;
  235. /*int8_t original = (sfiv >> 5) & 0x01;*/
  236. /*int8_t home = (sfiv >> 4) & 0x01;*/
  237. //int8_t Emphasis; @remark, Emphasis is removed, @see https://github.com/ossrs/srs/issues/212#issuecomment-64154736
  238. // 4bits left.
  239. // adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS
  240. // copyright_identification_bit 1 bslbf
  241. // copyright_identification_start 1 bslbf
  242. /*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/
  243. /*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/
  244. // frame_length 13 bslbf: Length of the frame including headers and error_check in bytes.
  245. // use the left 2bits as the 13 and 12 bit,
  246. // the frame_length is 13bits, so we move 13-2=11.
  247. //int16_t frame_length = (sfiv << 11) & 0x1800;
  248. //int32_t abfv = ((*p) << 16)
  249. // | ((*(p + 1)) << 8)
  250. // | (*(p + 2));
  251. p += 3;
  252. // frame_length 13 bslbf: consume the first 13-2=11bits
  253. // the fh2 is 24bits, so we move right 24-11=13.
  254. //frame_length |= (abfv >> 13) & 0x07ff;
  255. // adts_buffer_fullness 11 bslbf
  256. /*int16_t fh_adts_buffer_fullness = (abfv >> 2) & 0x7ff;*/
  257. // number_of_raw_data_blocks_in_frame 2 uimsbf
  258. /*int16_t number_of_raw_data_blocks_in_frame = abfv & 0x03;*/
  259. // adts_error_check(), 1.A.2.2.3 Error detection
  260. if (!protection_absent) {
  261. if (size < 9) {
  262. ttf_human_trace( "adts: protection_absent disappare.");
  263. return 0;
  264. }
  265. // crc_check 16 Rpchof
  266. /*int16_t crc_check = */p += 2;
  267. }
  268. // TODO: check the sampling_frequency_index
  269. // TODO: check the channel_configuration
  270. // raw_data_blocks
  271. /*int adts_header_size = p - startp;
  272. int raw_data_size = frame_length - adts_header_size;
  273. if (raw_data_size > pend - p) {
  274. ttf_human_trace("adts: raw data size too little.");
  275. return 0;
  276. }*/
  277. //adts_codec_.protection_absent = protection_absent;
  278. //adts_codec_.aac_object = srs_codec_aac_ts2rtmp((SrsAacProfile)profile);
  279. //adts_codec_.sampling_frequency_index = sampling_frequency_index;
  280. //adts_codec_.channel_configuration = channel_configuration;
  281. //adts_codec_.frame_length = frame_length;
  282. @see srs_audio_write_raw_frame().
  283. TODO: FIXME: maybe need to resample audio.
  284. //adts_codec_.sound_format = 10; // AAC
  285. //if (sampling_frequency_index <= 0x0c && sampling_frequency_index > 0x0a) {
  286. // adts_codec_.sound_rate = SrsCodecAudioSampleRate5512;
  287. //}
  288. //else if (sampling_frequency_index <= 0x0a && sampling_frequency_index > 0x07) {
  289. // adts_codec_.sound_rate = SrsCodecAudioSampleRate11025;
  290. //}
  291. //else if (sampling_frequency_index <= 0x07 && sampling_frequency_index > 0x04) {
  292. // adts_codec_.sound_rate = SrsCodecAudioSampleRate22050;
  293. //}
  294. //else if (sampling_frequency_index <= 0x04) {
  295. // adts_codec_.sound_rate = SrsCodecAudioSampleRate44100;
  296. //}
  297. //else {
  298. // adts_codec_.sound_rate = SrsCodecAudioSampleRate44100;
  299. // //srs_warn("adts invalid sample rate for flv, rate=%#x", sampling_frequency_index);
  300. //}
  301. //adts_codec_.sound_type = srs_max(0, srs_min(1, channel_configuration - 1));
  302. TODO: FIXME: finger it out the sound size by adts.
  303. //adts_codec_.sound_size = 1; // 0(8bits) or 1(16bits).
  304. // frame data.
  305. *raw = p;
  306. *raw_size = pend - p;
  307. break;
  308. }
  309. return ret;
  310. }
  311. class MP4Writer
  312. {
  313. public:
  314. MP4Writer();
  315. ~MP4Writer();
  316. s32 CreatFile(char *strFileName);
  317. s32 Init265(u32 TimeScale);
  318. s32 Write265Sample(u8 *pData, u32 Size, u64 TimeStamp);
  319. s32 Init264(u32 TimeScale);
  320. s32 Write264Sample(u8 *pData, u32 Size, u64 TimeStamp);
  321. s32 InitAAC(u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale);
  322. s32 WriteAACSample(u8 *pData, u32 Size, u64 TimeStamp);
  323. void CloseFile();
  324. private:
  325. GF_ISOFile *m_ptFile;
  326. u32 m_265TrackIndex;
  327. u32 m_265StreamIndex;
  328. u8 m_Video265Statue;
  329. u32 m_264TrackIndex;
  330. u32 m_264StreamIndex;
  331. u8 m_Video264Statue;
  332. s64 m_VideoTimeStampStart;
  333. GF_HEVCConfig *m_ptHEVCConfig;
  334. GF_HEVCParamArray* m_tHEVCNaluParam_VPS;
  335. GF_HEVCParamArray* m_tHEVCNaluParam_SPS;
  336. GF_HEVCParamArray* m_tHEVCNaluParam_PPS;
  337. GF_AVCConfigSlot* m_tAVCConfig_VPS;
  338. GF_AVCConfigSlot* m_tAVCConfig_SPS;
  339. GF_AVCConfigSlot* m_tAVCConfig_PPS;
  340. GF_AVCConfigSlot* m_tAVCConfig_SPS264;
  341. GF_AVCConfigSlot* m_tAVCConfig_PPS264;
  342. GF_AVCConfig *m_ptAVCConfig;
  343. HEVCState *m_ptHEVCState;
  344. AVCState *m_ptAVCState;
  345. u32 m_AACTrackIndex;
  346. u32 m_AACStreamIndex;
  347. u8 m_AudioAACStatue;
  348. s64 m_AudioTimeStampStart;
  349. bool findfirsidr_;
  350. void FreeAllMem();
  351. };
  352. MP4Writer::MP4Writer()
  353. {
  354. m_ptFile = NULL;
  355. m_ptHEVCConfig = NULL;
  356. m_ptAVCConfig = NULL;
  357. m_Video265Statue = INIT_STATUS;
  358. m_AudioAACStatue = INIT_STATUS;
  359. m_Video264Statue = INIT_STATUS;
  360. m_tHEVCNaluParam_VPS = NULL;
  361. m_tHEVCNaluParam_SPS = NULL;
  362. m_tHEVCNaluParam_PPS = NULL;
  363. m_tAVCConfig_VPS = NULL;
  364. m_tAVCConfig_SPS = NULL;
  365. m_tAVCConfig_PPS = NULL;
  366. m_tAVCConfig_SPS264 = NULL;
  367. m_tAVCConfig_PPS264 = NULL;
  368. m_ptHEVCState = NULL;
  369. m_ptAVCState = NULL;
  370. findfirsidr_ = false;
  371. }
  372. MP4Writer::~MP4Writer()
  373. {
  374. CloseFile();
  375. }
  376. s32 MP4Writer::CreatFile(char *strFileName)
  377. {
  378. if ( NULL != m_ptFile)
  379. {
  380. return -1;
  381. }
  382. m_ptFile = gf_isom_open(strFileName, GF_ISOM_OPEN_WRITE, NULL);
  383. if ( NULL == m_ptFile)
  384. {
  385. return -1;
  386. }
  387. gf_isom_set_brand_info(m_ptFile, GF_ISOM_BRAND_MP42, 0);
  388. return 0;
  389. }
  390. void MP4Writer::CloseFile()
  391. {
  392. if (m_ptFile)
  393. {
  394. gf_isom_close(m_ptFile);
  395. m_ptFile = NULL;
  396. FreeAllMem();
  397. }
  398. }
  399. void MP4Writer::FreeAllMem()
  400. {
  401. if (m_ptHEVCConfig)
  402. {
  403. gf_odf_hevc_cfg_del(m_ptHEVCConfig);
  404. //gf_list_del(m_ptHEVCConfig->param_array);
  405. //free(m_ptHEVCConfig);
  406. m_ptHEVCConfig = NULL;
  407. }
  408. if (m_ptAVCConfig) {
  409. gf_odf_avc_cfg_del(m_ptAVCConfig);
  410. //gf_list_del(m_ptAVCConfig->param_array);
  411. //free(m_ptAVCConfig);
  412. m_ptAVCConfig = NULL;
  413. }
  414. if (m_ptHEVCState) {
  415. free(m_ptHEVCState);
  416. m_ptHEVCState = NULL;
  417. }
  418. if (m_ptAVCState) {
  419. free(m_ptAVCState);
  420. m_ptAVCState = NULL;
  421. }
  422. m_tHEVCNaluParam_VPS = NULL;
  423. m_tHEVCNaluParam_SPS = NULL;
  424. m_tHEVCNaluParam_PPS = NULL;
  425. m_tAVCConfig_VPS = NULL;
  426. m_tAVCConfig_SPS = NULL;
  427. m_tAVCConfig_PPS = NULL;
  428. m_tAVCConfig_SPS264 = NULL;
  429. m_tAVCConfig_PPS264 = NULL;
  430. m_Video265Statue = INIT_STATUS;
  431. m_AudioAACStatue = INIT_STATUS;
  432. m_Video264Statue = INIT_STATUS;
  433. findfirsidr_ = false;
  434. }
  435. s32 MP4Writer::Init265(u32 TimeScale)
  436. {
  437. if ( NULL == m_ptFile || INIT_STATUS != m_Video265Statue)
  438. return -1;
  439. m_VideoTimeStampStart = -1;
  440. /* 创建Track */
  441. m_265TrackIndex = gf_isom_new_track(m_ptFile, 0, GF_ISOM_MEDIA_VISUAL, TimeScale);
  442. if ( 0 == m_265TrackIndex)
  443. return -1;
  444. if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_265TrackIndex, 1))
  445. return -1;
  446. /* 创建流 */
  447. m_ptHEVCConfig = gf_odf_hevc_cfg_new();
  448. if ( NULL == m_ptHEVCConfig)
  449. return -1;
  450. m_ptHEVCConfig->nal_unit_size = 4;
  451. m_ptHEVCConfig->configurationVersion = 1;
  452. if (GF_OK != gf_isom_hevc_config_new(m_ptFile, m_265TrackIndex, m_ptHEVCConfig, NULL, NULL, &m_265StreamIndex))
  453. return -1;
  454. /* 初始化流的配置结构 */
  455. GF_SAFEALLOC(m_tHEVCNaluParam_VPS, GF_HEVCParamArray);
  456. GF_SAFEALLOC(m_tHEVCNaluParam_SPS, GF_HEVCParamArray);
  457. GF_SAFEALLOC(m_tHEVCNaluParam_PPS, GF_HEVCParamArray);
  458. GF_SAFEALLOC(m_tAVCConfig_VPS, GF_AVCConfigSlot);
  459. GF_SAFEALLOC(m_tAVCConfig_SPS, GF_AVCConfigSlot);
  460. GF_SAFEALLOC(m_tAVCConfig_PPS, GF_AVCConfigSlot);
  461. if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_VPS))
  462. return -1;
  463. if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_SPS))
  464. return -1;
  465. if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_PPS))
  466. return -1;
  467. m_tHEVCNaluParam_VPS->nalus = gf_list_new();
  468. if ( NULL == m_tHEVCNaluParam_VPS->nalus)
  469. return -1;
  470. m_tHEVCNaluParam_SPS->nalus = gf_list_new();
  471. if ( NULL == m_tHEVCNaluParam_SPS->nalus)
  472. return -1;
  473. m_tHEVCNaluParam_PPS->nalus = gf_list_new();
  474. if ( NULL == m_tHEVCNaluParam_PPS->nalus)
  475. return -1;
  476. m_tHEVCNaluParam_VPS->type = GF_HEVC_NALU_VID_PARAM;
  477. m_tHEVCNaluParam_SPS->type = GF_HEVC_NALU_SEQ_PARAM;
  478. m_tHEVCNaluParam_PPS->type = GF_HEVC_NALU_PIC_PARAM;
  479. m_tHEVCNaluParam_VPS->array_completeness = 1;
  480. m_tHEVCNaluParam_SPS->array_completeness = 1;
  481. m_tHEVCNaluParam_PPS->array_completeness = 1;
  482. if (GF_OK != gf_list_add(m_tHEVCNaluParam_VPS->nalus, m_tAVCConfig_VPS))
  483. return -1;
  484. if (GF_OK != gf_list_add(m_tHEVCNaluParam_SPS->nalus, m_tAVCConfig_SPS))
  485. return -1;
  486. if (GF_OK != gf_list_add(m_tHEVCNaluParam_PPS->nalus, m_tAVCConfig_PPS))
  487. return -1;
  488. m_ptHEVCState = (HEVCState *)malloc(sizeof(HEVCState)); //gf_malloc
  489. if ( NULL == m_ptHEVCState)
  490. return -1;
  491. memset(m_ptHEVCState, 0, sizeof(HEVCState));
  492. m_Video265Statue = CONFIG_STATUS;
  493. return 0;
  494. }
  495. s32 MP4Writer::Write265Sample(u8 *pData, u32 Size, u64 TimeStamp)
  496. {
  497. u8 *pStart = pData;
  498. u8 NaluType;
  499. u32 NaluSize = 0;
  500. s32 ID;
  501. GF_ISOSample tISOSample;
  502. /* 265还未初始化 */
  503. if (INIT_STATUS == m_Video265Statue)
  504. return -1;
  505. while ( 1)
  506. {
  507. pData = FindNalu(pData + NaluSize, Size - (u32)(pData - pStart) - NaluSize, &NaluType, &NaluSize);
  508. if ( NULL == pData)
  509. break;
  510. /* 配置完成后只处理IP帧 */
  511. if (CONFIG_FINISH == m_Video265Statue)
  512. {
  513. if ( 1 != NaluType && 19 != NaluType) /* P帧 I帧 */
  514. continue;
  515. if ( -1 == m_VideoTimeStampStart)
  516. m_VideoTimeStampStart = TimeStamp;
  517. *((u32 *)pData) = htonl(NaluSize - 4); /* 这里的长度不能包括前四个字节的头! */
  518. tISOSample.data = (char *)pData;
  519. tISOSample.dataLength = NaluSize;
  520. tISOSample.IsRAP = ( 19 == NaluType)? RAP: RAP_NO;
  521. tISOSample.DTS = TimeStamp - m_VideoTimeStampStart;
  522. tISOSample.CTS_Offset = 0;
  523. if (GF_OK != gf_isom_add_sample(m_ptFile, m_265TrackIndex, m_265StreamIndex, &tISOSample))
  524. {
  525. *((u32 *)pData) = htonl( 1); /* 恢复0x00000001的头 */
  526. return -1;
  527. }
  528. *((u32 *)pData) = htonl( 1); /* 恢复0x00000001的头 */
  529. }
  530. /* 配置未完成时只处理vps sps pps头 */
  531. else if (CONFIG_STATUS == m_Video265Statue)
  532. {
  533. pData += 4;
  534. NaluSize -= 4;
  535. if ( 32 == NaluType && NULL == m_tAVCConfig_VPS->data) /* VPS */
  536. {
  537. ID = gf_media_hevc_read_vps((char *)pData , NaluSize, m_ptHEVCState);
  538. m_ptHEVCConfig->avgFrameRate = m_ptHEVCState->vps[ID].rates[ 0].avg_pic_rate;
  539. m_ptHEVCConfig->temporalIdNested = m_ptHEVCState->vps[ID].temporal_id_nesting;
  540. m_ptHEVCConfig->constantFrameRate = m_ptHEVCState->vps[ID].rates[ 0].constand_pic_rate_idc;
  541. m_ptHEVCConfig->numTemporalLayers = m_ptHEVCState->vps[ID].max_sub_layers;
  542. m_tAVCConfig_VPS->id = ID;
  543. m_tAVCConfig_VPS->size = (u16)NaluSize;
  544. m_tAVCConfig_VPS->data = (char *)malloc(NaluSize);
  545. if ( NULL == m_tAVCConfig_VPS->data)
  546. continue;
  547. memcpy(m_tAVCConfig_VPS->data, pData, NaluSize);
  548. }
  549. else if ( 33 == NaluType && NULL == m_tAVCConfig_SPS->data) /* SPS */
  550. {
  551. ID = gf_media_hevc_read_sps((char *)pData, NaluSize, m_ptHEVCState);
  552. m_ptHEVCConfig->tier_flag = m_ptHEVCState->sps[ID].ptl.tier_flag;
  553. m_ptHEVCConfig->profile_idc = m_ptHEVCState->sps[ID].ptl.profile_idc;
  554. m_ptHEVCConfig->profile_space = m_ptHEVCState->sps[ID].ptl.profile_space;
  555. m_tAVCConfig_SPS->id = ID;
  556. m_tAVCConfig_SPS->size = (u16)NaluSize;
  557. m_tAVCConfig_SPS->data = (char *)malloc(NaluSize);
  558. if ( NULL == m_tAVCConfig_SPS->data)
  559. continue;
  560. memcpy(m_tAVCConfig_SPS->data, pData, NaluSize);
  561. gf_isom_set_visual_info(m_ptFile, m_265TrackIndex, m_265StreamIndex, m_ptHEVCState->sps[ID].width, m_ptHEVCState->sps[ID].height);
  562. }
  563. else if ( 34 == NaluType && NULL == m_tAVCConfig_PPS->data) /* PPS */
  564. {
  565. m_tAVCConfig_PPS->id = ID;
  566. m_tAVCConfig_PPS->size = (u16)NaluSize;
  567. m_tAVCConfig_PPS->data = (char *)malloc(NaluSize);
  568. if ( NULL == m_tAVCConfig_PPS->data)
  569. continue;
  570. memcpy(m_tAVCConfig_PPS->data, pData, NaluSize);
  571. }
  572. else
  573. {
  574. continue;
  575. }
  576. if (m_tAVCConfig_VPS->data && m_tAVCConfig_SPS->data && m_tAVCConfig_PPS->data)
  577. {
  578. gf_isom_hevc_config_update(m_ptFile, m_265TrackIndex, m_265StreamIndex, m_ptHEVCConfig);
  579. m_Video265Statue = CONFIG_FINISH;
  580. if (m_ptHEVCState) {
  581. free(m_ptHEVCState);
  582. m_ptHEVCState = NULL;
  583. }
  584. }
  585. }
  586. }
  587. return 0;
  588. }
  589. s32 MP4Writer::Init264(u32 TimeScale)
  590. {
  591. if ( NULL == m_ptFile || INIT_STATUS != m_Video265Statue)
  592. return -1;
  593. m_VideoTimeStampStart = -1;
  594. /* 创建Track */
  595. m_264TrackIndex = gf_isom_new_track(m_ptFile, 0, GF_ISOM_MEDIA_VISUAL, TimeScale);
  596. if ( 0 == m_264TrackIndex)
  597. return -1;
  598. if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_264TrackIndex, 1))
  599. return -1;
  600. /* 创建流 */
  601. m_ptAVCConfig = gf_odf_avc_cfg_new();
  602. if ( NULL == m_ptAVCConfig)
  603. return -1;
  604. //m_ptAVCConfig->nal_unit_size = 4;
  605. m_ptAVCConfig->configurationVersion = 1;
  606. if (GF_OK != gf_isom_avc_config_new(m_ptFile, m_264TrackIndex, m_ptAVCConfig, NULL, NULL, &m_264StreamIndex))
  607. return -1;
  608. /* 初始化流的配置结构 */
  609. GF_SAFEALLOC(m_tAVCConfig_SPS264, GF_AVCConfigSlot);
  610. GF_SAFEALLOC(m_tAVCConfig_PPS264, GF_AVCConfigSlot);
  611. gf_list_add(m_ptAVCConfig->sequenceParameterSets, m_tAVCConfig_SPS264);
  612. gf_list_add(m_ptAVCConfig->pictureParameterSets, m_tAVCConfig_PPS264);
  613. m_ptAVCState = (AVCState *)malloc(sizeof(AVCState)); //gf_malloc
  614. if ( NULL == m_ptAVCState)
  615. return -1;
  616. memset(m_ptAVCState, 0, sizeof(AVCState));
  617. m_Video264Statue = CONFIG_STATUS;
  618. return 0;
  619. }
  620. s32 MP4Writer::Write264Sample(u8 *pData, u32 Size, u64 TimeStamp)
  621. {
  622. u8 *pStart = pData;
  623. u8 NaluType;
  624. u32 NaluSize = 0;
  625. s32 ID;
  626. GF_ISOSample tISOSample;
  627. /* 265还未初始化 */
  628. if (INIT_STATUS == m_Video264Statue)
  629. return -1;
  630. while ( 1)
  631. {
  632. pData = FindNalu264(pData + NaluSize, Size - (u32)(pData - pStart) - NaluSize, &NaluType, &NaluSize);
  633. if ( NULL == pData)
  634. break;
  635. /* 配置完成后只处理IP帧 */
  636. if (CONFIG_FINISH == m_Video264Statue)
  637. {
  638. if (!findfirsidr_) {
  639. if ( 5 != NaluType)
  640. continue;
  641. else
  642. findfirsidr_ = true;
  643. }
  644. if ( 1 != NaluType && 5 != NaluType) /* P帧 I帧 */
  645. continue;
  646. if ( -1 == m_VideoTimeStampStart)
  647. m_VideoTimeStampStart = TimeStamp;
  648. *((u32 *)pData) = htonl(NaluSize - 4); /* 这里的长度不能包括前四个字节的头! */
  649. tISOSample.data = (char *)pData;
  650. tISOSample.dataLength = NaluSize;
  651. tISOSample.IsRAP = ( 5 == NaluType) ? RAP : RAP_NO;
  652. tISOSample.DTS = TimeStamp - m_VideoTimeStampStart;
  653. tISOSample.CTS_Offset = 0;
  654. tISOSample.nb_pack = 0;
  655. int ret = gf_isom_add_sample(m_ptFile, m_264TrackIndex, m_264StreamIndex, &tISOSample);
  656. if (GF_OK != ret)
  657. {
  658. //*((u32 *)pData) = htonl(1); /* 恢复0x00000001的头 */
  659. return -1;
  660. }
  661. //*((u32 *)pData) = htonl(1); /* 恢复0x00000001的头 */
  662. }
  663. /* 配置未完成时只处理vps sps pps头 */
  664. else if (CONFIG_STATUS == m_Video264Statue)
  665. {
  666. pData += 4;
  667. NaluSize -= 4;
  668. if ( 7 == NaluType && NULL == m_tAVCConfig_SPS264->data) /* SPS */
  669. {
  670. ID = gf_media_avc_read_sps((char *)pData, NaluSize, m_ptAVCState, 0, NULL);
  671. m_ptAVCConfig->AVCProfileIndication = m_ptAVCState->sps[ID].profile_idc;
  672. m_ptAVCConfig->profile_compatibility = m_ptAVCState->sps[ID].prof_compat;
  673. m_ptAVCConfig->AVCLevelIndication = m_ptAVCState->sps[ID].level_idc;
  674. m_tAVCConfig_SPS264->id = ID;
  675. m_tAVCConfig_SPS264->size = (u16)NaluSize;
  676. m_tAVCConfig_SPS264->data = (char *)malloc(NaluSize);
  677. if ( NULL == m_tAVCConfig_SPS264->data)
  678. continue;
  679. memcpy(m_tAVCConfig_SPS264->data, pData, NaluSize);
  680. gf_isom_set_visual_info(m_ptFile, m_264TrackIndex, m_264StreamIndex, m_ptAVCState->sps[ID].width, m_ptAVCState->sps[ID].height);
  681. }
  682. else if ( 8 == NaluType && NULL == m_tAVCConfig_PPS264->data) /* PPS */
  683. {
  684. m_tAVCConfig_PPS264->id = ID;
  685. m_tAVCConfig_PPS264->size = (u16)NaluSize;
  686. m_tAVCConfig_PPS264->data = (char *)malloc(NaluSize);
  687. if ( NULL == m_tAVCConfig_PPS264->data)
  688. continue;
  689. memcpy(m_tAVCConfig_PPS264->data, pData, NaluSize);
  690. }
  691. else
  692. {
  693. continue;
  694. }
  695. if (m_tAVCConfig_SPS264->data && m_tAVCConfig_PPS264->data)
  696. {
  697. gf_isom_avc_config_update(m_ptFile, m_264TrackIndex, m_264StreamIndex, m_ptAVCConfig);
  698. m_Video264Statue = CONFIG_FINISH;
  699. if (m_ptAVCState) {
  700. free(m_ptAVCState);
  701. m_ptAVCState = NULL;
  702. }
  703. }
  704. }
  705. }
  706. return 0;
  707. }
  708. s32 MP4Writer::InitAAC(u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale)
  709. {
  710. GF_ESD *ptStreamDesc;
  711. s8 SampleRateID;
  712. u16 AudioConfig = 0;
  713. u8 AACProfile;
  714. s32 res = 0;
  715. if ( NULL == m_ptFile || INIT_STATUS != m_AudioAACStatue)
  716. return -1;
  717. m_AudioTimeStampStart = -1;
  718. /* 创建Track */
  719. m_AACTrackIndex = gf_isom_new_track(m_ptFile, 0, GF_ISOM_MEDIA_AUDIO, TimeScale);
  720. if ( 0 == m_AACTrackIndex)
  721. return -1;
  722. if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_AACTrackIndex, 1))
  723. return -1;
  724. /* 创建并配置流 */
  725. SampleRateID = GetSampleRateID(SampleRate);
  726. if ( 0 > SampleRateID)
  727. return -1;
  728. GetAudioSpecificConfig(AudioType, (u8)SampleRateID, Channel, (u8*)(&AudioConfig), ((u8*)(&AudioConfig))+ 1);
  729. ptStreamDesc = gf_odf_desc_esd_new(SLPredef_MP4);
  730. ptStreamDesc->slConfig->timestampResolution = TimeScale;
  731. ptStreamDesc->decoderConfig->streamType = GF_STREAM_AUDIO;
  732. //ptStreamDesc->decoderConfig->bufferSizeDB = 20; //这参数干什么的
  733. ptStreamDesc->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4;
  734. ptStreamDesc->decoderConfig->decoderSpecificInfo->dataLength = 2;
  735. ptStreamDesc->decoderConfig->decoderSpecificInfo->data = (char *)&AudioConfig;
  736. ptStreamDesc->ESID = gf_isom_get_track_id(m_ptFile, m_AACTrackIndex);
  737. if (GF_OK != gf_isom_new_mpeg4_description(m_ptFile, m_AACTrackIndex, ptStreamDesc, NULL, NULL, &m_AACStreamIndex))
  738. {
  739. res = -1;
  740. goto ERR;
  741. }
  742. if (gf_isom_set_audio_info(m_ptFile, m_AACTrackIndex, m_AACStreamIndex, SampleRate, Channel, 16, GF_IMPORT_AUDIO_SAMPLE_ENTRY_NOT_SET))
  743. {
  744. res = -1;
  745. goto ERR;
  746. }
  747. AACProfile = GetAACProfile(AudioType, SampleRate, Channel);
  748. gf_isom_set_pl_indication(m_ptFile, GF_ISOM_PL_AUDIO, AACProfile);
  749. m_AudioAACStatue = CONFIG_FINISH;
  750. ERR:
  751. ptStreamDesc->decoderConfig->decoderSpecificInfo->data = NULL;
  752. gf_odf_desc_del((GF_Descriptor *)ptStreamDesc);
  753. return res;
  754. }
  755. s32 MP4Writer::WriteAACSample(u8 *pData, u32 Size, u64 TimeStamp)
  756. {
  757. GF_ISOSample tISOSample;
  758. if (CONFIG_FINISH != m_AudioAACStatue)
  759. return 0;
  760. if (!findfirsidr_) {
  761. return 0;
  762. }
  763. if ( -1 == m_AudioTimeStampStart)
  764. m_AudioTimeStampStart = TimeStamp;
  765. tISOSample.IsRAP = RAP;
  766. tISOSample.dataLength = Size;
  767. tISOSample.data = (char *)pData;
  768. tISOSample.DTS = TimeStamp - m_AudioTimeStampStart;
  769. tISOSample.CTS_Offset = 0;
  770. tISOSample.nb_pack = 0;
  771. if (GF_OK != gf_isom_add_sample(m_ptFile, m_AACTrackIndex, m_AACStreamIndex, &tISOSample))
  772. return -1;
  773. return 0;
  774. }
  775. extern "C" {
  776. void* MP4_Init()
  777. {
  778. return ( void *)( new MP4Writer());
  779. }
  780. s32 MP4_CreatFile( void *pCMP4Writer, char *strFileName)
  781. {
  782. if ( NULL == pCMP4Writer)
  783. return -1;
  784. return ((MP4Writer *)pCMP4Writer)->CreatFile(strFileName);
  785. }
  786. s32 MP4_InitVideo265( void *pCMP4Writer, u32 TimeScale)
  787. {
  788. if ( NULL == pCMP4Writer)
  789. return -1;
  790. return ((MP4Writer *)pCMP4Writer)->Init265(TimeScale);
  791. }
  792. s32 MP4_Write265Sample( void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp)
  793. {
  794. if ( NULL == pCMP4Writer)
  795. return -1;
  796. return ((MP4Writer *)pCMP4Writer)->Write265Sample(pData, Size, TimeStamp);
  797. }
  798. s32 MP4_InitVideo264( void * pCMP4Writer, u32 TimeScale)
  799. {
  800. if ( NULL == pCMP4Writer)
  801. return -1;
  802. return ((MP4Writer *)pCMP4Writer)->Init264(TimeScale);
  803. }
  804. s32 MP4_Write264Sample( void * pCMP4Writer, u8 * pData, u32 Size, u64 TimeStamp)
  805. {
  806. if ( NULL == pCMP4Writer)
  807. return -1;
  808. return ((MP4Writer *)pCMP4Writer)->Write264Sample(pData, Size, TimeStamp);
  809. }
  810. s32 MP4_InitAudioAAC( void *pCMP4Writer, u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale)
  811. {
  812. if ( NULL == pCMP4Writer)
  813. return -1;
  814. return ((MP4Writer *)pCMP4Writer)->InitAAC(AudioType, SampleRate, Channel, TimeScale);
  815. }
  816. s32 MP4_WriteAACSample( void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp)
  817. {
  818. if ( NULL == pCMP4Writer)
  819. return -1;
  820. return ((MP4Writer *)pCMP4Writer)->WriteAACSample(pData, Size, TimeStamp);
  821. }
  822. void MP4_CloseFile( void *pCMP4Writer)
  823. {
  824. if ( NULL == pCMP4Writer)
  825. return;
  826. ((MP4Writer *)pCMP4Writer)->CloseFile();
  827. }
  828. void MP4_Exit( void *pCMP4Writer)
  829. {
  830. if ( NULL == pCMP4Writer)
  831. return;
  832. delete pCMP4Writer;
  833. }
  834. }

AudioType类型值如下:


  
  
  1. GF_M4A_AAC_MAIN = 1, // Main主规格
  2. GF_M4A_AAC_LC = 2, // LC低复杂度规格(Low Complexity)
  3. GF_M4A_AAC_SSR = 3, // SSR可变采样率规格(Scaleable Sample Rate)
  4. GF_M4A_AAC_LTP = 4, // LTP长时期预测规格(Long Term Predicition)
  5. GF_M4A_AAC_SBR = 5, // SBR (Spectral Band Replication)
  6. GF_M4A_AAC_SCALABLE = 6,
  7. GF_M4A_TWINVQ = 7,
  8. GF_M4A_CELP = 8,
  9. GF_M4A_HVXC = 9,
  10. GF_M4A_TTSI = 12,
  11. GF_M4A_MAIN_SYNTHETIC = 13,
  12. GF_M4A_WAVETABLE_SYNTHESIS = 14,
  13. GF_M4A_GENERAL_MIDI = 15,
  14. GF_M4A_ALGO_SYNTH_AUDIO_FX = 16,
  15. GF_M4A_ER_AAC_LC = 17,
  16. GF_M4A_ER_AAC_LTP = 19,
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
GPAC是一个多媒体框架,它提供了一套用于处理多媒体数据的库函数。要往MP4文件中插入SEI帧,可以使用GPAC中的MP4Box工具或者使用GPAC库函数来实现。 以下是使用GPAC库函数往MP4文件中插入SEI帧的步骤: 1. 打开MP4文件 使用GPAC库函数中的MP4Read函数打开需要插入SEI帧的MP4文件,并创建一个MP4文件句柄。 ```C++ MP4FileHandle mp4 = MP4Read("test.mp4"); ``` 2. 获取视频轨道句柄 使用MP4GetTrackHandler函数获取视频轨道的句柄。 ```C++ MP4TrackId videoTrack = MP4FindTrackId(mp4, 0, MP4_VIDEO_TRACK_TYPE); MP4TrackHandle videoTrackHandle = MP4GetTrackHandler(mp4, videoTrack); ``` 3. 创建SEI帧数据 SEI帧是一种附加数据,用于传递一些额外的信息,如时间戳、场景描述等。需要根据SEI帧的格式,创建一个包含SEI帧数据的缓冲区。 ```C++ uint8_t seiData[] = {0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}; uint32_t seiDataSize = sizeof(seiData); ``` 4. 插入SEI帧数据 使用MP4AddSEI函数将SEI帧数据插入到视频轨道的每个帧中。 ```C++ MP4Duration videoDuration = MP4GetTrackDuration(mp4, videoTrack); MP4Duration videoTimeScale = MP4GetTrackTimeScale(mp4, videoTrack); MP4Timestamp videoTimestamp = 0; for (MP4Duration i = 0; i < videoDuration; i += videoTimeScale / 30) { MP4AddSEI(mp4, videoTrackHandle, seiData, seiDataSize, videoTimestamp); videoTimestamp += videoTimeScale / 30; } ``` 5. 保存MP4文件 使用MP4Write函数将修改后的MP4文件保存到磁盘上。 ```C++ MP4Write(mp4); ``` 6. 关闭MP4文件 使用MP4Close函数关闭MP4文件句柄。 ```C++ MP4Close(mp4); ``` 通过以上步骤,就可以往MP4文件中插入SEI帧数据。需要注意的是,SEI帧的格式需要符合MP4标准,否则可能会导致视频播放出现问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值