FFMPEG--裸码流解析AVCodecParser
来源:互联网 发布:网络维护公司 编辑:程序博客网 时间:2024/05/19 22:59
介绍
FFMPEG解码音视频的一般来讲,都是直接从媒体容器文件(网络码流或者封装文件)中,读取出AVPaket传个解码器。但一般音视频解码并不是在这样的场景下,而是直接给解码器传送裸码流(AAC、h264等),此时我们需要知道每次传给解码器的音视频数据大小,即每帧音频/视频大小。AVCodecParser可通过音视频裸码流解析出每帧的大小等信息。
AVCodecParser
解析器通过音视频标准解析出每帧音视频信息包括长度信息等。其核心函数如下:
/** * 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中的这帧数据取出来做后续处理。
从上边的参数中我们发现,解析码流帧信息,主要用到AVCodecParserContext 、AVCodecContext 等,这些参数的获取和使用可以参考以下例程:
示例
本示例主要是通过读取音视频裸码流文件,然后使用av_parser_parse2解析出每帧的信息,并将解析出来的每帧长度保存文件。已验证通过的码流类型有H264、Mpeg4、MP3,但aac解析出的长度异常、g719直接崩溃,有待经一步研究。
#include <stdio.h>extern "C"{#include "libavcodec/avcodec.h"};#define ASSERT(X) if(!(X)){printf("####[%s:%d]assert failed:%s\n", __FUNCTION__, __LINE__, #X);}#define _READ_BUF_SIZE (4<<10)int main(){ int dwRet = 0;//各个接口返回值 AVCodec* ptCodec = NULL; AVCodecContext* ptCodecCtx = NULL; AVCodecParserContext* ptCodecParserCtx = NULL; AVPacket tavPacket; av_init_packet(&tavPacket); enum AVCodecID emVidDecId = AV_CODEC_ID_MP3;//AV_CODEC_ID_MPEG4;//AV_CODEC_ID_H264; uint8_t* pbyReadBuf = new uint8_t[_READ_BUF_SIZE];//每次从文件中读取数据的缓冲 memset(pbyReadBuf, 0, _READ_BUF_SIZE); int dwCurBufSize = 0; //记录当前缓冲中剩余有效数据长度 uint8_t* pbyCurBuf = NULL; //记录缓冲读指针位置 const char* pcbyInputFileName = "mp3_3.dat";//"704x576.mpeg4";//"1080P.h264"; const char* pcbyOutPutFileName = "mp3_3.len";//"704x566.mpeg4.len";//"1080P.len"; //这里通过解析裸码流得到每帧长度 FILE* pfInput = fopen(pcbyInputFileName, "rb"); if (!pfInput) { ASSERT(pfInput != NULL); return -1; } FILE* pfOutPut = fopen(pcbyOutPutFileName, "wb"); if (!pfOutPut) { ASSERT(pfOutPut != NULL); return -1; } avcodec_register_all();//注册解码器 ptCodec = avcodec_find_decoder(emVidDecId);//获取指定类型的解码器 if(!ptCodec) { ASSERT(ptCodec != NULL); return -1; } ptCodecParserCtx = av_parser_init(emVidDecId);//根据解码器类型获取解析器上下文 if (!ptCodecParserCtx) { ASSERT(ptCodecParserCtx != NULL); return -1; } ptCodecCtx = avcodec_alloc_context3(ptCodec);//根据解码器获取解码器上下文 if (!ptCodecCtx) { ASSERT(ptCodecCtx != NULL); return -1; } for (;;) { dwCurBufSize = fread(pbyReadBuf, 1, _READ_BUF_SIZE, pfInput); if (feof(pfInput)) { printf("end of file\n"); break; } if (dwCurBufSize == 0) { ASSERT(dwCurBufSize != 0); return -1; } pbyCurBuf = pbyReadBuf; while (dwCurBufSize > 0) { //解析处理,tavPacket.size不为0,说明解析出完整的一帧数据 int len = av_parser_parse2(ptCodecParserCtx, ptCodecCtx, &tavPacket.data, &tavPacket.size, //输出 pbyCurBuf, dwCurBufSize, //输入 AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE); pbyCurBuf += len; //移动缓冲读指针 dwCurBufSize -= len;//剩余缓冲数据长度 if (tavPacket.size == 0) { //如果输出size为0 说明输入长度不够解析为完整的一帧,需要继续输入数据 continue; } //打印输出帧信息 printf("Packet Seq Num:%d\t", ptCodecParserCtx->output_picture_number); printf("KeyFrame:%d pts:%d, dts:%d, duration:%d\t", ptCodecParserCtx->key_frame, ptCodecParserCtx->pts, ptCodecParserCtx->dts, ptCodecParserCtx->duration); switch(ptCodecParserCtx->pict_type) { case AV_PICTURE_TYPE_I: printf("\tPacket Type:I\t"); break; case AV_PICTURE_TYPE_P: printf("\tPacket Type:P\t"); break; case AV_PICTURE_TYPE_B: printf("\tPacket Type:B\t"); break; default: printf("\tPacket Type:error:%d\t", ptCodecParserCtx->pict_type); break; } printf("\tPacket Size:%d\n", tavPacket.size); //将长度信息保存到文件中 fprintf(pfOutPut, "%d\n", tavPacket.size); } } }
以上解析出来的AvPacket就是完整的一帧码流,可以直接传给解码器解码。
参考
本文主要参考雷神博客:
参考原文点击这里
0 0
- FFMPEG--裸码流解析AVCodecParser
- AVCodecParser
- FFmpeg总结(五)AV系列结构体之AVCodec、AVCodecParameters、AVCodecParser、AVCodecParserContext、AVCodecDescriptor
- AVCodecParser用于解析输入的数据流并把它分成一帧一帧的压缩编码数据。
- AVCodecParser用于解析输入的数据流并把它分成一帧一帧的压缩编码数据。
- AVCodecParser用于解析输入的数据流并把它分成一帧一帧的压缩编码数据。
- ffmpeg解析
- ffmpeg解析-----解析文件格式
- ffmpeg tutorial2 解析
- ffmpeg init_opts()解析
- ffmpeg parse_options函数解析
- FFMPEG编译参数解析
- TS流解析 ffmpeg
- ffmpeg之packet_queue_put解析
- FFMpeg之 Mpeg2TS解析
- FFmpeg数据结构:AVPacket解析
- ffmpeg: 解析SDP
- FFmpeg部分函数解析
- 设计模式之中介者模式
- 记安卓中倒计时代码
- java Web 文件断点续传
- 你是如何看待5月12号爆发的在各高校电脑勒索比特币的病毒WannaCry?
- 信息安全工程师 学习笔记(二十二)
- FFMPEG--裸码流解析AVCodecParser
- java项目在Linux下目录错误问题
- 编程思想之多线程与多进程(4):C++ 中的多线程
- 剑指offer 12. 打印1到最大的n位数
- 微擎上传图片附带demo
- 1029. 旧键盘(20) PAT
- 牛顿法、雅克比矩阵、海森矩阵
- 配置linux网络环境 设置静态ip
- 信息安全工程师 学习笔记(二十三)