+static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
+{
+ AVCodecInternal *avci = avctx->internal;
+ InternalBuffer *buf;
+ int buf_size, ret, i, needs_extended_data;
+
+ buf_size = av_samples_get_buffer_size(NULL, avctx->channels,
+ frame->nb_samples, avctx->sample_fmt,
+ 32);
+ if (buf_size < 0)
+ return AVERROR(EINVAL);
+
+ needs_extended_data = av_sample_fmt_is_planar(avctx->sample_fmt) &&
+ avctx->channels > AV_NUM_DATA_POINTERS;
+
+ /* allocate InternalBuffer if needed */
+ if (!avci->buffer) {
+ avci->buffer = av_mallocz(sizeof(InternalBuffer));
+ if (!avci->buffer)
+ return AVERROR(ENOMEM);
+ }
+ buf = avci->buffer;
+
+ /* if there is a previously-used internal buffer, check its size and
+ channel count to see if we can reuse it */
+ if (buf->extended_data) {
+ /* if current buffer is too small, free it */
+ if (buf->extended_data[0] && buf_size > buf->audio_data_size) {
+ av_free(buf->extended_data[0]);
+ if (buf->extended_data != buf->data)
+ av_free(&buf->extended_data);
+ buf->extended_data = NULL;
+ buf->data[0] = NULL;
+ }
+ /* if number of channels has changed, reset and/or free extended data
+ pointers but leave data buffer in buf->data[0] for reuse */
+ if (buf->nb_channels != avctx->channels) {
+ if (buf->extended_data != buf->data)
+ av_free(buf->extended_data);
+ buf->extended_data = NULL;
+ }
+ }
+
+ /* if there is no previous buffer or the previous buffer cannot be used
+ as-is, allocate a new buffer and/or rearrange the channel pointers */
+ if (!buf->extended_data) {
+ /* if the channel pointers will fit, just set extended_data to data,
+ otherwise allocate the extended_data channel pointers */
+ if (needs_extended_data) {
+ buf->extended_data = av_mallocz(avctx->channels *
+ sizeof(*buf->extended_data));
+ if (!buf->extended_data)
+ return AVERROR(ENOMEM);
+ } else {
+ buf->extended_data = buf->data;
+ }
+
+ /* if there is a previous buffer and it is large enough, reuse it and
+ just fill-in new channel pointers and linesize, otherwise allocate
+ a new buffer */
+ if (buf->extended_data[0]) {
+ ret = av_samples_fill_arrays(buf->extended_data, &buf->linesize[0],
+ buf->extended_data[0], avctx->channels,
+ frame->nb_samples, avctx->sample_fmt,
+ 32);
+ } else {
+ ret = av_samples_alloc(buf->extended_data, &buf->linesize[0],
+ avctx->channels, frame->nb_samples,
+ avctx->sample_fmt, 32);
+ }
+ if (ret)
+ return ret;
+
+ /* if data was not used for extended_data, we need to copy as many of
+ the extended_data channel pointers as will fit */
+ if (needs_extended_data) {
+ for (i = 0; i < AV_NUM_DATA_POINTERS; i++)
+ buf->data[i] = buf->extended_data[i];
+ }
+ buf->audio_data_size = buf_size;
+ buf->nb_channels = avctx->channels;
+ }
+
+ /* copy InternalBuffer info to the AVFrame */
+ frame->type = FF_BUFFER_TYPE_INTERNAL;
+ frame->extended_data = buf->extended_data;
+ frame->linesize[0] = buf->linesize[0];
+ memcpy(frame->data, buf->data, sizeof(frame->data));
+
+ if (avctx->pkt) {
+ frame->pkt_pts = avctx->pkt->pts;
+ frame->pkt_pos = avctx->pkt->pos;
+ } else {
+ frame->pkt_pts = AV_NOPTS_VALUE;
+ frame->pkt_pos = -1;
+ }
+
+ frame->reordered_opaque = avctx->reordered_opaque;
+
+ if (avctx->debug & FF_DEBUG_BUFFERS)
+ av_log(avctx, AV_LOG_DEBUG, "default_get_buffer called on frame %p, "
+ "internal audio buffer used\n", frame);
+
+ return 0;
+}
+
+static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
+{