[FFmpeg-devel] [PATCH] MLP Encoder

Michael Niedermayer michaelni
Thu Aug 14 19:38:17 CEST 2008


On Thu, Aug 14, 2008 at 02:08:45AM -0300, Ramiro Polla wrote:
> Hello,
> 
> Attached is the MLP encoder written as part of the Google Summer of
> Code project and mentored by Justin Ruggles.
> 
> Things that are not quite complete:
> - 24-bit support. I'm waiting to see what will become of
> SAMPLE_FMT_S24, and the code might need a few changes. But mostly it
> works;
> - The filters... The filtering code is there and it works, but finding
> good coefficients is not. The FIR code from flacenc.c can be plugged
> in there quite easily, but it takes more bits to encode the
> coefficients than the raw data. It might be because of the small frame
> size (40 samples @ 44100kHz). If the frame size was raised to
> something like 256 samples, the compression would be much better, but
> the RE work shows that the bitstream doesn't allow this. Also my
> attempts with IIR filters weren't successful.
> 
> Things that are awfully suboptimal:
> - The search for the best offset for the codebooks. If just one offset
> (the average) is taken into account and no search is done, encoding is
> 30% faster and the resulting filesize is 0.5% bigger. At one point I
> thought taking the median (instead of the average) of all the samples
> would compress better (more values close to 0), but it took longer to
> calculate and would have highly inaccurate offsets, having to search
> even more.
> 
> Things that have not been implemented:
> - The lossless matrix. I don't know what to do of it. So there is no
> channel decorrelation.
> - More than 2 channels. This shouldn't be too hard, I just didn't put
> it high on my priorities.
> 
> Things that can be reused from existing code:
> - A pending patch for END_OF_STREAM in mlp.h.
> - More structs can be reused from mlpdec.c. I would prefer to split
> Substr into DecodingParams and RestartHeader (like the encoder does),
> and move that to mlp.h. I'll send a patch about this depending on the
> review.
> - The noise code can be reused if the noise generation functions are
> cleaned up to use shared structs or more generic parameters. This code
> is still not being needed by the encoder though, since it does no
> rematrixing.
> 
> There's also another patch pending to simplify quant_step_size in mlpdec.c.
> 
> Example of file sizes and compression using sample "luckynight.mlp":
> decoded wav: 10668844
> original mlp: 7899056  25.9%
> encoded  mlp: 8563354  19.7%
> 
> Besides this, the bitstream is very robust. You can trash it at will
> and the decoder will play as much as possible, resuming lossless
> playback usually in less than 70ms (for 44100kHz, with 40 samples per
> frame and 16 frames per major sync).
> 
> Please review.
[...]


> /*
>  * MLP encoder
>  * Copyright (c) 2008 Ramiro Polla <ramiro at lisha.ufsc.br>
>  *
>  * 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 "libavutil/crc.h"
> #include "mlp.h"
> 
> #define MAJOR_HEADER_INTERVAL 16

ok (and yes please commit the stuff between ok and the previous non '>')


> 
> typedef struct {
>     //! The index of the first channel coded in this substream.
>     uint8_t         min_channel;
>     //! The index of the last channel coded in this substream.
>     uint8_t         max_channel;
>     //! The number of channels input into the rematrix stage.
>     uint8_t         max_matrix_channel;
> 
>     //! The left shift applied to random noise in 0x31ea substreams.
>     uint8_t         noise_shift;
>     //! The current seed value for the pseudorandom noise generator(s).
>     uint32_t        noisegen_seed;
> 
>     //! Set if the substream contains extra info to check the size of VLC blocks.
>     int             data_check_present;
> 
>     //! Running XOR of all output samples.
>     int32_t         lossless_check_data;
> } RestartHeader;

please place comments to the right of fields or leave a space before each
comment and the previous unrelated field


> 
> typedef struct {
>     //! number of PCM samples in current audio block
>     uint16_t        blocksize;

i do not think this needs to be uint16


[...]
> #define BITS_16         0x0
> #define BITS_20         0x1
> #define BITS_24         0x2

enum


> 
> /** Returns the coded sample_rate for MLP. */
> static int mlp_sample_rate(int sample_rate)
> {
>     switch (sample_rate) {
>     case 44100 << 0: return 0x8 + 0;
>     case 44100 << 1: return 0x8 + 1;
>     case 44100 << 2: return 0x8 + 2;
>     case 48000 << 0: return 0x0 + 0;
>     case 48000 << 1: return 0x0 + 1;
>     case 48000 << 2: return 0x0 + 2;
>     default:
>         return -1;
>     }
> }

