gui: Use whline() for drawing the separator.
[paraslash.git] / spxdec_filter.c
1 /*
2 * Copyright (C) 2002-2006 Jean-Marc Valin
3 * Copyright (C) 2010-2014 Andre Noll <maan@systemlinux.org>
4 *
5 * Licensed under the GPL v2. For licencing details see COPYING.
6 */
7
8 /** \file spxdec_filter.c Paraslash's ogg/speex decoder. */
9
10 /* This file is based on speexdec.c, by Jean-Marc Valin, see below. */
11
12 /* Copyright (C) 2002-2006 Jean-Marc Valin
13 File: speexdec.c
14
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions
17 are met:
18
19 - Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
21
22 - Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
25
26 - Neither the name of the Xiph.org Foundation nor the names of its
27 contributors may be used to endorse or promote products derived from
28 this software without specific prior written permission.
29
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
34 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
36 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
37 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
38 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
39 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 */
42
43 #include <regex.h>
44 #include <ogg/ogg.h>
45 #include <speex/speex.h>
46 #include <speex/speex_header.h>
47 #include <speex/speex_stereo.h>
48 #include <speex/speex_callbacks.h>
49
50 #include "para.h"
51 #include "list.h"
52 #include "sched.h"
53 #include "ggo.h"
54 #include "buffer_tree.h"
55 #include "filter.h"
56 #include "error.h"
57 #include "string.h"
58 #include "spx.h"
59
60 /** Data specific to the speexdec filter. */
61 struct private_spxdec_data {
62 /** Header information obtained from the first ogg packet. */
63 struct spx_header_info shi;
64 /** Read from and written to by the Speex routines. */
65 SpeexBits bits;
66 /* Ogg pages are retrieved from this structure. */
67 ogg_sync_state oy;
68 /** Extracted from header. */
69 int speex_serialno;
70 /** Total number of ogg packets retrieved so far. */
71 int packet_count;
72 /** Needed to find out how much to skip. */
73 ogg_int64_t last_granule;
74 /** Also needed for skipping packets. */
75 int lookahead;
76 /** The state information about the current stream. */
77 ogg_stream_state os;
78 /** Whether \a os initialized. */
79 bool stream_init;
80 };
81
82 static void spxdec_open(struct filter_node *fn)
83 {
84 struct private_spxdec_data *psd = para_calloc(sizeof(*psd));
85
86 fn->private_data = psd;
87 fn->min_iqs = 200;
88 psd->speex_serialno = -1;
89 }
90
91 static void speexdec_close(struct filter_node *fn)
92 {
93 struct private_spxdec_data *psd = fn->private_data;
94
95 if (psd->shi.state) {
96 /* Destroy the decoder state */
97 speex_decoder_destroy(psd->shi.state);
98 /* Destroy the bit-stream struct */
99 speex_bits_destroy(&psd->bits);
100 }
101 free(psd);
102 fn->private_data = NULL;
103 }
104
105 static int speexdec_execute(struct btr_node *btrn, const char *cmd,
106 char **result)
107 {
108 struct filter_node *fn = btr_context(btrn);
109 struct private_spxdec_data *psd = fn->private_data;
110
111 return decoder_execute(cmd, psd->shi.sample_rate, psd->shi.channels,
112 result);
113 }
114
115 static int speexdec_init(struct filter_node *fn)
116 {
117 struct private_spxdec_data *psd = fn->private_data;
118
119 PARA_INFO_LOG("init\n");
120 ogg_sync_init(&psd->oy);
121 speex_bits_init(&psd->bits);
122 return 1;
123 }
124
125 #if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
126 #define le_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8))
127 #else
128 #define le_short(s) ((short) (s))
129 #endif
130
131 #define MAX_FRAME_SIZE 2000
132 /* Copy Ogg packet to Speex bitstream */
133 static int speexdec_write_frames(int packet_no,
134 struct private_spxdec_data *psd, int skip_samples,
135 int page_nb_packets, struct btr_node *btrn)
136 {
137 int i, j;
138
139 for (j = 0; j != psd->shi.nframes; j++) {
140 short output[MAX_FRAME_SIZE], *btr_output;
141 int skip = skip_samples + psd->lookahead, skip_idx = 0;
142 int samples, new_frame_size = psd->shi.frame_size;
143
144 if (speex_decode_int(psd->shi.state, &psd->bits, output) < 0)
145 return -E_SPX_DECODE;
146 if (speex_bits_remaining(&psd->bits) < 0)
147 return -E_SPX_DECODE_OVERFLOW;
148 if (psd->shi.channels == 2)
149 speex_decode_stereo_int(output, psd->shi.frame_size,
150 &psd->shi.stereo);
151 if (packet_no == 1 && j == 0 && skip_samples > 0) {
152 new_frame_size -= skip;
153 skip_idx = skip * psd->shi.channels;
154 }
155 if (packet_no == page_nb_packets && skip_samples < 0) {
156 new_frame_size = psd->shi.nframes * psd->shi.frame_size
157 + skip - j * psd->shi.frame_size;
158 if (new_frame_size < 0)
159 new_frame_size = 0;
160 if (new_frame_size > psd->shi.frame_size)
161 new_frame_size = psd->shi.frame_size;
162 }
163 if (new_frame_size <= 0)
164 continue;
165 samples = new_frame_size * psd->shi.channels;
166 btr_output = para_malloc(2 * samples);
167 for (i = 0; i < samples; i++)
168 btr_output[i] = le_short(output[i + skip_idx]);
169 btr_add_output((char *)btr_output, samples * 2, btrn);
170 }
171 return 1;
172 }
173
174 /* Extract all available packets */
175 static int speexdec_extract_packets(struct private_spxdec_data *psd,
176 ogg_stream_state *os, int skip_samples, int page_nb_packets,
177 struct btr_node *btrn)
178 {
179 int ret, packet_no;
180 bool eos = false;
181
182 for (packet_no = 0;; psd->packet_count++) {
183 ogg_packet op;
184
185 if (ogg_stream_packetout(os, &op) != 1)
186 return 0;
187 if (op.bytes >= 5 && !memcmp(op.packet, "Speex", 5))
188 psd->speex_serialno = os->serialno;
189 if (psd->speex_serialno == -1)
190 return 0;
191 if (os->serialno != psd->speex_serialno)
192 return 0;
193 /* If first packet, process as Speex header */
194 if (psd->packet_count == 0) {
195 ret = spx_process_header(op.packet, op.bytes, &psd->shi);
196 if (ret < 0)
197 return ret;
198 ret = speex_decoder_ctl(psd->shi.state, SPEEX_GET_LOOKAHEAD,
199 &psd->lookahead);
200 if (ret < 0)
201 return ret;
202 if (!psd->shi.nframes)
203 psd->shi.nframes = 1;
204 PARA_INFO_LOG("frame size: %d\n", psd->shi.frame_size);
205 continue;
206 }
207 if (psd->packet_count == 1) /* ignore comments */
208 continue;
209 if (psd->packet_count <= 1 + psd->shi.extra_headers)
210 continue; /* Ignore extra headers */
211 packet_no++;
212 /* check end of stream condition */
213 if (op.e_o_s && os->serialno == psd->speex_serialno)
214 eos = true;
215 speex_bits_read_from(&psd->bits, (char *)op.packet,
216 op.bytes);
217 ret = speexdec_write_frames(packet_no, psd,
218 skip_samples, page_nb_packets, btrn);
219 if (ret < 0)
220 return ret;
221 if (eos == true)
222 return -E_SPX_EOS;
223 }
224 }
225
226 static int compute_skip_samples(ogg_page *og, struct private_spxdec_data *psd)
227 {
228 int ret, page_granule = ogg_page_granulepos(og);
229
230 if (page_granule <= 0)
231 return 0;
232 if (psd->shi.frame_size == 0)
233 return 0;
234 ret = ogg_page_packets(og) * psd->shi.frame_size * psd->shi.nframes
235 - page_granule + psd->last_granule;
236 if (ogg_page_eos(og))
237 ret = -ret;
238 return ret;
239 }
240
241 static int speexdec_post_select(__a_unused struct sched *s, struct task *t)
242 {
243 struct filter_node *fn = container_of(t, struct filter_node, task);
244 struct private_spxdec_data *psd = fn->private_data;
245 struct btr_node *btrn = fn->btrn;
246 int ret, ns;
247 ogg_page og;
248 char *btr_buf;
249 size_t nbytes;
250
251 next_buffer:
252 ret = ns = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
253 btr_merge(btrn, fn->min_iqs);
254 if (!psd->shi.state) {
255 if (ret <= 0)
256 goto fail;
257 ret = speexdec_init(fn);
258 if (ret <= 0)
259 goto fail;
260 }
261 nbytes = btr_next_buffer(btrn, &btr_buf);
262 nbytes = PARA_MIN(nbytes, (size_t)200);
263 if (nbytes > 0) {
264 char *data = ogg_sync_buffer(&psd->oy, nbytes);
265 memcpy(data, btr_buf, nbytes);
266 btr_consume(btrn, nbytes);
267 ogg_sync_wrote(&psd->oy, nbytes);
268 }
269 /* Loop for all complete pages we got */
270 while (ogg_sync_pageout(&psd->oy, &og) == 1) {
271 int skip_samples;
272
273 if (psd->stream_init == false) {
274 ogg_stream_init(&psd->os, ogg_page_serialno(&og));
275 psd->stream_init = true;
276 }
277 if (ogg_page_serialno(&og) != psd->os.serialno)
278 ogg_stream_reset_serialno(&psd->os, ogg_page_serialno(&og));
279 /* Add page to the bitstream */
280 ogg_stream_pagein(&psd->os, &og);
281 skip_samples = compute_skip_samples(&og, psd);
282 psd->last_granule = ogg_page_granulepos(&og);
283 ret = speexdec_extract_packets(psd, &psd->os, skip_samples,
284 ogg_page_packets(&og), btrn);
285 if (ret < 0)
286 goto fail;
287 }
288 if (ns > 0)
289 goto next_buffer;
290 ret = ns;
291 fail:
292 if (ret < 0)
293 btr_remove_node(&fn->btrn);
294 return ret;
295 }
296
297 /**
298 * The init function of the ogg/speex decoder.
299 *
300 * \param f Its fields are filled in by the function.
301 */
302 void spxdec_filter_init(struct filter *f)
303 {
304 f->open = spxdec_open;
305 f->close = speexdec_close;
306 f->pre_select = generic_filter_pre_select;
307 f->post_select = speexdec_post_select;
308 f->execute = speexdec_execute;
309 }