1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2017
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / AMR&EVRC&SMV reframer 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/bitstream.h>
29 #include <gpac/internal/media_dev.h>
30 
31 typedef struct
32 {
33 	u64 pos;
34 	Double duration;
35 } QCPIdx;
36 
37 typedef struct
38 {
39 	//filter args
40 	Double index;
41 
42 	//only one input pid declared
43 	GF_FilterPid *ipid;
44 	//only one output pid declared
45 	GF_FilterPid *opid;
46 
47 	u32 codecid, sample_rate, block_size;
48 	Bool done;
49 
50 	u64 cts;
51 	GF_Fraction64 duration;
52 	Double start_range;
53 
54 	Bool in_seek;
55 	u32 timescale;
56 	Bool is_playing;
57 	Bool is_file;
58 	Bool initial_play_done, file_loaded;
59 
60 	u32 data_chunk_offset, data_chunk_size, data_chunk_remain;
61 	u32 resume_from;
62 	u32 remaining;
63 	u32 skip_bytes;
64 	u32 vrat_rate_flag, pck_size, rate_table_count;
65 	QCPRateTable rate_table[8];
66 
67 	Bool hdr_processed;
68 
69 	char *buffer;
70 	u32 buffer_alloc, buffer_size;
71 
72 	GF_BitStream *bs;
73 
74 
75 	QCPIdx *indexes;
76 	u32 index_alloc_size, index_size;
77 } GF_QCPDmxCtx;
78 
79 
80 
81 
qcpdmx_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)82 GF_Err qcpdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
83 {
84 	GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
85 
86 	if (is_remove) {
87 		ctx->ipid = NULL;
88 		gf_filter_pid_remove(ctx->opid);
89 		return GF_OK;
90 	}
91 	if (! gf_filter_pid_check_caps(pid))
92 		return GF_NOT_SUPPORTED;
93 
94 	ctx->ipid = pid;
95 	return GF_OK;
96 }
97 
98 static GF_Err qcpdmx_process_header(GF_Filter *filter, GF_QCPDmxCtx *ctx, char *data, u32 size, GF_BitStream *file_bs);
99 
qcpdmx_check_dur(GF_Filter * filter,GF_QCPDmxCtx * ctx)100 static void qcpdmx_check_dur(GF_Filter *filter, GF_QCPDmxCtx *ctx)
101 {
102 	FILE *stream;
103 	GF_BitStream *bs;
104 	u32 i, chunk_size;
105 	GF_Err e;
106 	u32 data_chunk_size = 0;
107 	u64 duration, cur_dur;
108 	char magic[4];
109 	const GF_PropertyValue *p;
110 	if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
111 
112 	if (ctx->index<=0) {
113 		ctx->file_loaded = GF_TRUE;
114 		return;
115 	}
116 
117 	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
118 	if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
119 		ctx->is_file = GF_FALSE;
120 		ctx->file_loaded = GF_TRUE;
121 		return;
122 	}
123 	ctx->is_file = GF_TRUE;
124 
125 	stream = gf_fopen(p->value.string, "rb");
126 	if (!stream) return;
127 
128 	ctx->codecid = 0;
129 	ctx->sample_rate = 8000;
130 	ctx->block_size = 160;
131 
132 	bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
133 	if (!ctx->hdr_processed ) {
134 		e = qcpdmx_process_header(filter, ctx, NULL, 0, bs);
135 		if (e) {
136 			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Header parsed error %s\n", gf_error_to_string(e) ));
137 		}
138 	} else {
139 		gf_bs_skip_bytes(bs, 170);
140 	}
141 	while (gf_bs_available(bs) ) {
142 		gf_bs_read_data(bs, magic, 4);
143 		chunk_size = gf_bs_read_u32_le(bs);
144 
145 		if (strncmp(magic, "data", 4)) {
146 			gf_bs_skip_bytes(bs, chunk_size);
147 			if (chunk_size%2) gf_bs_skip_bytes(bs, 1);
148 			continue;
149 		}
150 		data_chunk_size = chunk_size;
151 		break;
152 	}
153 	if (!data_chunk_size) {
154 		gf_bs_del(bs);
155 		gf_fclose(stream);
156 		return;
157 	}
158 
159 	ctx->index_size = 0;
160 	ctx->data_chunk_offset = (u32) gf_ftell(stream);
161 	ctx->data_chunk_size = data_chunk_size;
162 
163 	duration = 0;
164 	cur_dur = 0;
165 	while (data_chunk_size) {
166 		u32 idx, size=0;
167 		u64 pos;
168 		pos = gf_ftell(stream);
169 		/*get frame rate idx*/
170 		if (ctx->vrat_rate_flag) {
171 			idx = gf_fgetc(stream);
172 			chunk_size-=1;
173 			for (i=0; i<ctx->rate_table_count; i++) {
174 				if (ctx->rate_table[i].rate_idx==idx) {
175 					size = ctx->rate_table[i].pck_size;
176 					break;
177 				}
178 			}
179 			gf_fseek(stream, size, SEEK_CUR);
180 			size++;
181 		} else {
182 			size = ctx->pck_size;
183 			gf_fseek(stream, size, SEEK_CUR);
184 		}
185 		data_chunk_size-= size;
186 
187 		duration += ctx->block_size;
188 		cur_dur += ctx->block_size;
189 		if (cur_dur > ctx->index * ctx->sample_rate) {
190 			if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
191 			else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
192 			ctx->indexes = gf_realloc(ctx->indexes, sizeof(QCPIdx)*ctx->index_alloc_size);
193 			ctx->indexes[ctx->index_size].pos = pos;
194 			ctx->indexes[ctx->index_size].duration = (Double) duration;
195 			ctx->indexes[ctx->index_size].duration /= ctx->sample_rate;
196 			ctx->index_size ++;
197 			cur_dur = 0;
198 		}
199 	}
200 	gf_bs_del(bs);
201 	gf_fclose(stream);
202 
203 	if (!ctx->duration.num || (ctx->duration.num  * ctx->sample_rate != duration * ctx->duration.den)) {
204 		ctx->duration.num = (s32) duration;
205 		ctx->duration.den = ctx->sample_rate;
206 
207 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
208 	}
209 
210 	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
211 	if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
212 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
213 }
214 
qcpdmx_process_event(GF_Filter * filter,const GF_FilterEvent * evt)215 static Bool qcpdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
216 {
217 	u32 i;
218 	u64 file_pos = 0;
219 	GF_FilterEvent fevt;
220 	GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
221 
222 	switch (evt->base.type) {
223 	case GF_FEVT_PLAY:
224 		if (!ctx->is_playing) {
225 			ctx->is_playing = GF_TRUE;
226 			ctx->cts = 0;
227 			ctx->remaining = 0;
228 		}
229 		if (! ctx->is_file) {
230 			return GF_FALSE;
231 		}
232 		qcpdmx_check_dur(filter, ctx);
233 
234 		ctx->start_range = evt->play.start_range;
235 		ctx->in_seek = GF_TRUE;
236 		if (ctx->start_range) {
237 			for (i=1; i<ctx->index_size; i++) {
238 				if (ctx->indexes[i].duration>ctx->start_range) {
239 					ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
240 					file_pos = ctx->indexes[i-1].pos;
241 					break;
242 				}
243 			}
244 		}
245 		if (!ctx->initial_play_done) {
246 			ctx->initial_play_done = GF_TRUE;
247 			//seek will not change the current source state, don't send a seek
248 			if (!file_pos) {
249 				return GF_TRUE;
250 			}
251 		}
252 		if (!file_pos) {
253 			file_pos = ctx->data_chunk_offset;
254 			ctx->data_chunk_remain = ctx->data_chunk_size;
255 		}
256 
257 		//post a seek
258 		GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
259 		fevt.seek.start_offset = file_pos;
260 		gf_filter_pid_send_event(ctx->ipid, &fevt);
261 
262 		//cancel event
263 		return GF_TRUE;
264 
265 	case GF_FEVT_STOP:
266 		ctx->is_playing = GF_FALSE;
267 		//don't cancel event
268 		return GF_FALSE;
269 
270 	case GF_FEVT_SET_SPEED:
271 		//cancel event
272 		return GF_TRUE;
273 	default:
274 		break;
275 	}
276 	//by default don't cancel event - to rework once we have downloading in place
277 	return GF_FALSE;
278 }
279 
280 /*QCP codec GUIDs*/
281 static const char *QCP_QCELP_GUID_1 = "\x41\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\x00\x80\x5F\xB4\xB9\x7E";
282 static const char *QCP_QCELP_GUID_2 = "\x42\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\x00\x80\x5F\xB4\xB9\x7E";
283 static const char *QCP_EVRC_GUID = "\x8D\xD4\x89\xE6\x76\x90\xB5\x46\x91\xEF\x73\x6A\x51\x00\xCE\xB4";
284 static const char *QCP_SMV_GUID = "\x75\x2B\x7C\x8D\x97\xA7\x46\xED\x98\x5E\xD5\x3C\x8C\xC7\x5F\x84";
285 
qcpdmx_process_header(GF_Filter * filter,GF_QCPDmxCtx * ctx,char * data,u32 size,GF_BitStream * file_bs)286 static GF_Err qcpdmx_process_header(GF_Filter *filter, GF_QCPDmxCtx *ctx, char *data, u32 size, GF_BitStream *file_bs)
287 {
288 	char magic[12], GUID[17], name[81], fmt[162];
289 	u32 riff_size, chunk_size, i, avg_bps;
290 	Bool has_pad;
291 	const GF_PropertyValue *p;
292 	GF_BitStream *bs;
293 
294 	bs = file_bs ? file_bs : gf_bs_new(data, size, GF_BITSTREAM_READ);
295 
296 	gf_bs_read_data(bs, magic, 4);
297 	if (strnicmp(magic, "RIFF", 4)) {
298 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: RIFF header not found\n"));
299 		if (!file_bs) gf_bs_del(bs);
300 		return GF_NON_COMPLIANT_BITSTREAM;
301 	}
302 	riff_size = gf_bs_read_u32_le(bs);
303 	gf_bs_read_data(bs, fmt, 162);
304 	gf_bs_seek(bs, 8);
305 	gf_bs_read_data(bs, magic, 4);
306 	if (strnicmp(magic, "QLCM", 4)) {
307 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: QLCM header not found\n"));
308 		if (!file_bs) gf_bs_del(bs);
309 		return GF_NON_COMPLIANT_BITSTREAM;
310 	}
311 	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
312 	if (p && p->value.longuint != riff_size+8) {
313 		GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[QCPDmx] Broken file:  RIFF-Size %d got %d\n", p->value.uint - 8, riff_size));
314 	}
315 	/*fmt*/
316 	gf_bs_read_data(bs, magic, 4);
317 	if (strnicmp(magic, "fmt ", 4)) {
318 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: FMT not found\n"));
319 		if (!file_bs) gf_bs_del(bs);
320 		return GF_NON_COMPLIANT_BITSTREAM;
321 	}
322 	chunk_size = gf_bs_read_u32_le(bs);
323 	has_pad = (chunk_size%2) ? GF_TRUE : GF_FALSE;
324 	/*major = */gf_bs_read_u8(bs);
325 	/*minor = */gf_bs_read_u8(bs);
326 	chunk_size -= 2;
327 	/*codec info*/
328 	gf_bs_read_data(bs, GUID, 16);
329 	GUID[16]=0;
330 	/*version = */gf_bs_read_u16_le(bs);
331 	chunk_size -= 18;
332 	gf_bs_read_data(bs, name, 80);
333 	name[80]=0;
334 	chunk_size -= 80;
335 	avg_bps = gf_bs_read_u16_le(bs);
336 	ctx->pck_size = gf_bs_read_u16_le(bs);
337 	ctx->block_size = gf_bs_read_u16_le(bs);
338 	ctx->sample_rate = gf_bs_read_u16_le(bs);
339 	/*bps = */gf_bs_read_u16_le(bs);
340 	ctx->rate_table_count = gf_bs_read_u32_le(bs);
341 	chunk_size -= 14;
342 	/*skip var rate*/
343 	for (i=0; i<8; i++) {
344 		ctx->rate_table[i].pck_size = gf_bs_read_u8(bs);
345 		ctx->rate_table[i].rate_idx = gf_bs_read_u8(bs);
346 	}
347 	chunk_size -= 16;
348 	gf_bs_skip_bytes(bs, 5*4);/*reserved*/
349 	chunk_size -= 20;
350 	gf_bs_skip_bytes(bs, chunk_size);
351 	if (has_pad) gf_bs_read_u8(bs);
352 
353 	if (!strncmp(GUID, QCP_QCELP_GUID_1, 16) || !strncmp(GUID, QCP_QCELP_GUID_2, 16)) {
354 		ctx->codecid = GF_CODECID_QCELP;
355 	} else if (!strncmp(GUID, QCP_EVRC_GUID, 16)) {
356 		ctx->codecid = GF_CODECID_EVRC;
357 	} else if (!strncmp(GUID, QCP_SMV_GUID, 16)) {
358 		ctx->codecid = GF_CODECID_SMV;
359 	} else {
360 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Unsupported codec GUID %s\n", GUID));
361 		if (!file_bs) gf_bs_del(bs);
362 		return GF_NON_COMPLIANT_BITSTREAM;
363 	}
364 	/*vrat*/
365 	gf_bs_read_data(bs, magic, 4);
366 	if (strnicmp(magic, "vrat", 4)) {
367 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[QCPDmx] Broken file: VRAT not found\n"));
368 		if (!file_bs) gf_bs_del(bs);
369 		return GF_NON_COMPLIANT_BITSTREAM;
370 	}
371 	chunk_size = gf_bs_read_u32_le(bs);
372 	has_pad = (chunk_size%2) ? GF_TRUE : GF_FALSE;
373 	ctx->vrat_rate_flag = gf_bs_read_u32_le(bs);
374 	/*size_in_packet =*/gf_bs_read_u32_le(bs);
375 	chunk_size -= 8;
376 	gf_bs_skip_bytes(bs, chunk_size);
377 	if (has_pad) gf_bs_read_u8(bs);
378 
379 	if (file_bs) return GF_OK;
380 
381 	gf_bs_del(bs);
382 
383 
384 	ctx->opid = gf_filter_pid_new(filter);
385 	gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
386 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
387 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->sample_rate));
388 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
389 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(1) );
390 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(ctx->codecid ) );
391 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->block_size ) );
392 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(avg_bps));
393 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FRAME_SIZE, & PROP_UINT(ctx->pck_size));
394 
395 	qcpdmx_check_dur(filter, ctx);
396 
397 	return GF_OK;
398 
399 }
400 
qcpdmx_process(GF_Filter * filter)401 GF_Err qcpdmx_process(GF_Filter *filter)
402 {
403 	GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
404 	GF_FilterPacket *pck;
405 	u64 byte_offset;
406 	u8 *data, *output;
407 	u8 *start;
408 	u32 pck_size, remain;
409 	GF_Err e;
410 	//update duration
411 	qcpdmx_check_dur(filter, ctx);
412 
413 	if (ctx->done) return GF_EOS;
414 
415 	if (ctx->opid && !ctx->is_playing)
416 		return GF_OK;
417 
418 	pck = gf_filter_pid_get_packet(ctx->ipid);
419 	if (!pck) {
420 		if (gf_filter_pid_is_eos(ctx->ipid)) {
421 			if (ctx->opid)
422 				gf_filter_pid_set_eos(ctx->opid);
423 			assert(ctx->remaining == 0);
424 			return GF_EOS;
425 		}
426 		return GF_OK;
427 	}
428 
429 	data = (char *) gf_filter_pck_get_data(pck, &pck_size);
430 	byte_offset = gf_filter_pck_get_byte_offset(pck);
431 
432 	start = data;
433 	remain = pck_size;
434 
435 	//flush not previously dispatched data
436 	if (ctx->remaining) {
437 		u32 to_send = ctx->remaining;
438 		if (ctx->remaining > pck_size) {
439 			to_send = pck_size;
440 			ctx->remaining -= pck_size;
441 		} else {
442 			ctx->remaining = 0;
443 		}
444 		if (! ctx->in_seek) {
445 			GF_FilterPacket *dst_pck = gf_filter_pck_new_alloc(ctx->opid, to_send, &output);
446 			memcpy(output, data, to_send);
447 
448 			gf_filter_pck_set_cts(dst_pck, ctx->cts);
449 			gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
450 			gf_filter_pck_set_framing(dst_pck, GF_FALSE, ctx->remaining ? GF_FALSE : GF_TRUE);
451 			if (byte_offset != GF_FILTER_NO_BO) {
452 				gf_filter_pck_set_byte_offset(dst_pck, byte_offset);
453 			}
454 			gf_filter_pck_send(dst_pck);
455 		}
456 		assert (ctx->data_chunk_remain >= to_send);
457 		ctx->data_chunk_remain -= to_send;
458 
459 		if (ctx->remaining) {
460 			gf_filter_pid_drop_packet(ctx->ipid);
461 			return GF_OK;
462 		}
463 		ctx->cts += ctx->block_size;
464 		start += to_send;
465 		remain -= to_send;
466 
467 		if (!ctx->data_chunk_remain) {
468 			ctx->done = GF_TRUE;
469 			if (ctx->opid)
470 				gf_filter_pid_set_eos(ctx->opid);
471 			return GF_EOS;
472 		}
473 	}
474 
475 	if (ctx->resume_from) {
476 		start += ctx->resume_from;
477 		remain -= ctx->resume_from;
478 		ctx->resume_from = 0;
479 	}
480 
481 
482 	while (remain) {
483 		u32 i, chunk_size=0;
484 		u32 idx = 0;
485 		u32 size = 0;
486 		u64 b_offset;
487 		u8 *pck_data;
488 		Bool has_pad;
489 
490 		if (!ctx->hdr_processed) {
491 			if (ctx->buffer_size + remain < 170) {
492 				if (ctx->buffer_alloc < ctx->buffer_size + remain) {
493 					ctx->buffer_alloc = ctx->buffer_size + remain;
494 					ctx->buffer = gf_realloc(ctx->buffer, ctx->buffer_alloc);
495 				}
496 				memcpy(ctx->buffer + ctx->buffer_size, start, remain);
497 				ctx->buffer_size += remain;
498 				gf_filter_pid_drop_packet(ctx->ipid);
499 				return GF_OK;
500 			}
501 			ctx->hdr_processed = GF_TRUE;
502 			if (ctx->buffer_size) {
503 				e = qcpdmx_process_header(filter, ctx, ctx->buffer, ctx->buffer_size, NULL);
504 			} else {
505 				e = qcpdmx_process_header(filter, ctx, start, remain, NULL);
506 			}
507 			start += 170 - ctx->buffer_size;
508 			remain -= 170 - ctx->buffer_size;
509 			ctx->buffer_size = 0;
510 
511 			if (e) {
512 				gf_filter_setup_failure(filter, e);
513 				ctx->done = GF_TRUE;
514 				gf_filter_pid_drop_packet(ctx->ipid);
515 				return GF_EOS;
516 			}
517 			continue;
518 		}
519 		//skip current chunk
520 		if (ctx->skip_bytes) {
521 			if (remain<ctx->skip_bytes) {
522 				ctx->skip_bytes -= remain;
523 				gf_filter_pid_drop_packet(ctx->ipid);
524 				return GF_OK;
525 			}
526 			start += ctx->skip_bytes;
527 			remain -= ctx->skip_bytes;
528 			ctx->skip_bytes = 0;
529 		}
530 
531 		//load chunk tag
532 		if (!ctx->data_chunk_remain) {
533 			char magic[4];
534 			//load chunk
535 			if (remain<8) {
536 				if (ctx->buffer_alloc < ctx->buffer_size + 8) {
537 					ctx->buffer_alloc = ctx->buffer_size + 8;
538 					ctx->buffer = gf_realloc(ctx->buffer, ctx->buffer_alloc);
539 				}
540 				memcpy(ctx->buffer + ctx->buffer_size, start, remain);
541 				ctx->buffer_size += remain;
542 				gf_filter_pid_drop_packet(ctx->ipid);
543 				return GF_OK;
544 			}
545 			if (!ctx->buffer_size) {
546 				if (!ctx->bs) {
547 					ctx->bs = gf_bs_new((u8 *) start, remain, GF_BITSTREAM_READ);
548 				} else {
549 					gf_bs_reassign_buffer(ctx->bs, start, remain);
550 				}
551 			} else {
552 				if (!ctx->bs) {
553 					ctx->bs = gf_bs_new((u8 *) ctx->buffer, ctx->buffer_size, GF_BITSTREAM_READ);
554 				} else {
555 					gf_bs_reassign_buffer(ctx->bs, ctx->buffer, ctx->buffer_size);
556 				}
557 			}
558 
559 			gf_bs_read_data(ctx->bs, magic, 4);
560 			chunk_size = gf_bs_read_u32_le(ctx->bs);
561 			has_pad = (chunk_size%2) ? GF_TRUE : GF_FALSE;
562 			start += 8-ctx->buffer_size;
563 			remain -= 8-ctx->buffer_size;
564 			ctx->buffer_size = 0;
565 
566 			//wait until we reach data chunk
567 			if (strnicmp(magic, "data", 4)) {
568 				ctx->skip_bytes = chunk_size;
569 				if (has_pad) ctx->skip_bytes++;
570 				continue;
571 			} else {
572 				ctx->data_chunk_size = ctx->data_chunk_remain = chunk_size;
573 			}
574 		}
575 
576 		//we are in the data chunk
577 		if (!ctx->is_playing) {
578 			ctx->resume_from = (u32) ( (char *)start -  (char *)data);
579 			return GF_OK;
580 		}
581 
582 		b_offset = gf_filter_pck_get_byte_offset(pck);
583 		if (b_offset != GF_FILTER_NO_BO) {
584 			b_offset += (start - (u8 *) data);
585 		}
586 		/*get frame rate idx*/
587 		if (ctx->vrat_rate_flag) {
588 			idx = start[0];
589 			//chunk_size-=1;
590 			for (i=0; i<ctx->rate_table_count; i++) {
591 				if (ctx->rate_table[i].rate_idx==idx) {
592 					size = ctx->rate_table[i].pck_size;
593 					break;
594 				}
595 			}
596 			size++;
597 		} else {
598 			size = ctx->pck_size;
599 		}
600 
601 		if (size > remain) {
602 			ctx->remaining = size - remain;
603 			size = remain;
604 		} else {
605 			ctx->remaining = 0;
606 		}
607 
608 		if (ctx->in_seek) {
609 			u64 nb_samples_at_seek = (u64) (ctx->start_range * ctx->sample_rate);
610 			if (ctx->cts + ctx->block_size >= nb_samples_at_seek) {
611 				//u32 samples_to_discard = (ctx->cts + ctx->block_size ) - nb_samples_at_seek;
612 				ctx->in_seek = GF_FALSE;
613 			}
614 		}
615 
616 		if (!ctx->in_seek) {
617 			GF_FilterPacket *dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &pck_data);
618 			memcpy(pck_data, start, size);
619 
620 			gf_filter_pck_set_framing(dst_pck, GF_TRUE, ctx->remaining ? GF_FALSE : GF_TRUE);
621 			gf_filter_pck_set_cts(dst_pck, ctx->cts);
622 			gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
623 			gf_filter_pck_set_duration(dst_pck, ctx->block_size);
624 			if (b_offset != GF_FILTER_NO_BO)
625 				gf_filter_pck_set_byte_offset(dst_pck, b_offset);
626 
627 			gf_filter_pck_send(dst_pck);
628 		}
629 
630 		assert (ctx->data_chunk_remain >= size);
631 		ctx->data_chunk_remain -= size;
632 		if (!ctx->data_chunk_remain) {
633 			ctx->done = GF_TRUE;
634 			if (ctx->opid)
635 				gf_filter_pid_set_eos(ctx->opid);
636 			break;
637 		}
638 
639 		if (ctx->remaining) break;
640 		ctx->cts += ctx->block_size;
641 		start += size;
642 		remain -= size;
643 
644 
645 		//don't demux too much of input, abort when we would block. This avoid dispatching
646 		//a huge number of frames in a single call
647 		if (gf_filter_pid_would_block(ctx->opid)) {
648 			ctx->resume_from = (u32) ((char *)start -  (char *)data);
649 			return GF_OK;
650 		}
651 	}
652 	gf_filter_pid_drop_packet(ctx->ipid);
653 
654 	return GF_OK;
655 }
656 
qcpdmx_finalize(GF_Filter * filter)657 static void qcpdmx_finalize(GF_Filter *filter)
658 {
659 	GF_QCPDmxCtx *ctx = gf_filter_get_udta(filter);
660 	if (ctx->indexes) gf_free(ctx->indexes);
661 	if (ctx->bs) gf_bs_del(ctx->bs);
662 	if (ctx->buffer) gf_free(ctx->buffer);
663 }
664 
qcpdmx_probe_data(const u8 * data,u32 size,GF_FilterProbeScore * score)665 static const char *qcpdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
666 {
667 	char magic[5];
668 	Bool is_qcp = GF_TRUE;
669 	GF_BitStream *bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
670 
671 	magic[4] = 0;
672 	gf_bs_read_data(bs, magic, 4);
673 	if (strnicmp(magic, "RIFF", 4)) {
674 		is_qcp = GF_FALSE;
675 	} else {
676 		/*riff_size = */gf_bs_read_u32_le(bs);
677 		gf_bs_read_data(bs, magic, 4);
678 		if (strnicmp(magic, "QLCM", 4)) {
679 			is_qcp = GF_FALSE;
680 		}
681 	}
682 	gf_bs_del(bs);
683 	if (!is_qcp) return NULL;
684 	*score = GF_FPROBE_SUPPORTED;
685 	return "audio/qcp";
686 }
687 
688 static const GF_FilterCapability QCPDmxCaps[] =
689 {
690 	CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
691 	CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "qcp"),
692 	CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/qcp"),
693 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
694 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_QCELP),
695 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_SMV),
696 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_EVRC),
697 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_EVRC_PV),
698 	CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
699 };
700 
701 
702 #define OFFS(_n)	#_n, offsetof(GF_QCPDmxCtx, _n)
703 static const GF_FilterArgs QCPDmxArgs[] =
704 {
705 	{ OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
706 	{0}
707 };
708 
709 
710 GF_FilterRegister QCPDmxRegister = {
711 	.name = "rfqcp",
712 	GF_FS_SET_DESCRIPTION("QCP reframer")
713 	GF_FS_SET_HELP("This filter parses QCP files/data and outputs corresponding audio PID and frames.")
714 	.private_size = sizeof(GF_QCPDmxCtx),
715 	.args = QCPDmxArgs,
716 	.finalize = qcpdmx_finalize,
717 	SETCAPS(QCPDmxCaps),
718 	.configure_pid = qcpdmx_configure_pid,
719 	.process = qcpdmx_process,
720 	.probe_data = qcpdmx_probe_data,
721 	.process_event = qcpdmx_process_event
722 };
723 
724 
qcpdmx_register(GF_FilterSession * session)725 const GF_FilterRegister *qcpdmx_register(GF_FilterSession *session)
726 {
727 	return &QCPDmxRegister;
728 }
729 
730