AVPacket结构体是FFmpeg中用于存储编码或解码后的媒体数据的数据结构。AVPacket通常与AVFrame结构体一起使用,用于进行媒体数据的编解码和处理。下面是关于AVPacket结构体的详细介绍,并提供一个简单的代码示例。
AVPacket 结构体定义
AVPacket结构体的定义可以在FFmpeg的AVPacket.h头文件中找到。其定义如下:
typedef struct AVPacket {
...
} AVPacket;
AVPacket 结构体成员变量
AVPacket结构体包含了丰富的参数和数据信息,其中一些重要的成员变量如下:
buf:AVBufferRef 结构体指针,该结构体用于存储媒体数据的内存区域,支持自动管理内存(引用计数)和手动管理内存(avbufferalloc() 和 avbufferunref()),有效提高媒体数据的传输效率和程序的稳定性。
data:指向媒体数据的指针,是 AVPacket 结构体中的重要成员,用于访问和管理媒体数据。
size:媒体数据的长度,单位为字节,描述了该AVPacket中存储的实际媒体数据大小。
pts:表示该数据包的显示时间戳 Presentation Timestamp,也就是解码后该数据包内容在整个媒体流中的显示时间。
dts:表示该数据包的解码时间戳 Decode Timestamp,也就是该数据包在整个媒体流中的时间排序标记。
duration:表示该数据包所持续的时间长度,通常表示几秒或几帧。
stream_index:媒体数据流的索引号,用于标记该数据包属于哪个媒体流。
flags:一个32位的标志位,用于支持一些针对特定编码器和格式的编解码特性。
除此之外,还有一些额外的成员变量,如 sidedata、pos、convergenceduration、codec、discarded等等可以根据实际需求来使用和调整。
AVPacket 结构体使用示例
下面是一个简单的示例代码,用于从一个媒体文件中读取媒体数据包,进行解码,并将解码后的媒体数据保存到一个新的媒体文件中。
// 打开媒体文件,并获取媒体文件的AVFormatContext结构体
AVFormatContext *fmt_ctx = avformat_alloc_context();
if (avformat_open_input(&fmt_ctx, input_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open input file '%s'\n", input_filename);
return -1;
}
// 找到视频流和音频流解码器并打开
...
// 分配AVPacket和AVFrame结构体
AVPacket *pkt = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
// 打开输出文件并写文件头
AVIOContext *output_io_ctx = NULL;
if (avio_open(&output_io_ctx, output_filename, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Could not open output file '%s'\n", output_filename);
return -1;
}
AVFormatContext *output_fmt_ctx = avformat_alloc_context();
output_fmt_ctx->pb = output_io_ctx;
if (avformat_write_header(output_fmt_ctx, NULL) < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
return -1;
}
while (av_read_frame(fmt_ctx, pkt) >= 0) {
if (pkt->stream_index == video_stream_index) {
// 解码视频帧
int ret = avcodec_send_packet(codec_ctx, pkt);
if (ret < 0) {
// 发送数据包失败
av_packet_unref(pkt);
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret < 0) {
break;
}
// 修改AVPacket的媒体数据并向输出文件流中写入
av_packet_rescale_ts(pkt, fmt_ctx->streams[video_stream_index]->time_base,
output_fmt_ctx->streams[video_stream_index]->time_base);
pkt->pos = -1;
pkt->stream_index = output_fmt_ctx->streams[video_stream_index]->index;
av_interleaved_write_frame(output_fmt_ctx, pkt);
// 释放AVFrame结构体的内存
av_frame_unref(frame);
}
}
av_packet_unref(pkt);
}
// 写入输出文件尾,释放资源
...
在以上的代码中,通过 avreadframe() 函数从输入媒体文件中读取单个数据包,然后进行解码,使用 avpacketrescale_ts() 函数对时间戳进行改变并进行一些其他调整,最后将解码后的媒体数据包写入输出文件中。注意在使用 AVPacket 结构体时,需要根据具体的媒体数据类型和应用需求进行参数的调整和处理,以便实现媒体数据的正确处理和传输。此外,还需要进行相应的内存管理和资源释放操作,以防止内存泄漏和资源浪费。