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