]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/flacdec.c
pthread_frame: ensure the threads don't run simultaneously with hwaccel
[ffmpeg] / libavcodec / flacdec.c
index f6206947a8ccc0f01f4bd7ccbe97615ec2c5b2eb..7af71f3c0c0de3e664a058c8ae52128458eca2f3 100644 (file)
@@ -2,20 +2,20 @@
  * FLAC (Free Lossless Audio Codec) decoder
  * Copyright (c) 2003 Alex Beregszaszi
  *
- * This file is part of FFmpeg.
+ * This file is part of Libav.
  *
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav 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,
+ * Libav 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
+ * License along with Libav; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -23,9 +23,7 @@
  * @file
  * FLAC (Free Lossless Audio Codec) decoder
  * @author Alex Beregszaszi
- *
- * For more information on the FLAC format, visit:
- *  http://flac.sourceforge.net/
+ * @see http://flac.sourceforge.net/
  *
  * This decoder can be used in 1 of 2 ways: Either raw FLAC data can be fed
  * through, starting from the initial 'fLaC' signature; or by passing the
@@ -35,7 +33,6 @@
 
 #include <limits.h>
 
-#include "libavutil/crc.h"
 #include "avcodec.h"
 #include "internal.h"
 #include "get_bits.h"
@@ -43,9 +40,7 @@
 #include "golomb.h"
 #include "flac.h"
 #include "flacdata.h"
