Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Romain Bouqueau, Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2018-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / AV1 IVF/OBU/annexB 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 : #include <gpac/internal/media_dev.h>
30 :
31 : #ifndef GPAC_DISABLE_AV_PARSERS
32 :
33 : typedef struct
34 : {
35 : u64 pos;
36 : Double duration;
37 : } AV1Idx;
38 :
39 : typedef enum {
40 : NOT_SET, /*Section 5*/
41 : OBUs, /*Section 5*/
42 : AnnexB,
43 : IVF,
44 : UNSUPPORTED
45 : } AV1BitstreamSyntax;
46 :
47 : typedef struct
48 : {
49 : //filter args
50 : GF_Fraction fps;
51 : Double index;
52 : Bool importer;
53 : Bool deps;
54 :
55 : u32 bsdbg;
56 :
57 : //only one input pid declared
58 : GF_FilterPid *ipid;
59 : //only one output pid declared
60 : GF_FilterPid *opid;
61 :
62 : AV1BitstreamSyntax bsmode;
63 :
64 : GF_BitStream *bs;
65 : u64 cts;
66 : u32 width, height;
67 : GF_Fraction64 duration;
68 : Double start_range;
69 : Bool in_seek;
70 : u32 timescale;
71 : GF_Fraction cur_fps;
72 :
73 : u32 resume_from;
74 :
75 : char *buffer;
76 : u32 buf_size, alloc_size;
77 :
78 : //ivf header for now
79 : u32 file_hdr_size;
80 :
81 : Bool is_av1;
82 : Bool is_vp9;
83 : Bool is_vpX;
84 : u32 codecid;
85 : GF_VPConfig *vp_cfg;
86 :
87 : Bool is_playing;
88 : Bool is_file, file_loaded;
89 : Bool initial_play_done;
90 :
91 : GF_FilterPacket *src_pck;
92 :
93 : AV1Idx *indexes;
94 : u32 index_alloc_size, index_size;
95 :
96 : AV1State state;
97 : u32 dsi_crc;
98 :
99 : Bool pts_from_file;
100 : u64 cumulated_dur, last_pts;
101 : u32 bitrate;
102 : } GF_AV1DmxCtx;
103 :
104 :
105 87 : GF_Err av1dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
106 : {
107 : const GF_PropertyValue *p;
108 87 : GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);
109 :
110 87 : if (is_remove) {
111 0 : ctx->ipid = NULL;
112 0 : if (ctx->opid) {
113 0 : gf_filter_pid_remove(ctx->opid);
114 0 : ctx->opid = NULL;
115 : }
116 : return GF_OK;
117 : }
118 87 : if (! gf_filter_pid_check_caps(pid))
119 : return GF_NOT_SUPPORTED;
120 :
121 87 : ctx->ipid = pid;
122 87 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
123 87 : if (p) ctx->timescale = p->value.uint;
124 87 : ctx->state.mem_mode = GF_TRUE;
125 87 : if (ctx->timescale && !ctx->opid) {
126 0 : ctx->opid = gf_filter_pid_new(filter);
127 0 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
128 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
129 : }
130 87 : if (ctx->timescale) {
131 : //if we have a FPS prop, use it
132 0 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
133 0 : if (p) ctx->cur_fps = p->value.frac;
134 : }
135 : return GF_OK;
136 : }
137 :
138 21045 : GF_Err av1dmx_check_format(GF_Filter *filter, GF_AV1DmxCtx *ctx, GF_BitStream *bs, u32 *last_obu_end)
139 : {
140 : GF_Err e;
141 21045 : if (last_obu_end) (*last_obu_end) = 0;
142 : //probing av1 bs mode
143 21045 : if (ctx->bsmode != NOT_SET) return GF_OK;
144 :
145 :
146 87 : if (!ctx->state.config)
147 87 : ctx->state.config = gf_odf_av1_cfg_new();
148 :
149 87 : ctx->is_av1 = ctx->is_vp9 = ctx->is_vpX = GF_FALSE;
150 87 : ctx->codecid = 0;
151 87 : if (ctx->vp_cfg) gf_odf_vp_cfg_del(ctx->vp_cfg);
152 87 : ctx->vp_cfg = NULL;
153 87 : ctx->cur_fps = ctx->fps;
154 87 : if (!ctx->fps.num || !ctx->fps.den) {
155 87 : ctx->cur_fps.num = 25000;
156 87 : ctx->cur_fps.den = 1000;
157 : }
158 :
159 87 : ctx->pts_from_file = GF_FALSE;
160 87 : if (gf_media_probe_ivf(bs)) {
161 16 : u32 width = 0, height = 0;
162 16 : u32 codec_fourcc = 0, timebase_den = 0, timebase_num = 0, num_frames = 0;
163 16 : ctx->bsmode = IVF;
164 :
165 16 : e = gf_media_parse_ivf_file_header(bs, &width, &height, &codec_fourcc, &timebase_num, &timebase_den, &num_frames);
166 16 : if (e) return e;
167 :
168 16 : switch (codec_fourcc) {
169 6 : case GF_4CC('A', 'V', '0', '1'):
170 6 : ctx->is_av1 = GF_TRUE;
171 6 : ctx->codecid = GF_CODECID_AV1;
172 6 : break;
173 8 : case GF_4CC('V', 'P', '9', '0'):
174 8 : ctx->is_vp9 = GF_TRUE;
175 8 : ctx->codecid = GF_CODECID_VP9;
176 8 : ctx->vp_cfg = gf_odf_vp_cfg_new();
177 8 : break;
178 2 : case GF_4CC('V', 'P', '8', '0'):
179 2 : ctx->codecid = GF_CODECID_VP8;
180 2 : ctx->vp_cfg = gf_odf_vp_cfg_new();
181 2 : break;
182 0 : case GF_4CC('V', 'P', '1', '0'):
183 0 : ctx->codecid = GF_CODECID_VP10;
184 0 : ctx->vp_cfg = gf_odf_vp_cfg_new();
185 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF] %s parsing not implemented, import might be uncomplete or broken\n", gf_4cc_to_str(codec_fourcc) ));
186 : break;
187 0 : default:
188 0 : ctx->codecid = codec_fourcc;
189 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF] Unsupported codec FourCC %s\n", gf_4cc_to_str(codec_fourcc) ));
190 : return GF_NON_COMPLIANT_BITSTREAM;
191 : }
192 16 : if (ctx->vp_cfg && !ctx->is_vp9) {
193 2 : ctx->is_vpX = GF_TRUE;
194 2 : ctx->vp_cfg->profile = 1;
195 2 : ctx->vp_cfg->level = 10;
196 2 : ctx->vp_cfg->bit_depth = 8;
197 : //leave the rest as 0
198 : }
199 :
200 16 : ctx->state.width = ctx->state.width < width ? width : ctx->state.width;
201 16 : ctx->state.height = ctx->state.height < height ? height : ctx->state.height;
202 16 : ctx->state.tb_num = timebase_num;
203 16 : ctx->state.tb_den = timebase_den;
204 :
205 16 : if ((!ctx->fps.num || !ctx->fps.den) && ctx->state.tb_num && ctx->state.tb_den && ! ( (ctx->state.tb_num<=1) && (ctx->state.tb_den<=1) ) ) {
206 16 : ctx->cur_fps.num = ctx->state.tb_num;
207 16 : ctx->cur_fps.den = ctx->state.tb_den;
208 16 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[AV1Dmx] Detected IVF format FPS %d/%d\n", ctx->cur_fps.num, ctx->cur_fps.den));
209 16 : ctx->pts_from_file = GF_TRUE;
210 : } else {
211 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[AV1Dmx] Detected IVF format\n"));
212 : }
213 16 : ctx->file_hdr_size = (u32) gf_bs_get_position(bs);
214 16 : if (last_obu_end) (*last_obu_end) = (u32) gf_bs_get_position(bs);
215 : return GF_OK;
216 71 : } else if (gf_media_aom_probe_annexb(bs)) {
217 53 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[AV1Dmx] Detected Annex B format\n"));
218 53 : ctx->bsmode = AnnexB;
219 : } else {
220 18 : gf_bs_seek(bs, 0);
221 18 : e = aom_av1_parse_temporal_unit_from_section5(bs, &ctx->state);
222 18 : if (e && !gf_list_count(ctx->state.frame_state.frame_obus) ) {
223 0 : gf_filter_setup_failure(filter, e);
224 0 : ctx->bsmode = UNSUPPORTED;
225 0 : return e;
226 : }
227 18 : if (ctx->state.obu_type != OBU_TEMPORAL_DELIMITER) {
228 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[AV1Dmx] Error OBU stream start with %s, not a temporal delimiter - NOT SUPPORTED\n", gf_av1_get_obu_name(ctx->state.obu_type) ));
229 0 : gf_filter_setup_failure(filter, e);
230 0 : ctx->bsmode = UNSUPPORTED;
231 0 : return e;
232 : }
233 18 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[AV1Dmx] Detected OBUs Section 5 format\n"));
234 18 : ctx->bsmode = OBUs;
235 :
236 18 : gf_av1_reset_state(&ctx->state, GF_FALSE);
237 18 : gf_bs_seek(bs, 0);
238 : }
239 71 : ctx->is_av1 = GF_TRUE;
240 71 : ctx->state.unframed = GF_TRUE;
241 71 : ctx->codecid = GF_CODECID_AV1;
242 71 : return GF_OK;
243 : }
244 :
245 :
246 21033 : static void av1dmx_check_dur(GF_Filter *filter, GF_AV1DmxCtx *ctx)
247 : {
248 : FILE *stream;
249 : GF_Err e;
250 : GF_BitStream *bs;
251 : u64 duration, cur_dur, last_cdur, rate, max_pts, last_pts;
252 : AV1State av1state;
253 : const char *filepath=NULL;
254 : const GF_PropertyValue *p;
255 42058 : if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
256 :
257 87 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
258 87 : if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
259 :
260 87 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
261 87 : if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
262 0 : ctx->is_file = GF_FALSE;
263 0 : ctx->file_loaded = GF_TRUE;
264 : return;
265 : }
266 : filepath = p->value.string;
267 87 : ctx->is_file = GF_TRUE;
268 :
269 87 : if (ctx->index<0) {
270 8 : if (gf_opts_get_bool("temp", "force_indexing")) {
271 0 : ctx->index = 1.0;
272 : } else {
273 8 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
274 8 : if (!p || (p->value.longuint > 20000000)) {
275 0 : GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[AV1/VP9] Source file larger than 20M, skipping indexing\n"));
276 : } else {
277 8 : ctx->index = -ctx->index;
278 : }
279 : }
280 : }
281 87 : if (ctx->index<=0)
282 : return;
283 :
284 8 : stream = gf_fopen(filepath, "rb");
285 8 : if (!stream) return;
286 :
287 8 : ctx->index_size = 0;
288 :
289 8 : bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
290 :
291 8 : if (ctx->file_hdr_size) {
292 3 : gf_bs_seek(bs, ctx->file_hdr_size);
293 : }
294 8 : gf_av1_init_state(&av1state);
295 8 : av1state.skip_frames = GF_TRUE;
296 8 : av1state.config = gf_odf_av1_cfg_new();
297 :
298 : max_pts = last_pts = 0;
299 : duration = 0;
300 : cur_dur = last_cdur = 0;
301 1478 : while (gf_bs_available(bs)) {
302 : Bool is_sap=GF_FALSE;
303 1470 : u64 pts = GF_FILTER_NO_TS;
304 1470 : u64 frame_start = gf_bs_get_position(bs);
305 1470 : gf_av1_reset_state(&av1state, GF_FALSE);
306 :
307 : /*we process each TU and extract only the necessary OBUs*/
308 1470 : switch (ctx->bsmode) {
309 870 : case OBUs:
310 870 : e = aom_av1_parse_temporal_unit_from_section5(bs, &av1state);
311 : break;
312 0 : case AnnexB:
313 0 : e = aom_av1_parse_temporal_unit_from_annexb(bs, &av1state);
314 : break;
315 600 : case IVF:
316 600 : if (ctx->is_av1) {
317 0 : e = aom_av1_parse_temporal_unit_from_ivf(bs, &av1state);
318 : } else {
319 : u64 frame_size;
320 600 : e = gf_media_parse_ivf_frame_header(bs, &frame_size, &pts);
321 600 : if (!e) gf_bs_skip_bytes(bs, frame_size);
322 : is_sap = GF_TRUE;
323 : }
324 : break;
325 : default:
326 : e = GF_NOT_SUPPORTED;
327 : }
328 1470 : if (e)
329 : break;
330 :
331 1470 : if (pts != GF_FILTER_NO_TS) {
332 600 : if (pts + max_pts < last_pts) {
333 0 : max_pts = last_pts + ctx->cur_fps.den;
334 : }
335 600 : pts += max_pts;
336 : duration = pts;
337 600 : cur_dur = pts - last_cdur;
338 :
339 : last_pts = pts;
340 : } else {
341 870 : duration += ctx->cur_fps.den;
342 870 : cur_dur += ctx->cur_fps.den;
343 : }
344 1470 : if (av1state.frame_state.key_frame)
345 : is_sap = GF_TRUE;
346 :
347 : //only index at I-frame start
348 1470 : if (frame_start && is_sap && (cur_dur > ctx->index * ctx->cur_fps.num) ) {
349 447 : if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
350 444 : else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
351 447 : ctx->indexes = gf_realloc(ctx->indexes, sizeof(AV1Idx)*ctx->index_alloc_size);
352 447 : ctx->indexes[ctx->index_size].pos = frame_start;
353 447 : ctx->indexes[ctx->index_size].duration = (Double) duration;
354 447 : ctx->indexes[ctx->index_size].duration /= ctx->cur_fps.num;
355 447 : ctx->index_size ++;
356 : last_cdur = cur_dur;
357 : cur_dur = 0;
358 : }
359 : }
360 8 : rate = gf_bs_get_position(bs);
361 8 : gf_bs_del(bs);
362 8 : gf_fclose(stream);
363 8 : gf_odf_av1_cfg_del(av1state.config);
364 8 : gf_av1_reset_state(&av1state, GF_TRUE);
365 :
366 8 : if (!ctx->duration.num || (ctx->duration.num * ctx->cur_fps.num != duration * ctx->duration.den)) {
367 8 : ctx->duration.num = (s32) duration;
368 8 : ctx->duration.den = ctx->cur_fps.num;
369 :
370 8 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
371 :
372 8 : if (duration && (!gf_sys_is_test_mode() || gf_opts_get_bool("temp", "force_indexing"))) {
373 0 : rate *= 8 * ctx->duration.den;
374 0 : rate /= ctx->duration.num;
375 0 : ctx->bitrate = (u32) rate;
376 : }
377 : }
378 :
379 : //currently not supported because of OBU size field rewrite - could work on some streams but we would
380 : //need to analyse all OBUs in the stream for that
381 8 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_FALSE) );
382 : }
383 :
384 :
385 21138 : static Bool av1dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
386 : {
387 : u32 i;
388 : u64 file_pos = 0;
389 : GF_FilterEvent fevt;
390 21138 : GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);
391 :
392 21138 : switch (evt->base.type) {
393 87 : case GF_FEVT_PLAY:
394 87 : if (!ctx->is_playing) {
395 87 : ctx->is_playing = GF_TRUE;
396 87 : ctx->cts = 0;
397 : }
398 87 : if (! ctx->is_file) {
399 0 : ctx->buf_size = 0;
400 0 : return GF_FALSE;
401 : }
402 87 : ctx->start_range = evt->play.start_range;
403 87 : ctx->in_seek = GF_TRUE;
404 :
405 87 : if (ctx->start_range) {
406 :
407 0 : if (ctx->index<0) {
408 0 : ctx->index = -ctx->index;
409 0 : ctx->file_loaded = GF_FALSE;
410 0 : ctx->duration.den = ctx->duration.num = 0;
411 0 : GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[AV1/VP9Demx] Play request from %d, building index\n", ctx->start_range));
412 0 : av1dmx_check_dur(filter, ctx);
413 : }
414 :
415 0 : for (i=1; i<ctx->index_size; i++) {
416 0 : if (ctx->indexes[i].duration>ctx->start_range) {
417 0 : ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->cur_fps.num);
418 0 : file_pos = ctx->indexes[i-1].pos;
419 0 : break;
420 : }
421 : }
422 : }
423 87 : if (!ctx->initial_play_done) {
424 87 : ctx->initial_play_done = GF_TRUE;
425 : //seek will not change the current source state, don't send a seek
426 87 : if (!file_pos)
427 : return GF_TRUE;
428 : }
429 0 : ctx->buf_size = 0;
430 0 : if (!file_pos)
431 0 : file_pos = ctx->file_hdr_size;
432 :
433 : //post a seek
434 0 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
435 0 : fevt.seek.start_offset = file_pos;
436 0 : gf_filter_pid_send_event(ctx->ipid, &fevt);
437 :
438 : //cancel event
439 0 : return GF_TRUE;
440 :
441 12 : case GF_FEVT_STOP:
442 : //don't cancel event
443 12 : ctx->is_playing = GF_FALSE;
444 12 : return GF_FALSE;
445 :
446 : case GF_FEVT_SET_SPEED:
447 : //cancel event
448 : return GF_TRUE;
449 : default:
450 : break;
451 : }
452 : //by default don't cancel event - to rework once we have downloading in place
453 21039 : return GF_FALSE;
454 : }
455 :
456 : static GFINLINE void av1dmx_update_cts(GF_AV1DmxCtx *ctx)
457 : {
458 : assert(ctx->cur_fps.num);
459 : assert(ctx->cur_fps.den);
460 :
461 38684 : if (ctx->timescale) {
462 0 : u64 inc = ctx->cur_fps.den;
463 0 : inc *= ctx->timescale;
464 0 : inc /= ctx->cur_fps.num;
465 0 : ctx->cts += inc;
466 : } else {
467 38684 : ctx->cts += ctx->cur_fps.den;
468 : }
469 : }
470 :
471 59147 : static void av1dmx_check_pid(GF_Filter *filter, GF_AV1DmxCtx *ctx)
472 : {
473 : u8 *dsi;
474 : u32 dsi_size, crc;
475 :
476 : //no config or no config change
477 118207 : if (ctx->is_av1 && !gf_list_count(ctx->state.frame_state.header_obus)) return;
478 :
479 1768 : if (!ctx->opid) {
480 87 : ctx->opid = gf_filter_pid_new(filter);
481 87 : av1dmx_check_dur(filter, ctx);
482 : }
483 1768 : dsi = NULL;
484 1768 : dsi_size = 0;
485 :
486 1768 : if (ctx->vp_cfg) {
487 1376 : gf_odf_vp_cfg_write(ctx->vp_cfg, &dsi, &dsi_size, ctx->vp_cfg->codec_initdata_size ? GF_TRUE : GF_FALSE);
488 392 : } else if (ctx->is_av1) {
489 : //first or config changed, compute dsi
490 707 : while (gf_list_count(ctx->state.config->obu_array)) {
491 315 : GF_AV1_OBUArrayEntry *a = (GF_AV1_OBUArrayEntry*) gf_list_pop_back(ctx->state.config->obu_array);
492 315 : if (a->obu) gf_free(a->obu);
493 315 : gf_free(a);
494 : }
495 392 : dsi = NULL;
496 392 : dsi_size = 0;
497 1176 : while (gf_list_count(ctx->state.frame_state.header_obus)) {
498 392 : GF_AV1_OBUArrayEntry *a = (GF_AV1_OBUArrayEntry*) gf_list_get(ctx->state.frame_state.header_obus, 0);
499 392 : gf_list_add(ctx->state.config->obu_array, a);
500 392 : gf_list_rem(ctx->state.frame_state.header_obus, 0);
501 : }
502 392 : gf_odf_av1_cfg_write(ctx->state.config, &dsi, &dsi_size);
503 :
504 392 : if ((!ctx->fps.num || !ctx->fps.den) && ctx->state.tb_num && ctx->state.tb_den && ! ( (ctx->state.tb_num<=1) && (ctx->state.tb_den<=1) ) ) {
505 310 : ctx->cur_fps.num = ctx->state.tb_num;
506 310 : ctx->cur_fps.den = ctx->state.tb_den;
507 : }
508 :
509 : }
510 1768 : crc = gf_crc_32(dsi, dsi_size);
511 :
512 1768 : if (crc == ctx->dsi_crc) {
513 1681 : gf_free(dsi);
514 1681 : return;
515 : }
516 87 : ctx->dsi_crc = crc;
517 :
518 : //copy properties at init or reconfig
519 87 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
520 87 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT(GF_STREAM_VISUAL));
521 :
522 87 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(ctx->codecid));
523 :
524 87 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->cur_fps.num));
525 87 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, & PROP_FRAC(ctx->cur_fps));
526 87 : if (ctx->state.sequence_width && ctx->state.sequence_height) {
527 77 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT(ctx->state.sequence_width));
528 77 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT(ctx->state.sequence_height));
529 : } else {
530 10 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT(ctx->state.width));
531 10 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT(ctx->state.height));
532 : }
533 :
534 87 : if (ctx->duration.num)
535 8 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
536 :
537 87 : if (ctx->bitrate) {
538 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
539 : }
540 :
541 87 : if (dsi && dsi_size)
542 87 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(dsi, dsi_size));
543 :
544 87 : if (ctx->is_file && ctx->index) {
545 8 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
546 : }
547 :
548 87 : if (ctx->is_av1) {
549 77 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_PRIMARIES, & PROP_UINT(ctx->state.color_primaries) );
550 77 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_TRANSFER, & PROP_UINT(ctx->state.transfer_characteristics) );
551 77 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_MX, & PROP_UINT(ctx->state.matrix_coefficients) );
552 77 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_RANGE, & PROP_BOOL(ctx->state.color_range) );
553 : }
554 : //disabled for the time being, matchin `colr` box will be injected by mp43mx if needed
555 : //check vpX specs to see if always needed
556 : #if 0
557 : else if (ctx->vp_cfg) {
558 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_PRIMARIES, & PROP_UINT(ctx->vp_cfg->colour_primaries) );
559 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_TRANSFER, & PROP_UINT(ctx->vp_cfg->transfer_characteristics) );
560 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_MX, & PROP_UINT(ctx->vp_cfg->matrix_coefficients) );
561 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_RANGE, & PROP_BOOL(ctx->vp_cfg->video_fullRange_flag) );
562 : }
563 : #endif
564 : }
565 :
566 60 : GF_Err av1dmx_parse_ivf(GF_Filter *filter, GF_AV1DmxCtx *ctx)
567 : {
568 : GF_Err e;
569 : u32 pck_size;
570 60 : u64 frame_size = 0, pts = GF_FILTER_NO_TS;
571 : GF_FilterPacket *pck;
572 : u64 pos, pos_ivf_hdr;
573 : u8 *output;
574 :
575 60 : pos_ivf_hdr = gf_bs_get_position(ctx->bs);
576 60 : e = gf_media_parse_ivf_frame_header(ctx->bs, &frame_size, &pts);
577 60 : if (e) return e;
578 :
579 60 : pos = gf_bs_get_position(ctx->bs);
580 60 : if (gf_bs_available(ctx->bs) < frame_size) {
581 0 : gf_bs_seek(ctx->bs, pos_ivf_hdr);
582 0 : return GF_EOS;
583 : }
584 :
585 60 : if (ctx->pts_from_file) {
586 60 : pts += ctx->cumulated_dur;
587 60 : if (ctx->last_pts && (ctx->last_pts>pts)) {
588 0 : pts -= ctx->cumulated_dur;
589 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF/AV1] Corrupted timestamp "LLU" less than previous timestamp "LLU", assuming concatenation\n", pts, ctx->last_pts));
590 0 : ctx->cumulated_dur = ctx->last_pts + ctx->cur_fps.den;
591 0 : ctx->cumulated_dur -= pts;
592 0 : pts = ctx->cumulated_dur;
593 : }
594 60 : ctx->last_pts = pts;
595 : }
596 :
597 :
598 : //check pid state
599 60 : av1dmx_check_pid(filter, ctx);
600 :
601 60 : if (!ctx->opid) {
602 : return GF_OK;
603 : }
604 :
605 60 : if (!ctx->is_playing) {
606 2 : gf_bs_seek(ctx->bs, pos_ivf_hdr);
607 2 : return GF_EOS;
608 : }
609 :
610 58 : pck_size = (u32)frame_size;
611 58 : pck = gf_filter_pck_new_alloc(ctx->opid, pck_size, &output);
612 58 : if (!pck) {
613 0 : gf_bs_seek(ctx->bs, pos_ivf_hdr);
614 0 : return GF_OUT_OF_MEM;
615 : }
616 58 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, pck);
617 :
618 58 : if (ctx->pts_from_file) {
619 58 : gf_filter_pck_set_cts(pck, pts);
620 : } else {
621 0 : gf_filter_pck_set_cts(pck, ctx->cts);
622 : }
623 :
624 58 : gf_bs_seek(ctx->bs, pos);
625 58 : gf_bs_read_data(ctx->bs, output, pck_size);
626 :
627 58 : if (output[0] & 0x80)
628 32 : gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
629 : else
630 26 : gf_filter_pck_set_sap(pck, GF_FILTER_SAP_NONE);
631 :
632 58 : gf_filter_pck_send(pck);
633 :
634 : av1dmx_update_cts(ctx);
635 : return GF_OK;
636 : }
637 :
638 1833 : GF_Err av1dmx_parse_vp9(GF_Filter *filter, GF_AV1DmxCtx *ctx)
639 : {
640 1833 : Bool key_frame = GF_FALSE;
641 1833 : u64 frame_size = 0, pts = 0;
642 : u64 pos, pos_ivf_hdr;
643 1833 : u32 width = 0, height = 0, renderWidth, renderHeight;
644 1833 : u32 num_frames_in_superframe = 0, superframe_index_size = 0, i = 0;
645 : u32 frame_sizes[VP9_MAX_FRAMES_IN_SUPERFRAME];
646 : u8 *output;
647 : GF_Err e;
648 :
649 1833 : pos_ivf_hdr = gf_bs_get_position(ctx->bs);
650 1833 : e = gf_media_parse_ivf_frame_header(ctx->bs, &frame_size, &pts);
651 1833 : if (e) return e;
652 1833 : if (!frame_size) {
653 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[IVF/VP9] Corrupted frame header !\n"));
654 : return GF_NON_COMPLIANT_BITSTREAM;
655 : }
656 :
657 1833 : pos = gf_bs_get_position(ctx->bs);
658 1833 : if (gf_bs_available(ctx->bs) < frame_size) {
659 517 : gf_bs_seek(ctx->bs, pos_ivf_hdr);
660 517 : return GF_EOS;
661 : }
662 :
663 1316 : if (ctx->pts_from_file) {
664 1316 : pts += ctx->cumulated_dur;
665 1316 : if (ctx->last_pts && (ctx->last_pts>pts)) {
666 0 : pts -= ctx->cumulated_dur;
667 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF/VP9] Corrupted timestamp "LLU" less than previous timestamp "LLU", assuming concatenation\n", pts, ctx->last_pts));
668 0 : ctx->cumulated_dur = ctx->last_pts + ctx->cur_fps.den;
669 0 : ctx->cumulated_dur -= pts;
670 0 : pts = ctx->cumulated_dur;
671 : }
672 1316 : ctx->last_pts = pts;
673 : }
674 :
675 : /*check if it is a superframe*/
676 1316 : e = gf_media_vp9_parse_superframe(ctx->bs, frame_size, &num_frames_in_superframe, frame_sizes, &superframe_index_size);
677 1316 : if (e) {
678 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VP9Dmx] Error parsing superframe structure\n"));
679 : return e;
680 : }
681 :
682 1316 : for (i = 0; i < num_frames_in_superframe; ++i) {
683 1316 : u64 pos2 = gf_bs_get_position(ctx->bs);
684 1316 : if (gf_media_vp9_parse_sample(ctx->bs, ctx->vp_cfg, &key_frame, &width, &height, &renderWidth, &renderHeight) != GF_OK) {
685 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VP9Dmx] Error parsing frame\n"));
686 : return e;
687 : }
688 1316 : e = gf_bs_seek(ctx->bs, pos2 + frame_sizes[i]);
689 1316 : if (e) {
690 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VP9Dmx] Seek bad param (offset "LLU") (1)", pos2 + frame_sizes[i]));
691 : return e;
692 : }
693 : }
694 1316 : if (gf_bs_get_position(ctx->bs) + superframe_index_size != pos + frame_size) {
695 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[VP9Dmx] Inconsistent IVF frame size of "LLU" bytes.\n", frame_size));
696 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, (" Detected %d frames (+ %d bytes for the superframe index):\n", num_frames_in_superframe, superframe_index_size));
697 0 : for (i = 0; i < num_frames_in_superframe; ++i) {
698 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, (" superframe %d, size is %u bytes\n", i, frame_sizes[i]));
699 : }
700 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("\n"));
701 : }
702 1316 : e = gf_bs_seek(ctx->bs, pos + frame_size);
703 1316 : if (e) {
704 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[VP9Dmx] Seek bad param (offset "LLU") (2)", pos + frame_size));
705 : return e;
706 : }
707 :
708 1316 : u32 pck_size = (u32)(gf_bs_get_position(ctx->bs) - pos);
709 : assert(pck_size == frame_size);
710 :
711 : //check pid state
712 1316 : av1dmx_check_pid(filter, ctx);
713 :
714 1316 : if (!ctx->opid) {
715 : return GF_OK;
716 : }
717 :
718 1316 : if (!ctx->is_playing) {
719 8 : gf_bs_seek(ctx->bs, pos_ivf_hdr);
720 8 : return GF_EOS;
721 : }
722 :
723 1308 : GF_FilterPacket *pck = gf_filter_pck_new_alloc(ctx->opid, pck_size, &output);
724 1308 : if (!pck) {
725 0 : gf_bs_seek(ctx->bs, pos_ivf_hdr);
726 0 : return GF_OUT_OF_MEM;
727 : }
728 1308 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, pck);
729 :
730 1308 : if (ctx->pts_from_file) {
731 1308 : gf_filter_pck_set_cts(pck, pts);
732 : } else {
733 0 : gf_filter_pck_set_cts(pck, ctx->cts);
734 : }
735 :
736 :
737 1308 : if (key_frame) {
738 41 : gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
739 : }
740 :
741 1308 : if (ctx->deps) {
742 : u8 flags = 0;
743 : //dependsOn
744 0 : flags = (key_frame) ? 2 : 1;
745 : flags <<= 2;
746 : //dependedOn
747 : //flags |= 2;
748 0 : flags <<= 2;
749 : //hasRedundant
750 : //flags |= ctx->has_redundant ? 1 : 2;
751 0 : gf_filter_pck_set_dependency_flags(pck, flags);
752 : }
753 :
754 1308 : gf_bs_seek(ctx->bs, pos);
755 1308 : gf_bs_read_data(ctx->bs, output, pck_size);
756 1308 : gf_filter_pck_send(pck);
757 :
758 : av1dmx_update_cts(ctx);
759 : return GF_OK;
760 : }
761 :
762 37318 : static GF_Err av1dmx_parse_flush_sample(GF_Filter *filter, GF_AV1DmxCtx *ctx)
763 : {
764 : u32 pck_size;
765 : GF_FilterPacket *pck;
766 : u8 *output;
767 :
768 37318 : if (!ctx->opid)
769 : return GF_NON_COMPLIANT_BITSTREAM;
770 :
771 37318 : gf_bs_get_content_no_truncate(ctx->state.bs, &ctx->state.frame_obus, &pck_size, &ctx->state.frame_obus_alloc);
772 :
773 37318 : if (!pck_size) {
774 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[AV1Dmx] no frame OBU, skipping OBU\n"));
775 : return GF_OK;
776 : }
777 :
778 37318 : pck = gf_filter_pck_new_alloc(ctx->opid, pck_size, &output);
779 37318 : if (!pck) return GF_OUT_OF_MEM;
780 :
781 37318 : if (ctx->src_pck)
782 0 : gf_filter_pck_merge_properties(ctx->src_pck, pck);
783 :
784 37318 : gf_filter_pck_set_cts(pck, ctx->cts);
785 37318 : gf_filter_pck_set_sap(pck, ctx->state.frame_state.key_frame ? GF_FILTER_SAP_1 : 0);
786 :
787 37318 : memcpy(output, ctx->state.frame_obus, pck_size);
788 :
789 37318 : if (ctx->deps) {
790 : u8 flags = 0;
791 : //dependsOn
792 0 : flags = ( ctx->state.frame_state.key_frame) ? 2 : 1;
793 0 : flags <<= 2;
794 : //dependedOn
795 0 : flags |= ctx->state.frame_state.refresh_frame_flags ? 1 : 2;
796 0 : flags <<= 2;
797 : //hasRedundant
798 : //flags |= ctx->has_redundant ? 1 : 2;
799 0 : gf_filter_pck_set_dependency_flags(pck, flags);
800 : }
801 :
802 37318 : gf_filter_pck_send(pck);
803 :
804 : av1dmx_update_cts(ctx);
805 37318 : gf_av1_reset_state(&ctx->state, GF_FALSE);
806 :
807 : return GF_OK;
808 :
809 : }
810 57771 : GF_Err av1dmx_parse_av1(GF_Filter *filter, GF_AV1DmxCtx *ctx)
811 : {
812 : GF_Err e = GF_OK;
813 : u64 start;
814 :
815 57771 : if (!ctx->is_playing) {
816 95 : ctx->state.frame_state.is_first_frame = GF_TRUE;
817 : }
818 :
819 : /*we process each TU and extract only the necessary OBUs*/
820 57771 : start = gf_bs_get_position(ctx->bs);
821 57771 : switch (ctx->bsmode) {
822 1477 : case OBUs:
823 : //first frame loaded !
824 1477 : if (ctx->state.bs && gf_bs_get_position(ctx->state.bs) && (ctx->state.obu_type == OBU_TEMPORAL_DELIMITER)) {
825 : e = GF_OK;
826 : } else {
827 1461 : e = aom_av1_parse_temporal_unit_from_section5(ctx->bs, &ctx->state);
828 : }
829 : break;
830 61 : case AnnexB:
831 : //first TU loaded !
832 61 : if (ctx->state.bs && gf_bs_get_position(ctx->state.bs)) {
833 : e = GF_OK;
834 : } else {
835 59 : e = aom_av1_parse_temporal_unit_from_annexb(ctx->bs, &ctx->state);
836 59 : if (e==GF_BUFFER_TOO_SMALL) {
837 0 : gf_av1_reset_state(&ctx->state, GF_FALSE);
838 0 : gf_bs_seek(ctx->bs, start);
839 : }
840 : }
841 : break;
842 56233 : case IVF:
843 : //first frame loaded !
844 56233 : if (ctx->state.bs && gf_bs_get_position(ctx->state.bs)) {
845 : e = GF_OK;
846 : } else {
847 56227 : e = aom_av1_parse_temporal_unit_from_ivf(ctx->bs, &ctx->state);
848 : }
849 : break;
850 : default:
851 : e = GF_NOT_SUPPORTED;
852 : }
853 :
854 : //check pid state
855 57771 : av1dmx_check_pid(filter, ctx);
856 :
857 57771 : if (e) return e;
858 :
859 :
860 37345 : if (!ctx->opid) {
861 18 : if (ctx->state.obu_type != OBU_TEMPORAL_DELIMITER) {
862 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[AV1Dmx] output pid not configured (no sequence header yet ?), skipping OBU\n"));
863 : }
864 18 : gf_av1_reset_state(&ctx->state, GF_FALSE);
865 18 : return GF_OK;
866 : }
867 :
868 37327 : if (!ctx->is_playing) {
869 : //don't reset state we would skip seq header obu in first frame
870 : //gf_av1_reset_state(&ctx->state, GF_FALSE);
871 : return GF_OK;
872 : }
873 :
874 37252 : return av1dmx_parse_flush_sample(filter, ctx);
875 :
876 : }
877 :
878 : GF_Err gf_bs_set_logger(GF_BitStream *bs, void (*on_bs_log)(void *udta, const char *field_name, u32 nb_bits, u64 field_val, s32 idx1, s32 idx2, s32 idx3), void *udta);
879 0 : static void av1dmx_bs_log(void *udta, const char *field_name, u32 nb_bits, u64 field_val, s32 idx1, s32 idx2, s32 idx3)
880 : {
881 : GF_AV1DmxCtx *ctx = (GF_AV1DmxCtx *) udta;
882 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, (" %s", field_name));
883 0 : if (idx1>=0) {
884 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("_%d", idx1));
885 0 : if (idx2>=0) {
886 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("_%d", idx2));
887 0 : if (idx3>=0) {
888 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("_%d", idx3));
889 : }
890 : }
891 : }
892 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("=\""LLD, field_val));
893 0 : if ((ctx->bsdbg==2) && ((s32) nb_bits > 1) )
894 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("(%u)", nb_bits));
895 :
896 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("\" "));
897 0 : }
898 :
899 21045 : GF_Err av1dmx_process_buffer(GF_Filter *filter, GF_AV1DmxCtx *ctx, const char *data, u32 data_size, Bool is_copy)
900 : {
901 21045 : u32 last_obu_end = 0;
902 : GF_Err e = GF_OK;
903 :
904 21045 : if (!ctx->bs) ctx->bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
905 20958 : else gf_bs_reassign_buffer(ctx->bs, data, data_size);
906 :
907 : #ifndef GPAC_DISABLE_LOG
908 21045 : if (ctx->bsdbg && gf_log_tool_level_on(GF_LOG_PARSER, GF_LOG_DEBUG))
909 0 : gf_bs_set_logger(ctx->bs, av1dmx_bs_log, ctx);
910 : #endif
911 :
912 : //check ivf vs obu vs annexB
913 21045 : e = av1dmx_check_format(filter, ctx, ctx->bs, &last_obu_end);
914 21045 : if (e) return e;
915 :
916 59681 : while (gf_bs_available(ctx->bs)) {
917 :
918 59664 : if (ctx->is_vp9) {
919 1833 : e = av1dmx_parse_vp9(filter, ctx);
920 57831 : } else if (ctx->is_av1) {
921 57771 : e = av1dmx_parse_av1(filter, ctx);
922 : } else {
923 60 : e = av1dmx_parse_ivf(filter, ctx);
924 : }
925 :
926 59664 : if (e!=GF_EOS)
927 38788 : last_obu_end = (u32) gf_bs_get_position(ctx->bs);
928 :
929 59664 : if (e) {
930 : break;
931 : }
932 38711 : if (!ctx->is_playing && ctx->opid)
933 : break;
934 : }
935 :
936 21045 : if (is_copy && last_obu_end) {
937 : assert(ctx->buf_size>=last_obu_end);
938 10879 : memmove(ctx->buffer, ctx->buffer+last_obu_end, sizeof(char) * (ctx->buf_size-last_obu_end));
939 10879 : ctx->buf_size -= last_obu_end;
940 : }
941 21045 : if (e==GF_EOS) return GF_OK;
942 169 : if (e==GF_BUFFER_TOO_SMALL) return GF_OK;
943 92 : return e;
944 : }
945 :
946 21238 : GF_Err av1dmx_process(GF_Filter *filter)
947 : {
948 : GF_Err e;
949 21238 : GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);
950 : GF_FilterPacket *pck;
951 : char *data;
952 : u32 pck_size;
953 :
954 21238 : if (ctx->bsmode == UNSUPPORTED) return GF_EOS;
955 :
956 : //always reparse duration
957 21238 : if (!ctx->duration.num)
958 20946 : av1dmx_check_dur(filter, ctx);
959 :
960 21238 : if (!ctx->is_playing && ctx->opid)
961 : return GF_OK;
962 :
963 21113 : pck = gf_filter_pid_get_packet(ctx->ipid);
964 21113 : if (!pck) {
965 80 : if (gf_filter_pid_is_eos(ctx->ipid)) {
966 : //flush
967 91 : while (ctx->buf_size) {
968 : u32 buf_size = ctx->buf_size;
969 12 : e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
970 12 : if (e) break;
971 12 : if (buf_size == ctx->buf_size) {
972 : break;
973 : }
974 : }
975 80 : if (ctx->state.bs && gf_bs_get_position(ctx->state.bs))
976 66 : av1dmx_parse_flush_sample(filter, ctx);
977 :
978 80 : ctx->buf_size = 0;
979 80 : if (ctx->opid)
980 80 : gf_filter_pid_set_eos(ctx->opid);
981 80 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
982 80 : ctx->src_pck = NULL;
983 80 : return GF_EOS;
984 : }
985 : return GF_OK;
986 : }
987 :
988 21033 : if (ctx->opid) {
989 20938 : if (!ctx->is_playing || gf_filter_pid_would_block(ctx->opid))
990 : return GF_OK;
991 : }
992 :
993 21033 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
994 :
995 : //input pid sets some timescale - we flushed pending data , update cts
996 21033 : if (ctx->timescale) {
997 : Bool start, end;
998 : u64 cts;
999 :
1000 : e = GF_OK;
1001 :
1002 0 : gf_filter_pck_get_framing(pck, &start, &end);
1003 : //middle or end of frame, reaggregation
1004 0 : if (!start) {
1005 0 : if (ctx->alloc_size < ctx->buf_size + pck_size) {
1006 0 : ctx->alloc_size = ctx->buf_size + pck_size;
1007 0 : ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
1008 : }
1009 0 : memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
1010 0 : ctx->buf_size += pck_size;
1011 :
1012 : //end of frame, process av1
1013 0 : if (end) {
1014 0 : e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
1015 : }
1016 0 : ctx->buf_size=0;
1017 0 : gf_filter_pid_drop_packet(ctx->ipid);
1018 0 : return e;
1019 : }
1020 : //flush of pending frame (might have lost something)
1021 0 : if (ctx->buf_size) {
1022 0 : e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
1023 0 : ctx->buf_size = 0;
1024 0 : if (e) return e;
1025 : }
1026 :
1027 : //beginning of a new frame
1028 0 : cts = gf_filter_pck_get_cts(pck);
1029 0 : if (cts != GF_FILTER_NO_TS)
1030 0 : ctx->cts = cts;
1031 0 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
1032 0 : ctx->src_pck = pck;
1033 0 : gf_filter_pck_ref_props(&ctx->src_pck);
1034 0 : ctx->buf_size = 0;
1035 :
1036 0 : if (!end) {
1037 0 : if (ctx->alloc_size < ctx->buf_size + pck_size) {
1038 0 : ctx->alloc_size = ctx->buf_size + pck_size;
1039 0 : ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
1040 : }
1041 0 : memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
1042 0 : ctx->buf_size += pck_size;
1043 0 : gf_filter_pid_drop_packet(ctx->ipid);
1044 0 : return GF_OK;
1045 : }
1046 : assert(start && end);
1047 : //process
1048 0 : e = av1dmx_process_buffer(filter, ctx, data, pck_size, GF_FALSE);
1049 :
1050 0 : gf_filter_pid_drop_packet(ctx->ipid);
1051 0 : return e;
1052 : }
1053 :
1054 : //not from framed stream, copy buffer
1055 21033 : if (ctx->alloc_size < ctx->buf_size + pck_size) {
1056 166 : ctx->alloc_size = ctx->buf_size + pck_size;
1057 166 : ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
1058 : }
1059 21033 : memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
1060 21033 : ctx->buf_size += pck_size;
1061 21033 : e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
1062 21033 : gf_filter_pid_drop_packet(ctx->ipid);
1063 21033 : return e;
1064 : }
1065 :
1066 87 : static void av1dmx_finalize(GF_Filter *filter)
1067 : {
1068 87 : GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);
1069 87 : if (ctx->bs) gf_bs_del(ctx->bs);
1070 87 : if (ctx->indexes) gf_free(ctx->indexes);
1071 :
1072 87 : gf_av1_reset_state(&ctx->state, GF_TRUE);
1073 87 : if (ctx->state.config) gf_odf_av1_cfg_del(ctx->state.config);
1074 87 : if (ctx->state.bs) gf_bs_del(ctx->state.bs);
1075 87 : if (ctx->state.frame_obus) gf_free(ctx->state.frame_obus);
1076 87 : if (ctx->buffer) gf_free(ctx->buffer);
1077 :
1078 87 : if (ctx->vp_cfg) gf_odf_vp_cfg_del(ctx->vp_cfg);
1079 87 : }
1080 :
1081 3065 : static const char * av1dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
1082 : {
1083 3065 : GF_BitStream *bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
1084 : Bool res;
1085 : u32 lt;
1086 : const char *mime = "video/av1";
1087 3065 : lt = gf_log_get_tool_level(GF_LOG_CODING);
1088 3065 : gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_QUIET);
1089 :
1090 3065 : res = gf_media_probe_ivf(bs);
1091 3065 : if (res) {
1092 16 : *score = GF_FPROBE_SUPPORTED;
1093 : mime = "video/x-ivf";
1094 : } else {
1095 3049 : res = gf_media_aom_probe_annexb(bs);
1096 3049 : if (res) {
1097 53 : *score = GF_FPROBE_SUPPORTED;
1098 : } else {
1099 : AV1State state;
1100 : GF_Err e;
1101 : u32 nb_units = 0;
1102 :
1103 2996 : gf_av1_init_state(&state);
1104 2996 : state.config = gf_odf_av1_cfg_new();
1105 6032 : while (gf_bs_available(bs)) {
1106 3036 : e = aom_av1_parse_temporal_unit_from_section5(bs, &state);
1107 3036 : if ((e==GF_OK) || (nb_units && (e==GF_BUFFER_TOO_SMALL) ) ) {
1108 60 : if (!nb_units || gf_list_count(state.frame_state.header_obus) || gf_list_count(state.frame_state.frame_obus)) {
1109 58 : nb_units++;
1110 58 : if (e==GF_BUFFER_TOO_SMALL)
1111 2 : nb_units++;
1112 : } else {
1113 : break;
1114 : }
1115 : } else {
1116 : break;
1117 : }
1118 58 : gf_av1_reset_state(&state, GF_FALSE);
1119 58 : if (nb_units>2) {
1120 : res = GF_TRUE;
1121 18 : *score = GF_FPROBE_SUPPORTED;
1122 18 : break;
1123 : }
1124 : }
1125 2996 : gf_odf_av1_cfg_del(state.config);
1126 2996 : gf_av1_reset_state(&state, GF_TRUE);
1127 : }
1128 : }
1129 :
1130 3065 : gf_log_set_tool_level(GF_LOG_CODING, lt);
1131 :
1132 3065 : gf_bs_del(bs);
1133 3065 : if (res) return mime;
1134 2978 : return NULL;
1135 : }
1136 :
1137 : static const GF_FilterCapability AV1DmxCaps[] =
1138 : {
1139 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
1140 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "ivf|obu|av1b|av1"),
1141 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/x-ivf|video/av1"),
1142 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1143 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AV1),
1144 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_VP8),
1145 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_VP9),
1146 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_VP10),
1147 : CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
1148 : {0},
1149 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
1150 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AV1),
1151 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP8),
1152 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP9),
1153 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_VP10),
1154 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
1155 : };
1156 :
1157 : #define OFFS(_n) #_n, offsetof(GF_AV1DmxCtx, _n)
1158 : static const GF_FilterArgs AV1DmxArgs[] =
1159 : {
1160 : { OFFS(fps), "import frame rate (0 default to FPS from bitstream or 25 Hz)", GF_PROP_FRACTION, "0/1000", NULL, 0},
1161 : { OFFS(index), "indexing window length. If 0, bitstream is not probed for duration. A negative value skips the indexing if the source file is larger than 100M (slows down importers) unless a play with start range > 0 is issued, otherwise uses the positive value", GF_PROP_DOUBLE, "-1.0", NULL, 0},
1162 :
1163 : { OFFS(importer), "compatibility with old importer", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
1164 : { OFFS(deps), "import samples dependencies information", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
1165 :
1166 : { OFFS(bsdbg), "debug NAL parsing in parser@debug logs\n"
1167 : "- off: not enabled\n"
1168 : "- on: enabled\n"
1169 : "- full: enable with number of bits dumped", GF_PROP_UINT, "off", "off|on|full", GF_FS_ARG_HINT_EXPERT},
1170 : {0}
1171 : };
1172 :
1173 :
1174 : GF_FilterRegister AV1DmxRegister = {
1175 : .name = "rfav1",
1176 : GF_FS_SET_DESCRIPTION("AV1/IVF/VP9 reframer")
1177 : GF_FS_SET_HELP("This filter parses AV1 OBU, AV1 AnnexB or IVF with AV1 or VP9 files/data and outputs corresponding visual PID and frames.")
1178 : .private_size = sizeof(GF_AV1DmxCtx),
1179 : .args = AV1DmxArgs,
1180 : .finalize = av1dmx_finalize,
1181 : SETCAPS(AV1DmxCaps),
1182 : .configure_pid = av1dmx_configure_pid,
1183 : .process = av1dmx_process,
1184 : .probe_data = av1dmx_probe_data,
1185 : .process_event = av1dmx_process_event
1186 : };
1187 :
1188 :
1189 2877 : const GF_FilterRegister *av1dmx_register(GF_FilterSession *session)
1190 : {
1191 2877 : return &AV1DmxRegister;
1192 : }
1193 :
1194 : #else
1195 : const GF_FilterRegister *av1dmx_register(GF_FilterSession *session)
1196 : {
1197 : return NULL;
1198 : }
1199 : #endif // GPAC_DISABLE_AV_PARSERS
1200 :
|