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