-
-#undef NDEBUG
-#include <assert.h>
+#include "flacdsp.h"
 
 typedef struct FLACContext {
     FLACSTREAMINFO
@@ -54,72 +49,64 @@ typedef struct FLACContext {
     GetBitContext gb;                       ///< GetBitContext initialized to start at the current frame
 
     int blocksize;                          ///< number of samples in the current frame
-    int curr_bps;                           ///< bps for current subframe, adjusted for channel correlation and wasted bits
     int sample_shift;                       ///< shift required to make output samples 16-bit or 32-bit
-    int is32;                               ///< flag to indicate if output should be 32-bit instead of 16-bit
     int ch_mode;                            ///< channel decorrelation type in the current frame
     int got_streaminfo;                     ///< indicates if the STREAMINFO has been read
 
     int32_t *decoded[FLAC_MAX_CHANNELS];    ///< decoded samples
-    uint8_t *bitstream;
-    unsigned int bitstream_size;
-    unsigned int bitstream_index;
-    unsigned int allocated_bitstream_size;
+    uint8_t *decoded_buffer;
+    unsigned int decoded_buffer_size;
+
+    FLACDSPContext dsp;
 } FLACContext;
 
-static void allocate_buffers(FLACContext *s);
+static int allocate_buffers(FLACContext *s);
 
-int ff_flac_is_extradata_valid(AVCodecContext *avctx,
-                               enum FLACExtradataFormat *format,
-                               uint8_t **streaminfo_start)
+static void flac_set_bps(FLACContext *s)
 {
-    if (!avctx->extradata || avctx->extradata_size < FLAC_STREAMINFO_SIZE) {
-        av_log(avctx, AV_LOG_ERROR, "extradata NULL or too small.\n");
-        return 0;
-    }
-    if (AV_RL32(avctx->extradata) != MKTAG('f','L','a','C')) {
-        /* extradata contains STREAMINFO only */
-        if (avctx->extradata_size != FLAC_STREAMINFO_SIZE) {
-            av_log(avctx, AV_LOG_WARNING, "extradata contains %d bytes too many.\n",
-                   FLAC_STREAMINFO_SIZE-avctx->extradata_size);
-        }
-        *format = FLAC_EXTRADATA_FORMAT_STREAMINFO;
-        *streaminfo_start = avctx->extradata;
+    enum AVSampleFormat req = s->avctx->request_sample_fmt;
+    int need32 = s->bps > 16;
+    int want32 = av_get_bytes_per_sample(req) > 2;
+    int planar = av_sample_fmt_is_planar(req);
+
+    if (need32 || want32) {
+        if (planar)
+            s->avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
+        else
+            s->avctx->sample_fmt = AV_SAMPLE_FMT_S32;
+        s->sample_shift = 32 - s->bps;
     } else {
-        if (avctx->extradata_size < 8+FLAC_STREAMINFO_SIZE) {
-            av_log(avctx, AV_LOG_ERROR, "extradata too small.\n");
-            return 0;
-        }
-        *format = FLAC_EXTRADATA_FORMAT_FULL_HEADER;
-        *streaminfo_start = &avctx->extradata[8];
+        if (planar)
+            s->avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
+        else
+            s->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+        s->sample_shift = 16 - s->bps;
     }
-    return 1;
 }
 
 static av_cold int flac_decode_init(AVCodecContext *avctx)
 {
     enum FLACExtradataFormat format;
     uint8_t *streaminfo;
+    int ret;
     FLACContext *s = avctx->priv_data;
     s->avctx = avctx;
 
-    avctx->sample_fmt = AV_SAMPLE_FMT_S16;
-
     /* for now, the raw FLAC header is allowed to be passed to the decoder as
        frame data instead of extradata. */
     if (!avctx->extradata)
         return 0;
 
     if (!ff_flac_is_extradata_valid(avctx, &format, &streaminfo))
-        return -1;
+        return AVERROR_INVALIDDATA;
 
     /* initialize based on the demuxer-supplied streamdata header */
     ff_flac_parse_streaminfo(avctx, (FLACStreaminfo *)s, streaminfo);
-    if (s->bps > 16)
-        avctx->sample_fmt = AV_SAMPLE_FMT_S32;
-    else
-        avctx->sample_fmt = AV_SAMPLE_FMT_S16;
-    allocate_buffers(s);
+    ret = allocate_buffers(s);
+    if (ret < 0)
+        return ret;
+    flac_set_bps(s);
+    ff_flacdsp_init(&s->dsp, avctx->sample_fmt, s->bps);
     s->got_streaminfo = 1;
 
     return 0;
@@ -134,72 +121,22 @@ static void dump_headers(AVCodecContext *avctx, FLACStreaminfo *s)
     av_log(avctx, AV_LOG_DEBUG, "  Bits: %d\n", s->bps);
 }
 
-static void allocate_buffers(FLACContext *s)
+static int allocate_buffers(FLACContext *s)
 {
-    int i;
-
-    assert(s->max_blocksize);
+    int buf_size;
 
-    if (s->max_framesize == 0 && s->max_blocksize) {
-        s->max_framesize = ff_flac_get_max_frame_size(s->max_blocksize,
-                                                      s->channels, s->bps);
-    }
+    buf_size = av_samples_get_buffer_size(NULL, s->channels, s->max_blocksize,
+                                          AV_SAMPLE_FMT_S32P, 0);
+    if (buf_size < 0)
+        return buf_size;
 
-    for (i = 0; i < s->channels; i++) {
-        s->decoded[i] = av_realloc(s->decoded[i],
-                                   sizeof(int32_t)*s->max_blocksize);
-    }
+    av_fast_malloc(&s->decoded_buffer, &s->decoded_buffer_size, buf_size);
+    if (!s->decoded_buffer)
+        return AVERROR(ENOMEM);
 
-    if (s->allocated_bitstream_size < s->max_framesize)
-        s->bitstream= av_fast_realloc(s->bitstream,
-                                      &s->allocated_bitstream_size,
-                                      s->max_framesize);
-}
-
-void ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s,
-                              const uint8_t *buffer)
-{
-    GetBitContext gb;
-    init_get_bits(&gb, buffer, FLAC_STREAMINFO_SIZE*8);
-
-    skip_bits(&gb, 16); /* skip min blocksize */
-    s->max_blocksize = get_bits(&gb, 16);
-    if (s->max_blocksize < FLAC_MIN_BLOCKSIZE) {
-        av_log(avctx, AV_LOG_WARNING, "invalid max blocksize: %d\n",
-               s->max_blocksize);
-        s->max_blocksize = 16;
-    }
-
-    skip_bits(&gb, 24); /* skip min frame size */
-    s->max_framesize = get_bits_long(&gb, 24);
-
-    s->samplerate = get_bits_long(&gb, 20);
-    s->channels = get_bits(&gb, 3) + 1;
-    s->bps = get_bits(&gb, 5) + 1;
-
-    avctx->channels = s->channels;
-    avctx->sample_rate = s->samplerate;
-    avctx->bits_per_raw_sample = s->bps;
-
-    s->samples  = get_bits_long(&gb, 32) << 4;
-    s->samples |= get_bits(&gb, 4);
-
-    skip_bits_long(&gb, 64); /* md5 sum */
-    skip_bits_long(&gb, 64); /* md5 sum */
-
-    dump_headers(avctx, s);
-}
-
-void ff_flac_parse_block_header(const uint8_t *block_header,
-                                int *last, int *type, int *size)
-{
-    int tmp = bytestream_get_byte(&block_header);
-    if (last)
-        *last = tmp & 0x80;
-    if (type)
-        *type = tmp & 0x7F;
-    if (size)
-        *size = bytestream_get_be24(&block_header);
+    return av_samples_fill_arrays((uint8_t **)s->decoded, NULL,
+                                  s->decoded_buffer, s->channels,
+                                  s->max_blocksize, AV_SAMPLE_FMT_S32P, 0);
 }
 
 /**
@@ -211,19 +148,23 @@ void ff_flac_parse_block_header(const uint8_t *block_header,
  */
 static int parse_streaminfo(FLACContext *s, const uint8_t *buf, int buf_size)
 {
-    int metadata_type, metadata_size;
+    int metadata_type, metadata_size, ret;
 
     if (buf_size < FLAC_STREAMINFO_SIZE+8) {
         /* need more data */
         return 0;
     }
-    ff_flac_parse_block_header(&buf[4], NULL, &metadata_type, &metadata_size);
+    flac_parse_block_header(&buf[4], NULL, &metadata_type, &metadata_size);
     if (metadata_type != FLAC_METADATA_TYPE_STREAMINFO ||
         metadata_size != FLAC_STREAMINFO_SIZE) {
         return AVERROR_INVALIDDATA;
     }
     ff_flac_parse_streaminfo(s->avctx, (FLACStreaminfo *)s, &buf[8]);
-    allocate_buffers(s);
+    ret = allocate_buffers(s);
+    if (ret < 0)
+        return ret;
+    flac_set_bps(s);
+    ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps);
     s->got_streaminfo = 1;
 
     return 0;
@@ -242,9 +183,11 @@ static int get_metadata_size(const uint8_t *buf, int buf_size)
 
     buf += 4;
     do {
-        ff_flac_parse_block_header(buf, &metadata_last, NULL, &metadata_size);
+        if (buf_end - buf < 4)
+            return 0;
+        flac_parse_block_header(buf, &metadata_last, NULL, &metadata_size);
         buf += 4;
-        if (buf + metadata_size > buf_end) {
+        if (buf_end - buf < metadata_size) {
             /* need more data in order to read the complete header */
             return 0;
         }
@@ -254,16 +197,17 @@ static int get_metadata_size(const uint8_t *buf, int buf_size)
     return buf_size - (buf_end - buf);
 }
 
-static int decode_residuals(FLACContext *s, int channel, int pred_order)
+static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order)
 {
     int i, tmp, partition, method_type, rice_order;
-    int sample = 0, samples;
+    int rice_bits, rice_esc;
+    int samples;
 
     method_type = get_bits(&s->gb, 2);
     if (method_type > 1) {
         av_log(s->avctx, AV_LOG_ERROR, "illegal residual coding method %d\n",
                method_type);
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
 
     rice_order = get_bits(&s->gb, 4);
@@ -272,20 +216,23 @@ static int decode_residuals(FLACContext *s, int channel, int pred_order)
     if (pred_order > samples) {
         av_log(s->avctx, AV_LOG_ERROR, "invalid predictor order: %i > %i\n",
                pred_order, samples);
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
 
-    sample=
+    rice_bits = 4 + method_type;
+    rice_esc  = (1 << rice_bits) - 1;
+
+    decoded += pred_order;
     i= pred_order;
     for (partition = 0; partition < (1 << rice_order); partition++) {
-        tmp = get_bits(&s->gb, method_type == 0 ? 4 : 5);
-        if (tmp == (method_type == 0 ? 15 : 31)) {
+        tmp = get_bits(&s->gb, rice_bits);
+        if (tmp == rice_esc) {
             tmp = get_bits(&s->gb, 5);
-            for (; i < samples; i++, sample++)
-                s->decoded[channel][sample] = get_sbits_long(&s->gb, tmp);
+            for (; i < samples; i++)
+                *decoded++ = get_sbits_long(&s->gb, tmp);
         } else {
-            for (; i < samples; i++, sample++) {
-                s->decoded[channel][sample] = get_sr_golomb_flac(&s->gb, tmp, INT_MAX, 0);
+            for (; i < samples; i++) {
+                *decoded++ = get_sr_golomb_flac(&s->gb, tmp, INT_MAX, 0);
             }
         }
         i= 0;
@@ -294,19 +241,19 @@ static int decode_residuals(FLACContext *s, int channel, int pred_order)
     return 0;
 }
 
-static int decode_subframe_fixed(FLACContext *s, int channel, int pred_order)
+static int decode_subframe_fixed(FLACContext *s, int32_t *decoded,
+                                 int pred_order, int bps)
 {
     const int blocksize = s->blocksize;
-    int32_t *decoded = s->decoded[channel];
-    int av_uninit(a), av_uninit(b), av_uninit(c), av_uninit(d), i;
+    int a, b, c, d, i, ret;
 
     /* warm up samples */
     for (i = 0; i < pred_order; i++) {
-        decoded[i] = get_sbits_long(&s->gb, s->curr_bps);
+        decoded[i] = get_sbits_long(&s->gb, bps);
     }
 
-    if (decode_residuals(s, channel, pred_order) < 0)
-        return -1;
+    if ((ret = decode_residuals(s, decoded, pred_order)) < 0)
+        return ret;
 
     if (pred_order > 0)
         a = decoded[pred_order-1];
@@ -338,133 +285,112 @@ static int decode_subframe_fixed(FLACContext *s, int channel, int pred_order)
         break;
     default:
         av_log(s->avctx, AV_LOG_ERROR, "illegal pred order %d\n", pred_order);
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
 
     return 0;
 }
 
-static int decode_subframe_lpc(FLACContext *s, int channel, int pred_order)
+static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
+                               int bps)
 {
-    int i, j;
+    int i, ret;
     int coeff_prec, qlevel;
     int coeffs[32];
-    int32_t *decoded = s->decoded[channel];
 
     /* warm up samples */
     for (i = 0; i < pred_order; i++) {
-        decoded[i] = get_sbits_long(&s->gb, s->curr_bps);
+        decoded[i] = get_sbits_long(&s->gb, bps);
     }
 
     coeff_prec = get_bits(&s->gb, 4) + 1;
     if (coeff_prec == 16) {
         av_log(s->avctx, AV_LOG_ERROR, "invalid coeff precision\n");
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     qlevel = get_sbits(&s->gb, 5);
     if (qlevel < 0) {
         av_log(s->avctx, AV_LOG_ERROR, "qlevel %d not supported, maybe buggy stream\n",
                qlevel);
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
 
     for (i = 0; i < pred_order; i++) {
-        coeffs[i] = get_sbits(&s->gb, coeff_prec);
+        coeffs[pred_order - i - 1] = get_sbits(&s->gb, coeff_prec);
     }
 
-    if (decode_residuals(s, channel, pred_order) < 0)
-        return -1;
+    if ((ret = decode_residuals(s, decoded, pred_order)) < 0)
+        return ret;
 
-    if (s->bps > 16) {
-        int64_t sum;
-        for (i = pred_order; i < s->blocksize; i++) {
-            sum = 0;
-            for (j = 0; j < pred_order; j++)
-                sum += (int64_t)coeffs[j] * decoded[i-j-1];
-            decoded[i] += sum >> qlevel;
-        }
-    } else {
-        for (i = pred_order; i < s->blocksize-1; i += 2) {
-            int c;
-            int d = decoded[i-pred_order];
-            int s0 = 0, s1 = 0;
-            for (j = pred_order-1; j > 0; j--) {
-                c = coeffs[j];
-                s0 += c*d;
-                d = decoded[i-j];
-                s1 += c*d;
-            }
-            c = coeffs[0];
-            s0 += c*d;
-            d = decoded[i] += s0 >> qlevel;
-            s1 += c*d;
-            decoded[i+1] += s1 >> qlevel;
-        }
-        if (i < s->blocksize) {
-            int sum = 0;
-            for (j = 0; j < pred_order; j++)
-                sum += coeffs[j] * decoded[i-j-1];
-            decoded[i] += sum >> qlevel;
-        }
-    }
+    s->dsp.lpc(decoded, coeffs, pred_order, qlevel, s->blocksize);
 
     return 0;
 }
 
 static inline int decode_subframe(FLACContext *s, int channel)
 {
+    int32_t *decoded = s->decoded[channel];
     int type, wasted = 0;
-    int i, tmp;
+    int bps = s->bps;
+    int i, tmp, ret;
 
-    s->curr_bps = s->bps;
     if (channel == 0) {
         if (s->ch_mode == FLAC_CHMODE_RIGHT_SIDE)
-            s->curr_bps++;
+            bps++;
     } else {
         if (s->ch_mode == FLAC_CHMODE_LEFT_SIDE || s->ch_mode == FLAC_CHMODE_MID_SIDE)
-            s->curr_bps++;
+            bps++;
     }
 
     if (get_bits1(&s->gb)) {
         av_log(s->avctx, AV_LOG_ERROR, "invalid subframe padding\n");
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     type = get_bits(&s->gb, 6);
 
     if (get_bits1(&s->gb)) {
+        int left = get_bits_left(&s->gb);
         wasted = 1;
+        if ( left < 0 ||
+            (left < bps && !show_bits_long(&s->gb, left)) ||
+                           !show_bits_long(&s->gb, bps)) {
+            av_log(s->avctx, AV_LOG_ERROR,
+                   "Invalid number of wasted bits > available bits (%d) - left=%d\n",
+                   bps, left);
+            return AVERROR_INVALIDDATA;
+        }
         while (!get_bits1(&s->gb))
             wasted++;
-        s->curr_bps -= wasted;
+        bps -= wasted;
     }
-    if (s->curr_bps > 32) {
-        av_log_missing_feature(s->avctx, "decorrelated bit depth > 32", 0);
-        return -1;
+    if (bps > 32) {
+        avpriv_report_missing_feature(s->avctx, "Decorrelated bit depth > 32");
+        return AVERROR_PATCHWELCOME;
     }
 
 //FIXME use av_log2 for types
     if (type == 0) {
-        tmp = get_sbits_long(&s->gb, s->curr_bps);
+        tmp = get_sbits_long(&s->gb, bps);
         for (i = 0; i < s->blocksize; i++)
-            s->decoded[channel][i] = tmp;
+            decoded[i] = tmp;
     } else if (type == 1) {
         for (i = 0; i < s->blocksize; i++)
-            s->decoded[channel][i] = get_sbits_long(&s->gb, s->curr_bps);
+            decoded[i] = get_sbits_long(&s->gb, bps);
     } else if ((type >= 8) && (type <= 12)) {
-        if (decode_subframe_fixed(s, channel, type & ~0x8) < 0)
-            return -1;
+        if ((ret = decode_subframe_fixed(s, decoded, type & ~0x8, bps)) < 0)
+            return ret;
     } else if (type >= 32) {
-        if (decode_subframe_lpc(s, channel, (type & ~0x20)+1) < 0)
-            return -1;
+        if ((ret = decode_subframe_lpc(s, decoded, (type & ~0x20)+1, bps)) < 0)
+            return ret;
     } else {
         av_log(s->avctx, AV_LOG_ERROR, "invalid coding type\n");
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
 
     if (wasted) {
         int i;
         for (i = 0; i < s->blocksize; i++)
-            s->decoded[channel][i] <<= wasted;
+            decoded[i] <<= wasted;
     }
 
     return 0;
@@ -472,44 +398,42 @@ static inline int decode_subframe(FLACContext *s, int channel)
 
 static int decode_frame(FLACContext *s)
 {
-    int i;
+    int i, ret;
     GetBitContext *gb = &s->gb;
     FLACFrameInfo fi;
 
-    if (ff_flac_decode_frame_header(s->avctx, gb, &fi)) {
+    if ((ret = ff_flac_decode_frame_header(s->avctx, gb, &fi, 0)) < 0) {
         av_log(s->avctx, AV_LOG_ERROR, "invalid frame header\n");
-        return -1;
+        return ret;
     }
 
-    if (s->channels && fi.channels != s->channels) {
-        av_log(s->avctx, AV_LOG_ERROR, "switching channel layout mid-stream "
-                                       "is not supported\n");
-        return -1;
+    if (s->channels && fi.channels != s->channels && s->got_streaminfo) {
+        s->channels = s->avctx->channels = fi.channels;
+        ff_flac_set_channel_layout(s->avctx);
+        ret = allocate_buffers(s);
+        if (ret < 0)
+            return ret;
     }
     s->channels = s->avctx->channels = fi.channels;
+    if (!s->avctx->channel_layout)
+        ff_flac_set_channel_layout(s->avctx);
     s->ch_mode = fi.ch_mode;
 
     if (!s->bps && !fi.bps) {
         av_log(s->avctx, AV_LOG_ERROR, "bps not found in STREAMINFO or frame header\n");
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     if (!fi.bps) {
         fi.bps = s->bps;
     } else if (s->bps && fi.bps != s->bps) {
         av_log(s->avctx, AV_LOG_ERROR, "switching bps mid-stream is not "
                                        "supported\n");
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
-    s->bps = s->avctx->bits_per_raw_sample = fi.bps;
 
-    if (s->bps > 16) {
-        s->avctx->sample_fmt = AV_SAMPLE_FMT_S32;
-        s->sample_shift = 32 - s->bps;
-        s->is32 = 1;
-    } else {
-        s->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
-        s->sample_shift = 16 - s->bps;
-        s->is32 = 0;
+    if (!s->bps) {
+        s->bps = s->avctx->bits_per_raw_sample = fi.bps;
+        flac_set_bps(s);
     }
 
     if (!s->max_blocksize)
@@ -517,25 +441,24 @@ static int decode_frame(FLACContext *s)
     if (fi.blocksize > s->max_blocksize) {
         av_log(s->avctx, AV_LOG_ERROR, "blocksize %d > %d\n", fi.blocksize,
                s->max_blocksize);
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     s->blocksize = fi.blocksize;
 
     if (!s->samplerate && !fi.samplerate) {
         av_log(s->avctx, AV_LOG_ERROR, "sample rate not found in STREAMINFO"
                                         " or frame header\n");
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
-    if (fi.samplerate == 0) {
+    if (fi.samplerate == 0)
         fi.samplerate = s->samplerate;
-    } else if (s->samplerate && fi.samplerate != s->samplerate) {
-        av_log(s->avctx, AV_LOG_WARNING, "sample rate changed from %d to %d\n",
-               s->samplerate, fi.samplerate);
-    }
     s->samplerate = s->avctx->sample_rate = fi.samplerate;
 
     if (!s->got_streaminfo) {
-        allocate_buffers(s);
+        ret = allocate_buffers(s);
+        if (ret < 0)
+            return ret;
+        ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps);
         s->got_streaminfo = 1;
         dump_headers(s->avctx, (FLACStreaminfo *)s);
     }
@@ -544,8 +467,8 @@ static int decode_frame(FLACContext *s)
 
     /* subframes */
     for (i = 0; i < s->channels; i++) {
-        if (decode_subframe(s, i) < 0)
-            return -1;
+        if ((ret = decode_subframe(s, i)) < 0)
+            return ret;
     }
 
     align_get_bits(gb);
@@ -556,183 +479,93 @@ static int decode_frame(FLACContext *s)
     return 0;
 }
 
-static int flac_decode_frame(AVCodecContext *avctx,
-                            void *data, int *data_size,
-                            AVPacket *avpkt)
+static int flac_decode_frame(AVCodecContext *avctx, void *data,
+                             int *got_frame_ptr, AVPacket *avpkt)
 {
+    AVFrame *frame     = data;
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
     FLACContext *s = avctx->priv_data;
-    int i, j = 0, input_buf_size = 0, bytes_read = 0;
-    int16_t *samples_16 = data;
-    int32_t *samples_32 = data;
-    int alloc_data_size= *data_size;
-    int output_size;
+    int bytes_read = 0;
+    int ret;
 
-    *data_size=0;
+    *got_frame_ptr = 0;
 
     if (s->max_framesize == 0) {
         s->max_framesize =
             ff_flac_get_max_frame_size(s->max_blocksize ? s->max_blocksize : FLAC_MAX_BLOCKSIZE,
                                        FLAC_MAX_CHANNELS, 32);
-        s->bitstream= av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, s->max_framesize);
-    }
-
-    if (1 && s->max_framesize) { //FIXME truncated
-        if (s->bitstream_size < 4 || AV_RL32(s->bitstream) != MKTAG('f','L','a','C'))
-            buf_size= FFMIN(buf_size, s->max_framesize - FFMIN(s->bitstream_size, s->max_framesize));
-        input_buf_size= buf_size;
-
-        if (s->bitstream_size + buf_size < buf_size || s->bitstream_index + s->bitstream_size + buf_size < s->bitstream_index)
-            return -1;
-
-        if (s->allocated_bitstream_size < s->bitstream_size + buf_size)
-            s->bitstream= av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, s->bitstream_size + buf_size);
-
-        if (s->bitstream_index + s->bitstream_size + buf_size > s->allocated_bitstream_size) {
-            memmove(s->bitstream, &s->bitstream[s->bitstream_index],
-                    s->bitstream_size);
-            s->bitstream_index=0;
-        }
-        memcpy(&s->bitstream[s->bitstream_index + s->bitstream_size],
-               buf, buf_size);
-        buf= &s->bitstream[s->bitstream_index];
-        buf_size += s->bitstream_size;
-        s->bitstream_size= buf_size;
-
-        if (buf_size < s->max_framesize && input_buf_size) {
-            return input_buf_size;
-        }
     }
 
     /* check that there is at least the smallest decodable amount of data.
        this amount corresponds to the smallest valid FLAC frame possible.
        FF F8 69 02 00 00 9A 00 00 34 46 */
-    if (buf_size < 11)
-        goto end;
+    if (buf_size < FLAC_MIN_FRAME_SIZE)
+        return buf_size;
 
     /* check for inline header */
     if (AV_RB32(buf) == MKBETAG('f','L','a','C')) {
-        if (!s->got_streaminfo && parse_streaminfo(s, buf, buf_size)) {
+        if (!s->got_streaminfo && (ret = parse_streaminfo(s, buf, buf_size))) {
             av_log(s->avctx, AV_LOG_ERROR, "invalid header\n");
-            return -1;
+            return ret;
         }
-        bytes_read = get_metadata_size(buf, buf_size);
-        goto end;
-    }
-
-    /* check for frame sync code and resync stream if necessary */
-    if ((AV_RB16(buf) & 0xFFFE) != 0xFFF8) {
-        const uint8_t *buf_end = buf + buf_size;
-        av_log(s->avctx, AV_LOG_ERROR, "FRAME HEADER not here\n");
-        while (buf+2 < buf_end && (AV_RB16(buf) & 0xFFFE) != 0xFFF8)
-            buf++;
-        bytes_read = buf_size - (buf_end - buf);
-        goto end; // we may not have enough bits left to decode a frame, so try next time
+        return get_metadata_size(buf, buf_size);
     }
 
     /* decode frame */
     init_get_bits(&s->gb, buf, buf_size*8);
-    if (decode_frame(s) < 0) {
+    if ((ret = decode_frame(s)) < 0) {
         av_log(s->avctx, AV_LOG_ERROR, "decode_frame() failed\n");
-        s->bitstream_size=0;
-        s->bitstream_index=0;
-        return -1;
+        return ret;
     }
     bytes_read = (get_bits_count(&s->gb)+7)/8;
 
-    /* check if allocated data size is large enough for output */
-    output_size = s->blocksize * s->channels * (s->is32 ? 4 : 2);
-    if (output_size > alloc_data_size) {
-        av_log(s->avctx, AV_LOG_ERROR, "output data size is larger than "
-                                       "allocated data size\n");
-        goto end;
-    }
-    *data_size = output_size;
-
-#define DECORRELATE(left, right)\
-            assert(s->channels == 2);\
-            for (i = 0; i < s->blocksize; i++) {\
-                int a= s->decoded[0][i];\
-                int b= s->decoded[1][i];\
-                if (s->is32) {\
-                    *samples_32++ = (left)  << s->sample_shift;\
-                    *samples_32++ = (right) << s->sample_shift;\
-                } else {\
-                    *samples_16++ = (left)  << s->sample_shift;\
-                    *samples_16++ = (right) << s->sample_shift;\
-                }\
-            }\
-            break;
-
-    switch (s->ch_mode) {
-    case FLAC_CHMODE_INDEPENDENT:
-        for (j = 0; j < s->blocksize; j++) {
-            for (i = 0; i < s->channels; i++) {
-                if (s->is32)
-                    *samples_32++ = s->decoded[i][j] << s->sample_shift;
-                else
-                    *samples_16++ = s->decoded[i][j] << s->sample_shift;
-            }
-        }
-        break;
-    case FLAC_CHMODE_LEFT_SIDE:
-        DECORRELATE(a,a-b)
-    case FLAC_CHMODE_RIGHT_SIDE:
-        DECORRELATE(a+b,b)
-    case FLAC_CHMODE_MID_SIDE:
-        DECORRELATE( (a-=b>>1) + b, a)
+    /* get output buffer */
+    frame->nb_samples = s->blocksize;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+        return ret;
     }
 
-end:
+    s->dsp.decorrelate[s->ch_mode](frame->data, s->decoded, s->channels,
+                                   s->blocksize, s->sample_shift);
+
     if (bytes_read > buf_size) {
         av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", bytes_read - buf_size);
-        s->bitstream_size=0;
-        s->bitstream_index=0;
-        return -1;
+        return AVERROR_INVALIDDATA;
+    }
+    if (bytes_read < buf_size) {
+        av_log(s->avctx, AV_LOG_DEBUG, "underread: %d orig size: %d\n",
+               buf_size - bytes_read, buf_size);
     }
 
-    if (s->bitstream_size) {
-        s->bitstream_index += bytes_read;
-        s->bitstream_size  -= bytes_read;
-        return input_buf_size;
-    } else
-        return bytes_read;
+    *got_frame_ptr = 1;
+
+    return bytes_read;
 }
 
 static av_cold int flac_decode_close(AVCodecContext *avctx)
 {
     FLACContext *s = avctx->priv_data;
-    int i;
 
-    for (i = 0; i < s->channels; i++) {
-        av_freep(&s->decoded[i]);
-    }
-    av_freep(&s->bitstream);
+    av_freep(&s->decoded_buffer);
 
     return 0;
 }
 
-static void flac_flush(AVCodecContext *avctx)
-{
-    FLACContext *s = avctx->priv_data;
-
-    s->bitstream_size=
-    s->bitstream_index= 0;
-}
-
-AVCodec flac_decoder = {
-    "flac",
-    AVMEDIA_TYPE_AUDIO,
-    CODEC_ID_FLAC,
-    sizeof(FLACContext),
-    flac_decode_init,
-    NULL,
-    flac_decode_close,
-    flac_decode_frame,
-    CODEC_CAP_DELAY | CODEC_CAP_SUBFRAMES, /* FIXME: add a FLAC parser so that
-                                              we will not need to use either
-                                              of these capabilities */
-    .flush= flac_flush,
-    .long_name= NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
+AVCodec ff_flac_decoder = {
+    .name           = "flac",
+    .long_name      = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_FLAC,
+    .priv_data_size = sizeof(FLACContext),
+    .init           = flac_decode_init,
+    .close          = flac_decode_close,
+    .decode         = flac_decode_frame,
+    .capabilities   = AV_CODEC_CAP_DR1,
+    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
+                                                      AV_SAMPLE_FMT_S16P,
+                                                      AV_SAMPLE_FMT_S32,
+                                                      AV_SAMPLE_FMT_S32P,
+                                                      -1 },
 };