AVPacket 相关API

本文详细介绍了FFmpeg中AVPacket的相关API,包括如何分配、初始化、复制、调整大小等操作,并解释了AVPacket的数据管理机制。

AVPacket 相关API 定义是在avcodec.h  中, 但是函数实体在avpacket.c 中。需要注意的是av_packet_alloc() 申请的是AVPacket 本身struct 的空间,data buff 需要单独申请,比如av_new_packet()。data buff 通过av_packet_unref() 释放,当refcount 为1 时,buff 才真正释放,av_packet_ref() refcountf 加1, av_packet_unref() refcount 减1。packet_side_data 是packet 一些附加信息,例如在编码结束时,更新一些流的参数。

函数原型

作用

AVPacket *av_packet_alloc(void);

alloc avpacket struct,但是没有给data 开辟空间,可通过av_new_packet() 去为data 开辟空间

AVPacket *av_packet_clone(const AVPacket *src)

根据src clone 一个avpacket,等于av_packet_alloc() + av_packet_ref()

void av_packet_free(AVPacket **pkt);

free avpacket, 如果ref 被计数,将先unref

void av_init_packet(AVPacket *pkt)

初始化avpacket 成默认值

int av_new_packet(AVPacket *pkt,int size)

为avpacket date 开辟空间

void av_shrink_packet(AVPacket *pkt,int size);

将AVPacket 的size减小到设置的size

int avgrow_packet(AVPacket *pkt,int grow_by);

通过realloc 增加grow_by 的空间

int  av_packet_from_data(*pkt,data,size)

将malloc 过的data 传递给avpacket

av_packet_new_side_data(pkt,sideDateType,size)

alloc side data

av_packet_add_side_data(pkt,sideDateTyoe,*data,size)

添加side_data 信息

u8 *av_packet_pack_dictionary(dict,size)

pack a dictionary for use in side_date

int av_packet_unpack_dictionary(data,size,dict)

unpack adictionary from side_data

av_packet_free_side_data(avpacket *data)

free all the side data

int av_packet_ref(AVPacket *dst,const AVPacket *src)

相当于将AVPacket软链接

void av_packet_unref(AVPakct* pkt)

当unref count 到1 时,data将被清空

void av_packet_move_ref(AVPackt *dst,AVPackt*src)

将 src move 到dst , src 被清空,ref count 不变

int av_packet_copy_props(AVPackt *dst,AVPackt*src)

只仅仅将properties copy

int av_packet_make_refcounted(AVPacket *pkt)

确保data buf 存在

int av_packet_make_writeable(AVPacket *pkt)

与上差不多,都是确保data buf空间的存在

void av_packet_rescale_ts(pkt,RationaSrc.RationalDst)

将pts,dts,duration时间信息进行转换

 

