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