ok


> 
> /** Writes a major sync header to the bitstream. */
> static void write_major_sync(MLPEncodeContext *ctx, uint8_t *buf, int buf_size)
> {
>     PutBitContext pb;
> 
>     init_put_bits(&pb, buf, buf_size);
> 
>     put_bits(&pb, 24, SYNC_MAJOR       );
>     put_bits(&pb,  8, SYNC_MLP         );

ok


>     put_bits(&pb,  4, ctx->sample_fmt  );
>     put_bits(&pb,  4, ctx->sample_fmt  );

>     put_bits(&pb,  4, ctx->sample_rate );

>     put_bits(&pb,  4, ctx->sample_rate );

as it is not the sample rate but some kind of sample_rate_code it should be
named accordingly


>     put_bits(&pb, 11, 0                );

and that is what?


>     put_bits(&pb,  5, ctx->mlp_channels);
> 
>     /* These values seem to be constant for all MLP samples tested. */
>     put_bits(&pb, 16, 0xb752);
>     put_bits(&pb, 16, 0x4000);
>     put_bits(&pb, 16, 0x0000);
> 
>     put_bits(&pb,  1, 1); /* This value is 1 in all MLP samples tested.
>                            * I suppose it would be 0 only when no filters
>                            * or codebooks are used. */

ok


>     put_bits(&pb, 15, 0); /* TODO peak_bitrate: most MLP samples tested encode
>                            * a value that evaluates peak_bitrate to 9600000 or
>                            * a little bit less. */


>     put_bits(&pb,  4, 1); /* TODO Support more num_substreams. */

ok, we dont need substreams anytime soon IMHO


> 
>     put_bits(&pb,  4, 0x1       ); /* TODO These values have something */
>     put_bits(&pb, 16, 0x054c    ); /* to do with the sample rate       */
>     put_bits(&pb,  8, ctx->mlp_channels2);

>     put_bits(&pb, 32, 0x00008080); /* These values seem */
>     put_bits(&pb,  8, 0x00      ); /* to be constants   */

likely not but ok to commit


>     put_bits(&pb,  8, ctx->mlp_channels3); /* TODO Finish understanding this field. */

and i just wanted to ask what mlp_channels2 and mlp_channels3 mean :/


> 
>     flush_put_bits(&pb);
> 
>     AV_WL16(buf+26, ff_mlp_checksum16(buf, 26));
> }

ok


> 
> /** Writes a restart header to the bitstream. Damaged streams can start being
>  *  decoded losslessly again after such a header and the subsequent decoding
>  *  params header.
>  */
> static void write_restart_header(MLPEncodeContext *ctx,
>                                  PutBitContext *pb, int substr)
> {
>     RestartHeader *rh = &ctx->restart_header[substr];
>     int32_t lossless_check = xor_32_to_8(rh->lossless_check_data);
>     unsigned int start_count = put_bits_count(pb);
>     PutBitContext tmpb;
>     uint8_t checksum;
>     unsigned int ch;
> 
>     put_bits(pb, 14, 0x31ea                ); /* TODO 0x31eb */
>     put_bits(pb, 16, 0                     ); /* TODO I don't know what this is. Ask Ian. */
>     put_bits(pb,  4, rh->min_channel       );
>     put_bits(pb,  4, rh->max_channel       );
>     put_bits(pb,  4, rh->max_matrix_channel);
>     put_bits(pb,  4, rh->noise_shift       );
>     put_bits(pb, 23, rh->noisegen_seed     );
>     put_bits(pb, 19, 0                     ); /* TODO What the hell is this? */
>     put_bits(pb,  1, rh->data_check_present);
>     put_bits(pb,  8, lossless_check        );
>     put_bits(pb, 16, 0                     ); /* this is zero =) */
> 
>     for (ch = 0; ch <= rh->max_matrix_channel; ch++)
>         put_bits(pb, 6, ch);
> 
>     /* data must be flushed for the checksum to be right. */
>     tmpb = *pb;
>     flush_put_bits(&tmpb);
> 
>     checksum = ff_mlp_restart_checksum(pb->buf, put_bits_count(pb) - start_count);
> 
>     put_bits(pb,  8, checksum);
> }