<think>好的,我现在需要帮助用户了解在使用FFmpeg API封装MP4时AVPacket的作用和用法。用户之前已经询问过如何在Linux C环境下使用FFmpeg封装MP4,现在他们特别关注AVPacket的具体使用。我需要结合之前的回答和提供的引用资料来详细解答。 首先,回顾用户之前的提问和我的回答,其中提到了写入数据包的步骤,涉及AVPacket的初始化和写入。用户现在可能想更深入地了解AVPacket的结构、生命周期以及在实际编码和封装中的具体应用。 接下来,查看用户提供的引用资料,引用[3]提到了AVPacket的内存管理问题,指出如果不正确释放会导致内存泄漏。引用[4]讨论了MP4解封装时处理音频和视频流,保存为AAC和H264文件,这可能涉及到AVPacket的解封装过程,但用户现在关注的是封装,所以需要反向思考如何正确填充和写入AVPacket。 我需要从以下几个方面展开: 1. **AVPacket的基本结构**:解释AVPacket在FFmpeg中的作用,作为编码后的数据包,包含压缩后的音视频数据及其元数据,如PTS、DTS、流索引等。 2. **AVPacket的生命周期**:如何正确初始化、分配内存、填充数据、写入文件,最后释放资源,避免内存泄漏。需要强调av_packet_unref的重要性,如引用[3]提到的内存泄漏问题。 3. **在封装MP4时的具体应用**:包括设置流索引、时间戳计算(PTS/DTS)、数据写入方式(av_interleaved_write_frame)。需要结合之前的代码示例,说明如何将编码后的数据包写入输出文件。 4. **时间戳同步问题**:如何根据流的time_base计算正确的PTS和DTS,确保音视频同步。引用用户之前的问题中的相关问题,可能需要简要提及同步策略。 5. **错误处理和内存管理**:强调在每次写入后释放AVPacket资源,避免内存泄漏,引用[3]中的教训。 此外,用户可能在实际编码过程中遇到问题,比如如何将原始数据编码为AVPacket,但根据问题描述,用户主要关注封装过程,所以重点应放在封装阶段AVPacket的处理,而不是编码过程。 需要确保回答结构清晰,分步骤说明使用方法,并结合代码示例,让用户能够直接应用。同时,相关问题部分要引导用户深入可能遇到的问题,如内存管理、时间戳处理等,参考之前的回答和相关引用。</think>以下为分步解答: ### FFmpeg AVPacket在MP4封装中的核心作用与使用方法 AVPacket是FFmpeg多媒体处理流程中的核心数据结构,在MP4封装过程中承担着*编码后数据载体*的角色(存储压缩后的音视频帧)。其关键应用场景如下: $$ \text{编码器输出} \xrightarrow{\text{生成}} \text{AVPacket} \xrightarrow{\text{写入}} \text{MP4容器} $$ #### 一、AVPacket生命周期管理(重点) 1. **初始化与创建** ```c AVPacket *pkt = av_packet_alloc(); // FFmpeg 4.0+推荐方式 av_init_packet(pkt); // 传统初始化方法(需配合av_packet_unref) ``` *注意:av_packet_alloc()与av_init_packet()不可混用[^3]* 2. **数据填充流程** ```c // 假设已通过编码器获得压缩数据 pkt->data = encoded_data; // 指向编码后的二进制数据 pkt->size = data_size; // 数据长度 pkt->stream_index = stream_index; // 对应视频/音频流索引 pkt->pts = calc_pts(); // 显示时间戳(需按time_base换算) pkt->dts = calc_dts(); // 解码时间戳 pkt->duration = frame_duration; // 帧持续时间 ``` 3. **时间戳计算示例** ```c // 假设视频流time_base = {1, 25}(25fps) int64_t pts = frame_count * video_stream->time_base.den / 25; // 计算绝对时间戳 pkt->pts = av_rescale_q(pts, AV_TIME_BASE_Q, video_stream->time_base); ``` 4. **写入容器文件** ```c int ret = av_interleaved_write_frame(fmt_ctx, pkt); // 自动处理数据包排序 if (ret < 0) { fprintf(stderr, "写入失败: %s\n", av_err2str(ret)); } ``` 5. **内存释放** ```c av_packet_unref(pkt); // 清空数据包内容 av_packet_free(&pkt); // 释放数据包对象(alloc创建时使用) ``` *关键点:每次写入后必须调用av_packet_unref(),否则会导致内存泄漏[^3]* #### 二、封装MP4时的特殊处理 1. **流匹配验证** ```c // 检查数据包与流的对应关系 if (pkt->stream_index == video_stream->index) { // 视频包处理逻辑 } else if (pkt->stream_index == audio_stream->index) { // 音频包处理逻辑 } ``` 2. **关键帧标记** ```c if (pkt->flags & AV_PKT_FLAG_KEY) { printf("关键帧数据包\n"); // MP4需要关键帧作为随机访问点 } ``` 3. **时间基转换公式** $$ \text{目标时间戳} = \text{原始时间戳} \times \frac{\text{目标时间基}}{\text{源时间基}} $$ 对应代码实现: ```c pkt->pts = av_rescale_q_rnd(pkt->pts, in_time_base, out_time_base, AV_ROUND_NEAR_INF); pkt->dts = av_rescale_q_rnd(pkt->dts, in_time_base, out_time_base, AV_ROUND_NEAR_INF); ``` #### 三、典型错误处理模式 ```c AVPacket *pkt = av_packet_alloc(); while (/* 获取数据包的条件 */) { if (av_read_frame(fmt_ctx, pkt) < 0) break; // 时间戳重计算 pkt->pts = av_rescale_q_rnd(...); if (av_interleaved_write_frame(output_ctx, pkt) < 0) { av_packet_unref(pkt); // 写入失败仍需释放 break; } av_packet_unref(pkt); // 成功写入后释放 } av_packet_free(&pkt); ``` ### 附:完整数据包处理流程图 ``` [编码器输出] ↓ av_packet_alloc() ↓ 填充编码数据/时间戳 ↓ av_interleaved_write_frame() ↓ av_packet_unref() ←─┐ │ │ └───[循环处理]───┘ ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值