1 // Don't change for DVB card, it must be 2048
2 #define PES_MAX_SIZE 2048
7 * test_av.c - Test program for new API
9 * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
10 * & Marcus Metzler <marcus@convergence.de>
11 * for convergence integrated media GmbH
13 * libav - MPEG-PS multiplexer, part of ffmpeg
14 * Copyright Gerard Lantau (see http://ffmpeg.sf.net)
23 #include <sys/types.h>
36 #include <sys/ioctl.h>
41 #include <ost/frontend.h>
43 #include <ost/video.h>
44 #include <ost/audio.h>
51 #include <sys/ioctl.h>
55 #include <linux/dvb/dmx.h>
56 #include <linux/dvb/frontend.h>
57 #include <linux/dvb/video.h>
58 #include <linux/dvb/audio.h>
63 #include "video_out.h"
64 #include "video_out_internal.h"
67 int vo_mpegpes_fd2
=-1;
69 static vo_info_t info
=
72 "Mpeg-PES to DVB card",
81 LIBVO_EXTERN (mpegpes
)
84 config(uint32_t s_width
, uint32_t s_height
, uint32_t width
, uint32_t height
, uint32_t flags
, char *title
, uint32_t format
)
94 mp_msg(MSGT_VO
,MSGL_ERR
,"DVB: height=%d not supported (try 240/480 (ntsc) or 288/576 (pal)\n",s_height
);
101 static int preinit(const char *arg
){
104 char vo_file
[30], ao_file
[30], *tmp
;
107 if((tmp
= strstr(arg
, "card=")) != NULL
) {
108 card
= atoi(&tmp
[5]);
109 if((card
< 1) || (card
> 4)) {
110 mp_msg(MSGT_VO
, MSGL_ERR
, "DVB card number must be between 1 and 4\n");
120 #ifndef HAVE_DVB_HEAD
121 mp_msg(MSGT_VO
,MSGL_INFO
, "Opening /dev/ost/video+audio\n");
122 sprintf(vo_file
, "/dev/ost/video");
123 sprintf(ao_file
, "/dev/ost/audio");
125 mp_msg(MSGT_VO
,MSGL_INFO
, "Opening /dev/dvb/adapter%d/video0+audio0\n", card
);
126 sprintf(vo_file
, "/dev/dvb/adapter%d/video0", card
);
127 sprintf(ao_file
, "/dev/dvb/adapter%d/audio0", card
);
129 if((vo_mpegpes_fd
= open(vo_file
,O_RDWR
)) < 0){
130 perror("DVB VIDEO DEVICE: ");
133 if((vo_mpegpes_fd2
= open(ao_file
,O_RDWR
|O_NONBLOCK
)) < 0){
134 perror("DVB AUDIO DEVICE: ");
137 if ( (ioctl(vo_mpegpes_fd
,VIDEO_SET_BLANK
, false) < 0)){
138 perror("DVB VIDEO SET BLANK: ");
141 if ( (ioctl(vo_mpegpes_fd
,VIDEO_SELECT_SOURCE
, VIDEO_SOURCE_MEMORY
) < 0)){
142 perror("DVB VIDEO SELECT SOURCE: ");
146 if ( (ioctl(vo_mpegpes_fd2
,AUDIO_SELECT_SOURCE
, AUDIO_SOURCE_MEMORY
) < 0)){
147 perror("DVB AUDIO SELECT SOURCE: ");
150 if ( (ioctl(vo_mpegpes_fd2
,AUDIO_PLAY
) < 0)){
151 perror("DVB AUDIO PLAY: ");
155 if ( (ioctl(vo_mpegpes_fd2
,AUDIO_STOP
,0) < 0)){
156 perror("DVB AUDIO STOP: ");
160 if ( (ioctl(vo_mpegpes_fd
,VIDEO_PLAY
) < 0)){
161 perror("DVB VIDEO PLAY: ");
164 if ( (ioctl(vo_mpegpes_fd2
,AUDIO_SET_AV_SYNC
, true) < 0)){
165 perror("DVB AUDIO SET AV SYNC: ");
168 // if ( (ioctl(vo_mpegpes_fd2,AUDIO_SET_MUTE, false) < 0)){
169 if ( (ioctl(vo_mpegpes_fd2
,AUDIO_SET_MUTE
, true) < 0)){
170 perror("DVB AUDIO SET MUTE: ");
176 arg
= (arg
? arg
: "grab.mpg");
177 mp_msg(MSGT_VO
,MSGL_INFO
, "Saving PES stream to %s\n", arg
);
178 vo_mpegpes_fd
=open(arg
,O_WRONLY
|O_CREAT
,0666);
180 perror("vo_mpegpes");
183 vo_mpegpes_fd2
=vo_mpegpes_fd
;
188 static void draw_osd(void)
193 static void my_write(unsigned char* data
,int len
){
196 struct pollfd pfd
[NFD
];
198 // printf("write %d bytes \n",len);
200 pfd
[0].fd
= vo_mpegpes_fd
;
201 pfd
[0].events
= POLLOUT
;
203 pfd
[1].fd
= vo_mpegpes_fd2
;
204 pfd
[1].events
= POLLOUT
;
207 if (poll(pfd
,NFD
,1)){
208 if (pfd
[0].revents
& POLLOUT
){
209 int ret
=write(vo_mpegpes_fd
,data
,len
);
210 // printf("ret=%d \n",ret);
222 write(vo_mpegpes_fd
,data
,len
); // write to file
226 static unsigned char pes_header
[PES_MAX_SIZE
];
228 void send_pes_packet(unsigned char* data
,int len
,int id
,int timestamp
){
229 int ptslen
=timestamp
?5:1;
232 pes_header
[0]=pes_header
[1]=0;
233 pes_header
[2]=id
>>8; pes_header
[3]=id
&255;
236 int payload_size
=len
; // data + PTS
237 if(6+ptslen
+payload_size
>PES_MAX_SIZE
) payload_size
=PES_MAX_SIZE
-(6+ptslen
);
239 // construct PES header: (code from ffmpeg's libav)
241 pes_header
[4]=(ptslen
+payload_size
)>>8;
242 pes_header
[5]=(ptslen
+payload_size
)&255;
246 // presentation time stamp:
247 x
=(0x02 << 4) | (((timestamp
>> 30) & 0x07) << 1) | 1;
249 x
=((((timestamp
>> 15) & 0x7fff) << 1) | 1);
250 pes_header
[7]=x
>>8; pes_header
[8]=x
&255;
251 x
=((((timestamp
) & 0x7fff) << 1) | 1);
252 pes_header
[9]=x
>>8; pes_header
[10]=x
&255;
254 // stuffing and header bits:
258 memcpy(&pes_header
[6+ptslen
],data
,payload_size
);
259 my_write(pes_header
,6+ptslen
+payload_size
);
261 len
-=payload_size
; data
+=payload_size
;
262 ptslen
=1; // store PTS only once, at first packet!
265 // printf("PES: draw frame! pts=%d size=%d \n",timestamp,len);
269 void send_lpcm_packet(unsigned char* data
,int len
,int id
,unsigned int timestamp
,int freq_id
){
271 int ptslen
=timestamp
?5:0;
274 pes_header
[0]=pes_header
[1]=0;
275 pes_header
[2]=1; pes_header
[3]=0xBD;
280 payload_size
=PES_MAX_SIZE
-6-20; // max possible data len
281 if(payload_size
>len
) payload_size
=len
;
282 payload_size
&=(~3); // align!
284 //if(6+payload_size>PES_MAX_SIZE) payload_size=PES_MAX_SIZE-6;
287 pes_header
[4]=(payload_size
+3+ptslen
+7)>>8;
288 pes_header
[5]=(payload_size
+3+ptslen
+7)&255;
291 // TTCCxxxx CC=css TT=type: 1=STD 0=mpeg1 2=vob
294 // FFxxxxxx FF=pts flags=2 vs 0
295 pes_header
[7]=ptslen
? 0x80 : 0;
298 pes_header
[8]=ptslen
;
302 // presentation time stamp:
303 x
=(0x02 << 4) | (((timestamp
>> 30) & 0x07) << 1) | 1;
305 x
=((((timestamp
>> 15) & 0x7fff) << 1) | 1);
306 pes_header
[10]=x
>>8; pes_header
[11]=x
&255;
307 x
=((((timestamp
) & 0x7fff) << 1) | 1);
308 pes_header
[12]=x
>>8; pes_header
[13]=x
&255;
311 // ============ LPCM header: (7 bytes) =================
312 // Info by mocm@convergence.de
315 pes_header
[ptslen
+9]=id
;
318 pes_header
[ptslen
+10]=0x07;
320 // first acces unit pointer, i.e. start of audio frame:
321 pes_header
[ptslen
+11]=0x00;
322 pes_header
[ptslen
+12]=0x04;
324 // audio emphasis on-off 1 bit
325 // audio mute on-off 1 bit
327 // audio frame number 5 bit
328 pes_header
[ptslen
+13]=0x0C;
330 // quantization word length 2 bit
331 // audio sampling frequency (48khz = 0, 96khz = 1) 2 bit
333 // number of audio channels - 1 (e.g. stereo = 1) 3 bit
334 pes_header
[ptslen
+14]=1|(freq_id
<<4);
336 // dynamic range control (0x80 if off)
337 pes_header
[ptslen
+15]=0x80;
339 memcpy(&pes_header
[6+3+ptslen
+7],data
,payload_size
);
340 my_write(pes_header
,6+3+ptslen
+7+payload_size
);
342 len
-=payload_size
; data
+=payload_size
;
343 ptslen
=0; // store PTS only once, at first packet!
346 // printf("PES: draw frame! pts=%d size=%d \n",timestamp,len);
351 static int draw_frame(uint8_t * src
[])
353 vo_mpegpes_t
*p
=(vo_mpegpes_t
*)src
[0];
354 send_pes_packet(p
->data
,p
->size
,p
->id
,(p
->timestamp
>0)?p
->timestamp
:vo_pts
); // video data
358 static void flip_page (void)
362 static int draw_slice(uint8_t *srcimg
[], int stride
[], int w
,int h
,int x0
,int y0
)
369 query_format(uint32_t format
)
371 if(format
==IMGFMT_MPEGPES
) return VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
|VFCAP_TIMER
;
378 if(vo_mpegpes_fd2
>=0 && vo_mpegpes_fd2
!=vo_mpegpes_fd
) close(vo_mpegpes_fd2
);
380 if(vo_mpegpes_fd
>=0){ close(vo_mpegpes_fd
);vo_mpegpes_fd
=-1;}
384 static void check_events(void)
388 static int control(uint32_t request
, void *data
, ...)
391 case VOCTRL_QUERY_FORMAT
:
392 return query_format(*((uint32_t*)data
));