ffmpeg h264 aac 裸数据 保存到文件 avpacket pts 怎么计算
时间: 2023-07-30 22:07:32 浏览: 270
要将 H264 和 AAC 裸数据保存到文件,你需要使用 FFmpeg 库中的 AVFormatContext 和 AVOutputFormat 结构体来打开一个文件并写入数据。具体步骤如下:
1. 使用 avformat_alloc_output_context2 函数创建 AVFormatContext 对象。
2. 使用 avio_open 函数打开输出文件。
3. 使用 avformat_new_stream 函数创建一个新的视频流和音频流。
4. 对于每个视频帧和音频帧,使用 av_packet_alloc 函数创建一个 AVPacket 对象,并将数据填充到 AVPacket 中。
5. 设置 AVPacket 的 PTS(Presentation Time Stamp)和 DTS(Decoding Time Stamp)字段。对于视频帧,PTS 和 DTS 可以通过解码后的帧数据中的信息计算得出;对于音频帧,PTS 和 DTS 可以通过采样率、声道数和采样点数计算得出。
6. 使用 av_interleaved_write_frame 函数将 AVPacket 写入输出文件。
下面是一个保存 H264 和 AAC 裸数据的示例代码:
```c
AVFormatContext *fmt_ctx = NULL;
AVOutputFormat *out_fmt = NULL;
AVStream *video_stream = NULL, *audio_stream = NULL;
AVCodecContext *video_ctx = NULL, *audio_ctx = NULL;
AVPacket video_pkt, audio_pkt;
int video_frame_count = 0, audio_frame_count = 0;
// 打开输出文件
if (avio_open(&fmt_ctx->pb, "output.mp4", AVIO_FLAG_WRITE) < 0) {
printf("Error opening output file.\n");
return -1;
}
// 创建 AVFormatContext 对象
if (avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, "mp4") < 0) {
printf("Error creating output context.\n");
return -1;
}
// 查找 H264 和 AAC 编码器
AVCodec *video_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
AVCodec *audio_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
// 创建视频流和音频流
video_stream = avformat_new_stream(fmt_ctx, video_codec);
audio_stream = avformat_new_stream(fmt_ctx, audio_codec);
// 创建视频编码器和音频编码器上下文
video_ctx = avcodec_alloc_context3(video_codec);
audio_ctx = avcodec_alloc_context3(audio_codec);
// 填充视频编码器和音频编码器上下文
video_ctx->width = 1280;
video_ctx->height = 720;
video_ctx->time_base = (AVRational){1, 30};
video_ctx->framerate = (AVRational){30, 1};
video_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
avcodec_parameters_from_context(video_stream->codecpar, video_ctx);
audio_ctx->sample_rate = 44100;
audio_ctx->channels = 2;
audio_ctx->channel_layout = av_get_default_channel_layout(2);
audio_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
audio_ctx->time_base = (AVRational){1, 44100};
avcodec_parameters_from_context(audio_stream->codecpar, audio_ctx);
// 打开视频编码器和音频编码器
avcodec_open2(video_ctx, video_codec, NULL);
avcodec_open2(audio_ctx, audio_codec, NULL);
// 初始化 AVPacket
av_init_packet(&video_pkt);
av_init_packet(&audio_pkt);
// 读取视频帧和音频帧,写入输出文件
while (/* 读取视频帧 */) {
// 填充视频帧数据到 video_pkt 中
video_pkt.data = /* 视频帧数据 */;
video_pkt.size = /* 视频帧数据大小 */;
// 计算视频帧的 PTS 和 DTS
video_pkt.pts = av_rescale_q(video_frame_count, video_ctx->time_base, video_stream->time_base);
video_pkt.dts = video_pkt.pts;
// 设置视频帧的 stream_index 字段
video_pkt.stream_index = video_stream->index;
// 写入视频帧到输出文件
av_interleaved_write_frame(fmt_ctx, &video_pkt);
// 增加视频帧计数器
video_frame_count++;
}
while (/* 读取音频帧 */) {
// 填充音频帧数据到 audio_pkt 中
audio_pkt.data = /* 音频帧数据 */;
audio_pkt.size = /* 音频帧数据大小 */;
// 计算音频帧的 PTS 和 DTS
audio_pkt.pts = av_rescale_q(audio_frame_count * audio_ctx->frame_size, audio_ctx->time_base, audio_stream->time_base);
audio_pkt.dts = audio_pkt.pts;
// 设置音频帧的 stream_index 字段
audio_pkt.stream_index = audio_stream->index;
// 写入音频帧到输出文件
av_interleaved_write_frame(fmt_ctx, &audio_pkt);
// 增加音频帧计数器
audio_frame_count++;
}
// 关闭输出文件并释放资源
av_write_trailer(fmt_ctx);
avcodec_close(video_ctx);
avcodec_close(audio_ctx);
avio_close(fmt_ctx->pb);
avformat_free_context(fmt_ctx);
```
在上面的示例代码中,我们使用 av_rescale_q 函数将帧计数器转换为时间戳。这个函数将一个数值从一个时间基转换到另一个时间基,例如将帧计数器转换为以秒为单位的时间戳。在视频流中,时间基是帧率的倒数,例如 1/30;在音频流中,时间基是采样率的倒数,例如 1/44100。
阅读全文