[FFmpeg-devel] AAC decoder round 5
Michael Niedermayer
michaelni
Thu Aug 7 21:17:18 CEST 2008
On Thu, Aug 07, 2008 at 04:04:44PM +0100, Robert Swain wrote:
> 2008/8/6 Michael Niedermayer <michaelni at gmx.at>:
> > On Wed, Aug 06, 2008 at 12:32:32AM +0100, Robert Swain wrote:
> >> $subj
> >>
> >> Best regards,
> >> Rob
> >
> >> Index: Changelog
> >> ===================================================================
> >> --- Changelog (revision 14623)
> >> +++ Changelog (working copy)
> >> @@ -128,6 +128,7 @@
> >> - Motion Pixels MVI demuxer
> >> - removed animated GIF decoder/demuxer
> >> - D-Cinema audio muxer
> >> +- AAC decoder
> >>
> >> version 0.4.9-pre1:
> >>
> >
> > ok
>
> You can ignore/I can not submit the build system and documentation
> changes. I won't commit them until the whole thing has been committed.
You could commit the doc changes :)
>
> > [...]
> >
> >> Index: libavcodec/aactab.c
> >> ===================================================================
> >> --- libavcodec/aactab.c (revision 14625)
> >> +++ libavcodec/aactab.c (working copy)
>
> [...]
>
> >> +DECLARE_ALIGNED(16, float, ff_aac_kbd_long_1024[1024]);
> >> +DECLARE_ALIGNED(16, float, ff_aac_kbd_short_128[128]);
> >> +DECLARE_ALIGNED(16, float, ff_aac_sine_long_1024[1024]);
> >> +DECLARE_ALIGNED(16, float, ff_aac_sine_short_128[128]);
> >> +
> >> +const uint8_t ff_aac_num_swb_1024[] = {
> >> + 41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40
> >> +};
> >> +
> >> +const uint8_t ff_aac_num_swb_128[] = {
> >> + 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15
> >> +};
> >> +
> >> const uint32_t ff_aac_scalefactor_code[121] = {
> >> 0x3ffe8, 0x3ffe6, 0x3ffe7, 0x3ffe5, 0x7fff5, 0x7fff1, 0x7ffed, 0x7fff6,
> >> 0x7ffee, 0x7ffef, 0x7fff0, 0x7fffc, 0x7fffd, 0x7ffff, 0x7fffe, 0x7fff7,
> >
> >
> >> @@ -795,4 +809,90 @@
> >> 4064.0312908, 4074.6805676, 4085.3368071, 4096.0000000,
> >> };
> >>
> >> +/* [ 0, 255] scale factor decoding when using C dsp.float_to_int16
> >> + * [60, 315] scale factor decoding when using SIMD dsp.float_to_int16
> >> + * [45, 300] intensity stereo position decoding mapped in reverse order i.e. 0->300, 1->299, ..., 254->46, 255->45
> >> + */
> >
> > not doxygen compat, no description of what the table actually contains.
>
> Comment quoted above improved. Does your statement apply to all of the
> above or just the comment for pow2sf_tab[]?
i just meant pow2sf_tab but the ff_aac_num_swb_128/1024 could also benefit
from a little doxy, the windows are obvious at least to me so i dont care
if they get a doxy or not.
[...]
> > [...]
> >> +{
> >> + /* Pre-mixed down-mix outputs are not available. */
> >> + newpcs->mono_mixdown_tag = -1;
> >> + newpcs->stereo_mixdown_tag = -1;
> >> +
> >> + if(channels < 1 || channels > 7) {
> >> + av_log(ac->avccontext, AV_LOG_ERROR, "invalid default channel configuration (%d channels)\n",
> >> + channels);
> >> + return -1;
> >> + }
> >> +
> >> + /* default channel configurations:
> >> + *
> >> + * 1ch : front center (mono)
> >> + * 2ch : L + R (stereo)
> >> + * 3ch : front center + L + R
> >> + * 4ch : front center + L + R + back center
> >> + * 5ch : front center + L + R + back stereo
> >> + * 6ch : front center + L + R + back stereo + LFE
> >
> >> + * 7ch : front center + L + R + outer front left + outer front right + back stereo + LFE
> >
> > its still 8, so channels/num_channels is no longer an appropriate name for
> > the vars used as its not 7 channels.
>
> channel_configuration_index?
id prefer channel_config, its shorter
>
> > [...]
> >> @@ -213,6 +830,764 @@
> >> }
> >> }
> >>
> >
> >> +/**
> >> + * Dequantize and scale spectral data; reference: 4.6.3.3.
> >> + *
> >> + * @param icoef array of quantized spectral data
> >> + * @param band_type array of the used band type
> >> + * @param sf array of scalefactors or intensity stereo positions
> >> + * @param coef array of dequantized, scaled spectral data
> >
> > why are the coeffs not dequantized in place, that is coef==icoef ?
>
> icoef[] are integers. coef[] are floats. To be able to use
oops yes, silly me
> ivquant_tab[icoef[]], icoef[] have to be integers don't they?
>
> > [...]
> >> +/**
> >> + * Decode an individual_channel_stream payload; reference: table 4.44.
> >> + *
> >> + * @param common_window Channels have independent [0], or shared [1], Individual Channel Stream information.
> >> + * @param scale_flag scalable [1] or non-scalable [0] AAC (Unused until scalable AAC is implemented.)
> >> + * @return Returns error status. 0 - OK, !0 - error
> >> + */
> >> +static int decode_ics(AACContext * ac, SingleChannelElement * sce, GetBitContext * gb, int common_window, int scale_flag) {
> >> + int icoeffs[1024];
> >> + Pulse pulse;
> >> + TemporalNoiseShaping * tns = &sce->tns;
> >> + IndividualChannelStream * ics = &sce->ics;
> >> + float * out = sce->coeffs;
> >> + int global_gain, pulse_present = 0;
> >> +
> >
> >> + pulse.num_pulse = 0;
> >> + pulse.start = 0;
> >
> > what effect does start have when num_pulse=0 ?
>
> These are assigned only to silence a GCC warning about them possibly
> being uninitialised when they always will be in the cases that they're
> used. I could add a comment to this effect.
please do, or ill forget and complain about it in every 3rd review
[...]
> > [...]
> >> +
> >> +/**
> >> + * channel coupling transformation interface
> >> + *
> >> + * @param index index into coupling gain array
> >> + * @param apply_coupling_method pointer to (in)dependent coupling function
> >> + */
> >> +static void apply_channel_coupling(AACContext * ac, ChannelElement * cc,
> >> + void (*apply_coupling_method)(AACContext * ac, SingleChannelElement * sce, ChannelElement * cc, int index))
> >> +{
> >> + int c;
> >> + int index = 0;
> >> + ChannelCoupling * coup = &cc->coup;
> >> + for (c = 0; c <= coup->num_coupled; c++) {
> >> + if ( !coup->is_cpe[c] && ac->che[ID_SCE][coup->tag_select[c]]) {
> >> + apply_coupling_method(ac, &ac->che[ID_SCE][coup->tag_select[c]]->ch[0], cc, index++);
> >> + } else if(coup->is_cpe[c] && ac->che[ID_CPE][coup->tag_select[c]]) {
> >
> >> + if (!coup->l[c] && !coup->r[c]) {
> >> + apply_coupling_method(ac, &ac->che[ID_CPE][coup->tag_select[c]]->ch[0], cc, index);
> >> + apply_coupling_method(ac, &ac->che[ID_CPE][coup->tag_select[c]]->ch[1], cc, index++);
> >> + }
> >
> > The struct docs say r/l are "apply gain to r/l channel" this contradicts the
> > 0/0 case. which is correct and which is wrong?
>
> In the spec, for cc_l[] it says:
>
> "one bit indicating that a list of gain_element values is applied to the left
> channel of a channel pair."
>
> The code that uses it implies that description isn't strictly true. In
> the !l[] && !r[] case, there is a shared list of gain_element values.
> So l[] and r[] indicate the presence of a channel-specific list of
> gain_element values. I'll change the comments.
if(coup->ch_select!=2){
apply_coupling_method(ac, &ac->che[ID_CPE][coup->tag_select[c]]->ch[0], cc, index);
if(coup->ch_select!=0)
index++;
}
if(coup->ch_select!=1)
apply_coupling_method(ac, &ac->che[ID_CPE][coup->tag_select[c]]->ch[1], cc, index++);
>
> > [...]
> >> +
> >> +/**
> >> + * Conduct matrix mix-down and float to int16 conversion.
> >> + *
> >> + * @param data pointer to output data
> >> + * @param data_size output data size in bytes
> >> + * @return Returns error status. 0 - OK, !0 - error
> >> + */
> >> +static int mixdown_and_convert_to_int16(AVCodecContext * avccontext, uint16_t * data, int * data_size) {
> >> + AACContext * ac = avccontext->priv_data;
> >> + int i;
> >> + float *c, *l, *r, *sl, *sr, *out;
> >> +
> >> + if (!ac->is_saved) {
> >> + ac->is_saved = 1;
> >> + *data_size = 0;
> >> + return 0;
> >> + }
> >> +
> >> + i = 1024 * avccontext->channels * sizeof(int16_t);
> >> + if(*data_size < i) {
> >> + av_log(avccontext, AV_LOG_ERROR,
> >> + "Output buffer too small (%d) or trying to output too many samples (%d) for this frame.\n",
> >> + *data_size, i);
> >> + return -1;
> >> + }
> >> + *data_size = i;
> >> +
> >> + if(ac->mm[MIXDOWN_CENTER]) {
> >> + /* matrix mix-down */
> >> + l = ac->mm[MIXDOWN_FRONT ]->ch[0].ret;
> >> + r = ac->mm[MIXDOWN_FRONT ]->ch[1].ret;
> >> + c = ac->mm[MIXDOWN_CENTER]->ch[0].ret;
> >> + sl = ac->mm[MIXDOWN_BACK ]->ch[0].ret;
> >> + sr = ac->mm[MIXDOWN_BACK ]->ch[1].ret;
> >> + out = ac->interleaved_output;
> >> +
> >> + // XXX dsputil-ize
> >> + if(avccontext->channels == 2) {
> >> + if(ac->pcs.pseudo_surround) {
> >> + for(i = 0; i < 1024; i++) {
> >> + *out++ = *l++ + *c - *sl - *sr + ac->add_bias;
> >> + *out++ = *r++ + *c++ + *sl++ + *sr++ - ac->add_bias * 3;
> >> + }
> >> + } else {
> >> + for(i = 0; i < 1024; i++) {
> >> + *out++ = *l++ + *c + *sl++ - ac->add_bias * 2;
> >> + *out++ = *r++ + *c++ + *sr++ - ac->add_bias * 2;
> >> + }
> >> + }
> >> +
> >> + } else {
> >> + assert(avccontext->channels == 1);
> >> + for(i = 0; i < 1024; i++) {
> >> + *out++ = *l++ + *r++ + *c++ + *sl++ + *sr++ - ac->add_bias * 4;
> >> + }
> >> + }
> >> +
> >> + ac->dsp.float_to_int16(data, ac->interleaved_output, 1024 * avccontext->channels);
> >> + } else {
> >> + ac->dsp.float_to_int16_interleave(data, (const float **)ac->output_data, 1024, avccontext->channels);
> >> + }
> >> +
> >> + return 0;
> >> +}
> >
> > mixdown should be done prior to the IMDCT when possible and the IMDCT skipped
> > for channels that are not needed, or _ALL_ mixdown code should be removed
> > from the AAC decoder, as in that case mixdown can be done outside of the
> > decoder equally well and cleaner.
>
> I think doing pre-IMDCT mix-down will be complicated because of the
> different windows and their overlaps. As a consequence of these issues
> the optimisation may or may not be worth it. I think the overlapping
> simplifications I had planned when transitioning to using imdct_half()
> may help so I should probably do those first.
>
> *** In the spec they advise against using the matrix mix-down method
> so I think all this matrix mix-down code should be dropped in favour
> of generic channel mixing either pre-IMDCT or post decoding, unless
> someone knows of a good reason why it should be kept. I think Andreas
> implemented this code but I'm not sure.
also droping it will make it hit svn sooner ...
>
> >> +
> >> +
> >> +static int aac_decode_frame(AVCodecContext * avccontext, void * data, int * data_size, const uint8_t * buf, int buf_size) {
> >> + AACContext * ac = avccontext->priv_data;
> >> + GetBitContext gb;
> >> + enum RawDataBlockID id;
> >> + int err, tag;
> >> +
> >> + init_get_bits(&gb, buf, buf_size*8);
> >> +
> >> + // parse
> >> + while ((id = get_bits(&gb, 3)) != ID_END) {
> >> + tag = get_bits(&gb, 4);
> >> + err = -1;
> >> + switch (id) {
> >> +
> >
> >> + case ID_SCE:
> >> + if(!ac->che[ID_SCE][tag]) {
> >
> > this id / tag naming confuses the hell out of me ...
> > Both values together identify the "thing". the id here is the
> > type (channel pair / single channel / ...)
>
> Why is it confusing? As you say, the id is the type and the tag is
> (and I know you don't like this but I'm going to use it anyway because
> I'm happy with it) the instance of that type.
Well iam not a native englishman ...
but to me id is something by which a specific individual or instance can
uniquely be identified. This isnt true here ...
That is, the number on the license plate of a car is an ID,
Rolls Royce Phantom II is not an ID its the type or model.
>
> > [...]
> >> Index: libavcodec/aac.h
> >> ===================================================================
> >> --- libavcodec/aac.h (revision 14624)
> >> +++ libavcodec/aac.h (working copy)
> >> @@ -42,8 +44,63 @@
> >> ff_aac_spectral_codes[num], sizeof(ff_aac_spectral_codes[num][0]), sizeof(ff_aac_spectral_codes[num][0]), \
> >> size);
> >>
> >> +#define MAX_CHANNELS 64
> >
> > ok as long as its not causing huge arrays, like if there was a use like
> > array[MAX_FRAME][MAX_TAGS][MAX_BANDS][MAX_CHANNELS] ...
>
> Please define huge.
huge being 10k for the context IMHO, that is if you can safe 10k by
making MAX_CHANNELS a realistic number please do.
if it just safes 500 bytes its not worth it if it makes the code more
complex ...
[...]
> > [...]
> >> +/**
> >> + * M/S joint channel coding
> >> + */
> >> +typedef struct {
> >> + int present;
> >> + uint8_t mask[8][64];
> >> +} MidSideStereo;
> >
> > cant this use the channel coupling struct and code? Its doing the same thing
> > i think
>
> "coupling channel elements provide two functionalities: First,
> coupling channels may be used to implement generalized intensity
> stereo coding where channel spectra can be shared across channel
> boundaries. Second, coupling channels may be used to dynamically
> perform a downmix of one sound object into the stereo image."
>
> I don't think they quite do the same thing.
I didnt mean there is a semantic relation just that what they do is
quite similar and that it may but does not have to be a good idea
to convert MS to coupling structs on reading.
> mask[][] is the only array
> left in this struct now though so I'll rename it ms_mask[][] and
> remove the struct.
ok, each struct less is a good thing.
[...]
> >> + int num_coupled; ///< number of target elements
> >
> >> + int is_cpe[9]; ///< Set if target is an CPE (otherwise it's an SCE).
> >
> > Maybe some code could be simplified if these where ID_CPE/ID_SCE ?
>
> Do you mean if the array values were ID_CPE/ID_SCE?
yes
> I don't think it
> would allow any simplifications.
hmm
>
> >> + int tag_select[9]; ///< element tag index
> >> + int l[9]; ///< Apply gain to left channel of a CPE.
> >> + int r[9]; ///< Apply gain to right channel of a CPE.
> >
> > do these arrays need 9 or 8 elements?
>
> 9
how can a 9th element be written in there?
from what i remember it looked like that it was limited to 8, but i might
have been wrong...
>
> > [...]
> >> Index: libavcodec/aacdectab.h
> >> ===================================================================
> >> --- libavcodec/aacdectab.h (revision 0)
> >> +++ libavcodec/aacdectab.h (revision 0)
> >> @@ -0,0 +1,189 @@
> >> +/*
> >> + * AAC decoder data
> >> + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org )
> >> + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com )
> >> + *
> >> + * 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
> >> + */
> >> +
> >> +/**
> >> + * @file aacdectab.h
> >> + * AAC decoder data
> >> + * @author Oded Shimon ( ods15 ods15 dyndns org )
> >> + * @author Maxim Gavrilov ( maxim.gavrilov gmail com )
> >> + */
> >> +
> >> +#ifndef FFMPEG_AACDECTAB_H
> >> +#define FFMPEG_AACDECTAB_H
> >> +
> >> +#include "aac.h"
> >> +
> >> +#include <stdint.h>
> >> +
> >> +static const uint16_t swb_offset_1024_96[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 32, 36, 40, 44, 48, 52, 56, 64,
> >> + 72, 80, 88, 96, 108, 120, 132, 144,
> >> + 156, 172, 188, 212, 240, 276, 320, 384,
> >> + 448, 512, 576, 640, 704, 768, 832, 896,
> >> + 960, 1024
> >> +};
> >> +
> >> +static const uint16_t swb_offset_128_96[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128
> >> +};
> >> +
> >> +static const uint16_t swb_offset_1024_64[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 32, 36, 40, 44, 48, 52, 56, 64,
> >> + 72, 80, 88, 100, 112, 124, 140, 156,
> >> + 172, 192, 216, 240, 268, 304, 344, 384,
> >> + 424, 464, 504, 544, 584, 624, 664, 704,
> >> + 744, 784, 824, 864, 904, 944, 984, 1024
> >> +};
> >> +
> >> +static const uint16_t swb_offset_1024_48[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 32, 36, 40, 48, 56, 64, 72, 80,
> >> + 88, 96, 108, 120, 132, 144, 160, 176,
> >> + 196, 216, 240, 264, 292, 320, 352, 384,
> >> + 416, 448, 480, 512, 544, 576, 608, 640,
> >> + 672, 704, 736, 768, 800, 832, 864, 896,
> >> + 928, 1024
> >> +};
> >> +
> >> +static const uint16_t swb_offset_128_48[] = {
> >> + 0, 4, 8, 12, 16, 20, 28, 36,
> >> + 44, 56, 68, 80, 96, 112, 128
> >> +};
> >> +
> >> +static const uint16_t swb_offset_1024_32[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 32, 36, 40, 48, 56, 64, 72, 80,
> >> + 88, 96, 108, 120, 132, 144, 160, 176,
> >> + 196, 216, 240, 264, 292, 320, 352, 384,
> >> + 416, 448, 480, 512, 544, 576, 608, 640,
> >> + 672, 704, 736, 768, 800, 832, 864, 896,
> >> + 928, 960, 992, 1024
> >> +};
> >> +
> >> +static const uint16_t swb_offset_1024_24[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 32, 36, 40, 44, 52, 60, 68, 76,
> >> + 84, 92, 100, 108, 116, 124, 136, 148,
> >> + 160, 172, 188, 204, 220, 240, 260, 284,
> >> + 308, 336, 364, 396, 432, 468, 508, 552,
> >> + 600, 652, 704, 768, 832, 896, 960, 1024
> >> +};
> >> +
> >> +static const uint16_t swb_offset_128_24[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 36, 44, 52, 64, 76, 92, 108, 128
> >> +};
> >> +
> >> +static const uint16_t swb_offset_1024_16[] = {
> >> + 0, 8, 16, 24, 32, 40, 48, 56,
> >> + 64, 72, 80, 88, 100, 112, 124, 136,
> >> + 148, 160, 172, 184, 196, 212, 228, 244,
> >> + 260, 280, 300, 320, 344, 368, 396, 424,
> >> + 456, 492, 532, 572, 616, 664, 716, 772,
> >> + 832, 896, 960, 1024
> >> +};
> >> +
> >> +static const uint16_t swb_offset_128_16[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 32, 40, 48, 60, 72, 88, 108, 128
> >> +};
> >> +
> >> +static const uint16_t swb_offset_1024_8[] = {
> >> + 0, 12, 24, 36, 48, 60, 72, 84,
> >> + 96, 108, 120, 132, 144, 156, 172, 188,
> >> + 204, 220, 236, 252, 268, 288, 308, 328,
> >> + 348, 372, 396, 420, 448, 476, 508, 544,
> >> + 580, 620, 664, 712, 764, 820, 880, 944,
> >> + 1024
> >> +};
> >> +
> >> +static const uint16_t swb_offset_128_8[] = {
> >> + 0, 4, 8, 12, 16, 20, 24, 28,
> >> + 36, 44, 52, 60, 72, 88, 108, 128
> >> +};
> >> +
> >> +static const uint16_t *swb_offset_1024[] = {
> >> + swb_offset_1024_96, swb_offset_1024_96, swb_offset_1024_64,
> >> + swb_offset_1024_48, swb_offset_1024_48, swb_offset_1024_32,
> >> + swb_offset_1024_24, swb_offset_1024_24, swb_offset_1024_16,
> >> + swb_offset_1024_16, swb_offset_1024_16, swb_offset_1024_8
> >> +};
> >> +
> >> +static const uint16_t *swb_offset_128[] = {
> >> + /* The last entry on the following row is swb_offset_128_64 but is a
> >> + duplicate of swb_offset_128_96. */
> >> + swb_offset_128_96, swb_offset_128_96, swb_offset_128_96,
> >> + swb_offset_128_48, swb_offset_128_48, swb_offset_128_48,
> >> + swb_offset_128_24, swb_offset_128_24, swb_offset_128_16,
> >> + swb_offset_128_16, swb_offset_128_16, swb_offset_128_8
> >> +};
> >
> > Does storing band sizes instead of band offsets lead to simpler code?
> > if not, the code above is ok
>
> grepping for 'offset' in aac.c shows quite a few more lines of
> for(i=offset[idx]; i<offset[idx+1]; i++) or just offset[idx] than
> lines using offset[idx+1] - offset[idx] so I think it's better as it
> is.
ok, the reason why i brought it up was that it would safe a few byte as the
tables would then fit in uint8_t
>
> > Btw, what does swb stand for? it should be mentioned somewhere in a doxy
>
> scalefactor window band - term for scalefactor bands within a window,
> given in Table 4.110 to Table 4.128.
>
> scalefactor band - term for scalefactor band within a group. In case
> of EIGHT_SHORT_SEQUENCE and grouping a scalefactor band may contain
> several scalefactor window bands of corresponding frequency. For all
> other window_sequences scalefactor bands and scalefactor window bands
> are identical.
>
> I think all that information is useful but where would be a good place
> to put it?
hmm, i do not know but anywhere is better than nowhere
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
I do not agree with what you have to say, but I'll defend to the death your
right to say it. -- Voltaire
-------------- 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/20080807/2c652152/attachment.pgp>
More information about the ffmpeg-devel
mailing list