Merge svn changes up to r30694
[mplayer/glamo.git] / libmpcodecs / ad_dvdpcm.c
blob50593a8e70aa662aa037d4dfc00e30199a214857
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
23 #include "config.h"
24 #include "mp_msg.h"
25 #include "help_mp.h"
26 #include "ad_internal.h"
28 static const ad_info_t info =
30 "Uncompressed DVD/VOB LPCM audio decoder",
31 "dvdpcm",
32 "Nick Kurshev",
33 "A'rpi",
37 LIBAD_EXTERN(dvdpcm)
39 static int init(sh_audio_t *sh)
41 /* DVD PCM Audio:*/
42 sh->i_bps = 0;
43 if(sh->codecdata_len==3){
44 // we have LPCM header:
45 unsigned char h=sh->codecdata[1];
46 sh->channels=1+(h&7);
47 switch((h>>4)&3){
48 case 0: sh->samplerate=48000;break;
49 case 1: sh->samplerate=96000;break;
50 case 2: sh->samplerate=44100;break;
51 case 3: sh->samplerate=32000;break;
53 switch ((h >> 6) & 3) {
54 case 0:
55 sh->sample_format = AF_FORMAT_S16_BE;
56 sh->samplesize = 2;
57 break;
58 case 1:
59 mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Samples of this format are needed to improve support. Please contact the developers.\n");
60 sh->i_bps = sh->channels * sh->samplerate * 5 / 2;
61 case 2:
62 sh->sample_format = AF_FORMAT_S24_BE;
63 sh->samplesize = 3;
64 break;
65 default:
66 sh->sample_format = AF_FORMAT_S16_BE;
67 sh->samplesize = 2;
69 } else {
70 // use defaults:
71 sh->channels=2;
72 sh->samplerate=48000;
73 sh->sample_format = AF_FORMAT_S16_BE;
74 sh->samplesize = 2;
76 if (!sh->i_bps)
77 sh->i_bps = sh->samplesize * sh->channels * sh->samplerate;
78 return 1;
81 static int preinit(sh_audio_t *sh)
83 sh->audio_out_minsize=2048;
84 return 1;
87 static void uninit(sh_audio_t *sh)
91 static int control(sh_audio_t *sh,int cmd,void* arg, ...)
93 int skip;
94 switch(cmd)
96 case ADCTRL_SKIP_FRAME:
97 skip=sh->i_bps/16;
98 skip=skip&(~3);
99 demux_read_data(sh->ds,NULL,skip);
100 return CONTROL_TRUE;
102 return CONTROL_UNKNOWN;
105 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
107 int j,len;
108 if (sh_audio->samplesize == 3) {
109 if (((sh_audio->codecdata[1] >> 6) & 3) == 1) {
110 // 20 bit
111 // not sure if the "& 0xf0" and "<< 4" are the right way around
112 // can somebody clarify?
113 for (j = 0; j < minlen; j += 12) {
114 char tmp[10];
115 len = demux_read_data(sh_audio->ds, tmp, 10);
116 if (len < 10) break;
117 // first sample
118 buf[j + 0] = tmp[0];
119 buf[j + 1] = tmp[1];
120 buf[j + 2] = tmp[8] & 0xf0;
121 // second sample
122 buf[j + 3] = tmp[2];
123 buf[j + 4] = tmp[3];
124 buf[j + 5] = tmp[8] << 4;
125 // third sample
126 buf[j + 6] = tmp[4];
127 buf[j + 7] = tmp[5];
128 buf[j + 8] = tmp[9] & 0xf0;
129 // fourth sample
130 buf[j + 9] = tmp[6];
131 buf[j + 10] = tmp[7];
132 buf[j + 11] = tmp[9] << 4;
134 len = j;
135 } else {
136 // 24 bit
137 for (j = 0; j < minlen; j += 12) {
138 char tmp[12];
139 len = demux_read_data(sh_audio->ds, tmp, 12);
140 if (len < 12) break;
141 // first sample
142 buf[j + 0] = tmp[0];
143 buf[j + 1] = tmp[1];
144 buf[j + 2] = tmp[8];
145 // second sample
146 buf[j + 3] = tmp[2];
147 buf[j + 4] = tmp[3];
148 buf[j + 5] = tmp[9];
149 // third sample
150 buf[j + 6] = tmp[4];
151 buf[j + 7] = tmp[5];
152 buf[j + 8] = tmp[10];
153 // fourth sample
154 buf[j + 9] = tmp[6];
155 buf[j + 10] = tmp[7];
156 buf[j + 11] = tmp[11];
158 len = j;
160 } else
161 len=demux_read_data(sh_audio->ds,buf,(minlen+3)&(~3));
162 return len;