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  * select audio channel plugin for VDR
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #define LOG_MODULE "vdr_audio"
30 #define LOG_VERBOSE
31 /*
32 #define LOG
33 */
34 
35 #include <xine/xine_internal.h>
36 #include <xine/post.h>
37 #include "combined_vdr.h"
38 
39 
40 
41 typedef struct vdr_audio_post_plugin_s
42 {
43   post_plugin_t post_plugin;
44 
45   xine_event_queue_t *event_queue;
46   xine_stream_t      *vdr_stream;
47 
48   uint8_t audio_channels;
49   int num_channels;
50 
51 }
52 vdr_audio_post_plugin_t;
53 
54 
vdr_audio_select_audio(vdr_audio_post_plugin_t * this,uint8_t channels)55 static void vdr_audio_select_audio(vdr_audio_post_plugin_t *this, uint8_t channels)
56 {
57   this->audio_channels = channels;
58 }
59 
60 
61 /* plugin class functions */
62 static post_plugin_t *vdr_audio_open_plugin(post_class_t *class_gen, int inputs,
63                                             xine_audio_port_t **audio_target,
64                                             xine_video_port_t **video_target);
65 
66 /* plugin instance functions */
67 static void           vdr_audio_dispose(post_plugin_t *this_gen);
68 
69 /* replaced ao_port functions */
70 static int            vdr_audio_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
71                                           uint32_t bits, uint32_t rate, int mode);
72 static void           vdr_audio_port_put_buffer(xine_audio_port_t *port_gen, audio_buffer_t *buf, xine_stream_t *stream);
73 
74 
75 
vdr_audio_init_plugin(xine_t * xine,const void * data)76 void *vdr_audio_init_plugin(xine_t *xine, const void *data)
77 {
78   post_class_t *class = calloc(1, sizeof (post_class_t));
79 
80   (void)xine;
81   (void)data;
82 
83   if (!class)
84     return NULL;
85 
86   class->open_plugin     = vdr_audio_open_plugin;
87   class->identifier      = "vdr_audio";
88   class->description     = N_("modifies every audio frame as requested by VDR");
89   class->dispose         = default_post_class_dispose;
90 
91   return class;
92 }
93 
vdr_audio_open_plugin(post_class_t * class_gen,int inputs,xine_audio_port_t ** audio_target,xine_video_port_t ** video_target)94 static post_plugin_t *vdr_audio_open_plugin(post_class_t *class_gen, int inputs,
95 				      xine_audio_port_t **audio_target,
96 				      xine_video_port_t **video_target)
97 {
98   vdr_audio_post_plugin_t *this = calloc(1, sizeof (vdr_audio_post_plugin_t));
99   post_in_t               *input;
100   post_out_t              *output;
101   post_audio_port_t       *port;
102 /*
103 fprintf(stderr, "~~~~~~~~~~ vdr open plugin\n");
104 */
105   if (!this || !audio_target || !audio_target[ 0 ])
106   {
107     free(this);
108     return NULL;
109   }
110 
111   (void)class_gen;
112   (void)inputs;
113   (void)video_target;
114 
115   _x_post_init(&this->post_plugin, 1, 0);
116   this->post_plugin.dispose = vdr_audio_dispose;
117 
118   port = _x_post_intercept_audio_port(&this->post_plugin, audio_target[ 0 ], &input, &output);
119   port->new_port.open       = vdr_audio_port_open;
120   port->new_port.put_buffer = vdr_audio_port_put_buffer;
121 
122   this->post_plugin.xine_post.audio_input[ 0 ] = &port->new_port;
123 
124 
125 
126   this->audio_channels = 0;
127 
128   return &this->post_plugin;
129 }
130 
vdr_audio_dispose(post_plugin_t * this_gen)131 static void vdr_audio_dispose(post_plugin_t *this_gen)
132 {
133 /*
134 fprintf(stderr, "~~~~~~~~~~ vdr dispose\n");
135 */
136   if (_x_post_dispose(this_gen))
137   {
138     vdr_audio_post_plugin_t *this = (vdr_audio_post_plugin_t *)this_gen;
139 
140     if (this->vdr_stream)
141       xine_event_dispose_queue(this->event_queue);
142 
143     free(this_gen);
144   }
145 }
146 
vdr_audio_port_open(xine_audio_port_t * port_gen,xine_stream_t * stream,uint32_t bits,uint32_t rate,int mode)147 static int vdr_audio_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
148                                uint32_t bits, uint32_t rate, int mode) {
149 
150   post_audio_port_t       *port = (post_audio_port_t *)port_gen;
151   vdr_audio_post_plugin_t *this = (vdr_audio_post_plugin_t *)port->post;
152 
153   _x_post_rewire(&this->post_plugin);
154   _x_post_inc_usage(port);
155 /*
156 fprintf(stderr, "~~~~~~~~~~ vdr port open\n");
157 */
158   port->stream = stream;
159   port->bits = bits;
160   port->rate = rate;
161   port->mode = mode;
162 
163   this->num_channels = _x_ao_mode2channels(mode);
164 
165   return (port->original_port->open) (port->original_port, stream, bits, rate, mode );
166 }
167 
168 
vdr_audio_port_put_buffer(xine_audio_port_t * port_gen,audio_buffer_t * buf,xine_stream_t * stream)169 static void vdr_audio_port_put_buffer(xine_audio_port_t *port_gen, audio_buffer_t *buf, xine_stream_t *stream)
170 {
171   post_audio_port_t       *port = (post_audio_port_t *)port_gen;
172   vdr_audio_post_plugin_t *this = (vdr_audio_post_plugin_t *)port->post;
173   xine_event_t *event;
174 /*
175 fprintf(stderr, "~~~~~~ vdr_audio\n");
176 */
177   if (this->vdr_stream
178       && !_x_continue_stream_processing(this->vdr_stream))
179   {
180     this->vdr_stream = 0;
181 
182     xine_event_dispose_queue(this->event_queue);
183     this->event_queue = 0;
184 
185     this->audio_channels = 0;
186   }
187 
188   if (!this->vdr_stream
189       && vdr_is_vdr_stream(stream))
190   {
191     this->event_queue = xine_event_new_queue(stream);
192     if (this->event_queue)
193     {
194       this->vdr_stream = stream;
195 
196       {
197         xine_event_t event;
198 
199         event.type = XINE_EVENT_VDR_PLUGINSTARTED;
200         event.data = 0;
201         event.data_length = 1; /* vdr_audio */
202 
203         xine_event_send(this->vdr_stream, &event);
204       }
205     }
206   }
207 
208   if (this->event_queue)
209   {
210     while ((event = xine_event_get(this->event_queue)))
211     {
212       if (event->type == XINE_EVENT_VDR_SELECTAUDIO)
213       {
214         vdr_select_audio_data_t *data = (vdr_select_audio_data_t *)event->data;
215 
216         vdr_audio_select_audio(this, data->channels);
217       }
218 
219       xine_event_free(event);
220     }
221   }
222 
223   if (this->num_channels == 2
224       && this->audio_channels != 0
225       && this->audio_channels != 3)
226   {
227     audio_buffer_t *vdr_buf = port->original_port->get_buffer(port->original_port);
228     vdr_buf->num_frames = buf->num_frames;
229     vdr_buf->vpts = buf->vpts;
230     vdr_buf->frame_header_count = buf->frame_header_count;
231     vdr_buf->first_access_unit = buf->first_access_unit;
232     /* FIXME: The audio buffer should contain this info.
233      *        We should not have to get it from the open call.
234      */
235     vdr_buf->format.bits = buf->format.bits;
236     vdr_buf->format.rate = buf->format.rate;
237     vdr_buf->format.mode = buf->format.mode;
238     _x_extra_info_merge(vdr_buf->extra_info, buf->extra_info);
239 
240     {
241       int step = buf->format.bits / 8;
242       uint8_t *src = (uint8_t *)buf->mem;
243       uint8_t *dst = (uint8_t *)vdr_buf->mem;
244 
245       if (this->audio_channels == 2)
246         src += step;
247 /*
248       fprintf(stderr, "~~~~~~~~~~ vdr port put buffer: channels: %d, %d\n"
249               , this->audio_channels
250               , buf->format.bits);
251 */
252       int i, k;
253       for (i = 0; i < buf->num_frames; i++)
254       {
255         for (k = 0; k < step; k++)
256           *dst++ = *src++;
257 
258         src -= step;
259 
260         for (k = 0; k < step; k++)
261           *dst++ = *src++;
262 
263         src += step;
264       }
265     }
266 
267     /* pass data to original port */
268     port->original_port->put_buffer(port->original_port, vdr_buf, stream);
269 
270     /* free data from origial buffer */
271     buf->num_frames = 0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */
272   }
273 
274   port->original_port->put_buffer(port->original_port, buf, stream);
275 
276   return;
277 }
278