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