1 /*------------------------------------------------------------------------------
2 // emAvServerProc_xine.c
3 //
4 // Copyright (C) 2008,2010-2013,2015,2019-2020 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //----------------------------------------------------------------------------*/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/shm.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <pthread.h>
32 #include <xine.h>
33
34
35 /*============================================================================*/
36 /*============================= Helper Functions =============================*/
37 /*============================================================================*/
38
emAvCpDynStr(char ** pTgt,const char * src)39 static void emAvCpDynStr(char * * pTgt, const char * src)
40 {
41 if (*pTgt) {
42 free(*pTgt);
43 *pTgt=NULL;
44 }
45 if (src) {
46 *pTgt=strdup(src);
47 }
48 }
49
50
emAvCpDynStrArr(char *** pTgt,const char * const * src)51 static void emAvCpDynStrArr(char * * * pTgt, const char * const * src)
52 {
53 char * * tgt;
54 int i;
55
56 tgt=*pTgt;
57 if (tgt) {
58 for (i=0; tgt[i]; i++) free(tgt[i]);
59 free(tgt);
60 *pTgt=NULL;
61 }
62 if (src) {
63 for (i=0; src[i]; i++);
64 tgt=(char**)malloc(sizeof(char*)*(i+1));
65 for (i=0; src[i]; i++) tgt[i]=strdup(src[i]);
66 tgt[i]=NULL;
67 *pTgt=tgt;
68 }
69 }
70
71
emAv_get_xine_error(xine_stream_t * stream)72 static const char * emAv_get_xine_error(xine_stream_t * stream)
73 {
74 static char buf[256];
75 int e;
76
77 e=xine_get_error(stream);
78 switch (e) {
79 case XINE_ERROR_NONE : return "No error reported.";
80 case XINE_ERROR_NO_INPUT_PLUGIN: return "No input plugin.";
81 case XINE_ERROR_NO_DEMUX_PLUGIN: return "No demux plugin.";
82 case XINE_ERROR_DEMUX_FAILED : return "Demux failed.";
83 case XINE_ERROR_MALFORMED_MRL : return "Malformed MRL.";
84 case XINE_ERROR_INPUT_FAILED : return "Input failed.";
85 default:
86 sprintf(buf,"xine error code %d.",e);
87 return buf;
88 }
89 }
90
91
92 /*============================================================================*/
93 /*============================= emAv_raw_visual_t ============================*/
94 /*============================================================================*/
95
96 typedef struct {
97 raw_visual_t base;
98 pthread_mutex_t mutex;
99 int min_shm_size;
100 int shm_size;
101 void * shm_ptr;
102 int crop_left;
103 int crop_right;
104 int crop_top;
105 int crop_bottom;
106 } emAv_raw_visual_t;
107
108
emAv_raw_output_cb(void * user_data,int frame_format,int frame_width,int frame_height,double frame_aspect,void * data0,void * data1,void * data2)109 static void emAv_raw_output_cb(
110 void * user_data, int frame_format, int frame_width, int frame_height,
111 double frame_aspect, void * data0, void * data1, void * data2
112 )
113 {
114 emAv_raw_visual_t * visual=(emAv_raw_visual_t*)user_data;
115 int x1,y1,x2,y2,pitch0,pitch1,pitch2,size0,size1,size2,headerSize,sz;
116 int volatile * pi;
117 char volatile * pc;
118
119 pthread_mutex_lock(&visual->mutex);
120
121 x1=visual->crop_left;
122 y1=visual->crop_top;
123 x2=frame_width-visual->crop_right;
124 y2=frame_height-visual->crop_bottom;
125 if (x1<0) x1=0;
126 if (y1<0) y1=0;
127 if (x2>frame_width) x2=frame_width;
128 if (y2>frame_height) y2=frame_height;
129 if (x2-x1 < frame_width/2) {
130 x1=0;
131 x2=frame_width;
132 }
133 if (y2-y1 < frame_height/2) {
134 y1=0;
135 y2=frame_height;
136 }
137
138 if (
139 frame_width<1 || frame_width>0x7fffff ||
140 frame_height<1 || frame_height>0x7fffff ||
141 frame_width*(long)frame_height > 0x3fffffff
142 ) {
143 pthread_mutex_unlock(&visual->mutex);
144 return;
145 }
146
147 switch (frame_format) {
148 case XINE_VORAW_YV12:
149 pitch0=8*((frame_width+7)/8);
150 pitch1=8*((frame_width+15)/16);
151 pitch2=8*((frame_width+15)/16);
152 x1&=~15;
153 y1&=~1;
154 data0=((char*)data0)+pitch0*y1+x1;
155 data1=((char*)data1)+(pitch1*y1+x1)/2;
156 data2=((char*)data2)+(pitch2*y1+x1)/2;
157 size0=pitch0*(y2-y1);
158 size1=pitch1*((y2-y1+1)/2);
159 size2=pitch2*((y2-y1+1)/2);
160 headerSize=10*sizeof(int);
161 break;
162 case XINE_VORAW_YUY2:
163 pitch0=8*((frame_width+3)/4);
164 pitch1=0;
165 pitch2=0;
166 x1&=~3;
167 data0=((char*)data0)+pitch0*y1+2*x1;
168 size0=pitch0*(y2-y1);
169 size1=0;
170 size2=0;
171 headerSize=7*sizeof(int);
172 break;
173 case XINE_VORAW_RGB:
174 pitch0=3*frame_width;
175 pitch1=0;
176 pitch2=0;
177 data0=((char*)data0)+pitch0*y1+3*x1;
178 size0=pitch0*(y2-y1);
179 size1=0;
180 size2=0;
181 headerSize=7*sizeof(int);
182 break;
183 default:
184 pthread_mutex_unlock(&visual->mutex);
185 return;
186 }
187 sz=headerSize+256+size0+size1+size2;
188
189 if (visual->min_shm_size<sz) visual->min_shm_size=sz;
190 pi=(int volatile *)visual->shm_ptr;
191 if (pi && visual->shm_size>=sz && !pi[0]) {
192 pi[1]=x2-x1;
193 pi[2]=y2-y1;
194 pi[3]=(int)(frame_aspect*65536.0+0.5);
195 switch (frame_format) {
196 case XINE_VORAW_YV12:
197 pi[4]=1;
198 pi[5]=pitch0;
199 pi[6]=pitch1;
200 pc=(char*)(pi+10);
201 pi[7]=(((char*)NULL)-pc)&7;
202 pc+=pi[7];
203 pi[8]=0;
204 pi[9]=0;
205 memcpy((void*)pc,data0,size0);
206 pc+=size0;
207 memcpy((void*)pc,data1,size1);
208 pc+=size1;
209 memcpy((void*)pc,data2,size2);
210 break;
211 case XINE_VORAW_YUY2:
212 pi[4]=2;
213 pi[5]=pitch0;
214 pc=(char*)(pi+7);
215 pi[6]=(((char*)NULL)-pc)&7;
216 pc+=pi[6];
217 memcpy((void*)pc,data0,size0);
218 break;
219 case XINE_VORAW_RGB:
220 pi[4]=0;
221 pi[5]=pitch0;
222 pc=(char*)(pi+7);
223 pi[6]=(((char*)NULL)-pc)&7;
224 pc+=pi[6];
225 memcpy((void*)pc,data0,size0);
226 break;
227 }
228 pi[0]=1;
229 }
230
231 pthread_mutex_unlock(&visual->mutex);
232 }
233
234
emAv_raw_overlay_cb(void * user_data,int num_ovl,raw_overlay_t * overlays_array)235 static void emAv_raw_overlay_cb(
236 void * user_data, int num_ovl, raw_overlay_t * overlays_array
237 )
238 {
239 }
240
241
emAv_raw_visual_create(xine_t * xine)242 static emAv_raw_visual_t * emAv_raw_visual_create(xine_t * xine)
243 {
244 emAv_raw_visual_t * visual;
245
246 visual=(emAv_raw_visual_t*)calloc(1,sizeof(emAv_raw_visual_t));
247 visual->base.user_data=visual;
248 visual->base.supported_formats=XINE_VORAW_YV12|XINE_VORAW_YUY2|XINE_VORAW_RGB;
249 visual->base.raw_output_cb=emAv_raw_output_cb;
250 visual->base.raw_overlay_cb=emAv_raw_overlay_cb;
251 pthread_mutex_init(&visual->mutex,NULL);
252 return visual;
253 }
254
255
emAv_raw_visual_dispose(emAv_raw_visual_t * visual)256 static void emAv_raw_visual_dispose(emAv_raw_visual_t * visual)
257 {
258 if (visual->shm_ptr) shmdt((const void*)visual->shm_ptr);
259 pthread_mutex_destroy(&visual->mutex);
260 memset(visual,0,sizeof(emAv_raw_visual_t));
261 free(visual);
262 }
263
264
emAv_raw_visual_update_out_params(emAv_raw_visual_t * visual,xine_stream_t * stream)265 static void emAv_raw_visual_update_out_params(
266 emAv_raw_visual_t * visual, xine_stream_t * stream
267 )
268 {
269 xine_current_frame_data_t data;
270
271 /*
272 This is a workaround for the problem that xine does not give us
273 per-frame crop information anyhow via raw_visual_t. See
274 xine-lib-1.2.6/src/video_out/video_out_raw.c: It ignores
275 frame->vo_frame.crop_* in raw_frame_proc_slice(...), though it
276 sets VO_CAP_CROP in raw_get_capabilities(...).
277 */
278 if (visual && stream) {
279 memset(&data,0,sizeof(data));
280 xine_get_current_frame_data(stream,&data,0);
281 pthread_mutex_lock(&visual->mutex);
282 visual->crop_left =data.crop_left;
283 visual->crop_right =data.crop_right;
284 visual->crop_top =data.crop_top;
285 visual->crop_bottom=data.crop_bottom;
286 pthread_mutex_unlock(&visual->mutex);
287 }
288 }
289
290
291 /*============================================================================*/
292 /*================================== emAvPipe ================================*/
293 /*============================================================================*/
294
295 #define EM_AV_MAX_MSG_LEN 32768
296
297 static int emAvPipeIn=-1;
298 static int emAvPipeOut=-1;
299 static int emAvPipeBufSize=EM_AV_MAX_MSG_LEN*2;
300 static char * emAvPipeInBuf;
301 static char * emAvPipeOutBuf;
302 static int emAvPipeInBufPos=0;
303 static int emAvPipeInBufEnd=0;
304 static int emAvPipeOutBufFill=0;
305
306
emAvInitPipe()307 static void emAvInitPipe()
308 {
309 int f;
310
311 emAvPipeInBuf=(char*)malloc(emAvPipeBufSize);
312 emAvPipeOutBuf=(char*)malloc(emAvPipeBufSize);
313
314 emAvPipeIn=dup(STDIN_FILENO);
315 if (emAvPipeIn==-1) {
316 fprintf(
317 stderr,
318 "emAvServerProc_xine: dup(STDIN_FILENO) failed: %s\n",
319 strerror(errno)
320 );
321 exit(255);
322 }
323 close(STDIN_FILENO);
324
325 if (
326 (f=fcntl(emAvPipeIn,F_GETFL))<0 ||
327 fcntl(emAvPipeIn,F_SETFL,f|O_NONBLOCK)<0
328 ) {
329 fprintf(
330 stderr,
331 "emAvServerProc_xine: Failed to set pipe read handle to non-blocking mode: %s\n",
332 strerror(errno)
333 );
334 exit(255);
335 }
336
337 emAvPipeOut=dup(STDOUT_FILENO);
338 if (emAvPipeOut==-1) {
339 fprintf(
340 stderr,
341 "emAvServerProc_xine: dup(STDOUT_FILENO) failed: %s\n",
342 strerror(errno)
343 );
344 exit(255);
345 }
346 close(STDOUT_FILENO);
347 if (dup2(STDERR_FILENO,STDOUT_FILENO)==-1) {
348 fprintf(
349 stderr,
350 "emAvServerProc_xine: dup2(STDERR_FILENO,STDOUT_FILENO) failed: %s\n",
351 strerror(errno)
352 );
353 exit(255);
354 }
355 }
356
357
emAvFlushPipe()358 static void emAvFlushPipe()
359 {
360 int pos,len;
361
362 for (pos=0; pos<emAvPipeOutBufFill; pos+=len) {
363 len=write(emAvPipeOut,emAvPipeOutBuf+pos,emAvPipeOutBufFill-pos);
364 if (len<0) {
365 fprintf(
366 stderr,
367 "emAvServerProc_xine: Could not write to pipe: %s\n",
368 strerror(errno)
369 );
370 exit(255);
371 }
372 }
373 emAvPipeOutBufFill=0;
374 }
375
376
emAvBeginMsg(int instIndex,const char * tag)377 static void emAvBeginMsg(int instIndex, const char * tag)
378 {
379 if (emAvPipeBufSize-emAvPipeOutBufFill<EM_AV_MAX_MSG_LEN) {
380 emAvFlushPipe();
381 }
382 emAvPipeOutBufFill+=
383 sprintf(emAvPipeOutBuf+emAvPipeOutBufFill,"%d:%s",instIndex,tag)
384 ;
385 }
386
387
emAvContMsgV(const char * format,va_list args)388 static void emAvContMsgV(const char * format, va_list args)
389 {
390 char * p;
391 int a,l,i;
392
393 p=emAvPipeOutBuf+emAvPipeOutBufFill;
394 a=emAvPipeBufSize-emAvPipeOutBufFill;
395 l=vsnprintf(p,a,format,args);
396 if (l<0 || l>a) l=a; /* just clip it... */
397 for (i=0; i<l; i++) {
398 if (p[i]==0x0a) p[i]=0x1a;
399 if (p[i]==0x0d) p[i]=0x1d;
400 }
401 emAvPipeOutBufFill+=l;
402 }
403
404
emAvContMsg(const char * format,...)405 static void emAvContMsg(const char * format, ...)
406 {
407 va_list args;
408
409 va_start(args,format);
410 emAvContMsgV(format,args);
411 va_end(args);
412 }
413
414
emAvEndMsg()415 static void emAvEndMsg()
416 {
417 if (emAvPipeOutBufFill>=emAvPipeBufSize) {
418 emAvPipeOutBufFill=emAvPipeBufSize-1;
419 }
420 emAvPipeOutBuf[emAvPipeOutBufFill]='\n';
421 emAvPipeOutBufFill++;
422 }
423
424
emAvSendMsg(int instIndex,const char * tag,const char * format,...)425 static void emAvSendMsg(
426 int instIndex, const char * tag, const char * format, ...
427 )
428 {
429 va_list args;
430
431 emAvBeginMsg(instIndex,tag);
432 if (format && *format) {
433 emAvContMsg(":");
434 va_start(args,format);
435 emAvContMsgV(format,args);
436 va_end(args);
437 }
438 emAvEndMsg();
439 }
440
441
emAvReceiveMsg(int * pInstIndex,const char ** pTag,const char ** pData)442 static int emAvReceiveMsg(
443 int * pInstIndex, const char * * pTag, const char * * pData
444 )
445 {
446 char * p1, * p2, * p3, * p4, * pe;
447 int l;
448
449 /* Return value: -1 = pipe closed, 0 = try later again, 1 = got message. */
450
451 for (;;) {
452 p1=emAvPipeInBuf+emAvPipeInBufPos;
453 pe=emAvPipeInBuf+emAvPipeInBufEnd;
454 while (p1<pe && (unsigned char)*p1<=0x20) {
455 emAvPipeInBufPos++;
456 p1++;
457 }
458 for (p4=p1; p4<pe && *p4!=0x0a && *p4!=0x0d; p4++);
459 if (p4<pe) {
460 p2=(char*)memchr(p1,':',p4-p1);
461 if (!p2) {
462 fprintf(stderr,"emAvServerProc_xine: Protocol error.\n");
463 exit(255);
464 }
465 *p2++=0;
466 p3=(char*)memchr(p2,':',p4-p2);
467 if (p3) *p3++=0; else p3=p4;
468 *p4=0;
469 emAvPipeInBufPos+=(p4+1-p1);
470 *pInstIndex=atoi(p1);
471 *pTag=p2;
472 *pData=p3;
473 return 1;
474 }
475 if (emAvPipeInBufPos>0) {
476 emAvPipeInBufEnd-=emAvPipeInBufPos;
477 if (emAvPipeInBufEnd>0) {
478 memmove(
479 emAvPipeInBuf,
480 emAvPipeInBuf+emAvPipeInBufPos,
481 emAvPipeInBufEnd
482 );
483 }
484 emAvPipeInBufPos=0;
485 }
486 l=emAvPipeBufSize-emAvPipeInBufEnd;
487 if (l<=0) {
488 fprintf(stderr,"emAvServerProc_xine: Pipe input buffer too small.\n");
489 exit(255);
490 }
491 l=read(emAvPipeIn,emAvPipeInBuf+emAvPipeInBufEnd,l);
492 if (l<0) {
493 if (errno==EAGAIN) return 0;
494 fprintf(
495 stderr,
496 "emAvServerProc_xine: Could not read from pipe: %s\n",
497 strerror(errno)
498 );
499 exit(255);
500 }
501 if (l==0) return -1;
502 emAvPipeInBufEnd+=l;
503 }
504 }
505
506
507 /*============================================================================*/
508 /*================================ emAvInstance ==============================*/
509 /*============================================================================*/
510
511 typedef struct {
512 xine_t * Xine;
513 xine_audio_port_t * AudioPort;
514 xine_video_port_t * VideoPort;
515 emAv_raw_visual_t * MyRawVisual;
516 xine_stream_t * Stream;
517 xine_post_t * CurrentAudioVisuPost;
518 int CurrentAudioVisu;
519 int MinShmSize;
520 int Status;
521 int SpeedParam;
522 int PlayLength;
523 int PlayPos;
524 int AudioVolume;
525 int AudioMute;
526 int Warnings;
527 char * * AudioVisus;
528 char * * AudioChannels;
529 char * * SpuChannels;
530 int AudioVisu;
531 int AudioChannel;
532 int SpuChannel;
533 } emAvInstance;
534
535 #define EM_AV_WARNING_NO_AUDIO_DRIVER (1<<0)
536 #define EM_AV_WARNING_NO_AUDIO_CODEC (1<<1)
537 #define EM_AV_WARNING_NO_VIDEO_CODEC (1<<2)
538
539 #define EM_AV_MAX_INSTANCES 100
540 static emAvInstance * emAvInstances[EM_AV_MAX_INSTANCES];
541 static int emAvInstanceCount=0;
542
543 #define HAVE_ONE_XINE_PER_STREAM
544
545 #ifndef HAVE_ONE_XINE_PER_STREAM
546 static xine_t * TheXine=NULL;
547 #endif
548
549
emAvInitInstances()550 static void emAvInitInstances()
551 {
552 memset(emAvInstances,0,sizeof(emAvInstances));
553 }
554
555
emAvSendInfo(int instIndex)556 static void emAvSendInfo(int instIndex)
557 {
558 #if 0 /* developer's view... */
559 static struct {
560 int param;
561 const char * name;
562 } params[]={
563 { XINE_PARAM_SPEED , "PARAM_SPEED " },
564 { XINE_PARAM_AV_OFFSET , "PARAM_AV_OFFSET " },
565 { XINE_PARAM_AUDIO_CHANNEL_LOGICAL , "PARAM_AUDIO_CHANNEL_LOGICAL " },
566 { XINE_PARAM_SPU_CHANNEL , "PARAM_SPU_CHANNEL " },
567 { XINE_PARAM_VIDEO_CHANNEL , "PARAM_VIDEO_CHANNEL " },
568 { XINE_PARAM_AUDIO_VOLUME , "PARAM_AUDIO_VOLUME " },
569 { XINE_PARAM_AUDIO_MUTE , "PARAM_AUDIO_MUTE " },
570 { XINE_PARAM_AUDIO_COMPR_LEVEL , "PARAM_AUDIO_COMPR_LEVEL " },
571 { XINE_PARAM_AUDIO_AMP_LEVEL , "PARAM_AUDIO_AMP_LEVEL " },
572 { XINE_PARAM_AUDIO_REPORT_LEVEL , "PARAM_AUDIO_REPORT_LEVEL " },
573 { XINE_PARAM_VERBOSITY , "PARAM_VERBOSITY " },
574 { XINE_PARAM_SPU_OFFSET , "PARAM_SPU_OFFSET " },
575 { XINE_PARAM_IGNORE_VIDEO , "PARAM_IGNORE_VIDEO " },
576 { XINE_PARAM_IGNORE_AUDIO , "PARAM_IGNORE_AUDIO " },
577 { XINE_PARAM_IGNORE_SPU , "PARAM_IGNORE_SPU " },
578 { XINE_PARAM_BROADCASTER_PORT , "PARAM_BROADCASTER_PORT " },
579 { XINE_PARAM_METRONOM_PREBUFFER , "PARAM_METRONOM_PREBUFFER " },
580 { XINE_PARAM_EQ_30HZ , "PARAM_EQ_30HZ " },
581 { XINE_PARAM_EQ_60HZ , "PARAM_EQ_60HZ " },
582 { XINE_PARAM_EQ_125HZ , "PARAM_EQ_125HZ " },
583 { XINE_PARAM_EQ_250HZ , "PARAM_EQ_250HZ " },
584 { XINE_PARAM_EQ_500HZ , "PARAM_EQ_500HZ " },
585 { XINE_PARAM_EQ_1000HZ , "PARAM_EQ_1000HZ " },
586 { XINE_PARAM_EQ_2000HZ , "PARAM_EQ_2000HZ " },
587 { XINE_PARAM_EQ_4000HZ , "PARAM_EQ_4000HZ " },
588 { XINE_PARAM_EQ_8000HZ , "PARAM_EQ_8000HZ " },
589 { XINE_PARAM_EQ_16000HZ , "PARAM_EQ_16000HZ " },
590 { XINE_PARAM_AUDIO_CLOSE_DEVICE , "PARAM_AUDIO_CLOSE_DEVICE " },
591 { XINE_PARAM_AUDIO_AMP_MUTE , "PARAM_AUDIO_AMP_MUTE " },
592 { XINE_PARAM_FINE_SPEED , "PARAM_FINE_SPEED " },
593 { XINE_PARAM_EARLY_FINISHED_EVENT , "PARAM_EARLY_FINISHED_EVENT " },
594 { XINE_PARAM_GAPLESS_SWITCH , "PARAM_GAPLESS_SWITCH " },
595 { XINE_PARAM_DELAY_FINISHED_EVENT , "PARAM_DELAY_FINISHED_EVENT " },
596 { -1 , NULL }
597 };
598 static struct {
599 int param;
600 const char * name;
601 } stream_infos[]={
602 { XINE_STREAM_INFO_BITRATE , "STREAM_INFO_BITRATE " },
603 { XINE_STREAM_INFO_SEEKABLE , "STREAM_INFO_SEEKABLE " },
604 { XINE_STREAM_INFO_VIDEO_WIDTH , "STREAM_INFO_VIDEO_WIDTH " },
605 { XINE_STREAM_INFO_VIDEO_HEIGHT , "STREAM_INFO_VIDEO_HEIGHT " },
606 { XINE_STREAM_INFO_VIDEO_RATIO , "STREAM_INFO_VIDEO_RATIO " },
607 { XINE_STREAM_INFO_VIDEO_CHANNELS , "STREAM_INFO_VIDEO_CHANNELS " },
608 { XINE_STREAM_INFO_VIDEO_STREAMS , "STREAM_INFO_VIDEO_STREAMS " },
609 { XINE_STREAM_INFO_VIDEO_BITRATE , "STREAM_INFO_VIDEO_BITRATE " },
610 { XINE_STREAM_INFO_VIDEO_FOURCC , "STREAM_INFO_VIDEO_FOURCC " },
611 { XINE_STREAM_INFO_VIDEO_HANDLED , "STREAM_INFO_VIDEO_HANDLED " },
612 { XINE_STREAM_INFO_FRAME_DURATION , "STREAM_INFO_FRAME_DURATION " },
613 { XINE_STREAM_INFO_AUDIO_CHANNELS , "STREAM_INFO_AUDIO_CHANNELS " },
614 { XINE_STREAM_INFO_AUDIO_BITS , "STREAM_INFO_AUDIO_BITS " },
615 { XINE_STREAM_INFO_AUDIO_SAMPLERATE , "STREAM_INFO_AUDIO_SAMPLERATE " },
616 { XINE_STREAM_INFO_AUDIO_BITRATE , "STREAM_INFO_AUDIO_BITRATE " },
617 { XINE_STREAM_INFO_AUDIO_FOURCC , "STREAM_INFO_AUDIO_FOURCC " },
618 { XINE_STREAM_INFO_AUDIO_HANDLED , "STREAM_INFO_AUDIO_HANDLED " },
619 { XINE_STREAM_INFO_HAS_CHAPTERS , "STREAM_INFO_HAS_CHAPTERS " },
620 { XINE_STREAM_INFO_HAS_VIDEO , "STREAM_INFO_HAS_VIDEO " },
621 { XINE_STREAM_INFO_HAS_AUDIO , "STREAM_INFO_HAS_AUDIO " },
622 { XINE_STREAM_INFO_IGNORE_VIDEO , "STREAM_INFO_IGNORE_VIDEO " },
623 { XINE_STREAM_INFO_IGNORE_AUDIO , "STREAM_INFO_IGNORE_AUDIO " },
624 { XINE_STREAM_INFO_IGNORE_SPU , "STREAM_INFO_IGNORE_SPU " },
625 { XINE_STREAM_INFO_VIDEO_HAS_STILL , "STREAM_INFO_VIDEO_HAS_STILL " },
626 { XINE_STREAM_INFO_MAX_AUDIO_CHANNEL , "STREAM_INFO_MAX_AUDIO_CHANNEL " },
627 { XINE_STREAM_INFO_MAX_SPU_CHANNEL , "STREAM_INFO_MAX_SPU_CHANNEL " },
628 { XINE_STREAM_INFO_AUDIO_MODE , "STREAM_INFO_AUDIO_MODE " },
629 { XINE_STREAM_INFO_SKIPPED_FRAMES , "STREAM_INFO_SKIPPED_FRAMES " },
630 { XINE_STREAM_INFO_DISCARDED_FRAMES , "STREAM_INFO_DISCARDED_FRAMES " },
631 { XINE_STREAM_INFO_VIDEO_AFD , "STREAM_INFO_VIDEO_AFD " },
632 { XINE_STREAM_INFO_DVD_TITLE_NUMBER , "STREAM_INFO_DVD_TITLE_NUMBER " },
633 { XINE_STREAM_INFO_DVD_TITLE_COUNT , "STREAM_INFO_DVD_TITLE_COUNT " },
634 { XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, "STREAM_INFO_DVD_CHAPTER_NUMBER" },
635 { XINE_STREAM_INFO_DVD_CHAPTER_COUNT , "STREAM_INFO_DVD_CHAPTER_COUNT " },
636 { XINE_STREAM_INFO_DVD_ANGLE_NUMBER , "STREAM_INFO_DVD_ANGLE_NUMBER " },
637 { XINE_STREAM_INFO_DVD_ANGLE_COUNT , "STREAM_INFO_DVD_ANGLE_COUNT " },
638 { -1 , NULL }
639 };
640 static struct {
641 int param;
642 const char * name;
643 } meta_infos[]={
644 { XINE_META_INFO_TITLE , "META_INFO_TITLE " },
645 { XINE_META_INFO_COMMENT , "META_INFO_COMMENT " },
646 { XINE_META_INFO_ARTIST , "META_INFO_ARTIST " },
647 { XINE_META_INFO_GENRE , "META_INFO_GENRE " },
648 { XINE_META_INFO_ALBUM , "META_INFO_ALBUM " },
649 { XINE_META_INFO_YEAR , "META_INFO_YEAR " },
650 { XINE_META_INFO_VIDEOCODEC , "META_INFO_VIDEOCODEC " },
651 { XINE_META_INFO_AUDIOCODEC , "META_INFO_AUDIOCODEC " },
652 { XINE_META_INFO_SYSTEMLAYER , "META_INFO_SYSTEMLAYER " },
653 { XINE_META_INFO_INPUT_PLUGIN , "META_INFO_INPUT_PLUGIN " },
654 { XINE_META_INFO_CDINDEX_DISCID , "META_INFO_CDINDEX_DISCID " },
655 { XINE_META_INFO_TRACK_NUMBER , "META_INFO_TRACK_NUMBER " },
656 { XINE_META_INFO_COMPOSER , "META_INFO_COMPOSER " },
657 { XINE_META_INFO_PUBLISHER , "META_INFO_PUBLISHER " },
658 { XINE_META_INFO_COPYRIGHT , "META_INFO_COPYRIGHT " },
659 { XINE_META_INFO_LICENSE , "META_INFO_LICENSE " },
660 { XINE_META_INFO_ARRANGER , "META_INFO_ARRANGER " },
661 { XINE_META_INFO_LYRICIST , "META_INFO_LYRICIST " },
662 { XINE_META_INFO_AUTHOR , "META_INFO_AUTHOR " },
663 { XINE_META_INFO_CONDUCTOR , "META_INFO_CONDUCTOR " },
664 { XINE_META_INFO_PERFORMER , "META_INFO_PERFORMER " },
665 { XINE_META_INFO_ENSEMBLE , "META_INFO_ENSEMBLE " },
666 { XINE_META_INFO_OPUS , "META_INFO_OPUS " },
667 { XINE_META_INFO_PART , "META_INFO_PART " },
668 { XINE_META_INFO_PARTNUMBER , "META_INFO_PARTNUMBER " },
669 { XINE_META_INFO_LOCATION , "META_INFO_LOCATION " },
670 { XINE_META_INFO_DISCNUMBER , "META_INFO_DISCNUMBER " },
671 { -1 , NULL }
672 };
673 emAvInstance * inst;
674 xine_stream_t * s;
675 const char * str;
676 uint32_t u;
677 int i;
678
679 inst=emAvInstances[instIndex];
680 s=inst->Stream;
681
682 emAvBeginMsg(instIndex,"set");
683 emAvContMsg(":info:");
684
685 for (i=0; params[i].name; i++) {
686 u=xine_get_param(s,params[i].param);
687 emAvContMsg("%s = %u\n",params[i].name,u);
688 }
689
690 for (i=0; stream_infos[i].name; i++) {
691 u=xine_get_stream_info(s,stream_infos[i].param);
692 emAvContMsg("%s = %u\n",stream_infos[i].name,u);
693 }
694
695 for (i=0; meta_infos[i].name; i++) {
696 str=xine_get_meta_info(s,meta_infos[i].param);
697 if (!str) str="";
698 emAvContMsg("%s = %s\n",meta_infos[i].name,str);
699 }
700
701 emAvEndMsg();
702
703 #else
704
705 emAvInstance * inst;
706 xine_stream_t * s;
707 const char * str, * sep;
708 uint32_t u,u2;
709 int pos_stream,pos_time,length_time,min,sec;
710
711 inst=emAvInstances[instIndex];
712 s=inst->Stream;
713
714 emAvBeginMsg(instIndex,"set");
715 emAvContMsg(":info:");
716
717 str=xine_get_meta_info(s,XINE_META_INFO_TITLE);
718 emAvContMsg("Title : %s\n",str?str:"");
719
720 str=xine_get_meta_info(s,XINE_META_INFO_COMMENT);
721 emAvContMsg("Comment: %s\n",str?str:"");
722
723 str=xine_get_meta_info(s,XINE_META_INFO_ARTIST);
724 emAvContMsg("Artist : %s\n",str?str:"");
725
726 str=xine_get_meta_info(s,XINE_META_INFO_GENRE);
727 emAvContMsg("Genre : %s\n",str?str:"");
728
729 str=xine_get_meta_info(s,XINE_META_INFO_ALBUM);
730 emAvContMsg("Album : %s\n",str?str:"");
731
732 str=xine_get_meta_info(s,XINE_META_INFO_YEAR);
733 emAvContMsg("Year : %s\n",str?str:"");
734
735 emAvContMsg("\n");
736
737 emAvContMsg("Length :");
738 if (
739 xine_get_pos_length(s,&pos_stream,&pos_time,&length_time) &&
740 length_time>0
741 ) {
742 sec=(length_time+500)/1000;
743 min=sec/60;
744 sec%=60;
745 if (min>=30) emAvContMsg(" %d minutes",min+(sec+30)/60);
746 else if (min) emAvContMsg(" %d minutes, %d seconds",min,sec);
747 else emAvContMsg(" %d seconds",sec);
748 }
749 emAvContMsg("\n");
750
751 emAvContMsg("System :");
752 sep="";
753 str=xine_get_meta_info(s,XINE_META_INFO_SYSTEMLAYER);
754 if (str && *str) {
755 emAvContMsg(" %s",str);
756 sep=",";
757 }
758 u=xine_get_stream_info(s,XINE_STREAM_INFO_BITRATE);
759 if (u) emAvContMsg("%s %u bits/sec",sep,u);
760 emAvContMsg("\n");
761
762 emAvContMsg("Audio :");
763 sep="";
764 str=xine_get_meta_info(s,XINE_META_INFO_AUDIOCODEC);
765 if (str && *str) {
766 emAvContMsg(" %s",str);
767 sep=",";
768 }
769 u=xine_get_stream_info(s,XINE_STREAM_INFO_AUDIO_BITRATE);
770 if (u) {
771 emAvContMsg("%s %u bits/sec",sep,u);
772 sep=",";
773 }
774 u=xine_get_stream_info(s,XINE_STREAM_INFO_AUDIO_BITS);
775 if (u) {
776 emAvContMsg("%s %u-bit",sep,u);
777 sep=",";
778 }
779 u=xine_get_stream_info(s,XINE_STREAM_INFO_AUDIO_SAMPLERATE);
780 if (u) emAvContMsg("%s %u Hz",sep,u);
781 emAvContMsg("\n");
782
783 emAvContMsg("Video :");
784 sep="";
785 str=xine_get_meta_info(s,XINE_META_INFO_VIDEOCODEC);
786 if (str && *str) {
787 emAvContMsg(" %s",str);
788 sep=",";
789 }
790 u=xine_get_stream_info(s,XINE_STREAM_INFO_VIDEO_BITRATE);
791 if (u) {
792 emAvContMsg("%s %u bits/sec",sep,u);
793 sep=",";
794 }
795 u=xine_get_stream_info(s,XINE_STREAM_INFO_VIDEO_WIDTH);
796 u2=xine_get_stream_info(s,XINE_STREAM_INFO_VIDEO_HEIGHT);
797 if (u && u2) {
798 emAvContMsg("%s %ux%u pixels",sep,u,u2);
799 sep=",";
800 }
801 u=xine_get_stream_info(s,XINE_STREAM_INFO_FRAME_DURATION);
802 if (u) emAvContMsg("%s %u Hz",sep,(90000+u/2)/u);
803
804 emAvEndMsg();
805 #endif
806 }
807
808
emAvPollProperties(int instIndex,int initialize)809 static void emAvPollProperties(int instIndex, int initialize)
810 {
811 emAvInstance * inst;
812 const char * str, * sep;
813 int status,param,pos_stream,pos_time,length_time,sz,w,h,i,n;
814
815 inst=emAvInstances[instIndex];
816
817 /* minshmsize */
818 if (inst->MyRawVisual) {
819 pthread_mutex_lock(&inst->MyRawVisual->mutex);
820 sz=inst->MyRawVisual->min_shm_size;
821 pthread_mutex_unlock(&inst->MyRawVisual->mutex);
822 }
823 else {
824 sz=0;
825 }
826 if (inst->MinShmSize<sz || initialize) {
827 inst->MinShmSize=sz;
828 emAvSendMsg(instIndex,"minshmsize","%d",sz);
829 }
830
831 /* type */
832 if (initialize) {
833 param=xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_HAS_VIDEO);
834 emAvSendMsg(instIndex,"set","type:%s",param?"video":"audio");
835 }
836
837 /* state */
838 status=xine_get_status(inst->Stream);
839 param=xine_get_param(inst->Stream,XINE_PARAM_SPEED);
840 if (inst->Status!=status || inst->SpeedParam!=param || initialize) {
841 inst->Status=status;
842 inst->SpeedParam=param;
843 if (status!=XINE_STATUS_PLAY) str="stopped";
844 else if (param==XINE_SPEED_PAUSE) str="paused";
845 else if (param==XINE_SPEED_SLOW_4) str="slow";
846 else if (param==XINE_SPEED_FAST_4) str="fast";
847 else str="normal";
848 emAvSendMsg(instIndex,"set","state:%s",str);
849 }
850
851 /* length, pos */
852 if (xine_get_pos_length(inst->Stream,&pos_stream,&pos_time,&length_time)) {
853 if ((inst->PlayLength!=length_time && length_time>0) || initialize) {
854 inst->PlayLength=length_time;
855 emAvSendMsg(instIndex,"set","length:%d",length_time);
856 }
857 if (inst->PlayPos!=pos_time || initialize) {
858 inst->PlayPos=pos_time;
859 emAvSendMsg(instIndex,"set","pos:%d",pos_time);
860 }
861 }
862
863 /* aspect */
864 if (initialize) {
865 param=xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_VIDEO_RATIO);
866 if (param>0) {
867 param=(int)(param/10000.0*65536.0+0.5);
868 }
869 else {
870 w=xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_VIDEO_WIDTH);
871 h=xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_VIDEO_HEIGHT);
872 if (h) param=((w<<16)+h/2)/h;
873 if (param<=0) param=(4<<16)/3;
874 }
875 emAvSendMsg(instIndex,"set","aspect:%d",param);
876 }
877
878 /* audio_volume */
879 param=xine_get_param(inst->Stream,XINE_PARAM_AUDIO_AMP_LEVEL);
880 if (inst->AudioVolume!=param || initialize) {
881 inst->AudioVolume=param;
882 emAvSendMsg(instIndex,"set","audio_volume:%d",param);
883 }
884
885 /* audio_mute */
886 param=xine_get_param(inst->Stream,XINE_PARAM_AUDIO_AMP_MUTE);
887 if (inst->AudioMute!=param || initialize) {
888 inst->AudioMute=param;
889 emAvSendMsg(instIndex,"set","audio_mute:%s",param?"on":"off");
890 }
891
892 /* info */
893 if (initialize) {
894 emAvSendInfo(instIndex);
895 }
896
897 /* warning */
898 param=inst->Warnings;
899 if (xine_get_status(inst->Stream)==XINE_STATUS_PLAY) {
900 param&=~(EM_AV_WARNING_NO_AUDIO_CODEC|EM_AV_WARNING_NO_VIDEO_CODEC);
901 if (
902 !xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_AUDIO_HANDLED) &&
903 xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_HAS_AUDIO)
904 ) {
905 param|=EM_AV_WARNING_NO_AUDIO_CODEC;
906 }
907 if (
908 !xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_VIDEO_HANDLED) &&
909 xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_HAS_VIDEO)
910 ) {
911 param|=EM_AV_WARNING_NO_VIDEO_CODEC;
912 }
913 }
914 if (inst->Warnings!=param || initialize) {
915 inst->Warnings=param;
916 emAvBeginMsg(instIndex,"set");
917 emAvContMsg(":warning:");
918 sep="";
919 if (param&EM_AV_WARNING_NO_VIDEO_CODEC) {
920 emAvContMsg("No suitable video codec available.");
921 sep="\n";
922 }
923 if (param&EM_AV_WARNING_NO_AUDIO_DRIVER) {
924 emAvContMsg("%sFailed to prepare an audio driver.",sep);
925 sep="\n";
926 }
927 else if (param&EM_AV_WARNING_NO_AUDIO_CODEC) {
928 emAvContMsg("%sNo suitable audio codec available.",sep);
929 }
930 emAvEndMsg();
931 }
932
933 /* audio_visus */
934 if (initialize) {
935 emAvBeginMsg(instIndex,"set");
936 emAvContMsg(":audio_visus");
937 for (i=0; inst->AudioVisus[i]; i++) {
938 emAvContMsg(":%s",inst->AudioVisus[i]);
939 }
940 emAvEndMsg();
941 }
942
943 /* audio_visu */
944 if (inst->AudioVisu!=inst->CurrentAudioVisu || initialize) {
945 inst->AudioVisu=inst->CurrentAudioVisu;
946 emAvSendMsg(
947 instIndex,"set","audio_visu:%s",
948 inst->AudioVisus[inst->AudioVisu]
949 );
950 }
951
952 /* audio_channels */
953 if (initialize) {
954 emAvBeginMsg(instIndex,"set");
955 emAvContMsg(":audio_channels");
956 for (i=0; inst->AudioChannels[i]; i++) {
957 emAvContMsg(":%s",inst->AudioChannels[i]);
958 }
959 emAvEndMsg();
960 }
961
962 /* audio_channel */
963 param=xine_get_stream_info(inst->Stream,XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
964 for (n=0; inst->AudioChannels[n]; n++);
965 if (param<-2 || param>=n-2) param=-2;
966 if (inst->AudioChannel!=param || initialize) {
967 inst->AudioChannel=param;
968 emAvSendMsg(
969 instIndex,"set","audio_channel:%s",
970 param<n-2 ? inst->AudioChannels[param+2] : ""
971 );
972 }
973
974 /* spu_channels */
975 if (initialize) {
976 emAvBeginMsg(instIndex,"set");
977 emAvContMsg(":spu_channels");
978 for (i=0; inst->SpuChannels[i]; i++) {
979 emAvContMsg(":%s",inst->SpuChannels[i]);
980 }
981 emAvEndMsg();
982 }
983
984 /* spu_channel */
985 param=xine_get_stream_info(inst->Stream,XINE_PARAM_SPU_CHANNEL);
986 for (n=0; inst->SpuChannels[n]; n++);
987 if (param<-2 || param>=n-2) param=-2;
988 if (inst->SpuChannel!=param || initialize) {
989 inst->SpuChannel=param;
990 emAvSendMsg(
991 instIndex,"set","spu_channel:%s",
992 param<n-2 ? inst->SpuChannels[param+2] : ""
993 );
994 }
995 }
996
997
emAvSetAudioVisu(int instIndex,int audioVisu)998 static void emAvSetAudioVisu(int instIndex, int audioVisu)
999 {
1000 emAvInstance * inst;
1001 xine_audio_port_t * audio_ports[2];
1002 xine_video_port_t * video_ports[2];
1003
1004 inst=emAvInstances[instIndex];
1005 if (!inst) return;
1006
1007 if (inst->CurrentAudioVisuPost) {
1008 xine_post_wire_audio_port(
1009 xine_get_audio_source(inst->Stream),
1010 inst->AudioPort
1011 );
1012 xine_post_dispose(inst->Xine,inst->CurrentAudioVisuPost);
1013 inst->CurrentAudioVisuPost=NULL;
1014 }
1015
1016 inst->CurrentAudioVisu=audioVisu;
1017
1018 if (audioVisu<=0) return;
1019 if (!inst->AudioPort) return;
1020 if (!inst->VideoPort) return;
1021 if (!inst->Stream) return;
1022 if (!inst->MyRawVisual) return;
1023
1024 audio_ports[0]=inst->AudioPort;
1025 audio_ports[1]=NULL;
1026 video_ports[0]=inst->VideoPort;
1027 video_ports[1]=NULL;
1028 inst->CurrentAudioVisuPost=xine_post_init(
1029 inst->Xine,
1030 inst->AudioVisus[audioVisu],
1031 0,
1032 audio_ports,
1033 video_ports
1034 );
1035 if (!inst->CurrentAudioVisuPost) return;
1036
1037 if (!xine_post_wire_audio_port(
1038 xine_get_audio_source(inst->Stream),
1039 inst->CurrentAudioVisuPost->audio_input[0]
1040 )) {
1041 xine_post_dispose(inst->Xine,inst->CurrentAudioVisuPost);
1042 inst->CurrentAudioVisuPost=NULL;
1043 }
1044 }
1045
1046
emAvSetProperty(int instIndex,const char * name,const char * value)1047 static const char * emAvSetProperty(
1048 int instIndex, const char * name, const char * value
1049 )
1050 {
1051 emAvInstance * inst;
1052 int param,i;
1053
1054 inst=emAvInstances[instIndex];
1055 if (!inst) return "Not an opened instance.";
1056
1057 if (strcmp(name,"pos")==0) {
1058 inst->PlayPos=atoi(value);
1059 if (xine_get_status(inst->Stream)==XINE_STATUS_PLAY) {
1060 xine_play(inst->Stream,0,inst->PlayPos);
1061 xine_set_param(inst->Stream,XINE_PARAM_SPEED,inst->SpeedParam);
1062 }
1063 }
1064 else if (strcmp(name,"state")==0) {
1065 if (strcmp(value,"stopped")==0) {
1066 inst->Status=XINE_STATUS_STOP;
1067 inst->SpeedParam=XINE_SPEED_NORMAL;
1068 xine_stop(inst->Stream);
1069 }
1070 else {
1071 if (strcmp(value,"paused")==0) param=XINE_SPEED_PAUSE;
1072 else if (strcmp(value,"slow")==0) param=XINE_SPEED_SLOW_4;
1073 else if (strcmp(value,"fast")==0) param=XINE_SPEED_FAST_4;
1074 else if (strcmp(value,"normal")==0) param=XINE_SPEED_NORMAL;
1075 else return "Illegal property value";
1076 inst->Status=XINE_STATUS_PLAY;
1077 inst->SpeedParam=param;
1078 if (xine_get_status(inst->Stream)!=XINE_STATUS_PLAY) {
1079 xine_play(inst->Stream,0,inst->PlayPos);
1080 }
1081 xine_set_param(inst->Stream,XINE_PARAM_SPEED,param);
1082 }
1083 }
1084 else if (strcmp(name,"audio_volume")==0) {
1085 inst->AudioVolume=atoi(value);
1086 xine_set_param(inst->Stream,XINE_PARAM_AUDIO_AMP_LEVEL,inst->AudioVolume);
1087 }
1088 else if (strcmp(name,"audio_mute")==0) {
1089 inst->AudioMute=(strcmp(value,"on")==0 ? 1 : 0);
1090 xine_set_param(inst->Stream,XINE_PARAM_AUDIO_AMP_MUTE,inst->AudioMute);
1091 }
1092 else if (strcmp(name,"audio_visu")==0) {
1093 for (i=0; inst->AudioVisus[i]; i++) {
1094 if (strcmp(inst->AudioVisus[i],value)==0) {
1095 inst->AudioVisu=i;
1096 emAvSetAudioVisu(instIndex,i);
1097 break;
1098 }
1099 }
1100 }
1101 else if (strcmp(name,"audio_channel")==0) {
1102 for (i=0; inst->AudioChannels[i]; i++) {
1103 if (strcmp(inst->AudioChannels[i],value)==0) {
1104 inst->AudioChannel=i-2;
1105 xine_set_param(
1106 inst->Stream,XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
1107 inst->AudioChannel
1108 );
1109 break;
1110 }
1111 }
1112 }
1113 else if (strcmp(name,"spu_channel")==0) {
1114 for (i=0; inst->SpuChannels[i]; i++) {
1115 if (strcmp(inst->SpuChannels[i],value)==0) {
1116 inst->SpuChannel=i-2;
1117 xine_set_param(
1118 inst->Stream,XINE_PARAM_SPU_CHANNEL,
1119 inst->SpuChannel
1120 );
1121 break;
1122 }
1123 }
1124 }
1125 else {
1126 return "Unknown property.";
1127 }
1128
1129 return NULL;
1130 }
1131
1132
emAvDetachShm(int instIndex)1133 static void emAvDetachShm(int instIndex)
1134 {
1135 emAvInstance * inst;
1136
1137 inst=emAvInstances[instIndex];
1138 if (!inst) return;
1139
1140 if (!inst->MyRawVisual) return;
1141 pthread_mutex_lock(&inst->MyRawVisual->mutex);
1142 if (inst->MyRawVisual->shm_ptr) {
1143 shmdt((const void*)inst->MyRawVisual->shm_ptr);
1144 inst->MyRawVisual->shm_ptr=NULL;
1145 inst->MyRawVisual->shm_size=0;
1146 }
1147 pthread_mutex_unlock(&inst->MyRawVisual->mutex);
1148 }
1149
1150
emAvAttachShm(int instIndex,int shmId,int shmSize)1151 static const char * emAvAttachShm(int instIndex, int shmId, int shmSize)
1152 {
1153 emAvInstance * inst;
1154 void * shmPtr;
1155
1156 inst=emAvInstances[instIndex];
1157 if (!inst) return "Not an opened instance.";
1158
1159 if (!inst->MyRawVisual) return "No suitable video driver for shm.";
1160
1161 if (shmId<0 || shmSize<=0) return "Illegal shm parameters.";
1162
1163 shmPtr=shmat(shmId,NULL,0);
1164 if (shmPtr==(void*)-1) return "Failed to attach shm.";
1165
1166 pthread_mutex_lock(&inst->MyRawVisual->mutex);
1167 if (inst->MyRawVisual->shm_ptr) shmdt((const void*)inst->MyRawVisual->shm_ptr);
1168 inst->MyRawVisual->shm_ptr=shmPtr;
1169 inst->MyRawVisual->shm_size=shmSize;
1170 pthread_mutex_unlock(&inst->MyRawVisual->mutex);
1171
1172 return NULL;
1173 }
1174
1175
emAvCloseInstance(int instIndex)1176 static void emAvCloseInstance(int instIndex)
1177 {
1178 emAvInstance * inst;
1179
1180 inst=emAvInstances[instIndex];
1181 if (!inst) return;
1182
1183 if (inst->Stream) xine_stop(inst->Stream);
1184
1185 emAvDetachShm(instIndex);
1186
1187 emAvSetAudioVisu(instIndex,0);
1188
1189 if (inst->Stream) {
1190 xine_close(inst->Stream);
1191 xine_dispose(inst->Stream);
1192 }
1193
1194 if (inst->AudioPort) xine_close_audio_driver(inst->Xine,inst->AudioPort);
1195 if (inst->VideoPort) xine_close_video_driver(inst->Xine,inst->VideoPort);
1196 if (inst->MyRawVisual) emAv_raw_visual_dispose(inst->MyRawVisual);
1197
1198 #ifdef HAVE_ONE_XINE_PER_STREAM
1199 if (inst->Xine) xine_exit(inst->Xine);
1200 #endif
1201
1202 emAvCpDynStrArr(&inst->AudioVisus,NULL);
1203 emAvCpDynStrArr(&inst->AudioChannels,NULL);
1204 emAvCpDynStrArr(&inst->SpuChannels,NULL);
1205
1206 free(inst);
1207 emAvInstances[instIndex]=NULL;
1208 emAvInstanceCount--;
1209
1210 #ifndef HAVE_ONE_XINE_PER_STREAM
1211 if (emAvInstanceCount<=0 && TheXine) {
1212 xine_exit(TheXine);
1213 TheXine=NULL;
1214 }
1215 #endif
1216 }
1217
1218
emAvOpenInstance(int instIndex,const char * audioDrv,const char * videoDrv,const char * file)1219 static const char * emAvOpenInstance(
1220 int instIndex, const char * audioDrv, const char * videoDrv, const char * file
1221 )
1222 {
1223 static char errBuf[512];
1224 char lang[XINE_LANG_MAX];
1225 char chName[64+XINE_LANG_MAX];
1226 const char * const * avplugins;
1227 emAvInstance * inst;
1228 int i,n;
1229
1230 if (emAvInstances[instIndex]) return "Instance already open.";
1231
1232 if (!xine_check_version(XINE_MAJOR_VERSION,XINE_MINOR_VERSION,XINE_SUB_VERSION)) {
1233 return "xine_check_version failed - please recompile emAvServerProc_xine.";
1234 }
1235
1236 inst=(emAvInstance*)calloc(1,sizeof(emAvInstance));
1237 emAvInstances[instIndex]=inst;
1238 emAvInstanceCount++;
1239
1240 #ifndef HAVE_ONE_XINE_PER_STREAM
1241 inst->Xine=TheXine;
1242 if (!inst->Xine) {
1243 #endif
1244 inst->Xine=xine_new();
1245 if (!inst->Xine) {
1246 emAvCloseInstance(instIndex);
1247 return "xine_new failed.";
1248 }
1249 xine_init(inst->Xine);
1250 xine_engine_set_param(inst->Xine,XINE_ENGINE_PARAM_VERBOSITY,XINE_VERBOSITY_NONE);
1251 #ifndef HAVE_ONE_XINE_PER_STREAM
1252 TheXine=inst->Xine;
1253 }
1254 #endif
1255
1256 if (strcmp(audioDrv,"auto")==0) audioDrv=NULL;
1257 #if defined(__linux__)
1258 if (!audioDrv) {
1259 audioDrv="alsa";
1260 inst->AudioPort=xine_open_audio_driver(inst->Xine,audioDrv,NULL);
1261 if (!inst->AudioPort) {
1262 audioDrv=NULL;
1263 inst->AudioPort=xine_open_audio_driver(inst->Xine,audioDrv,NULL);
1264 }
1265 }
1266 else {
1267 inst->AudioPort=xine_open_audio_driver(inst->Xine,audioDrv,NULL);
1268 }
1269 #else
1270 inst->AudioPort=xine_open_audio_driver(inst->Xine,audioDrv,NULL);
1271 #endif
1272 if (!inst->AudioPort) {
1273 inst->Warnings|=EM_AV_WARNING_NO_AUDIO_DRIVER;
1274 inst->AudioPort=xine_open_audio_driver(inst->Xine,"none",NULL);
1275 if (!inst->AudioPort) {
1276 emAvCloseInstance(instIndex);
1277 return "Failed to prepare audio driver. Likely there are no xine plugins installed.";
1278 }
1279 }
1280
1281 if (strcmp(videoDrv,"emAv")==0) {
1282 inst->MyRawVisual=emAv_raw_visual_create(inst->Xine);
1283 inst->VideoPort=xine_open_video_driver(
1284 inst->Xine,"raw",XINE_VISUAL_TYPE_RAW,inst->MyRawVisual
1285 );
1286 if (!inst->VideoPort) {
1287 emAvCloseInstance(instIndex);
1288 return "Failed to prepare video driver.";
1289 }
1290 }
1291 else {
1292 inst->VideoPort=xine_open_video_driver(
1293 inst->Xine,videoDrv,XINE_VISUAL_TYPE_NONE,NULL
1294 );
1295 if (!inst->VideoPort) {
1296 emAvCloseInstance(instIndex);
1297 return "Failed to prepare video driver.";
1298 }
1299 }
1300
1301 inst->Stream=xine_stream_new(inst->Xine,inst->AudioPort,inst->VideoPort);
1302 if (!inst->Stream) {
1303 sprintf(
1304 errBuf,
1305 "xine_stream_new failed: %s",
1306 emAv_get_xine_error(inst->Stream)
1307 );
1308 emAvCloseInstance(instIndex);
1309 return errBuf;
1310 }
1311
1312 xine_set_param(inst->Stream,XINE_PARAM_VERBOSITY,XINE_VERBOSITY_NONE);
1313
1314 if (!xine_open(inst->Stream,file)) {
1315 sprintf(
1316 errBuf,
1317 "xine_open failed: %s",
1318 emAv_get_xine_error(inst->Stream)
1319 );
1320 emAvCloseInstance(instIndex);
1321 return errBuf;
1322 }
1323
1324 avplugins=NULL;
1325 if (
1326 !xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_HAS_VIDEO) &&
1327 xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_HAS_AUDIO)
1328 ) {
1329 avplugins=xine_list_post_plugins_typed(
1330 inst->Xine,XINE_POST_TYPE_AUDIO_VISUALIZATION
1331 );
1332 }
1333 for (n=0; avplugins && avplugins[n]; n++);
1334 inst->AudioVisus=(char**)calloc(n+2,sizeof(char*));
1335 emAvCpDynStr(inst->AudioVisus+0,"none");
1336 for (i=0; i<n; i++) emAvCpDynStr(inst->AudioVisus+1+i,avplugins[i]);
1337 for (i=n; i>1 && strcmp(inst->AudioVisus[i],"goom")!=0; i--);
1338 emAvSetAudioVisu(instIndex,i);
1339
1340 n=xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
1341 if (n>1024) n=1024; else if (n<0) n=0;
1342 emAvCpDynStrArr(&inst->AudioChannels,NULL);
1343 inst->AudioChannels=(char**)calloc(n+3,sizeof(char*));
1344 emAvCpDynStr(inst->AudioChannels+0,"none");
1345 if (n>0) {
1346 emAvCpDynStr(inst->AudioChannels+1,"auto");
1347 for (i=0; i<n; i++) {
1348 sprintf(chName,"%d",i);
1349 if (xine_get_audio_lang(inst->Stream,i,lang)) {
1350 sprintf(chName+strlen(chName)," - %s",lang);
1351 }
1352 emAvCpDynStr(inst->AudioChannels+2+i,chName);
1353 }
1354 }
1355
1356 n=xine_get_stream_info(inst->Stream,XINE_STREAM_INFO_MAX_SPU_CHANNEL);
1357 if (n>1024) n=1024; else if (n<0) n=0;
1358 emAvCpDynStrArr(&inst->SpuChannels,NULL);
1359 inst->SpuChannels=(char**)calloc(n+3,sizeof(char*));
1360 emAvCpDynStr(inst->SpuChannels+0,"none");
1361 if (n>0) {
1362 emAvCpDynStr(inst->SpuChannels+1,"auto");
1363 for (i=0; i<n; i++) {
1364 sprintf(chName,"%d",i);
1365 if (xine_get_spu_lang(inst->Stream,i,lang)) {
1366 sprintf(chName+strlen(chName)," - %s",lang);
1367 }
1368 emAvCpDynStr(inst->SpuChannels+2+i,chName);
1369 }
1370 }
1371
1372 emAvPollProperties(instIndex,1);
1373
1374 return NULL;
1375 }
1376
1377
emAvHandleMsg(int instIndex,const char * tag,const char * data)1378 static void emAvHandleMsg(int instIndex, const char * tag, const char * data)
1379 {
1380 const char * err, * p1, * p2, * p3;
1381 int shmId,shmSize;
1382
1383 if (instIndex<0 || instIndex>=EM_AV_MAX_INSTANCES) {
1384 emAvSendMsg(instIndex,"error","Instance index out of range.");
1385 }
1386 else if (strcmp(tag,"open")==0) {
1387 p1=data;
1388 if ((p2=strchr(p1,':'))==NULL || (p3=strchr(p2+1,':'))==NULL) {
1389 emAvSendMsg(instIndex,"error","Illegal open request.");
1390 return;
1391 }
1392 *((char*)p2++)=0;
1393 *((char*)p3++)=0;
1394 err=emAvOpenInstance(instIndex,p1,p2,p3);
1395 if (err) emAvSendMsg(instIndex,"error","%s",err);
1396 else emAvSendMsg(instIndex,"ok",tag);
1397 }
1398 else if (strcmp(tag,"close")==0) {
1399 emAvCloseInstance(instIndex);
1400 emAvSendMsg(instIndex,"ok",tag);
1401 }
1402 else if (strcmp(tag,"attachshm")==0) {
1403 shmId=-1;
1404 shmSize=0;
1405 sscanf(data,"%d:%d",&shmId,&shmSize);
1406 err=emAvAttachShm(instIndex,shmId,shmSize);
1407 if (err) emAvSendMsg(instIndex,"error","%s",err);
1408 else emAvSendMsg(instIndex,"ok",tag);
1409 }
1410 else if (strcmp(tag,"detachshm")==0) {
1411 emAvDetachShm(instIndex);
1412 emAvSendMsg(instIndex,"ok",tag);
1413 }
1414 else if (strcmp(tag,"set")==0) {
1415 p1=data;
1416 p2=strchr(p1,':');
1417 if (p2) *((char*)p2++)=0; else p2="";
1418 err=emAvSetProperty(instIndex,p1,p2);
1419 if (err) emAvSendMsg(instIndex,"error","%s",err);
1420 else emAvSendMsg(instIndex,"ok","set:%s",p1);
1421 }
1422 else {
1423 emAvSendMsg(instIndex,"error","Unknown tag: %s",tag);
1424 }
1425 }
1426
1427
1428 /*============================================================================*/
1429 /*==================================== main ==================================*/
1430 /*============================================================================*/
1431
main(int argc,char * argv[])1432 int main(int argc, char * argv[])
1433 {
1434 static const int dtInc= 1000;
1435 static const int dtMax= 25000;
1436 static const int tPoll=200000;
1437 const char * tag, * data;
1438 int i,t,dt,instIndex;
1439
1440 emAvInitPipe();
1441 emAvInitInstances();
1442 for (t=0, dt=0;;) {
1443 i=emAvReceiveMsg(&instIndex,&tag,&data);
1444 if (i) {
1445 if (i<0) break;
1446 emAvHandleMsg(instIndex,tag,data);
1447 dt=0;
1448 }
1449 else {
1450 if (t>=tPoll) {
1451 t=0;
1452 for (i=0; i<EM_AV_MAX_INSTANCES; i++) {
1453 if (emAvInstances[i]) emAvPollProperties(i,0);
1454 }
1455 }
1456 emAvFlushPipe();
1457 dt+=dtInc;
1458 if (dt>dtMax) dt=dtMax;
1459 usleep(dt);
1460 t+=dt;
1461 }
1462 for (i=0; i<EM_AV_MAX_INSTANCES; i++) {
1463 if (emAvInstances[i]) {
1464 emAv_raw_visual_update_out_params(
1465 emAvInstances[i]->MyRawVisual,
1466 emAvInstances[i]->Stream
1467 );
1468 }
1469 }
1470 }
1471 for (i=0; i<EM_AV_MAX_INSTANCES; i++) {
1472 if (emAvInstances[i]) emAvCloseInstance(i);
1473 }
1474 return 0;
1475 }
1476