Files
TAIXIN/sdk/app/mp4/mp4_encode.h

439 lines
11 KiB
C
Raw Permalink Normal View History

#ifndef __MP4_ENCODE_H
#define __MP4_ENCODE_H
#include "basic_include.h"
#include "fatfs/osal_file.h"
#define mp4_moov mp4_common_box_s
#define mp4_trak mp4_common_box_s
#define mp4_mdia mp4_common_box_s
#define mp4_minf mp4_common_box_s
#define mp4_dinf mp4_common_box_s
#define mp4_stbl mp4_common_box_s
#define mp4_mdat mp4_common_box_s
#define mp4_free mp4_common_box_s
#define mp4_esds mp4_common_box_full_s
/************************************************************************/
/* Some values of MP4(E/D)_track_t->object_type_indication */
/************************************************************************/
// MPEG-4 AAC (all profiles)
#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_14496_3 0x40
// MPEG-2 AAC, Main profile
#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_13818_7_MAIN_PROFILE 0x66
// MPEG-2 AAC, LC profile
#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_13818_7_LC_PROFILE 0x67
// MPEG-2 AAC, SSR profile
#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_13818_7_SSR_PROFILE 0x68
// H.264 (AVC) video
#define MP4_OBJECT_TYPE_AVC 0x21
// H.265 (HEVC) video
#define MP4_OBJECT_TYPE_HEVC 0x23
// http://www.mp4ra.org/object.html 0xC0-E0 && 0xE2 - 0xFE are specified as "user private"
#define MP4_OBJECT_TYPE_USER_PRIVATE 0xC0
#define MAX_PPS_SPS_LEN (32)
#ifndef SEEK_SET
#define SEEK_SET 0 /* set file offset to offset */
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1 /* set file offset to current plus offset */
#endif
#ifndef SEEK_END
#define SEEK_END 2 /* set file offset to EOF plus offset */
#endif
enum
{
MP4_OK,
MP4_INIT_ERR,
MP4_FULL_ERR,
MP4_V_TYPE_ERR,
MP4_I_ERR,
MP4_B_ERR,
MP4_P_ERR,
MP4_WRITE_ERR,
MP4_AUDIO_ERR,
};
typedef struct
{
uint32_t sample_count;
uint32_t delta;
} stts_entries;
// 这里记录的都是对应表格的起始地址,分配的缓冲区长度都是512?
// 如果512写入完毕,则offset+512,
typedef struct
{
uint32_t type; // 1:视频 2:音频,0是无效
uint32_t tkhd_duration_offset;
uint32_t mdhd_duration_offset; // time scale为时间单位
uint32_t duration;
uint32_t count; // 记录保存了多少帧数据
uint32_t stts_offset;
uint32_t stsc_offset;
uint32_t stsz_offset;
uint32_t stco_offset;
uint32_t stss_offset;
uint32_t stts_write_offset; // 当前需要写入的位置
uint32_t stts_need_write_len;
uint32_t stts_count;
stts_entries last_entries; // 如果相同,则需要一直增加,减少stts的空间
uint32_t stsc_write_offset; // 当前需要写入的位置
uint32_t stsc_need_write_len;
uint32_t stsc_count;
uint32_t stsz_write_offset; // 当前需要写入的位置
uint32_t stsz_need_write_len;
uint32_t stsz_count;
uint32_t stco_write_offset; // 当前需要写入的位置
uint32_t stco_need_write_len;
uint32_t stco_count;
uint32_t stss_write_offset; // 当前需要写入的位置
uint32_t stss_need_write_len;
uint32_t stss_count;
uint8_t stts_tmp_buf[512]; // 除了这个是比较特殊外,其他都是写完清0
uint8_t stsc_tmp_buf[512];
uint8_t stsz_tmp_buf[512];
uint8_t stco_tmp_buf[512];
uint8_t stss_tmp_buf[512];
} trak_key_msg;
// pps和sps预分配空间,就不动态申请了,考虑用psram,多几十字节
typedef struct
{
uint8_t cache[512];
uint8_t init;
uint8_t audio_enable;
uint16_t asps_len;
uint8_t *asps_data;
uint16_t video_w;
uint16_t video_h;
uint32_t msg_end;
uint16_t pps_len;
uint16_t sps_len;
uint8_t *sps_data;
uint8_t *pps_data;
uint32_t trak_count;
uint32_t file_max_size;
uint32_t mdat_size; // 记录mdat的实际size,如果后续需要用到,则调用
uint32_t mdat_size_offset; // 记录mdat的size变量偏移
uint32_t mdat_offset;
uint32_t mdat_nowoffset;
uint32_t mvhd_duration_offset;
F_FILE *fp;
// 设置缓冲区
trak_key_msg trak[2];
} mp4_key_msg;
typedef struct
{
uint32_t size;
char boxname[4];
} mp4_common_box_s; // 通用结构体
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24;
} mp4_common_box_full_s; // 通用结构体
typedef struct
{
char major[4];
uint32_t version;
char *compatible_brands; // 字符串,每一个是4byte(不能带'\0'),默认"mp42isom"
} mp4_ftyp;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t creation_time;
uint32_t modification_time;
uint32_t timescale;
uint32_t duration;
uint32_t rate;
uint16_t volume;
uint8_t reserved1[2];
uint8_t reserved2[8];
uint32_t matrix[9];
uint32_t pre_defined[6];
uint32_t next_track_id;
} mp4_mvhd;
typedef struct
{
uint32_t size; // 采用预留方式,可以动态添加数据
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t creation_time;
uint32_t modification_time;
uint32_t track_ID;
uint8_t reserved1[4];
uint32_t duration;
uint8_t reserved2[8];
uint16_t layer;
uint16_t alternate_group;
uint16_t volume;
uint8_t reserved3[2];
uint32_t matrix[9];
uint32_t width; // 16整数+16小数
uint32_t height; // 16整数+16小数
} mp4_tkhd;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t creation_time;
uint32_t modification_time;
uint32_t timescale;
uint32_t duration;
uint16_t language;
uint16_t pre_defined;
} mp4_mdhd;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t pre_defined;
char handler_type[4];
uint8_t reserved[12];
// char name[1]; //可变参数
} mp4_hdlr;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint16_t graphicsmode;
uint16_t opcolorR;
uint16_t opcolorG;
uint16_t opcolorB;
} mp4_vmhd;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t entry_count;
} mp4_dref;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
} mp4_url;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t entry_count;
} mp4_stsd;
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint8_t reserved1[6];
uint16_t data_reference_index;
uint8_t pre_defined1[16];
uint16_t width;
uint16_t height;
uint32_t horiz_resolution;
uint32_t vert_resolution;
uint8_t reserved2[4];
uint16_t frame_count;
uint8_t compressorname[32];
uint16_t depth;
uint8_t pre_defined2[2];
} mp4_avc1;
// 因为涉及pps和sps,所以需要找到对应pps和sps才能初始化
// 测试可以先采用固定模式
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint8_t configurationVersion; // 1
uint8_t AVCProfileIndication; // sps[3]
uint8_t profile_compatibility; // sps[4]
uint8_t AVCLevelIndication; // sps[5]
uint8_t lengthSizeMinusOne; // 0xff
#if 0
uint8_t numOfSPS;
uint8_t *sps_data;
uint16_t sps_data_size;
uint8_t numOfPPS;
uint8_t *pps_data;
uint16_t pps_data_size;
#endif
} mp4_avcC;
typedef struct __attribute__((packed))
{
uint32_t size; // 盒子大小
char boxname[4]; // 固定为'colr'
char colour_type[4]; // 颜色类型: 'nclc', 'prof', 'rICC'
uint16_t colour_primaries; // 颜色原色
uint16_t transfer_characteristics; // 传输特性
uint16_t matrix_coefficients; // 矩阵系数
uint8_t full_range_flag; // 颜色范围标志 (bit 7)
} mp4_colr;
typedef struct
{
uint8_t numOfSPS;
uint8_t *sps_data;
uint16_t sps_data_size;
uint8_t numOfPPS;
uint8_t *pps_data;
uint16_t pps_data_size;
} mp4_sps_pps;
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t entry_count; // 应该采用预留空间的方法
union
{
stts_entries entries;
stts_entries end;
};
} mp4_stts;
typedef struct
{
uint32_t first_chunk;
uint32_t per_chunk;
uint32_t index;
} stsc_entries;
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t entry_count; // 应该采用预留空间的方法
union
{
stsc_entries entries;
stsc_entries end;
};
} mp4_stsc;
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t sample_size; // 应该采用预留空间的方法
uint32_t sample_count;
union
{
uint32_t entries;
uint32_t end;
};
} mp4_stsz;
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t entry_count; // 应该采用预留空间的方法
union
{
uint32_t chunk_offsets;
uint32_t end;
};
} mp4_stco;
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24; // version+flags
uint32_t entry_count; // 应该采用预留空间的方法
union
{
uint32_t sample_numbers;
uint32_t end;
};
} mp4_stss;
typedef struct
{
uint32_t size;
char boxname[4];
uint32_t version : 8, flags : 24;
uint16_t balance;
uint16_t reserved;
} mp4_smhd;
typedef struct __attribute__((packed))
{
uint32_t size;
char boxname[4];
uint8_t reserved4[4];
uint8_t reserved2[2];
uint16_t dataReferenceIndex;
uint16_t version, revisionLevel;
uint32_t vendor;
uint16_t channelCount;
uint16_t sampleSize;
uint8_t reserved[4];
uint32_t time_scale;
} mp4_mp4a;
typedef uint32_t (*mp4_func)(F_FILE *fp, uint32_t offset, mp4_key_msg *msg);
typedef struct
{
uint32_t offset;
mp4_func func;
} mp4_func_stack;
uint32_t write_aac_data(mp4_key_msg *msg, uint8_t *aac_buf, uint32_t size, uint32_t duration);
uint32_t mp4_syn(mp4_key_msg *msg);
void *MP4_open_init(F_FILE *fp, uint8_t audio_en);
uint32_t mp4_audio_cfg_init(mp4_key_msg *msg, uint8_t *asps_data, uint8_t len);
uint32_t mp4_set_max_size(mp4_key_msg *msg, uint32_t max_size);
uint32_t mp4_video_cfg_init(mp4_key_msg *msg, uint16_t w, uint16_t h);
uint32_t write_h264_pps_sps(mp4_key_msg *msg, uint8_t *nal_buf, uint32_t size);
uint32_t write_h264_data(mp4_key_msg *msg, uint8_t *nal_buf, uint32_t size, uint32_t duration);
uint32_t mp4_deinit(mp4_key_msg *msg);
#endif