av_read_frame读出的视频流数据在AVPacket中的存储

本文详细解析了FFmpeg中AVPacket结构体的定义及其字段含义,并通过实际文件对比展示了packet数据的存储方式,包括关键帧和非关键帧的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、先看看AVPacket的定义:

typedef struct AVPacket {
    /**
     * A reference to the reference-counted buffer where the packet data is
     * stored.
     * May be NULL, then the packet data is not reference-counted.
     */
    AVBufferRef *buf;
    /**
     * Presentation timestamp in AVStream->time_base units; the time at which
     * the decompressed packet will be presented to the user.
     * Can be AV_NOPTS_VALUE if it is not stored in the file.
     * pts MUST be larger or equal to dts as presentation cannot happen before
     * decompression, unless one wants to view hex dumps. Some formats misuse
     * the terms dts and pts/cts to mean something different. Such timestamps
     * must be converted to true pts/dts before they are stored in AVPacket.
     */
    int64_t pts;
    /**
     * Decompression timestamp in AVStream->time_base units; the time at which
     * the packet is decompressed.
     * Can be AV_NOPTS_VALUE if it is not stored in the file.
     */
    int64_t dts;
    uint8_t *data;
    int   size;
    int   stream_index;
    /**
     * A combination of AV_PKT_FLAG values
     */
    int   flags;
    /**
     * Additional packet data that can be provided by the container.
     * Packet can contain several types of side information.
     */
    AVPacketSideData *side_data;
    int side_data_elems;

    /**
     * Duration of this packet in AVStream->time_base units, 0 if unknown.
     * Equals next_pts - this_pts in presentation order.
     */
    int   duration;
#if FF_API_DESTRUCT_PACKET
    attribute_deprecated
    void  (*destruct)(struct AVPacket *);
    attribute_deprecated
    void  *priv;
#endif
    int64_t pos;                            ///< byte position in stream, -1 if unknown

    /**
     * Time difference in AVStream->time_base units from the pts of this
     * packet to the point at which the output from the decoder has converged
     * independent from the availability of previous frames. That is, the
     * frames are virtually identical no matter if decoding started from
     * the very first frame or from this keyframe.
     * Is AV_NOPTS_VALUE if unknown.
     * This field is not the display duration of the current packet.
     * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY
     * set.
     *
     * The purpose of this field is to allow seeking in streams that have no
     * keyframes in the conventional sense. It corresponds to the
     * recovery point SEI in H.264 and match_time_delta in NUT. It is also
     * essential for some types of subtitle streams to ensure that all
     * subtitles are correctly displayed after seeking.
     */
    int64_t convergence_duration;
} AVPacket;
这应该是ffmpeg中定义算很少的结构体了,大致意思注释已经说很清楚了。

2、下面说下我的理解

data存储的是从文件中读出来的流数据。

pts和dts为显示、解码时间戳,他们两个乘以AVStream中的timebase可以得到真实的时间。

flags可以通过if(pkt.flags &AV_PKT_FLAG_KEY )来判断是否为关键帧。

//////如果是h264编码,从帧数据判断
frame = |length|data|
length后面紧跟着的第一个byte后5位如果是01001则为关键帧
if((frame[4] & 0x1f) == 5)
{
keyframe
}

else

{
not keyframe
}

pos是此帧在源文件中的位置。

stream_index为流数据索引号。

size为此packet大小。

3、源文件中的数据如何在packet的data中存储的

以avi文件为例,把packet数据保存到文件并和源文件比较,看下图:

左边是packet保存的数据,右边是源文件数据,此帧是一个关键帧。
再看下图,此图是程序中对应packet的数据视图:

可以看出源文件中00dc表示视频流数据,12 30 00 00 四个字节表示长度,根据存储规则,长度为0x3012,pos为26ee,第一个四字节为00 00 01 00为关键帧标示,和源文件一一对应。

再看下图,为非关键帧和源文件对比:

左边是packet数据,右边是源文件,
再来看与之对应的packet数据视图:

可以看出packet存储的是源文件00dc和数据长度后面的数据。
从关键帧和非关键帧的对比中可以看出,在avi中data的头4字节标示了是否为关键帧。

以x264编码的MP4文件:
下图是read出的第一个视频流pack:

可以看到,很多关于x264的参数都在这里。




