blob: 48dcb4cb48231d1e5f8460c44efe62cb1bae0fdd [file] [log] [blame]
------------------------------------------------------------------------
r35228 | cigaes | 2012-10-04 15:04:42 -0300 (Thu, 04 Oct 2012) | 5 lines
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.
------------------------------------------------------------------------
Index: libmpcodecs/ad_ffmpeg.c
===================================================================
--- libmpcodecs/ad_ffmpeg.c (revision 35227)
+++ libmpcodecs/ad_ffmpeg.c (revision 35228)
@@ -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;
}