ffmpeg之AVPacket结构体详细解释

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 结构体时,需要根据具体的媒体数据类型和应用需求进行参数的调整和处理,以便实现媒体数据的正确处理和传输。此外,还需要进行相应的内存管理和资源释放操作,以防止内存泄漏和资源浪费。

你可能感兴趣的:(ffmpeg)