<think>好的,我现在需要帮助用户解决在使用av_interleaved_write_frame推流时出现的视频花屏问题。首先,我得回忆一下用户提供的引用内容,特别是引用4,里面提到他们遇到了花屏和画面卡住的问题,发现pts的设置是关键,必须自增90000而不是0。这可能涉及到时间戳的正确处理。接下来,我需要考虑可能导致花屏的其他原因。根据FFmpeg的知识,花屏通常和编码参数、数据包处理、时间戳、关键帧间隔等有关。用户的问题集中在av_interleaved_write_frame,所以需要分析这个函数的使用注意事项。首先,检查时间戳是否正确。引用2和4都提到时间基转换和pts的设置。比如,av_packet_rescale_ts是否正确调整了时间基,确保时间戳与流的time_base匹配。如果时间戳没有正确转换,可能导致同步问题,进而花屏。其次,关键帧的问题。如果视频流中缺少关键帧(I帧),或者GOP(关键帧间隔)设置过大,解码端可能在丢包后无法正确恢复图像,导致花屏。需要检查编码器的参数,比如gop_size是否合理。 另外,编码器本身的配置是否正确?比如码率、分辨率、像素格式是否匹配。如果用户使用的是硬件编码器,可能需要检查数据是否正确地传递给了硬件,比如是否正确的内存映射或拷贝。引用4提到用户使用硬件编码,可能涉及数据拷贝的问题,比如没有正确复制数据包的内容,导致数据损坏。 还有,检查av_interleaved_write_frame的使用是否正确。比如,是否在每次写入前正确设置了packet的stream_index,是否在写入后释放了资源。引用2中的代码示例显示,设置stream_index是必要的步骤。数据包处理方面,是否正确地处理了B帧(双向预测帧),这会影响dts和pts的顺序。如果dts和pts设置不正确,可能导致解码顺序错误,出现花屏。此外,还要考虑推流协议(如RTSP)的封装格式是否正确,是否支持特定的编码格式。例如,某些协议可能对H.264的打包方式有特定要求,需要检查sps和pps参数是否已经正确发送。可能的解决方案包括:确保时间戳连续递增,正确进行时间基转换;检查编码器配置,确保关键帧间隔合理;验证数据包的数据是否正确,特别是硬件编码后的数据是否需要特殊处理;检查是否所有必要的流信息(如sps/pps)已经写入输出流。最后,需要根据用户的代码示例,特别是引用4中的处理,建议用户检查pts的自增是否合理,是否与帧率匹配。比如,如果帧率是30fps,时间基可能是1/90000,所以每帧pts递增3000(90000/30),但用户提到递增90000有效,这可能与具体的时间基设置有关,需要进一步确认。</think>### av_interleaved_write_frame视频推流花屏问题解析 #### 一、主要原因分析 1. **时间戳(PTS/DTS)错误** - 未正确设置`AVPacket`的`pts`和`dts`会导致解码器无法按顺序处理帧,引发花屏[^4]。若`pts`为0或非递增,视频可能卡顿并伴随花屏。 - 时间基未正确转换:需通过`av_packet_rescale_ts`将编码器时间基转换为输出流时间基[^2]。 2. **关键帧(I帧)缺失** - 编码参数中`gop_size`设置过大或未强制插入关键帧,导致解码端无法恢复图像。 3. **硬件编码数据未正确映射** - 硬件编码器(如NVENC)输出的数据可能需特殊处理(如内存拷贝或映射),直接引用可能导致数据损坏[^4]。 4. **编码参数与流格式不匹配** - 分辨率、像素格式(如YUV420P)或码率与输出流协议要求冲突。 --- #### 二、解决方案 1. **时间戳处理** - **手动递增PTS**:根据帧率计算步长,例如帧率30fps时,时间基为`1/90000`,则每帧`pts`递增`3000`(90000/30)[^4]。 - **时间基转换**:调用`av_packet_rescale_ts(pkt, src_timebase, stream_timebase)`确保时间戳对齐[^2]。 ```c // 示例:时间基转换与PTS自增 AVPacket *pkt = av_packet_alloc(); pkt->pts = pts_counter; pkt->dts = pts_counter; av_packet_rescale_ts(pkt, codec_timebase, stream_timebase); pts_counter += 90000 / framerate; // 根据实际帧率调整 ``` 2. **强制插入关键帧** - 设置编码器参数`AV_CODEC_FLAG2_FORCE_KEY_FRAME`或指定`gop_size=0`(每帧为关键帧)。 3. **硬件数据处理** - 若使用硬件编码(如CUDA),需将GPU内存数据拷贝到CPU缓冲区后再封装: ```c // 示例:从GPU显存拷贝到CPU av_hwframe_transfer_data(sw_frame, hw_frame, 0); ``` 4. **验证封装格式** - RTSP推流需确保`AVStream`的`codecpar`中`extradata`包含H.264的SPS/PPS,可通过`avformat_write_header`自动写入。 --- #### 三、调试建议 1. **检查编码输出数据** - 用`ffplay`直接播放编码后的本地文件,确认是否花屏。 2. **日志跟踪** - 启用FFmpeg日志`av_log_set_level(AV_LOG_DEBUG)`,观察`av_interleaved_write_frame`返回值及错误码。 3. **帧内容验证** - 在调用`av_interleaved_write_frame`前,检查`AVPacket`的`data`是否包含完整帧数据。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dancing_night

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值