diff options
author | wm4 <wm4@nowhere> | 2012-09-08 12:05:13 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-09-18 21:08:14 +0200 |
commit | c8154630bfc1b35da59e7db8c09e85c4f8d5904c (patch) | |
tree | c59946e0495590c2c94f0387e00c60a56aab9286 /libmpcodecs | |
parent | 70e7d63ba011a326f5e03137b8fb45df222c43af (diff) |
ad_dvdpcm: add back PCM decoder for DVD
This is needed by demux_mpg (and possibly by demux_ts) for PCM playback.
The decoder does the mapping from MPEG headers to the actual PCM format,
and also unpacks sample data for 20/24 bit formats.
Diffstat (limited to 'libmpcodecs')
-rw-r--r-- | libmpcodecs/ad.c | 2 | ||||
-rw-r--r-- | libmpcodecs/ad_dvdpcm.c | 162 |
2 files changed, 164 insertions, 0 deletions
diff --git a/libmpcodecs/ad.c b/libmpcodecs/ad.c index c4066caaa4..93cebed86d 100644 --- a/libmpcodecs/ad.c +++ b/libmpcodecs/ad.c @@ -34,6 +34,7 @@ extern const ad_functions_t mpcodecs_ad_mpg123; extern const ad_functions_t mpcodecs_ad_ffmpeg; extern const ad_functions_t mpcodecs_ad_pcm; +extern const ad_functions_t mpcodecs_ad_dvdpcm; extern const ad_functions_t mpcodecs_ad_spdif; const ad_functions_t * const mpcodecs_ad_drivers[] = @@ -43,6 +44,7 @@ const ad_functions_t * const mpcodecs_ad_drivers[] = #endif &mpcodecs_ad_ffmpeg, &mpcodecs_ad_pcm, + &mpcodecs_ad_dvdpcm, &mpcodecs_ad_spdif, NULL }; diff --git a/libmpcodecs/ad_dvdpcm.c b/libmpcodecs/ad_dvdpcm.c new file mode 100644 index 0000000000..41f6a1426d --- /dev/null +++ b/libmpcodecs/ad_dvdpcm.c @@ -0,0 +1,162 @@ +/* + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "config.h" +#include "mp_msg.h" +#include "ad_internal.h" + +static const ad_info_t info = +{ + "Uncompressed DVD/VOB LPCM audio decoder", + "dvdpcm", + "Nick Kurshev", + "A'rpi", + "" +}; + +LIBAD_EXTERN(dvdpcm) + +static int init(sh_audio_t *sh) +{ +/* DVD PCM Audio:*/ + sh->i_bps = 0; + if(sh->codecdata_len==3){ + // we have LPCM header: + unsigned char h=sh->codecdata[1]; + sh->channels=1+(h&7); + switch((h>>4)&3){ + case 0: sh->samplerate=48000;break; + case 1: sh->samplerate=96000;break; + case 2: sh->samplerate=44100;break; + case 3: sh->samplerate=32000;break; + } + switch ((h >> 6) & 3) { + case 0: + sh->sample_format = AF_FORMAT_S16_BE; + sh->samplesize = 2; + break; + case 1: + mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Samples of this format are needed to improve support. Please contact the developers.\n"); + sh->i_bps = sh->channels * sh->samplerate * 5 / 2; + case 2: + sh->sample_format = AF_FORMAT_S24_BE; + sh->samplesize = 3; + break; + default: + sh->sample_format = AF_FORMAT_S16_BE; + sh->samplesize = 2; + } + } else { + // use defaults: + sh->channels=2; + sh->samplerate=48000; + sh->sample_format = AF_FORMAT_S16_BE; + sh->samplesize = 2; + } + if (!sh->i_bps) + sh->i_bps = sh->samplesize * sh->channels * sh->samplerate; + return 1; +} + +static int preinit(sh_audio_t *sh) +{ + sh->audio_out_minsize=2048; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + int skip; + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + skip=sh->i_bps/16; + skip=skip&(~3); + demux_read_data(sh->ds,NULL,skip); + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + int j,len; + if (sh_audio->samplesize == 3) { + if (((sh_audio->codecdata[1] >> 6) & 3) == 1) { + // 20 bit + // not sure if the "& 0xf0" and "<< 4" are the right way around + // can somebody clarify? + for (j = 0; j < minlen; j += 12) { + char tmp[10]; + len = demux_read_data(sh_audio->ds, tmp, 10); + if (len < 10) break; + // first sample + buf[j + 0] = tmp[0]; + buf[j + 1] = tmp[1]; + buf[j + 2] = tmp[8] & 0xf0; + // second sample + buf[j + 3] = tmp[2]; + buf[j + 4] = tmp[3]; + buf[j + 5] = tmp[8] << 4; + // third sample + buf[j + 6] = tmp[4]; + buf[j + 7] = tmp[5]; + buf[j + 8] = tmp[9] & 0xf0; + // fourth sample + buf[j + 9] = tmp[6]; + buf[j + 10] = tmp[7]; + buf[j + 11] = tmp[9] << 4; + } + len = j; + } else { + // 24 bit + for (j = 0; j < minlen; j += 12) { + char tmp[12]; + len = demux_read_data(sh_audio->ds, tmp, 12); + if (len < 12) break; + // first sample + buf[j + 0] = tmp[0]; + buf[j + 1] = tmp[1]; + buf[j + 2] = tmp[8]; + // second sample + buf[j + 3] = tmp[2]; + buf[j + 4] = tmp[3]; + buf[j + 5] = tmp[9]; + // third sample + buf[j + 6] = tmp[4]; + buf[j + 7] = tmp[5]; + buf[j + 8] = tmp[10]; + // fourth sample + buf[j + 9] = tmp[6]; + buf[j + 10] = tmp[7]; + buf[j + 11] = tmp[11]; + } + len = j; + } + } else + len=demux_read_data(sh_audio->ds,buf,(minlen+3)&(~3)); + return len; +} |