ok


> /** Encodes the third type of channel information for the sync headers. */
> static uint8_t code_channels3(int channels)
> {
>     switch (channels) {
>     case 1: return 0x1f;
>     case 2: return 0x1b;
>     case 6: return 0x00;
>     default:
>         return 0x1b;
>     }
> }

i assume you dont know anything about the values? if so its ok otherwise
please document it
though name the function more sanely, get_channel3_code() for example


> 
> static av_cold int mlp_encode_init(AVCodecContext *avctx)
> {
>     MLPEncodeContext *ctx = avctx->priv_data;
>     unsigned int quant_step_size;
>     unsigned int substr;
> 
>     ctx->avctx = avctx;
> 
>     ctx->sample_rate = mlp_sample_rate(avctx->sample_rate);
>     if (ctx->sample_rate < 0) {
>         av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate %d. Supported "
>                             "sample rates are 44100, 88200, 176400, 48000, "
>                             "96000, and 192000.\n", avctx->sample_rate);
>         return -1;
>     }
> 
>     /* TODO support more channels. */
>     if (avctx->channels > 2) {
>         av_log(avctx, AV_LOG_ERROR,
>                "Only mono and stereo are supported at the moment.\n");
>         return -1;
>     }
> 
>     switch (avctx->sample_fmt) {
>     case SAMPLE_FMT_S16: ctx->sample_fmt = BITS_16; quant_step_size = 8; break;
>     /* TODO 20 bits: */
>     case SAMPLE_FMT_S24: ctx->sample_fmt = BITS_24; quant_step_size = 0; break;
>     default:
>         av_log(avctx, AV_LOG_ERROR, "Sample format not supported. "
>                "Only 16- and 24-bit samples are supported.\n");
>         return -1;
>     }
> 
>     avctx->frame_size               = 40 << (ctx->sample_rate & 0x7);
>     avctx->coded_frame              = avcodec_alloc_frame();
>     avctx->coded_frame->key_frame   = 1;
> 
>     ff_mlp_init_crc();
>     ff_mlp_init_crc2D(NULL);
> 
>     /* TODO mlp_channels is more complex, but for now
>      * we only accept mono and stereo. */
>     ctx->mlp_channels   = avctx->channels - 1;
>     ctx->mlp_channels2  = (1 << avctx->channels) - 1;
>     ctx->mlp_channels3  = code_channels3(avctx->channels);
>     ctx->num_substreams = 1;
> 
>     for (substr = 0; substr < ctx->num_substreams; substr++) {
>         DecodingParams *dp = &ctx->decoding_params[substr];
>         RestartHeader  *rh = &ctx->restart_header [substr];
>         uint8_t param_presence_flags = 0;
>         unsigned int channel;
> 
>         rh->min_channel        = 0;
>         rh->max_channel        = avctx->channels - 1;
>         rh->max_matrix_channel = 1;
> 
>         dp->blocksize          = avctx->frame_size;
> 
>         for (channel = 0; channel <= rh->max_channel; channel++) {
>             ChannelParams *cp = &ctx->channel_params[channel];
> 
>             dp->quant_step_size[channel] = quant_step_size;
>             cp->huff_lsbs                = 24;
>         }
> 
>         param_presence_flags |= PARAM_BLOCKSIZE;
> /*      param_presence_flags |= PARAM_MATRIX; */
> /*      param_presence_flags |= PARAM_OUTSHIFT; */
>         param_presence_flags |= PARAM_QUANTSTEP;
>         param_presence_flags |= PARAM_FIR;
> /*      param_presence_flags |= PARAM_IIR; */
>         param_presence_flags |= PARAM_HUFFOFFSET;
> 
>         dp->param_presence_flags = param_presence_flags;
>     }
> 
>     return 0;
> }

ok


> 
> /** Calculates the smallest number of bits it takes to encode a given signed
>  *  value in two's complement.
>  */
> static int inline number_sbits(int number)
> {
>     int bits = 0;
> 
>     if      (number > 0)
>         for (bits = 31; bits && !(number & (1<<(bits-1))); bits--);
>     else if (number < 0)
>         for (bits = 31; bits &&  (number & (1<<(bits-1))); bits--);

isnt something with av_log2(FFABS()) faster?


> 
>     return bits + 1;
> }

