FFmpeg学习笔记之av_parser_parse2()

av_parser_parse2()拿到AVPaket数据,将一个个AVPaket数据解析组成完整的一帧未解码的压缩数据;

跟av_read_frame类似。

输入必须是只包含视频编码数据“裸流”(例如H.264、HEVC码流文件),而不能是包含封装格式的媒体数据(例如AVI、MKV、MP4)。

av_parser_init():初始化AVCodecParserContext。其参数是codec_id,所以同时只能解析一种


AVCodecParser用于解析输入的数据流并把它们分成一帧一帧的压缩编码数据。核心函数是av_parser_parse2():

av_parser_parse2():解析数据获得一个Packet, 从输入的数据流中分离出一帧一帧的压缩编码数据。

/** 
 * Parse a packet. 
 * 
 * @param s             parser context. 
 * @param avctx         codec context. 
 * @param poutbuf       set to pointer to parsed buffer or NULL if not yet finished. 
 * @param poutbuf_size  set to size of parsed buffer or zero if not yet finished. 
 * @param buf           input buffer. 
 * @param buf_size      input length, to signal EOF, this should be 0 (so that the last frame can be output). 
 * @param pts           input presentation timestamp. 
 * @param dts           input decoding timestamp. 
 * @param pos           input byte position in stream. 
 * @return the number of bytes of the input bitstream used. 
 * 
 * Example: 
 * @code 
 *   while(in_len){ 
 *       len = av_parser_parse2(myparser, AVCodecContext, &data, &size, 
 *                                        in_data, in_len, 
 *                                        pts, dts, pos); 
 *       in_data += len; 
 *       in_len  -= len; 
 * 
 *       if(size) 
 *          decode_frame(data, size); 
 *   } 
 * @endcode 
 */  
int av_parser_parse2(AVCodecParserContext *s,  
                     AVCodecContext *avctx,  
                     uint8_t **poutbuf, int *poutbuf_size,  
                     const uint8_t *buf, int buf_size,  
                     int64_t pts, int64_t dts,  
                     int64_t pos);  

     其中poutbuf指向解析后输出的压缩编码数据帧,buf指向输入的压缩编码数据。如果函数执行完后输出数据为空(poutbuf_size为0),则代表解析还没有完成,还需要再次调用av_parser_parse2()解析一部分数据才可以得到解析后的数据帧。当函数执行完后输出数据不为空的时候,代表解析完成,可以将poutbuf中的这帧数据取出来做后续处理。

数据结构初始化流程:

avformat_open_input()会调用avformat_new_stream()创建AVStream;
avformat_new_stream()中又会调用avcodec_alloc_context3()创建AVCodecContext
av_read_frame():获取媒体的一帧压缩编码数据。其中调用了av_parser_parse2()。(注:av_read_frame()属于外部接口,由上层程序主动调用

“纯净”的解码器中,通过avcodec_decode_video2()(注:此接口在ffmpeg3.0之后已经被遗弃掉了)成功解码第一帧之后,才能获取到宽高等信息

解析出来的数据,可通过下面的方法判断帧类型:
AVCodecParserContext->pict_type  :AV_PICTURE_TYPE_I,AV_PICTURE_TYPE_P


参考:
原文:https://blog.youkuaiyun.com/elesos/article/details/53509420 
 

### av_parser_parse2 函数实现细节及其在解析非帧数据中的作用 #### 1. **av_parser_parse2 的核心功能** `av_parser_parse2` 是 FFmpeg 中的一个重要函数,主要用于从输入的压缩编码数据流中分离出单个的数据帧。它能够识别特定的同步标记(sync markers),从而将连续的比特流分割成独立的帧单元。 该函数的主要参数如下: - `parser`: 解析器上下文 (`AVCodecParserContext`)。 - `avctx`: 编解码器上下文 (`AVCodecContext`)。 - `poutbuf` 和 `poutbuf_size`: 输出缓冲区指针及大小,用于返回解析后的帧数据。 - `buf` 和 `buf_size`: 输入缓冲区指针及大小,提供待解析的压缩编码数据。 - `pts`, `dts`, 和 `pos`: 时间戳及相关位置信息,帮助定位帧的时间和偏移量。 具体来说,`av_parser_parse2` 能够逐步扫描输入数据流,寻找帧边界,并将找到的有效帧传递给调用者[^3]。 #### 2. **实现细节分析** ##### (1)**查找帧边界** - 在内部,`av_parser_parse2` 利用预定义的同步模式表(sync table)来检测每种编解码标准特有的起始码(start code)。例如,在 MPEG-4 ASP 或 H.264 中,常见的起始码为 `0x000001` 或 `0x00000001`。 - 当发现匹配的起始码时,意味着找到了一个新的帧起点。此时,前一段数据被认定为一个完整的帧,并通过 `poutbuf` 返回给调用方。 ##### (2)**时间戳处理** - 如果提供了有效的时间戳(PTS/DTS),它们会被附加到对应的帧上以便后续使用。这对于精确控制播放顺序至关重要。 - 特殊情况下,如果当前帧跨越多个分片,则可能需要累积多次调用来完成整个帧的收集工作。 ##### (3)**错误恢复机制** - 若遇到损坏或不完整的数据包,`av_parser_parse2` 不会立即崩溃而是尝试跳过有问题的部分继续向前推进直到下一个合法帧头出现为止。这种健壮的设计使得即使面对一定程度上的传输丢失也能维持基本的功能正常运作状态[^2]。 #### 3. **如何利用 av_parser_parse2 解析非帧数据** 对于非帧形式存在的原始字节序列(比如裸露的 NAL 单元串列),同样可以借助 `av_parser_parse2` 实现逐帧拆分的目的: ```c #include <libavcodec/avcodec.h> #include <libavutil/mem.h> int main(int argc, char *argv[]) { uint8_t input_buffer[BUFFER_SIZE]; // 假设这是你的输入数据缓存区域 size_t bytes_consumed = 0; AVCodecParserContext *parser = av_parser_init(AV_CODEC_ID_H264); if (!parser) return -1; while ((bytes_consumed += av_parser_parse2( parser, NULL, &data_chunk, &chunk_length, input_buffer + bytes_consumed, remaining_bytes, timestamp_pts, timestamp_dts, byte_position))) { if (chunk_length > 0) { process_individual_frame(data_chunk, chunk_length); // 自定义逻辑去处理每一帧 } } av_parser_close(parser); } ``` 在这个例子当中,循环读取来自外部源的新批次数据填充至本地数组 `input_buffer[]` 内部;每次迭代都把尚未消耗掉剩余部分提交给 `av_parser_parse2` 方法作进一步剖析直至耗尽全部供给物为止[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值