[FFmpeg-devel] [PATCH] ALAC Encoder
Ramiro Polla
ramiro.polla
Sun Aug 17 06:38:38 CEST 2008
On Sat, Aug 16, 2008 at 11:35 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
> On Sun, Aug 17, 2008 at 04:14:43AM +0530, Jai Menon wrote:
>> Hi,
>>
>> The attached ALAC encoder was written as part of GSoC and mentored by Justin
>> Ruggles. I'm posting it for inclusion into FFmpeg-svn.
> [...]
>> Index: libavcodec/alacenc.c
>> ===================================================================
>> --- libavcodec/alacenc.c (revision 0)
>> +++ libavcodec/alacenc.c (revision 0)
>> @@ -0,0 +1,459 @@
>> +/**
>> + * ALAC audio encoder
>> + * Copyright (c) 2008 Jaikrishnan Menon <realityman at gmx.net>
>> + *
>> + * This file is part of FFmpeg.
>> + *
>> + * FFmpeg is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * FFmpeg is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with FFmpeg; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> + */
>> +
>> +#include "avcodec.h"
>> +#include "bitstream.h"
>> +#include "dsputil.h"
>> +#include "lpc.h"
>> +
>> +#define DEFAULT_FRAME_SIZE 4096
>> +#define DEFAULT_SAMPLE_SIZE 16
>> +#define MAX_CHANNELS 8
>> +#define ALAC_EXTRADATA_SIZE 36
>> +#define ALAC_FRAME_HEADER_SIZE 55
>> +#define ALAC_FRAME_FOOTER_SIZE 3
>> +
>> +#define ALAC_ESCAPE_CODE 0x1FF
>> +#define ALAC_MAX_LPC_ORDER 30
>
> ok
[...]
> [...]
>> + int interlacing_shift;
>> + int interlacing_leftweight;
>> + PutBitContext pbctx;
>
> ok (pb is more common than pbctx but this is nitpicking, pbctx is ok if you
> prefer, the same is true for dspctx)
>
>
> [...]
>
>> + DSPContext dspctx;
>> + AVCodecContext *avctx;
>> +} AlacEncodeContext;
>
> ok
[...]
> [...]
>> +static void encode_scalar(AlacEncodeContext *s, int x, int k, int write_sample_size)
>> +{
>> + int divisor, q, r;
>> +
>> + k = FFMIN(k, s->rc.k_modifier);
>> + divisor = (1<<k) - 1;
>> + q = x / divisor;
>> + r = x % divisor;
>> +
>> + if(q > 8) {
>> + // write escape code and sample value directly
>> + put_bits(&s->pbctx, 9, ALAC_ESCAPE_CODE);
>> + put_bits(&s->pbctx, write_sample_size, x);
>> + } else {
>> + if(q)
>> + put_bits(&s->pbctx, q, (1<<q) - 1);
>> + put_bits(&s->pbctx, 1, 0);
>> +
>> + if(k != 1) {
>> + if(r > 0)
>> + put_bits(&s->pbctx, k, r+1);
>> + else
>> + put_bits(&s->pbctx, k-1, 0);
>> + }
>> + }
>> +}
>
> ok
>
>
>> +
>> +static void write_frame_header(AlacEncodeContext *s, int is_verbatim)
>> +{
>> + put_bits(&s->pbctx, 3, s->channels-1); // No. of channels -1
>> + put_bits(&s->pbctx, 16, 0); // Seems to be zero
>> + put_bits(&s->pbctx, 1, 1); // Sample count is in the header
>> + put_bits(&s->pbctx, 2, 0); // FIXME: Wasted bytes field
>> + put_bits(&s->pbctx, 1, is_verbatim); // Audio block is verbatim
>> + put_bits(&s->pbctx, 32, s->avctx->frame_size); // No. of samples in the frame
>> +}
>
> ok
[...]
> [...]
>> +static void write_compressed_frame(AlacEncodeContext *s)
>> +{
>> + int i, j;
>> +
>> + /* only simple mid/side decorrelation supported as of now */
>> + alac_stereo_decorrelation(s);
>> + put_bits(&s->pbctx, 8, s->interlacing_shift);
>> + put_bits(&s->pbctx, 8, s->interlacing_leftweight);
>> +
>> + for(i=0;i<s->channels;i++) {
>> +
>> + calc_predictor_params(s, i);
>> +
>> + put_bits(&s->pbctx, 4, 0); // prediction type : currently only type 0 has been RE'd
>> + put_bits(&s->pbctx, 4, s->lpc[i].lpc_quant);
>> +
>> + put_bits(&s->pbctx, 3, s->rc.rice_modifier);
>> + put_bits(&s->pbctx, 5, s->lpc[i].lpc_order);
>> + // predictor coeff. table
>> + for(j=0;j<s->lpc[i].lpc_order;j++) {
>> + put_sbits(&s->pbctx, 16, s->lpc[i].lpc_coeff[j]);
>> + }
>> + }
>> +
>> + // apply lpc and entropy coding to audio samples
>> +
>> + for(i=0;i<s->channels;i++) {
>> + alac_linear_predictor(s, i);
>> + alac_entropy_coder(s);
>> + }
>> +}
>
> ok
>
>
>> +static av_cold int alac_encode_init(AVCodecContext *avctx)
>> +{
>> + AlacEncodeContext *s = avctx->priv_data;
>> + uint8_t *alac_extradata = av_mallocz(ALAC_EXTRADATA_SIZE+1);
>> +
>> + avctx->frame_size = DEFAULT_FRAME_SIZE;
>> + avctx->bits_per_sample = DEFAULT_SAMPLE_SIZE;
>> + s->channels = avctx->channels;
>> + s->samplerate = avctx->sample_rate;
>> +
>> + if(avctx->sample_fmt != SAMPLE_FMT_S16) {
>> + av_log(avctx, AV_LOG_ERROR, "only pcm_s16 input samples are supported\n");
>> + return -1;
>> + }
>> +
>> + // Set default compression level
>> + if(avctx->compression_level == FF_COMPRESSION_DEFAULT)
>> + s->compression_level = 1;
>> + else
>> + s->compression_level = av_clip(avctx->compression_level, 0, 1);
>> +
>> + // Initialize default Rice parameters
>> + s->rc.history_mult = 40;
>> + s->rc.initial_history = 10;
>> + s->rc.k_modifier = 14;
>> + s->rc.rice_modifier = 4;
>> +
>> + s->max_coded_frame_size = (ALAC_FRAME_HEADER_SIZE + ALAC_FRAME_FOOTER_SIZE +
>> + avctx->frame_size*s->channels*avctx->bits_per_sample)>>3;
>> +
>> + s->write_sample_size = avctx->bits_per_sample + s->channels - 1; // FIXME: consider wasted_bytes
>> +
>> + AV_WB32(alac_extradata, ALAC_EXTRADATA_SIZE);
>> + AV_WB32(alac_extradata+4, MKBETAG('a','l','a','c'));
>> + AV_WB32(alac_extradata+12, avctx->frame_size);
>> + AV_WB8 (alac_extradata+17, avctx->bits_per_sample);
>> + AV_WB8 (alac_extradata+21, s->channels);
>> + AV_WB32(alac_extradata+24, s->max_coded_frame_size);
>> + AV_WB32(alac_extradata+28, s->samplerate*s->channels*avctx->bits_per_sample); // average bitrate
>> + AV_WB32(alac_extradata+32, s->samplerate);
>> +
>> + // Set relevant extradata fields
>> + if(s->compression_level > 0) {
>> + AV_WB8(alac_extradata+18, s->rc.history_mult);
>> + AV_WB8(alac_extradata+19, s->rc.initial_history);
>> + AV_WB8(alac_extradata+20, s->rc.k_modifier);
>> + }
>> +
>> + avctx->extradata = alac_extradata;
>> + avctx->extradata_size = ALAC_EXTRADATA_SIZE;
>> +
>> + avctx->coded_frame = avcodec_alloc_frame();
>> + avctx->coded_frame->key_frame = 1;
>> +
>> + s->avctx = avctx;
>> + dsputil_init(&s->dspctx, avctx);
>> +
>> + allocate_sample_buffers(s);
>> +
>> + return 0;
>> +}
>
> ok
[...]
>> +static av_cold int alac_encode_close(AVCodecContext *avctx)
>> +{
>> + AlacEncodeContext *s = avctx->priv_data;
>> +
>> + av_freep(&avctx->extradata);
>> + avctx->extradata_size = 0;
>> + av_freep(&avctx->coded_frame);
>> + free_sample_buffers(s);
>> + return 0;
>> +}
>> +
>> +AVCodec alac_encoder = {
>> + "alac",
>> + CODEC_TYPE_AUDIO,
>> + CODEC_ID_ALAC,
>> + sizeof(AlacEncodeContext),
>> + alac_encode_init,
>> + alac_encode_frame,
>> + alac_encode_close,
>> + .capabilities = CODEC_CAP_SMALL_LAST_FRAME,
>> + .long_name = "ALAC (Apple Lossless Audio Codec)",
>> +};
>
> ok
Applied ok'd parts.
More information about the ffmpeg-devel
mailing list