> 
> /** Determines the smallest number of bits needed to encode the filter
>  *  coefficients, and if it's possible to right-shift their values without
>  *  losing any precision.
>  */
> static void code_filter_coeffs(MLPEncodeContext *ctx,
>                                unsigned int channel, unsigned int filter,
>                                int *pcoeff_shift, int *pcoeff_bits)
> {
>     FilterParams *fp = &ctx->channel_params[channel].filter_params[filter];

hmm, why not pass FilterParams as argument?


>     int min = INT_MAX, max = INT_MIN;
>     int bits, shift;
>     int or = 0;
>     int order;
> 
>     for (order = 0; order < fp->order; order++) {
>         int coeff = fp->coeff[order];
> 


>         if (coeff < min)
>             min = coeff;
>         if (coeff > max)
>             max = coeff;
> 
>         or |= coeff;
>     }
> 
>     bits = FFMAX(number_sbits(min), number_sbits(max));

max= FFMAX(max, FFABS(coeff))

that way you also do not need a signed "bits counter" ...


[...]
> /** Inputs data from the samples passed by lavc into the context, shifts them
>  *  appropriately depending on the bit-depth, and calculates the
>  *  lossless_check_data that will be written to the restart header.
>  */
> static void input_data_internal(MLPEncodeContext *ctx, const uint8_t *samples,
>                                 int32_t *lossless_check_data, int is24)
> {
>     const int32_t *samples_32 = (const int32_t *) samples;
>     const int16_t *samples_16 = (const int16_t *) samples;
>     unsigned int substr;
> 
>     for (substr = 0; substr < ctx->num_substreams; substr++) {
>         DecodingParams *dp = &ctx->decoding_params[substr];
>         RestartHeader  *rh = &ctx->restart_header [substr];
>         int32_t temp_lossless_check_data = 0;
>         unsigned int channel;
>         int i;
> 
>         for (i = 0; i < dp->blocksize; i++) {
>             for (channel = 0; channel <= rh->max_channel; channel++) {
>                 int32_t sample;
> 
>                 if (is24) sample = *samples_32++;
>                 else      sample = *samples_16++;
> 
>                 sample <<= dp->quant_step_size[channel];
> 
>                 temp_lossless_check_data ^= (sample & 0x00ffffff) << channel;
>                 ctx->sample_buffer[i][channel] = sample;
>             }
>         }
> 
>         lossless_check_data[substr] = temp_lossless_check_data;
>     }
> }
> 
> /** Wrapper function for inputting data in two different bit-depths. */
> static void input_data(MLPEncodeContext *ctx, void *samples,
>                        int32_t *lossless_check_data)
> {
>     if (ctx->avctx->sample_fmt == SAMPLE_FMT_S24)
>         input_data_internal(ctx, samples, lossless_check_data, 1);
>     else
>         input_data_internal(ctx, samples, lossless_check_data, 0);
> }

ok though i would prefer if no copying where needed but it may be cleaner
as is due to 16/32 support



> 
> /** Determines the best filter parameters for the given data and writes the
>  *  necessary information to the context.

>  *  TODO Add actual filter predictors!

yes


>  */
> static void set_filter_params(MLPEncodeContext *ctx,
>                               unsigned int channel, unsigned int filter,
>                               int restart_frame)
> {
>     FilterParams *fp = &ctx->channel_params[channel].filter_params[filter];
> 
>     /* Restart frames must not depend on filter state from previous frames. */
>     if (restart_frame) {
>         fp->order    =  0;
>         return;
>     }
> 
>     if (filter == FIR) {
>         fp->order    =  1;
>         fp->shift    =  0;
>         fp->coeff[0] =  1;
>     } else { /* IIR */
>         fp->order    =  0;
>         fp->shift    =  0;
>     }
> }


> 
> #define INT24_MAX ((1 << 23) - 1)
> #define INT24_MIN (~INT24_MAX)
> 
> #define MSB_MASK(bits)  (-1u << bits)
> 
> /* TODO What substream to use for applying filters to channel? */
> 


> /** Applies the filter to the current samples, and saves the residual back
>  *  into the samples buffer. If the filter is too bad and overflows the
>  *  maximum amount of bits allowed (24), the samples buffer is left as is and
>  *  the function returns -1.
>  */

i do not belive overflow is possible
without checking the code too carefull i suspect you got the wrap around wrong
somewhere
remember (a+b) & MASK = c & MASKis the same as a & MASK = (c-b) & MASK


[...]
> 
> /** Min and max values that can be encoded with each codebook. The values for
>  *  the third codebook take into account the fact that the sign shift for this
>  *  codebook is outside the coded value, so it has one more bit of precision.
>  *  It should actually be -7 -> 7, shifted down by 0.5.
>  */
> static int codebook_extremes[3][2] = {
>     {-9, 8}, {-8, 7}, {-15, 14},
> };

hmm, isnt the 3rd wrong now?


> 
> typedef struct BestOffset {
>     int16_t offset;
>     int bitcount;
>     int lsb_bits;
> } BestOffset;
> 

> /** Determines the least amount of bits needed to encode the samples using no
>  *  codebooks.
>  */
> static void no_codebook_bits(MLPEncodeContext *ctx, unsigned int substr,
>                              unsigned int channel,
>                              int32_t min, int32_t max,
>                              BestOffset *bo)
> {
>     ChannelParams  *cp = &ctx->channel_params[channel];
>     DecodingParams *dp = &ctx->decoding_params[substr];
>     int16_t offset;
>     int32_t unsign;
>     uint32_t diff;
>     int lsb_bits;
> 
>     /* Set offset inside huffoffset's boundaries by adjusting extremes
>      * so that more bits are used thus shifting the offset. */

>     if (min < HUFF_OFFSET_MIN)
>         max = FFMAX(max, HUFF_OFFSET_MIN + HUFF_OFFSET_MIN - min + 1);

2*HUFF_OFFSET_MIN


>     if (max > HUFF_OFFSET_MAX)
>         min = FFMIN(min, HUFF_OFFSET_MAX + HUFF_OFFSET_MAX - max - 1);

ditto


[...]
> /** Writes the residuals to the bitstream. That is, the vlc codes from the
>  *  codebooks (if any is used), and then the residual.
>  */
> static void write_block_data(MLPEncodeContext *ctx, PutBitContext *pb,
>                              unsigned int substr)
> {
>     DecodingParams *dp = &ctx->decoding_params[substr];
>     RestartHeader  *rh = &ctx->restart_header [substr];
>     int32_t sign_huff_offset[MAX_CHANNELS];
>     int codebook            [MAX_CHANNELS];
>     int lsb_bits            [MAX_CHANNELS];
>     unsigned int i, ch;
> 
>     for (ch = rh->min_channel; ch <= rh->max_channel; ch++) {
>         ChannelParams *cp = &ctx->channel_params[ch];
>         int sign_shift;
> 
>         lsb_bits        [ch] = cp->huff_lsbs - dp->quant_step_size[ch];

>         codebook        [ch] = cp->codebook  - 1;

why -1 ?


>         sign_huff_offset[ch] = cp->huff_offset;
> 
>         sign_shift = lsb_bits[ch] - 1;
> 
>         if (codebook[ch] >= 0) {
>             sign_huff_offset[ch] -= 7 << lsb_bits[ch];
>             sign_shift += 2 - codebook[ch];
>         }
> 
>         /* Unsign if needed. */
>         if (sign_shift >= 0)
>             sign_huff_offset[ch] -= 1 << sign_shift;
>     }
> 
>     for (i = 0; i < dp->blocksize; i++) {
>         for (ch = rh->min_channel; ch <= rh->max_channel; ch++) {
>             int32_t sample = ctx->sample_buffer[i][ch] >> dp->quant_step_size[ch];
> 
>             sample -= sign_huff_offset[ch];
> 

>             if (codebook[ch] >= 0) {
>                 int8_t vlc = sample >> lsb_bits[ch];
>                 put_bits(pb, ff_mlp_huffman_tables[codebook[ch]][vlc][1],
>                              ff_mlp_huffman_tables[codebook[ch]][vlc][0]);

why int8_t and not int?


>             }
> 
>             put_sbits(pb, lsb_bits[ch], sample);

are you assuming here that ths masks the high bits off? you should not


[...]

> 
> /** Writes the access unit and substream headers to the bitstream. */
> static void write_frame_headers(MLPEncodeContext *ctx, uint8_t *frame_header,
>                                 uint8_t *substream_headers, unsigned int length,
>                                 uint16_t substream_data_len[MAX_SUBSTREAMS])
> {
>     uint16_t access_unit_header = 0;
>     uint16_t parity_nibble = 0;
>     unsigned int substr;
> 
>     parity_nibble  = ctx->timestamp;
>     parity_nibble ^= length;
> 
>     for (substr = 0; substr < ctx->num_substreams; substr++) {
>         uint16_t substr_hdr = 0;
> 
>         substr_hdr |= (0 << 15); /* extraword */
>         substr_hdr |= (0 << 14); /* ??? */
>         substr_hdr |= (1 << 13); /* checkdata */
>         substr_hdr |= (0 << 12); /* ??? */
>         substr_hdr |= (substream_data_len[substr] / 2) & 0x0FFF;
> 
>         AV_WB16(substream_headers, substr_hdr);
> 
>         parity_nibble ^= *substream_headers++;
>         parity_nibble ^= *substream_headers++;
>     }
> 
>     parity_nibble ^= parity_nibble >> 8;
>     parity_nibble ^= parity_nibble >> 4;
>     parity_nibble &= 0xF;
> 
>     access_unit_header |= (parity_nibble ^ 0xF) << 12;
>     access_unit_header |= length & 0xFFF;
> 
>     AV_WB16(frame_header  , access_unit_header);
>     AV_WB16(frame_header+2, ctx->timestamp    );
> }

ok


[...]
> static int mlp_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size,
>                             void *data)
> {
>     DecodingParams decoding_params[MAX_SUBSTREAMS];
>     uint16_t substream_data_len[MAX_SUBSTREAMS];
>     int32_t lossless_check_data[MAX_SUBSTREAMS];
>     ChannelParams channel_params[MAX_CHANNELS];
>     MLPEncodeContext *ctx = avctx->priv_data;
>     uint8_t *buf2, *buf1, *buf0 = buf;
>     int total_length;
>     unsigned int substr;
>     int restart_frame;
> 
>     if (avctx->frame_size > MAX_BLOCKSIZE) {
>         av_log(avctx, AV_LOG_ERROR, "Invalid frame size (%d > %d)\n",
>                avctx->frame_size, MAX_BLOCKSIZE);
>         return -1;
>     }
> 
>     memcpy(decoding_params, ctx->decoding_params, sizeof(decoding_params));
>     memcpy(channel_params, ctx->channel_params, sizeof(channel_params));
> 
>     if (buf_size < 4)
>         return -1;
> 
>     /* Frame header will be written at the end. */
>     buf      += 4;
>     buf_size -= 4;
> 

>     restart_frame = !(avctx->frame_number & (MAJOR_HEADER_INTERVAL - 1));

gop_size could be used here


[...]
> static av_cold int mlp_encode_close(AVCodecContext *avctx)
> {
>     av_freep(&avctx->coded_frame);
> 
>     return 0;
> }
> 
> AVCodec mlp_encoder = {
>     "mlp",
>     CODEC_TYPE_AUDIO,
>     CODEC_ID_MLP,
>     sizeof(MLPEncodeContext),
>     mlp_encode_init,
>     mlp_encode_frame,
>     mlp_encode_close,
>     .capabilities = CODEC_CAP_SMALL_LAST_FRAME,
>     .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_S24,SAMPLE_FMT_NONE},
>     .long_name = NULL_IF_CONFIG_SMALL("Meridian Lossless Packing"),
> };

ok


[...]
> Index: libavformat/raw.c
> ===================================================================
> --- libavformat/raw.c	(revision 14733)
> +++ libavformat/raw.c	(working copy)
> @@ -596,6 +596,21 @@
>  };
>  #endif
>  
> +#ifdef CONFIG_MUXERS
> +AVOutputFormat mlp_muxer = {
> +    "mlp",
> +    NULL_IF_CONFIG_SMALL("raw MLP"),
> +    NULL,
> +    "mlp",
> +    0,
> +    CODEC_ID_MLP,
> +    CODEC_ID_NONE,
> +    NULL,
> +    raw_write_packet,
> +    .flags= AVFMT_NOTIMESTAMPS,
> +};
> +#endif //CONFIG_MUXERS
> +
>  AVInputFormat flac_demuxer = {
>      "flac",
>      NULL_IF_CONFIG_SMALL("raw FLAC"),

ok


[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I count him braver who overcomes his desires than him who conquers his
enemies for the hardest victory is over self. -- Aristotle
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20080814/ad78f9e6/attachment.pgp>



More information about the ffmpeg-devel mailing list