Mercurial > mplayer.hg
changeset 35134:2b037cee0795
ad_ffmpeg: basic support for planar formats.
Upgrade to avcodec_decode_audio4().
Planar formats are immediately converted to packet formats.
A lot of optimizations are still possible.
author | cigaes |
---|---|
date | Thu, 04 Oct 2012 18:04:42 +0000 |
parents | 816fffbf8647 |
children | 6f635f9d2404 |
files | libmpcodecs/ad_ffmpeg.c |
diffstat | 1 files changed, 72 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpcodecs/ad_ffmpeg.c Wed Oct 03 10:19:31 2012 +0000 +++ b/libmpcodecs/ad_ffmpeg.c Thu Oct 04 18:04:42 2012 +0000 @@ -57,7 +57,7 @@ { int broken_srate = 0; int samplerate = lavc_context->sample_rate; - int sample_format = samplefmt2affmt(lavc_context->sample_fmt); + int sample_format = samplefmt2affmt(av_get_packed_sample_fmt(lavc_context->sample_fmt)); if (!sample_format) sample_format = sh_audio->sample_format; if(sh_audio->wf){ @@ -169,10 +169,10 @@ sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; switch (lavc_context->sample_fmt) { - case AV_SAMPLE_FMT_U8: - case AV_SAMPLE_FMT_S16: - case AV_SAMPLE_FMT_S32: - case AV_SAMPLE_FMT_FLT: + case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: + case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S16P: + case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_S32P: + case AV_SAMPLE_FMT_FLT: case AV_SAMPLE_FMT_FLTP: break; default: return 0; @@ -202,10 +202,68 @@ return CONTROL_UNKNOWN; } +static av_always_inline void copy_samples_planar(unsigned bps, + unsigned nb_samples, + unsigned nb_channels, + unsigned char *dst, + unsigned char **src) +{ + unsigned s, c, o = 0; + + for (s = 0; s < nb_samples; s++) { + for (c = 0; c < nb_channels; c++) { + memcpy(dst, src[c] + o, bps); + dst += bps; + } + o += bps; + } +} + +static int copy_samples(AVCodecContext *avc, AVFrame *frame, + unsigned char *buf, int max_size) +{ + int channels = avc->channels; + int sample_size = av_get_bytes_per_sample(avc->sample_fmt); + int size = channels * sample_size * frame->nb_samples; + + if (size > max_size) { + av_log(avc, AV_LOG_ERROR, + "Buffer overflow while decoding a single frame\n"); + return AVERROR(EINVAL); /* same as avcodec_decode_audio3 */ + } + /* TODO reorder channels at the same time */ + if (av_sample_fmt_is_planar(avc->sample_fmt)) { + switch (sample_size) { + case 1: + copy_samples_planar(1, frame->nb_samples, channels, + buf, frame->extended_data); + break; + case 2: + copy_samples_planar(2, frame->nb_samples, channels, + buf, frame->extended_data); + break; + case 4: + copy_samples_planar(4, frame->nb_samples, channels, + buf, frame->extended_data); + default: + copy_samples_planar(sample_size, frame->nb_samples, channels, + buf, frame->extended_data); + } + } else { + memcpy(buf, frame->data[0], size); + } + return size; +} + static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) { unsigned char *start=NULL; - int y,len=-1; + int y,len=-1, got_frame; + AVFrame *frame = avcodec_alloc_frame(); + + if (!frame) + return AVERROR(ENOMEM); + while(len<minlen){ AVPacket pkt; int len2=maxlen; @@ -230,7 +288,7 @@ sh_audio->pts = pts; sh_audio->pts_bytes = 0; } - y=avcodec_decode_audio3(sh_audio->context,(int16_t*)buf,&len2,&pkt); + y=avcodec_decode_audio4(sh_audio->context, frame, &got_frame, &pkt); //printf("return:%d samples_out:%d bitstream_in:%d sample_sum:%d\n", y, len2, x, len); fflush(stdout); // LATM may need many packets to find mux info if (y == AVERROR(EAGAIN)) @@ -238,6 +296,11 @@ if(y<0){ mp_msg(MSGT_DECAUDIO,MSGL_V,"lavc_audio: error\n");break; } if(!sh_audio->parser && y<x) sh_audio->ds->buffer_pos+=y-x; // put back data (HACK!) + if (!got_frame) + continue; + len2 = copy_samples(sh_audio->context, frame, buf, maxlen); + if (len2 < 0) + return len2; if(len2>0){ if (((AVCodecContext *)sh_audio->context)->channels >= 5) { int samplesize = av_get_bytes_per_sample(((AVCodecContext *) @@ -258,5 +321,7 @@ if (setup_format(sh_audio, sh_audio->context)) break; } + + av_free(frame); return len; }