FFmpeg codec HOWTO(http://wiki.multimedia.cx/index.php?title=FFmpeg_codec_HOWTO)
来源:互联网 发布:json对象合并 编辑:程序博客网 时间:2024/04/29 17:07
FFmpeg codec HOWTO
这篇文字意在对FFmpeg内置编解码库的API做一个入门级介绍。其中也将告诉大家编解码库是如何同demuxers(初步学习,认为是FFmpeg的接口之一)链接的。这无意于提供一个完整的指导,但是对于了解如何将一个编解码库加入到FFmpeg是足够的。
registering the codec
libavcodec/avcodec.h
首先看AVCodec结构体。
typedef struct AVCodec { const char *name; enum CodecType type; enum CodecID id; int priv_data_size; 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); int capabilities; struct AVCodec *next; void (*flush)(AVCodecContext *); const AVRational *supported_framerates; ///array of supported framerates, or NULL if any, array is terminated by {0,0} const enum PixelFormat *pix_fmts; ///array of supported pixel formats, or NULL if unknown, array is terminanted by -1} AVCodec;
上边结构体里存在一些元素用于命名编解码器,比如它的类型(视频还是音频),所支持的像素格式以及一些init/encode/decode/close功能函数的指针。
libavcodec/cook.c
当我们查看文件的末端,我们将看到以下代码:
AVCodec cook_decoder ={ .name = "cook", .type = CODEC_TYPE_AUDIO, .id = CODEC_ID_COOK, .priv_data_size = sizeof(COOKContext), .init = cook_decode_init, .close = cook_decode_close, .decode = cook_decode_frame,};
首先我们得到了一个名为cook_decoder的AVCodec对象。然后我们设置cook_decoder的变量,但只是设置了必须设定的变量。目前没有一个编码器于是我们不需要设置。我们考虑其中的id变量,CODEC_ID_COOK不再libavcodec/cook.c中定义,而是在avcodec.h。
libavcodec/avcodec.h
我们会看到CodecID的枚举变量
enum CodecID {...CODEC_ID_GSM,CODEC_ID_QDM2,CODEC_ID_COOK,CODEC_ID_TRUESPEECH,CODEC_ID_TTA,...};
CODEC_ID_COOK位列其中。列表中是所有在FFmpeg中支持的编解码器,这份列表被修正过而且也内置使用在每一份编解码器的id。更改上述顺序会打破二进制兼容性。
目前对于申明一个编解码器已经足够。现在我们需要注册它们用于内置使用。
libavcodec/allcodecs.c
该文件中存在avcodec_register_all()函数,在所有的编解码器中,它都这样被调用。
... REGISTER_DECODER(COOK, cook);...
这个宏延伸到一个avcodec_register_all()调用,该调用注册一个编解码器为内置使用。考虑到register_avcodec()仅在CONFIG_COOK_DECODER被定义时才被调用。这允许可以为一段特定的编码器而不必编译解码器。但是它在哪里定义的?这是由以下命令行抽取配置的:
sed -n 's/^[^#]*DEC.*, *\(.*\)).*/\1_decoder/p' libavcodec/allcodecs.c
所以添加REGISTER_DECODER(NEW, new)的入口到allcodecs.c和重复配置对于添加需要的定义是足够的。现在我们已经有了连接一个编解码器的所有准备。
libavcodec/Makefile
这个文件中我们定义了一个编解码器所基于的对象。比如,cook使用fft和mdct代码,于是它就基于mdct.o、fft.o、cook.o的对象文件。
...OBJS-$(CONFIG_COOK_DECODER) += cook.o mdct.o fft.o...
Codec code
libavcodec/cook.c Init
在确立了编解码器的用途之后,ffmpeg调用已在AVCodec结构体中申明好的初始化函数指针。在cook.c中它被称作cook_decode_init。在我们开始解码之前,尽可能多的初始化,接下来的几项将在init, vlc表的初始化、表的更新、存储的分配以及extradata的parsing中得到处理。
libavcodec/cook.c Close
这个cook_decode_close函数是编解码器clean-up的调用。所有的存储空间、vlc表格等都会再此被释放。
libavcodec/cook.c Decode
在cook.c中解码调用函数名cook_decode_frame。
static int cook_decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size) {...
这个函数有五个参数:
- avctx是AVCodecContext的指针
- data是output buffer的指针
- data_size 是个需要为output buffer size 用bytes设置的变量(通常是解码样例的数量*包含的管道数*每个样例的字节大小)
- buf是input buffer的指针
- buf_size是input buffer的字节大小
The Glue codec template
虚构的Glue视频编解码器将作为展示比特流读取、vlc解码等的基础。这段代码纯粹虚构的并纯粹有时为样例而写的。没有尝试着抑制无效数据的操作。
Glue编解码器如下:
/* The following includes have the bitstream reader, various dsp functions and the various defaults */#define ALT_BITSTREAM_READER#include "avcodec.h"#include "bitstream.h"#include "dsputil.h"/* This includes the tables needed for the Glue codec template */#include "gluedata.h"/* Here we declare the struct used for the codec private data */typedef struct { GetBitContext gb; FFTContext fft_ctx; VLC vlc_table; MDCTContext mdct_ctx; float* sample_buffer;} GLUEContext;/* The init function */static int glue_decode_init(AVCodecContext *avctx){ GLUEContext *q = avctx->priv_data; /* This imaginary codec uses one fft, one mdct and one vlc table. */ ff_mdct_init(&q->mdct_ctx, 10, 1); // 2^10 == size of mdct, 1 == inverse mdct ff_fft_init(&q->fft_ctx, 9, 1); // 2^9 == size of fft, 0 == inverse fft init_vlc (&q->vlc_table, 9, 24, vlctable_huffbits, 1, 1, vlctable_huffcodes, 2, 2, 0); // look in bitstream.h for the meaning of the arguments /* We also need to allocate a sample buffer */ q->sample_buffer = av_mallocz(sizeof(float)*1024); // here we used av_mallocz instead of av_malloc // av_mallocz memsets the whole buffer to 0 /* Check if the allocation was successful */ if(q->sample_buffer == NULL) return -1; /* return 0 for a successful init, -1 for failure */ return 0;}/* This is the main decode function */static int glue_decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size){ GLUEContext *q = avctx->priv_data; int16_t *outbuffer = data; /* We know what the arguments for this function are from above now we just have to decode this imaginary codec, the made up bitstream format is as follows: 12 bits representing the amount of samples 1 bit fft or mdct coded coeffs, 0 for fft/1 for mdct read 13 bits representing the amount of vlc coded fft data coeffs read 10 bits representing the amount of vlc coded mdct data coeffs (...bits representing the coeffs...) 5 bits of dummy data that should be ignored 32 bits the hex value 0x12345678, used for integrity check */ /* Declare the needed variables */ int samples, coeffs, i, fft; float mdct_tmp[1024]; /* Now we init the bitstream reader, we start at the beginning of the inbuffer */ init_get_bits(&q->gb, buf, buf_size*8); //the buf_size is in bytes but we need bits /* Now we take 12 bits to get the amount of samples the current frame has */ samples = get_bits(&q->gb, 12); /* Now we check if we have fft or mdct coeffs */ fft = get_bits1(&q->gb); if (fft) { //fft coeffs, get how many coeffs = get_bits(&q->gb, 13); } else { //mdct coeffs, get how many coeffs = get_bits(&q->gb, 10); } /* Now decode the vlc coded coeffs to the sample_buffer */ for (i=0 ; i<coeffs ; i++) q->sample_buffer[i] = get_vlc2(&q->gb, q->vlc_table.table, vlc_table.bits, 3); //read about the arguments in bitstream.h /* Now we need to transform the coeffs to samples */ if (fft) { //The fft is done inplace ff_fft_permute(&q->fft_ctx, (FFTComplex *) q->sample_buffer); ff_fft_calc(&q->fft_ctx, (FFTComplex *) q->sample_buffer); } else { //And we pretend that the mdct is also inplace ff_imdct_calc(&q->mdct_ctx, q->sample_buffer, q->sample_buffer, mdct_tmp); } /* To make it easy the stream can only be 16 bits mono, so let's convert it to that */ for (i=0 ; i<samples ; i++) outbuffer[i] = (int16_t)q->sample_buffer[i]; /* Report how many samples we got */ *data_size = samples; /* Skip the dummy data bits */ skip_bits(&q->gb, 5); /* Check if the buffer was consumed ok */ if (get_bits(&q->gb,32) != 0x12345678) { av_log(avctx,AV_LOG_ERROR,"Stream error, integrity check failed!\n"); return -1; } /* The decision between erroring out or not in case of unexpected data should be made so that the output quality is maximized. This means that if undamaged data is assumed then unused/resereved values should lead to warnings but not failure. (assumption of slightly non compliant file) OTOH if possibly damaged data is assumed and it is assumed that the original did contain specific values in reserved/unused fields then finding unexpected values should trigger error concealment code and the decoder/demuxer should attempt to resync. The decision between these 2 should be made by using AVCodecContext.error_recognition unless its a clear case where only one of the 2 makes sense. */ /* Return the amount of bytes consumed if everything was ok */ return *data_size*sizeof(int16_t);}/* the uninit function, here we just do the inverse of the init */ static int glue_decode_close(AVCodecContext *avctx){ GLUEContext *q = avctx->priv_data; /* Free allocated memory buffer */ av_free(q->sample_buffer); /* Free the fft transform */ ff_fft_end(&q->fft_ctx); /* Free the mdct transform */ ff_mdct_end(&q->mdct_ctx); /* Free the vlc table */ free_vlc(&q->vlc_table); /* Return 0 if everything is ok, -1 if not */ return 0;}AVCodec glue_decoder ={ .name = "glue", .type = CODEC_TYPE_AUDIO, .id = CODEC_ID_GLUE, .priv_data_size = sizeof(GLUEContext), .init = glue_decode_init, .close = glue_decode_close, .decode = glue_decode_frame,};
- FFmpeg codec HOWTO(http://wiki.multimedia.cx/index.php?title=FFmpeg_codec_HOWTO)
- FFmpeg(http://wiki.multimedia.cx/index.php?title=FFmpeg)
- FFmpeg codec HOWTO
- FFmpeg codec howto and FFmpeg demuxer howto
- 翻译http://kb.mozillazine.org/index.php?title=Extension_development
- linux命令详解:http://wiki.linux-ren.org/index.php/
- HOWTO add new codec to ffmpeg
- Service-Oriented Architecture[FROM:http://wiki.ittoolbox.com/index.php/Service-Oriented_Architecture]
- 稀疏自编码http://deeplearning.stanford.edu/wiki/index.php/Exercise:Sparse_Autoencoder#Results
- 关于robocup3d在linux上的安装//详细信息http://simspark.sourceforge.net/wiki/index.php/Installation_on_Linux#Opti
- FreeBSD操作技巧 (来自于 http://wiki.scivoid.net/index.cgi/FreebsdTips )
- http://localhost/myphpsite/index.php
- http://appxcode.com/index.php
- FFmpeg参数说明(转自MultiMedia之旅)
- http://www.qiantu.org/index.php?p=403#comments
- Android Multimedia框架总结(十一)CodeC部分之AwesomePlayer到OMX服务
- Android Multimedia框架总结(十二)CodeC部分之OMXCodec与OMX事件回调流程
- http://appxcode.com/index.php?con=index&act=category&cid=5
- 报文解析
- 重新演绎动态编译类,打造灵活多变的系统
- Windows界面编程第一篇 位图背景与位图画刷
- zoj 1048 求平均数 python
- windows server2008使用hyper安装虚拟机~~
- FFmpeg codec HOWTO(http://wiki.multimedia.cx/index.php?title=FFmpeg_codec_HOWTO)
- Windows界面编程第二篇 半透明窗体
- hibernate generator class的内置实现名
- C++ Primer Chapter 10 关联容器之map
- Windows界面编程第三篇 异形窗体 普通版
- CentOS5.5 添加一块新硬盘,分区并设置系统启动自动挂载的方法
- netbeans在mac上使用svn提交数据 报错处理
- 生活随笔
- Matlab 深度优先搜索求解迷宫问题