spudec.c: minor improvements
[mplayer/glamo.git] / libmpcodecs / ad_dvdpcm.c
blob41f6a1426d0e79a7a54fde5c34dc7ebd7feb585c
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 "ad_internal.h"
27 static const ad_info_t info =
29 "Uncompressed DVD/VOB LPCM audio decoder",
30 "dvdpcm",
31 "Nick Kurshev",
32 "A'rpi",
36 LIBAD_EXTERN(dvdpcm)
38 static int init(sh_audio_t *sh)
40 /* DVD PCM Audio:*/
41 sh->i_bps = 0;
42 if(sh->codecdata_len==3){
43 // we have LPCM header:
44 unsigned char h=sh->codecdata[1];
45 sh->channels=1+(h&7);
46 switch((h>>4)&3){
47 case 0: sh->samplerate=48000;break;
48 case 1: sh->samplerate=96000;break;
49 case 2: sh->samplerate=44100;break;
50 case 3: sh->samplerate=32000;break;
52 switch ((h >> 6) & 3) {
53 case 0:
54 sh->sample_format = AF_FORMAT_S16_BE;
55 sh->samplesize = 2;
56 break;
57 case 1:
58 mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Samples of this format are needed to improve support. Please contact the developers.\n");
59 sh->i_bps = sh->channels * sh->samplerate * 5 / 2;
60 case 2:
61 sh->sample_format = AF_FORMAT_S24_BE;
62 sh->samplesize = 3;
63 break;
64 default:
65 sh->sample_format = AF_FORMAT_S16_BE;
66 sh->samplesize = 2;
68 } else {
69 // use defaults:
70 sh->channels=2;
71 sh->samplerate=48000;
72 sh->sample_format = AF_FORMAT_S16_BE;
73 sh->samplesize = 2;
75 if (!sh->i_bps)
76 sh->i_bps = sh->samplesize * sh->channels * sh->samplerate;
77 return 1;
80 static int preinit(sh_audio_t *sh)
82 sh->audio_out_minsize=2048;
83 return 1;
86 static void uninit(sh_audio_t *sh)
90 static int control(sh_audio_t *sh,int cmd,void* arg, ...)
92 int skip;
93 switch(cmd)
95 case ADCTRL_SKIP_FRAME:
96 skip=sh->i_bps/16;
97 skip=skip&(~3);
98 demux_read_data(sh->ds,NULL,skip);
99 return CONTROL_TRUE;
101 return CONTROL_UNKNOWN;
104 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
106 int j,len;
107 if (sh_audio->samplesize == 3) {
108 if (((sh_audio->codecdata[1] >> 6) & 3) == 1) {
109 // 20 bit
110 // not sure if the "& 0xf0" and "<< 4" are the right way around
111 // can somebody clarify?
112 for (j = 0; j < minlen; j += 12) {
113 char tmp[10];
114 len = demux_read_data(sh_audio->ds, tmp, 10);
115 if (len < 10) break;
116 // first sample
117 buf[j + 0] = tmp[0];
118 buf[j + 1] = tmp[1];
119 buf[j + 2] = tmp[8] & 0xf0;
120 // second sample
121 buf[j + 3] = tmp[2];
122 buf[j + 4] = tmp[3];
123 buf[j + 5] = tmp[8] << 4;
124 // third sample
125 buf[j + 6] = tmp[4];
126 buf[j + 7] = tmp[5];
127 buf[j + 8] = tmp[9] & 0xf0;
128 // fourth sample
129 buf[j + 9] = tmp[6];
130 buf[j + 10] = tmp[7];
131 buf[j + 11] = tmp[9] << 4;
133 len = j;
134 } else {
135 // 24 bit
136 for (j = 0; j < minlen; j += 12) {
137 char tmp[12];
138 len = demux_read_data(sh_audio->ds, tmp, 12);
139 if (len < 12) break;
140 // first sample
141 buf[j + 0] = tmp[0];
142 buf[j + 1] = tmp[1];
143 buf[j + 2] = tmp[8];
144 // second sample
145 buf[j + 3] = tmp[2];
146 buf[j + 4] = tmp[3];
147 buf[j + 5] = tmp[9];
148 // third sample
149 buf[j + 6] = tmp[4];
150 buf[j + 7] = tmp[5];
151 buf[j + 8] = tmp[10];
152 // fourth sample
153 buf[j + 9] = tmp[6];
154 buf[j + 10] = tmp[7];
155 buf[j + 11] = tmp[11];
157 len = j;
159 } else
160 len=demux_read_data(sh_audio->ds,buf,(minlen+3)&(~3));
161 return len;