1 /*
2 * Copyright (C) 2000-2019 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 * some helper functions for post plugins
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #define POST_INTERNAL
30
31 #include <xine/post.h>
32 #include "xine_private.h"
33
34 #include <stdarg.h>
35 #include <pthread.h>
36
37 #define HARD_DEBUG
38 #ifdef HARD_DEBUG
39 # define NAILS_S(struct,nail) memset (struct, nail, sizeof (*(struct)))
40 #else
41 # define NAILS_S(struct,nail)
42 #endif
43
44 /* TJ. O dear. It was intended that post plugins inside vo_frame.draw () did
45 call either
46 _x_post_frame_copy_down (f, f->next);
47 f->next->draw (f->next, stream);
48 _x_post_frame_copy_up (f, f->next);
49 or
50 _x_post_frame_u_turn (f, stream);
51 to set vo_frame.stream, and to lock that stream until the frame gets unreferenced
52 completely. Unfortunately,
53 - Most post plugins dont do that.
54 - It does not strictly guarantee a stream lock long enough.
55 - Somebody might change vo_frame.stream without proper relocking.
56 So lets do safe hidden locking when vo_frame.free () uses default post_frame_free ().
57 */
58 typedef struct {
59 vo_frame_t frame;
60 xine_stream_t *stream;
61 } vf_alias_t;
62
63 static void post_frame_lock (vo_frame_t *vo_img);
64 static void post_frame_proc_slice (vo_frame_t *vo_img, uint8_t **src);
65 static void post_frame_proc_frame (vo_frame_t *vo_img);
66 static void post_frame_field (vo_frame_t *vo_img, int which_field);
67 static int post_frame_draw (vo_frame_t *vo_img, xine_stream_t *stream);
68 static void post_frame_free (vo_frame_t *vo_img);
69 static void post_frame_dispose (vo_frame_t *vo_img);
70
post_new_video_alias(post_video_port_t * port,int usage)71 static vf_alias_t *post_new_video_alias (post_video_port_t *port, int usage) {
72 vf_alias_t *new_frame;
73 /* get a free frame slot */
74 pthread_mutex_lock (&port->usage_lock);
75 if (port->free_frame_slots) {
76 new_frame = (vf_alias_t *)port->free_frame_slots;
77 port->free_frame_slots = new_frame->frame.next;
78 } else {
79 new_frame = calloc (1, sizeof (vf_alias_t));
80 }
81 if (usage)
82 port->usage_count++;
83 pthread_mutex_unlock (&port->usage_lock);
84 return new_frame;
85 }
86
post_free_unused_video_alias(post_video_port_t * port,vf_alias_t * f)87 static void post_free_unused_video_alias (post_video_port_t *port, vf_alias_t *f) {
88 /* put the now free slot into the free frames list */
89 pthread_mutex_lock (&port->usage_lock);
90 f->frame.next = port->free_frame_slots;
91 port->free_frame_slots = &f->frame;
92 port->usage_count--;
93 if (port->usage_count || !port->post->dispose_pending) {
94 pthread_mutex_unlock (&port->usage_lock);
95 } else {
96 pthread_mutex_unlock (&port->usage_lock);
97 port->post->dispose (port->post);
98 }
99 }
100
post_intercept_video_frame(post_video_port_t * port,vo_frame_t * frame,vf_alias_t * new_frame,int usage)101 static vo_frame_t *post_intercept_video_frame (post_video_port_t *port, vo_frame_t *frame, vf_alias_t *new_frame, int usage) {
102
103 if (usage && port->frame_lock)
104 pthread_mutex_lock (port->frame_lock);
105
106 /* make a copy and attach the original */
107 xine_fast_memcpy (&new_frame->frame, frame, sizeof (vo_frame_t));
108 new_frame->frame.next = frame;
109
110 /* modify the frame with the intercept functions */
111 new_frame->frame.port = &port->new_port;
112 new_frame->frame.proc_frame = port->new_frame->proc_frame ? port->new_frame->proc_frame : NULL;
113 new_frame->frame.proc_slice = port->new_frame->proc_slice ? port->new_frame->proc_slice : NULL;
114 new_frame->frame.field = port->new_frame->field ? port->new_frame->field : post_frame_field;
115 new_frame->frame.draw = port->new_frame->draw ? port->new_frame->draw : post_frame_draw;
116 new_frame->frame.lock = port->new_frame->lock ? port->new_frame->lock : post_frame_lock;
117 new_frame->frame.free = port->new_frame->free ? port->new_frame->free : post_frame_free;
118 new_frame->frame.dispose = port->new_frame->dispose ? port->new_frame->dispose : post_frame_dispose;
119
120 /* Optimization: dont NULL stream ref, will often be reused later */
121 if ((new_frame->frame.free == post_frame_free) &&
122 new_frame->frame.stream && (new_frame->stream != new_frame->frame.stream)) {
123 xine_stream_private_t *s;
124 s = (xine_stream_private_t *)new_frame->frame.stream;
125 xine_refs_add (&s->refs, 1);
126 if (new_frame->stream) {
127 s = (xine_stream_private_t *)new_frame->stream;
128 xine_refs_sub (&s->refs, 1);
129 }
130 new_frame->stream = new_frame->frame.stream;
131 }
132
133 if (!port->new_frame->draw || (port->route_preprocessing_procs && port->route_preprocessing_procs(port, frame))) {
134 /* draw will most likely modify the frame, so the decoder
135 * should only request preprocessing when there is no new draw
136 * but route_preprocessing_procs() can override this decision */
137 if (frame->proc_frame && !new_frame->frame.proc_frame)
138 new_frame->frame.proc_frame = post_frame_proc_frame;
139 if (frame->proc_slice && !new_frame->frame.proc_slice)
140 new_frame->frame.proc_slice = post_frame_proc_slice;
141 }
142
143 if (usage && port->frame_lock)
144 pthread_mutex_unlock (port->frame_lock);
145
146 return &new_frame->frame;
147 }
148
post_restore_video_frame(vo_frame_t * frame,post_video_port_t * port,int usage)149 static vo_frame_t *post_restore_video_frame (vo_frame_t *frame, post_video_port_t *port, int usage) {
150 /* the first attched context is the original frame */
151 vo_frame_t *original = frame->next;
152
153 /* propagate any changes */
154 _x_post_frame_copy_down(frame, original);
155
156 if (usage && port->frame_lock)
157 pthread_mutex_unlock (port->frame_lock);
158
159 /* put the now free slot into the free frames list */
160 pthread_mutex_lock (&port->usage_lock);
161 frame->next = port->free_frame_slots;
162 port->free_frame_slots = frame;
163 /* Unref stream when already closed. */
164 if ((frame->free == post_frame_free) && !port->stream) {
165 vf_alias_t *f = (vf_alias_t *)frame;
166 if (f->stream) {
167 xine_stream_private_t *s = (xine_stream_private_t *)f->stream;
168 xine_refs_sub (&s->refs, 1);
169 f->stream = NULL;
170 }
171 }
172 if (usage) {
173 port->usage_count--;
174 if (port->usage_count || !port->post->dispose_pending)
175 usage = 0;
176 }
177 pthread_mutex_unlock (&port->usage_lock);
178
179 if (usage)
180 port->post->dispose (port->post);
181
182 return original;
183 }
184
185 /* (Un)ref intercepted post ports as well. This prevents nasty writes after free
186 with live filter chain editors like xine-ui. A generic port->open works but
187 raises a similar issue later when output is discarded before post.
188 */
189 static uint32_t post_video_get_capabilities (xine_video_port_t *port_gen);
190 static vo_frame_t *post_video_get_frame (xine_video_port_t *port_gen, uint32_t width,
191 uint32_t height, double ratio, int format, int flags);
192 static void post_video_enable_ovl (xine_video_port_t *port_gen, int ovl_enable);
193 static video_overlay_manager_t *post_video_get_overlay_manager (xine_video_port_t *port_gen);
194
post_video_port_ref(xine_video_port_t * port_gen)195 static int post_video_port_ref (xine_video_port_t *port_gen) {
196 post_video_port_t *port = (post_video_port_t *)port_gen;
197 int n = -1;
198 if (!port)
199 return n;
200 if ((port->new_port.get_capabilities == post_video_get_capabilities)
201 || (port->new_port.get_frame == post_video_get_frame)
202 || (port->new_port.enable_ovl == post_video_enable_ovl)
203 || (port->new_port.get_overlay_manager == post_video_get_overlay_manager)) {
204 pthread_mutex_lock (&port->usage_lock);
205 n = (++port->usage_count);
206 pthread_mutex_unlock (&port->usage_lock);
207 }
208 return n;
209 }
210
_x_post_video_port_ref(xine_video_port_t * port_gen)211 int _x_post_video_port_ref (xine_video_port_t *port_gen) {
212 return post_video_port_ref (port_gen);
213 }
214
post_video_port_unref(xine_video_port_t * port_gen)215 static int post_video_port_unref (xine_video_port_t *port_gen) {
216 post_video_port_t *port = (post_video_port_t *)port_gen;
217 int n = -1;
218 if (!port)
219 return n;
220 if ((port->new_port.get_capabilities == post_video_get_capabilities)
221 || (port->new_port.get_frame == post_video_get_frame)
222 || (port->new_port.enable_ovl == post_video_enable_ovl)
223 || (port->new_port.get_overlay_manager == post_video_get_overlay_manager)) {
224 pthread_mutex_lock (&port->usage_lock);
225 n = (--port->usage_count);
226 if (port->usage_count || !port->post->dispose_pending) {
227 pthread_mutex_unlock (&port->usage_lock);
228 } else {
229 pthread_mutex_unlock (&port->usage_lock);
230 port->post->dispose (port->post);
231 }
232 }
233 return n;
234 }
235
_x_post_video_port_unref(xine_video_port_t * port_gen)236 int _x_post_video_port_unref (xine_video_port_t *port_gen) {
237 return post_video_port_unref (port_gen);
238 }
239
240 static uint32_t post_audio_get_capabilities (xine_audio_port_t *port_gen);
241 static audio_buffer_t *post_audio_get_buffer (xine_audio_port_t *port_gen);
242 static int post_audio_control (xine_audio_port_t *port_gen, int cmd, ...);
243 static void post_audio_put_buffer (xine_audio_port_t *port_gen, audio_buffer_t *buf,
244 xine_stream_t *stream);
245
post_audio_port_ref(xine_audio_port_t * port_gen)246 static int post_audio_port_ref (xine_audio_port_t *port_gen) {
247 post_audio_port_t *port = (post_audio_port_t *)port_gen;
248 int n = -1;
249 if (!port)
250 return n;
251 if ((port->new_port.get_capabilities == post_audio_get_capabilities)
252 || (port->new_port.get_buffer == post_audio_get_buffer)
253 || (port->new_port.control == post_audio_control)
254 || (port->new_port.put_buffer == post_audio_put_buffer)) {
255 pthread_mutex_lock (&port->usage_lock);
256 n = (++port->usage_count);
257 pthread_mutex_unlock (&port->usage_lock);
258 }
259 return n;
260 }
261
_x_post_audio_port_ref(xine_audio_port_t * port_gen)262 int _x_post_audio_port_ref (xine_audio_port_t *port_gen) {
263 return post_audio_port_ref (port_gen);
264 }
265
post_audio_port_unref(xine_audio_port_t * port_gen)266 static int post_audio_port_unref (xine_audio_port_t *port_gen) {
267 post_audio_port_t *port = (post_audio_port_t *)port_gen;
268 int n = -1;
269 if (!port)
270 return n;
271 if ((port->new_port.get_capabilities == post_audio_get_capabilities)
272 || (port->new_port.get_buffer == post_audio_get_buffer)
273 || (port->new_port.control == post_audio_control)
274 || (port->new_port.put_buffer == post_audio_put_buffer)) {
275 pthread_mutex_lock (&port->usage_lock);
276 n = (--port->usage_count);
277 if (port->usage_count || !port->post->dispose_pending) {
278 pthread_mutex_unlock (&port->usage_lock);
279 } else {
280 pthread_mutex_unlock (&port->usage_lock);
281 port->post->dispose (port->post);
282 }
283 }
284 return n;
285 }
286
_x_post_audio_port_unref(xine_audio_port_t * port_gen)287 int _x_post_audio_port_unref (xine_audio_port_t *port_gen) {
288 return post_audio_port_unref (port_gen);
289 }
290
291
_x_post_init(post_plugin_t * post,int num_audio_inputs,int num_video_inputs)292 void _x_post_init(post_plugin_t *post, int num_audio_inputs, int num_video_inputs) {
293 post->input = xine_list_new();
294 post->output = xine_list_new();
295 post->xine_post.audio_input = calloc(num_audio_inputs + 1, sizeof(xine_audio_port_t *));
296 post->xine_post.video_input = calloc(num_video_inputs + 1, sizeof(xine_video_port_t *));
297 }
298
299 /* dummy intercept functions that just pass the call on to the original port */
post_video_get_capabilities(xine_video_port_t * port_gen)300 static uint32_t post_video_get_capabilities(xine_video_port_t *port_gen) {
301 post_video_port_t *port = (post_video_port_t *)port_gen;
302 uint32_t caps;
303
304 if (port->port_lock) pthread_mutex_lock(port->port_lock);
305 caps = port->original_port->get_capabilities(port->original_port);
306 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
307 return caps;
308 }
309
post_video_open(xine_video_port_t * port_gen,xine_stream_t * stream)310 static void post_video_open(xine_video_port_t *port_gen, xine_stream_t *stream) {
311 post_video_port_t *port = (post_video_port_t *)port_gen;
312
313 _x_post_inc_usage (port);
314 _x_post_rewire (port->post);
315 if (port->port_lock) pthread_mutex_lock(port->port_lock);
316 (port->original_port->open) (port->original_port, stream);
317 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
318 if (stream)
319 port->stream = stream;
320 }
321
post_video_get_frame(xine_video_port_t * port_gen,uint32_t width,uint32_t height,double ratio,int format,int flags)322 static vo_frame_t *post_video_get_frame(xine_video_port_t *port_gen, uint32_t width,
323 uint32_t height, double ratio, int format, int flags) {
324 post_video_port_t *port = (post_video_port_t *)port_gen;
325 vo_frame_t *frame;
326 /* We always need to ref this port here to protect it from
327 * possible port rewiring inside get_frame ().
328 * In the intercept case, we save an extra unref. */
329 vf_alias_t *alias = post_new_video_alias (port, 1);
330
331 if (port->port_lock) pthread_mutex_lock(port->port_lock);
332 frame = port->original_port->get_frame(port->original_port,
333 width, height, ratio, format, flags);
334 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
335
336 if (frame && (!port->intercept_frame || port->intercept_frame(port, frame))) {
337 frame = post_intercept_video_frame (port, frame, alias, 1);
338 } else {
339 post_free_unused_video_alias (port, alias);
340 }
341
342 return frame;
343 }
344
post_video_get_last_frame(xine_video_port_t * port_gen)345 static vo_frame_t *post_video_get_last_frame(xine_video_port_t *port_gen) {
346 post_video_port_t *port = (post_video_port_t *)port_gen;
347 vo_frame_t *frame;
348
349 if (port->port_lock) pthread_mutex_lock(port->port_lock);
350 frame = port->original_port->get_last_frame(port->original_port);
351 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
352 return frame;
353 }
354
post_video_new_grab_video_frame(xine_video_port_t * port_gen)355 static xine_grab_video_frame_t *post_video_new_grab_video_frame(xine_video_port_t *port_gen) {
356 post_video_port_t *port = (post_video_port_t *)port_gen;
357 xine_grab_video_frame_t *frame;
358
359 if (port->port_lock) pthread_mutex_lock(port->port_lock);
360 frame = port->original_port->new_grab_video_frame(port->original_port);
361 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
362 return frame;
363 }
364
post_video_enable_ovl(xine_video_port_t * port_gen,int ovl_enable)365 static void post_video_enable_ovl(xine_video_port_t *port_gen, int ovl_enable) {
366 post_video_port_t *port = (post_video_port_t *)port_gen;
367
368 if (port->port_lock) pthread_mutex_lock(port->port_lock);
369 port->original_port->enable_ovl(port->original_port, ovl_enable);
370 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
371 }
372
post_video_close(xine_video_port_t * port_gen,xine_stream_t * stream)373 static void post_video_close(xine_video_port_t *port_gen, xine_stream_t *stream) {
374 post_video_port_t *port = (post_video_port_t *)port_gen;
375 vf_alias_t *f;
376
377 if (port->port_lock) pthread_mutex_lock(port->port_lock);
378 port->original_port->close(port->original_port, stream);
379 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
380 if (stream) {
381 /* XXX: do a real stream database like video_out ? */
382 port->stream = NULL;
383 pthread_mutex_lock (&port->usage_lock);
384 f = (vf_alias_t *)port->free_frame_slots;
385 while (f) {
386 if ((f->frame.free == post_frame_free) && f->stream) {
387 xine_stream_private_t *s = (xine_stream_private_t *)f->stream;
388 xine_refs_sub (&s->refs, 1);
389 f->stream = NULL;
390 }
391 f = (vf_alias_t *)f->frame.next;
392 }
393 pthread_mutex_unlock (&port->usage_lock);
394 }
395 _x_post_dec_usage (port);
396 }
397
post_video_exit(xine_video_port_t * port_gen)398 static void post_video_exit(xine_video_port_t *port_gen) {
399 post_video_port_t *port = (post_video_port_t *)port_gen;
400
401 if (port->port_lock) pthread_mutex_lock(port->port_lock);
402 port->original_port->exit(port->original_port);
403 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
404 }
405
post_video_get_overlay_manager(xine_video_port_t * port_gen)406 static video_overlay_manager_t *post_video_get_overlay_manager(xine_video_port_t *port_gen) {
407 post_video_port_t *port = (post_video_port_t *)port_gen;
408 video_overlay_manager_t *manager;
409
410 if (port->port_lock) pthread_mutex_lock(port->port_lock);
411 manager = port->original_port->get_overlay_manager(port->original_port);
412 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
413
414 if (port->intercept_ovl && port->intercept_ovl(port)) {
415 if (manager && !port->original_manager)
416 /* this is the first access to overlay manager */
417 _x_post_intercept_overlay_manager(manager, port);
418 else
419 /* the original port might have changed */
420 port->original_manager = manager;
421 return port->new_manager;
422 } else
423 return manager;
424 }
425
post_video_flush(xine_video_port_t * port_gen)426 static void post_video_flush(xine_video_port_t *port_gen) {
427 post_video_port_t *port = (post_video_port_t *)port_gen;
428
429 if (port->port_lock) pthread_mutex_lock(port->port_lock);
430 port->original_port->flush(port->original_port);
431 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
432 }
433
post_video_trigger_drawing(xine_video_port_t * port_gen)434 static void post_video_trigger_drawing(xine_video_port_t *port_gen) {
435 post_video_port_t *port = (post_video_port_t *)port_gen;
436
437 if (port->port_lock) pthread_mutex_lock(port->port_lock);
438 port->original_port->trigger_drawing(port->original_port);
439 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
440 }
441
post_video_status(xine_video_port_t * port_gen,xine_stream_t * stream,int * width,int * height,int64_t * img_duration)442 static int post_video_status(xine_video_port_t *port_gen, xine_stream_t *stream,
443 int *width, int *height, int64_t *img_duration) {
444 post_video_port_t *port = (post_video_port_t *)port_gen;
445 int status;
446
447 if (port->port_lock) pthread_mutex_lock(port->port_lock);
448 status = port->original_port->status(port->original_port, stream, width, height, img_duration);
449 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
450 return status;
451 }
452
post_video_get_property(xine_video_port_t * port_gen,int property)453 static int post_video_get_property(xine_video_port_t *port_gen, int property) {
454 post_video_port_t *port = (post_video_port_t *)port_gen;
455 int prop;
456
457 if (port->port_lock) pthread_mutex_lock(port->port_lock);
458 prop = port->original_port->get_property(port->original_port, property);
459 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
460 return prop;
461 }
462
post_video_set_property(xine_video_port_t * port_gen,int property,int value)463 static int post_video_set_property(xine_video_port_t *port_gen, int property, int value) {
464 post_video_port_t *port = (post_video_port_t *)port_gen;
465 int val;
466
467 if (port->port_lock) pthread_mutex_lock(port->port_lock);
468 val = port->original_port->set_property(port->original_port, property, value);
469 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
470 return val;
471 }
472
473
post_video_rewire(xine_post_out_t * output_gen,void * data)474 static int post_video_rewire(xine_post_out_t *output_gen, void *data) {
475 post_out_t *output = (post_out_t *)output_gen;
476 xine_video_port_t *new_port = (xine_video_port_t *)data;
477 post_video_port_t *input_port = (post_video_port_t *)output->user_data;
478 post_plugin_t *this = output->post;
479 int64_t img_duration;
480 int width, height;
481
482 if (!new_port)
483 return 0;
484
485 this->running_ticket->revoke (this->running_ticket, XINE_TICKET_FLAG_REWIRE);
486
487 if (new_port) {
488 /* The wiring itself. */
489 post_video_port_ref (new_port);
490 /* The user stuff. */
491 if (input_port->stream)
492 new_port->open (new_port, input_port->stream);
493 }
494 if (input_port->original_port) {
495 if (input_port->stream &&
496 input_port->original_port->status (input_port->original_port, input_port->stream,
497 &width, &height, &img_duration))
498 input_port->original_port->close (input_port->original_port, input_port->stream);
499 post_video_port_unref (input_port->original_port);
500 }
501 input_port->original_port = new_port;
502
503 this->running_ticket->issue (this->running_ticket, XINE_TICKET_FLAG_REWIRE);
504
505 return 1;
506 }
507
508
_x_post_intercept_video_port(post_plugin_t * post,xine_video_port_t * original,post_in_t ** input,post_out_t ** output)509 post_video_port_t *_x_post_intercept_video_port(post_plugin_t *post, xine_video_port_t *original,
510 post_in_t **input, post_out_t **output) {
511 post_video_port_t *port = calloc(1, sizeof(post_video_port_t));
512
513 if (!port)
514 return NULL;
515
516 port->new_port.get_capabilities = post_video_get_capabilities;
517 port->new_port.open = post_video_open;
518 port->new_port.get_frame = post_video_get_frame;
519 port->new_port.get_last_frame = post_video_get_last_frame;
520 port->new_port.new_grab_video_frame = post_video_new_grab_video_frame;
521 port->new_port.enable_ovl = post_video_enable_ovl;
522 port->new_port.close = post_video_close;
523 port->new_port.exit = post_video_exit;
524 port->new_port.get_overlay_manager = post_video_get_overlay_manager;
525 port->new_port.flush = post_video_flush;
526 port->new_port.trigger_drawing = post_video_trigger_drawing;
527 port->new_port.status = post_video_status;
528 port->new_port.get_property = post_video_get_property;
529 port->new_port.set_property = post_video_set_property;
530 port->new_port.driver = original->driver;
531
532 post_video_port_ref (original);
533 port->original_port = original;
534 port->new_frame = &port->frame_storage;
535 port->new_manager = &port->manager_storage;
536 port->post = post;
537
538 pthread_mutex_init(&port->usage_lock, NULL);
539 pthread_mutex_init(&port->free_frames_lock, NULL);
540
541 if (input) {
542 *input = calloc(1, sizeof(post_in_t));
543 if (!*input) return port;
544 (*input)->xine_in.name = "video in";
545 (*input)->xine_in.type = XINE_POST_DATA_VIDEO;
546 (*input)->xine_in.data = &port->new_port;
547 (*input)->post = post;
548 xine_list_push_back(post->input, *input);
549 }
550
551 if (output) {
552 *output = calloc(1, sizeof(post_out_t));
553 if (!*output) return port;
554 (*output)->xine_out.name = "video out";
555 (*output)->xine_out.type = XINE_POST_DATA_VIDEO;
556 (*output)->xine_out.data = &port->original_port;
557 (*output)->xine_out.rewire = post_video_rewire;
558 (*output)->post = post;
559 (*output)->user_data = port;
560 xine_list_push_back(post->output, *output);
561 }
562
563 return port;
564 }
565
566
567 /* Default intercept functions for frames. */
post_frame_free(vo_frame_t * vo_img)568 static void post_frame_free(vo_frame_t *vo_img) {
569 post_video_port_t *port = _x_post_video_frame_to_port(vo_img);
570
571 if (port->frame_lock) pthread_mutex_lock(port->frame_lock);
572 if (--vo_img->lock_counter == 0) {
573 /* this frame is free */
574 vo_img = post_restore_video_frame (vo_img, port, 1);
575 /* unlock (port->frame_lock) already done above */
576 vo_img->free(vo_img);
577 } else if (vo_img->next) {
578 /* this frame is still in use */
579 _x_post_frame_copy_down(vo_img, vo_img->next);
580 vo_img->next->free(vo_img->next);
581 _x_post_frame_copy_up(vo_img, vo_img->next);
582 if (port->frame_lock) pthread_mutex_unlock(port->frame_lock);
583 } else {
584 if (port->frame_lock) pthread_mutex_unlock(port->frame_lock);
585 }
586 }
587
post_frame_proc_slice(vo_frame_t * vo_img,uint8_t ** src)588 static void post_frame_proc_slice(vo_frame_t *vo_img, uint8_t **src) {
589 post_video_port_t *port = _x_post_video_frame_to_port(vo_img);
590
591 if (port->frame_lock) pthread_mutex_lock(port->frame_lock);
592 _x_post_frame_copy_down(vo_img, vo_img->next);
593 vo_img->next->proc_slice(vo_img->next, src);
594 _x_post_frame_copy_up(vo_img, vo_img->next);
595 if (port->frame_lock) pthread_mutex_unlock(port->frame_lock);
596 }
597
post_frame_proc_frame(vo_frame_t * vo_img)598 static void post_frame_proc_frame(vo_frame_t *vo_img) {
599 post_video_port_t *port = _x_post_video_frame_to_port(vo_img);
600
601 if (port->frame_lock) pthread_mutex_lock(port->frame_lock);
602 _x_post_frame_copy_down(vo_img, vo_img->next);
603 vo_img->next->proc_frame(vo_img->next);
604 _x_post_frame_copy_up(vo_img, vo_img->next);
605 if (port->frame_lock) pthread_mutex_unlock(port->frame_lock);
606 }
607
post_frame_field(vo_frame_t * vo_img,int which_field)608 static void post_frame_field(vo_frame_t *vo_img, int which_field) {
609 post_video_port_t *port = _x_post_video_frame_to_port(vo_img);
610
611 if (port->frame_lock) pthread_mutex_lock(port->frame_lock);
612 _x_post_frame_copy_down(vo_img, vo_img->next);
613 vo_img->next->field(vo_img->next, which_field);
614 _x_post_frame_copy_up(vo_img, vo_img->next);
615 if (port->frame_lock) pthread_mutex_unlock(port->frame_lock);
616 }
617
post_frame_draw(vo_frame_t * vo_img,xine_stream_t * stream)618 static int post_frame_draw(vo_frame_t *vo_img, xine_stream_t *stream) {
619 post_video_port_t *port = _x_post_video_frame_to_port(vo_img);
620 int skip;
621
622 if (port->frame_lock) pthread_mutex_lock(port->frame_lock);
623 _x_post_frame_copy_down(vo_img, vo_img->next);
624 skip = vo_img->next->draw(vo_img->next, stream);
625 _x_post_frame_copy_up(vo_img, vo_img->next);
626 if (port->frame_lock) pthread_mutex_unlock(port->frame_lock);
627 return skip;
628 }
629
post_frame_lock(vo_frame_t * vo_img)630 static void post_frame_lock(vo_frame_t *vo_img) {
631 post_video_port_t *port = _x_post_video_frame_to_port(vo_img);
632
633 if (port->frame_lock) pthread_mutex_lock(port->frame_lock);
634 _x_post_frame_copy_down(vo_img, vo_img->next);
635 vo_img->lock_counter++;
636 vo_img->next->lock(vo_img->next);
637 _x_post_frame_copy_up(vo_img, vo_img->next);
638 if (port->frame_lock) pthread_mutex_unlock(port->frame_lock);
639 }
640
post_frame_dispose(vo_frame_t * vo_img)641 static void post_frame_dispose(vo_frame_t *vo_img) {
642 post_video_port_t *port = _x_post_video_frame_to_port(vo_img);
643
644 if (port->frame_lock) pthread_mutex_lock(port->frame_lock);
645 vo_img = post_restore_video_frame (vo_img, port, 1);
646 /* unlock (port->frame_lock) already done above */
647 vo_img->dispose(vo_img);
648 }
649
650
_x_post_intercept_video_frame(vo_frame_t * frame,post_video_port_t * port)651 vo_frame_t *_x_post_intercept_video_frame(vo_frame_t *frame, post_video_port_t *port) {
652 vf_alias_t *alias = post_new_video_alias (port, 0);
653 return post_intercept_video_frame (port, frame, alias, 0);
654 }
655
_x_post_restore_video_frame(vo_frame_t * frame,post_video_port_t * port)656 vo_frame_t *_x_post_restore_video_frame(vo_frame_t *frame, post_video_port_t *port) {
657 return post_restore_video_frame (frame, port, 0);
658 }
659
_x_post_frame_copy_down(vo_frame_t * from,vo_frame_t * to)660 void _x_post_frame_copy_down(vo_frame_t *from, vo_frame_t *to) {
661 /* propagate changes downwards (from decoders to video out) */
662 if (to->free == post_frame_free) {
663 vf_alias_t *f = (vf_alias_t *)to;
664 f->frame.stream = from->stream;
665 if (f->frame.stream && (f->frame.stream != f->stream)) {
666 xine_stream_private_t *s;
667 s = (xine_stream_private_t *)f->frame.stream;
668 xine_refs_add (&s->refs, 1);
669 if (f->stream) {
670 s = (xine_stream_private_t *)f->stream;
671 xine_refs_sub (&s->refs, 1);
672 }
673 f->stream = f->frame.stream;
674 }
675 }
676
677 to->pts = from->pts;
678 to->bad_frame = from->bad_frame;
679 to->duration = from->duration;
680 to->top_field_first = from->top_field_first;
681 to->repeat_first_field = from->repeat_first_field;
682 to->progressive_frame = from->progressive_frame;
683 to->picture_coding_type = from->picture_coding_type;
684 to->drawn = from->drawn;
685 to->crop_left = from->crop_left;
686 to->crop_right = from->crop_right;
687 to->crop_top = from->crop_top;
688 to->crop_bottom = from->crop_bottom;
689 to->ratio = from->ratio;
690
691 if (to->extra_info != from->extra_info)
692 _x_extra_info_merge(to->extra_info, from->extra_info);
693 }
694
_x_post_frame_copy_up(vo_frame_t * to,vo_frame_t * from)695 void _x_post_frame_copy_up(vo_frame_t *to, vo_frame_t *from) {
696 /* propagate changes upwards (from video out to decoders) */
697 if (to->free == post_frame_free) {
698 vf_alias_t *f = (vf_alias_t *)to;
699 f->frame.stream = from->stream;
700 if (f->frame.stream && (f->frame.stream != f->stream)) {
701 xine_stream_private_t *s;
702 s = (xine_stream_private_t *)f->frame.stream;
703 xine_refs_add (&s->refs, 1);
704 if (f->stream) {
705 s = (xine_stream_private_t *)f->stream;
706 xine_refs_sub (&s->refs, 1);
707 }
708 f->stream = f->frame.stream;
709 }
710 }
711
712 to->vpts = from->vpts;
713 to->duration = from->duration;
714
715 if (to->extra_info != from->extra_info)
716 _x_extra_info_merge(to->extra_info, from->extra_info);
717 }
718
_x_post_frame_u_turn(vo_frame_t * frame,xine_stream_t * stream)719 void _x_post_frame_u_turn(vo_frame_t *frame, xine_stream_t *stream) {
720 /* frame's travel will end here => do the housekeeping */
721 if (frame->free == post_frame_free) {
722 vf_alias_t *f = (vf_alias_t *)frame;
723 f->frame.stream = stream;
724 if (f->frame.stream && (f->frame.stream != f->stream)) {
725 xine_stream_private_t *s;
726 s = (xine_stream_private_t *)f->frame.stream;
727 xine_refs_add (&s->refs, 1);
728 if (f->stream) {
729 s = (xine_stream_private_t *)f->stream;
730 xine_refs_sub (&s->refs, 1);
731 }
732 f->stream = f->frame.stream;
733 }
734 }
735
736 if (stream) {
737 xine_stream_private_t *s = (xine_stream_private_t *)stream;
738 _x_extra_info_merge (frame->extra_info, s->video_decoder_extra_info);
739 stream->metronom->got_video_frame(stream->metronom, frame);
740 }
741 }
742
743
744 /* dummy intercept functions that just pass the call on to the original overlay manager */
post_overlay_init(video_overlay_manager_t * ovl_gen)745 static void post_overlay_init(video_overlay_manager_t *ovl_gen) {
746 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
747
748 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
749 port->original_manager->init(port->original_manager);
750 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
751 }
752
post_overlay_dispose(video_overlay_manager_t * ovl_gen)753 static void post_overlay_dispose(video_overlay_manager_t *ovl_gen) {
754 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
755
756 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
757 port->original_manager->dispose(port->original_manager);
758 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
759 }
760
post_overlay_get_handle(video_overlay_manager_t * ovl_gen,int object_type)761 static int32_t post_overlay_get_handle(video_overlay_manager_t *ovl_gen, int object_type) {
762 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
763 int32_t handle;
764
765 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
766 handle = port->original_manager->get_handle(port->original_manager, object_type);
767 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
768 return handle;
769 }
770
post_overlay_free_handle(video_overlay_manager_t * ovl_gen,int32_t handle)771 static void post_overlay_free_handle(video_overlay_manager_t *ovl_gen, int32_t handle) {
772 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
773
774 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
775 port->original_manager->free_handle(port->original_manager, handle);
776 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
777 }
778
post_overlay_add_event(video_overlay_manager_t * ovl_gen,void * event)779 static int32_t post_overlay_add_event(video_overlay_manager_t *ovl_gen, void *event) {
780 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
781 int32_t result;
782
783 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
784 result = port->original_manager->add_event(port->original_manager, event);
785 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
786 return result;
787 }
788
post_overlay_flush_events(video_overlay_manager_t * ovl_gen)789 static void post_overlay_flush_events(video_overlay_manager_t *ovl_gen) {
790 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
791
792 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
793 port->original_manager->flush_events(port->original_manager);
794 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
795 }
796
post_overlay_redraw_needed(video_overlay_manager_t * ovl_gen,int64_t vpts)797 static int post_overlay_redraw_needed(video_overlay_manager_t *ovl_gen, int64_t vpts) {
798 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
799 int redraw;
800
801 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
802 redraw = port->original_manager->redraw_needed(port->original_manager, vpts);
803 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
804 return redraw;
805 }
806
post_overlay_multiple_overlay_blend(video_overlay_manager_t * ovl_gen,int64_t vpts,vo_driver_t * output,vo_frame_t * vo_img,int enabled)807 static void post_overlay_multiple_overlay_blend(video_overlay_manager_t *ovl_gen, int64_t vpts,
808 vo_driver_t *output, vo_frame_t *vo_img, int enabled) {
809 post_video_port_t *port = _x_post_ovl_manager_to_port(ovl_gen);
810
811 if (port->manager_lock) pthread_mutex_lock(port->manager_lock);
812 port->original_manager->multiple_overlay_blend(port->original_manager, vpts, output, vo_img, enabled);
813 if (port->manager_lock) pthread_mutex_unlock(port->manager_lock);
814 }
815
816
_x_post_intercept_overlay_manager(video_overlay_manager_t * original,post_video_port_t * port)817 void _x_post_intercept_overlay_manager(video_overlay_manager_t *original, post_video_port_t *port) {
818 if (!port->new_manager->init)
819 port->new_manager->init = post_overlay_init;
820 if (!port->new_manager->dispose)
821 port->new_manager->dispose = post_overlay_dispose;
822 if (!port->new_manager->get_handle)
823 port->new_manager->get_handle = post_overlay_get_handle;
824 if (!port->new_manager->free_handle)
825 port->new_manager->free_handle = post_overlay_free_handle;
826 if (!port->new_manager->add_event)
827 port->new_manager->add_event = post_overlay_add_event;
828 if (!port->new_manager->flush_events)
829 port->new_manager->flush_events = post_overlay_flush_events;
830 if (!port->new_manager->redraw_needed)
831 port->new_manager->redraw_needed = post_overlay_redraw_needed;
832 if (!port->new_manager->multiple_overlay_blend)
833 port->new_manager->multiple_overlay_blend = post_overlay_multiple_overlay_blend;
834
835 port->original_manager = original;
836 }
837
838
839 /* dummy intercept functions that just pass the call on to the original port */
post_audio_get_capabilities(xine_audio_port_t * port_gen)840 static uint32_t post_audio_get_capabilities(xine_audio_port_t *port_gen) {
841 post_audio_port_t *port = (post_audio_port_t *)port_gen;
842 uint32_t caps;
843
844 if (port->port_lock) pthread_mutex_lock(port->port_lock);
845 caps = port->original_port->get_capabilities(port->original_port);
846 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
847 return caps;
848 }
849
post_audio_get_property(xine_audio_port_t * port_gen,int property)850 static int post_audio_get_property(xine_audio_port_t *port_gen, int property) {
851 post_audio_port_t *port = (post_audio_port_t *)port_gen;
852 int prop;
853
854 if (port->port_lock) pthread_mutex_lock(port->port_lock);
855 prop = port->original_port->get_property(port->original_port, property);
856 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
857 return prop;
858 }
859
post_audio_set_property(xine_audio_port_t * port_gen,int property,int value)860 static int post_audio_set_property(xine_audio_port_t *port_gen, int property, int value) {
861 post_audio_port_t *port = (post_audio_port_t *)port_gen;
862 int val;
863
864 if (port->port_lock) pthread_mutex_lock(port->port_lock);
865 val = port->original_port->set_property(port->original_port, property, value);
866 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
867 return val;
868 }
869
post_audio_open(xine_audio_port_t * port_gen,xine_stream_t * stream,uint32_t bits,uint32_t rate,int mode)870 static int post_audio_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
871 uint32_t bits, uint32_t rate, int mode) {
872 post_audio_port_t *port = (post_audio_port_t *)port_gen;
873 int result;
874
875 _x_post_inc_usage (port);
876 _x_post_rewire (port->post);
877 if (port->port_lock) pthread_mutex_lock(port->port_lock);
878 result = (port->original_port->open) (port->original_port, stream, bits, rate, mode);
879 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
880 port->stream = stream;
881 port->bits = bits;
882 port->rate = rate;
883 port->mode = mode;
884 return result;
885 }
886
post_audio_get_buffer(xine_audio_port_t * port_gen)887 static audio_buffer_t *post_audio_get_buffer(xine_audio_port_t *port_gen) {
888 post_audio_port_t *port = (post_audio_port_t *)port_gen;
889 audio_buffer_t *buf;
890 /* Ugly: we always need to ref this port here to protect it from
891 * possible port rewiring inside get_buffer (). */
892 _x_post_inc_usage (port);
893 if (port->port_lock) pthread_mutex_lock(port->port_lock);
894 buf = port->original_port->get_buffer(port->original_port);
895 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
896 _x_post_dec_usage (port);
897 return buf;
898 }
899
post_audio_put_buffer(xine_audio_port_t * port_gen,audio_buffer_t * buf,xine_stream_t * stream)900 static void post_audio_put_buffer(xine_audio_port_t *port_gen, audio_buffer_t *buf,
901 xine_stream_t *stream) {
902 post_audio_port_t *port = (post_audio_port_t *)port_gen;
903
904 if (port->port_lock) pthread_mutex_lock(port->port_lock);
905 port->original_port->put_buffer(port->original_port, buf, stream);
906 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
907 }
908
post_audio_close(xine_audio_port_t * port_gen,xine_stream_t * stream)909 static void post_audio_close(xine_audio_port_t *port_gen, xine_stream_t *stream) {
910 post_audio_port_t *port = (post_audio_port_t *)port_gen;
911
912 if (port->port_lock) pthread_mutex_lock(port->port_lock);
913 port->original_port->close(port->original_port, stream);
914 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
915 port->stream = NULL;
916 _x_post_dec_usage(port);
917 }
918
post_audio_exit(xine_audio_port_t * port_gen)919 static void post_audio_exit(xine_audio_port_t *port_gen) {
920 post_audio_port_t *port = (post_audio_port_t *)port_gen;
921
922 if (port->port_lock) pthread_mutex_lock(port->port_lock);
923 port->original_port->exit(port->original_port);
924 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
925 }
926
post_audio_control(xine_audio_port_t * port_gen,int cmd,...)927 static int post_audio_control(xine_audio_port_t *port_gen, int cmd, ...) {
928 post_audio_port_t *port = (post_audio_port_t *)port_gen;
929 va_list args;
930 void *arg;
931 int rval;
932
933 va_start(args, cmd);
934 arg = va_arg(args, void*);
935 if (port->port_lock) pthread_mutex_lock(port->port_lock);
936 rval = port->original_port->control(port->original_port, cmd, arg);
937 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
938 va_end(args);
939
940 return rval;
941 }
942
post_audio_flush(xine_audio_port_t * port_gen)943 static void post_audio_flush(xine_audio_port_t *port_gen) {
944 post_audio_port_t *port = (post_audio_port_t *)port_gen;
945
946 if (port->port_lock) pthread_mutex_lock(port->port_lock);
947 port->original_port->flush(port->original_port);
948 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
949 }
950
post_audio_status(xine_audio_port_t * port_gen,xine_stream_t * stream,uint32_t * bits,uint32_t * rate,int * mode)951 static int post_audio_status(xine_audio_port_t *port_gen, xine_stream_t *stream,
952 uint32_t *bits, uint32_t *rate, int *mode) {
953 post_audio_port_t *port = (post_audio_port_t *)port_gen;
954 int result;
955
956 if (port->port_lock) pthread_mutex_lock(port->port_lock);
957 result = port->original_port->status(port->original_port, stream, bits, rate, mode);
958 *bits = port->bits;
959 *rate = port->rate;
960 *mode = port->mode;
961 if (port->port_lock) pthread_mutex_unlock(port->port_lock);
962 return result;
963 }
964
965
post_audio_rewire(xine_post_out_t * output_gen,void * data)966 static int post_audio_rewire(xine_post_out_t *output_gen, void *data) {
967 post_out_t *output = (post_out_t *)output_gen;
968 xine_audio_port_t *new_port = (xine_audio_port_t *)data;
969 post_audio_port_t *input_port = (post_audio_port_t *)output->user_data;
970 post_plugin_t *this = output->post;
971 uint32_t bits, rate;
972 int mode;
973
974 if (!new_port)
975 return 0;
976
977 this->running_ticket->revoke (this->running_ticket, XINE_TICKET_FLAG_REWIRE);
978
979 post_audio_port_ref (new_port);
980 if (input_port->original_port->status(input_port->original_port, input_port->stream,
981 &bits, &rate, &mode)) {
982 (new_port->open) (new_port, input_port->stream, bits, rate, mode);
983 input_port->original_port->close(input_port->original_port, input_port->stream);
984 }
985 post_audio_port_unref (input_port->original_port);
986 input_port->original_port = new_port;
987
988 this->running_ticket->issue (this->running_ticket, XINE_TICKET_FLAG_REWIRE);
989
990 return 1;
991 }
992
_x_post_intercept_audio_port(post_plugin_t * post,xine_audio_port_t * original,post_in_t ** input,post_out_t ** output)993 post_audio_port_t *_x_post_intercept_audio_port(post_plugin_t *post, xine_audio_port_t *original,
994 post_in_t **input, post_out_t **output) {
995 post_audio_port_t *port = calloc(1, sizeof(post_audio_port_t));
996
997 if (!port)
998 return NULL;
999
1000 port->new_port.open = post_audio_open;
1001 port->new_port.get_buffer = post_audio_get_buffer;
1002 port->new_port.put_buffer = post_audio_put_buffer;
1003 port->new_port.close = post_audio_close;
1004 port->new_port.exit = post_audio_exit;
1005 port->new_port.get_capabilities = post_audio_get_capabilities;
1006 port->new_port.get_property = post_audio_get_property;
1007 port->new_port.set_property = post_audio_set_property;
1008 port->new_port.control = post_audio_control;
1009 port->new_port.flush = post_audio_flush;
1010 port->new_port.status = post_audio_status;
1011
1012 post_audio_port_ref (original);
1013 port->original_port = original;
1014 port->post = post;
1015
1016 pthread_mutex_init(&port->usage_lock, NULL);
1017
1018 if (input) {
1019 *input = calloc(1, sizeof(post_in_t));
1020 if (!*input) return port;
1021 (*input)->xine_in.name = "audio in";
1022 (*input)->xine_in.type = XINE_POST_DATA_AUDIO;
1023 (*input)->xine_in.data = &port->new_port;
1024 (*input)->post = post;
1025 xine_list_push_back(post->input, *input);
1026 }
1027
1028 if (output) {
1029 *output = calloc(1, sizeof(post_out_t));
1030 if (!*output) return port;
1031 (*output)->xine_out.name = "audio out";
1032 (*output)->xine_out.type = XINE_POST_DATA_AUDIO;
1033 (*output)->xine_out.data = &port->original_port;
1034 (*output)->xine_out.rewire = post_audio_rewire;
1035 (*output)->post = post;
1036 (*output)->user_data = port;
1037 xine_list_push_back(post->output, *output);
1038 }
1039
1040 return port;
1041 }
1042
1043
_x_post_dispose(post_plugin_t * this)1044 int _x_post_dispose(post_plugin_t *this) {
1045 int i, j, in_use = 0;
1046
1047 /* acquire all usage locks, and check counters. */
1048 for (i = 0; this->xine_post.audio_input[i]; i++) {
1049 post_audio_port_t *port = (post_audio_port_t *)this->xine_post.audio_input[i];
1050 pthread_mutex_lock(&port->usage_lock);
1051 in_use += port->usage_count;
1052 }
1053 for (j = 0; this->xine_post.video_input[j]; j++) {
1054 post_video_port_t *port = (post_video_port_t *)this->xine_post.video_input[j];
1055 pthread_mutex_lock(&port->usage_lock);
1056 in_use += port->usage_count;
1057 }
1058
1059 /* we can set this witout harm, because it is always checked with
1060 * usage lock held */
1061 this->dispose_pending = 1;
1062
1063 /* free the locks */
1064 for (j--; j >= 0; j--) {
1065 post_video_port_t *port = (post_video_port_t *)this->xine_post.video_input[j];
1066 pthread_mutex_unlock(&port->usage_lock);
1067 }
1068 for (i--; i >= 0; i--) {
1069 post_audio_port_t *port = (post_audio_port_t *)this->xine_post.audio_input[i];
1070 pthread_mutex_unlock(&port->usage_lock);
1071 }
1072
1073 xprintf (this->xine, XINE_VERBOSITY_DEBUG, "post: _x_post_dispose (%p): %d refs.\n", (void*)this, in_use);
1074
1075 if (!in_use) {
1076 xine_post_in_t *input;
1077 xine_post_out_t *output;
1078 xine_list_iterator_t ite;
1079
1080 /* we can really dispose it */
1081
1082 _x_freep(&this->xine_post.audio_input);
1083 _x_freep(&this->xine_post.video_input);
1084 /* these were allocated in the plugin loader */
1085 _x_freep(&this->input_ids);
1086 _x_freep(&this->output_ids);
1087
1088 ite = NULL;
1089 while ((input = xine_list_next_value (this->input, &ite))) {
1090 switch (input->type) {
1091 case XINE_POST_DATA_VIDEO:
1092 {
1093 post_video_port_t *port = (post_video_port_t *)input->data;
1094 vf_alias_t *f;
1095
1096 post_video_port_unref (port->original_port);
1097
1098 pthread_mutex_destroy(&port->usage_lock);
1099 pthread_mutex_destroy(&port->free_frames_lock);
1100
1101 f = (vf_alias_t *)port->free_frame_slots;
1102 if (f) {
1103 int n = 0;
1104 do {
1105 vf_alias_t *next = (vf_alias_t *)f->frame.next;
1106 if ((f->frame.free == post_frame_free) && f->stream) {
1107 xine_stream_private_t *s = (xine_stream_private_t *)f->stream;
1108 xine_refs_sub (&s->refs, 1);
1109 }
1110 free (f);
1111 n++;
1112 f = next;
1113 } while (f);
1114 port->free_frame_slots = NULL;
1115 xprintf (this->xine, XINE_VERBOSITY_DEBUG, "post: freed %d video frame aliases.\n", n);
1116 }
1117
1118 NAILS_S (port, 0x53);
1119 NAILS_S (input, 0x54);
1120 free(port);
1121 free(input);
1122 }
1123 break;
1124 case XINE_POST_DATA_AUDIO:
1125 {
1126 post_audio_port_t *port = (post_audio_port_t *)input->data;
1127
1128 post_audio_port_unref (port->original_port);
1129
1130 pthread_mutex_destroy(&port->usage_lock);
1131
1132 NAILS_S (port, 0x53);
1133 NAILS_S (input, 0x54);
1134 free(port);
1135 free(input);
1136 }
1137 break;
1138 }
1139 }
1140 ite = NULL;
1141 while ((output = xine_list_next_value (this->output, &ite))) {
1142 switch (output->type) {
1143 case XINE_POST_DATA_VIDEO:
1144 if (output->rewire == post_video_rewire) {
1145 /* we allocated it, we free it */
1146 NAILS_S (output, 0x52);
1147 free(output);
1148 }
1149 break;
1150 case XINE_POST_DATA_AUDIO:
1151 if (output->rewire == post_audio_rewire) {
1152 /* we allocated it, we free it */
1153 NAILS_S (output, 0x52);
1154 free(output);
1155 }
1156 break;
1157 }
1158 }
1159
1160 xine_list_delete(this->input);
1161 xine_list_delete(this->output);
1162
1163 /* since the plugin loader does not know, when the plugin gets disposed,
1164 * we have to handle the reference counter here */
1165 pthread_mutex_lock(&this->xine->plugin_catalog->lock);
1166 this->node->ref--;
1167 pthread_mutex_unlock(&this->xine->plugin_catalog->lock);
1168
1169 NAILS_S (this, 0x55);
1170 return 1;
1171 }
1172
1173 return 0;
1174 }
1175
1176
1177