1. 简介
FFmpeg是一个集录制、转换、音/视频编码解码功能为一体的完整的开源解决方案。FFmpeg的
开发是基于Linux操作系统,但是可以在大多数操作系统中编译和使用。FFmpeg支持MPEG、
DivX、MPEG4、AC3、DV、FLV等40多种编码,AVI、MPEG、OGG、Matroska、ASF等90多种解码.
TCPMP, VLC, MPlayer等开源播放器都用到了FFmpeg。
FFmpeg主目录下主要有libavcodec、libavformat和libavutil等子目录。其中libavcodec用
于存放各个encode/decode模块,libavformat用于存放muxer/demuxer模块,libavutil用于
存放内存操作等辅助性模块。
以flash movie的flv文件格式为例, muxer/demuxer的flvenc.c和flvdec.c文件在
libavformat目录下,encode/decode的mpegvideo.c和h263de.c在libavcodec目录下。
2. muxer/demuxer与encoder/decoder定义与初始化
muxer/demuxer和encoder/decoder在FFmpeg中的实现代码里,有许多相同的地方,而二者最
大的差别是muxer 和demuxer分别是不同的结构AVOutputFormat与AVInputFormat,而encoder
和decoder都是用的AVCodec 结构。
muxer/demuxer和encoder/decoder在FFmpeg中相同的地方有:
二者都是在main()开始的av_register_all()函数内初始化的
二者都是以链表的形式保存在全局变量中的
muxer/demuxer是分别保存在全局变量AVOutputFormat *first_oformat与
AVInputFormat *first_iformat中的。
encoder/decoder都是保存在全局变量AVCodec *first_avcodec中的。
二者都用函数指针的方式作为开放的公共接口
demuxer开放的接口有:
int (*read_probe)(AVProbeData *);
int (*read_header)(struct AVFormatContext *, AVFormatParameters *ap);
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
int (*read_close)(struct AVFormatContext *);
int (*read_seek)(struct AVFormatContext *, int stream_index, int64_t timestamp, int flags);
muxer开放的接口有:
int (*write_header)(struct AVFormatContext *);
int (*write_packet)(struct AVFormatContext *, AVPacket *pkt);
int (*write_trailer)(struct AVFormatContext *);
encoder/decoder的接口是一样的,只不过二者分别只实现encoder和decoder函数:
int (*init)(AVCodecContext *);
int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data);
int (*close)(AVCodecContext *);
int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, uint8_t *buf, int buf_size);
仍以flv文件为例来说明muxer/demuxer的初始化。
在libavformat\allformats.c文件的av_register_all(void)函数中,通过执行
REGISTER_MUXDEMUX(FLV, flv);
将支持flv 格式的flv_muxer与flv_demuxer变量分别注册到全局变量first_oformat与first_iformat链表的最后位置。
其中flv_muxer在libavformat\flvenc.c中定义如下:
AVOutputFormat flv_muxer = {
"flv",
"flv format",
"video/x-flv",
"flv",
sizeof(FLVContext),
#ifdef CONFIG_LIBMP3LAME
CODEC_ID_MP3,
#else // CONFIG_LIBMP3LAME
CODEC_ID_NONE,
CODEC_ID_FLV1,
flv_write_header,
flv_write_packet,
flv_write_trailer,
.codec_tag= (const AVCodecTag*[]){flv_video_codec_ids, flv_audio_codec_ids, 0},
}
AVOutputFormat结构的定义如下:
typedef struct AVOutputFormat {
const char *name;
const char *long_name;
const char *mime_type;
const char *extensions; /**< comma separated filename extensions */
/** size of private data so that it can be allocated in the wrapper */
int priv_data_size;
/* output support */
enum CodecID audio_codec; /**< default audio codec */
enum CodecID video_codec; /**< default video codec */
int (*write_header)(struct AVFormatContext *);
int (*write_packet)(struct AVFormatContext *, AVPacket *pkt);
int (*write_trailer)(struct AVFormatContext *);
/** can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_GLOBALHEADER */
int flags;
/** currently only used to set pixel format if not YUV420P */
int (*set_parameters)(struct AVFormatContext *, AVFormatParameters *);
int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, AVPacket *in, int flush);
/**
*list of supported codec_id-codec_tag pairs,ordered by "better choice first"
* the arrays are all CODEC_ID_NONE terminated
*/
const struct AVCodecTag **codec_tag;
/* private fields */
struct AVOutputFormat *next;
} AVOutputFormat;
由AVOutputFormat结构的定义可知,flv_muxer变量初始化的第一、二个成员分别为该muxer
的名称与长名称,第三、第四个成员为所对应MIMIE Type和后缀名,第五个成员是所对应的
私有结构的大小,第六、第七个成员为所对应的音频编码和视频编码类型ID,接下来就是三
个重要的接口函数,该 muxer的功能也就是通过调用这三个接口实现的。
flv_demuxer在libavformat\flvdec.c中定义如下, 与flv_muxer类似,在这儿主要也是设置
了5个接口函数,其中flv_probe接口用途是测试传入的数据段是否是符合当前文件格式,这
个接口在匹配当前demuxer时会用到。
AVInputFormat flv_demuxer = {
"flv",
"flv format",
0,
flv_probe,
flv_read_header,
flv_read_packet,
flv_read_close,
flv_read_seek,
.extensions = "flv",
.value = CODEC_ID_FLV1,
};
在上述av_register_all(void)函数中通过执行libavcodec\allcodecs.c文件里的
avcodec_register_all(void)函数来初始化全部的encoder/decoder。
因为不是每种编码方式都支持encode和decode,所以有以下三种注册方式:
#define REGISTER_ENCODER(X,x) \
if(ENABLE_##X##_ENCODER) register_avcodec(&x##_encoder)
#define REGISTER_DECODER(X,x) \
if(ENABLE_##X##_DECODER) register_avcodec(&x##_decoder)
#define REGISTER_ENCDEC(X,x) REGISTER_ENCODER(X,x); REGISTER_DECODER(X,x)
如支持flv的flv_encoder和flv_decoder变量就分别是在libavcodec\mpegvideo.c和
libavcodec\h263de.c中创建的。
3. 当前muxer/demuxer的匹配
在FFmpeg的文件转换过程中,首先要做的就是根据传入文件和传出文件的后缀名[FIXME]匹配
合适的demuxer和muxer。匹配上的demuxer和muxer都保存在如下所示,定义在ffmpeg.c里的
全局变量file_iformat和file_oformat中:
static AVInputFormat *file_iformat;
static AVOutputFormat *file_oformat;
3.1 demuxer匹配
在libavformat\utils.c中的static AVInputFormat *av_probe_input_format2(
AVProbeData *pd, int is_opened, int *score_max)函数用途是根据传入的probe data数据
,依次调用每个demuxer的read_probe接口,来进行该demuxer是否和传入的文件内容匹配的
判断。其调用顺序如下:
void parse_options(int argc, char **argv, const OptionDef *options,
void (* parse_arg_function)(const char *));
static void opt_input_file(const char *filename)
int av_open_input_file(…… )
AVInputFormat *av_probe_input_format(AVProbeData *pd,
int is_opened)
static AVInputFormat *av_probe_input_format2(……)
opt_input_file函数是在保存在const OptionDef options[]数组中,用于
void parse_options(int argc, char **argv, const OptionDef *options)中解析argv里的
“-i” 参数,也就是输入文件名时调用的。
3.2 muxer匹配
与demuxer的匹配不同,muxer的匹配是调用guess_format函数,根据main() 函数的argv里的
输出文件后缀名来进行的。
void parse_options(int argc, char **argv, const OptionDef *options,
void (* parse_arg_function)(const char *));
void parse_arg_file(const char *filename)
static void opt_output_file(const char *filename)
AVOutputFormat *guess_format(const char *short_name,
const char *filename,
const char *mime_type)
3.3 当前encoder/decoder的匹配
在main()函数中除了解析传入参数并初始化demuxer与muxer的parse_options( )函数以外,
其他的功能都是在av_encode( )函数里完成的。
在libavcodec\utils.c中有如下二个函数:
AVCodec *avcodec_find_encoder(enum CodecID id)
AVCodec *avcodec_find_decoder(enum CodecID id)
他们的功能就是根据传入的CodecID,找到匹配的encoder和decoder。
在av_encode( )函数的开头,首先初始化各个AVInputStream和AVOutputStream,然后分别调
用上述二个函数,并将匹配上的encoder与decoder分别保存在:
AVInputStream->AVStream *st->AVCodecContext *codec->struct AVCodec *codec与
AVOutputStream->AVStream *st->AVCodecContext *codec->struct AVCodec *codec变量。
4. 其他主要数据结构
4.1 AVFormatContext
AVFormatContext是FFMpeg格式转换过程中实现输入和输出功能、保存相关数据的主要结构。
每一个输入和输出文件,都在如下定义的指针数组全局变量中有对应的实体。
static AVFormatContext *output_files[MAX_FILES];
static AVFormatContext *input_files[MAX_FILES];
对于输入和输出,因为共用的是同一个结构体,所以需要分别对该结构中如下定义的iformat
或oformat成员赋值。
struct AVInputFormat *iformat;
struct AVOutputFormat *oformat;
对一个AVFormatContext来说,这二个成员不能同时有值,即一个AVFormatContext不能同时
含有demuxer和muxer。在main( )函数开头的parse_options( )函数中找到了匹配的muxer和
demuxer之后,根据传入的argv参数,初始化每个输入和输出的AVFormatContext结构,
文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008727/134072.html
并保
存在相应的output_files和input_files指针数组中。在av_encode( )函数中,output_files
和input_files是作为函数参数传入后,在其他地方就没有用到了。
4.2 AVCodecContext
保存AVCodec指针和与codec相关数据,如video的width、height,audio的sample rate等。
AVCodecContext中的codec_type,codec_id二个变量对于encoder/decoder的匹配来说,最为
重要。
enum CodecType codec_type; /* see CODEC_TYPE_xxx */
enum CodecID codec_id; /* see CODEC_ID_xxx */
如上所示,codec_type保存的是CODEC_TYPE_VIDEO,CODEC_TYPE_AUDIO等媒体类型,
codec_id保存的是CODEC_ID_FLV1,CODEC_ID_VP6F等编码方式。
以支持flv格式为例,在前述的av_open_input_file(…… ) 函数中,匹配到正确的
AVInputFormat demuxer后,通过av_open_input_stream( )函数中调用AVInputFormat的
read_header接口来执行flvdec.c中的flv_read_header( )函数。在flv_read_header( )函数
内,根据文件头中的数据,创建相应的视频或音频AVStream,并设置AVStream中
AVCodecContext的正确的codec_type值。codec_id值是在解码过程中flv_read_packet( )函
数执行时根据每一个packet头中的数据来设置的。
4.3 AVStream
AVStream结构保存与数据流相关的编解码器,数据段等信息。比较重要的有如下二个成员:
AVCodecContext *codec; /**< codec context */
void *priv_data;
其中codec指针保存的就是上节所述的encoder或decoder结构。priv_data指针保存的是和具
体编解码流相关的数据,如下代码所示,在ASF的解码过程中,priv_data保存的就是
ASFStream结构的数据。
AVStream *st;
ASFStream *asf_st;
… …
st->priv_data = asf_st;
4.4 AVInputStream/ AVOutputStream
根据输入和输出流的不同,前述的AVStream结构都是封装在AVInputStream和AVOutputStream
结构中,在av_encode( )函数中使用。AVInputStream中还保存的有与时间有关的信息。
AVOutputStream中还保存有与音视频同步等相关的信息。
4.5 AVPacket
AVPacket结构定义如下,其是用于保存读取的packet数据。
typedef struct AVPacket {
int64_t pts; ///< presentation time stamp in time_base units
int64_t dts; ///< decompression time stamp in time_base units
uint8_t *data;
int size;
int stream_index;
int flags;
int duration; ///< presentation duration in time_base units (0 if not available)
void (*destruct)(struct AVPacket *);
void *priv;
int64_t pos; ///< byte position in stream, -1 if unknown
} AVPacket;
在av_encode()函数中,调用AVInputFormat的
(*read_packet)(struct AVFormatContext *, AVPacket *pkt)接口,读取输入文件的一帧数
据保存在当前输入AVFormatContext的AVPacket成员中。
5. av_encode函数主要流程
av_encode()函数是FFMpeg中最重要的函数,编解码和输出等大部分功能都在此函数完成,
因此有必要详细描述一下这个函数的主要流程。
1).input streams initializing
2).output streams initializing
3).encoders and decoders initializing
4).set meta data information from input file if required.
5).write output files header
6).loop of handling each frame
a.read frame from input file:
b.decode frame data
c.encode new frame data
d.write new frame to output file
7).write output files trailer
.close each encoder and decoder
文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008727/134072_2.html
分享到:
相关推荐
ffmpeg
在本项目中,我们将关注如何使用FFmpeg将MP3文件转换为PCM(脉冲编码调制)文件格式。PCM是数字音频的基础格式,它以原始的二进制数据形式存储音频信号,便于进行进一步的处理或分析。 首先,MP3是一种有损压缩的...
要实现“C#使用ffmpeg将wav转mp3”,首先确保你已经在你的开发环境中安装了ffmpeg,并将其添加到系统环境变量Path中,这样可以通过命令行直接调用。在C#代码中,我们可以使用System.Diagnostics.Process类来执行外部...
使用ffmpeg转换flac文件为mp3,重命名中文文件后使用ffmpeg保持高保真比率转换flac文件
ffmpeg进行视频旋转
在本话题中,我们将深入探讨如何使用FFmpeg将PCM(脉冲编码调制)音频数据转换为AAC(高级音频编码)格式。 PCM是未经压缩的原始音频数据,通常占用大量存储空间,而AAC是一种高效的有损音频编码标准,能够在保持较...
在C++中,使用FFmpeg库进行图像转换通常涉及以下步骤: 1. **初始化FFmpeg上下文**:调用`avformat_alloc_context`创建一个`AVFormatContext`对象,它是FFmpeg的核心结构,包含了媒体文件的全局信息。 2. **加载...
FFmpeg是一款强大的开源多媒体处理工具,它包含了音...综上所述,FFmpeg使用手册(FFmpeg官方文档中文翻译)提供了全面的FFmpeg使用指南,无论是初学者还是经验丰富的开发者,都能从中受益,快速掌握FFmpeg的各项功能。
对于图像旋转,FFmpeg通常使用libavfilter模块中的`transpose`滤镜来完成。`transpose`滤镜可以执行四种基本的旋转操作:0度(无旋转)、90度、180度和270度。 在FFmpeg命令行中,我们可以使用以下命令来旋转一个...
在本教程中,我们将深入探讨如何使用FFmpeg将AVI视频格式转换为MP4格式。 1. **FFmpeg简介** FFmpeg是一个命令行工具,其核心是libavcodec(编解码库)、libavformat(容器处理库)和libavfilter(滤镜系统)。它...
Java FFmpeg视频转换是一个在Java开发中常见的任务,它涉及到使用FFmpeg库通过Java代码来处理多媒体文件,如视频的编码、解码、格式转换等。FFmpeg是一个强大的跨平台命令行工具,提供了丰富的功能,包括视频转码、...
在这个场景中,我们的目标是使用FFmpeg库将AAC(Advanced Audio Coding)格式的音频文件转换为WAV(Waveform Audio File Format)格式。这是一个常见的需求,因为WAV是一种通用且无损的音频格式,适用于各种音频处理...
在本文中,我们将深入探讨如何使用Java程序调用FFmpeg执行视频文件格式转换,特别是将非FFmpeg原生支持的格式转换为FLV格式。FFmpeg是一个强大的多媒体处理工具,支持多种视频、音频格式的编码、解码和转换。在这个...
在ASP.NET应用中集成FFmpeg,可以实现服务器端的视频处理功能,例如本示例中的MP4转M3U8。 M3U8(Media Playlist)是一种基于UTF-8的文本格式,用于定义多媒体播放列表,尤其是在HTTP Live Streaming (HLS) 中广泛...
在本文中,我们将深入探讨如何使用 FFmpeg 在 Java 环境中进行 AMR 转 MP3 的操作,以及如何在 Windows 和 Linux 系统上执行这个过程。 首先,AMR(Adaptive Multi-Rate)是一种广泛用于语音编码的压缩格式,常用于...
在实际使用中,FFmpeg支持许多音频和视频格式,包括但不限于WAV、AAC、FLAC、OGG等,并且可以自定义转换参数,如比特率、采样率等,以适应不同的质量和存储需求。此外,FFmpeg还提供了丰富的滤镜和功能,如音频混合...
在这个"视频无损旋转ffmpeg任意角度可批量操作"的压缩包中,我们可以看到几个关键点,包括如何使用 FFmpeg 进行视频的无损旋转、批量处理以及相关脚本的使用。 1. **视频无损旋转**:通常,视频旋转可能会导致质量...
5. **安装**:使用`sudo make install`将编译好的FFmpeg二进制文件安装到系统路径中。 这个压缩包提供的脚本`ffmpeg_by_lenovo_ccc.sh`很可能是自动执行上述步骤的脚本,使得用户无需手动完成每一步。脚本可能会...
这个“FFmpeg使用中文手册”是为用户提供详细指导的宝贵资源,旨在帮助用户理解和有效地运用FFmpeg。 首先,FFmpeg的核心组成部分包括以下几个模块: 1. **FFmpeg命令行工具**:这是用户最直接接触的部分,通过...
在本项目中,我们将重点讨论如何使用FFmpeg库将JPEG图像转换为不同类型的YUV格式数据。 首先,我们需要了解JPEG和YUV的基本概念。JPEG是一种广泛使用的有损图像压缩标准,而YUV是视频编码中常见的颜色空间,尤其在...