FFmpeg学习1:视频解码
在视频解码前,先了解以下几个基本的概念:
- 编解码器(CODEC):能够进行视频和音频压缩(CO)与解压缩(DEC),是视频编解码的核心部分。
- 容器/多媒体文件(Container/File):没有了解视频的编解码之前,总是错误的认为平常下载的电影的文件的后缀(avi,mkv,rmvb等)就是视频的编码方式。事实上,刚才提到的几种文件的后缀
并不是视频的编码方式,只是其封装的方式。一个视频文件通常有视频数据、音频数据以及字幕等,封装的格式决定这些数据在文件中是如何的存放的,封装在一起音频、视频等数据组成的多媒体文件,也可以叫做容器(其中包含了视音频数据)。所以,只看多媒体文件的后缀名是难以知道视音频的编码方式的。 - 流数据 Stream,例如视频流(Video Stream),音频流(Audio Stream)。流中的数据元素被称为帧Frame。
FFmpeg视频解码过程
通常来说,FFmpeg的视频解码过程有以下几个步骤:
- 注册所支持的所有的文件(容器)格式及其对应的CODEC
av_register_all() - 打开文件
avformat_open_input() - 从文件中提取流信息
avformat_find_stream_info() - 在多个数据流中找到视频流 video stream(类型为
MEDIA_TYPE_VIDEO) - 查找video stream 相对应的解码器
avcodec_find_decoder - 打开解码器
avcodec_open2() - 为解码帧分配内存
av_frame_alloc() - 从流中读取读取数据到Packet中
av_read_frame() - 对video 帧进行解码,调用
avcodec_decode_video2()
解码过程的具体说明
1. 注册
av_register_all该函数注册支持的所有的文件格式(容器)及其对应的CODEC,只需要调用一次,故一般放在main函数中。也可以注册某个特定的容器格式,但通常来说不需要这么做。
2. 打开文件
avformat_open_input该函数读取文件的头信息,并将其信息保存到AVFormatContext结构体中。其调用如下
AVFormatContext* pFormatCtx = nullptr;
avformat_open_input(&pFormatCtx, filenName, nullptr, nullptr)
第一个参数是AVFormatContext结构体的指针,第二个参数为文件路径;第三个参数用来设定输入文件的格式,如果设为null,将自动检测文件格式;第四个参数用来填充AVFormatContext一些字段以及Demuxer的private选项。
AVFormatContext包含有较多的码流信息参数,通常由avformat_open_input创建并填充关键字段。
3. 获取必要的CODEC参数
avformat_open_input通过解析多媒体文件或流的头信息及其他的辅助数据,能够获取到足够多的关于文件、流和CODEC的信息,并将这些信息填充到AVFormatContext结构体中。但任何一种多媒体格式(容器)提供的信息都是有限的,而且不同的多媒体制作软件对头信息的设置也不尽相同,在制作多媒体文件的时候难免会引入一些错误。也就是说,仅仅通过avformat_open_input并不能保证能够获取所需要的信息,所以一般要使用
avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
avformat_find_stream_info主要用来获取必要的CODEC参数,设置到ic->streams[i]->codec。
在解码的过程中,首先要获取到各个stream所对应的CODEC类型和id,CODEC的类型和id是两个枚举值,其定义如下:
enum AVMediaType {
AVMEDIA_TYPE_UNKNOWN = -1,
AVMEDIA_TYPE_VIDEO,
AVMEDIA_TYPE_AUDIO,
AVMEDIA_TYPE_DATA,
AVMEDIA_TYPE_SUBTITLE,
AVMEDIA_TYPE_ATTACHMENT,
AVMEDIA_TYPE_NB
};
enum CodecID {
CODEC_ID_NONE, /* video codecs */
CODEC_ID_MPEG1VIDEO,
CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
CODEC_ID_MPEG2VIDEO_XVMC,
CODEC_ID_H261,
CODEC_ID_H263,
...
}
通常,如果多媒体文件具有完整而正确的头信息,通过avformat_open_input即可用获得这两个参数。
4. 打开解码器
经过上面的步骤,已经将文件格式信息读取到了AVFormatContext中,要打开流数据相应的CODEC需要经过下面几个步骤
- 找到视频流 video stream
一个多媒体文件包含有多个原始流,例如 movie.mkv这个多媒体文件可能包含下面的流数据 - 原始流 1 h.264 video
- 原始流 2 aac audio for Chinese
- 原始流 3 aac audio for English
- 原始流 4 Chinese Subtitle
- 原始流 5 English Subtitle
要解码视频,首先要在AVFormatContext包含的多个流中找到CODEC类型为AVMEDIA_TYPE_VIDEO,代码如下:
//查找视频流 video stream
int videoStream = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
}
if (videoStream == -1)
return -1; // 没有找到视频流video stream
结构体AVFormatContext中的streams字段是一个AVStream指针的数组,包含了文件所有流的描述,上述上述代码在该数组中查找CODEC类型为
AVMEDIA_TYPE_VIDEO的流的下标。
- 根据codec_id找到相应的CODEC,并打开
结构体AVCodecContext描述了CODEC上下文,包含了众多CODEC所需要的参数信息。
AVCodecContext* pCodecCtxOrg = nullptr;
AVCodec* pCodec = nullptr;
pCodecCtxOrg = pFormatCtx->streams[videoStream]->codec; // codec context
// 找到video stream的 decoder
pCodec = avcodec_find_decoder(pCodecCtxOrg->codec_id);
// open codec
if (avcodec_open2(pCodecCtxOrg , pCodec, nullptr) < 0)
return -1; // Could open codec
上述代码,首先通过codec_id找到相应的CODEC,然后调用avcodec_open2打开相应的CODEC。
5. 读取数据帧并解码
已经有了相应的解码器,下面的工作就是将数据从流中读出,并解码为没有压缩的原始数据
AVPacket packet;
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == videoStream)
{
int frameFinished = 0;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished)
{
doSomething();
}
}
}
上述代码调用av_read_frame将数据从流中读取数据到packet中,并调用avcodec_decode_video2对读取的数据进行解码。
6. 关闭
需要关闭avformat_open_input打开的输入流,avcodec_open2打开的CODEC
avcodec_close(pCodecCtxOrg);
avformat_close_input(&pFormatCtx);
补充
在配置好FFmpeg的开发环境后,在C++中使用FFmpeg的库函数,会出现解析不出函数的名称链接错误,这是由于FFmpeg库是C语言实现,要在C++调用C函数需要 extern "C"的声明。
extern "C"
{
# include <libavcodec\avcodec.h>
# include <libavformat\avformat.h>
# include <libswscale\swscale.h>
}
哎,博客园的Markdown用着好不方便啊,不知道怎么画流程图....
代码 FFmpeg0.cpp
FFmpeg学习1:视频解码的更多相关文章
- FFmpeg学习5:多线程播放视音频
在前面的学习中,视频和音频的播放是分开进行的.这主要是为了学习的方便,经过一段时间的学习,对FFmpeg的也有了一定的了解,本文就介绍了 如何使用多线程同时播放音频和视频(未实现同步),并对前面的学习 ...
- FFmpeg 学习(五):FFmpeg 编解码 API 分析
在上一篇文章 FFmpeg学习(四):FFmpeg API 介绍与通用 API 分析 中,我们简单的讲解了一下FFmpeg 的API基本概念,并分析了一下通用API,本文我们将分析 FFmpeg 在编 ...
- FFmpeg 学习(七):FFmpeg 学习整理总结
一.FFmpeg 播放视频的基本流程整理 播放流程: video.avi(Container) -> 打开得到 Video_Stream -> 读取Packet -> 解析到 Fra ...
- FFmpeg学习起步 —— 环境搭建
下面是我搭建FFmpeg学习环境的步骤. 一.在Ubuntu下 从http://www.ffmpeg.org/download.html下载最新的FFmpeg版本,我的版本是ffmpeg-2.7.2. ...
- FFMPEG学习----打印视频信息
FFMPEG学习资料少之又少,在此推荐雷神的博客: http://blog.csdn.net/leixiaohua1020 在这里,我们把打印视频里的相关信息作为学习FFMPEG的 Hello Wor ...
- ffmpeg学习笔记-多线程音视频解码
之前的视频解码仍然存在问题,那就是是在主线程中去完成解码的,会造成线程阻塞,这里将其改为多线程解码,使其主线程不被阻塞 前面介绍了音视频的主线程解码,那样会阻塞主线程,在前面学习了多线程以后,就可以对 ...
- FFmpeg学习2:解码数据结构及函数总结
在上一篇文章中,对FFmpeg的视频解码过程做了一个总结.由于才接触FFmpeg,还是挺陌生的,这里就解码过程再做一个总结. 本文的总结分为以下两个部分: 数据读取,主要关注在解码过程中所用到的FFm ...
- FFmpeg学习4:音频格式转换
前段时间,在学习试用FFmpeg播放音频的时候总是有杂音,网上的很多教程是基于之前版本的FFmpeg的,而新的FFmepg3中audio增加了平面(planar)格式,而SDL播放音频是不支持平面格式 ...
- ffmpeg学习笔记
对于每一个刚開始学习的人,刚開始接触ffmpeg时,想必会有三个问题最为关心,即ffmpeg是什么?能干什么?怎么開始学习?本人前段时间開始接触ffmpeg,在刚開始学习过程中.这三个问 ...
随机推荐
- 使用python抓取婚恋网用户数据并用决策树生成自己择偶观
最近在看<机器学习实战>的时候萌生了一个想法,自己去网上爬一些数据按照书上的方法处理一下,不仅可以加深自己对书本的理解,顺便还可以在github拉拉人气.刚好在看决策树这一章,书里面的理论 ...
- [.NET] C# 知识回顾 - Event 事件
C# 知识回顾 - Event 事件 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6060297.html 序 昨天,通过<C# 知识回顾 - ...
- 【HanLP】资料链接汇总
Java中调用HanLP配置 HanLP自然语言处理包开源官方文档 了解HanLP的全部 自然语言处理HanLP 开源自由的汉语言处理包主页 GitHub源码 基于hanLP的中文分词详解-MapRe ...
- 基于window7+caffe实现图像艺术风格转换style-transfer
这个是在去年微博里面非常流行的,在git_hub上的代码是https://github.com/fzliu/style-transfer 比如这是梵高的画 这是你自己的照片 然后你想生成这样 怎么实现 ...
- slf4j中的MDC
slf4j中MDC是什么鬼 slf4j除了trace.debug.info.warn.error这几个日志接口外,还可以配合MDC将数据写入日志.换句话说MDC也是用来记录日志的,但它的使用方式与使用 ...
- 似懂非懂的localStorage和sessionStorage
一.区别 相信很多人都见过这两个关于HTML5的新名词!HTML5种的web storage包含两种存储方式:localStorage和sessionStorage,这两种方式存储的数据不会自动发给服 ...
- [AlwaysOn Availability Groups]健康模型 Part 1——概述
健康模型概述 在成功部署AG之后,跟踪和维护健康状况是很重要的. 1.AG健康模型概述 AG的健康模型是基于策略管理(Policy Based Management PBM)的.如果不熟悉这个特性,可 ...
- μCos-ii学习笔记1_概述
一.μCos-ii _概述 网上关于μCosii的文章多不胜数,本人学习的过程中也参考了很多人的理解和想法,看的是卢有亮老师的<嵌入式实时操作系统-μC/OS原理与实践>(第2版),同时也 ...
- ENode框架Conference案例分析系列之 - 文章索引
ENode框架Conference案例分析系列之 - 业务简介 ENode框架Conference案例分析系列之 - 上下文划分和领域建模 ENode框架Conference案例分析系列之 - 架构设 ...
- 【完全开源】知乎日报UWP版:项目结构说明、关键源代码解释
目录 说明 项目结构 关键代码 演示视频 说明 上一篇博客将源码放出来了,但是并没有做过多的介绍,所以如果自己硬看可能需要花费很长的时间,尤其这些代码并不是自己写的.项目不算复杂但是也不算简单,这篇文 ...