From c8154630bfc1b35da59e7db8c09e85c4f8d5904c Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 8 Sep 2012 12:05:13 +0200 Subject: 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. --- Makefile | 1 + etc/codecs.conf | 6 ++ libmpcodecs/ad.c | 2 + libmpcodecs/ad_dvdpcm.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 libmpcodecs/ad_dvdpcm.c diff --git a/Makefile b/Makefile index 863eeb4b85..879d496964 100644 --- a/Makefile +++ b/Makefile @@ -142,6 +142,7 @@ SRCS_COMMON = asxparser.c \ libmpcodecs/ad.c \ libmpcodecs/ad_ffmpeg.c \ libmpcodecs/ad_pcm.c \ + libmpcodecs/ad_dvdpcm.c \ libmpcodecs/ad_spdif.c \ libmpcodecs/dec_audio.c \ libmpcodecs/dec_video.c \ diff --git a/etc/codecs.conf b/etc/codecs.conf index 0b2fcb793e..ab9267c5a9 100644 --- a/etc/codecs.conf +++ b/etc/codecs.conf @@ -1972,6 +1972,12 @@ audiocodec libgsmms driver ffmpeg dll "libgsm_ms" +audiocodec dvdpcm + info "Uncompressed DVD/VOB LPCM" + status working + format 0x10001 + driver dvdpcm + audiocodec fflpcm info "Blu-ray LPCM" status working 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 +#include +#include + +#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; +} -- cgit v1.2.3