Add support for VDPAU video out, including hardware decoding.
[mplayer/glamo.git] / libao2 / ao_mpegpes.c
blob38f30b1c1680bdda4334320dd1b4f57202486180
1 /*
2 * MPEG-PES audio output driver
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <inttypes.h>
29 #include <errno.h>
31 #include "config.h"
33 #ifdef CONFIG_DVB
34 #include <poll.h>
35 #include <sys/ioctl.h>
36 #endif
38 #include "audio_out.h"
39 #include "audio_out_internal.h"
41 #include "libaf/af_format.h"
42 #include "libmpdemux/mpeg_packetizer.h"
43 #include "subopt-helper.h"
45 #include "mp_msg.h"
46 #include "help_mp.h"
48 #ifdef CONFIG_DVB
49 #ifndef CONFIG_DVB_HEAD
50 #include <ost/audio.h>
51 audioMixer_t dvb_mixer={255,255};
52 #else
53 #include <linux/dvb/audio.h>
54 audio_mixer_t dvb_mixer={255,255};
55 #endif
56 #endif
58 #define true 1
59 #define false 0
61 extern int vo_mpegpes_fd;
62 int vo_mpegpes_fd2 = -1;
64 #include <errno.h>
66 static ao_info_t info =
68 #ifdef CONFIG_DVB
69 "DVB audio output",
70 #else
71 "MPEG-PES audio output",
72 #endif
73 "mpegpes",
74 "A'rpi",
78 LIBAO_EXTERN(mpegpes)
81 // to set/get/query special features/parameters
82 static int control(int cmd,void *arg){
83 #ifdef CONFIG_DVB
84 switch(cmd){
85 case AOCONTROL_GET_VOLUME:
86 if(vo_mpegpes_fd2>=0){
87 ((ao_control_vol_t*)(arg))->left=dvb_mixer.volume_left/2.56;
88 ((ao_control_vol_t*)(arg))->right=dvb_mixer.volume_right/2.56;
89 return CONTROL_OK;
91 return CONTROL_ERROR;
92 case AOCONTROL_SET_VOLUME:
93 if(vo_mpegpes_fd2>=0){
94 dvb_mixer.volume_left=((ao_control_vol_t*)(arg))->left*2.56;
95 dvb_mixer.volume_right=((ao_control_vol_t*)(arg))->right*2.56;
96 if(dvb_mixer.volume_left>255) dvb_mixer.volume_left=255;
97 if(dvb_mixer.volume_right>255) dvb_mixer.volume_right=255;
98 // printf("Setting DVB volume: %d ; %d \n",dvb_mixer.volume_left,dvb_mixer.volume_right);
99 if ( (ioctl(vo_mpegpes_fd2,AUDIO_SET_MIXER, &dvb_mixer) < 0)){
100 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_MPEGPES_CantSetMixer,
101 strerror(errno));
102 return CONTROL_ERROR;
104 return CONTROL_OK;
106 return CONTROL_ERROR;
108 #endif
109 return CONTROL_UNKNOWN;
112 static int freq=0;
113 static int freq_id=0;
115 #ifdef CONFIG_DVB
116 static int init_device(int card)
118 char ao_file[30];
119 #ifndef CONFIG_DVB_HEAD
120 mp_msg(MSGT_VO,MSGL_INFO, "Opening /dev/ost/audio\n");
121 sprintf(ao_file, "/dev/ost/audio");
122 #else
123 mp_msg(MSGT_VO,MSGL_INFO, "Opening /dev/dvb/adapter%d/audio0\n", card);
124 sprintf(ao_file, "/dev/dvb/adapter%d/audio0", card);
125 #endif
126 if((vo_mpegpes_fd2 = open(ao_file,O_RDWR|O_NONBLOCK)) < 0)
128 mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO DEVICE: %s\n", strerror(errno));
129 return -1;
131 if( (ioctl(vo_mpegpes_fd2,AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY) < 0))
133 mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO SELECT SOURCE: %s\n", strerror(errno));
134 return -1;
136 if((ioctl(vo_mpegpes_fd2,AUDIO_PLAY) < 0))
138 mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO PLAY: %s\n", strerror(errno));
139 return -1;
141 if((ioctl(vo_mpegpes_fd2,AUDIO_SET_AV_SYNC, true) < 0))
143 mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO SET AV SYNC: %s\n", strerror(errno));
144 return -1;
146 //FIXME: in vo_mpegpes audio was initialized as MUTEd
147 if((ioctl(vo_mpegpes_fd2,AUDIO_SET_MUTE, false) < 0))
149 mp_msg(MSGT_VO, MSGL_ERR, "DVB AUDIO SET MUTE: %s\n", strerror(errno));
150 return -1;
152 return vo_mpegpes_fd2;
154 #endif
156 static int preinit(const char *arg)
158 int card = -1;
159 char *ao_file = NULL;
161 opt_t subopts[] = {
162 {"card", OPT_ARG_INT, &card, NULL},
163 {"file", OPT_ARG_MSTRZ, &ao_file, NULL},
164 {NULL}
167 if(subopt_parse(ao_subdevice, subopts) != 0)
169 mp_msg(MSGT_VO, MSGL_ERR, "AO_MPEGPES, Unrecognized options\n");
170 return -1;
172 if(card==-1)
174 //search the first usable card
175 int n;
176 char file[30];
177 for(n=0; n<4; n++)
179 sprintf(file, "/dev/dvb/adapter%d/audio0", n);
180 if(access(file, F_OK | W_OK)==0)
182 card = n+1;
183 break;
187 if((card < 1) || (card > 4))
189 mp_msg(MSGT_VO, MSGL_ERR, "DVB card number must be between 1 and 4\n");
190 return -1;
192 card--;
194 #ifdef CONFIG_DVB
195 if(!ao_file)
196 return init_device(card);
197 #else
198 if(!ao_file)
199 return vo_mpegpes_fd; //video fd
200 #endif
202 vo_mpegpes_fd2=open(ao_file,O_WRONLY|O_CREAT,0666);
203 if(vo_mpegpes_fd2<0)
205 mp_msg(MSGT_VO, MSGL_ERR, "ao_mpegpes: %s\n", strerror(errno));
206 return -1;
208 return vo_mpegpes_fd2;
211 static int my_ao_write(unsigned char* data,int len){
212 int orig_len = len;
213 #ifdef CONFIG_DVB
214 #define NFD 1
215 struct pollfd pfd[NFD];
217 pfd[0].fd = vo_mpegpes_fd2;
218 pfd[0].events = POLLOUT;
220 while(len>0){
221 if(poll(pfd,NFD,1)){
222 if(pfd[0].revents & POLLOUT){
223 int ret=write(vo_mpegpes_fd2,data,len);
224 if(ret<=0){
225 mp_msg(MSGT_VO, MSGL_ERR, "ao_mpegpes write: %s\n", strerror(errno));
226 usleep(0);
227 } else {
228 len-=ret;
229 data+=ret;
231 } else usleep(1000);
235 #else
236 if(vo_mpegpes_fd2<0) return 0; // no file
237 write(vo_mpegpes_fd2,data,len); // write to file
238 #endif
239 return orig_len;
243 // open & setup audio device
244 // return: 1=success 0=fail
245 static int init(int rate,int channels,int format,int flags){
246 if(preinit(NULL)<0) return 0;
248 ao_data.channels=2;
249 ao_data.outburst=2000;
250 switch(format){
251 case AF_FORMAT_S16_BE:
252 case AF_FORMAT_MPEG2:
253 case AF_FORMAT_AC3:
254 ao_data.format=format;
255 break;
256 default:
257 ao_data.format=AF_FORMAT_S16_BE;
260 switch(rate){
261 case 48000: freq_id=0;break;
262 case 96000: freq_id=1;break;
263 case 44100: freq_id=2;break;
264 case 32000: freq_id=3;break;
265 default:
266 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_MPEGPES_UnsupSamplerate, rate);
267 #if 0
268 if(rate>48000) rate=96000; else
269 if(rate>44100) rate=48000; else
270 if(rate>32000) rate=44100; else
271 rate=32000;
272 goto retry;
273 #else
274 rate=48000; freq_id=0;
275 #endif
278 ao_data.bps=rate*2*2;
279 freq=ao_data.samplerate=rate;
281 return 1;
284 // close audio device
285 static void uninit(int immed){
289 // stop playing and empty buffers (for seeking/pause)
290 static void reset(void){
294 // stop playing, keep buffers (for pause)
295 static void audio_pause(void)
297 // for now, just call reset();
298 reset();
301 // resume playing, after audio_pause()
302 static void audio_resume(void)
306 void send_pes_packet(unsigned char* data,int len,int id,int timestamp);
307 void send_lpcm_packet(unsigned char* data,int len,int id,int timestamp,int freq_id);
308 extern int vo_pts;
310 // return: how many bytes can be played without blocking
311 static int get_space(void){
312 float x=(float)(vo_pts-ao_data.pts)/90000.0;
313 int y;
314 //FIXME: is it correct?
315 if(vo_mpegpes_fd < 0) return 32000; //not using -vo mpegpes
316 // printf("vo_pts: %5.3f ao_pts: %5.3f\n",vo_pts/90000.0,ao_data.pts/90000.0);
317 if(x<=0) return 0;
318 y=freq*4*x;y/=ao_data.outburst;y*=ao_data.outburst;
319 if(y>32000) y=32000;
320 // printf("diff: %5.3f -> %d \n",x,y);
321 return y;
324 // plays 'len' bytes of 'data'
325 // it should round it down to outburst*n
326 // return: number of bytes played
327 static int play(void* data,int len,int flags){
328 // printf("\nao_mpegpes: play(%d) freq=%d\n",len,freq_id);
329 if(ao_data.format==AF_FORMAT_MPEG2)
330 send_mpeg_pes_packet (data, len, 0x1C0, ao_data.pts, 1, my_ao_write);
331 else {
332 int i;
333 unsigned short *s=data;
334 // if(len>2000) len=2000;
335 // printf("ao_mpegpes: len=%d \n",len);
336 if(ao_data.format==AF_FORMAT_AC3)
337 for(i=0;i<len/2;i++) s[i]=(s[i]>>8)|(s[i]<<8); // le<->be
338 send_mpeg_lpcm_packet(data, len, 0xA0, ao_data.pts, freq_id, my_ao_write);
340 return len;
343 // return: delay in seconds between first and last sample in buffer
344 static float get_delay(void){
346 return 0.0;