H.264 封装mp4 源码
时间: 2024-01-17 15:03:23 浏览: 95
H.264 封装为 MP4 的源码可以比较复杂,需要涉及到视频编码、封装格式等多个方面的知识。以下是一个简单的示例代码,可以实现将 H.264 裸流封装为 MP4 文件的功能:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FRAME_RATE 25
#define BIT_RATE 4800000
typedef struct {
FILE *fp;
int width;
int height;
int frame_rate;
int bit_rate;
int gop_size;
int frame_count;
} MP4File;
typedef struct {
unsigned char *data;
int size;
int key_frame;
int pts;
} H264Frame;
static void write_int(FILE *fp, int value)
{
unsigned char buf[4];
buf[0] = value >> 24;
buf[1] = value >> 16;
buf[2] = value >> 8;
buf[3] = value;
fwrite(buf, 1, 4, fp);
}
static void write_short(FILE *fp, short value)
{
unsigned char buf[2];
buf[0] = value >> 8;
buf[1] = value;
fwrite(buf, 1, 2, fp);
}
static void write_data(FILE *fp, unsigned char *data, int size)
{
fwrite(data, 1, size, fp);
}
MP4File *mp4_create(const char *filename, int width, int height, int frame_rate, int bit_rate)
{
MP4File *mp4 = (MP4File *)malloc(sizeof(MP4File));
memset(mp4, 0, sizeof(MP4File));
mp4->fp = fopen(filename, "wb");
if (!mp4->fp) {
printf("failed to create mp4 file\n");
free(mp4);
return NULL;
}
mp4->width = width;
mp4->height = height;
mp4->frame_rate = frame_rate;
mp4->bit_rate = bit_rate;
mp4->gop_size = frame_rate * 2;
write_data(mp4->fp, (unsigned char *)"ftypisom", 8);
write_int(mp4->fp, 0);
write_data(mp4->fp, (unsigned char *)"isom", 4);
write_data(mp4->fp, (unsigned char *)"mp42", 4);
return mp4;
}
void mp4_destroy(MP4File *mp4)
{
if (mp4) {
fclose(mp4->fp);
free(mp4);
}
}
void mp4_write_frame(MP4File *mp4, H264Frame *frame)
{
if (!mp4 || !frame) {
return;
}
if (frame->key_frame) {
write_data(mp4->fp, (unsigned char *)"mdat", 4);
write_int(mp4->fp, 0);
}
int size = frame->size + 4;
write_int(mp4->fp, size);
if (frame->key_frame) {
write_data(mp4->fp, (unsigned char *)"avc1", 4);
write_short(mp4->fp, 0);
write_short(mp4->fp, 0);
write_short(mp4->fp, mp4->width);
write_short(mp4->fp, mp4->height);
write_int(mp4->fp, mp4->bit_rate);
write_int(mp4->fp, mp4->frame_rate);
write_short(mp4->fp, 1);
write_short(mp4->fp, 12);
write_data(mp4->fp, (unsigned char *)"avcC", 4);
write_int(mp4->fp, 0x01);
write_data(mp4->fp, frame->data + 4, 3);
write_short(mp4->fp, 0xffe1);
write_short(mp4->fp, 16);
write_data(mp4->fp, (unsigned char *)"avcC", 4);
write_data(mp4->fp, frame->data + 7, frame->size - 7);
} else {
write_data(mp4->fp, frame->data, frame->size);
}
mp4->frame_count++;
}
int main()
{
MP4File *mp4 = mp4_create("test.mp4", 1280, 720, FRAME_RATE, BIT_RATE);
if (!mp4) {
return 0;
}
FILE *h264 = fopen("test.h264", "rb");
if (!h264) {
mp4_destroy(mp4);
return 0;
}
H264Frame frame;
memset(&frame, 0, sizeof(H264Frame));
frame.data = (unsigned char *)malloc(1024 * 1024);
while (!feof(h264)) {
size_t size = fread(frame.data, 1, 1024 * 1024, h264);
frame.size = size;
frame.key_frame = 1;
frame.pts = mp4->frame_count * 90000 / mp4->frame_rate;
mp4_write_frame(mp4, &frame);
}
free(frame.data);
fclose(h264);
mp4_destroy(mp4);
return 0;
}
```
在这个示例中,我们首先定义了一个 MP4File 结构体,用于保存 MP4 文件的相关信息,比如宽高、帧率、码率等。mp4_create 函数用于创建 MP4 文件,它会写入 MP4 文件的头信息。mp4_write_frame 函数用于写入 H.264 数据帧,它会根据帧类型(关键帧或非关键帧)来写入相应的 MP4 Box。最后,在主函数中我们读入 H.264 裸流,并将其封装为 MP4 文件。
需要注意的是,这里只是一个简单的示例,实际的 MP4 封装格式可能比这个复杂得多,还需要考虑音频、时间戳等问题。如果需要进行更加复杂的封装,建议使用现有的一些开源封装库,比如 FFmpeg 等。
阅读全文