ffmpeg内部分析
来源:互联网 发布:域名和公网ip绑定 编辑:程序博客网 时间:2024/06/06 11:47
没有文档.... 只有自己东看西看,总结点东西。
打开视频:
1.首先是 libavformat/allformats.c 中的av_register_all();
这一步注册库中含有 的所有可用的文件格式和编码器,这样当打开一个文件时,它们才能够自动选择相应的文件格式和编码器。要注意你只需调用一次 av_register_all(),所以,尽可能的在你的初始代码中使用它。如果你愿意,你可以仅仅注册个人的文件格式和编码,不过,通常你不得不这么 做却没有什么原因。
2.打开文件 libavformat/utils.c 中的av_open_input_file函数.
int i = av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL);返回一个int , 不等于0则说明打开失败
传入pFormatCtx指针变量地址,会根据打开的文件来填充FormatContext(只填充头信息),传入时,它必须为NULL;
最 后三个参数描述了文件格式,缓冲区大小(size)和格式参数;我们通过简单地指明NULL或0告诉 libavformat 去自动探测文件格式并且使用默认的缓冲 区大小。
3.取出文件中的流信息 libavformat/utils.c 中的av_find_stream_info函数.
int i = av_find_stream_info(pFormatCtx) ; i<0出错
这一步会用有效的信息把 AVFormatContext 的流域(streams field)填满
4.现在pFormatCtx已经充满了流信息,接下来需要找出里面的第一种视频流,
int videoStream = -1;
for( i = 0; i < pFormatCtx->nb_streams; i++ )
{
if(pFormatCtx->streams->codec.codec_type==CODEC_TYPE_VIDEO)
{
videoStream=i;
break;
}
}
如果videoStream不等-1,说明找到了第一种视频流,这个videoStream应该是流的位置 streams[videoStream]
5得到视频流编码上下文的指针:
pCodecCtx=&pFormatCtx->streams[videoStream]->codec;
6.找到真正的解码器.
AVCodec *pCodec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
pCodec == NULL为出错
7.通知解码器我们能够处理截断的bit流--ie,
// bit流帧边界可以在包中
if(pCodec->capabilities & CODEC_CAP_TRUNCATED)
{
pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
}
8. 打开解码器 libavcodec/utils.c 中的avcodec_open函数
int i = avcodec_open(pCodecCtx, pCodec); i<0说明打开失败
9.给视频帧分配空间以便存储解码后的图片:
AVFrame *pFrame;
pFrame=avcodec_alloc_frame();
10. 别人封装好的一个函数,它返回下一帧
bool GetNextFrame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx,
int videoStream, AVFrame *pFrame)
{
static AVPacket packet;
static int bytesRemaining=0;
static uint8_t *rawData;
static bool fFirstTime=true;
Int bytesDecoded;
Int frameFinished;
// 我们第一次调用时,将 packet.data 设置为NULL指明它不用释放了
if(fFirstTime)
{
fFirstTime=false;
packet.data=NULL;
}
// 解码直到成功解码完整的一帧
while(true)
{
// 除非解码完毕,否则一直在当前包中工作
while(bytesRemaining > 0)
{
// 解码下一块数据
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame,
&frameFinished, rawData, bytesRemaining);
// 出错了?
if(bytesDecoded < 0)
{
fprintf(stderr, "Error while decoding frame/n");
return false;
}
bytesRemaining-=bytesDecoded;
rawData+=bytesDecoded;
// 我们完成当前帧了吗?接着我们返回
if(frameFinished)
return true;
}
// 读取下一包,跳过所有不属于这个流的包
do
{
// 释放旧的包
if(packet.data!=NULL)
av_free_packet(&packet);
// 读取新的包
if(av_read_packet(pFormatCtx, &packet)<0)
goto loop_exit;
} while(packet.stream_index!=videoStream);
bytesRemaining=packet.size;
rawData=packet.data;
}
loop_exit:
// 解码最后一帧的余下部分
bytesDecoded=avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
rawData, bytesRemaining);
// 释放最后一个包
if(packet.data!=NULL)
av_free_packet(&packet);
return frameFinished!=0;
}
这个函数的好处是,不用理会 两帧之间的边界也可以在包的中间部分 这种情况
接下来我们要做的就是在一个循环中,调用 GetNextFrame () 直到它返回false。
while(GetNextFrame(pFormatCtx, pCodecCtx, videoStream, pFrame))
{
img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
// 处理视频帧(存盘等等)
DoSomethingWithTheImage(pFrameRGB);
}
RGB 图象pFrameRGB (AVFrame *类型)的空间分配如下:
AVFrame *pFrameRGB;
int numBytes;
uint8_t *buffer;
// 分配一个AVFrame 结构的空间
pFrameRGB=avcodec_alloc_frame();
if(pFrameRGB==NULL)
handle_error();
// 确认所需缓冲区大小并且分配缓冲区空间
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
buffer=new uint8_t[numBytes];
// 在pFrameRGB中给图象位面赋予合适的缓冲区
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
清除
好了,我们已经处理了我们的视频,现在需要做的就是清除我们自己的东西:
// 释放 RGB 图象
delete [] buffer;
av_free(pFrameRGB);
// 释放YUV 帧
av_free(pFrame);
// 关闭解码器(codec)
avcodec_close(pCodecCtx);
// 关闭视频文件
av_close_input_file(pFormatCtx);
- ffmpeg内部分析
- FFMPeg代码分析:av_read_frame()函数的内部构造
- FFMPEG分析
- FFmpeg分析
- 输出ffmpeg内部的log
- FFMpeg分析详细分析
- FFMpeg分析详细分析
- FFMpeg分析详细分析
- [FFMPEG-代码分析]ffmpeg.c
- 内部排序算法分析
- Hibernate内部缓存分析
- hibrnate内部缓存分析
- linphone 内部线程分析
- linphone内部原理分析
- linphone 内部线程分析
- 产品的内部分析
- Hibernate内部缓存分析
- linphone 内部线程分析
- JVM OutOfMemoryError
- 程序开发剖解圣经(003)
- CUDA和OpenCL
- Java程序员从笨鸟到菜鸟之(一百零三)java操作office和pdf文件(一)java读取word,excel和pdf文档内容
- .net网站发布-允许更新此预编译站点 及修改发布后内容
- ffmpeg内部分析
- android电源管理简要
- 深入浅出Linux设备驱动之并发控制
- S3C2440 VxWorks移植随笔--CAN总线测试小问题
- 逐个取出jsonArray中的每一项
- 《Getting Started with D3》中文翻译(第一章)
- 基于边缘重组的遗传算法求解TSP问题
- Spring基础xfire报:报 Error initializing XFireServlet.
- 关于文本内容比较