1 /*
2 * Copyright (C) 2000-2020 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 */
20
21 /*
22 * top-level xine functions
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <pthread.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <unistd.h>
40 #if defined (__linux__) || defined (__GLIBC__)
41 #include <endian.h>
42 #elif defined (__FreeBSD__)
43 #include <machine/endian.h>
44 #endif
45
46 #ifdef HAVE_SETLOCALE
47 #include <locale.h>
48 #endif
49
50 #include <basedir.h>
51
52 #define LOG_MODULE "xine"
53 #define LOG_VERBOSE
54 /*
55 #define LOG
56 #define DEBUG
57 */
58
59 #define XINE_ENABLE_EXPERIMENTAL_FEATURES
60 #define METRONOM_CLOCK_INTERNAL
61 #define POST_INTERNAL
62
63 #include <xine/xine_internal.h>
64 #include <xine/plugin_catalog.h>
65 #include <xine/audio_out.h>
66 #include <xine/video_out.h>
67 #include <xine/post.h>
68 #include <xine/demux.h>
69 #include <xine/buffer.h>
70 #include <xine/spu_decoder.h>
71 #include <xine/input_plugin.h>
72 #include <xine/metronom.h>
73 #include <xine/configfile.h>
74 #include <xine/osd.h>
75 #include <xine/spu.h>
76
77 #include <xine/xineutils.h>
78 #include <xine/compat.h>
79
80 #ifdef WIN32
81 # include <fcntl.h>
82 # include <winsock.h>
83 #endif /* WIN32 */
84
85 #include "xine_private.h"
86
87
88
mutex_cleanup(void * mutex)89 static void mutex_cleanup (void *mutex) {
90 pthread_mutex_unlock ((pthread_mutex_t *) mutex);
91 }
92
_x_handle_stream_end(xine_stream_t * s,int non_user)93 void _x_handle_stream_end (xine_stream_t *s, int non_user) {
94 xine_stream_private_t *stream = (xine_stream_private_t *)s;
95
96 stream = stream->side_streams[0];
97 if (stream->status == XINE_STATUS_QUIT)
98 return;
99 stream->status = XINE_STATUS_STOP;
100
101 if (non_user) {
102 /* frontends will not be interested in receiving this event
103 * if they have called xine_stop explicitly, so only send
104 * it if stream playback finished because of stream end reached
105 */
106
107 xine_event_t event;
108
109 stream->finished_naturally = 1;
110
111 event.data_length = 0;
112 event.type = XINE_EVENT_UI_PLAYBACK_FINISHED;
113
114 xine_event_send (&stream->s, &event);
115 }
116 }
117
_x_extra_info_reset(extra_info_t * extra_info)118 void _x_extra_info_reset( extra_info_t *extra_info ) {
119 memset( extra_info, 0, sizeof(extra_info_t) );
120 }
121
_x_extra_info_merge(extra_info_t * dst,extra_info_t * src)122 void _x_extra_info_merge( extra_info_t *dst, extra_info_t *src ) {
123
124 if (!src->invalid) {
125 if( src->input_normpos )
126 dst->input_normpos = src->input_normpos;
127
128 if( src->input_time )
129 dst->input_time = src->input_time;
130
131 if( src->frame_number )
132 dst->frame_number = src->frame_number;
133
134 if( src->seek_count )
135 dst->seek_count = src->seek_count;
136
137 if( src->vpts )
138 dst->vpts = src->vpts;
139 }
140 }
141
xine_current_extra_info_reset(xine_stream_private_t * stream)142 static void xine_current_extra_info_reset (xine_stream_private_t *stream) {
143 int index = xine_refs_get (&stream->current_extra_info_index);
144 extra_info_t *b = &stream->current_extra_info[(index + 1) & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
145
146 memset (b, 0, sizeof (*b));
147 xine_refs_add (&stream->current_extra_info_index, 1);
148 }
149
xine_current_extra_info_set(xine_stream_private_t * stream,const extra_info_t * info)150 void xine_current_extra_info_set (xine_stream_private_t *stream, const extra_info_t *info) {
151 if (!info->invalid) {
152 int index = xine_refs_get (&stream->current_extra_info_index);
153 const extra_info_t *a = &stream->current_extra_info[index & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
154 extra_info_t *b = &stream->current_extra_info[(index + 1) & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
155
156 b->input_normpos = info->input_normpos ? info->input_normpos : a->input_normpos;
157 b->input_time = info->input_time ? info->input_time : a->input_time;
158 b->frame_number = info->frame_number ? info->frame_number : a->frame_number;
159 b->seek_count = info->seek_count ? info->seek_count : a->seek_count;
160 b->vpts = info->vpts ? info->vpts : a->vpts;
161
162 xine_refs_add (&stream->current_extra_info_index, 1);
163 }
164 }
165
xine_current_extra_info_get(xine_stream_private_t * stream,extra_info_t * info)166 static int xine_current_extra_info_get (xine_stream_private_t *stream, extra_info_t *info) {
167 int index = xine_refs_get (&stream->current_extra_info_index);
168 const extra_info_t *a = &stream->current_extra_info[index & (XINE_NUM_CURR_EXTRA_INFOS - 1)];
169
170 *info = *a;
171 return stream->video_seek_count;
172 }
173
174 #define XINE_TICKET_FLAG_PAUSE (int)0x40000000
175
176 typedef struct {
177 xine_ticket_t t;
178
179 pthread_mutex_t lock;
180 pthread_cond_t issued;
181 pthread_cond_t revoked;
182 xine_rwlock_t port_rewiring_lock;
183
184 int pause_revoked;
185 int tickets_granted;
186 int irrevocable_tickets;
187 int plain_renewers;
188
189 int rewirers;
190 int pending_revocations;
191 int atomic_revokers;
192 pthread_t atomic_revoker_thread;
193
194 struct {
195 int count;
196 pthread_t holder;
197 } *holder_threads;
198 unsigned holder_thread_count;
199
200 #define XINE_TICKET_MAX_CB 15
201 xine_ticket_revoke_cb_t *revoke_callbacks[XINE_TICKET_MAX_CB + 1];
202 void *revoke_cb_data[XINE_TICKET_MAX_CB + 1];
203 } xine_ticket_private_t;
204
ticket_revoke_cb_register(xine_ticket_t * tgen,xine_ticket_revoke_cb_t * cb,void * user_data)205 static void ticket_revoke_cb_register (xine_ticket_t *tgen, xine_ticket_revoke_cb_t *cb, void *user_data) {
206 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
207 int i;
208 pthread_mutex_lock (&this->lock);
209 for (i = 0; i < XINE_TICKET_MAX_CB; i++) {
210 if (!this->revoke_callbacks[i]) {
211 this->revoke_callbacks[i] = cb;
212 this->revoke_cb_data[i] = user_data;
213 break;
214 }
215 if ((this->revoke_callbacks[i] == cb) && (this->revoke_cb_data[i] == user_data))
216 break;
217 }
218 pthread_mutex_unlock (&this->lock);
219 }
220
ticket_revoke_cb_unregister(xine_ticket_t * tgen,xine_ticket_revoke_cb_t * cb,void * user_data)221 static void ticket_revoke_cb_unregister (xine_ticket_t *tgen, xine_ticket_revoke_cb_t *cb, void *user_data) {
222 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
223 int f;
224 pthread_mutex_lock (&this->lock);
225 for (f = 0; this->revoke_callbacks[f]; f++) {
226 if ((this->revoke_callbacks[f] == cb) && (this->revoke_cb_data[f] == user_data)) {
227 int l;
228 for (l = f; this->revoke_callbacks[l + 1]; l++) ;
229 if (f < l) {
230 this->revoke_callbacks[f] = this->revoke_callbacks[l];
231 this->revoke_cb_data[f] = this->revoke_cb_data[l];
232 }
233 this->revoke_callbacks[l] = NULL;
234 this->revoke_cb_data[l] = NULL;
235 break;
236 }
237 }
238 pthread_mutex_unlock (&this->lock);
239 }
240
ticket_acquire_internal(xine_ticket_private_t * this,int irrevocable,int nonblocking)241 static int ticket_acquire_internal (xine_ticket_private_t *this, int irrevocable, int nonblocking) {
242 pthread_t self = pthread_self ();
243 unsigned int wait, i;
244
245 pthread_mutex_lock (&this->lock);
246
247 /* find ourselves in user list */
248 for (i = 0; i < this->holder_thread_count; i++) {
249 if (pthread_equal (this->holder_threads[i].holder, self))
250 break;
251 }
252
253 if (i >= this->holder_thread_count) {
254 /* not found */
255 wait = this->pending_revocations
256 && (this->atomic_revokers ? !pthread_equal (this->atomic_revoker_thread, self) : !irrevocable);
257 if (nonblocking && wait) {
258 /* not available immediately, bail out */
259 pthread_mutex_unlock (&this->lock);
260 return 0;
261 }
262 /* add */
263 if (((i & 31) == 31) && (this->holder_threads[i].count == -1000)) {
264 /* enlarge list */
265 void *new = realloc (this->holder_threads, sizeof (*this->holder_threads) * (i + 33));
266 if (!new) {
267 pthread_mutex_unlock (&this->lock);
268 return 0;
269 }
270 this->holder_threads = new;
271 this->holder_threads[i + 32].count = -1000;
272 }
273 this->holder_threads[i].count = 1;
274 this->holder_threads[i].holder = self;
275 this->holder_thread_count = i + 1;
276
277 while (wait) {
278 pthread_cond_wait (&this->issued, &this->lock);
279 wait = this->pending_revocations
280 && (this->atomic_revokers ? !pthread_equal (this->atomic_revoker_thread, self) : !irrevocable);
281 }
282
283 } else {
284 /* found, we already hold this */
285 this->holder_threads[i].count++;
286 }
287
288 this->tickets_granted++;
289 if (irrevocable)
290 this->irrevocable_tickets++;
291
292 pthread_mutex_unlock (&this->lock);
293 return 1;
294 }
295
ticket_acquire_nonblocking(xine_ticket_t * tgen,int irrevocable)296 static int ticket_acquire_nonblocking(xine_ticket_t *tgen, int irrevocable) {
297 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
298 return ticket_acquire_internal(this, irrevocable, 1);
299 }
300
ticket_acquire(xine_ticket_t * tgen,int irrevocable)301 static void ticket_acquire(xine_ticket_t *tgen, int irrevocable) {
302 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
303 ticket_acquire_internal(this, irrevocable, 0);
304 }
305
ticket_release_internal(xine_ticket_private_t * this,int irrevocable)306 static void ticket_release_internal (xine_ticket_private_t *this, int irrevocable) {
307 pthread_t self = pthread_self ();
308 unsigned int i;
309
310 pthread_mutex_lock (&this->lock);
311
312 /* find ourselves in user list */
313 for (i = 0; i < this->holder_thread_count; i++) {
314 if (pthread_equal (this->holder_threads[i].holder, self))
315 break;
316 }
317
318 if (i >= this->holder_thread_count) {
319 lprintf ("BUG! Ticket 0x%p released by a thread that never took it! Allowing code to continue\n", (void*)this);
320 _x_assert (0);
321 } else {
322 this->holder_threads[i].count--;
323 if (this->holder_threads[i].count == 0) {
324 this->holder_thread_count--;
325 if (i < this->holder_thread_count) {
326 this->holder_threads[i].count = this->holder_threads[this->holder_thread_count].count;
327 this->holder_threads[i].holder = this->holder_threads[this->holder_thread_count].holder;
328 }
329 }
330 }
331
332 if ((this->irrevocable_tickets > 0) && irrevocable)
333 this->irrevocable_tickets--;
334 if (this->tickets_granted > 0)
335 this->tickets_granted--;
336
337 if (this->pending_revocations
338 && (!this->tickets_granted || (this->rewirers && !this->irrevocable_tickets)))
339 pthread_cond_broadcast(&this->revoked);
340
341 pthread_mutex_unlock(&this->lock);
342 }
343
ticket_release_nonblocking(xine_ticket_t * tgen,int irrevocable)344 static void ticket_release_nonblocking (xine_ticket_t *tgen, int irrevocable) {
345 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
346 ticket_release_internal (this, irrevocable);
347 }
348
ticket_release(xine_ticket_t * tgen,int irrevocable)349 static void ticket_release (xine_ticket_t *tgen, int irrevocable) {
350 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
351 ticket_release_internal (this, irrevocable);
352 }
353
ticket_renew(xine_ticket_t * tgen,int irrevocable)354 static void ticket_renew (xine_ticket_t *tgen, int irrevocable) {
355 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
356 unsigned int i;
357 int grants;
358 pthread_t self = pthread_self ();
359 pthread_mutex_lock (&this->lock);
360 #if 0
361 /* For performance, caller checks ticket_revoked without lock. 0 here is not really a bug. */
362 _x_assert (this->ticket_revoked);
363 #endif
364 do {
365 /* Never wait for self. This may happen when post plugins call this during their open (). */
366 if (this->atomic_revokers && pthread_equal (this->atomic_revoker_thread, self))
367 break;
368 /* Multithreaded decoders may well allocate frames outside the time window of the main
369 * decoding call. Usually, we cannot make those hidden threads acquire and release
370 * tickets properly. Blocking one of them may freeze main decoder with ticket held.
371 * Lets give them special treatment. */
372 for (i = 0; i < this->holder_thread_count; i++) {
373 if (pthread_equal (this->holder_threads[i].holder, self))
374 break;
375 }
376 if (i >= this->holder_thread_count) {
377 /* If registered threads are safe: Wait for ticket reissue,
378 * and dont burn cpu in endless retries.
379 * If registered threads are still running around: Fall through. */
380 while (this->pending_revocations && !this->tickets_granted)
381 pthread_cond_wait (&this->issued, &this->lock);
382 break;
383 }
384 /* If our thread still has saved self grants and calls this, restore them.
385 * Assume later reissue by another thread (engine pause). */
386 grants = this->holder_threads[i].count;
387 if (grants >= 0x80000) {
388 grants &= 0x7ffff;
389 this->holder_threads[i].count = grants;
390 this->tickets_granted += grants;
391 }
392 /* Lift _all_ our grants, avoid freeze when we have more than 1. */
393 if (irrevocable & XINE_TICKET_FLAG_REWIRE) {
394 /* allow everything */
395 this->tickets_granted -= grants;
396 if (!this->tickets_granted)
397 pthread_cond_broadcast (&this->revoked);
398 while (this->pending_revocations
399 && (!this->irrevocable_tickets || !(irrevocable & ~XINE_TICKET_FLAG_REWIRE)))
400 pthread_cond_wait (&this->issued, &this->lock);
401 this->tickets_granted += grants;
402 } else {
403 /* fair wheather (not rewire) mode */
404 this->plain_renewers++;
405 this->tickets_granted -= grants;
406 if (!this->tickets_granted)
407 pthread_cond_broadcast (&this->revoked);
408 while (this->pending_revocations
409 && (!this->irrevocable_tickets || !irrevocable)
410 && !this->rewirers)
411 pthread_cond_wait (&this->issued, &this->lock);
412 this->tickets_granted += grants;
413 this->plain_renewers--;
414 }
415 } while (0);
416 pthread_mutex_unlock (&this->lock);
417 }
418
419 /* XINE_TICKET_FLAG_REWIRE implies XINE_TICKET_FLAG_ATOMIC. */
ticket_issue(xine_ticket_t * tgen,int flags)420 static void ticket_issue (xine_ticket_t *tgen, int flags) {
421 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
422 pthread_t self;
423 unsigned int i;
424
425 /* better not miss a reissue, and skip that no lock test. */
426 self = pthread_self ();
427 pthread_mutex_lock (&this->lock);
428 if (flags == XINE_TICKET_FLAG_PAUSE) {
429 if (!this->pause_revoked) {
430 pthread_mutex_unlock (&this->lock);
431 return;
432 }
433 this->pause_revoked = 0;
434 flags = 0;
435 }
436
437 if (this->pending_revocations > 0)
438 this->pending_revocations--;
439 if ((flags & XINE_TICKET_FLAG_REWIRE) && (this->rewirers > 0))
440 this->rewirers--;
441 if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC)) {
442 if (this->atomic_revokers > 0)
443 this->atomic_revokers--;
444 pthread_cond_broadcast (&this->revoked);
445 }
446
447 {
448 int n = !this->pending_revocations ? 0 : (this->rewirers ? (XINE_TICKET_FLAG_REWIRE | 1) : 1);
449 if (this->t.ticket_revoked != n) {
450 this->t.ticket_revoked = n;
451 pthread_cond_broadcast (&this->issued);
452 }
453 }
454
455 /* HACK: restore self grants. */
456 for (i = 0; i < this->holder_thread_count; i++) {
457 if (pthread_equal (this->holder_threads[i].holder, self)) {
458 int n = this->holder_threads[i].count;
459 if (n >= 0x80000) {
460 n -= 0x80000;
461 this->holder_threads[i].count = n;
462 if (n < 0x80000)
463 this->tickets_granted += n;
464 }
465 break;
466 }
467 }
468
469 pthread_mutex_unlock(&this->lock);
470 if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC))
471 xine_rwlock_unlock (&this->port_rewiring_lock);
472 }
473
ticket_revoke(xine_ticket_t * tgen,int flags)474 static void ticket_revoke (xine_ticket_t *tgen, int flags) {
475 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
476 pthread_t self;
477
478 if (flags == XINE_TICKET_FLAG_PAUSE) {
479 if (this->pause_revoked)
480 return;
481 self = pthread_self ();
482 /* flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC) does not happen here. */
483 pthread_mutex_lock (&this->lock);
484 if (this->pause_revoked) {
485 pthread_mutex_unlock (&this->lock);
486 return;
487 }
488 this->pause_revoked = 1;
489 flags = 0;
490 } else {
491 self = pthread_self ();
492 if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC))
493 xine_rwlock_wrlock (&this->port_rewiring_lock);
494 pthread_mutex_lock (&this->lock);
495 }
496
497 /* HACK: dont freeze on self grants, save them.
498 * Also, nest revokes at bit 19. */
499 {
500 unsigned int i;
501 for (i = 0; i < this->holder_thread_count; i++) {
502 if (pthread_equal (this->holder_threads[i].holder, self)) {
503 int n = this->holder_threads[i].count;
504 if (n < 0x80000)
505 this->tickets_granted -= n;
506 this->holder_threads[i].count = n + 0x80000;
507 break;
508 }
509 }
510 }
511
512 /* Set these early so release () / renew () see them. */
513 this->pending_revocations++;
514
515 /* No joke - see renew (). */
516 if (flags & XINE_TICKET_FLAG_REWIRE) {
517 this->rewirers++;
518 if (this->plain_renewers)
519 pthread_cond_broadcast (&this->issued);
520 }
521
522 /* New public status. */
523 this->t.ticket_revoked = (this->rewirers ? (XINE_TICKET_FLAG_REWIRE | 1) : 1);
524
525 do {
526 /* Never wait for self. */
527 if (this->atomic_revokers && pthread_equal (this->atomic_revoker_thread, self)) {
528 if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC))
529 this->atomic_revokers++;
530 break;
531 }
532 /* Need waiting? */
533 if (this->tickets_granted || (this->rewirers && this->plain_renewers) || this->atomic_revokers) {
534 /* Notify other holders. */
535 int i, f = (this->rewirers ? XINE_TICKET_FLAG_REWIRE : 0)
536 | (this->atomic_revokers ? XINE_TICKET_FLAG_ATOMIC : 0);
537 for (i = 0; i < XINE_TICKET_MAX_CB; i++) {
538 if (!this->revoke_callbacks[i])
539 break;
540 this->revoke_callbacks[i] (this->revoke_cb_data[i], f);
541 }
542 /* Wait for them to release/renew. */
543 do {
544 pthread_cond_wait (&this->revoked, &this->lock);
545 this->t.ticket_revoked = (this->rewirers ? (XINE_TICKET_FLAG_REWIRE | 1) : 1);
546 } while (this->tickets_granted || (this->rewirers && this->plain_renewers) || this->atomic_revokers);
547 }
548 /* Its ours now. */
549 if (flags & (XINE_TICKET_FLAG_REWIRE | XINE_TICKET_FLAG_ATOMIC)) {
550 this->atomic_revoker_thread = self;
551 this->atomic_revokers++;
552 }
553 } while (0);
554
555 pthread_mutex_unlock(&this->lock);
556 }
557
lock_timeout(pthread_mutex_t * mutex,int ms_timeout)558 static int lock_timeout (pthread_mutex_t *mutex, int ms_timeout) {
559 if (ms_timeout == 0)
560 return (0 == pthread_mutex_trylock (mutex));
561 if (ms_timeout >= 0) {
562 struct timespec abstime = {0, 0};
563 xine_gettime (&abstime);
564 abstime.tv_sec += ms_timeout / 1000;
565 abstime.tv_nsec += (ms_timeout % 1000) * 1000000;
566 if (abstime.tv_nsec >= 1000000000) {
567 abstime.tv_nsec -= 1000000000;
568 abstime.tv_sec++;
569 }
570 return (0 == pthread_mutex_timedlock (mutex, &abstime));
571 }
572 pthread_mutex_lock (mutex);
573 return 1;
574 }
575
ticket_lock_port_rewiring(xine_ticket_t * tgen,int ms_timeout)576 static int ticket_lock_port_rewiring (xine_ticket_t *tgen, int ms_timeout) {
577 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
578 if (ms_timeout == 0)
579 return (0 == xine_rwlock_tryrdlock (&this->port_rewiring_lock));
580 if (ms_timeout >= 0) {
581 struct timespec abstime = {0, 0};
582 xine_gettime (&abstime);
583 abstime.tv_sec += ms_timeout / 1000;
584 abstime.tv_nsec += (ms_timeout % 1000) * 1000000;
585 if (abstime.tv_nsec >= 1000000000) {
586 abstime.tv_nsec -= 1000000000;
587 abstime.tv_sec++;
588 }
589 return (0 == xine_rwlock_timedrdlock (&this->port_rewiring_lock, &abstime));
590 }
591 xine_rwlock_rdlock (&this->port_rewiring_lock);
592 return 1;
593 }
594
ticket_unlock_port_rewiring(xine_ticket_t * tgen)595 static void ticket_unlock_port_rewiring (xine_ticket_t *tgen) {
596 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
597 xine_rwlock_unlock (&this->port_rewiring_lock);
598 }
599
ticket_dispose(xine_ticket_t * tgen)600 static void ticket_dispose (xine_ticket_t *tgen) {
601 xine_ticket_private_t *this = (xine_ticket_private_t *)tgen;
602
603 xine_rwlock_destroy (&this->port_rewiring_lock);
604 pthread_mutex_destroy (&this->lock);
605 pthread_cond_destroy (&this->issued);
606 pthread_cond_destroy (&this->revoked);
607
608 free (this->holder_threads);
609 free (this);
610 }
611
ticket_init(void)612 static xine_ticket_t *XINE_MALLOC ticket_init(void) {
613 xine_ticket_private_t *port_ticket;
614
615 port_ticket = calloc (1, sizeof (xine_ticket_private_t));
616 if (!port_ticket)
617 return NULL;
618 #ifndef HAVE_ZERO_SAFE_MEM
619 port_ticket->t.ticket_revoked = 0;
620 port_ticket->pause_revoked = 0;
621 port_ticket->holder_thread_count = 0;
622 port_ticket->tickets_granted = 0;
623 port_ticket->irrevocable_tickets = 0;
624 port_ticket->atomic_revokers = 0;
625 port_ticket->rewirers = 0;
626 port_ticket->plain_renewers = 0;
627 {
628 int i;
629 for (i = 0; i < XINE_TICKET_MAX_CB; i++) {
630 port_ticket->revoke_callbacks[i] = NULL;
631 port_ticket->revoke_cb_data[i] = NULL;
632 }
633 }
634 #endif
635 port_ticket->t.acquire_nonblocking = ticket_acquire_nonblocking;
636 port_ticket->t.acquire = ticket_acquire;
637 port_ticket->t.release_nonblocking = ticket_release_nonblocking;
638 port_ticket->t.release = ticket_release;
639 port_ticket->t.renew = ticket_renew;
640 port_ticket->t.revoke_cb_register = ticket_revoke_cb_register;
641 port_ticket->t.revoke_cb_unregister = ticket_revoke_cb_unregister;
642 port_ticket->t.issue = ticket_issue;
643 port_ticket->t.revoke = ticket_revoke;
644 port_ticket->t.lock_port_rewiring = ticket_lock_port_rewiring;
645 port_ticket->t.unlock_port_rewiring = ticket_unlock_port_rewiring;
646 port_ticket->t.dispose = ticket_dispose;
647 port_ticket->holder_threads = malloc (32 * sizeof (*port_ticket->holder_threads));
648 if (!port_ticket->holder_threads) {
649 free (port_ticket);
650 return NULL;
651 }
652 port_ticket->holder_threads[31].count = -1000;
653
654 pthread_mutex_init (&port_ticket->lock, NULL);
655 xine_rwlock_init_default (&port_ticket->port_rewiring_lock);
656 pthread_cond_init (&port_ticket->issued, NULL);
657 pthread_cond_init (&port_ticket->revoked, NULL);
658
659 return &port_ticket->t;
660 }
661
set_speed_internal(xine_stream_private_t * stream,int speed)662 static void set_speed_internal (xine_stream_private_t *stream, int speed) {
663 xine_private_t *xine = (xine_private_t *)stream->s.xine;
664 int old_speed = xine->x.clock->speed;
665 int mode = 2 * (speed == XINE_SPEED_PAUSE) + (old_speed == XINE_SPEED_PAUSE);
666
667 if (mode & 1) {
668 if (mode & 2) {
669 /* stay paused */
670 return;
671 } else {
672 /* switch pause mode */
673 if (speed == XINE_LIVE_PAUSE_ON) {
674 xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
675 return;
676 }
677 if (speed == XINE_LIVE_PAUSE_OFF) {
678 xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
679 return;
680 }
681 /* unpause. all decoder and post threads may continue now, if not running already. */
682 xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
683 }
684 } else {
685 if (mode & 2) {
686 /* pause */
687 /* get all decoder and post threads in a state where they agree to be blocked */
688 xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_PAUSE);
689 /* set master clock so audio_out loop can pause in a safe place */
690 xine->x.clock->set_fine_speed (xine->x.clock, speed);
691 } else {
692 if ((speed == XINE_LIVE_PAUSE_ON) || (speed == XINE_LIVE_PAUSE_OFF))
693 return;
694 /* plain change */
695 if (speed == old_speed)
696 return;
697 }
698 }
699
700 /* see coment on audio_out loop about audio_paused */
701 if (stream->s.audio_out) {
702 xine->port_ticket->acquire (xine->port_ticket, 1);
703
704 /* inform audio_out that speed has changed - he knows what to do */
705 stream->s.audio_out->set_property (stream->s.audio_out, AO_PROP_CLOCK_SPEED, speed);
706
707 xine->port_ticket->release (xine->port_ticket, 1);
708 }
709
710 if (mode < 2)
711 /* master clock is set after resuming the audio device (audio_out loop may continue) */
712 xine->x.clock->set_fine_speed (xine->x.clock, speed);
713 }
714
715
716 /* SPEED_FLAG_IGNORE_CHANGE must be set in stream->speed_change_flags, when entering this function */
stop_internal(xine_stream_private_t * stream)717 static void stop_internal (xine_stream_private_t *stream) {
718 lprintf ("status before = %d\n", stream->status);
719
720 if (stream->side_streams[0] == stream)
721 stream->demux.start_buffers_sent = 0;
722 stream = stream->side_streams[0];
723
724 if ( stream->status == XINE_STATUS_IDLE ||
725 stream->status == XINE_STATUS_STOP ) {
726 _x_demux_control_end (&stream->s, 0);
727 lprintf("ignored");
728 } else {
729 /* make sure we're not in "paused" state */
730 set_speed_internal (stream, XINE_FINE_SPEED_NORMAL);
731
732 /* Don't change status if we're quitting */
733 if (stream->status != XINE_STATUS_QUIT)
734 stream->status = XINE_STATUS_STOP;
735 }
736 /*
737 * stop demux
738 */
739 {
740 unsigned int u;
741 for (u = 0; u < XINE_NUM_SIDE_STREAMS; u++) {
742 xine_stream_private_t *side = stream->side_streams[u];
743 if (side && side->demux.plugin && side->demux.thread_created) {
744 lprintf ("stopping demux\n");
745 _x_demux_stop_thread (&side->s);
746 lprintf ("demux stopped\n");
747 }
748 }
749 }
750 lprintf ("done\n");
751 }
752
753 /* force engine to run at normal speed. if you are about to grab a ticket,
754 * do wait for the rare case of a set_fine_speed (0) in progress. */
755
lock_run(xine_stream_private_t * stream,int wait)756 static void lock_run (xine_stream_private_t *stream, int wait) {
757 xine_private_t *xine = (xine_private_t *)stream->s.xine;
758
759 pthread_mutex_lock (&xine->speed_change_lock);
760 if (xine->speed_change_flags & SPEED_FLAG_CHANGING) {
761 xine->speed_change_flags |= SPEED_FLAG_IGNORE_CHANGE | SPEED_FLAG_WANT_NEW;
762 xine->speed_change_new_speed = XINE_FINE_SPEED_NORMAL;
763 if (wait) {
764 do {
765 pthread_cond_wait (&xine->speed_change_done, &xine->speed_change_lock);
766 } while (xine->speed_change_flags & SPEED_FLAG_CHANGING);
767 }
768 pthread_mutex_unlock (&xine->speed_change_lock);
769 return;
770 }
771 xine->speed_change_flags |= SPEED_FLAG_IGNORE_CHANGE;
772 pthread_mutex_unlock (&xine->speed_change_lock);
773
774 if (xine->x.clock->speed == XINE_FINE_SPEED_NORMAL)
775 return;
776 xprintf (&xine->x, XINE_VERBOSITY_DEBUG, "set_speed %d.\n", XINE_FINE_SPEED_NORMAL);
777 set_speed_internal (stream, XINE_FINE_SPEED_NORMAL);
778 }
779
unlock_run(xine_stream_private_t * stream)780 static void unlock_run (xine_stream_private_t *stream) {
781 xine_private_t *xine = (xine_private_t *)stream->s.xine;
782
783 pthread_mutex_lock (&xine->speed_change_lock);
784 xine->speed_change_flags &= ~SPEED_FLAG_IGNORE_CHANGE;
785 pthread_mutex_unlock (&xine->speed_change_lock);
786 }
787
xine_stop(xine_stream_t * s)788 void xine_stop (xine_stream_t *s) {
789 xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
790 xine_private_t *xine;
791
792 if (!stream)
793 return;
794 m = stream->side_streams[0];
795 xine = (xine_private_t *)m->s.xine;
796
797 pthread_mutex_lock (&m->frontend_lock);
798 pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
799
800 /* make sure that other threads cannot change the speed, especially pauseing the stream */
801 lock_run (m, 1);
802
803 xine->port_ticket->acquire (xine->port_ticket, 1);
804
805 if (m->s.audio_out)
806 m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 1);
807 if (m->s.video_out)
808 m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 1);
809
810 stop_internal (m);
811
812 if (m->s.slave && (m->slave_affection & XINE_MASTER_SLAVE_STOP))
813 xine_stop (m->s.slave);
814
815 if (m->s.video_out)
816 m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 0);
817 if (m->s.audio_out)
818 m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 0);
819
820 xine->port_ticket->release (xine->port_ticket, 1);
821 unlock_run (m);
822
823 pthread_cleanup_pop (0);
824 pthread_mutex_unlock (&m->frontend_lock);
825 }
826
827
close_internal(xine_stream_private_t * stream)828 static void close_internal (xine_stream_private_t *stream) {
829 xine_stream_private_t *m = stream->side_streams[0];
830 xine_private_t *xine = (xine_private_t *)m->s.xine;
831 int flush = !m->gapless_switch && !m->finished_naturally;
832
833 if (m->s.slave) {
834 xine_close (m->s.slave);
835 if (m->slave_is_subtitle) {
836 xine_dispose (m->s.slave);
837 m->s.slave = NULL;
838 m->slave_is_subtitle = 0;
839 }
840 }
841
842 /* make sure that other threads cannot change the speed.
843 * especially pauseing the stream may hold demux waiting for fifo pool or ticket,
844 * and thus freeze stop_internal () -> _x_demux_stop_thread () below. */
845 lock_run (m, flush);
846
847 if (flush) {
848 xine->port_ticket->acquire (xine->port_ticket, 1);
849
850 if (m->s.audio_out)
851 m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 1);
852 if (m->s.video_out)
853 m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 1);
854 }
855
856 stop_internal (stream);
857
858 if (flush) {
859 if (m->s.video_out)
860 m->s.video_out->set_property (m->s.video_out, VO_PROP_DISCARD_FRAMES, 0);
861 if (m->s.audio_out)
862 m->s.audio_out->set_property (m->s.audio_out, AO_PROP_DISCARD_BUFFERS, 0);
863
864 xine->port_ticket->release (xine->port_ticket, 1);
865 }
866
867 unlock_run (m);
868
869 if (stream == m) {
870 unsigned int u;
871 for (u = 0; u < XINE_NUM_SIDE_STREAMS; u++) {
872 xine_stream_private_t *side = stream->side_streams[u];
873 if (side) {
874 if (side->demux.plugin)
875 _x_free_demux_plugin (&side->s, &side->demux.plugin);
876 if (side->s.input_plugin) {
877 _x_free_input_plugin (&side->s, side->s.input_plugin);
878 side->s.input_plugin = NULL;
879 }
880 }
881 }
882 } else {
883 if (stream->demux.plugin)
884 _x_free_demux_plugin (&stream->s, &stream->demux.plugin);
885 if (stream->s.input_plugin) {
886 _x_free_input_plugin (&stream->s, stream->s.input_plugin);
887 stream->s.input_plugin = NULL;
888 }
889 }
890
891 /*
892 * reset / free meta info
893 * XINE_STREAM_INFO_MAX is at least 99 but the info arrays are sparsely used.
894 * Save a lot of mutex/free calls.
895 */
896 if (stream == m) {
897 int i;
898 xine_rwlock_wrlock (&stream->info_lock);
899 for (i = 0; i < XINE_STREAM_INFO_MAX; i++)
900 stream->stream_info[i] = 0;
901 xine_rwlock_unlock (&stream->info_lock);
902 xine_rwlock_wrlock (&stream->meta_lock);
903 for (i = 0; i < XINE_STREAM_INFO_MAX; i++) {
904 if (stream->meta_info_public[i]) {
905 if (stream->meta_info_public[i] != stream->meta_info[i])
906 free (stream->meta_info_public[i]);
907 stream->meta_info_public[i] = NULL;
908 }
909 if (stream->meta_info[i])
910 free (stream->meta_info[i]), stream->meta_info[i] = NULL;
911 }
912 xine_rwlock_unlock (&stream->meta_lock);
913 }
914 stream->audio_track_map_entries = 0;
915 stream->spu_track_map_entries = 0;
916
917 _x_keyframes_set (&stream->s, NULL, 0);
918 }
919
xine_close(xine_stream_t * s)920 void xine_close (xine_stream_t *s) {
921 xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
922 /* a function that uses pthread_cleanup_push () should not modify its
923 * arguments. it also should not modify a variable that optimizes to
924 * be the same as an arg ("stream"). this avoids a "may be clobbered
925 * by longjmp () or vfork () warning. */
926
927 /* phonon bug */
928 if (!stream) {
929 printf ("xine_close: BUG: stream = NULL.\n");
930 return;
931 }
932
933 m = stream->side_streams[0];
934 pthread_mutex_lock (&m->frontend_lock);
935 pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
936
937 close_internal (m);
938
939 /*
940 * set status to idle.
941 * not putting this into close_internal because it is also called
942 * by open_internal.
943 */
944
945 /* Don't change status if we're quitting */
946 if (m->status != XINE_STATUS_QUIT)
947 m->status = XINE_STATUS_IDLE;
948
949 pthread_cleanup_pop (0);
950 pthread_mutex_unlock (&m->frontend_lock);
951 }
952
stream_rewire_audio(xine_post_out_t * output,void * data)953 static int stream_rewire_audio(xine_post_out_t *output, void *data)
954 {
955 xine_stream_private_t *stream = (xine_stream_private_t *)output->data;
956 xine_private_t *xine = (xine_private_t *)stream->s.xine;
957 xine_audio_port_t *new_port = (xine_audio_port_t *)data, *old_port;
958 uint32_t bits, rate;
959 int mode;
960
961 if (!data)
962 return 0;
963
964 stream = stream->side_streams[0];
965
966 xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
967 /* just an optimization. Keep engine paused at rewire safe position for subsequent rewires. */
968 set_speed_internal (stream, XINE_LIVE_PAUSE_OFF);
969
970 old_port = stream->s.audio_out;
971 _x_post_audio_port_ref (new_port);
972 if (old_port->status (old_port, &stream->s, &bits, &rate, &mode)) {
973 /* register our stream at the new output port */
974 (new_port->open) (new_port, &stream->s, bits, rate, mode);
975 old_port->close (old_port, &stream->s);
976 }
977 stream->s.audio_out = new_port;
978 _x_post_audio_port_unref (old_port);
979
980 xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
981
982 return 1;
983 }
984
stream_rewire_video(xine_post_out_t * output,void * data)985 static int stream_rewire_video(xine_post_out_t *output, void *data)
986 {
987 xine_stream_private_t *stream = (xine_stream_private_t *)output->data;
988 xine_private_t *xine = (xine_private_t *)stream->s.xine;
989 xine_video_port_t *new_port = (xine_video_port_t *)data, *old_port;
990 int64_t img_duration;
991 int width, height;
992
993 if (!data)
994 return 0;
995
996 stream = stream->side_streams[0];
997
998 xine->port_ticket->revoke (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
999 /* just an optimization. Keep engine paused at rewire safe position for subsequent rewires. */
1000 set_speed_internal (stream, XINE_LIVE_PAUSE_OFF);
1001
1002 old_port = stream->s.video_out;
1003 _x_post_video_port_ref (new_port);
1004 if (old_port->status (old_port, &stream->s, &width, &height, &img_duration)) {
1005 /* register our stream at the new output port */
1006 (new_port->open) (new_port, &stream->s);
1007 old_port->close (old_port, &stream->s);
1008 }
1009 stream->s.video_out = new_port;
1010 _x_post_video_port_unref (old_port);
1011
1012 xine->port_ticket->issue (xine->port_ticket, XINE_TICKET_FLAG_REWIRE);
1013
1014 return 1;
1015 }
1016
video_decoder_update_disable_flush_at_discontinuity(void * s,xine_cfg_entry_t * entry)1017 static void video_decoder_update_disable_flush_at_discontinuity (void *s, xine_cfg_entry_t *entry) {
1018 xine_stream_private_t *stream = (xine_stream_private_t *)s;
1019 stream = stream->side_streams[0];
1020 stream->disable_decoder_flush_at_discontinuity = !!entry->num_value;
1021 }
1022
_xine_dummy_dest(void * object)1023 static void _xine_dummy_dest (void *object) {
1024 (void)object;
1025 }
1026
1027 static void xine_dispose_internal (xine_stream_private_t *stream);
1028
xine_stream_new(xine_t * this,xine_audio_port_t * ao,xine_video_port_t * vo)1029 xine_stream_t *xine_stream_new (xine_t *this, xine_audio_port_t *ao, xine_video_port_t *vo) {
1030
1031 xine_stream_private_t *stream;
1032 pthread_mutexattr_t attr;
1033
1034 xprintf (this, XINE_VERBOSITY_DEBUG, "xine_stream_new\n");
1035
1036 /* create a new stream object */
1037 stream = calloc (1, sizeof (*stream));
1038 if (!stream)
1039 goto err_null;
1040 #ifndef HAVE_ZERO_SAFE_MEM
1041 /* Do these first, when compiler still knows stream is all zeroed.
1042 * Let it optimize away this on most systems where clear mem
1043 * interpretes as 0, 0f or NULL safely.
1044 */
1045 stream->s.spu_decoder_plugin = NULL;
1046 stream->audio_decoder_plugin = NULL;
1047 stream->early_finish_event = 0;
1048 stream->delay_finish_event = 0;
1049 stream->gapless_switch = 0;
1050 stream->keep_ao_driver_open = 0;
1051 stream->video_channel = 0;
1052 stream->video_decoder_plugin = NULL;
1053 stream->counter.headers_audio = 0;
1054 stream->counter.headers_video = 0;
1055 stream->counter.finisheds_audio = 0;
1056 stream->counter.finisheds_video = 0;
1057 stream->counter.demuxers_running = 0;
1058 stream->counter.nbc_refs = 0;
1059 stream->counter.nbc = NULL;
1060 stream->demux.action_pending = 0;
1061 stream->demux.input_caps = 0;
1062 stream->demux.thread_created = 0;
1063 stream->demux.thread_running = 0;
1064 stream->demux.start_buffers_sent = 0;
1065 stream->err = 0;
1066 stream->broadcaster = NULL;
1067 stream->index.array = NULL;
1068 stream->s.slave = NULL;
1069 stream->slave_is_subtitle = 0;
1070 stream->query_input_plugins[0] = NULL;
1071 stream->query_input_plugins[1] = NULL;
1072 {
1073 int i;
1074 for (i = 1; i < XINE_NUM_SIDE_STREAMS; i++)
1075 stream->side_streams[i] = NULL;
1076 for (i = 0; i < XINE_STREAM_INFO_MAX; i++) {
1077 stream->stream_info[i] = 0;
1078 stream->meta_info_public[i] = stream->meta_info[i] = NULL;
1079 }
1080 }
1081 #endif
1082 /* no need to memset again
1083 _x_extra_info_reset (&stream->ei[0]);
1084 _x_extra_info_reset (&stream->ei[1]);
1085 */
1086
1087 stream->audio_decoder_extra_info = &stream->ei[0];
1088 stream->video_decoder_extra_info = &stream->ei[1];
1089
1090 stream->side_streams[0] = stream;
1091 stream->id_flag = 1 << 0;
1092 stream->s.xine = this;
1093 stream->status = XINE_STATUS_IDLE;
1094
1095 stream->video_source.name = "video source";
1096 stream->video_source.type = XINE_POST_DATA_VIDEO;
1097 stream->video_source.data = &stream->s;
1098 stream->video_source.rewire = stream_rewire_video;
1099
1100 stream->audio_source.name = "audio source";
1101 stream->audio_source.type = XINE_POST_DATA_AUDIO;
1102 stream->audio_source.data = &stream->s;
1103 stream->audio_source.rewire = stream_rewire_audio;
1104
1105 stream->demux.max_seek_bufs = 0xffffffff;
1106 stream->s.spu_decoder_streamtype = -1;
1107 stream->s.audio_out = ao;
1108 stream->audio_channel_user = -1;
1109 stream->s.audio_channel_auto = -1;
1110 stream->audio_decoder_streamtype = -1;
1111 stream->s.spu_channel_auto = -1;
1112 stream->s.spu_channel_letterbox = -1;
1113 stream->spu_channel_pan_scan = -1;
1114 stream->s.spu_channel_user = -1;
1115 stream->s.spu_channel = -1;
1116 /* Do not flush output when opening/closing yet unused streams (eg subtitle). */
1117 stream->finished_naturally = 1;
1118 stream->s.video_out = vo;
1119 stream->s.video_driver = vo ? vo->driver : NULL;
1120 stream->video_decoder_streamtype = -1;
1121 /* initial master/slave */
1122 stream->s.master = &stream->s;
1123
1124 /* event queues */
1125 stream->event.queues = xine_list_new ();
1126 if (!stream->event.queues)
1127 goto err_free;
1128
1129 /* init mutexes and conditions */
1130 xine_refs_init (&stream->current_extra_info_index, _xine_dummy_dest, stream);
1131 xine_rwlock_init_default (&stream->info_lock);
1132 xine_rwlock_init_default (&stream->meta_lock);
1133 pthread_mutex_init (&stream->demux.lock, NULL);
1134 pthread_mutex_init (&stream->demux.action_lock, NULL);
1135 pthread_mutex_init (&stream->demux.pair, NULL);
1136 pthread_cond_init (&stream->demux.resume, NULL);
1137 pthread_mutex_init (&stream->event.lock, NULL);
1138 pthread_mutex_init (&stream->counter.lock, NULL);
1139 pthread_cond_init (&stream->counter.changed, NULL);
1140 pthread_mutex_init (&stream->first_frame.lock, NULL);
1141 pthread_cond_init (&stream->first_frame.reached, NULL);
1142 pthread_mutex_init (&stream->index.lock, NULL);
1143
1144 /* warning: frontend_lock is a recursive mutex. it must NOT be
1145 * used with neither pthread_cond_wait() or pthread_cond_timedwait()
1146 */
1147 pthread_mutexattr_init(&attr);
1148 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1149 pthread_mutex_init (&stream->frontend_lock, &attr);
1150 pthread_mutexattr_destroy(&attr);
1151
1152 pthread_mutex_lock (&this->streams_lock);
1153
1154 /* some user config */
1155 stream->disable_decoder_flush_at_discontinuity = this->config->register_bool (this->config,
1156 "engine.decoder.disable_flush_at_discontinuity", 0,
1157 _("disable decoder flush at discontinuity"),
1158 _("when watching live tv a discontinuity happens for example about every 26.5 hours due to a pts wrap.\n"
1159 "flushing the decoder at that time causes decoding errors for images after the pts wrap.\n"
1160 "to avoid the decoding errors, decoder flush at discontinuity should be disabled.\n\n"
1161 "WARNING: as the flush was introduced to fix some issues when playing DVD still images, it is\n"
1162 "likely that these issues may reappear in case they haven't been fixed differently meanwhile.\n"),
1163 20, video_decoder_update_disable_flush_at_discontinuity, stream);
1164
1165 /* create a metronom */
1166 stream->s.metronom = _x_metronom_init ( (vo != NULL), (ao != NULL), this);
1167 if (!stream->s.metronom)
1168 goto err_mutex;
1169
1170 /* alloc fifos, init and start decoder threads */
1171 if (!_x_video_decoder_init (&stream->s))
1172 goto err_metronom;
1173
1174 if (!_x_audio_decoder_init (&stream->s))
1175 goto err_video;
1176
1177 /* osd */
1178 if (vo) {
1179 _x_spu_misc_init (this);
1180 stream->s.osd_renderer = _x_osd_renderer_init (&stream->s);
1181 } else
1182 stream->s.osd_renderer = NULL;
1183
1184 /* create a reference counter */
1185 xine_refs_init (&stream->refs, (void (*)(void *))xine_dispose_internal, &stream->s);
1186
1187 /* register stream */
1188 xine_list_push_back (this->streams, &stream->s);
1189 pthread_mutex_unlock (&this->streams_lock);
1190 return &stream->s;
1191
1192 /* err_audio: */
1193 /* _x_audio_decoder_shutdown (&stream->s); */
1194
1195 err_video:
1196 _x_video_decoder_shutdown (&stream->s);
1197
1198 err_metronom:
1199 stream->s.metronom->exit (stream->s.metronom);
1200
1201 err_mutex:
1202 pthread_mutex_unlock (&this->streams_lock);
1203 pthread_mutex_destroy (&stream->frontend_lock);
1204 pthread_mutex_destroy (&stream->index.lock);
1205 pthread_cond_destroy (&stream->first_frame.reached);
1206 pthread_mutex_destroy (&stream->first_frame.lock);
1207 pthread_cond_destroy (&stream->counter.changed);
1208 pthread_mutex_destroy (&stream->counter.lock);
1209 pthread_mutex_destroy (&stream->event.lock);
1210 pthread_cond_destroy (&stream->demux.resume);
1211 pthread_mutex_destroy (&stream->demux.pair);
1212 pthread_mutex_destroy (&stream->demux.action_lock);
1213 pthread_mutex_destroy (&stream->demux.lock);
1214 xine_rwlock_destroy (&stream->meta_lock);
1215 xine_rwlock_destroy (&stream->info_lock);
1216 xine_refs_sub (&stream->current_extra_info_index, xine_refs_get (&stream->current_extra_info_index));
1217 xine_list_delete (stream->event.queues);
1218
1219 err_free:
1220 free (stream);
1221
1222 err_null:
1223 return NULL;
1224 }
1225
xine_side_dispose_internal(xine_stream_private_t * stream)1226 static void xine_side_dispose_internal (xine_stream_private_t *stream) {
1227 xine_t *xine = stream->s.xine;
1228
1229 lprintf ("stream: %p\n", (void*)stream);
1230
1231 xine->config->unregister_callbacks (xine->config, NULL, NULL, stream, sizeof (*stream));
1232
1233 {
1234 xine_stream_private_t *m = stream->side_streams[0];
1235 unsigned int u;
1236 xine_rwlock_wrlock (&m->info_lock);
1237 for (u = 1; u < XINE_NUM_SIDE_STREAMS; u++) {
1238 if (m->side_streams[u] == stream) {
1239 m->side_streams[u] = NULL;
1240 break;
1241 }
1242 }
1243 xine_rwlock_unlock (&m->info_lock);
1244 if (u < XINE_NUM_SIDE_STREAMS)
1245 xine_refs_sub (&m->refs, 1);
1246 }
1247
1248 /* these are not used in side streams.
1249 xine_refs_sub (&stream->current_extra_info_index, xine_refs_get (&stream->current_extra_info_index));
1250 pthread_mutex_destroy (&stream->frontend_lock);
1251 pthread_mutex_destroy (&stream->index.lock);
1252 pthread_mutex_destroy (&stream->demux.pair_mutex);
1253 pthread_mutex_destroy (&stream->event.lock);
1254 pthread_mutex_destroy (&stream->counter.lock);
1255 pthread_mutex_destroy (&stream->first_frame.lock);
1256 pthread_cond_destroy (&stream->first_frame.reached);
1257 pthread_cond_destroy (&stream->counter.changed);
1258 xine_rwlock_destroy (&stream->meta_lock);
1259 xine_rwlock_destroy (&stream->info_lock);
1260 */
1261 pthread_cond_destroy (&stream->demux.resume);
1262 pthread_mutex_destroy (&stream->demux.action_lock);
1263 pthread_mutex_destroy (&stream->demux.lock);
1264
1265 free (stream->index.array);
1266 free (stream);
1267 }
1268
xine_get_side_stream(xine_stream_t * master,int index)1269 xine_stream_t *xine_get_side_stream (xine_stream_t *master, int index) {
1270 xine_stream_private_t *m = (xine_stream_private_t *)master, *s;
1271
1272 if (!m || (index < 0) || (index >= XINE_NUM_SIDE_STREAMS))
1273 return NULL;
1274 /* no sub-sides, please. */
1275 m = m->side_streams[0];
1276 xine_rwlock_rdlock (&m->info_lock);
1277 s = m->side_streams[index];
1278 xine_rwlock_unlock (&m->info_lock);
1279 if (s)
1280 return &s->s;
1281
1282 xprintf (m->s.xine, XINE_VERBOSITY_DEBUG, "xine_side_stream_new (%p, %d)\n", (void *)m, index);
1283
1284 /* create a new stream object */
1285 s = calloc (1, sizeof (*s));
1286 if (!s)
1287 return NULL;
1288
1289 #ifndef HAVE_ZERO_SAFE_MEM
1290 s->s.spu_decoder_plugin = NULL;
1291 s->audio_decoder_plugin = NULL;
1292 s->audio_track_map_entries = 0;
1293 s->audio_type = 0;
1294 s->early_finish_event = 0;
1295 s->delay_finish_event = 0;
1296 s->gapless_switch = 0;
1297 s->keep_ao_driver_open = 0;
1298 s->video_channel = 0;
1299 s->video_decoder_plugin = NULL;
1300 s->spu_track_map_entries = 0;
1301 s->counter.headers_audio = 0;
1302 s->counter.headers_video = 0;
1303 s->counter.finisheds_audio = 0;
1304 s->counter.finisheds_video = 0;
1305 s->demux.action_pending = 0;
1306 s->demux.input_caps = 0;
1307 s->demux.thread_created = 0;
1308 s->demux.thread_running = 0;
1309 s->err = 0;
1310 s->broadcaster = NULL;
1311 s->index.array = NULL;
1312 s->s.slave = NULL;
1313 s->slave_is_subtitle = 0;
1314 s->query_input_plugins[0] = NULL;
1315 s->query_input_plugins[1] = NULL;
1316 {
1317 int i;
1318 for (i = 1; i < XINE_NUM_SIDE_STREAMS; i++)
1319 s->side_streams[i] = NULL;
1320 for (i = 0; i < XINE_STREAM_INFO_MAX; i++) {
1321 s->stream_info[i] = 0;
1322 s->meta_info_public[i] = s->meta_info[i] = NULL;
1323 }
1324 }
1325 #endif
1326 /* no need to memset again
1327 _x_extra_info_reset (&stream->ei[0]);
1328 _x_extra_info_reset (&stream->ei[1]);
1329 */
1330
1331 /* create a reference counter */
1332 xine_refs_init (&s->refs, (void (*)(void *))xine_side_dispose_internal, &s->s);
1333
1334 s->audio_decoder_extra_info = m->audio_decoder_extra_info;
1335 s->video_decoder_extra_info = m->video_decoder_extra_info;
1336
1337 s->side_streams[0] = m;
1338 s->id_flag = 1 << index;
1339 s->s.xine = m->s.xine;
1340 s->status = XINE_STATUS_IDLE;
1341
1342 s->video_source.name = "video source";
1343 s->video_source.type = XINE_POST_DATA_VIDEO;
1344 s->video_source.data = &m->s;
1345 s->video_source.rewire = stream_rewire_video;
1346
1347 s->audio_source.name = "audio source";
1348 s->audio_source.type = XINE_POST_DATA_AUDIO;
1349 s->audio_source.data = &m->s;
1350 s->audio_source.rewire = stream_rewire_audio;
1351
1352 s->s.spu_decoder_streamtype = -1;
1353 s->s.audio_out = m->s.audio_out;
1354 s->audio_channel_user = -1;
1355 s->s.audio_channel_auto = -1;
1356 s->audio_decoder_streamtype = -1;
1357 s->s.spu_channel_auto = -1;
1358 s->s.spu_channel_letterbox = -1;
1359 s->spu_channel_pan_scan = -1;
1360 s->s.spu_channel_user = -1;
1361 s->s.spu_channel = -1;
1362 /* Do not flush output when opening/closing yet unused streams (eg subtitle). */
1363 s->finished_naturally = 1;
1364 s->s.video_out = m->s.video_out;
1365 s->s.video_driver = m->s.video_driver;
1366 s->video_decoder_streamtype = -1;
1367 /* initial master/slave */
1368 s->s.master = &s->s;
1369
1370 s->event.queues = m->event.queues;
1371
1372 /* these are not used in side streams.
1373 {
1374 pthread_mutexattr_t attr;
1375 pthread_mutexattr_init (&attr);
1376 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
1377 pthread_mutex_init (&s->frontend_lock, &attr);
1378 pthread_mutexattr_destroy (&attr);
1379 }
1380 xine_refs_init (&stream->current_extra_info_index, _xine_dummy_dest, stream);
1381 pthread_mutex_init (&s->demux.pair, NULL);
1382 pthread_mutex_init (&s->index.lock, NULL);
1383 pthread_mutex_init (&s->event.lock, NULL);
1384 pthread_mutex_init (&s->counter.lock, NULL);
1385 pthread_mutex_init (&s->first_frame.lock, NULL);
1386 pthread_cond_init (&s->counter.changed, NULL);
1387 pthread_cond_init (&s->first_frame.reached, NULL);
1388 xine_rwlock_init_default (&s->info_lock);
1389 xine_rwlock_init_default (&s->meta_lock);
1390 */
1391 /* init mutexes and conditions */
1392 pthread_mutex_init (&s->demux.lock, NULL);
1393 pthread_mutex_init (&s->demux.action_lock, NULL);
1394 pthread_cond_init (&s->demux.resume, NULL);
1395
1396 /* some user config */
1397 s->disable_decoder_flush_at_discontinuity = m->disable_decoder_flush_at_discontinuity;
1398 s->s.metronom = m->s.metronom;
1399
1400 /* this will just link to master */
1401 s->s.video_fifo = m->s.video_fifo;
1402 s->s.audio_fifo = m->s.audio_fifo;
1403
1404 /* osd */
1405 s->s.osd_renderer = m->s.osd_renderer;
1406
1407 /* register stream */
1408 xine_refs_add (&m->refs, 1);
1409 xine_rwlock_wrlock (&m->info_lock);
1410 m->side_streams[index] = s;
1411 xine_rwlock_unlock (&m->info_lock);
1412 return &s->s;
1413 }
1414
_x_mrl_unescape(char * mrl)1415 void _x_mrl_unescape (char *mrl) {
1416 static const uint8_t tab_unhex[256] = {
1417 #define nn 128
1418 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1419 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1420 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1421 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,nn,nn,nn,nn,nn,nn,
1422 nn,10,11,12,13,14,15,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1423 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1424 nn,10,11,12,13,14,15,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1425 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1426 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1427 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1428 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1429 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1430 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1431 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1432 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,
1433 nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn,nn
1434 };
1435 const uint8_t *p = (const uint8_t *)mrl;
1436 uint8_t *q;
1437 /* dont touch until first %xx */
1438 while (*p) {
1439 if (*p == '%') break;
1440 p++;
1441 }
1442 if (!*p)
1443 return;
1444 /* now really unescape */
1445 /* q = (uint8_t *)p ?? */
1446 q = (uint8_t *)mrl + (p - (const uint8_t *)mrl);
1447 while (1) {
1448 uint8_t z = *p++;
1449 if (z == '%') {
1450 uint8_t h = tab_unhex[*p];
1451 if (!(h & nn)) {
1452 z = h;
1453 p++;
1454 h = tab_unhex[*p];
1455 if (!(h & nn)) {
1456 z = (z << 4) | h;
1457 p++;
1458 }
1459 } else if (*p == '%') {
1460 p++;
1461 }
1462 }
1463 *q++ = z;
1464 if (!z) break;
1465 }
1466 #undef nn
1467 }
1468
_x_mrl_remove_auth(const char * mrl_in)1469 char *_x_mrl_remove_auth(const char *mrl_in)
1470 {
1471 char *mrl = strdup(mrl_in);
1472 char *auth, *p, *at, *host_end;
1473
1474 /* parse protocol */
1475 if (!(p = strchr(mrl, ':'))) {
1476 /* no protocol means plain filename */
1477 return mrl;
1478 }
1479
1480 p++; /* skip ':' */
1481 if (*p == '/') p++;
1482 if (*p == '/') p++;
1483
1484 /* authorization (user[:pass]@hostname) */
1485 auth = p;
1486 host_end = strchr(p, '/');
1487 while ((at = strchr(p, '@')) && at < host_end) {
1488 p = at + 1; /* skip '@' */
1489 }
1490
1491 if (p != auth) {
1492 while (p[-1]) {
1493 *auth++ = *p++;
1494 }
1495 }
1496
1497 return mrl;
1498 }
1499
1500 /* 0x01 (end), 0x02 (alpha), 0x04 (alnum - + .), 0x08 (:), 0x10 (;), 0x20 (#) */
1501 static const uint8_t tab_parse[256] = {
1502 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1504 0, 0, 0,32, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 4, 0,
1505 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8,16, 0, 0, 0, 0,
1506 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
1507 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0,
1508 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
1509 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0,
1510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1516 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1517 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1518 };
1519
1520 /* aka "does path have a protocol prefix" */
_x_path_looks_like_mrl(const char * path)1521 static inline int _x_path_looks_like_mrl (const char *path) {
1522 const uint8_t *p = (const uint8_t *)path;
1523 if (!(tab_parse[*p++] & 0x02))
1524 return 0;
1525 while (tab_parse[*p++] & 0x04) ;
1526 return (p[-1] == ':') && (p[0] == '/');
1527 }
1528
open_internal(xine_stream_private_t * stream,const char * mrl)1529 static int open_internal (xine_stream_private_t *stream, const char *mrl) {
1530
1531 static const uint8_t tab_tolower[256] = {
1532 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1533 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1534 ' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',
1535 '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
1536 '@','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
1537 'p','q','r','s','t','u','v','w','x','y','z','[','\\',']','^','_',
1538 '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
1539 'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~',127,
1540 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
1541 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
1542 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
1543 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
1544 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
1545 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
1546 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
1547 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
1548 };
1549
1550 uint8_t *buf, *name, *args;
1551 int no_cache = 0;
1552
1553 if (!mrl) {
1554 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("xine: error while parsing mrl\n"));
1555 stream->err = XINE_ERROR_MALFORMED_MRL;
1556 if (stream->status != XINE_STATUS_IDLE)
1557 stream->status = XINE_STATUS_STOP;
1558 return 0;
1559 }
1560
1561 lprintf ("opening MRL '%s'...\n", mrl);
1562
1563 /*
1564 * stop engine if necessary
1565 */
1566
1567 close_internal (stream);
1568
1569 lprintf ("engine should be stopped now\n");
1570
1571 /*
1572 * look for a stream_setup in MRL and try finding an input plugin
1573 */
1574 buf = malloc (32 + strlen (mrl) + 32);
1575 if (!buf)
1576 return 0;
1577 name = buf + 32;
1578 args = NULL;
1579 {
1580 const uint8_t *p = (const uint8_t *)mrl;
1581 uint8_t *prot = NULL, *q = name, z;
1582 /* test protocol prefix */
1583 if (tab_parse[*p] & 0x02) {
1584 while (tab_parse[z = *p] & 0x04) p++, *q++ = z;
1585 if ((q > name) && (z == ':') && (p[1] == '/')) prot = name;
1586 }
1587 if (prot) {
1588 /* split off args at first hash */
1589 while (!(tab_parse[z = *p] & 0x21)) p++, *q++ = z;
1590 *q = 0;
1591 if (z == '#') {
1592 p++;
1593 args = ++q;
1594 while ((*q++ = *p++) != 0) ;
1595 }
1596 } else {
1597 /* raw filename, may contain any number of hashes */
1598 while (1) {
1599 struct stat s;
1600 while (!(tab_parse[z = *p] & 0x21)) p++, *q++ = z;
1601 *q = 0;
1602 /* no need to stat when no hashes found */
1603 if (!args && !z) break;
1604 if (!stat ((const char *)name, &s)) {
1605 args = NULL;
1606 /* no general break yet, beware "/foo/#bar.flv" */
1607 }
1608 if (!z) break;
1609 p++, *q++ = z;
1610 args = q;
1611 }
1612 if (args) args[-1] = 0;
1613 }
1614 }
1615
1616 {
1617 /*
1618 * find an input plugin
1619 */
1620 stream->s.input_plugin = _x_find_input_plugin (&stream->s, (const char *)name);
1621
1622 if (stream->s.input_plugin) {
1623 int res;
1624 input_class_t *input_class = stream->s.input_plugin->input_class;
1625
1626 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: found input plugin : %s\n"),
1627 dgettext(input_class->text_domain ? input_class->text_domain : XINE_TEXTDOMAIN,
1628 input_class->description));
1629 if (stream->s.input_plugin->input_class->eject_media)
1630 stream->eject_class = stream->s.input_plugin->input_class;
1631 _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_INPUT_PLUGIN,
1632 stream->s.input_plugin->input_class->identifier);
1633
1634 res = (stream->s.input_plugin->open) (stream->s.input_plugin);
1635 switch(res) {
1636 case 1: /* Open successfull */
1637 break;
1638 case -1: /* Open unsuccessfull, but correct plugin */
1639 stream->err = XINE_ERROR_INPUT_FAILED;
1640 _x_flush_events_queues (&stream->s);
1641 free (buf);
1642 return 0;
1643 default:
1644 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: input plugin cannot open MRL [%s]\n"),mrl);
1645 _x_free_input_plugin (&stream->s, stream->s.input_plugin);
1646 stream->s.input_plugin = NULL;
1647 stream->err = XINE_ERROR_INPUT_FAILED;
1648 }
1649 }
1650 }
1651
1652 if (!stream->s.input_plugin) {
1653 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: cannot find input plugin for MRL [%s]\n"),mrl);
1654 stream->err = XINE_ERROR_NO_INPUT_PLUGIN;
1655 _x_flush_events_queues (&stream->s);
1656 free (buf);
1657 return 0;
1658 }
1659
1660 if (args) {
1661 uint8_t *entry = NULL;
1662
1663 while (*args) {
1664 /* Turn "WhatAGreat:Bullshit[;]" into key="whatagreat" entry="WhatAGreat" value="Bullshit". */
1665 uint8_t *key = buf, *value = NULL;
1666 if (entry)
1667 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: no value for \"%s\", ignoring.\n"), entry);
1668 entry = args;
1669 {
1670 uint8_t *spos = args + 31, sval = *spos, *q = key, z;
1671 *spos = 0;
1672 while (!(tab_parse[z = *args] & 0x19)) *q++ = tab_tolower[z], args++;
1673 *q = 0;
1674 *spos = sval;
1675 while (!(tab_parse[z = *args] & 0x19)) args++;
1676 if (z == ':') {
1677 *args++ = 0;
1678 value = args;
1679 while (!(tab_parse[z = *args] & 0x11)) args++;
1680 }
1681 if (z == ';')
1682 *args++ = 0;
1683 }
1684
1685 if (!memcmp (key, "demux", 6)) {
1686 if (value) {
1687 /* demuxer specified by name */
1688 char *demux_name = (char *)value;
1689 _x_mrl_unescape (demux_name);
1690 if (!(stream->demux.plugin = _x_find_demux_plugin_by_name (&stream->s, demux_name, stream->s.input_plugin))) {
1691 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: specified demuxer %s failed to start\n"), demux_name);
1692 stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1693 stream->status = XINE_STATUS_IDLE;
1694 free (buf);
1695 return 0;
1696 }
1697
1698 _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1699 stream->demux.plugin->demux_class->identifier);
1700 entry = NULL;
1701 }
1702 continue;
1703 }
1704
1705 if (!memcmp (key, "save", 5)) {
1706 if (value) {
1707 /* filename to save */
1708 char *filename = (char *)value;
1709 input_plugin_t *input_saver;
1710
1711 _x_mrl_unescape (filename);
1712
1713 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: join rip input plugin\n"));
1714 input_saver = _x_rip_plugin_get_instance (&stream->s, filename);
1715
1716 if( input_saver ) {
1717 stream->s.input_plugin = input_saver;
1718 } else {
1719 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("xine: error opening rip input plugin instance\n"));
1720 stream->err = XINE_ERROR_MALFORMED_MRL;
1721 stream->status = XINE_STATUS_IDLE;
1722 free (buf);
1723 return 0;
1724 }
1725 entry = NULL;
1726 }
1727 continue;
1728 }
1729
1730 if (!memcmp (key, "lastdemuxprobe", 15)) {
1731 if (value) {
1732 /* all demuxers will be probed before the specified one */
1733 char *demux_name = (char *)value;
1734 _x_mrl_unescape (demux_name);
1735 if (!(stream->demux.plugin = _x_find_demux_plugin_last_probe (&stream->s, demux_name, stream->s.input_plugin))) {
1736 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: last_probed demuxer %s failed to start\n"), demux_name);
1737 stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1738 stream->status = XINE_STATUS_IDLE;
1739 free (buf);
1740 return 0;
1741 }
1742 lprintf ("demux and input plugin found\n");
1743
1744 _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1745 stream->demux.plugin->demux_class->identifier);
1746 entry = NULL;
1747 }
1748 continue;
1749 }
1750
1751 if (!memcmp (key, "novideo", 8)) {
1752 _x_stream_info_set (&stream->s, XINE_STREAM_INFO_IGNORE_VIDEO, 1);
1753 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("ignoring video\n"));
1754 entry = NULL;
1755 continue;
1756 }
1757
1758 if (!memcmp (key, "noaudio", 8)) {
1759 _x_stream_info_set (&stream->s, XINE_STREAM_INFO_IGNORE_AUDIO, 1);
1760 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("ignoring audio\n"));
1761 entry = NULL;
1762 continue;
1763 }
1764
1765 if (!memcmp (key, "nospu", 6)) {
1766 _x_stream_info_set (&stream->s, XINE_STREAM_INFO_IGNORE_SPU, 1);
1767 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("ignoring subpicture\n"));
1768 entry = NULL;
1769 continue;
1770 }
1771
1772 if (!memcmp (key, "nocache", 8)) {
1773 no_cache = 1;
1774 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("input cache plugin disabled\n"));
1775 entry = NULL;
1776 continue;
1777 }
1778
1779 if (!memcmp (key, "volume", 7)) {
1780 if (value) {
1781 char *volume = (char *)value;
1782 _x_mrl_unescape (volume);
1783 xine_set_param (&stream->s, XINE_PARAM_AUDIO_VOLUME, atoi (volume));
1784 entry = NULL;
1785 }
1786 continue;
1787 }
1788
1789 if (!memcmp (key, "compression", 12)) {
1790 if (value) {
1791 char *compression = (char *)value;
1792 _x_mrl_unescape (compression);
1793 xine_set_param (&stream->s, XINE_PARAM_AUDIO_COMPR_LEVEL, atoi (compression));
1794 entry = NULL;
1795 }
1796 continue;
1797 }
1798
1799 if (!memcmp (key, "subtitle", 9)) {
1800 if (value) {
1801 char *subtitle_mrl = (char *)value;
1802 /* unescape for xine_open() if the MRL looks like a raw pathname */
1803 if (!_x_path_looks_like_mrl(subtitle_mrl))
1804 _x_mrl_unescape(subtitle_mrl);
1805 stream->s.slave = xine_stream_new (stream->s.xine, NULL, stream->s.video_out);
1806 stream->slave_affection = XINE_MASTER_SLAVE_PLAY | XINE_MASTER_SLAVE_STOP;
1807 if (xine_open (stream->s.slave, subtitle_mrl)) {
1808 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("subtitle mrl opened '%s'\n"), subtitle_mrl);
1809 stream->s.slave->master = &stream->s;
1810 stream->slave_is_subtitle = 1;
1811 } else {
1812 xprintf (stream->s.xine, XINE_VERBOSITY_LOG, _("xine: error opening subtitle mrl\n"));
1813 xine_dispose (stream->s.slave);
1814 stream->s.slave = NULL;
1815 }
1816 entry = NULL;
1817 }
1818 continue;
1819 }
1820
1821 if (value) {
1822 /* when we got here, the stream setup parameter must be a config entry */
1823 int retval;
1824 value[-1] = ':';
1825 _x_mrl_unescape ((char *)entry);
1826 retval = _x_config_change_opt (stream->s.xine->config, (char *)entry);
1827 if (retval <= 0) {
1828 value[-1] = 0;
1829 if (retval == 0) {
1830 /* the option not found */
1831 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: unknown config option \"%s\", ignoring.\n"), entry);
1832 } else {
1833 /* not permitted to change from MRL */
1834 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: changing option '%s' from MRL isn't permitted\n"), entry);
1835 }
1836 }
1837 entry = NULL;
1838 }
1839 }
1840 if (entry)
1841 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: no value for \"%s\", ignoring.\n"), entry);
1842 }
1843
1844 free (buf);
1845
1846 /* Nasty xine-ui issue:
1847 * 1. User pauses playback, then opens a playlist.
1848 * 2. Xine-ui grabs a separate stream tied to our "none" output plugins.
1849 * 3. Xine-ui tries to open every playlist item in turn in order to query some info like duration.
1850 * We dont discuss the performance and security implications thereof here.
1851 * But we do find that any such open attempt will freeze inside _x_demux_control_headers_done ()
1852 * below because the engine is still paused.
1853 * Workaround:
1854 * If fifo's are (nearly) empty, try that live pause hack.
1855 * If not, unpause for real. */
1856 if (_x_get_fine_speed (&stream->s) == XINE_SPEED_PAUSE) {
1857 if (stream->s.audio_fifo && (stream->s.audio_fifo->fifo_size < 10)
1858 && stream->s.video_fifo && (stream->s.video_fifo->fifo_size < 10)) {
1859 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
1860 "xine_open: switching to live pause mode to avoid freeze.\n");
1861 set_speed_internal (stream->side_streams[0], XINE_LIVE_PAUSE_ON);
1862 } else {
1863 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
1864 "xine_open: unpauseing to avoid freeze.\n");
1865 set_speed_internal (stream->side_streams[0], XINE_FINE_SPEED_NORMAL);
1866 }
1867 }
1868
1869 no_cache = no_cache || (stream->s.input_plugin->get_capabilities (stream->s.input_plugin) & INPUT_CAP_NO_CACHE);
1870 if( !no_cache )
1871 /* enable buffered input plugin (request optimizer) */
1872 stream->s.input_plugin = _x_cache_plugin_get_instance (&stream->s);
1873
1874 /* Let the plugin request a specific demuxer (if the user hasn't).
1875 * This overrides find-by-content & find-by-extension.
1876 */
1877 if (!stream->demux.plugin)
1878 {
1879 char *default_demux = NULL;
1880 stream->s.input_plugin->get_optional_data (stream->s.input_plugin, &default_demux, INPUT_OPTIONAL_DATA_DEMUXER);
1881 if (default_demux)
1882 {
1883 stream->demux.plugin = _x_find_demux_plugin_by_name (&stream->s, default_demux, stream->s.input_plugin);
1884 if (stream->demux.plugin)
1885 {
1886 lprintf ("demux and input plugin found\n");
1887 _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1888 stream->demux.plugin->demux_class->identifier);
1889 }
1890 else
1891 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: couldn't load plugin-specified demux %s for >%s<\n"), default_demux, mrl);
1892 }
1893 }
1894
1895 if (!stream->demux.plugin) {
1896
1897 /*
1898 * find a demux plugin
1899 */
1900 if (!(stream->demux.plugin = _x_find_demux_plugin (&stream->s, stream->s.input_plugin))) {
1901 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: couldn't find demux for >%s<\n"), mrl);
1902 stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1903
1904 stream->status = XINE_STATUS_IDLE;
1905
1906 /* force the engine to unregister fifo callbacks */
1907 _x_demux_control_nop (&stream->s, BUF_FLAG_END_STREAM);
1908
1909 return 0;
1910 }
1911 lprintf ("demux and input plugin found\n");
1912
1913 _x_meta_info_set_utf8 (&stream->s, XINE_META_INFO_SYSTEMLAYER,
1914 stream->demux.plugin->demux_class->identifier);
1915 }
1916
1917 {
1918 demux_class_t *demux_class = stream->demux.plugin->demux_class;
1919 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: found demuxer plugin: %s\n"),
1920 dgettext(demux_class->text_domain ? demux_class->text_domain : XINE_TEXTDOMAIN,
1921 demux_class->description));
1922 }
1923
1924 _x_extra_info_reset( stream->current_extra_info );
1925 _x_extra_info_reset( stream->video_decoder_extra_info );
1926 _x_extra_info_reset( stream->audio_decoder_extra_info );
1927
1928 /* assume handled for now. we will only know for sure after trying
1929 * to init decoders (which should happen when headers are sent)
1930 */
1931 _x_stream_info_set (&stream->s, XINE_STREAM_INFO_VIDEO_HANDLED, 1);
1932 _x_stream_info_set (&stream->s, XINE_STREAM_INFO_AUDIO_HANDLED, 1);
1933
1934 /*
1935 * send and decode headers
1936 */
1937
1938 stream->demux.plugin->send_headers (stream->demux.plugin);
1939
1940 if (stream->demux.plugin->get_status (stream->demux.plugin) != DEMUX_OK) {
1941 if (stream->demux.plugin->get_status (stream->demux.plugin) == DEMUX_FINISHED) {
1942 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: demuxer is already done. that was fast!\n"));
1943 } else {
1944 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine: demuxer failed to start\n"));
1945 }
1946
1947 _x_free_demux_plugin (&stream->s, &stream->demux.plugin);
1948
1949 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "demux disposed\n");
1950
1951 _x_free_input_plugin (&stream->s, stream->s.input_plugin);
1952 stream->s.input_plugin = NULL;
1953 stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
1954
1955 stream->status = XINE_STATUS_IDLE;
1956
1957 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "return from\n");
1958 return 0;
1959 }
1960
1961 _x_demux_control_headers_done (&stream->s);
1962
1963 stream->status = XINE_STATUS_STOP;
1964
1965 lprintf ("done\n");
1966 return 1;
1967 }
1968
xine_open(xine_stream_t * s,const char * mrl)1969 int xine_open (xine_stream_t *s, const char *mrl) {
1970 xine_stream_private_t *stream = (xine_stream_private_t *)s;
1971 xine_private_t *xine = (xine_private_t *)stream->s.xine;
1972 pthread_mutex_t *frontend_lock = &stream->side_streams[0]->frontend_lock;
1973 int ret;
1974
1975 pthread_mutex_lock (frontend_lock);
1976 pthread_cleanup_push (mutex_cleanup, (void *) frontend_lock);
1977
1978 lprintf ("open MRL:%s\n", mrl);
1979
1980 ret = open_internal (stream, mrl);
1981
1982 if (xine->join_av && mrl && (stream->side_streams[0] == stream)) do {
1983 char nbuf[1024];
1984 struct stat st;
1985 size_t nlen;
1986 xine_stream_private_t *side;
1987 const uint8_t *p, *n, *d;
1988 const char *orig = mrl;
1989 if (!strncasecmp (orig, "file:/", 6))
1990 orig += 6;
1991 n = d = p = (const uint8_t *)orig;
1992 while (1) {
1993 while (*p >= 0x30)
1994 p++;
1995 if ((*p == 0) || (*p == '#'))
1996 break;
1997 if (*p == '/') {
1998 p++;
1999 n = d = p;
2000 } else if (*p == '.') {
2001 d = p;
2002 p++;
2003 } else {
2004 p++;
2005 }
2006 }
2007 nlen = p - (const uint8_t *)orig;
2008 if (nlen > sizeof (nbuf) - 1)
2009 break;
2010 if ((n + 2 > d) || (d[-2] != '_') || (d[0] != '.'))
2011 break;
2012 if ((d[-1] != 'a') && (d[-1] != 'v'))
2013 break;
2014 if (stat (orig, &st))
2015 break;
2016 if (!S_ISREG (st.st_mode))
2017 break;
2018 memcpy (nbuf, orig, nlen);
2019 nbuf[nlen] = 0;
2020 nbuf[d - (const uint8_t *)orig - 1] = d[-1] == 'a' ? 'v' : 'a';
2021 if (stat (nbuf, &st))
2022 break;
2023 if (!S_ISREG (st.st_mode))
2024 break;
2025 side = (xine_stream_private_t *)xine_get_side_stream (&stream->s, 1);
2026 if (!side)
2027 break;
2028 xprintf (&xine->x, XINE_VERBOSITY_DEBUG,
2029 "xine_open: auto joining \"%s\" with \"%s\".\n", orig, nbuf);
2030 open_internal (side, nbuf);
2031 } while (0);
2032
2033 pthread_cleanup_pop (0);
2034 pthread_mutex_unlock (frontend_lock);
2035
2036 return ret;
2037 }
2038
wait_first_frame(xine_stream_private_t * stream)2039 static void wait_first_frame (xine_stream_private_t *stream) {
2040 if (stream->video_decoder_plugin || stream->audio_decoder_plugin) {
2041 pthread_mutex_lock (&stream->first_frame.lock);
2042 if (stream->first_frame.flag > 0) {
2043 struct timespec ts = {0, 0};
2044 xine_gettime (&ts);
2045 ts.tv_sec += 10;
2046 pthread_cond_timedwait(&stream->first_frame.reached, &stream->first_frame.lock, &ts);
2047 }
2048 pthread_mutex_unlock (&stream->first_frame.lock);
2049 }
2050 }
2051
play_internal(xine_stream_private_t * stream,int start_pos,int start_time)2052 static int play_internal (xine_stream_private_t *stream, int start_pos, int start_time) {
2053 xine_private_t *xine = (xine_private_t *)stream->s.xine;
2054 int flush;
2055 int first_frame_flag = 3;
2056 int demux_status;
2057 uint32_t input_is_seekable = 1;
2058 struct timespec ts1 = {0, 0}, ts2 = {0, 0};
2059 struct {
2060 xine_stream_private_t *s;
2061 uint32_t flags;
2062 } sides[XINE_NUM_SIDE_STREAMS + 1], *sp, *sp2;
2063
2064 if (stream->s.xine->verbosity >= XINE_VERBOSITY_DEBUG) {
2065 xine_gettime (&ts1);
2066 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
2067 "play_internal (%d.%03d, %d)\n", start_time / 1000, start_time % 1000, start_pos);
2068 }
2069
2070 /* list the streams (master and sides) with a demux. */
2071 {
2072 unsigned int u;
2073 sp = sides;
2074 xine_rwlock_rdlock (&stream->info_lock);
2075 for (u = 0; u < XINE_NUM_SIDE_STREAMS; u++) {
2076 xine_stream_private_t *side = stream->side_streams[u];
2077 if (side && side->demux.plugin) {
2078 sp->s = side;
2079 sp->flags = 0;
2080 sp++;
2081 }
2082 }
2083 xine_rwlock_unlock (&stream->info_lock);
2084 sp->s = NULL;
2085 sp->flags = 0;
2086 }
2087
2088 if (!sides[0].s) {
2089 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine_play: no demux available\n"));
2090 stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
2091
2092 return 0;
2093 }
2094
2095 if (start_pos || start_time) {
2096 stream->finished_naturally = 0;
2097 first_frame_flag = 2;
2098 }
2099 flush = (stream->s.master == &stream->s) && !stream->gapless_switch && !stream->finished_naturally;
2100 if (!flush)
2101 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: using gapless switch.\n");
2102
2103 /* hint demuxer thread we want to interrupt it */
2104 sp = sides;
2105 do {
2106 pthread_mutex_lock (&sp->s->demux.action_lock);
2107 sp->s->demux.action_pending += 0x10001;
2108 if (!(sp->s->demux.input_caps & (INPUT_CAP_SEEKABLE | INPUT_CAP_SLOW_SEEKABLE)))
2109 input_is_seekable = 0;
2110 pthread_mutex_unlock (&sp->s->demux.action_lock);
2111 sp++;
2112 } while (sp->s);
2113
2114 /* WTF??
2115 * TJ. OK these calls involve lock/unlock of the fifo mutexes.
2116 * Demux will do that again later by fifo->put ().
2117 * At least with x86 Linux, such a sequence forces a data cache sync from this thread
2118 * to the demux thread. This way, demux will see demux.action_pending > 0 early,
2119 * without the need to grab demux.action_lock for every iteration.
2120 * Reduces response delay by average 20ms. */
2121 (void)stream->s.video_fifo->size (stream->s.video_fifo);
2122 (void)stream->s.audio_fifo->size (stream->s.audio_fifo);
2123
2124 /* ignore speed changes (net_buf_ctrl causes deadlocks while seeking ...) */
2125 lock_run (stream, 1);
2126
2127 xine->port_ticket->acquire (xine->port_ticket, 1);
2128
2129 /* only flush/discard output ports on master streams */
2130 if (flush) {
2131 /* discard audio/video buffers to get engine going and take the lock faster */
2132 if (stream->s.audio_out)
2133 stream->s.audio_out->set_property (stream->s.audio_out, AO_PROP_DISCARD_BUFFERS, 1);
2134 if (stream->s.video_out)
2135 stream->s.video_out->set_property (stream->s.video_out, VO_PROP_DISCARD_FRAMES, 1);
2136 /* freeze safety (discontinuity wait?) when there are multiple streams.
2137 * or, when all input is seekable, suspend faster this way. */
2138 if (sides[1].s || input_is_seekable) {
2139 stream->s.video_fifo->clear (stream->s.video_fifo);
2140 stream->s.audio_fifo->clear (stream->s.audio_fifo);
2141 }
2142 }
2143
2144 sp = sides;
2145 do {
2146 pthread_mutex_lock (&sp->s->demux.lock);
2147 /* demux.lock taken. now demuxer is suspended. unblock io for seeking. */
2148 pthread_mutex_lock (&sp->s->demux.action_lock);
2149 sp->s->demux.action_pending -= 0x00001;
2150 pthread_mutex_unlock (&sp->s->demux.action_lock);
2151 sp++;
2152 } while (sp->s);
2153
2154 if (stream->s.xine->verbosity >= XINE_VERBOSITY_DEBUG) {
2155 int diff;
2156 xine_gettime (&ts2);
2157 diff = (int)(ts2.tv_nsec - ts1.tv_nsec) / 1000000;
2158 diff += (ts2.tv_sec - ts1.tv_sec) * 1000;
2159 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: ...demux suspended after %dms.\n", diff);
2160 }
2161
2162 /* set normal speed again (now that demuxer/input pair is suspended)
2163 * some input plugin may have changed speed by itself, we must ensure
2164 * the engine is not paused.
2165 */
2166 if (_x_get_fine_speed (&stream->s) != XINE_FINE_SPEED_NORMAL)
2167 set_speed_internal (stream, XINE_FINE_SPEED_NORMAL);
2168
2169 /*
2170 * start/seek demux
2171 */
2172
2173 pthread_mutex_lock (&stream->demux.pair);
2174 stream->demux.max_seek_bufs = sides[1].s ? 1 : 0xffffffff;
2175 pthread_mutex_unlock (&stream->demux.pair);
2176
2177 /* seek to new position (no data is sent to decoders yet) */
2178 sp = sides;
2179 do {
2180 xine_stream_private_t *s;
2181 int r;
2182 int32_t vtime = 0;
2183 if (!sides[1].s)
2184 break;
2185 sp2 = sides;
2186 do {
2187 if (sp2->s->demux.plugin->get_capabilities (sp2->s->demux.plugin) & DEMUX_CAP_VIDEO_TIME)
2188 break;
2189 sp2++;
2190 } while (sp2->s);
2191 if (!sp2->s)
2192 break;
2193 s = sp2->s;
2194 sp2->s = sides[0].s;
2195 sides[0].s = s;
2196 sp++;
2197 r = sides[0].s->demux.plugin->seek (sides[0].s->demux.plugin,
2198 start_pos, start_time, sides[0].s->demux.thread_running);
2199 sides[0].flags = r == DEMUX_OK ? 1 : 0;
2200 if (r != DEMUX_OK)
2201 break;
2202 if (sides[0].s->demux.plugin->get_optional_data (sides[0].s->demux.plugin, &vtime,
2203 DEMUX_OPTIONAL_DATA_VIDEO_TIME) != DEMUX_OPTIONAL_SUCCESS)
2204 break;
2205 start_pos = 0;
2206 start_time = vtime;
2207 } while (0);
2208 do {
2209 int r = sp->s->demux.plugin->seek (sp->s->demux.plugin,
2210 start_pos, start_time, sp->s->demux.thread_running);
2211 sp->flags = r == DEMUX_OK ? 1 : 0;
2212 sp++;
2213 } while (sp->s);
2214
2215 /* only flush/discard output ports on master streams */
2216 if (flush) {
2217 if (stream->s.audio_out)
2218 stream->s.audio_out->set_property (stream->s.audio_out, AO_PROP_DISCARD_BUFFERS, 0);
2219 if (stream->s.video_out)
2220 stream->s.video_out->set_property (stream->s.video_out, VO_PROP_DISCARD_FRAMES, 0);
2221 } else {
2222 stream->s.metronom->handle_audio_discontinuity (stream->s.metronom, DISC_GAPLESS, 0);
2223 }
2224
2225 xine->port_ticket->release (xine->port_ticket, 1);
2226 unlock_run (stream);
2227
2228 /* before resuming the demuxer, set first_frame_flag */
2229 pthread_mutex_lock (&stream->first_frame.lock);
2230 stream->first_frame.flag = first_frame_flag;
2231 pthread_mutex_unlock (&stream->first_frame.lock);
2232
2233 /* before resuming the demuxer, reset current position information */
2234 xine_current_extra_info_reset (stream);
2235
2236 /* now resume demuxer thread if it is running already */
2237 demux_status = 0;
2238 sp = sides;
2239 do {
2240 sp->flags |= sp->s->demux.thread_running ? 2 : 0;
2241 pthread_mutex_unlock (&sp->s->demux.lock);
2242 /* now that demux lock is released, resume demux. */
2243 pthread_mutex_lock (&sp->s->demux.action_lock);
2244 sp->s->demux.action_pending -= 0x10000;
2245 if (sp->s->demux.action_pending <= 0)
2246 pthread_cond_signal (&sp->s->demux.resume);
2247 pthread_mutex_unlock (&sp->s->demux.action_lock);
2248 /* seek OK but not running? try restart. */
2249 if (sp->flags == 1) {
2250 if (_x_demux_start_thread (&sp->s->s) >= 0)
2251 sp->flags = 3;
2252 }
2253 if (sp->flags == 3)
2254 demux_status++;
2255 sp++;
2256 } while (sp->s);
2257
2258 if (!demux_status)
2259 goto demux_failed;
2260
2261 stream->status = XINE_STATUS_PLAY;
2262 stream->finished_naturally = 0;
2263
2264
2265 /* Wait until the first frame produced is displayed
2266 * see video_out.c
2267 */
2268 wait_first_frame (stream);
2269 {
2270 extra_info_t info;
2271 int video_seek_count = xine_current_extra_info_get (stream, &info);
2272 if (info.seek_count != video_seek_count)
2273 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: warning: seek count still %d != %d.\n",
2274 info.seek_count, video_seek_count);
2275 }
2276
2277 if (stream->s.xine->verbosity >= XINE_VERBOSITY_DEBUG) {
2278 int diff;
2279 xine_gettime (&ts2);
2280 diff = (int)(ts2.tv_nsec - ts1.tv_nsec) / 1000000;
2281 diff += (ts2.tv_sec - ts1.tv_sec) * 1000;
2282 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "play_internal: ...done after %dms.\n", diff);
2283 }
2284
2285 return 1;
2286
2287 demux_failed:
2288 xine_log (stream->s.xine, XINE_LOG_MSG, _("xine_play: demux failed to start\n"));
2289
2290 stream->err = XINE_ERROR_DEMUX_FAILED;
2291 pthread_mutex_lock (&stream->first_frame.lock);
2292 stream->first_frame.flag = 0;
2293 // no need to signal: wait is done only in this function.
2294 pthread_mutex_unlock (&stream->first_frame.lock);
2295 return 0;
2296 }
2297
xine_play(xine_stream_t * s,int start_pos,int start_time)2298 int xine_play (xine_stream_t *s, int start_pos, int start_time) {
2299 xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
2300 int ret;
2301
2302 if (!stream)
2303 return 0;
2304 m = stream->side_streams[0];
2305
2306 pthread_mutex_lock (&m->frontend_lock);
2307 pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
2308
2309 m->delay_finish_event = 0;
2310
2311 ret = play_internal (m, start_pos, start_time);
2312 if (m->s.slave && (m->slave_affection & XINE_MASTER_SLAVE_PLAY) )
2313 xine_play (m->s.slave, start_pos, start_time);
2314
2315 m->gapless_switch = 0;
2316
2317 pthread_cleanup_pop (0);
2318 pthread_mutex_unlock (&m->frontend_lock);
2319
2320 return ret;
2321 }
2322
xine_eject(xine_stream_t * s)2323 int xine_eject (xine_stream_t *s) {
2324 xine_stream_private_t *stream = (xine_stream_private_t *)s, *m;
2325 int status;
2326
2327 if (!stream)
2328 return 0;
2329 m = stream->side_streams[0];
2330
2331 if (!m->eject_class)
2332 return 0;
2333
2334 pthread_mutex_lock (&m->frontend_lock);
2335 pthread_cleanup_push (mutex_cleanup, (void *) &m->frontend_lock);
2336
2337 status = 0;
2338 /* only eject, if we are stopped OR a different input plugin is playing */
2339 if (m->eject_class && m->eject_class->eject_media &&
2340 ((m->status == XINE_STATUS_STOP) ||
2341 m->eject_class != m->s.input_plugin->input_class)) {
2342
2343 status = m->eject_class->eject_media (m->eject_class);
2344 }
2345
2346 pthread_cleanup_pop (0);
2347 pthread_mutex_unlock (&m->frontend_lock);
2348
2349 return status;
2350 }
2351
xine_dispose_internal(xine_stream_private_t * stream)2352 static void xine_dispose_internal (xine_stream_private_t *stream) {
2353 xine_t *xine = stream->s.xine;
2354
2355 lprintf("stream: %p\n", (void*)stream);
2356
2357 xine->config->unregister_callbacks (xine->config, NULL, NULL, stream, sizeof (*stream));
2358
2359 pthread_mutex_lock (&xine->streams_lock);
2360 {
2361 xine_list_iterator_t ite = xine_list_find (xine->streams, stream);
2362 if (ite)
2363 xine_list_remove (xine->streams, ite);
2364 }
2365 /* keep xine instance open for this */
2366 stream->s.metronom->exit (stream->s.metronom);
2367 pthread_mutex_unlock (&xine->streams_lock);
2368
2369 pthread_mutex_destroy (&stream->frontend_lock);
2370 pthread_mutex_destroy (&stream->index.lock);
2371 pthread_cond_destroy (&stream->first_frame.reached);
2372 pthread_mutex_destroy (&stream->first_frame.lock);
2373 pthread_cond_destroy (&stream->counter.changed);
2374 pthread_mutex_destroy (&stream->counter.lock);
2375 pthread_mutex_destroy (&stream->event.lock);
2376 pthread_cond_destroy (&stream->demux.resume);
2377 pthread_mutex_destroy (&stream->demux.pair);
2378 pthread_mutex_destroy (&stream->demux.action_lock);
2379 pthread_mutex_destroy (&stream->demux.lock);
2380 xine_rwlock_destroy (&stream->meta_lock);
2381 xine_rwlock_destroy (&stream->info_lock);
2382
2383 xine_refs_sub (&stream->current_extra_info_index, xine_refs_get (&stream->current_extra_info_index));
2384
2385 xine_list_delete (stream->event.queues);
2386
2387 free (stream->index.array);
2388 free (stream);
2389 }
2390
xine_dispose(xine_stream_t * s)2391 void xine_dispose (xine_stream_t *s) {
2392 xine_stream_private_t *stream = (xine_stream_private_t *)s;
2393 /* decrease the reference counter
2394 * if there is no more reference on this stream, the xine_dispose_internal
2395 * function is called
2396 */
2397 if (!stream)
2398 return;
2399 /* never dispose side streams directly. */
2400 if (stream->side_streams[0] != stream)
2401 return;
2402
2403 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "xine_dispose\n");
2404 stream->status = XINE_STATUS_QUIT;
2405
2406 xine_close (&stream->s);
2407
2408 if (stream->s.master != &stream->s) {
2409 stream->s.master->slave = NULL;
2410 }
2411 if (stream->s.slave && (stream->s.slave->master == &stream->s)) {
2412 stream->s.slave->master = NULL;
2413 }
2414
2415 {
2416 unsigned int u;
2417 for (u = 1; u < XINE_NUM_SIDE_STREAMS; u++) {
2418 xine_stream_private_t *side = stream->side_streams[u];
2419 if (side)
2420 xine_refs_sub (&side->refs, 1);
2421 }
2422 }
2423
2424 if(stream->broadcaster)
2425 _x_close_broadcaster(stream->broadcaster);
2426
2427 /* Demuxers mpeg, mpeg_block and yuv_frames may send video pool buffers
2428 * to audio fifo. Fifos should be empty at this point. For safety,
2429 * shut down audio first anyway.
2430 */
2431 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "shutdown audio\n");
2432 _x_audio_decoder_shutdown (&stream->s);
2433
2434 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG, "shutdown video\n");
2435 _x_video_decoder_shutdown (&stream->s);
2436
2437 if (stream->s.osd_renderer)
2438 stream->s.osd_renderer->close (stream->s.osd_renderer);
2439
2440 /* Remove the reference that the stream was created with. */
2441 xine_refs_sub (&stream->refs, 1);
2442 }
2443
2444 #ifdef WIN32
2445 static int xine_wsa_users = 0;
2446 #endif
2447
xine_exit(xine_t * this_gen)2448 void xine_exit (xine_t *this_gen) {
2449 xine_private_t *this = (xine_private_t *)this_gen;
2450 if (this->x.streams) {
2451 int n = 10;
2452 /* XXX: streams kill themselves via their refs hook. */
2453 while (n--) {
2454 xine_stream_private_t *stream = NULL;
2455 xine_list_iterator_t ite;
2456
2457 pthread_mutex_lock (&this->x.streams_lock);
2458 ite = NULL;
2459 while (1) {
2460 stream = xine_list_next_value (this->x.streams, &ite);
2461 if (!ite || (stream && (&stream->s != XINE_ANON_STREAM)))
2462 break;
2463 }
2464 if (!ite) {
2465 pthread_mutex_unlock (&this->x.streams_lock);
2466 break;
2467 }
2468 /* stream->refcounter->lock might be taken already */
2469 {
2470 int i = xine_refs_add (&stream->refs, 0);
2471 pthread_mutex_unlock (&this->x.streams_lock);
2472 xprintf (&this->x, XINE_VERBOSITY_LOG,
2473 "xine_exit: BUG: stream %p still open (%d refs), waiting.\n",
2474 (void*)stream, i);
2475 }
2476 if (n) {
2477 xine_usec_sleep (50000);
2478 } else {
2479 #ifdef FORCE_STREAM_SHUTDOWN
2480 /* might raise even more heap damage, disabled for now */
2481 xprintf (&this->x, XINE_VERBOSITY_LOG,
2482 "xine_exit: closing stream %p.\n",
2483 (void*)stream);
2484 stream->refcounter->count = 1;
2485 xine_dispose (stream);
2486 n = 1;
2487 #endif
2488 }
2489 }
2490 xine_list_delete (this->x.streams);
2491 pthread_mutex_destroy (&this->x.streams_lock);
2492 }
2493
2494 if (this->x.config)
2495 this->x.config->unregister_callbacks (this->x.config, NULL, NULL, this, sizeof (*this));
2496
2497 xprintf (&this->x, XINE_VERBOSITY_DEBUG, "xine_exit: bye!\n");
2498
2499 _x_dispose_plugins (&this->x);
2500
2501 if (this->x.clock)
2502 this->x.clock->exit (this->x.clock);
2503
2504 if (this->x.config)
2505 this->x.config->dispose (this->x.config);
2506
2507 if(this->port_ticket)
2508 this->port_ticket->dispose(this->port_ticket);
2509
2510 pthread_cond_destroy (&this->speed_change_done);
2511 pthread_mutex_destroy (&this->speed_change_lock);
2512
2513 {
2514 int i;
2515 for (i = 0; i < XINE_LOG_NUM; i++)
2516 if (this->x.log_buffers[i])
2517 this->x.log_buffers[i]->dispose (this->x.log_buffers[i]);
2518 }
2519 pthread_mutex_destroy(&this->log_lock);
2520
2521 #if defined(WIN32)
2522 if (xine_wsa_users) {
2523 if (--xine_wsa_users == 0)
2524 WSACleanup ();
2525 }
2526 #endif
2527
2528 xdgWipeHandle (&this->x.basedir_handle);
2529
2530 free (this);
2531 }
2532
xine_new(void)2533 xine_t *xine_new (void) {
2534 xine_private_t *this;
2535
2536 this = calloc (1, sizeof (*this));
2537 if (!this)
2538 return NULL;
2539 #ifndef HAVE_ZERO_SAFE_MEM
2540 this->x.plugin_catalog = NULL;
2541 this->x.save_path = NULL;
2542 this->x.streams = NULL;
2543 this->x.clock = NULL;
2544 this->port_ticket = NULL;
2545 this->speed_change_flags = 0;
2546 #endif
2547
2548 pthread_mutex_init (&this->speed_change_lock, NULL);
2549 pthread_cond_init (&this->speed_change_done, NULL);
2550
2551 #ifdef ENABLE_NLS
2552 /*
2553 * i18n
2554 */
2555
2556 bindtextdomain(XINE_TEXTDOMAIN, XINE_LOCALEDIR);
2557 #endif
2558
2559 /*
2560 * config
2561 */
2562
2563 this->x.config = _x_config_init ();
2564 if (!this->x.config) {
2565 free(this);
2566 return NULL;
2567 }
2568
2569 /*
2570 * log buffers
2571 */
2572 memset (this->x.log_buffers, 0, sizeof (this->x.log_buffers));
2573 pthread_mutex_init (&this->log_lock, NULL);
2574
2575 #ifdef WIN32
2576 if (!xine_wsa_users) {
2577 /* WinSock Library Init. */
2578 WSADATA Data;
2579 int i_err = WSAStartup (MAKEWORD (1, 1), &Data);
2580 if (i_err) {
2581 fprintf (stderr, "error: can't initiate WinSocks, error %i\n", i_err);
2582 } else {
2583 xine_wsa_users++;
2584 }
2585 } else {
2586 xine_wsa_users++;
2587 }
2588 #endif /* WIN32 */
2589
2590 this->x.verbosity = XINE_VERBOSITY_NONE;
2591
2592 return &this->x;
2593 }
2594
xine_engine_set_param(xine_t * this,int param,int value)2595 void xine_engine_set_param(xine_t *this, int param, int value) {
2596
2597 if(this) {
2598 switch(param) {
2599
2600 case XINE_ENGINE_PARAM_VERBOSITY:
2601 this->verbosity = value;
2602 break;
2603
2604 default:
2605 lprintf("Unknown parameter %d\n", param);
2606 break;
2607 }
2608 }
2609 }
2610
xine_engine_get_param(xine_t * this,int param)2611 int xine_engine_get_param(xine_t *this, int param) {
2612
2613 if(this) {
2614 switch(param) {
2615
2616 case XINE_ENGINE_PARAM_VERBOSITY:
2617 return this->verbosity;
2618 break;
2619
2620 default:
2621 lprintf("Unknown parameter %d\n", param);
2622 break;
2623 }
2624 }
2625 return -1;
2626 }
2627
config_demux_strategy_cb(void * this_gen,xine_cfg_entry_t * entry)2628 static void config_demux_strategy_cb (void *this_gen, xine_cfg_entry_t *entry) {
2629 xine_t *this = (xine_t *)this_gen;
2630
2631 this->demux_strategy = entry->num_value;
2632 }
2633
config_save_cb(void * this_gen,xine_cfg_entry_t * entry)2634 static void config_save_cb (void *this_gen, xine_cfg_entry_t *entry) {
2635 xine_t *this = (xine_t *)this_gen;
2636 char homedir_trail_slash[strlen(xine_get_homedir()) + 2];
2637
2638 sprintf(homedir_trail_slash, "%s/", xine_get_homedir());
2639 if (entry->str_value[0] &&
2640 (entry->str_value[0] != '/' || strstr(entry->str_value, "/.") ||
2641 strcmp(entry->str_value, xine_get_homedir()) == 0 ||
2642 strcmp(entry->str_value, homedir_trail_slash) == 0)) {
2643 xine_stream_t *stream;
2644 xine_list_iterator_t ite;
2645
2646 xine_log(this, XINE_LOG_MSG,
2647 _("xine: The specified save_dir \"%s\" might be a security risk.\n"), entry->str_value);
2648
2649 pthread_mutex_lock(&this->streams_lock);
2650 ite = NULL;
2651 if ((stream = xine_list_next_value (this->streams, &ite))) {
2652 _x_message(stream, XINE_MSG_SECURITY, _("The specified save_dir might be a security risk."), NULL);
2653 }
2654 pthread_mutex_unlock(&this->streams_lock);
2655 }
2656
2657 this->save_path = entry->str_value;
2658 }
2659
xine_set_flags(xine_t * this_gen,int flags)2660 void xine_set_flags (xine_t *this_gen, int flags)
2661 {
2662 xine_private_t *this = (xine_private_t *)this_gen;
2663 this->flags = flags;
2664 }
2665
_x_query_network_timeout(xine_t * xine_gen)2666 int _x_query_network_timeout (xine_t *xine_gen) {
2667 xine_private_t *xine = (xine_private_t *)xine_gen;
2668 return xine ? xine->network_timeout : 30;
2669 }
2670
network_timeout_cb(void * this_gen,xine_cfg_entry_t * entry)2671 static void network_timeout_cb (void *this_gen, xine_cfg_entry_t *entry) {
2672 xine_private_t *this = (xine_private_t *)this_gen;
2673 this->network_timeout = entry->num_value;
2674 }
2675
2676 #ifdef ENABLE_IPV6
ip_pref_cb(void * this_gen,xine_cfg_entry_t * entry)2677 static void ip_pref_cb (void *this_gen, xine_cfg_entry_t *entry) {
2678 xine_private_t *this = (xine_private_t *)this_gen;
2679 this->ip_pref = entry->num_value;
2680 }
2681 #endif
2682
join_av_cb(void * this_gen,xine_cfg_entry_t * entry)2683 static void join_av_cb (void *this_gen, xine_cfg_entry_t *entry) {
2684 xine_private_t *this = (xine_private_t *)this_gen;
2685 this->join_av = entry->num_value;
2686 }
2687
xine_init(xine_t * this_gen)2688 void xine_init (xine_t *this_gen) {
2689 xine_private_t *this = (xine_private_t *)this_gen;
2690
2691 /* First of all, initialise libxdg-basedir as it's used by plugins. */
2692 setenv ("HOME", xine_get_homedir (), 0); /* libxdg-basedir needs $HOME */
2693 xdgInitHandle (&this->x.basedir_handle);
2694
2695 /* debug verbosity override */
2696 {
2697 int v = 0;
2698 const uint8_t *s = (const uint8_t *)getenv ("LIBXINE_VERBOSITY"), *t = s;
2699 uint8_t z;
2700 if (s) {
2701 while ((z = *s++ ^ '0') < 10)
2702 v = 10 * v + z;
2703 if (s > t + 1)
2704 this->x.verbosity = v;
2705 }
2706 }
2707
2708 /*
2709 * locks
2710 */
2711 pthread_mutex_init (&this->x.streams_lock, NULL);
2712
2713 /* initialize color conversion tables and functions */
2714 init_yuv_conversion();
2715
2716 /* probe for optimized memcpy or config setting */
2717 xine_probe_fast_memcpy (&this->x);
2718
2719 /*
2720 * plugins
2721 */
2722 XINE_PROFILE (_x_scan_plugins (&this->x));
2723
2724 #ifdef HAVE_SETLOCALE
2725 if (!setlocale(LC_CTYPE, ""))
2726 xprintf (&this->x, XINE_VERBOSITY_LOG, _("xine: locale not supported by C library\n"));
2727 #endif
2728
2729 /*
2730 * content detection strategy
2731 */
2732 {
2733 static const char *const demux_strategies[] = {"default", "reverse", "content", "extension", NULL};
2734 this->x.demux_strategy = this->x.config->register_enum (
2735 this->x.config, "engine.demux.strategy", 0,
2736 (char **)demux_strategies,
2737 _("media format detection strategy"),
2738 _("xine offers various methods to detect the media format of input to play. "
2739 "The individual values are:\n\n"
2740 "default\n"
2741 "First try to detect by content, then by file name extension.\n\n"
2742 "reverse\n"
2743 "First try to detect by file name extension, then by content.\n\n"
2744 "content\n"
2745 "Detect by content only.\n\n"
2746 "extension\n"
2747 "Detect by file name extension only.\n"),
2748 20, config_demux_strategy_cb, this);
2749 }
2750
2751 /*
2752 * save directory
2753 */
2754 this->x.save_path = this->x.config->register_filename (
2755 this->x.config,
2756 "media.capture.save_dir", "", XINE_CONFIG_STRING_IS_DIRECTORY_NAME,
2757 _("directory for saving streams"),
2758 _("When using the stream save feature, files will be written only into this directory.\n"
2759 "This setting is security critical, because when changed to a different directory, xine "
2760 "can be used to fill files in it with arbitrary content. So you should be careful that "
2761 "the directory you specify is robust against any content in any file."),
2762 XINE_CONFIG_SECURITY, config_save_cb, this);
2763
2764 /*
2765 * implicit configuration changes
2766 */
2767 this->x.config->register_bool (this->x.config,
2768 "misc.implicit_config", 0,
2769 _("allow implicit changes to the configuration (e.g. by MRL)"),
2770 _("If enabled, you allow xine to change your configuration without "
2771 "explicit actions from your side. For example configuration changes "
2772 "demanded by MRLs or embedded into playlist will be executed.\n"
2773 "This setting is security critcal, because xine can receive MRLs or "
2774 "playlists from untrusted remote sources. If you allow them to "
2775 "arbitrarily change your configuration, you might end with a totally "
2776 "messed up xine."),
2777 XINE_CONFIG_SECURITY, NULL, this);
2778
2779 /*
2780 * timeout for network I/O to avoid freezes
2781 */
2782 this->network_timeout = this->x.config->register_num (this->x.config,
2783 "media.network.timeout", 30,
2784 _("Timeout for network stream reading (in seconds)"),
2785 _("Specifies the timeout when reading from network streams, in seconds. "
2786 "Too low values might stop streaming when the source is slow or the "
2787 "bandwidth is occupied, too high values will freeze the player if the "
2788 "connection is lost."),
2789 0, network_timeout_cb, this);
2790
2791 #ifdef ENABLE_IPV6
2792 /*
2793 * network ip version
2794 */
2795 {
2796 static const char *const ip_versions[] = {"auto", "IPv4", "IPv4, IPv6", "IPv6, IPv4", NULL};
2797 this->ip_pref = this->x.config->register_enum (
2798 this->x.config, "media.network.ip_version", 1,
2799 (char **)ip_versions,
2800 _("Internet Protocol version(s) to use"),
2801 _("\"auto\" just tries what the name query returned.\n"
2802 "Otherwise, IPv4 may offer more compatibility and privacy."),
2803 20, ip_pref_cb, this);
2804 }
2805 #endif
2806
2807 /*
2808 * auto join separate audio/video files (testing the side stream feature).
2809 */
2810 this->join_av = this->x.config->register_bool (this->x.config,
2811 "media.files.join_av", 0,
2812 _("Auto join separate audio/video files"),
2813 _("When opening an audio only file \"foo_a.ext\", assume that \"foo_v.ext\" "
2814 "contains the missing video track for it, and vice versa.\n"
2815 "This mainly serves as a test for engine side streams."),
2816 20, join_av_cb, this);
2817
2818 /*
2819 * keep track of all opened streams
2820 */
2821 this->x.streams = xine_list_new ();
2822
2823 /*
2824 * start metronom clock
2825 */
2826
2827 this->x.clock = _x_metronom_clock_init (&this->x);
2828
2829 this->x.clock->start_clock (this->x.clock, 0);
2830
2831 /*
2832 * tickets
2833 */
2834 this->port_ticket = ticket_init();
2835 }
2836
_x_select_spu_channel(xine_stream_t * s,int channel)2837 void _x_select_spu_channel (xine_stream_t *s, int channel) {
2838 xine_stream_private_t *stream = (xine_stream_private_t *)s;
2839 xine_private_t *xine = (xine_private_t *)stream->s.xine;
2840 xine_stream_private_t *substream = NULL;
2841
2842 stream = stream->side_streams[0];
2843 substream = (xine_stream_private_t *)stream->s.slave;
2844
2845 pthread_mutex_lock (&stream->frontend_lock);
2846 stream->s.spu_channel_user = (channel >= -2 ? channel : -2);
2847
2848 xine->port_ticket->acquire (xine->port_ticket, 1);
2849
2850 switch (stream->s.spu_channel_user) {
2851 case -2:
2852 stream->s.spu_channel = -1;
2853 break;
2854 case -1:
2855 if (substream)
2856 stream->s.spu_channel = substream->s.spu_channel_auto;
2857 else
2858 stream->s.spu_channel = stream->s.spu_channel_auto;
2859 break;
2860 default:
2861 stream->s.spu_channel = stream->s.spu_channel_user;
2862 }
2863 lprintf ("set to %d\n", stream->s.spu_channel);
2864
2865 xine->port_ticket->release (xine->port_ticket, 1);
2866
2867 pthread_mutex_unlock (&stream->frontend_lock);
2868
2869 if (substream)
2870 {
2871 pthread_mutex_lock (&substream->frontend_lock);
2872 substream->s.spu_channel = stream->s.spu_channel;
2873 substream->s.spu_channel_user = stream->s.spu_channel_user;
2874 pthread_mutex_unlock (&substream->frontend_lock);
2875 }
2876 }
2877
_x_get_current_info(xine_stream_t * s,extra_info_t * extra_info,int size)2878 void _x_get_current_info (xine_stream_t *s, extra_info_t *extra_info, int size) {
2879 xine_stream_private_t *stream = (xine_stream_private_t *)s;
2880
2881 stream = stream->side_streams[0];
2882
2883 if (!extra_info || (size <= 0)) {
2884 return;
2885 } else if ((size_t)size < sizeof (*extra_info)) {
2886 extra_info_t info;
2887 xine_current_extra_info_get (stream, &info);
2888 memcpy (extra_info, &info, size);
2889 } else {
2890 xine_current_extra_info_get (stream, extra_info);
2891 }
2892 }
2893
2894
xine_get_status(xine_stream_t * s)2895 int xine_get_status (xine_stream_t *s) {
2896 xine_stream_private_t *stream = (xine_stream_private_t *)s;
2897 /* phonon bug */
2898 if (!stream) {
2899 printf ("xine_get_status: BUG: stream = NULL.\n");
2900 return XINE_STATUS_QUIT;
2901 }
2902 stream = stream->side_streams[0];
2903 return stream->status;
2904 }
2905
2906 /*
2907 * trick play
2908 */
2909
_x_set_fine_speed(xine_stream_t * s,int speed)2910 void _x_set_fine_speed (xine_stream_t *s, int speed) {
2911 xine_stream_private_t *stream = (xine_stream_private_t *)s;
2912 xine_private_t *xine = (xine_private_t *)stream->s.xine;
2913 uint32_t speed_change_flags;
2914
2915 stream = stream->side_streams[0];
2916
2917 /* net_buf_ctrl may have 2 threads trying to pause with ticket held in parallel.
2918 * Avoid that freeze like this:
2919 * - Hold speed_change_lock for finite time only.
2920 * - While changing speed, remember latest speed wishes from elsewhere,
2921 * and apply them after the current one. */
2922 pthread_mutex_lock (&xine->speed_change_lock);
2923 speed_change_flags = xine->speed_change_flags;
2924 if (speed_change_flags & SPEED_FLAG_IGNORE_CHANGE) {
2925 pthread_mutex_unlock (&xine->speed_change_lock);
2926 return;
2927 }
2928 if (speed_change_flags & SPEED_FLAG_CHANGING) {
2929 if ((speed == XINE_LIVE_PAUSE_ON) || (speed == XINE_LIVE_PAUSE_OFF)) {
2930 xine->speed_change_flags = speed_change_flags | SPEED_FLAG_WANT_LIVE;
2931 xine->speed_change_new_live = speed;
2932 pthread_mutex_unlock (&xine->speed_change_lock);
2933 return;
2934 }
2935 xine->speed_change_flags = speed_change_flags | SPEED_FLAG_WANT_NEW;
2936 xine->speed_change_new_speed = speed;
2937 pthread_mutex_unlock (&xine->speed_change_lock);
2938 return;
2939 }
2940 xine->speed_change_flags |= SPEED_FLAG_CHANGING;
2941 pthread_mutex_unlock (&xine->speed_change_lock);
2942
2943 while (1) {
2944 if (speed <= XINE_SPEED_PAUSE)
2945 speed = XINE_SPEED_PAUSE;
2946 xprintf (&xine->x, XINE_VERBOSITY_DEBUG, "set_speed %d.\n", speed);
2947 set_speed_internal (stream, speed);
2948 if (stream->s.slave && (stream->slave_affection & XINE_MASTER_SLAVE_SPEED))
2949 set_speed_internal ((xine_stream_private_t *)stream->s.slave, speed);
2950
2951 pthread_mutex_lock (&xine->speed_change_lock);
2952 speed_change_flags = xine->speed_change_flags;
2953 if (!(speed_change_flags & (SPEED_FLAG_WANT_LIVE | SPEED_FLAG_WANT_NEW))) {
2954 xine->speed_change_flags = speed_change_flags & ~(SPEED_FLAG_CHANGING | SPEED_FLAG_WANT_LIVE | SPEED_FLAG_WANT_NEW);
2955 if (speed_change_flags & SPEED_FLAG_IGNORE_CHANGE)
2956 pthread_cond_broadcast (&xine->speed_change_done);
2957 pthread_mutex_unlock (&xine->speed_change_lock);
2958 return;
2959 }
2960 if (speed_change_flags & SPEED_FLAG_WANT_LIVE) {
2961 xine->speed_change_flags = speed_change_flags & ~SPEED_FLAG_WANT_LIVE;
2962 speed = xine->speed_change_new_live;
2963 } else { /* speed_change_flags & SPEED_FLAG_WANT_NEW */
2964 xine->speed_change_flags = speed_change_flags & ~SPEED_FLAG_WANT_NEW;
2965 speed = xine->speed_change_new_speed;
2966 }
2967 pthread_mutex_unlock (&xine->speed_change_lock);
2968 }
2969 }
2970
_x_get_fine_speed(xine_stream_t * stream)2971 int _x_get_fine_speed (xine_stream_t *stream) {
2972 return stream->xine->clock->speed;
2973 }
2974
_x_set_speed(xine_stream_t * stream,int speed)2975 void _x_set_speed (xine_stream_t *stream, int speed) {
2976
2977 if (speed > XINE_SPEED_FAST_4)
2978 speed = XINE_SPEED_FAST_4;
2979
2980 _x_set_fine_speed (stream, speed * XINE_FINE_SPEED_NORMAL / XINE_SPEED_NORMAL);
2981 }
2982
_x_get_speed(xine_stream_t * stream)2983 int _x_get_speed (xine_stream_t *stream) {
2984 int speed = _x_get_fine_speed (stream);
2985
2986 /*
2987 * ensure compatibility with old API, only valid XINE_SPEED_xxx
2988 * constants are allowed. XINE_SPEED_NORMAL may only be returned
2989 * if speed is exactly XINE_FINE_SPEED_NORMAL.
2990 */
2991
2992 if( speed <= XINE_SPEED_PAUSE )
2993 return XINE_SPEED_PAUSE;
2994 if( speed <= XINE_SPEED_SLOW_4 * XINE_FINE_SPEED_NORMAL / XINE_SPEED_NORMAL )
2995 return XINE_SPEED_SLOW_4;
2996 if( speed < XINE_FINE_SPEED_NORMAL )
2997 return XINE_SPEED_SLOW_2;
2998 if( speed == XINE_FINE_SPEED_NORMAL )
2999 return XINE_SPEED_NORMAL;
3000 if( speed <= XINE_SPEED_FAST_2 * XINE_FINE_SPEED_NORMAL / XINE_SPEED_NORMAL )
3001 return XINE_SPEED_FAST_2;
3002 return XINE_SPEED_FAST_4;
3003 }
3004
3005
3006 /*
3007 * time measurement / seek
3008 */
3009
xine_get_pos_length(xine_stream_t * s,int * pos_stream,int * pos_time,int * length_time)3010 int xine_get_pos_length (xine_stream_t *s, int *pos_stream, int *pos_time, int *length_time) {
3011 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3012 extra_info_t info;
3013 int normpos, timepos;
3014
3015 stream = stream->side_streams[0];
3016 pthread_mutex_lock (&stream->frontend_lock);
3017
3018 if (!stream->s.input_plugin) {
3019 lprintf ("no input source\n");
3020 pthread_mutex_unlock (&stream->frontend_lock);
3021 return 0;
3022 }
3023
3024 if ((!stream->video_decoder_plugin && !stream->audio_decoder_plugin)) {
3025 /* rare case: no decoders available. */
3026 xine_rwlock_rdlock (&stream->info_lock);
3027 if (stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO]) {
3028 xine_rwlock_unlock (&stream->info_lock);
3029 xine_current_extra_info_set (stream, stream->video_decoder_extra_info);
3030 } else {
3031 xine_rwlock_unlock (&stream->info_lock);
3032 xine_current_extra_info_set (stream, stream->audio_decoder_extra_info);
3033 }
3034 }
3035 xine_current_extra_info_get (stream, &info);
3036 if (info.seek_count != stream->video_seek_count) {
3037 pthread_mutex_unlock (&stream->frontend_lock);
3038 return 0; /* position not yet known */
3039 }
3040 normpos = info.input_normpos;
3041 timepos = info.input_time;
3042
3043 if (length_time) {
3044 int length = 0;
3045 /* frontend lock prevents demux unload. To be very precise, we would need to
3046 * suspend demux here as well, and trash performance :-/
3047 * Well. Demux either knows length from the start, and value is constant.
3048 * Or, it grows with current position. We can do that, too. */
3049 if (stream->demux.plugin)
3050 length = stream->demux.plugin->get_stream_length (stream->demux.plugin);
3051 pthread_mutex_unlock (&stream->frontend_lock);
3052 if ((length > 0) && (length < timepos))
3053 length = timepos;
3054 *length_time = length;
3055 } else {
3056 pthread_mutex_unlock (&stream->frontend_lock);
3057 }
3058
3059 if (pos_stream)
3060 *pos_stream = normpos;
3061 if (pos_time)
3062 *pos_time = timepos;
3063 return 1;
3064 }
3065
_x_get_current_frame_data(xine_stream_t * stream,xine_current_frame_data_t * data,int flags,int img_size_unknown)3066 static int _x_get_current_frame_data (xine_stream_t *stream,
3067 xine_current_frame_data_t *data,
3068 int flags, int img_size_unknown) {
3069
3070 xine_private_t *xine;
3071 vo_frame_t *frame;
3072 size_t required_size = 0;
3073
3074 {
3075 xine_stream_private_t *s = (xine_stream_private_t *)stream;
3076 stream = &s->side_streams[0]->s;
3077 }
3078 xine = (xine_private_t *)stream->xine;
3079
3080 xine->port_ticket->acquire (xine->port_ticket, 1);
3081 frame = stream->video_out->get_last_frame (stream->video_out);
3082 xine->port_ticket->release (xine->port_ticket, 1);
3083
3084 if (!frame) {
3085 data->img_size = 0;
3086 return 0;
3087 }
3088
3089 data->width = frame->width;
3090 data->height = frame->height;
3091 data->crop_left = frame->crop_left;
3092 data->crop_right = frame->crop_right;
3093 data->crop_top = frame->crop_top;
3094 data->crop_bottom = frame->crop_bottom;
3095
3096 data->ratio_code = 10000.0 * frame->ratio;
3097 /* make ratio_code backward compatible */
3098 #define RATIO_LIKE(a, b) ((b) - 1 <= (a) && (a) <= 1 + (b))
3099 if (RATIO_LIKE(data->ratio_code, 10000))
3100 data->ratio_code = XINE_VO_ASPECT_SQUARE;
3101 else if (RATIO_LIKE(data->ratio_code, 13333))
3102 data->ratio_code = XINE_VO_ASPECT_4_3;
3103 else if (RATIO_LIKE(data->ratio_code, 17778))
3104 data->ratio_code = XINE_VO_ASPECT_ANAMORPHIC;
3105 else if (RATIO_LIKE(data->ratio_code, 21100))
3106 data->ratio_code = XINE_VO_ASPECT_DVB;
3107
3108 data->format = frame->format;
3109 data->interlaced = frame->progressive_frame ? 0 : (2 - frame->top_field_first);
3110
3111 switch (frame->format) {
3112
3113 default:
3114 if (frame->proc_provide_standard_frame_data) {
3115 uint8_t *img = data->img;
3116 size_t img_size = data->img_size;
3117 data->img = 0;
3118 data->img_size = 0;
3119
3120 /* ask frame implementation for required img buffer size */
3121 frame->proc_provide_standard_frame_data(frame, data);
3122 required_size = data->img_size;
3123
3124 data->img = img;
3125 data->img_size = img_size;
3126 break;
3127 }
3128
3129 if (!data->img && !(flags & XINE_FRAME_DATA_ALLOCATE_IMG))
3130 break; /* not interested in image data */
3131
3132 xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
3133 "xine: error, snapshot function not implemented for format 0x%x\n", frame->format);
3134 /* fall through and provide "green" YV12 image */
3135 data->format = XINE_IMGFMT_YV12;
3136 /* fall through */
3137 case XINE_IMGFMT_YV12:
3138 required_size = frame->width * frame->height
3139 + ((frame->width + 1) / 2) * ((frame->height + 1) / 2)
3140 + ((frame->width + 1) / 2) * ((frame->height + 1) / 2);
3141 break;
3142
3143 case XINE_IMGFMT_YUY2:
3144 required_size = frame->width * frame->height
3145 + ((frame->width + 1) / 2) * frame->height
3146 + ((frame->width + 1) / 2) * frame->height;
3147 break;
3148
3149 }
3150
3151 if (flags & XINE_FRAME_DATA_ALLOCATE_IMG) {
3152 /* return allocated buffer size */
3153 data->img_size = required_size;
3154 /* allocate img or fail */
3155 if (!(data->img = calloc(1, required_size))) {
3156 frame->free(frame);
3157 return 0;
3158 }
3159 } else {
3160 /* fail if supplied buffer is to small */
3161 if (data->img && !img_size_unknown && data->img_size < (int)required_size) {
3162 data->img_size = required_size;
3163 frame->free(frame);
3164 return 0;
3165 }
3166 /* return used buffer size */
3167 data->img_size = required_size;
3168 }
3169
3170 if (data->img) {
3171 switch (frame->format) {
3172
3173 case XINE_IMGFMT_YV12:
3174 yv12_to_yv12(
3175 /* Y */
3176 frame->base[0], frame->pitches[0],
3177 data->img, frame->width,
3178 /* U */
3179 frame->base[1], frame->pitches[1],
3180 data->img+frame->width*frame->height, frame->width/2,
3181 /* V */
3182 frame->base[2], frame->pitches[2],
3183 data->img+frame->width*frame->height+frame->width*frame->height/4, frame->width/2,
3184 /* width x height */
3185 frame->width, frame->height);
3186 break;
3187
3188 case XINE_IMGFMT_YUY2:
3189 yuy2_to_yuy2(
3190 /* src */
3191 frame->base[0], frame->pitches[0],
3192 /* dst */
3193 data->img, frame->width*2,
3194 /* width x height */
3195 frame->width, frame->height);
3196 break;
3197
3198 default:
3199 if (frame->proc_provide_standard_frame_data)
3200 frame->proc_provide_standard_frame_data(frame, data);
3201 else if (!(flags & XINE_FRAME_DATA_ALLOCATE_IMG))
3202 memset(data->img, 0, data->img_size);
3203 }
3204 }
3205
3206 frame->free(frame);
3207 return 1;
3208 }
3209
xine_get_current_frame_data(xine_stream_t * stream,xine_current_frame_data_t * data,int flags)3210 int xine_get_current_frame_data (xine_stream_t *stream,
3211 xine_current_frame_data_t *data,
3212 int flags) {
3213
3214 return _x_get_current_frame_data(stream, data, flags, 0);
3215 }
3216
xine_get_current_frame_alloc(xine_stream_t * stream,int * width,int * height,int * ratio_code,int * format,uint8_t ** img,int * img_size)3217 int xine_get_current_frame_alloc (xine_stream_t *stream, int *width, int *height,
3218 int *ratio_code, int *format,
3219 uint8_t **img, int *img_size) {
3220
3221 int result;
3222 xine_current_frame_data_t data;
3223
3224 memset(&data, 0, sizeof (data));
3225
3226 result = _x_get_current_frame_data(stream, &data, img ? XINE_FRAME_DATA_ALLOCATE_IMG : 0, 0);
3227 if (width) *width = data.width;
3228 if (height) *height = data.height;
3229 if (ratio_code) *ratio_code = data.ratio_code;
3230 if (format) *format = data.format;
3231 if (img_size) *img_size = data.img_size;
3232 if (img) *img = data.img;
3233 return result;
3234 }
3235
xine_get_current_frame_s(xine_stream_t * stream,int * width,int * height,int * ratio_code,int * format,uint8_t * img,int * img_size)3236 int xine_get_current_frame_s (xine_stream_t *stream, int *width, int *height,
3237 int *ratio_code, int *format,
3238 uint8_t *img, int *img_size) {
3239 int result;
3240 xine_current_frame_data_t data;
3241
3242 memset(&data, 0, sizeof (data));
3243 data.img = img;
3244 if (img_size)
3245 data.img_size = *img_size;
3246
3247 result = _x_get_current_frame_data(stream, &data, 0, 0);
3248 if (width) *width = data.width;
3249 if (height) *height = data.height;
3250 if (ratio_code) *ratio_code = data.ratio_code;
3251 if (format) *format = data.format;
3252 if (img_size) *img_size = data.img_size;
3253 return result;
3254 }
3255
xine_get_current_frame(xine_stream_t * stream,int * width,int * height,int * ratio_code,int * format,uint8_t * img)3256 int xine_get_current_frame (xine_stream_t *stream, int *width, int *height,
3257 int *ratio_code, int *format,
3258 uint8_t *img) {
3259 int result;
3260 xine_current_frame_data_t data;
3261
3262 memset(&data, 0, sizeof (data));
3263 data.img = img;
3264
3265 result = _x_get_current_frame_data(stream, &data, 0, 1);
3266 if (width) *width = data.width;
3267 if (height) *height = data.height;
3268 if (ratio_code) *ratio_code = data.ratio_code;
3269 if (format) *format = data.format;
3270 return result;
3271 }
3272
xine_new_grab_video_frame(xine_stream_t * stream)3273 xine_grab_video_frame_t* xine_new_grab_video_frame (xine_stream_t *stream) {
3274 xine_private_t *xine = (xine_private_t *)stream->xine;
3275 xine_grab_video_frame_t *frame;
3276
3277 xine->port_ticket->acquire (xine->port_ticket, 1);
3278
3279 {
3280 xine_stream_private_t *s = (xine_stream_private_t *)stream;
3281 stream = &s->side_streams[0]->s;
3282 }
3283
3284 if (stream->video_out->driver->new_grab_video_frame)
3285 frame = stream->video_out->driver->new_grab_video_frame(stream->video_out->driver);
3286 else
3287 frame = stream->video_out->new_grab_video_frame(stream->video_out);
3288
3289 xine->port_ticket->release (xine->port_ticket, 1);
3290
3291 return frame;
3292 }
3293
_get_spu_lang(xine_stream_private_t * stream,int channel,char * lang)3294 static int _get_spu_lang (xine_stream_private_t *stream, int channel, char *lang) {
3295 if (!lang)
3296 return 0;
3297
3298 /* Ask the demuxer first (e.g. TS extracts this information from
3299 * the stream)
3300 **/
3301 if (stream->demux.plugin) {
3302 if (stream->demux.plugin->get_capabilities (stream->demux.plugin) & DEMUX_CAP_SPULANG) {
3303 /* pass the channel number to the plugin in the data field */
3304 memcpy(lang, &channel, sizeof(channel));
3305 if (stream->demux.plugin->get_optional_data (stream->demux.plugin, lang,
3306 DEMUX_OPTIONAL_DATA_SPULANG) == DEMUX_OPTIONAL_SUCCESS)
3307 return 1;
3308 }
3309 }
3310
3311 /* No match, check with input plugin instead (e.g. DVD gets this
3312 * info from the IFO).
3313 **/
3314 if (stream->s.input_plugin) {
3315 if (stream->s.input_plugin->get_capabilities (stream->s.input_plugin) & INPUT_CAP_SPULANG) {
3316 /* pass the channel number to the plugin in the data field */
3317 memcpy(lang, &channel, sizeof(channel));
3318 if (stream->s.input_plugin->get_optional_data (stream->s.input_plugin, lang,
3319 INPUT_OPTIONAL_DATA_SPULANG) == INPUT_OPTIONAL_SUCCESS)
3320 return 1;
3321 }
3322 }
3323
3324 memcpy (lang, "und", 4);
3325 return 0;
3326 }
3327
xine_get_spu_lang(xine_stream_t * s,int channel,char * lang)3328 int xine_get_spu_lang (xine_stream_t *s, int channel, char *lang) {
3329 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3330 int ret;
3331
3332 pthread_mutex_lock (&stream->frontend_lock);
3333 ret = _get_spu_lang(stream, channel, lang);
3334 pthread_mutex_unlock (&stream->frontend_lock);
3335 return ret;
3336 }
3337
_get_audio_lang(xine_stream_private_t * stream,int channel,char * lang)3338 static int _get_audio_lang (xine_stream_private_t *stream, int channel, char *lang) {
3339 if (!lang)
3340 return 0;
3341
3342 if (stream->demux.plugin) {
3343 if (stream->demux.plugin->get_capabilities (stream->demux.plugin) & DEMUX_CAP_AUDIOLANG) {
3344 /* pass the channel number to the plugin in the data field */
3345 memcpy(lang, &channel, sizeof(channel));
3346 if (stream->demux.plugin->get_optional_data (stream->demux.plugin, lang,
3347 DEMUX_OPTIONAL_DATA_AUDIOLANG) == DEMUX_OPTIONAL_SUCCESS)
3348 return 1;
3349 }
3350 }
3351
3352 if (stream->s.input_plugin) {
3353 if (stream->s.input_plugin->get_capabilities (stream->s.input_plugin) & INPUT_CAP_AUDIOLANG) {
3354 /* pass the channel number to the plugin in the data field */
3355 memcpy(lang, &channel, sizeof(channel));
3356 if (stream->s.input_plugin->get_optional_data (stream->s.input_plugin, lang,
3357 INPUT_OPTIONAL_DATA_AUDIOLANG) == INPUT_OPTIONAL_SUCCESS)
3358 return 1;
3359 }
3360 }
3361
3362 memcpy (lang, "und", 4);
3363 return 0;
3364 }
3365
xine_get_audio_lang(xine_stream_t * s,int channel,char * lang)3366 int xine_get_audio_lang (xine_stream_t *s, int channel, char *lang) {
3367 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3368 int ret;
3369
3370 pthread_mutex_lock (&stream->frontend_lock);
3371 ret = _get_audio_lang(stream, channel, lang);
3372 pthread_mutex_unlock (&stream->frontend_lock);
3373 return ret;
3374 }
3375
_x_get_spu_channel(xine_stream_t * stream)3376 int _x_get_spu_channel (xine_stream_t *stream) {
3377 xine_stream_private_t *s = (xine_stream_private_t *)stream;
3378 stream = &s->side_streams[0]->s;
3379 return stream->spu_channel_user;
3380 }
3381
_x_get_video_streamtype(xine_stream_t * s)3382 int _x_get_video_streamtype (xine_stream_t *s) {
3383 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3384 stream = stream->side_streams[0];
3385 return stream->video_decoder_streamtype;
3386 }
3387
3388 /*
3389 * log functions
3390 */
xine_get_log_section_count(xine_t * this)3391 int xine_get_log_section_count (xine_t *this) {
3392 (void)this;
3393 return XINE_LOG_NUM;
3394 }
3395
xine_get_log_names(xine_t * this)3396 const char *const *xine_get_log_names (xine_t *this) {
3397 static const char *log_sections[XINE_LOG_NUM + 1];
3398
3399 log_sections[XINE_LOG_MSG] = _("messages");
3400 log_sections[XINE_LOG_PLUGIN] = _("plugin");
3401 log_sections[XINE_LOG_TRACE] = _("trace");
3402 log_sections[XINE_LOG_NUM] = NULL;
3403
3404 (void)this;
3405 return log_sections;
3406 }
3407
check_log_alloc(xine_private_t * this,int buf)3408 static inline void check_log_alloc (xine_private_t *this, int buf)
3409 {
3410 if (this->x.log_buffers[buf])
3411 return;
3412
3413 pthread_mutex_lock (&this->log_lock);
3414
3415 if (!this->x.log_buffers[buf])
3416 this->x.log_buffers[buf] = _x_new_scratch_buffer(150);
3417
3418 pthread_mutex_unlock (&this->log_lock);
3419 }
3420
xine_log(xine_t * this_gen,int buf,const char * format,...)3421 void xine_log (xine_t *this_gen, int buf, const char *format, ...) {
3422 xine_private_t *this = (xine_private_t *)this_gen;
3423 va_list argp;
3424 char buffer[SCRATCH_LINE_LEN_MAX];
3425
3426 check_log_alloc (this, buf);
3427
3428 va_start (argp, format);
3429 this->x.log_buffers[buf]->scratch_printf (this->x.log_buffers[buf], format, argp);
3430 va_end(argp);
3431
3432 if (this->x.verbosity) {
3433 va_start(argp, format);
3434 vsnprintf(buffer, SCRATCH_LINE_LEN_MAX, format, argp);
3435 printf("%s", buffer);
3436 va_end (argp);
3437 }
3438
3439 if (this->log_cb)
3440 this->log_cb (this->log_cb_user_data, buf);
3441 }
3442
xine_vlog(xine_t * this_gen,int buf,const char * format,va_list args)3443 void xine_vlog (xine_t *this_gen, int buf, const char *format,
3444 va_list args)
3445 {
3446 xine_private_t *this = (xine_private_t *)this_gen;
3447 check_log_alloc (this, buf);
3448
3449 this->x.log_buffers[buf]->scratch_printf (this->x.log_buffers[buf], format, args);
3450
3451 if (this->log_cb)
3452 this->log_cb (this->log_cb_user_data, buf);
3453 }
3454
xine_get_log(xine_t * this,int buf)3455 char *const *xine_get_log (xine_t *this, int buf) {
3456
3457 if(buf >= XINE_LOG_NUM)
3458 return NULL;
3459
3460 if ( this->log_buffers[buf] )
3461 return this->log_buffers[buf]->get_content (this->log_buffers[buf]);
3462 else
3463 return NULL;
3464 }
3465
xine_register_log_cb(xine_t * this_gen,xine_log_cb_t cb,void * user_data)3466 void xine_register_log_cb (xine_t *this_gen, xine_log_cb_t cb, void *user_data) {
3467 xine_private_t *this = (xine_private_t *)this_gen;
3468 this->log_cb = cb;
3469 this->log_cb_user_data = user_data;
3470 }
3471
xine_get_error(xine_stream_t * s)3472 int xine_get_error (xine_stream_t *s) {
3473 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3474 stream = stream->side_streams[0];
3475 return stream->err;
3476 }
3477
xine_stream_master_slave(xine_stream_t * m,xine_stream_t * slave,int affection)3478 int xine_stream_master_slave (xine_stream_t *m, xine_stream_t *slave, int affection) {
3479 xine_stream_private_t *master = (xine_stream_private_t *)m;
3480 master->s.slave = slave;
3481 master->slave_affection = affection;
3482 /* respect transitivity: if our designated master already has a master
3483 * of its own, we point to this master's master; if our master is a
3484 * standalone stream, its master pointer will point to itself */
3485 slave->master = master->s.master;
3486
3487 _x_select_spu_channel (m, master->s.spu_channel_user);
3488 return 1;
3489 }
3490
_x_query_buffer_usage(xine_stream_t * stream,int * num_video_buffers,int * num_audio_buffers,int * num_video_frames,int * num_audio_frames)3491 int _x_query_buffer_usage(xine_stream_t *stream, int *num_video_buffers, int *num_audio_buffers, int *num_video_frames, int *num_audio_frames)
3492 {
3493 xine_private_t *xine = (xine_private_t *)stream->xine;
3494 int ticket_acquired = -1;
3495
3496 {
3497 xine_stream_private_t *s = (xine_stream_private_t *)stream;
3498 stream = &s->side_streams[0]->s;
3499 }
3500
3501 if (num_video_buffers)
3502 *num_video_buffers = (stream->video_fifo ? stream->video_fifo->size(stream->video_fifo) : 0);
3503
3504 if (num_audio_buffers)
3505 *num_audio_buffers = (stream->audio_fifo ? stream->audio_fifo->size(stream->audio_fifo) : 0);
3506
3507 if ((num_video_frames && stream->video_out)
3508 || (num_audio_frames && stream->audio_out)) {
3509
3510 ticket_acquired = xine->port_ticket->acquire_nonblocking (xine->port_ticket, 1);
3511 }
3512
3513 if (num_video_frames)
3514 *num_video_frames = ((ticket_acquired && stream->video_out) ? stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_IN_FIFO) : 0);
3515
3516 if (num_audio_frames)
3517 *num_audio_frames = ((ticket_acquired && stream->audio_out) ? stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO) : 0);
3518
3519 if (ticket_acquired > 0)
3520 xine->port_ticket->release_nonblocking (xine->port_ticket, 1);
3521
3522 return ticket_acquired != 0;
3523 }
3524
_x_query_buffers_fix_data(xine_query_buffers_data_t * data)3525 static void _x_query_buffers_fix_data(xine_query_buffers_data_t *data)
3526 {
3527 if (data->total < 0)
3528 data->total = 0;
3529
3530 if (data->ready < 0)
3531 data->ready = 0;
3532
3533 if (data->avail < 0)
3534 data->avail = 0;
3535
3536 /* fix race condition of not filling data atomically */
3537 if (data->ready + data->avail > data->total)
3538 data->avail = data->total - data->ready;
3539 }
3540
_x_query_buffers(xine_stream_t * stream,xine_query_buffers_t * query)3541 int _x_query_buffers(xine_stream_t *stream, xine_query_buffers_t *query)
3542 {
3543 xine_private_t *xine = (xine_private_t *)stream->xine;
3544 int ticket_acquired = -1;
3545
3546 {
3547 xine_stream_private_t *s = (xine_stream_private_t *)stream;
3548 stream = &s->side_streams[0]->s;
3549 }
3550
3551 memset(query, 0, sizeof (*query));
3552
3553 if (stream->video_fifo)
3554 {
3555 query->vi.total = stream->video_fifo->buffer_pool_capacity;
3556 query->vi.ready = stream->video_fifo->size(stream->video_fifo);
3557 query->vi.avail = stream->video_fifo->num_free(stream->video_fifo);
3558 _x_query_buffers_fix_data(&query->vi);
3559 }
3560
3561 if (stream->audio_fifo)
3562 {
3563 query->ai.total = stream->audio_fifo->buffer_pool_capacity;
3564 query->ai.ready = stream->audio_fifo->size(stream->audio_fifo);
3565 query->ai.avail = stream->audio_fifo->num_free(stream->audio_fifo);
3566 _x_query_buffers_fix_data(&query->ai);
3567 }
3568
3569 if (stream->video_out || stream->audio_out)
3570 ticket_acquired = xine->port_ticket->acquire_nonblocking (xine->port_ticket, 1);
3571
3572 if (ticket_acquired > 0)
3573 {
3574 if (stream->video_out)
3575 {
3576 query->vo.total = stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_TOTAL);
3577 query->vo.ready = stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_IN_FIFO);
3578 query->vo.avail = stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_FREE);
3579 }
3580
3581 if (stream->audio_out)
3582 {
3583 query->ao.total = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_TOTAL);
3584 query->ao.ready = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO);
3585 query->ao.avail = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_FREE);
3586 }
3587
3588 xine->port_ticket->release_nonblocking (xine->port_ticket, 1);
3589 }
3590
3591 return ticket_acquired != 0;
3592 }
3593
_x_lock_port_rewiring(xine_t * xine_gen,int ms_timeout)3594 int _x_lock_port_rewiring (xine_t *xine_gen, int ms_timeout)
3595 {
3596 xine_private_t *xine = (xine_private_t *)xine_gen;
3597 return xine->port_ticket->lock_port_rewiring(xine->port_ticket, ms_timeout);
3598 }
3599
_x_unlock_port_rewiring(xine_t * xine_gen)3600 void _x_unlock_port_rewiring (xine_t *xine_gen)
3601 {
3602 xine_private_t *xine = (xine_private_t *)xine_gen;
3603 xine->port_ticket->unlock_port_rewiring(xine->port_ticket);
3604 }
3605
_x_lock_frontend(xine_stream_t * s,int ms_to_time_out)3606 int _x_lock_frontend (xine_stream_t *s, int ms_to_time_out) {
3607 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3608 stream = stream->side_streams[0];
3609 return lock_timeout (&stream->frontend_lock, ms_to_time_out);
3610 }
3611
_x_unlock_frontend(xine_stream_t * s)3612 void _x_unlock_frontend (xine_stream_t *s) {
3613 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3614 stream = stream->side_streams[0];
3615 pthread_mutex_unlock(&stream->frontend_lock);
3616 }
3617
_x_query_unprocessed_osd_events(xine_stream_t * stream)3618 int _x_query_unprocessed_osd_events(xine_stream_t *stream)
3619 {
3620 xine_private_t *xine = (xine_private_t *)stream->xine;
3621 video_overlay_manager_t *ovl;
3622 int redraw_needed;
3623
3624 {
3625 xine_stream_private_t *s = (xine_stream_private_t *)stream;
3626 stream = &s->side_streams[0]->s;
3627 }
3628
3629 if (!xine->port_ticket->acquire_nonblocking (xine->port_ticket, 1))
3630 return -1;
3631
3632 ovl = stream->video_out->get_overlay_manager(stream->video_out);
3633 redraw_needed = ovl->redraw_needed(ovl, 0);
3634
3635 if (redraw_needed)
3636 stream->video_out->trigger_drawing(stream->video_out);
3637
3638 xine->port_ticket->release_nonblocking (xine->port_ticket, 1);
3639
3640 return redraw_needed;
3641 }
3642
_x_continue_stream_processing(xine_stream_t * s)3643 int _x_continue_stream_processing (xine_stream_t *s) {
3644 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3645 stream = stream->side_streams[0];
3646 return stream->status != XINE_STATUS_STOP
3647 && stream->status != XINE_STATUS_QUIT;
3648 }
3649
_x_trigger_relaxed_frame_drop_mode(xine_stream_t * s)3650 void _x_trigger_relaxed_frame_drop_mode (xine_stream_t *s) {
3651 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3652 stream = stream->side_streams[0];
3653 pthread_mutex_lock (&stream->first_frame.lock);
3654 stream->first_frame.flag = 2;
3655 pthread_mutex_unlock (&stream->first_frame.lock);
3656 }
3657
_x_reset_relaxed_frame_drop_mode(xine_stream_t * s)3658 void _x_reset_relaxed_frame_drop_mode (xine_stream_t *s) {
3659 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3660 stream = stream->side_streams[0];
3661 pthread_mutex_lock (&stream->first_frame.lock);
3662 stream->first_frame.flag = 1;
3663 pthread_mutex_unlock (&stream->first_frame.lock);
3664 }
3665
3666
3667 #define KF_BITS 10
3668 #define KF_SIZE (1 << KF_BITS)
3669 #define KF_MASK (KF_SIZE - 1)
3670
xine_keyframes_find(xine_stream_t * s,xine_keyframes_entry_t * pos,int offs)3671 int xine_keyframes_find (xine_stream_t *s, xine_keyframes_entry_t *pos, int offs) {
3672 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3673 if (!stream || (&stream->s == XINE_ANON_STREAM) || !pos)
3674 return 2;
3675
3676 stream = stream->side_streams[0];
3677 pthread_mutex_lock (&stream->index.lock);
3678 if (!stream->index.array || !stream->index.used) {
3679 pthread_mutex_unlock (&stream->index.lock);
3680 return 2;
3681 }
3682 /* binary search the index */
3683 {
3684 xine_keyframes_entry_t *t = stream->index.array;
3685 int d, a = 0, e = stream->index.used, m = e >> 1, l;
3686 if ((pos->normpos > 0) && (pos->normpos < 0x10000)) {
3687 do {
3688 d = t[m].normpos - pos->normpos;
3689 if (d == 0)
3690 break;
3691 if (d > 0)
3692 e = m;
3693 else
3694 a = m;
3695 l = m;
3696 m = (a + e) >> 1;
3697 } while (m != l);
3698 if ((offs == 0) && (m + 1 < stream->index.used) &&
3699 (pos->normpos >= ((t[m].normpos + t[m + 1].normpos) >> 1)))
3700 m++;
3701 } else {
3702 do {
3703 d = t[m].msecs - pos->msecs;
3704 if (d == 0)
3705 break;
3706 if (d > 0)
3707 e = m;
3708 else
3709 a = m;
3710 l = m;
3711 m = (a + e) >> 1;
3712 } while (m != l);
3713 if ((offs == 0) && (m + 1 < stream->index.used) &&
3714 (pos->msecs >= ((t[m].msecs + t[m + 1].msecs) >> 1)))
3715 m++;
3716 }
3717 e = 0;
3718 if ((offs < 0) && (d != 0))
3719 offs++;
3720 m += offs;
3721 if (m < 0) {
3722 m = 0;
3723 e = 1;
3724 } else if (m >= stream->index.used) {
3725 m = stream->index.used - 1;
3726 e = 1;
3727 }
3728 *pos = t[m];
3729 pthread_mutex_unlock (&stream->index.lock);
3730 return e;
3731 }
3732 }
3733
_x_keyframes_add(xine_stream_t * s,xine_keyframes_entry_t * pos)3734 int _x_keyframes_add (xine_stream_t *s, xine_keyframes_entry_t *pos) {
3735 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3736 xine_keyframes_entry_t *t;
3737 stream = stream->side_streams[0];
3738 pthread_mutex_lock (&stream->index.lock);
3739 /* first ever entry */
3740 t = stream->index.array;
3741 if (!t) {
3742 t = calloc (KF_SIZE, sizeof (*t));
3743 if (!t) {
3744 pthread_mutex_unlock (&stream->index.lock);
3745 return -1;
3746 }
3747 t[0] = *pos;
3748 stream->index.array = t;
3749 stream->index.lastadd = 0;
3750 stream->index.used = 1;
3751 stream->index.size = KF_SIZE;
3752 pthread_mutex_unlock (&stream->index.lock);
3753 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
3754 "keyframes: build index while playing.\n");
3755 return 0;
3756 }
3757 /* enlarge buf */
3758 if (stream->index.used + 1 >= stream->index.size) {
3759 t = realloc (stream->index.array, (stream->index.size + KF_SIZE) * sizeof (*t));
3760 if (!t) {
3761 pthread_mutex_unlock (&stream->index.lock);
3762 return -1;
3763 }
3764 stream->index.array = t;
3765 stream->index.size += KF_SIZE;
3766 }
3767 /* binary search seek target */
3768 {
3769 /* fast detect the most common "progressive" case */
3770 int d, a = 0, m = stream->index.lastadd, l, e = stream->index.used;
3771 if (m + 1 < e)
3772 m++;
3773 do {
3774 d = t[m].msecs - pos->msecs;
3775 if (abs (d) < 10) {
3776 t[m] = *pos; /* already known */
3777 pthread_mutex_unlock (&stream->index.lock);
3778 return m;
3779 }
3780 if (d > 0)
3781 e = m;
3782 else
3783 a = m;
3784 l = m;
3785 m = (a + e) >> 1;
3786 } while (m != l);
3787 if (d < 0)
3788 m++;
3789 if (m < stream->index.used) /* insert */
3790 memmove (&t[m + 1], &t[m], (stream->index.used - m) * sizeof (*t));
3791 stream->index.used++;
3792 stream->index.lastadd = m;
3793 t[m] = *pos;
3794 pthread_mutex_unlock (&stream->index.lock);
3795 return m;
3796 }
3797 }
3798
xine_keyframes_get(xine_stream_t * s,int * size)3799 xine_keyframes_entry_t *xine_keyframes_get (xine_stream_t *s, int *size) {
3800 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3801 xine_keyframes_entry_t *ret;
3802 if (!stream || (&stream->s == XINE_ANON_STREAM) || !size)
3803 return NULL;
3804 stream = stream->side_streams[0];
3805 pthread_mutex_lock (&stream->index.lock);
3806 if (stream->index.array && stream->index.used) {
3807 ret = malloc (stream->index.used * sizeof (xine_keyframes_entry_t));
3808 if (ret) {
3809 memcpy (ret, stream->index.array, stream->index.used * sizeof (xine_keyframes_entry_t));
3810 *size = stream->index.used;
3811 }
3812 } else {
3813 ret = NULL;
3814 *size = 0;
3815 }
3816 pthread_mutex_unlock (&stream->index.lock);
3817 return ret;
3818 }
3819
_x_keyframes_set(xine_stream_t * s,xine_keyframes_entry_t * list,int size)3820 int _x_keyframes_set (xine_stream_t *s, xine_keyframes_entry_t *list, int size) {
3821 xine_stream_private_t *stream = (xine_stream_private_t *)s;
3822 int n = (size + KF_MASK) & ~KF_MASK;
3823 stream = stream->side_streams[0];
3824 pthread_mutex_lock (&stream->index.lock);
3825 if (stream->index.array) {
3826 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
3827 "keyframes: deleting index.\n");
3828 free (stream->index.array);
3829 }
3830 stream->index.lastadd = 0;
3831 stream->index.array = (list && (n > 0)) ? malloc (n * sizeof (xine_keyframes_entry_t)) : NULL;
3832 if (!stream->index.array) {
3833 stream->index.used = 0;
3834 stream->index.size = 0;
3835 pthread_mutex_unlock (&stream->index.lock);
3836 return 1;
3837 }
3838 memcpy (stream->index.array, list, size * sizeof (xine_keyframes_entry_t));
3839 stream->index.used = size;
3840 stream->index.size = n;
3841 n -= size;
3842 if (n > 0)
3843 memset (stream->index.array + size, 0, n * sizeof (xine_keyframes_entry_t));
3844 pthread_mutex_unlock (&stream->index.lock);
3845 xprintf (stream->s.xine, XINE_VERBOSITY_DEBUG,
3846 "keyframes: got %d of them.\n", stream->index.used);
3847 return 0;
3848 }
3849