Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / XIPH Vorbis decoder filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : #include <gpac/filters.h>
28 : #include <gpac/constants.h>
29 : #include <gpac/bitstream.h>
30 :
31 : #ifdef GPAC_HAS_VORBIS
32 :
33 : #include <vorbis/codec.h>
34 :
35 : #if !defined(__GNUC__)
36 : # if defined(_WIN32_WCE) || defined (WIN32)
37 : # pragma comment(lib, "libvorbis_static")
38 : # endif
39 : #endif
40 :
41 : typedef struct
42 : {
43 : GF_FilterPid *ipid, *opid;
44 : u32 cfg_crc, sample_rate, nb_chan, timescale;
45 : u64 last_cts;
46 :
47 : vorbis_info vi;
48 : vorbis_dsp_state vd;
49 : vorbis_block vb;
50 : vorbis_comment vc;
51 : ogg_packet op;
52 :
53 : Bool has_reconfigured;
54 : } GF_VorbisDecCtx;
55 :
56 1 : static GF_Err vorbisdec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
57 : {
58 : const GF_PropertyValue *p;
59 : ogg_packet oggpacket;
60 : GF_BitStream *bs;
61 1 : GF_VorbisDecCtx *ctx = gf_filter_get_udta(filter);
62 :
63 :
64 1 : if (is_remove) {
65 0 : if (ctx->opid) {
66 0 : gf_filter_pid_remove(ctx->opid);
67 0 : ctx->opid = NULL;
68 : }
69 0 : ctx->ipid = NULL;
70 0 : return GF_OK;
71 : }
72 1 : if (! gf_filter_pid_check_caps(pid))
73 : return GF_NOT_SUPPORTED;
74 :
75 1 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
76 1 : if (p && p->value.data.ptr && p->value.data.size) {
77 : u32 ex_crc;
78 1 : if (strncmp(&p->value.data.ptr[3], "vorbis", 6)) return GF_NON_COMPLIANT_BITSTREAM;
79 1 : ex_crc = gf_crc_32(p->value.data.ptr, p->value.data.size);
80 1 : if (ctx->cfg_crc == ex_crc) return GF_OK;
81 1 : ctx->cfg_crc = ex_crc;
82 : } else {
83 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[XVID] Reconfiguring without DSI not yet supported\n"));
84 : return GF_NOT_SUPPORTED;
85 : }
86 1 : if (!ctx->opid) {
87 1 : ctx->opid = gf_filter_pid_new(filter);
88 : }
89 :
90 : //copy properties at init or reconfig
91 1 : gf_filter_pid_copy_properties(ctx->opid, pid);
92 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
93 :
94 1 : if (ctx->ipid) {
95 0 : vorbis_block_clear(&ctx->vb);
96 0 : vorbis_dsp_clear(&ctx->vd);
97 0 : vorbis_info_clear(&ctx->vi);
98 0 : vorbis_comment_clear(&ctx->vc);
99 : }
100 1 : ctx->ipid = pid;
101 1 : gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
102 :
103 1 : vorbis_info_init(&ctx->vi);
104 1 : vorbis_comment_init(&ctx->vc);
105 :
106 1 : oggpacket.granulepos = -1;
107 1 : oggpacket.b_o_s = 1;
108 1 : oggpacket.e_o_s = 0;
109 1 : oggpacket.packetno = 0;
110 :
111 1 : bs = gf_bs_new(p->value.data.ptr, p->value.data.size, GF_BITSTREAM_READ);
112 1 : while (gf_bs_available(bs)) {
113 : GF_Err e = GF_OK;
114 3 : oggpacket.bytes = gf_bs_read_u16(bs);
115 3 : oggpacket.packet = gf_malloc(sizeof(char) * oggpacket.bytes);
116 3 : gf_bs_read_data(bs, oggpacket.packet, oggpacket.bytes);
117 3 : if (vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &oggpacket) < 0 ) {
118 : e = GF_NON_COMPLIANT_BITSTREAM;
119 : }
120 3 : gf_free(oggpacket.packet);
121 3 : if (e) {
122 0 : gf_bs_del(bs);
123 0 : return e;
124 : }
125 : }
126 1 : vorbis_synthesis_init(&ctx->vd, &ctx->vi);
127 1 : vorbis_block_init(&ctx->vd, &ctx->vb);
128 1 : gf_bs_del(bs);
129 :
130 1 : return GF_OK;
131 : }
132 :
133 19 : static GFINLINE void vorbis_to_intern(u32 samples, Float **pcm, char *buf, u32 channels)
134 : {
135 : u32 i, j;
136 : s32 val;
137 : ogg_int16_t *data = (ogg_int16_t*)buf ;
138 :
139 38 : for (i=0 ; i<channels ; i++) {
140 : Float *mono;
141 : ogg_int16_t *ptr;
142 19 : ptr = &data[i];
143 19 : if (!ptr) break;
144 :
145 19 : if (channels>2) {
146 : /*center is third in gpac*/
147 0 : if (i==1) ptr = &data[2];
148 : /*right is 2nd in gpac*/
149 0 : else if (i==2) ptr = &data[1];
150 : /*LFE is 4th in gpac*/
151 0 : if ((channels==6) && (i>3)) {
152 0 : if (i==6) ptr = &data[4]; /*LFE*/
153 0 : else ptr = &data[i+1]; /*back l/r*/
154 : }
155 : }
156 :
157 19 : mono = pcm[i];
158 18131 : for (j=0; j<samples; j++) {
159 18112 : val = (s32) (mono[j] * 32767.f);
160 18112 : if (val > 32767) val = 32767;
161 18112 : if (val < -32768) val = -32768;
162 18112 : (*ptr) = val;
163 18112 : ptr += channels;
164 : }
165 : }
166 19 : }
167 :
168 21 : static GF_Err vorbisdec_process(GF_Filter *filter)
169 : {
170 : ogg_packet op;
171 21 : u8 *buffer=NULL;
172 : Float **pcm;
173 : u32 samples, total_samples, total_bytes, size;
174 21 : GF_VorbisDecCtx *ctx = gf_filter_get_udta(filter);
175 : GF_FilterPacket *pck, *dst_pck=NULL;
176 :
177 21 : pck = gf_filter_pid_get_packet(ctx->ipid);
178 21 : if (!pck) {
179 1 : if (!gf_filter_pid_is_eos(ctx->ipid)) {
180 : return GF_OK;
181 : }
182 : }
183 21 : op.granulepos = -1;
184 21 : op.b_o_s = 0;
185 21 : op.e_o_s = 0;
186 21 : op.packetno = 0;
187 :
188 21 : if (pck) {
189 : u32 psize;
190 20 : op.packet = (u8 *) gf_filter_pck_get_data(pck, &psize);
191 20 : op.bytes = psize;
192 : } else {
193 1 : op.packet = NULL;
194 1 : op.bytes = 0;
195 : }
196 :
197 21 : if (vorbis_synthesis(&ctx->vb, &op) == 0)
198 20 : vorbis_synthesis_blockin(&ctx->vd, &ctx->vb) ;
199 :
200 21 : if ( (ctx->vi.channels != ctx->nb_chan) || (ctx->vi.rate != ctx->sample_rate) ) {
201 : u64 chan_mask = 0;
202 1 : ctx->nb_chan = ctx->vi.channels;
203 1 : ctx->sample_rate = ctx->vi.rate;
204 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(ctx->sample_rate) );
205 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(ctx->nb_chan) );
206 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16) );
207 :
208 1 : switch (ctx->vi.channels) {
209 : case 1:
210 : chan_mask = GF_AUDIO_CH_FRONT_CENTER;
211 : break;
212 : case 2:
213 : chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;
214 : break;
215 : case 3:
216 : chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER;
217 : break;
218 : case 4:
219 : chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT;
220 : break;
221 : case 5:
222 : chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT;
223 : break;
224 : case 6:
225 : chan_mask = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT | GF_AUDIO_CH_FRONT_CENTER | GF_AUDIO_CH_SURROUND_LEFT | GF_AUDIO_CH_SURROUND_RIGHT | GF_AUDIO_CH_LFE;
226 : break;
227 : }
228 1 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(chan_mask) );
229 :
230 : }
231 21 : size = (ctx->vd.pcm_current - ctx->vd.pcm_returned) * 2 * ctx->vi.channels;
232 21 : if (size) {
233 19 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &buffer);
234 19 : if (!dst_pck) return GF_OUT_OF_MEM;
235 : }
236 :
237 21 : if (pck && dst_pck) gf_filter_pck_merge_properties(pck, dst_pck);
238 :
239 : /*trust vorbis max block info*/
240 : total_samples = 0;
241 : total_bytes = 0;
242 40 : while ((samples = vorbis_synthesis_pcmout(&ctx->vd, &pcm)) > 0) {
243 19 : vorbis_to_intern(samples, pcm, (char*) buffer + total_bytes, ctx->vi.channels);
244 19 : total_bytes += samples * 2 * ctx->vi.channels;
245 19 : total_samples += samples;
246 19 : vorbis_synthesis_read(&ctx->vd, samples);
247 : }
248 21 : if (!size) {
249 2 : if (pck) return GF_OK;
250 1 : gf_filter_pid_set_eos(ctx->opid);
251 1 : return GF_EOS;
252 : }
253 :
254 19 : if (pck) {
255 19 : ctx->last_cts = gf_filter_pck_get_cts(pck);
256 19 : ctx->timescale = gf_filter_pck_get_timescale(pck);
257 19 : gf_filter_pid_drop_packet(ctx->ipid);
258 : }
259 19 : gf_filter_pck_set_cts(dst_pck, ctx->last_cts);
260 :
261 19 : if (ctx->timescale != ctx->sample_rate) {
262 0 : u64 dur = total_samples * ctx->timescale;
263 0 : dur /= ctx->sample_rate;
264 0 : gf_filter_pck_set_duration(dst_pck, (u32) dur);
265 0 : ctx->last_cts += dur;
266 : } else {
267 19 : gf_filter_pck_set_duration(dst_pck, total_samples);
268 19 : ctx->last_cts += total_samples;
269 : }
270 :
271 : assert(size == total_bytes);
272 19 : gf_filter_pck_send(dst_pck);
273 19 : return GF_OK;
274 : }
275 :
276 1 : static void vorbisdec_finalize(GF_Filter *filter)
277 : {
278 1 : GF_VorbisDecCtx *ctx = gf_filter_get_udta(filter);
279 :
280 1 : vorbis_block_clear(&ctx->vb);
281 1 : vorbis_dsp_clear(&ctx->vd);
282 1 : vorbis_info_clear(&ctx->vi);
283 1 : vorbis_comment_clear(&ctx->vc);
284 1 : }
285 :
286 : static const GF_FilterCapability VorbisDecCaps[] =
287 : {
288 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
289 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VORBIS),
290 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
291 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
292 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
293 : };
294 :
295 : GF_FilterRegister VorbisDecRegister = {
296 : .name = "vorbisdec",
297 : GF_FS_SET_DESCRIPTION("Vorbis decoder")
298 : GF_FS_SET_HELP("This filter decodes Vorbis streams through libvorbis library.")
299 : .private_size = sizeof(GF_VorbisDecCtx),
300 : .priority = 1,
301 : SETCAPS(VorbisDecCaps),
302 : .finalize = vorbisdec_finalize,
303 : .configure_pid = vorbisdec_configure_pid,
304 : .process = vorbisdec_process,
305 : };
306 :
307 : #endif
308 :
309 2877 : const GF_FilterRegister *vorbisdec_register(GF_FilterSession *session)
310 : {
311 : #ifdef GPAC_HAS_VORBIS
312 2877 : return &VorbisDecRegister;
313 : #else
314 : return NULL;
315 : #endif
316 : }
317 :
318 :
|