1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2020
6 * All rights reserved
7 *
8 * This file is part of GPAC / XIPH OGG demux 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 #include <gpac/filters.h>
27 #include <gpac/constants.h>
28 #include <gpac/list.h>
29 #include <gpac/bitstream.h>
30
31 #if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_OGG)
32 #include <gpac/internal/ogg.h>
33 #include <gpac/internal/isomedia_dev.h>
34 //#include <ogg/ogg.h>
35 #include <gpac/avparse.h>
36
37
38
39 typedef struct
40 {
41 u32 streamType; /*MPEG-4 streamType*/
42 u32 num_init_headers;
43 u32 sample_rate, bitrate, nb_chan;
44 u32 width, height;
45 GF_Fraction sar;
46
47 u32 theora_kgs;
48 GF_Fraction frame_rate;
49
50 u32 type;
51 } OGGInfo;
52
53 typedef struct
54 {
55 //only one output pid declared
56 GF_FilterPid *opid;
57
58 ogg_stream_state os;
59 u32 serial_no;
60 /*DSI for ogg - cf constants.h*/
61 GF_BitStream *dsi_bs;
62
63 OGGInfo info;
64 Bool got_headers;
65
66 u32 parse_headers;
67
68 Bool eos_detected;
69
70 u32 recomputed_ts;
71
72 GF_VorbisParser *vorbis_parser;
73
74 GF_OpusParser *opus_parser;
75 } GF_OGGStream;
76
77 typedef struct
78 {
79 Double index;
80
81 //only one input pid declared
82 GF_FilterPid *ipid;
83
84 u64 file_pos, file_size;
85 u32 global_rate;
86 GF_Fraction64 duration;
87 Double start_range;
88 Bool seek_file;
89 u32 nb_playing;
90 Bool is_file;
91 Bool initial_play_done, file_loaded;
92
93 GF_List *streams;
94
95 /*ogg ogfile state*/
96 ogg_sync_state oy;
97 } GF_OGGDmxCtx;
98
oggdmx_signal_eos(GF_OGGDmxCtx * ctx)99 void oggdmx_signal_eos(GF_OGGDmxCtx *ctx)
100 {
101 GF_OGGStream *st;
102 u32 i=0;
103 while ((st = (GF_OGGStream*)gf_list_enum(ctx->streams, &i))) {
104 if (st->opid)
105 gf_filter_pid_set_eos(st->opid);
106 }
107 }
108
oggdmx_find_stream_for_page(GF_OGGDmxCtx * ctx,ogg_page * oggpage)109 static GF_OGGStream *oggdmx_find_stream_for_page(GF_OGGDmxCtx *ctx, ogg_page *oggpage)
110 {
111 u32 i, count;
112 count = gf_list_count(ctx->streams);
113 for (i=0; i<count; i++) {
114 GF_OGGStream *st = (GF_OGGStream*)gf_list_get(ctx->streams, i);
115 if (ogg_stream_pagein(&st->os, oggpage) == 0) return st;
116 }
117 return NULL;
118 }
119
oggdmx_get_stream_info(ogg_packet * oggpacket,OGGInfo * info)120 static void oggdmx_get_stream_info(ogg_packet *oggpacket, OGGInfo *info)
121 {
122 oggpack_buffer opb;
123
124 memset(info, 0, sizeof(OGGInfo));
125
126 /*vorbis*/
127 if ((oggpacket->bytes >= 7) && !strncmp((char *) &oggpacket->packet[1], "vorbis", 6)) {
128 info->streamType = GF_STREAM_AUDIO;
129 oggpack_readinit(&opb, oggpacket->packet, oggpacket->bytes);
130 oggpack_adv( &opb, 88);
131 info->nb_chan = oggpack_read( &opb, 8); /*nb chan*/
132 info->sample_rate = oggpack_read(&opb, 32);
133 oggpack_adv( &opb, 32); /*max rate*/
134 info->bitrate = oggpack_read(&opb, 32);
135 info->num_init_headers = 3;
136 info->type = GF_CODECID_VORBIS;
137 }
138 /*speex*/
139 else if ((oggpacket->bytes >= 7) && !strncmp((char *) &oggpacket->packet[0], "Speex", 5)) {
140 info->streamType = GF_STREAM_AUDIO;
141 oggpack_readinit(&opb, oggpacket->packet, oggpacket->bytes);
142 oggpack_adv(&opb, 224);
143 oggpack_adv(&opb, 32);
144 oggpack_adv( &opb, 32);
145 info->sample_rate = oggpack_read(&opb, 32);
146 info->type = GF_CODECID_SPEEX;
147 info->num_init_headers = 1;
148 }
149 /*flac*/
150 else if ((oggpacket->bytes >= 4) && !strncmp((char *) &oggpacket->packet[0], "fLaC", 4)) {
151 info->streamType = GF_STREAM_AUDIO;
152 info->type = GF_CODECID_FLAC;
153 info->num_init_headers = 3;
154 }
155 /*opus*/
156 else if ((oggpacket->bytes >= 8) && !strncmp((char *) &oggpacket->packet[0], "OpusHead", 8)) {
157 info->streamType = GF_STREAM_AUDIO;
158 info->type = GF_CODECID_OPUS;
159 info->num_init_headers = 1;
160 info->sample_rate = 48000;
161 }
162 /*theora*/
163 else if ((oggpacket->bytes >= 7) && !strncmp((char *) &oggpacket->packet[1], "theora", 6)) {
164 GF_BitStream *bs;
165 u32 keyframe_freq_force;
166
167 info->streamType = GF_STREAM_VISUAL;
168 info->type = GF_CODECID_THEORA;
169 bs = gf_bs_new((char *) oggpacket->packet, oggpacket->bytes, GF_BITSTREAM_READ);
170 gf_bs_read_int(bs, 56);
171 gf_bs_read_int(bs, 8); /* major version num */
172 gf_bs_read_int(bs, 8); /* minor version num */
173 gf_bs_read_int(bs, 8); /* subminor version num */
174 info->width = gf_bs_read_int(bs, 16) << 4; /* width */
175 info->height = gf_bs_read_int(bs, 16) << 4; /* height */
176 gf_bs_read_int(bs, 24); /* frame width */
177 gf_bs_read_int(bs, 24); /* frame height */
178 gf_bs_read_int(bs, 8); /* x offset */
179 gf_bs_read_int(bs, 8); /* y offset */
180 info->frame_rate.den = gf_bs_read_u32(bs);
181 info->frame_rate.num = gf_bs_read_u32(bs);
182 info->sar.num = gf_bs_read_int(bs, 24); /* aspect_numerator */
183 info->sar.den =gf_bs_read_int(bs, 24); /* aspect_denominator */
184 gf_bs_read_int(bs, 8); /* colorspace */
185 info->bitrate = gf_bs_read_int(bs, 24);/* bitrate */
186 gf_bs_read_int(bs, 6); /* quality */
187
188 /*patch for compatibility with old arch*/
189 if ((info->frame_rate.den==25025) && (info->frame_rate.num==1001) ) {
190 info->frame_rate.den = 25000;
191 info->frame_rate.num = 1000;
192 }
193
194 keyframe_freq_force = 1 << gf_bs_read_int(bs, 5);
195 info->theora_kgs = 0;
196 keyframe_freq_force--;
197 while (keyframe_freq_force) {
198 info->theora_kgs ++;
199 keyframe_freq_force >>= 1;
200 }
201 info->num_init_headers = 3;
202 gf_bs_del(bs);
203 }
204 }
205
oggdmx_declare_pid(GF_Filter * filter,GF_OGGDmxCtx * ctx,GF_OGGStream * st)206 static void oggdmx_declare_pid(GF_Filter *filter, GF_OGGDmxCtx *ctx, GF_OGGStream *st)
207 {
208 if (!st->opid) {
209 st->opid = gf_filter_pid_new(filter);
210 }
211 // gf_filter_pid_set_property(st->opid, GF_PROP_PID_ID, &PROP_UINT(st->serial_no) );
212 gf_filter_pid_set_property(st->opid, GF_PROP_PID_ID, &PROP_UINT(1 + gf_list_find(ctx->streams, st) ) );
213 gf_filter_pid_set_property(st->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(st->info.streamType) );
214 gf_filter_pid_set_property(st->opid, GF_PROP_PID_CODECID, &PROP_UINT(st->info.type) );
215 gf_filter_pid_set_property(st->opid, GF_PROP_PID_BITRATE, &PROP_UINT(st->info.bitrate) );
216 gf_filter_pid_set_property(st->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(st->info.sample_rate ? st->info.sample_rate : st->info.frame_rate.den) );
217 gf_filter_pid_set_property(st->opid, GF_PROP_PID_PROFILE_LEVEL, &PROP_UINT(0xFE) );
218
219 //opus DSI is formatted as box (ffmpeg compat) we might want to change that to avoid the box header
220 if (st->info.type==GF_CODECID_OPUS) {
221 GF_OpusSpecificBox *opus = (GF_OpusSpecificBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DOPS);
222 st->dsi_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
223 opus->version = 0;
224
225 opus->OutputChannelCount = st->opus_parser->OutputChannelCount;
226 opus->PreSkip = st->opus_parser->PreSkip;
227 opus->InputSampleRate = st->opus_parser->InputSampleRate;
228 opus->OutputGain = st->opus_parser->OutputGain;
229 opus->ChannelMappingFamily = st->opus_parser->ChannelMappingFamily;
230 opus->StreamCount = st->opus_parser->StreamCount;
231 opus->CoupledCount = st->opus_parser->CoupledCount;
232 memcpy(opus->ChannelMapping, st->opus_parser->ChannelMapping, sizeof(char)*255);
233 gf_isom_box_size((GF_Box *) opus);
234 gf_isom_box_write((GF_Box *) opus, st->dsi_bs);
235 gf_isom_box_del((GF_Box *) opus);
236
237 st->info.nb_chan = st->opus_parser->OutputChannelCount;
238 }
239
240 if (st->dsi_bs) {
241 u8 *data;
242 u32 size;
243 gf_bs_get_content(st->dsi_bs, &data, &size);
244 gf_bs_del(st->dsi_bs);
245 st->dsi_bs = NULL;
246 gf_filter_pid_set_property(st->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(data, size) );
247 }
248
249 if (st->info.sample_rate)
250 gf_filter_pid_set_property(st->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(st->info.sample_rate) );
251
252 if (st->info.nb_chan)
253 gf_filter_pid_set_property(st->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(st->info.nb_chan) );
254
255 if (st->info.width)
256 gf_filter_pid_set_property(st->opid, GF_PROP_PID_WIDTH, &PROP_UINT(st->info.width) );
257 if (st->info.height)
258 gf_filter_pid_set_property(st->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(st->info.height) );
259 if (st->info.sar.den)
260 gf_filter_pid_set_property(st->opid, GF_PROP_PID_SAR, &PROP_FRAC(st->info.sar) );
261 if (st->info.frame_rate.den)
262 gf_filter_pid_set_property(st->opid, GF_PROP_PID_FPS, &PROP_FRAC(st->info.frame_rate) );
263
264 if (ctx->duration.num)
265 gf_filter_pid_set_property(st->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
266
267 }
268
oggdmx_new_stream(GF_Filter * filter,GF_OGGDmxCtx * ctx,ogg_page * oggpage)269 static void oggdmx_new_stream(GF_Filter *filter, GF_OGGDmxCtx *ctx, ogg_page *oggpage)
270 {
271 ogg_packet oggpacket;
272 u32 serial_no, i;
273 GF_OGGStream *st;
274
275 /*reannounce of stream (caroussel in live streams) */
276 serial_no = ogg_page_serialno(oggpage);
277 i=0;
278 while ((st = (GF_OGGStream*)gf_list_enum(ctx->streams, &i))) {
279 if (st->serial_no==serial_no) {
280 //resetup stream
281 ogg_stream_clear(&st->os);
282 ogg_stream_init(&st->os, st->serial_no);
283 ogg_stream_pagein(&st->os, oggpage);
284 st->parse_headers = st->info.num_init_headers;
285 return;
286 }
287 }
288
289 /*look if we have the same stream defined (eg, reuse first stream dead with same header page)*/
290 i=0;
291 while ((st = (GF_OGGStream*)gf_list_enum(ctx->streams, &i))) {
292 if (st->eos_detected) {
293 gf_filter_pid_set_eos(st->opid);
294 //and reuse the pid connection
295 break;
296 }
297 }
298 if (!st) {
299 GF_SAFEALLOC(st, GF_OGGStream);
300 if (!st) {
301 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[OGG] Failed to allocate stream for demux\n"));
302 return;
303 }
304 }
305 st->eos_detected = GF_FALSE;
306 st->serial_no = serial_no;
307 ogg_stream_init(&st->os, st->serial_no);
308 ogg_stream_pagein(&st->os, oggpage);
309
310 ogg_stream_packetpeek(&st->os, &oggpacket);
311 oggdmx_get_stream_info(&oggpacket, &st->info);
312
313 gf_list_add(ctx->streams, st);
314 st->parse_headers = st->info.num_init_headers;
315 switch (st->info.type) {
316 case GF_CODECID_VORBIS:
317 GF_SAFEALLOC(st->vorbis_parser, GF_VorbisParser);
318 break;
319 case GF_CODECID_OPUS:
320 GF_SAFEALLOC(st->opus_parser, GF_OpusParser);
321 break;
322 default:
323 break;
324 }
325
326 if (st->got_headers) {
327 oggdmx_declare_pid(filter, ctx, st);
328 }
329 i=0;
330 ctx->global_rate = 0;
331 while ((st = (GF_OGGStream*)gf_list_enum(ctx->streams, &i))) {
332 if (!st->eos_detected) ctx->global_rate += st->info.bitrate;
333 }
334 if (ctx->global_rate && ctx->is_file && !ctx->file_loaded) {
335 if (!ctx->file_size) {
336 GF_PropertyEntry *pe=NULL;
337 const GF_PropertyValue *p = gf_filter_pid_get_info(ctx->ipid, GF_PROP_PID_DOWN_SIZE, &pe);
338 if (p) ctx->file_size = p->value.longuint;
339 gf_filter_release_property(pe);
340 }
341 if (ctx->file_size) {
342 ctx->duration.num = (u32) (8 * ctx->file_size);
343 ctx->duration.den = ctx->global_rate;
344 }
345 }
346 }
347
oggdmx_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)348 GF_Err oggdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
349 {
350 u32 i;
351 GF_OGGDmxCtx *ctx = gf_filter_get_udta(filter);
352
353 if (is_remove) {
354 GF_OGGStream *st;
355 ctx->ipid = NULL;
356
357 while ((st = (GF_OGGStream*)gf_list_enum(ctx->streams, &i))) {
358 if (st->opid)
359 gf_filter_pid_remove(st->opid);
360 }
361 return GF_OK;
362 }
363 if (! gf_filter_pid_check_caps(pid))
364 return GF_NOT_SUPPORTED;
365
366 ctx->ipid = pid;
367 return GF_OK;
368 }
369
oggdmx_check_dur(GF_Filter * filter,GF_OGGDmxCtx * ctx)370 static void oggdmx_check_dur(GF_Filter *filter, GF_OGGDmxCtx *ctx)
371 {
372 ogg_sync_state oy;
373 FILE *stream;
374 const GF_PropertyValue *p;
375 OGGInfo info, the_info;
376 ogg_page oggpage;
377 ogg_packet oggpacket;
378 ogg_stream_state os, the_os;
379 u64 max_gran;
380 Bool has_stream = GF_FALSE;
381 GF_VorbisParser vp;
382 GF_OpusParser op;
383 u64 recompute_ts;
384 GF_Fraction64 dur;
385
386 if (!ctx->index || ctx->duration.num) return;
387
388 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
389 if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
390
391 p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
392 if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7) ) {
393 ctx->is_file = GF_FALSE;
394 ctx->duration.num=1;
395 return;
396 }
397 ctx->is_file = GF_TRUE;
398 if (!ctx->file_loaded) return;
399
400 stream = gf_fopen(p->value.string, "rb");
401 if (!stream) return;
402
403 ogg_sync_init(&oy);
404 memset(&the_info, 0, sizeof(OGGInfo));
405 memset(&vp, 0, sizeof(GF_VorbisParser));
406 recompute_ts = 0;
407 max_gran = 0;
408 while (1) {
409 char buf[10000];
410 while (ogg_sync_pageout(&oy, &oggpage) != 1 ) {
411 char *buffer;
412 u32 bytes;
413
414 if (gf_feof(stream))
415 break;
416
417 bytes = (u32) gf_fread(buf, 10000, stream);
418 if (!bytes) break;
419 buffer = ogg_sync_buffer(&oy, bytes);
420 memcpy(buffer, buf, bytes);
421 ogg_sync_wrote(&oy, bytes);
422 }
423 if (gf_feof(stream))
424 break;
425
426 if (ogg_page_bos(&oggpage)) {
427 ogg_stream_init(&os, ogg_page_serialno(&oggpage));
428 if (ogg_stream_pagein(&os, &oggpage) >= 0 ) {
429 ogg_stream_packetpeek(&os, &oggpacket);
430 if (ogg_stream_pagein(&os, &oggpage) >= 0 ) {
431 ogg_stream_packetpeek(&os, &oggpacket);
432 oggdmx_get_stream_info(&oggpacket, &info);
433 }
434 if (!has_stream) {
435 has_stream = GF_TRUE;
436 ogg_stream_init(&the_os, ogg_page_serialno(&oggpage));
437 the_info = info;
438 }
439 }
440 ogg_stream_clear(&os);
441 }
442 if (has_stream && (ogg_stream_pagein(&the_os, &oggpage) >= 0) ) {
443 while (ogg_stream_packetout(&the_os, &oggpacket ) > 0 ) {
444 if (the_info.type==GF_CODECID_VORBIS) {
445 if (the_info.num_init_headers) {
446 the_info.num_init_headers--;
447 gf_vorbis_parse_header(&vp, oggpacket.packet, oggpacket.bytes);
448 } else {
449 recompute_ts += gf_vorbis_check_frame(&vp, (char *) oggpacket.packet, oggpacket.bytes);
450 }
451 } else if (the_info.type==GF_CODECID_OPUS) {
452 if (the_info.num_init_headers) {
453 the_info.num_init_headers--;
454 gf_opus_parse_header(&op, oggpacket.packet, oggpacket.bytes);
455 } else {
456 recompute_ts += gf_opus_check_frame(&op, (char *) oggpacket.packet, oggpacket.bytes);
457 }
458
459 } else if ((oggpacket.granulepos>=0) && ((u64) oggpacket.granulepos>max_gran) ) {
460 max_gran = oggpacket.granulepos;
461 }
462 }
463 }
464 }
465 ogg_sync_clear(&oy);
466 ctx->file_size = gf_ftell(stream);
467 if (has_stream) {
468 ogg_stream_clear(&the_os);
469 if (recompute_ts) {
470 dur.num = (u32) recompute_ts;
471 dur.den = the_info.sample_rate;
472 } else {
473 //convert granule to time
474 if (the_info.sample_rate) {
475 dur.num = (s32) max_gran;
476 } else if (the_info.frame_rate.num) {
477 s64 iframe = max_gran >> the_info.theora_kgs;
478 s64 pframe = max_gran - (iframe << the_info.theora_kgs);
479 pframe += iframe;
480 dur.num = (s32) (pframe / the_info.frame_rate.num);
481 } else {
482 dur.num = 0;
483 }
484 if (the_info.sample_rate) dur.den = the_info.sample_rate;
485 else dur.den = the_info.frame_rate.den;
486 }
487
488 if (!ctx->duration.num || (ctx->duration.num * dur.den != dur.num * ctx->duration.den)) {
489 u32 i=0;
490 GF_OGGStream *st;
491 ctx->duration = dur;
492 while ( (st = gf_list_enum(ctx->streams, &i)) ) {
493 gf_filter_pid_set_property(st->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
494 }
495 }
496 }
497 gf_fclose(stream);
498 }
499
oggdmx_process_event(GF_Filter * filter,const GF_FilterEvent * evt)500 static Bool oggdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
501 {
502 u32 i;
503 GF_OGGStream *st;
504 GF_FilterEvent fevt;
505 GF_OGGDmxCtx *ctx = gf_filter_get_udta(filter);
506
507 switch (evt->base.type) {
508 case GF_FEVT_PLAY:
509 if (ctx->nb_playing && (ctx->start_range == evt->play.start_range)) {
510 ctx->nb_playing++;
511 return GF_TRUE;
512 }
513 ctx->nb_playing++;
514 if (! ctx->is_file) {
515 return GF_FALSE;
516 }
517 oggdmx_check_dur(filter, ctx);
518
519
520 ctx->start_range = evt->play.start_range;
521 ctx->file_pos = 0;
522 if (ctx->duration.num) {
523 ctx->file_pos = (u32) (ctx->file_size * ctx->start_range);
524 ctx->file_pos *= ctx->duration.den;
525 ctx->file_pos /= ctx->duration.num;
526 if (ctx->file_pos>ctx->file_size) return GF_TRUE;
527 }
528
529 if (!ctx->initial_play_done) {
530 ctx->initial_play_done = GF_TRUE;
531 //seek will not change the current source state, don't send a seek
532 if (!ctx->file_pos)
533 return GF_TRUE;
534 }
535 ctx->seek_file = GF_TRUE;
536 i=0;
537 while ((st = gf_list_enum(ctx->streams, &i)) ) {
538 if (st->info.sample_rate) {
539 st->recomputed_ts = (u32) (ctx->start_range * st->info.sample_rate);
540 } else {
541 st->recomputed_ts = (u32) (ctx->start_range * st->info.frame_rate.den);
542 }
543 }
544
545 //post a seek
546 GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
547 fevt.seek.start_offset = ctx->file_pos;
548 gf_filter_pid_send_event(ctx->ipid, &fevt);
549
550 //cancel event
551 return GF_TRUE;
552
553 case GF_FEVT_STOP:
554 ctx->nb_playing --;
555 //cancel event if not last stream
556 if (ctx->nb_playing) return GF_TRUE;
557
558 //cancel event if we didn't get all stream headers yet not last stream
559 i=0;
560 while ((st = gf_list_enum(ctx->streams, &i))) {
561 if (!st->got_headers) return GF_TRUE;
562 }
563 return GF_FALSE;
564
565 case GF_FEVT_SET_SPEED:
566 //cancel event
567 return GF_TRUE;
568 default:
569 break;
570 }
571 //by default don't cancel event - to rework once we have downloading in place
572 return GF_FALSE;
573 }
574
oggdmx_process(GF_Filter * filter)575 GF_Err oggdmx_process(GF_Filter *filter)
576 {
577 ogg_page oggpage;
578 GF_OGGDmxCtx *ctx = gf_filter_get_udta(filter);
579 GF_FilterPacket *pck;
580 GF_OGGStream *st;
581 s64 granulepos_init = -1;
582
583 //update duration
584 oggdmx_check_dur(filter, ctx);
585
586
587 if (ctx->seek_file) {
588 ogg_sync_clear(&ctx->oy);
589 ogg_sync_init(&ctx->oy);
590 ctx->seek_file = GF_FALSE;
591 } else {
592 u32 i=0;
593 u32 would_block = 0;
594 //check if all the streams are in block state, if so return.
595 //we need to check for all output since one pid could still be buffering
596 while ((st = gf_list_enum(ctx->streams, &i))) {
597 if (st->got_headers && gf_filter_pid_would_block(st->opid))
598 would_block++;
599 }
600 if (would_block && (would_block+1==i))
601 return GF_OK;
602 }
603
604 while (1) {
605 ogg_packet oggpacket;
606
607 if (ogg_sync_pageout(&ctx->oy, &oggpage ) != 1 ) {
608 u32 pck_size;
609 char *data, *buffer;
610
611 pck = gf_filter_pid_get_packet(ctx->ipid);
612 if (!pck) {
613 if (gf_filter_pid_is_eos(ctx->ipid)) oggdmx_signal_eos(ctx);
614 return GF_OK;
615 }
616 data = (char *) gf_filter_pck_get_data(pck, &pck_size);
617 buffer = ogg_sync_buffer(&ctx->oy, pck_size);
618 memcpy(buffer, data, pck_size);
619 if (ogg_sync_wrote(&ctx->oy, pck_size) >= 0) {
620 gf_filter_pid_drop_packet(ctx->ipid);
621 }
622 continue;
623 }
624
625 if (ogg_page_bos(&oggpage)) {
626 oggdmx_new_stream(filter, ctx, &oggpage);
627 continue;
628 }
629
630 st = oggdmx_find_stream_for_page(ctx, &oggpage);
631 if (!st) {
632 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[OGG] cannot find stream for ogg page\n"));
633 continue;
634 }
635
636 if (ogg_page_eos(&oggpage))
637 st->eos_detected = GF_TRUE;
638
639 while (ogg_stream_packetout(&st->os, &oggpacket ) > 0 ) {
640 if (st->parse_headers && !st->got_headers) {
641 Bool res = GF_FALSE;
642 Bool add_page = GF_FALSE;
643 u32 bytes = oggpacket.bytes;
644 //bug in some files where first header is repeated
645 if ( (st->parse_headers + 1 == st->info.num_init_headers) && st->dsi_bs && (gf_bs_get_position(st->dsi_bs) == 2 + bytes) )
646 continue;
647
648 switch (st->info.type) {
649 case GF_CODECID_VORBIS:
650 res = gf_vorbis_parse_header(st->vorbis_parser, (char *) oggpacket.packet, oggpacket.bytes);
651 if (!res) {
652 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[OGG] Failed to parse Vorbis header\n"));
653 } else {
654 add_page = GF_TRUE;
655 }
656 break;
657 case GF_CODECID_OPUS:
658 res = gf_opus_parse_header(st->opus_parser, (char *) oggpacket.packet, oggpacket.bytes);
659 if (!res) {
660 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[OGG] Failed to parse Opus header\n"));
661 }
662 break;
663 case GF_CODECID_THEORA:
664 add_page = GF_TRUE;
665 break;
666 }
667
668 if (add_page) {
669 if (!st->dsi_bs) st->dsi_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
670 gf_bs_write_u16(st->dsi_bs, oggpacket.bytes);
671 gf_bs_write_data(st->dsi_bs, (char *) oggpacket.packet, oggpacket.bytes);
672 }
673
674 st->parse_headers--;
675 if (!st->parse_headers) {
676 st->got_headers = GF_TRUE;
677 oggdmx_declare_pid(filter, ctx, st);
678 }
679
680 granulepos_init = oggpacket.granulepos;
681 } else if (st->parse_headers && st->got_headers) {
682 st->parse_headers--;
683 } else if (!st->opid) {
684 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[OGG] Channel %d packet before configure done - discarding\n", st->serial_no));
685 } else {
686 u8 *output;
687 GF_FilterPacket *dst_pck;
688
689 if (st->info.type==GF_CODECID_THEORA) {
690 oggpack_buffer opb;
691 oggpackB_readinit(&opb, oggpacket.packet, oggpacket.bytes);
692 /*not a new frame*/
693 if (oggpackB_read(&opb, 1) != 0) continue;
694
695 dst_pck = gf_filter_pck_new_alloc(st->opid, oggpacket.bytes, &output);
696 memcpy(output, (char *) oggpacket.packet, oggpacket.bytes);
697 gf_filter_pck_set_cts(dst_pck, st->recomputed_ts);
698 gf_filter_pck_set_sap(dst_pck, oggpackB_read(&opb, 1) ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
699 st->recomputed_ts += st->info.frame_rate.num;
700 }
701 //this is audio
702 else {
703 u32 block_size = 0;
704
705 if (st->info.type==GF_CODECID_VORBIS) {
706 block_size = gf_vorbis_check_frame(st->vorbis_parser, (char *) oggpacket.packet, oggpacket.bytes);
707 if (!block_size) continue;
708 }
709 else if (st->info.type==GF_CODECID_OPUS) {
710 block_size = gf_opus_check_frame(st->opus_parser, (char *) oggpacket.packet, oggpacket.bytes);
711 if (!block_size) continue;
712
713 if (!st->recomputed_ts) {
714 //compat with old arch (keep same hashes), to remove once droping it
715 if (!gf_sys_old_arch_compat()) {
716 gf_filter_pid_set_property(st->opid, GF_PROP_PID_DELAY, &PROP_SINT((s32)-st->opus_parser->PreSkip));
717 }
718 }
719 }
720
721 if (ogg_page_eos(&oggpage)) {
722 //compat with old arch (keep same hashes), to remove once droping it
723 if (!gf_sys_old_arch_compat()) {
724 if (oggpacket.granulepos != -1 && granulepos_init != -1)
725 block_size = (u32)(oggpacket.granulepos - granulepos_init - st->recomputed_ts); /*4.4 End Trimming, cf https://tools.ietf.org/html/rfc7845*/
726 }
727 }
728 dst_pck = gf_filter_pck_new_alloc(st->opid, oggpacket.bytes, &output);
729 memcpy(output, (char *) oggpacket.packet, oggpacket.bytes);
730 gf_filter_pck_set_cts(dst_pck, st->recomputed_ts);
731 //compat with old arch (keep same hashes), to remove once droping it
732 if (!gf_sys_old_arch_compat()) {
733 gf_filter_pck_set_duration(dst_pck, block_size);
734 }
735
736 if (st->info.type == GF_CODECID_VORBIS) {
737 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
738 } else if (st->info.type == GF_CODECID_OPUS) {
739 //compat with old arch (keep same hashes), to remove once droping it
740 if (!gf_sys_old_arch_compat()) {
741 gf_filter_pck_set_roll_info(dst_pck, 3840);
742 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_4);
743 } else {
744 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
745 }
746 } else {
747 gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
748 }
749
750 st->recomputed_ts += block_size;
751 }
752
753 gf_filter_pck_send(dst_pck);
754 }
755 }
756 }
757 return GF_OK;
758 }
759
oggdmx_initialize(GF_Filter * filter)760 static GF_Err oggdmx_initialize(GF_Filter *filter)
761 {
762 GF_OGGDmxCtx *ctx = gf_filter_get_udta(filter);
763 ctx->streams = gf_list_new();
764 ogg_sync_init(&ctx->oy);
765 return GF_OK;
766 }
767
oggdmx_finalize(GF_Filter * filter)768 static void oggdmx_finalize(GF_Filter *filter)
769 {
770 GF_OGGDmxCtx *ctx = gf_filter_get_udta(filter);
771
772 /*just in case something went wrong*/
773 while (gf_list_count(ctx->streams)) {
774 GF_OGGStream *st = (GF_OGGStream*)gf_list_get(ctx->streams, 0);
775 gf_list_rem(ctx->streams, 0);
776 ogg_stream_clear(&st->os);
777 if (st->dsi_bs) gf_bs_del(st->dsi_bs);
778 if (st->vorbis_parser) gf_free(st->vorbis_parser);
779 if (st->opus_parser) gf_free(st->opus_parser);
780 gf_free(st);
781 }
782 gf_list_del(ctx->streams);
783 ogg_sync_clear(&ctx->oy);
784 }
785
oggdmx_probe_data(const u8 * data,u32 size,GF_FilterProbeScore * score)786 static const char *oggdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
787 {
788 if (!strncmp(data, "OggS", 4)) {
789 *score = GF_FPROBE_SUPPORTED;
790 return "video/ogg";
791 }
792 return NULL;
793 }
794
795
796 static const GF_FilterCapability OGGDmxCaps[] =
797 {
798 CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
799 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "oga|spx|ogg|ogv|oggm|opus"),
800 CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/ogg|audio/x-ogg|audio/x-vorbis+ogg|application/ogg|application/x-ogg|video/ogg|video/x-ogg|video/x-ogm+ogg"),
801 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
802 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_VORBIS),
803 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_FLAC),
804 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_OPUS),
805 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_SPEEX),
806 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
807 CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_THEORA),
808 };
809
810 #define OFFS(_n) #_n, offsetof(GF_OGGDmxCtx, _n)
811 static const GF_FilterArgs OGGDmxArgs[] =
812 {
813 { OFFS(index), "indexing window length (unimplemented, only 0 disables stream probing for duration), ", GF_PROP_DOUBLE, "1.0", NULL, 0},
814 {0}
815 };
816
817
818 GF_FilterRegister OGGDmxRegister = {
819 .name = "oggdmx",
820 GF_FS_SET_DESCRIPTION("OGG demuxer")
821 GF_FS_SET_HELP("This filter demultiplexes OGG files/data into a set of media PIDs and frames.")
822 .private_size = sizeof(GF_OGGDmxCtx),
823 .initialize = oggdmx_initialize,
824 .finalize = oggdmx_finalize,
825 .args = OGGDmxArgs,
826 .flags = GF_FS_REG_DYNAMIC_PIDS,
827 SETCAPS(OGGDmxCaps),
828 .configure_pid = oggdmx_configure_pid,
829 .process = oggdmx_process,
830 .process_event = oggdmx_process_event,
831 .probe_data = oggdmx_probe_data,
832 };
833
834 #endif // !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_OGG)
835
oggdmx_register(GF_FilterSession * session)836 const GF_FilterRegister *oggdmx_register(GF_FilterSession *session)
837 {
838 #if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_OGG)
839 return &OGGDmxRegister;
840 #else
841 return NULL;
842 #endif
843
844 }
845
846