Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2019-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / ProRes 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 : //filter args
36 : GF_Fraction fps;
37 : Bool findex;
38 : char *cid;
39 :
40 : //only one input pid declared
41 : GF_FilterPid *ipid;
42 : //only one output pid declared
43 : GF_FilterPid *opid;
44 :
45 : GF_BitStream *bs;
46 : u64 cts;
47 : GF_Fraction64 duration;
48 : u64 file_size, file_pos;
49 : Double start_range;
50 : Bool rewind;
51 : u32 cur_frame;
52 : u32 timescale;
53 : GF_Fraction cur_fps;
54 :
55 : u8 *buffer;
56 : u32 buf_size, alloc_size;
57 :
58 : GF_ProResFrameInfo cur_cfg;
59 :
60 : Bool is_playing;
61 : Bool is_file, file_loaded;
62 : Bool initial_play_done;
63 :
64 : //when source is not a file/pipe/net stream
65 : GF_FilterPacket *src_pck;
66 :
67 : /*frame index 0/NULL if findex is not set*/
68 : u32 nb_frames;
69 : u32 *frame_sizes;
70 :
71 : u32 bitrate;
72 : } GF_ProResDmxCtx;
73 :
74 :
75 2 : GF_Err proresdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
76 : {
77 : const GF_PropertyValue *p;
78 2 : GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
79 :
80 2 : if (is_remove) {
81 0 : ctx->ipid = NULL;
82 0 : if (ctx->opid) {
83 0 : gf_filter_pid_remove(ctx->opid);
84 0 : ctx->opid = NULL;
85 : }
86 : return GF_OK;
87 : }
88 2 : if (! gf_filter_pid_check_caps(pid))
89 : return GF_NOT_SUPPORTED;
90 :
91 2 : ctx->ipid = pid;
92 2 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
93 2 : if (p) ctx->timescale = p->value.uint;
94 :
95 2 : if (ctx->timescale && !ctx->opid) {
96 0 : ctx->opid = gf_filter_pid_new(filter);
97 0 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
98 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
99 : }
100 2 : if (ctx->timescale) {
101 : //if we have a FPS prop, use it
102 0 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
103 0 : if (p) ctx->cur_fps = p->value.frac;
104 : }
105 : return GF_OK;
106 : }
107 :
108 :
109 2 : static void proresdmx_check_dur(GF_Filter *filter, GF_ProResDmxCtx *ctx)
110 : {
111 : FILE *stream;
112 : GF_BitStream *bs;
113 : u64 duration, rate;
114 : u32 idx_size;
115 : const char *filepath=NULL;
116 : const GF_PropertyValue *p;
117 2 : if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;
118 :
119 2 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
120 2 : if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;
121 :
122 2 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
123 2 : if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
124 0 : ctx->is_file = GF_FALSE;
125 0 : ctx->file_loaded = GF_TRUE;
126 : return;
127 : }
128 : filepath = p->value.string;
129 2 : ctx->is_file = GF_TRUE;
130 :
131 2 : if (ctx->findex==1) {
132 2 : if (gf_opts_get_bool("temp", "force_indexing")) {
133 0 : ctx->findex = 2;
134 : } else {
135 2 : p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
136 2 : if (!p || (p->value.longuint > 100000000)) {
137 0 : GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[ProResDmx] Source file larger than 100M, skipping indexing\n"));
138 : } else {
139 2 : ctx->findex = 2;
140 : }
141 : }
142 : }
143 2 : if (!ctx->findex)
144 : return;
145 :
146 2 : stream = gf_fopen(filepath, "rb");
147 2 : if (!stream) return;
148 :
149 2 : bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);
150 :
151 2 : idx_size = ctx->nb_frames;
152 2 : ctx->nb_frames = 0;
153 2 : ctx->file_size = gf_bs_available(bs);
154 :
155 : duration = 0;
156 64 : while (gf_bs_available(bs)) {
157 62 : u64 frame_start = gf_bs_get_position(bs);
158 62 : u32 fsize = gf_bs_read_u32(bs);
159 62 : u32 fmark = gf_bs_read_u32(bs);
160 62 : gf_bs_seek(bs, frame_start + fsize);
161 62 : if (fmark != GF_4CC('i','c','p','f'))
162 : break;
163 :
164 62 : duration += ctx->cur_fps.den;
165 :
166 62 : if (!idx_size) idx_size = 10;
167 60 : else if (idx_size == ctx->nb_frames) idx_size += 10;
168 62 : ctx->frame_sizes = gf_realloc(ctx->frame_sizes, sizeof(u32)*idx_size);
169 62 : ctx->frame_sizes[ctx->nb_frames] = fsize;
170 62 : ctx->nb_frames++;
171 : }
172 2 : rate = gf_bs_get_position(bs);
173 2 : gf_bs_del(bs);
174 2 : gf_fclose(stream);
175 :
176 2 : if (!ctx->duration.num || (ctx->duration.num * ctx->cur_fps.num != duration * ctx->duration.den)) {
177 2 : ctx->duration.num = (s32) duration;
178 2 : ctx->duration.den = ctx->cur_fps.num;
179 :
180 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
181 :
182 2 : if (duration && (!gf_sys_is_test_mode() || gf_opts_get_bool("temp", "force_indexing"))) {
183 0 : rate *= 8 * ctx->duration.den;
184 0 : rate /= ctx->duration.num;
185 0 : ctx->bitrate = (u32) rate;
186 : }
187 : }
188 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_TRUE) );
189 : }
190 :
191 :
192 3110 : static Bool proresdmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
193 : {
194 : u32 i;
195 : u64 file_pos = 0;
196 : GF_FilterEvent fevt;
197 3110 : GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
198 :
199 3110 : switch (evt->base.type) {
200 2 : case GF_FEVT_PLAY:
201 2 : if (!ctx->is_playing) {
202 2 : ctx->is_playing = GF_TRUE;
203 2 : ctx->cts = 0;
204 : }
205 2 : if (! ctx->is_file) {
206 0 : ctx->buf_size = 0;
207 0 : return GF_FALSE;
208 : }
209 2 : ctx->start_range = evt->play.start_range;
210 :
211 2 : if (ctx->start_range) {
212 1 : ctx->cur_frame = 0;
213 :
214 1 : if (ctx->findex==1) {
215 0 : ctx->findex = 2;
216 0 : ctx->file_loaded = GF_FALSE;
217 0 : ctx->duration.den = ctx->duration.num = 0;
218 0 : GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[ProResDmx] Play request from %d, building index\n", ctx->start_range));
219 0 : proresdmx_check_dur(filter, ctx);
220 : }
221 1 : if ((evt->play.speed<0) && (ctx->start_range<0)) {
222 0 : ctx->start_range = (Double) ctx->duration.num;
223 0 : ctx->start_range /= ctx->duration.den;
224 : }
225 :
226 31 : for (i=0; i<ctx->nb_frames; i++) {
227 31 : Double t = ctx->cur_frame * ctx->cur_fps.den / ctx->cur_fps.num;
228 31 : ctx->cts = ctx->cur_frame * ctx->cur_fps.den;
229 31 : if (t>=ctx->start_range) {
230 : break;
231 : }
232 31 : if (i+1==ctx->nb_frames)
233 : break;
234 30 : ctx->cur_frame++;
235 30 : file_pos += ctx->frame_sizes[i];
236 : }
237 : }
238 :
239 2 : ctx->rewind = (ctx->nb_frames && (evt->play.speed<0)) ? GF_TRUE : GF_FALSE;
240 :
241 2 : if (!ctx->initial_play_done) {
242 2 : ctx->initial_play_done = GF_TRUE;
243 : //seek will not change the current source state, don't send a seek
244 2 : if (!file_pos)
245 : return GF_TRUE;
246 : }
247 1 : ctx->buf_size = 0;
248 1 : ctx->file_pos = file_pos;
249 :
250 : //post a seek
251 1 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
252 1 : fevt.seek.start_offset = file_pos;
253 1 : gf_filter_pid_send_event(ctx->ipid, &fevt);
254 :
255 : //cancel event
256 1 : return GF_TRUE;
257 :
258 0 : case GF_FEVT_STOP:
259 : //don't cancel event
260 0 : ctx->is_playing = GF_FALSE;
261 0 : return GF_FALSE;
262 :
263 : case GF_FEVT_SET_SPEED:
264 : //cancel event
265 : return GF_TRUE;
266 : default:
267 : break;
268 : }
269 : //by default don't cancel event - to rework once we have downloading in place
270 3108 : return GF_FALSE;
271 : }
272 :
273 : static GFINLINE void proresdmx_update_cts(GF_ProResDmxCtx *ctx)
274 : {
275 : u64 inc;
276 : assert(ctx->cur_fps.num);
277 : assert(ctx->cur_fps.den);
278 :
279 61 : if (ctx->timescale) {
280 0 : inc = ctx->cur_fps.den;
281 0 : inc *= ctx->timescale;
282 0 : inc /= ctx->cur_fps.num;
283 : } else {
284 61 : inc = ctx->cur_fps.den;
285 : }
286 61 : if (ctx->rewind)
287 30 : ctx->cts -= inc;
288 : else
289 31 : ctx->cts += inc;
290 : }
291 :
292 3135 : static void proresdmx_check_pid(GF_Filter *filter, GF_ProResDmxCtx *ctx, GF_ProResFrameInfo *finfo)
293 : {
294 : Bool same_cfg = GF_TRUE;
295 : u32 codec_id;
296 : u64 bitrate;
297 : GF_Fraction fps;
298 :
299 : #define CHECK_CFG(_name) if (ctx->cur_cfg._name!=finfo->_name) same_cfg = GF_FALSE;
300 :
301 3135 : CHECK_CFG(width)
302 3135 : CHECK_CFG(height)
303 3135 : CHECK_CFG(chroma_format)
304 3135 : CHECK_CFG(interlaced_mode)
305 3135 : CHECK_CFG(aspect_ratio_information)
306 3135 : CHECK_CFG(framerate_code)
307 3135 : CHECK_CFG(color_primaries)
308 3135 : CHECK_CFG(transfer_characteristics)
309 3135 : CHECK_CFG(matrix_coefficients)
310 3135 : CHECK_CFG(alpha_channel_type)
311 :
312 : #undef CHECK_CFG
313 :
314 3135 : if (same_cfg) return;
315 : fps.num = fps.den = 0;
316 : switch (finfo->framerate_code) {
317 : case 1: fps.num = 24000; fps.den = 1001; break;
318 : case 2: fps.num = 24; fps.den = 1; break;
319 : case 3: fps.num = 24; fps.den = 1; break;
320 : case 4: fps.num = 30000; fps.den = 1001; break;
321 : case 5: fps.num = 30; fps.den = 1; break;
322 : case 6: fps.num = 50; fps.den = 1; break;
323 : case 7: fps.num = 60000; fps.den = 1001; break;
324 : case 8: fps.num = 60; fps.den = 1; break;
325 : case 9: fps.num = 100; fps.den = 1; break;
326 : case 10: fps.num = 120000; fps.den = 1001; break;
327 : case 11: fps.num = 120; fps.den = 1; break;
328 : }
329 :
330 2 : ctx->cur_fps = ctx->fps;
331 2 : if (!ctx->fps.num || !ctx->fps.den) {
332 2 : if (fps.num && fps.den) {
333 0 : ctx->cur_fps = fps;
334 : } else {
335 2 : ctx->cur_fps.num = 25000;
336 2 : ctx->cur_fps.den = 1000;
337 : }
338 : }
339 :
340 2 : if (!ctx->opid) {
341 2 : ctx->opid = gf_filter_pid_new(filter);
342 2 : proresdmx_check_dur(filter, ctx);
343 : }
344 :
345 : bitrate = 0;
346 2 : if (ctx->nb_frames && ctx->file_size && ctx->cur_fps.den) {
347 2 : bitrate = ctx->file_size * 8;
348 2 : bitrate *= ctx->cur_fps.num;
349 2 : bitrate /= ctx->nb_frames * ctx->cur_fps.den;
350 : }
351 2 : memcpy(&ctx->cur_cfg, finfo, sizeof(GF_ProResFrameInfo));
352 2 : if (ctx->cid && (strlen(ctx->cid)>4)) {
353 0 : codec_id = GF_4CC(ctx->cid[0],ctx->cid[1],ctx->cid[2],ctx->cid[3]);
354 2 : } else if (finfo->chroma_format==3) {
355 : codec_id = GF_CODECID_AP4H;
356 : } else {
357 : codec_id = GF_CODECID_APCH;
358 : }
359 :
360 : //copy properties at init or reconfig
361 2 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
362 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT(GF_STREAM_VISUAL));
363 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(codec_id));
364 :
365 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->cur_fps.num));
366 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, & PROP_FRAC(ctx->cur_fps));
367 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT(finfo->width));
368 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT(finfo->height));
369 2 : switch (finfo->alpha_channel_type) {
370 0 : case 1:
371 : case 2:
372 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ALPHA, & PROP_BOOL(GF_TRUE));
373 0 : break;
374 2 : default:
375 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ALPHA, NULL);
376 2 : break;
377 : }
378 :
379 2 : switch (finfo->aspect_ratio_information) {
380 2 : case 0:
381 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, NULL);
382 2 : break;
383 0 : case 1:
384 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(1, 1) );
385 0 : break;
386 0 : case 2:
387 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(4, 3) );
388 0 : break;
389 0 : case 3:
390 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, & PROP_FRAC_INT(16, 9) );
391 0 : break;
392 0 : default:
393 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, NULL);
394 0 : break;
395 : }
396 :
397 2 : if (ctx->duration.num)
398 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));
399 :
400 2 : if (ctx->bitrate) {
401 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
402 : }
403 :
404 : /*prores is all intra, we support rewind*/
405 2 : if (ctx->is_file && ctx->findex) {
406 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_REWIND) );
407 : }
408 2 : if (bitrate && !gf_sys_is_test_mode())
409 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT((u32)bitrate) );
410 :
411 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_PRIMARIES, & PROP_UINT(finfo->color_primaries) );
412 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_TRANSFER, & PROP_UINT(finfo->transfer_characteristics) );
413 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_MX, & PROP_UINT(finfo->matrix_coefficients) );
414 :
415 : //set interlaced or remove interlaced property
416 2 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_INTERLACED, ctx->cur_cfg.interlaced_mode ? & PROP_UINT(GF_TRUE) : NULL);
417 : }
418 :
419 :
420 :
421 3108 : GF_Err proresdmx_process_buffer(GF_Filter *filter, GF_ProResDmxCtx *ctx, const u8 *data, u32 data_size, Bool is_copy)
422 : {
423 : u32 last_frame_end = 0;
424 : GF_Err e = GF_OK;
425 :
426 3108 : if (!ctx->bs) ctx->bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
427 3106 : else gf_bs_reassign_buffer(ctx->bs, data, data_size);
428 :
429 3139 : while (gf_bs_available(ctx->bs)) {
430 : u8 *output;
431 : GF_FilterPacket *pck;
432 : GF_ProResFrameInfo finfo;
433 3138 : e = gf_media_prores_parse_bs(ctx->bs, &finfo);
434 :
435 3138 : if (e) {
436 : break;
437 : }
438 3135 : proresdmx_check_pid(filter, ctx, &finfo);
439 :
440 3135 : if (!ctx->is_playing && ctx->opid)
441 : break;
442 :
443 3133 : if (gf_bs_available(ctx->bs)<finfo.frame_size)
444 : break;
445 :
446 61 : pck = gf_filter_pck_new_alloc(ctx->opid, finfo.frame_size, &output);
447 61 : if (!pck) break;
448 61 : gf_bs_read_data(ctx->bs, output, finfo.frame_size);
449 :
450 61 : if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, pck);
451 :
452 61 : gf_filter_pck_set_dts(pck, ctx->cts);
453 61 : gf_filter_pck_set_cts(pck, ctx->cts);
454 61 : gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
455 61 : gf_filter_pck_set_byte_offset(pck, ctx->file_pos);
456 :
457 61 : gf_filter_pck_send(pck);
458 : proresdmx_update_cts(ctx);
459 61 : last_frame_end = (u32) gf_bs_get_position(ctx->bs);
460 :
461 61 : if (ctx->rewind) {
462 30 : ctx->buf_size = 0;
463 : last_frame_end = 0;
464 : assert(ctx->cur_frame);
465 30 : ctx->cur_frame--;
466 30 : if (!ctx->cur_frame) {
467 1 : if (ctx->opid)
468 1 : gf_filter_pid_set_eos(ctx->opid);
469 : } else {
470 : GF_FilterEvent fevt;
471 29 : ctx->file_pos -= ctx->frame_sizes[ctx->cur_frame];
472 : //post a seek
473 29 : GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
474 29 : fevt.seek.start_offset = ctx->file_pos;
475 29 : gf_filter_pid_send_event(ctx->ipid, &fevt);
476 : }
477 : break;
478 : } else {
479 31 : ctx->file_pos += finfo.frame_size;
480 : }
481 : }
482 :
483 3108 : if (is_copy && last_frame_end) {
484 : assert(ctx->buf_size >= last_frame_end);
485 31 : memmove(ctx->buffer, ctx->buffer+last_frame_end, sizeof(char) * (ctx->buf_size-last_frame_end));
486 31 : ctx->buf_size -= last_frame_end;
487 : }
488 3108 : if (e==GF_EOS) return GF_OK;
489 3108 : if (e==GF_BUFFER_TOO_SMALL) return GF_OK;
490 3105 : return e;
491 : }
492 :
493 3145 : GF_Err proresdmx_process(GF_Filter *filter)
494 : {
495 : GF_Err e;
496 3145 : GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
497 : GF_FilterPacket *pck;
498 : char *data;
499 : u32 pck_size;
500 :
501 3145 : if (!ctx->is_playing && ctx->opid)
502 : return GF_OK;
503 :
504 3141 : if (ctx->rewind && !ctx->cur_frame) {
505 0 : gf_filter_pid_set_discard(ctx->ipid, GF_TRUE);
506 0 : return GF_OK;
507 : }
508 :
509 3141 : pck = gf_filter_pid_get_packet(ctx->ipid);
510 3141 : if (!pck) {
511 33 : if (gf_filter_pid_is_eos(ctx->ipid)) {
512 : //flush
513 1 : while (ctx->buf_size) {
514 : u32 buf_size = ctx->buf_size;
515 0 : e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
516 0 : if (e) break;
517 0 : if (buf_size == ctx->buf_size) {
518 : break;
519 : }
520 : }
521 :
522 1 : ctx->buf_size = 0;
523 1 : if (ctx->opid)
524 1 : gf_filter_pid_set_eos(ctx->opid);
525 1 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
526 1 : ctx->src_pck = NULL;
527 1 : return GF_EOS;
528 : }
529 : return GF_OK;
530 : }
531 :
532 3108 : if (ctx->opid) {
533 3106 : if (!ctx->is_playing || gf_filter_pid_would_block(ctx->opid))
534 : return GF_OK;
535 : }
536 :
537 3108 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
538 :
539 : //input pid sets some timescale - we flushed pending data , update cts
540 3108 : if (ctx->timescale) {
541 : Bool start, end;
542 : u64 cts;
543 :
544 : e = GF_OK;
545 :
546 0 : gf_filter_pck_get_framing(pck, &start, &end);
547 : //middle or end of frame, reaggregation
548 0 : if (!start) {
549 0 : if (ctx->alloc_size < ctx->buf_size + pck_size) {
550 0 : ctx->alloc_size = ctx->buf_size + pck_size;
551 0 : ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
552 : }
553 0 : memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
554 0 : ctx->buf_size += pck_size;
555 :
556 : //end of frame, process av1
557 0 : if (end) {
558 0 : e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
559 : }
560 0 : ctx->buf_size=0;
561 0 : gf_filter_pid_drop_packet(ctx->ipid);
562 0 : return e;
563 : }
564 : //flush of pending frame (might have lost something)
565 0 : if (ctx->buf_size) {
566 0 : e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
567 0 : ctx->buf_size = 0;
568 0 : if (e) return e;
569 : }
570 :
571 : //beginning of a new frame
572 0 : cts = gf_filter_pck_get_cts(pck);
573 0 : if (cts != GF_FILTER_NO_TS)
574 0 : ctx->cts = cts;
575 0 : if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
576 0 : ctx->src_pck = pck;
577 0 : gf_filter_pck_ref_props(&ctx->src_pck);
578 0 : ctx->buf_size = 0;
579 :
580 0 : if (!end) {
581 0 : if (ctx->alloc_size < ctx->buf_size + pck_size) {
582 0 : ctx->alloc_size = ctx->buf_size + pck_size;
583 0 : ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
584 : }
585 0 : memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
586 0 : ctx->buf_size += pck_size;
587 0 : gf_filter_pid_drop_packet(ctx->ipid);
588 0 : return GF_OK;
589 : }
590 : assert(start && end);
591 : //process
592 0 : e = proresdmx_process_buffer(filter, ctx, data, pck_size, GF_FALSE);
593 :
594 0 : gf_filter_pid_drop_packet(ctx->ipid);
595 0 : return e;
596 : }
597 :
598 : //not from framed stream, copy buffer
599 3108 : if (ctx->alloc_size < ctx->buf_size + pck_size) {
600 115 : ctx->alloc_size = ctx->buf_size + pck_size;
601 115 : ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
602 : }
603 3108 : memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
604 3108 : ctx->buf_size += pck_size;
605 3108 : e = proresdmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
606 3108 : gf_filter_pid_drop_packet(ctx->ipid);
607 3108 : return e;
608 : }
609 :
610 2 : static void proresdmx_finalize(GF_Filter *filter)
611 : {
612 2 : GF_ProResDmxCtx *ctx = gf_filter_get_udta(filter);
613 2 : if (ctx->bs) gf_bs_del(ctx->bs);
614 2 : if (ctx->frame_sizes) gf_free(ctx->frame_sizes);
615 2 : if (ctx->buffer) gf_free(ctx->buffer);
616 2 : }
617 :
618 3065 : static const char * proresdmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
619 : {
620 3065 : if (size<8) return NULL;
621 :
622 3063 : if ((data[4] == 'i') && (data[5] == 'c') && (data[6] == 'p') && (data[7] == 'f')) {
623 2 : *score = GF_FPROBE_SUPPORTED;
624 2 : return "video/prores";
625 : }
626 : return NULL;
627 : }
628 :
629 : static const GF_FilterCapability ProResDmxCaps[] =
630 : {
631 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
632 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_FILE_EXT, "prores"),
633 : CAP_STRING(GF_CAPS_INPUT, GF_PROP_PID_MIME, "video/prores"),
634 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
635 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCN),
636 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCO),
637 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCH),
638 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_APCS),
639 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AP4X),
640 : CAP_UINT(GF_CAPS_OUTPUT_STATIC, GF_PROP_PID_CODECID, GF_CODECID_AP4H),
641 : CAP_BOOL(GF_CAPS_OUTPUT_STATIC_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
642 : {0},
643 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
644 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCN),
645 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCO),
646 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCH),
647 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_APCS),
648 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4X),
649 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4H),
650 : CAP_BOOL(GF_CAPS_INPUT,GF_PROP_PID_UNFRAMED, GF_TRUE),
651 : };
652 :
653 : #define OFFS(_n) #_n, offsetof(GF_ProResDmxCtx, _n)
654 : static const GF_FilterArgs ProResDmxArgs[] =
655 : {
656 : { OFFS(fps), "import frame rate (0 default to FPS from bitstream or 25 Hz)", GF_PROP_FRACTION, "0/1000", NULL, 0},
657 : { OFFS(findex), "index frames. If true, filter will be able to work in rewind mode", GF_PROP_BOOL, "true", NULL, 0},
658 :
659 : { OFFS(cid), "set QT 4CC for the imported media. If not set, defaults to 'ap4h' for YUV444 or 'apch' for YUV422", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
660 : {0}
661 : };
662 :
663 :
664 : GF_FilterRegister ProResDmxRegister = {
665 : .name = "rfprores",
666 : GF_FS_SET_DESCRIPTION("ProRes reframer")
667 : GF_FS_SET_HELP("This filter parses ProRes raw files/data and outputs corresponding visual PID and frames.")
668 : .private_size = sizeof(GF_ProResDmxCtx),
669 : .args = ProResDmxArgs,
670 : .finalize = proresdmx_finalize,
671 : SETCAPS(ProResDmxCaps),
672 : .configure_pid = proresdmx_configure_pid,
673 : .process = proresdmx_process,
674 : .probe_data = proresdmx_probe_data,
675 : .process_event = proresdmx_process_event
676 : };
677 :
678 :
679 2877 : const GF_FilterRegister *proresdmx_register(GF_FilterSession *session)
680 : {
681 2877 : return &ProResDmxRegister;
682 : }
683 :
684 : #else
685 : const GF_FilterRegister *proresdmx_register(GF_FilterSession *session)
686 : {
687 : return NULL;
688 : }
689 : #endif // GPAC_DISABLE_AV_PARSERS
690 :
|