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