[FFmpeg-devel] Decoding the same audio frame twice produces different output

Haakon Riiser haakon.riiser
Tue May 12 14:52:55 CEST 2009


As the subject states, I am wondering why libavcodec produces
different output when the same audio frame is decoded twice in a
row.  As far as I know, every audio frame is as independent as an
I-frame in video, so it should always produce the same output.

I have created a small program to illustrate this bug.  Please read
it and let me know if this is a bug in libavcodec, or if my
understanding of audio coding and libavcodec is flawed.  Note that
while this program uses MP3, the same bug is present regardless of
codec (I haved also tried MP2 and AC3).

This program was compiled using

  $ CFLAGS=$(pkg-config --cflags libavcodec libavformat)
  $ LIBS=$(pkg-config --libs libavcodec libavformat)
  $ gcc -g -Wall $CFLAGS bug.c $LIBS -o bug

Running ./bug should produce no output if libavcodec produces the
same output for two identical avcodec_decode_audio2 calls in a row.

/***************************************************************************/

  #include <assert.h>
  #include <libavutil/avstring.h>
  #include <libavutil/avutil.h>
  #include <libavformat/avformat.h>
  #include <libavcodec/avcodec.h>
  
  /*
   * A single compressed MP3 frame, extracted from a media file created with
   * mencoder. (-oac mp3lame -lameopts abr:br=128:mode=1).
   */
  unsigned char frame[] = {
    0xff, 0xfb, 0x54, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x05, 0x00,
    0x00, 0x08, 0x00, 0x00, 0x0d, 0x20, 0xa0, 0x00, 0x01, 0x09, 0x14, 0xb8,
    0xfe, 0xb8, 0xd5, 0x00, 0x01, 0x21, 0x9e, 0x1f, 0x97, 0x23, 0x00, 0x00,
    0x00, 0x02, 0x48, 0x00, 0x0f, 0x16, 0x61, 0x7a, 0xf0, 0x24, 0x00, 0xf0,
    0xf3, 0xe3, 0x93, 0xc2, 0xc0, 0xb7, 0xf8, 0xb0, 0x0d, 0x82, 0xcf, 0xe2,
    0x1c, 0x0a, 0x62, 0xb7, 0xfe, 0x0d, 0x00, 0x80, 0x31, 0x10, 0xe1, 0x7f,
    0xff, 0xe4, 0x44, 0x82, 0xc1, 0xa7, 0x91, 0xff, 0xfe, 0x71, 0x20, 0xf0,
    0x17, 0x3f, 0xfe, 0x88, 0x6c, 0x10, 0xff, 0xc4, 0xe7, 0xc0, 0x0e, 0x4f,
    0xff, 0xc6, 0x00, 0xc3, 0xe0, 0x81, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xfc,
    0xb8, 0x00, 0x02, 0x00, 0x00, 0x78, 0x37, 0x50, 0x2e, 0x8f, 0x80, 0xab,
    0x01, 0x8f, 0xe2, 0xd0, 0x2c, 0x1e, 0x20, 0xc2, 0x2f, 0xfa, 0x88, 0xb9,
    0x4b, 0xf1, 0x70, 0x08, 0x30, 0x87, 0xff, 0xe7, 0xd3, 0x38, 0x4e, 0x0e,
    0x0f, 0xff, 0x33, 0x74, 0xd2, 0x34, 0x22, 0x1f, 0xff, 0x9d, 0x37, 0x27,
    0xce, 0x1a, 0x1a, 0x27, 0xff, 0xfe, 0x99, 0x3e, 0xa6, 0x41, 0x66, 0xe6,
    0xff, 0xf9, 0x00, 0x44, 0xfa, 0x40, 0x9f, 0xff, 0x59, 0xa3, 0x85, 0xde,
    0x04, 0x00, 0x20, 0x10, 0x17, 0x13, 0x6e, 0x01, 0x00, 0xfc, 0x05, 0xa7
  };
  unsigned int len = 192;
  
  int main()
  {
          /*
           * Recreate the audio codec context that was originally created by
           * libavformat for the stream from which the above compressed
           * MP3 frame was found.
           */
          AVCodecContext *accx = avcodec_alloc_context();
          accx->codec_type = CODEC_TYPE_AUDIO;
          accx->codec_id = CODEC_ID_MP3;
          accx->codec_tag = 0x55;
          accx->sub_id = 3;
          accx->sample_fmt = SAMPLE_FMT_S16;
          accx->flags = 0;
          accx->sample_rate = 48000;
          accx->channels = 2;
          accx->frame_size = 1152;
          accx->block_align = 1152;
          accx->extradata_size = 12;
          unsigned char extradata[12] = {
                  0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
                  0x80, 0x04, 0x01, 0x00, 0x00, 0x00
          };
          accx->extradata = extradata;
  
          /*
           * Initialize libavcodec.
           */
          av_register_all();
          AVCodec *codec = avcodec_find_decoder(accx->codec_id);
          if (!codec) {
                  printf("codec not supported\n");
                  return 1;
          }
          if (avcodec_open(accx, codec) < 0) {
                  printf("avcodec_open failed\n");
                  return 1;
          }
  
          /*
           * Output buffers.  Note that I deliberately do NOT initialize these
           * values.  One would think that would not be necessary, as this is
           * just an output buffer, so when N bytes are reported written to
           * this buffer, N bytes should be initialized, right?
           */ 
          int16_t buf1[64*1024];
          int16_t buf2[64*1024];
          int n_bytes1 = AVCODEC_MAX_AUDIO_FRAME_SIZE;
          int n_bytes2 = AVCODEC_MAX_AUDIO_FRAME_SIZE;
  
          /*
           * Decode the same MP3 frame twice in a row.  I expect identical
           * output from these two, both in ret1 and ret2, n_bytes1
           * and n_bytes2, and in the output buffers, buf1 and buf2.
           */
          int ret1 = avcodec_decode_audio2(accx, buf1, &n_bytes1, frame, len);
          int ret2 = avcodec_decode_audio2(accx, buf2, &n_bytes2, frame, len);
  
          /*
           * These assertions do not fail.
           */
          assert(ret1 == ret2);
          assert(n_bytes1 == n_bytes2);
  
          /*
           * Here, I iterate over the samples produced by libavcodec.  There
           * are two problems here:
           *
           *  (1) valgrind reports that some of the bytes in both buf1 and
           *      buf2 (range [0 ... n_bytes1-1]) have not been set.  That
           *      must be a bug, right?
           *
           *  (2) Since buf1 and buf2 are supposed to be identical, no lines
           *  should be printed, yet many are.
           */
          int i;
          for (i = 0; i < n_bytes1; i++) {
                  if (buf1[i] != buf2[i]) {
                          printf("[%d] %hd != %hd\n", i, buf1[i], buf2[i]);
                  }
          }
  
          return 0;
  }

/***************************************************************************/

-- 
 Haakon



More information about the ffmpeg-devel mailing list