Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / TrueHD 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/avparse.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/filters.h>
29 :
30 : typedef struct
31 : {
32 : u64 pos;
33 : Double duration;
34 : } TrueHDIdx;
35 :
36 : typedef struct
37 : {
38 : u32 frame_size;
39 : u32 time;
40 : u32 sync;
41 : u32 format;
42 :
43 : u32 sample_rate;
44 : Bool mc_6_ch, mc_8_ch;
45 : u8 ch_2_modif, ch_6_modif, ch_8_modif, ch_6_assign;
46 : u16 ch_8_assign;
47 : u16 peak_rate;
48 : } TrueHDHdr;
49 :
50 : typedef struct
51 : {
52 : //filter args
53 : Double index;
54 :
55 : //only one input pid declared
56 : GF_FilterPid *ipid;
57 : //only one output pid declared
58 : GF_FilterPid *opid;
59 :
60 : GF_BitStream *bs;
61 : u64 file_pos, cts;
62 : u32 sample_rate, nb_ch, format;
63 : GF_Fraction64 duration;
64 : Double start_range;
65 : Bool in_seek;
66 : u32 timescale, frame_dur;
67 :
68 : u8 *truehd_buffer;
69 : u32 truehd_buffer_size, truehd_buffer_alloc, resume_from;
70 : u64 byte_offset;
71 :
72 : Bool is_playing;
73 : Bool is_file, file_loaded;
74 : Bool initial_play_done;
75 :
76 : GF_FilterPacket *src_pck;
77 :
78 : TrueHDIdx *indexes;
79 : u32 index_alloc_size, index_size;
80 : } GF_TrueHDDmxCtx;
81 :
82 :
83 :
84 :
85 2 : GF_Err truehd_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
86 : {
87 : const GF_PropertyValue *p;
88 2 : GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
89 :
90 2 : if (is_remove) {
91 0 : ctx->ipid = NULL;
92 0 : if (ctx->opid) {
93 0 : gf_filter_pid_remove(ctx->opid);
94 0 : ctx->opid = NULL;
95 : }
96 : return GF_OK;
97 : }
98 2 : if (! gf_filter_pid_check_caps(pid))
99 : return GF_NOT_SUPPORTED;
100 :
101 2 : ctx->ipid = pid;
102 2 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
103 2 : if (p) ctx->timescale = p->value.uint;
104 :
105 2 : if (ctx->timescale && !ctx->opid) {
106 0 : ctx->opid = gf_filter_pid_new(filter);
107 0 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
108 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
109 : }
110 : return GF_OK;
111 : }
112 :
113 79034 : static GF_Err truehd_parse_frame(GF_BitStream *bs, TrueHDHdr *hdr)
114 : {
115 : memset(hdr, 0, sizeof(TrueHDHdr));
116 79034 : /*u8 nibble = */gf_bs_read_int(bs, 4);
117 79034 : hdr->frame_size = 2 * gf_bs_read_int(bs, 12);
118 79034 : hdr->time = gf_bs_read_u16(bs);
119 79034 : hdr->sync = gf_bs_read_u32(bs);
120 79034 : if (hdr->sync != 0xF8726FBA) {
121 78293 : hdr->sync = 0;
122 78293 : return GF_OK;
123 : }
124 741 : hdr->format = gf_bs_peek_bits(bs, 32, 0);
125 741 : u8 sr_idx = gf_bs_read_int(bs, 4);
126 741 : switch (sr_idx) {
127 0 : case 0: hdr->sample_rate = 48000; break;
128 0 : case 1: hdr->sample_rate = 96000; break;
129 0 : case 2: hdr->sample_rate = 192000; break;
130 741 : case 8: hdr->sample_rate = 44100; break;
131 0 : case 9: hdr->sample_rate = 88200; break;
132 0 : case 10: hdr->sample_rate = 176400; break;
133 : default:
134 : return GF_NON_COMPLIANT_BITSTREAM;
135 : }
136 741 : hdr->mc_6_ch = gf_bs_read_int(bs, 1);
137 741 : hdr->mc_8_ch = gf_bs_read_int(bs, 1);
138 741 : gf_bs_read_int(bs, 2);
139 741 : hdr->ch_2_modif = gf_bs_read_int(bs, 2);
140 741 : hdr->ch_6_modif = gf_bs_read_int(bs, 2);
141 741 : hdr->ch_6_assign = gf_bs_read_int(bs, 5);
142 741 : hdr->ch_8_modif = gf_bs_read_int(bs, 2);
143 741 : hdr->ch_8_assign = gf_bs_read_int(bs, 13);
144 :
145 741 : u16 sig = gf_bs_read_u16(bs);
146 741 : if (sig != 0xB752)
147 : return GF_NON_COMPLIANT_BITSTREAM;
148 :
149 741 : gf_bs_read_u16(bs);
150 741 : gf_bs_read_u16(bs);
151 741 : gf_bs_read_int(bs, 1);
152 741 : hdr->peak_rate = gf_bs_read_int(bs, 15);
153 :
154 :
155 741 : return GF_OK;
156 : }
157 :
158 : static u32 truehd_frame_dur(u32 sample_rate)
159 : {
160 :
161 702 : switch (sample_rate) {
162 0 : case 48000:
163 : case 96000:
164 : case 192000:
165 0 : return sample_rate / 1200;
166 702 : case 44100:
167 : case 88200:
168 : case 176400:
169 702 : return sample_rate * 2 / 2205;
170 : default:
171 : return 0;
172 : }
173 : }
174 155 : static void truehd_check_dur(GF_Filter *filter, GF_TrueHDDmxCtx *ctx)
175 : {
176 : FILE *stream;
177 : GF_BitStream *bs;
178 : u64 duration, cur_dur;
179 : s32 sr = -1;
180 : u32 frame_dur = 0;
181 : const GF_PropertyValue *p;
182 155 : if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
183 :
184 2 : if (ctx->index<=0) {
185 2 : ctx->file_loaded = GF_TRUE;
186 : return;
187 : }
188 :
189 0 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
190 0 : if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
191 0 : ctx->is_file = GF_FALSE;
192 0 : ctx->file_loaded = GF_TRUE;
193 : return;
194 : }
195 0 : ctx->is_file = GF_TRUE;
196 :
197 0 : stream = gf_fopen(p->value.string, "rb");
198 0 : if (!stream) return;
199 :
200 0 : ctx->index_size = 0;
201 :
202 0 : bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
203 : duration = 0;
204 : cur_dur = 0;
205 0 : while ( gf_bs_available(bs) > 8 ) {
206 : TrueHDHdr hdr;
207 0 : u64 pos = gf_bs_get_position(bs);
208 0 : GF_Err e = truehd_parse_frame(bs, &hdr);
209 0 : if (e) break;
210 :
211 0 : if (hdr.sync) {
212 0 : if ((sr>=0) && (sr != hdr.sample_rate)) {
213 0 : duration *= hdr.sample_rate;
214 0 : duration /= sr;
215 :
216 0 : cur_dur *= hdr.sample_rate;
217 0 : cur_dur /= sr;
218 : }
219 0 : sr = hdr.sample_rate;
220 : frame_dur = truehd_frame_dur(hdr.sample_rate);
221 : }
222 :
223 0 : duration += frame_dur;
224 0 : cur_dur += frame_dur;
225 :
226 0 : if (hdr.sync && (cur_dur > ctx->index * sr)) {
227 0 : if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
228 0 : else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
229 0 : ctx->indexes = gf_realloc(ctx->indexes, sizeof(TrueHDIdx)*ctx->index_alloc_size);
230 0 : ctx->indexes[ctx->index_size].pos = gf_bs_get_position(bs);
231 0 : ctx->indexes[ctx->index_size].duration = (Double) duration;
232 0 : ctx->indexes[ctx->index_size].duration /= sr;
233 0 : ctx->index_size ++;
234 : cur_dur = 0;
235 : }
236 :
237 0 : if (!hdr.frame_size) break;
238 0 : gf_bs_seek(bs, pos + hdr.frame_size);
239 : }
240 0 : gf_bs_del(bs);
241 0 : gf_fclose(stream);
242 :
243 0 : if (!ctx->duration.num || (ctx->duration.num * sr != duration * ctx->duration.den)) {
244 0 : ctx->duration.num = (s32) duration;
245 0 : ctx->duration.den = sr;
246 :
247 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
248 : }
249 :
250 0 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
251 0 : if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
252 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE ) );
253 : }
254 :
255 702 : static void truehd_check_pid(GF_Filter *filter, GF_TrueHDDmxCtx *ctx, TrueHDHdr *hdr)
256 : {
257 : u8 *data;
258 : u32 size, max_rate;
259 : GF_BitStream *bs;
260 702 : if (!ctx->opid) {
261 2 : ctx->opid = gf_filter_pid_new(filter);
262 2 : truehd_check_dur(filter, ctx);
263 : }
264 702 : if ((ctx->sample_rate == hdr->sample_rate) && (ctx->format == hdr->format) )
265 0 : return;
266 :
267 702 : ctx->frame_dur = truehd_frame_dur(hdr->sample_rate);
268 :
269 : //copy properties at init or reconfig
270 702 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
271 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT( GF_STREAM_AUDIO));
272 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLES_PER_FRAME, & PROP_UINT(ctx->frame_dur) );
273 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, & PROP_BOOL(GF_FALSE) );
274 :
275 702 : if (ctx->duration.num)
276 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
277 :
278 702 : if (hdr->ch_2_modif==1) {
279 0 : ctx->nb_ch = 1;
280 : } else {
281 702 : ctx->nb_ch = 2;
282 702 : if (hdr->ch_6_assign) {
283 702 : ctx->nb_ch = 0;
284 702 : if (hdr->ch_6_assign & 1) ctx->nb_ch += 2;
285 702 : if (hdr->ch_6_assign & 1<<1) ctx->nb_ch += 1;
286 702 : if (hdr->ch_6_assign & 1<<2) ctx->nb_ch += 1;
287 702 : if (hdr->ch_6_assign & 1<<3) ctx->nb_ch += 2;
288 702 : if (hdr->ch_6_assign & 1<<4) ctx->nb_ch += 2;
289 : }
290 702 : if (hdr->ch_8_assign) {
291 702 : ctx->nb_ch = 0;
292 702 : if (hdr->ch_8_assign & 1) ctx->nb_ch += 2;
293 702 : if (hdr->ch_8_assign & 1<<1) ctx->nb_ch += 1;
294 702 : if (hdr->ch_8_assign & 1<<2) ctx->nb_ch += 1;
295 702 : if (hdr->ch_8_assign & 1<<3) ctx->nb_ch += 2;
296 702 : if (hdr->ch_8_assign & 1<<4) ctx->nb_ch += 2;
297 702 : if (hdr->ch_8_assign & 1<<5) ctx->nb_ch += 2;
298 702 : if (hdr->ch_8_assign & 1<<6) ctx->nb_ch += 2;
299 702 : if (hdr->ch_8_assign & 1<<7) ctx->nb_ch += 1;
300 702 : if (hdr->ch_8_assign & 1<<8) ctx->nb_ch += 1;
301 702 : if (hdr->ch_8_assign & 1<<9) ctx->nb_ch += 2;
302 702 : if (hdr->ch_8_assign & 1<<10) ctx->nb_ch += 2;
303 702 : if (hdr->ch_8_assign & 1<<11) ctx->nb_ch += 1;
304 702 : if (hdr->ch_8_assign & 1<<12) ctx->nb_ch += 1;
305 : }
306 : }
307 :
308 702 : if (!ctx->timescale) {
309 : //we change sample rate, change cts
310 702 : if (ctx->cts && (ctx->sample_rate != hdr->sample_rate)) {
311 0 : ctx->cts *= hdr->sample_rate;
312 0 : ctx->cts /= ctx->sample_rate;
313 : }
314 : }
315 702 : ctx->sample_rate = hdr->sample_rate;
316 :
317 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->timescale ? ctx->timescale : ctx->sample_rate));
318 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, & PROP_UINT(ctx->sample_rate));
319 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, & PROP_UINT(ctx->nb_ch) );
320 :
321 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(GF_CODECID_TRUEHD) );
322 :
323 702 : max_rate = hdr->peak_rate;
324 702 : max_rate *= hdr->sample_rate;
325 702 : max_rate /= 16;
326 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(max_rate) );
327 :
328 702 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
329 702 : gf_bs_write_u32(bs, hdr->format);
330 702 : gf_bs_write_int(bs, hdr->peak_rate, 15);
331 702 : gf_bs_write_int(bs, 0, 1);
332 702 : gf_bs_write_u32(bs, 0);
333 702 : gf_bs_get_content(bs, &data, &size);
334 702 : gf_bs_del(bs);
335 702 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(data, size) );
336 :
337 702 : if (ctx->is_file && ctx->index) {
338 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
339 : }
340 : }
341 :
342 153 : static Bool truehd_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
343 : {
344 : u32 i;
345 : GF_FilterEvent fevt;
346 153 : GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
347 :
348 153 : switch (evt->base.type) {
349 2 : case GF_FEVT_PLAY:
350 2 : if (!ctx->is_playing) {
351 2 : ctx->is_playing = GF_TRUE;
352 2 : ctx->cts = 0;
353 2 : ctx->truehd_buffer_size = 0;
354 2 : ctx->resume_from = 0;
355 : }
356 2 : if (! ctx->is_file) {
357 : return GF_FALSE;
358 : }
359 0 : ctx->start_range = evt->play.start_range;
360 0 : ctx->in_seek = GF_TRUE;
361 0 : ctx->file_pos = 0;
362 0 : if (ctx->start_range) {
363 0 : for (i=1; i<ctx->index_size; i++) {
364 0 : if (ctx->indexes[i].duration>ctx->start_range) {
365 0 : ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->sample_rate);
366 0 : ctx->file_pos = ctx->indexes[i-1].pos;
367 0 : break;
368 : }
369 : }
370 : }
371 0 : if (!ctx->initial_play_done) {
372 0 : ctx->initial_play_done = GF_TRUE;
373 : //seek will not change the current source state, don't send a seek
374 0 : if (!ctx->file_pos)
375 : return GF_TRUE;
376 : }
377 0 : ctx->truehd_buffer_size = 0;
378 0 : ctx->resume_from = 0;
379 : //post a seek
380 0 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
381 0 : fevt.seek.start_offset = ctx->file_pos;
382 0 : gf_filter_pid_send_event(ctx->ipid, &fevt);
383 :
384 : //cancel event
385 0 : return GF_TRUE;
386 :
387 1 : case GF_FEVT_STOP:
388 : //don't cancel event
389 1 : ctx->is_playing = GF_FALSE;
390 1 : return GF_FALSE;
391 :
392 : case GF_FEVT_SET_SPEED:
393 : //cancel event
394 : return GF_TRUE;
395 : default:
396 : break;
397 : }
398 : //by default don't cancel event - to rework once we have downloading in place
399 150 : return GF_FALSE;
400 : }
401 :
402 : static GFINLINE void truehd_update_cts(GF_TrueHDDmxCtx *ctx, TrueHDHdr *hdr)
403 : {
404 11199 : if (ctx->timescale) {
405 0 : u64 inc = ctx->frame_dur;
406 0 : inc *= ctx->timescale;
407 0 : inc /= ctx->sample_rate;
408 0 : ctx->cts += inc;
409 : } else {
410 11199 : ctx->cts += ctx->frame_dur;
411 : }
412 : }
413 :
414 153 : GF_Err truehd_process(GF_Filter *filter)
415 : {
416 153 : GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
417 : GF_FilterPacket *pck, *dst_pck;
418 : u8 *output;
419 : u8 *start;
420 : GF_Err e = GF_OK;
421 : u32 pck_size, remain, prev_pck_size;
422 : u64 cts = GF_FILTER_NO_TS;
423 :
424 : //always reparse duration
425 153 : if (!ctx->duration.num)
426 153 : truehd_check_dur(filter, ctx);
427 :
428 153 : if (ctx->opid && !ctx->is_playing)
429 : return GF_OK;
430 :
431 150 : pck = gf_filter_pid_get_packet(ctx->ipid);
432 150 : if (!pck) {
433 1 : if (gf_filter_pid_is_eos(ctx->ipid)) {
434 1 : if (!ctx->truehd_buffer_size) {
435 1 : if (ctx->opid)
436 1 : gf_filter_pid_set_eos(ctx->opid);
437 1 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
438 1 : ctx->src_pck = NULL;
439 1 : return GF_EOS;
440 : }
441 : } else {
442 : return GF_OK;
443 : }
444 : }
445 :
446 149 : prev_pck_size = ctx->truehd_buffer_size;
447 149 : if (pck && !ctx->resume_from) {
448 149 : const u8 *data = gf_filter_pck_get_data(pck, &pck_size);
449 149 : if (!pck_size) {
450 0 : gf_filter_pid_drop_packet(ctx->ipid);
451 0 : return GF_OK;
452 : }
453 :
454 149 : if (ctx->byte_offset != GF_FILTER_NO_BO) {
455 149 : u64 byte_offset = gf_filter_pck_get_byte_offset(pck);
456 149 : if (!ctx->truehd_buffer_size) {
457 4 : ctx->byte_offset = byte_offset;
458 145 : } else if (ctx->byte_offset + ctx->truehd_buffer_size != byte_offset) {
459 0 : ctx->byte_offset = GF_FILTER_NO_BO;
460 0 : if ((byte_offset != GF_FILTER_NO_BO) && (byte_offset>ctx->truehd_buffer_size) ) {
461 0 : ctx->byte_offset = byte_offset - ctx->truehd_buffer_size;
462 : }
463 : }
464 : }
465 :
466 149 : if (ctx->truehd_buffer_size + pck_size > ctx->truehd_buffer_alloc) {
467 7 : ctx->truehd_buffer_alloc = ctx->truehd_buffer_size + pck_size;
468 7 : ctx->truehd_buffer = gf_realloc(ctx->truehd_buffer, ctx->truehd_buffer_alloc);
469 7 : if (!ctx->truehd_buffer) return GF_OUT_OF_MEM;
470 : }
471 149 : memcpy(ctx->truehd_buffer + ctx->truehd_buffer_size, data, pck_size);
472 149 : ctx->truehd_buffer_size += pck_size;
473 : }
474 :
475 : //input pid sets some timescale - we flushed pending data , update cts
476 149 : if (ctx->timescale && pck) {
477 0 : cts = gf_filter_pck_get_cts(pck);
478 : }
479 :
480 0 : if (cts == GF_FILTER_NO_TS) {
481 : //avoids updating cts
482 : prev_pck_size = 0;
483 : }
484 :
485 149 : remain = ctx->truehd_buffer_size;
486 149 : start = ctx->truehd_buffer;
487 :
488 149 : if (ctx->resume_from) {
489 0 : start += ctx->resume_from - 1;
490 0 : remain -= ctx->resume_from - 1;
491 0 : ctx->resume_from = 0;
492 : }
493 :
494 149 : if (!ctx->bs) {
495 2 : ctx->bs = gf_bs_new(start, remain, GF_BITSTREAM_READ);
496 : } else {
497 147 : gf_bs_reassign_buffer(ctx->bs, start, remain);
498 : }
499 11348 : while (remain > 8) {
500 : u8 *frame;
501 : TrueHDHdr hdr;
502 : u32 frame_start, bytes_to_drop=0;
503 :
504 11324 : frame_start = (u32) gf_bs_get_position(ctx->bs);
505 11324 : e = truehd_parse_frame(ctx->bs, &hdr);
506 11324 : if (e) {
507 : remain = 0;
508 123 : break;
509 : }
510 11324 : if (!hdr.frame_size) {
511 : remain = 0;
512 : break;
513 : }
514 :
515 : //frame not complete, wait
516 11324 : if (remain < frame_start + hdr.frame_size)
517 : break;
518 :
519 11201 : if (hdr.sync)
520 702 : truehd_check_pid(filter, ctx, &hdr);
521 :
522 11201 : if (!ctx->is_playing) {
523 2 : ctx->resume_from = 1 + ctx->truehd_buffer_size - remain;
524 4 : return GF_OK;
525 : }
526 :
527 11199 : frame = start + frame_start;
528 :
529 11199 : if (ctx->in_seek) {
530 0 : u64 nb_samples_at_seek = (u64) (ctx->start_range * hdr.sample_rate);
531 0 : if (ctx->cts + ctx->frame_dur >= nb_samples_at_seek) {
532 : //u32 samples_to_discard = (ctx->cts + ctx->dts_inc) - nb_samples_at_seek;
533 0 : ctx->in_seek = GF_FALSE;
534 : }
535 : }
536 :
537 11199 : bytes_to_drop = hdr.frame_size;
538 11199 : if (ctx->timescale && !prev_pck_size && (cts != GF_FILTER_NO_TS) ) {
539 : //trust input CTS if diff is more than one sec
540 0 : if ((cts > ctx->cts + ctx->timescale) || (ctx->cts > cts + ctx->timescale))
541 0 : ctx->cts = cts;
542 : cts = GF_FILTER_NO_TS;
543 : }
544 :
545 11199 : if (!ctx->in_seek) {
546 11199 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, hdr.frame_size, &output);
547 11199 : if (!dst_pck) return GF_OUT_OF_MEM;
548 11199 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, dst_pck);
549 :
550 11199 : memcpy(output, frame, hdr.frame_size);
551 11199 : gf_filter_pck_set_dts(dst_pck, ctx->cts);
552 11199 : gf_filter_pck_set_cts(dst_pck, ctx->cts);
553 11199 : if (hdr.sync)
554 700 : gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
555 11199 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
556 :
557 11199 : if (ctx->byte_offset != GF_FILTER_NO_BO) {
558 11199 : gf_filter_pck_set_byte_offset(dst_pck, ctx->byte_offset + hdr.frame_size);
559 : }
560 :
561 11199 : gf_filter_pck_send(dst_pck);
562 : }
563 : truehd_update_cts(ctx, &hdr);
564 :
565 : //truncated last frame
566 11199 : if (bytes_to_drop > remain) {
567 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[TrueHDDmx] truncated TrueHD frame!\n"));
568 : bytes_to_drop = remain;
569 : }
570 :
571 11199 : if (!bytes_to_drop) {
572 : bytes_to_drop = 1;
573 : }
574 11199 : start += bytes_to_drop;
575 11199 : remain -= bytes_to_drop;
576 11199 : gf_bs_reassign_buffer(ctx->bs, start, remain);
577 :
578 11199 : if (prev_pck_size) {
579 0 : if (prev_pck_size > bytes_to_drop) prev_pck_size -= bytes_to_drop;
580 : else {
581 : prev_pck_size=0;
582 0 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
583 0 : ctx->src_pck = pck;
584 0 : if (pck)
585 0 : gf_filter_pck_ref_props(&ctx->src_pck);
586 : }
587 : }
588 11199 : if (ctx->byte_offset != GF_FILTER_NO_BO)
589 11199 : ctx->byte_offset += bytes_to_drop;
590 : }
591 :
592 147 : if (!pck) {
593 0 : ctx->truehd_buffer_size = 0;
594 0 : return truehd_process(filter);
595 : } else {
596 147 : if (remain) {
597 146 : memmove(ctx->truehd_buffer, start, remain);
598 : }
599 147 : ctx->truehd_buffer_size = remain;
600 147 : gf_filter_pid_drop_packet(ctx->ipid);
601 : }
602 147 : return e;
603 : }
604 :
605 2 : static void truehd_finalize(GF_Filter *filter)
606 : {
607 2 : GF_TrueHDDmxCtx *ctx = gf_filter_get_udta(filter);
608 2 : if (ctx->bs) gf_bs_del(ctx->bs);
609 2 : if (ctx->truehd_buffer) gf_free(ctx->truehd_buffer);
610 2 : if (ctx->indexes) gf_free(ctx->indexes);
611 2 : }
612 :
613 3065 : static const char *truehd_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
614 : {
615 : u32 nb_frames=0;
616 3065 : GF_BitStream *bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
617 72222 : while (gf_bs_available(bs) > 8 ) {
618 : TrueHDHdr hdr;
619 67710 : u64 pos = gf_bs_get_position(bs);
620 67710 : GF_Err e = truehd_parse_frame(bs, &hdr);
621 67710 : if (e || !hdr.frame_size) {
622 : nb_frames = 0;
623 1618 : break;
624 : }
625 66092 : if (hdr.sync) nb_frames++;
626 66092 : gf_bs_seek(bs, pos + hdr.frame_size);
627 : }
628 3065 : gf_bs_del(bs);
629 3065 : if (nb_frames) {
630 2 : *score = GF_FPROBE_MAYBE_SUPPORTED;
631 2 : return "audio/truehd";
632 : }
633 : return NULL;
634 : }
635 :
636 : static const GF_FilterCapability TrueHDDmxCaps[] =
637 : {
638 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
639 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "mlp|thd|truehd"),
640 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "audio/truehd|audio/x-truehd"),
641 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
642 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_TRUEHD),
643 : CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
644 : {0},
645 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
646 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_TRUEHD),
647 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
648 : };
649 :
650 : #define OFFS(_n) #_n, offsetof(GF_TrueHDDmxCtx, _n)
651 : static const GF_FilterArgs TrueHDDmxArgs[] =
652 : {
653 : { OFFS(index), "indexing window length", GF_PROP_DOUBLE, "1.0", NULL, 0},
654 : {0}
655 : };
656 :
657 :
658 : GF_FilterRegister TrueHDDmxRegister = {
659 : .name = "rftruehd",
660 : GF_FS_SET_DESCRIPTION("TrueHD reframer")
661 : GF_FS_SET_HELP("This filter parses Dolby TrueHD files/data and outputs corresponding audio PID and frames.")
662 : .private_size = sizeof(GF_TrueHDDmxCtx),
663 : .args = TrueHDDmxArgs,
664 : .finalize = truehd_finalize,
665 : SETCAPS(TrueHDDmxCaps),
666 : .configure_pid = truehd_configure_pid,
667 : .process = truehd_process,
668 : .probe_data = truehd_probe_data,
669 : .process_event = truehd_process_event
670 : };
671 :
672 :
673 2877 : const GF_FilterRegister *truehd_register(GF_FilterSession *session)
674 : {
675 2877 : return &TrueHDDmxRegister;
676 : }
677 :
|