FFMPEG -- How to add one new CODEC

FFMPEG --  how to add a new codec

#################################

avcodec.h --> add a new CODEC_ID

allcodecs.c --> register_decoder(SKY,sky)

skydec.c --> AVCodec {int, decode,close}


=========================================

==The following the forwarding information from wiki

http://wiki.multimedia.cx/index.php?title=FFmpeg_codec_howto&oldid=7347

=========================================


FFmpeg codec HOWTO

Revision as of 01:05, 18 March 2007; view current revision
←Older revision | Newer revision→

This page is meant as an introduction to the internal codec API in FFmpeg. It will also show how the codecs are connected with the demuxers. This is by no means a complete guide but enough to understand how to add a codec to FFmpeg. Cook is used as an example throughout. Contents [hide]
1 libavcodec/avcodec.h
2 libavcodec/cook.c
3 libavcodec/avcodec.h
4 libavcodec/allcodecs.c
5 libavformat/rm.c
6 libavcodec/cook.c Init
7 libavcodec/cook.c Close
8 libavcodec/cook.c Decode
9 The Glue codec template

libavcodec/avcodec.h

The first thing to look at is the AVCodec struct.
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;

Here we can see that we have some elements to name the codec, what type it is (audio/video), the supported pixel formats and some function pointers for init/encode/decode and close. Now lets see how it is used.
libavcodec/cook.c

If we look in this file at the bottom we can see this code:
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,
};

First we get an AVCodec struct named cook_decoder. And then we set the variables of cook_decoder. Note that we only set the variables that are needed. Currently there is no encoder so we don't set any. If we now look at the id variable we can see that CODEC_ID_COOK isn't defined in libavcodec/cook.c. It is declared in avcodec.h.
libavcodec/avcodec.h

Here we will find the CodecID enumeration.
enum CodecID {
...
CODEC_ID_GSM,
CODEC_ID_QDM2,
CODEC_ID_COOK,
CODEC_ID_TRUESPEECH,
CODEC_ID_TTA,
...
};

CODEC_ID_COOK is there in the list. This is the list of all supported codecs in FFmpeg, the list is fixed and used internally to id every codec. Changing the order would break binary compatibility.

This is all enough to declare a codec. Now we must register them for internal use also. This is done at runtime.
libavcodec/allcodecs.c

In this file we have the avcodec_register_all() function, it has entries like this for all codecs.
...
REGISTER_DECODER(COOK, cook);
...

This macro expands to a register_avcodec() call which registers a codec for internal use. Note that register_avcodec() will only be called when CONFIG_COOK_DECODER is defined. This allows to not compile the decoder code for a specific codec. But where is it defined? This is extracted by configure with this command line:
sed -n 's/^[^#]*DEC.*, *\(.*\)).*/\1_decoder/p' libavcodec/allcodecs.c

So adding a REGISTER_DECODER(NEW, new) entry in allcodecs.c and reconfigure is enough to add the needed define. One more thing to note is that cook.c isn't included in allcodecs.c so the symbol cook_decoder can't be found. Thus it has to be declared somewhere, that happens in avcodec.h and it is declared as an external symbol.
extern AVCodec cook_decoder;

Now we have everything to hookup a codec now we will see how the codec. For this we look into libavformat.
libavformat/rm.c

If we think of an imaginary rm file that ffmpeg is about to process, the first thing that happens is that it is identified as a rm file. It is passed on to the rm demuxer (rm.c). The rm demuxer looks through the file and finds out that it is a cook file.
...
} else if (!strcmp(buf, "cook")) {
st->codec->codec_id = CODEC_ID_COOK;
...

Now ffmpeg knows what codec to init and where to send the payload from the container. So back to cook.c and the initialization process.
libavcodec/cook.c Init

After ffmpeg knows what codec to use, it calls the declared initialization function pointer declared in the codecs AVCodec struct. In cook.c it is called cook_decode_init. Here we setup as much as we can before we start decoding. The following things should be handled in the init, vlc table initialization, table generation, memory allocation and extradata parsing.
libavcodec/cook.c Close

The cook_decode_close function is the codec clean-up call. All memory, vlc tables, etc. should be freed here.
libavcodec/cook.c Decode

In cook.c the name of the decode call is cook_decode_frame.
static int cook_decode_frame(AVCodecContext *avctx,
void *data, int *data_size,
uint8_t *buf, int buf_size) {
...

The function has 5 arguments:
avctx is a pointer to a AVCodecContext
data is the pointer to the outbuffer
data_size is a variable that should be set to the outbuffer size in bytes
buf is the pointer to the inbuffer
buf_size is the size of the inbuffer

The decode function shall return the amount of bytes consumed from the inbuffer.


That's how it works without too much detail.


The Glue codec template

The imaginary Glue audio codec will serve as a base to exhibit bitstream reading, vlc decoding and other things. The code is purely fictional and is sometimes written purely for the sake of example. No attempt is made to prevent invalid data manipulation.

The Glue codec follows.
/* First we include some default includes */
#include <math.h>
#include <stddef.h>
#include <stdio.h>

/* 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;
}

/* 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,
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值