Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2020-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / compressed bitstream metadata rewrite 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/internal/media_dev.h>
29 : #include <gpac/mpeg4_odf.h>
30 :
31 : typedef struct _bsrw_pid_ctx BSRWPid;
32 : typedef struct _bsrw_ctx GF_BSRWCtx;
33 :
34 : struct _bsrw_pid_ctx
35 : {
36 : GF_FilterPid *ipid, *opid;
37 : u32 codec_id;
38 : Bool reconfigure;
39 : GF_Err (*rewrite_pid_config)(GF_BSRWCtx *ctx, BSRWPid *pctx);
40 : GF_Err (*rewrite_packet)(GF_BSRWCtx *ctx, BSRWPid *pctx, GF_FilterPacket *pck);
41 :
42 : s32 prev_cprim, prev_ctfc, prev_cmx, prev_sar;
43 :
44 : u32 nalu_size_length;
45 :
46 : GF_VUIInfo vui;
47 : Bool rewrite_vui;
48 : };
49 :
50 : struct _bsrw_ctx
51 : {
52 : GF_Fraction sar;
53 : s32 m4vpl, prof, lev, pcomp, pidc, pspace, gpcflags;
54 : s32 cprim, ctfc, cmx, vidfmt;
55 : Bool rmsei, fullrange, novsi;
56 :
57 : GF_List *pids;
58 : Bool reconfigure;
59 : };
60 :
61 1273 : static GF_Err none_rewrite_packet(GF_BSRWCtx *ctx, BSRWPid *pctx, GF_FilterPacket *pck)
62 : {
63 1273 : return gf_filter_pck_forward(pck, pctx->opid);
64 : }
65 :
66 2 : static GF_Err m4v_rewrite_pid_config(GF_BSRWCtx *ctx, BSRWPid *pctx)
67 : {
68 : GF_Err e;
69 : u8 *dsi;
70 : u32 dsi_size;
71 : const GF_PropertyValue *prop;
72 :
73 2 : prop = gf_filter_pid_get_property(pctx->ipid, GF_PROP_PID_DECODER_CONFIG);
74 2 : if (!prop) return GF_OK;
75 :
76 2 : pctx->reconfigure = GF_FALSE;
77 :
78 :
79 2 : dsi_size = prop->value.data.size;
80 2 : dsi = gf_malloc(sizeof(u8) * dsi_size);
81 2 : memcpy(dsi, prop->value.data.ptr, sizeof(u8) * dsi_size);
82 :
83 2 : if (ctx->sar.num && ctx->sar.den) {
84 2 : e = gf_m4v_rewrite_par(&dsi, &dsi_size, ctx->sar.num, ctx->sar.den);
85 2 : if (e) {
86 0 : gf_free(dsi);
87 0 : return e;
88 : }
89 2 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_SAR, &PROP_FRAC(ctx->sar) );
90 : }
91 2 : if (ctx->m4vpl>=0) {
92 2 : gf_m4v_rewrite_pl(&dsi, &dsi_size, (u32) ctx->m4vpl);
93 2 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_PROFILE_LEVEL, &PROP_UINT(ctx->m4vpl) );
94 : }
95 :
96 2 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_size) );
97 :
98 2 : return GF_OK;
99 : }
100 :
101 0 : static GF_Err avc_rewrite_packet(GF_BSRWCtx *ctx, BSRWPid *pctx, GF_FilterPacket *pck)
102 : {
103 : u32 size, pck_size, final_size;
104 : GF_FilterPacket *dst;
105 : u8 *output;
106 0 : const u8 *data = gf_filter_pck_get_data(pck, &pck_size);
107 0 : if (!data)
108 0 : return gf_filter_pck_forward(pck, pctx->opid);
109 :
110 : final_size = 0;
111 : size=0;
112 0 : while (size<pck_size) {
113 : u8 nal_type=0;
114 0 : u32 nal_hdr = pctx->nalu_size_length;
115 : u32 nal_size = 0;
116 0 : while (nal_hdr) {
117 0 : nal_size |= data[size];
118 0 : size++;
119 0 : nal_hdr--;
120 0 : if (!nal_hdr) break;
121 0 : nal_size<<=8;
122 : }
123 0 : nal_type = data[size];
124 0 : nal_type = nal_type & 0x1F;
125 0 : if (nal_type != GF_AVC_NALU_SEI) {
126 0 : final_size += nal_size+pctx->nalu_size_length;
127 : }
128 0 : size += nal_size;
129 : }
130 0 : if (final_size == pck_size)
131 0 : return gf_filter_pck_forward(pck, pctx->opid);
132 :
133 0 : dst = gf_filter_pck_new_alloc(pctx->opid, final_size, &output);
134 0 : if (!dst) return GF_OUT_OF_MEM;
135 :
136 0 : gf_filter_pck_merge_properties(pck, dst);
137 :
138 : size=0;
139 0 : while (size<pck_size) {
140 : u8 nal_type=0;
141 0 : u32 nal_hdr = pctx->nalu_size_length;
142 : u32 nal_size = 0;
143 0 : while (nal_hdr) {
144 0 : nal_size |= data[size];
145 0 : size++;
146 0 : nal_hdr--;
147 0 : if (!nal_hdr) break;
148 0 : nal_size<<=8;
149 : }
150 0 : nal_type = data[size];
151 0 : nal_type = nal_type & 0x1F;
152 0 : if (nal_type == GF_AVC_NALU_SEI) {
153 0 : size += nal_size;
154 0 : continue;
155 : }
156 0 : memcpy(output, &data[size-pctx->nalu_size_length], pctx->nalu_size_length+nal_size);
157 0 : output += pctx->nalu_size_length+nal_size;
158 0 : size += nal_size;
159 : }
160 0 : return gf_filter_pck_send(dst);
161 : }
162 :
163 4 : static void update_props(BSRWPid *pctx, GF_VUIInfo *vui)
164 : {
165 4 : if ((vui->ar_num>0) && (vui->ar_den>0))
166 4 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_SAR, &PROP_FRAC_INT(vui->ar_num, vui->ar_den) );
167 :
168 4 : if (vui->fullrange>0)
169 0 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_COLR_RANGE, &PROP_BOOL(vui->fullrange) );
170 :
171 4 : if (!vui->remove_video_info) {
172 4 : if (vui->color_prim>=0)
173 0 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_COLR_PRIMARIES, &PROP_UINT(vui->color_prim) );
174 4 : if (vui->color_tfc>=0)
175 0 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_COLR_TRANSFER, &PROP_UINT(vui->color_tfc) );
176 4 : if (vui->color_matrix>=0)
177 0 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_COLR_PRIMARIES, &PROP_UINT(vui->color_matrix) );
178 : }
179 4 : }
180 :
181 6 : static GF_Err avc_rewrite_pid_config(GF_BSRWCtx *ctx, BSRWPid *pctx)
182 : {
183 : GF_AVCConfig *avcc;
184 : GF_Err e = GF_OK;
185 : u8 *dsi;
186 : u32 dsi_size;
187 : const GF_PropertyValue *prop;
188 :
189 6 : prop = gf_filter_pid_get_property(pctx->ipid, GF_PROP_PID_DECODER_CONFIG);
190 6 : if (!prop) return GF_OK;
191 6 : pctx->reconfigure = GF_FALSE;
192 :
193 6 : avcc = gf_odf_avc_cfg_read(prop->value.data.ptr, prop->value.data.size);
194 :
195 6 : if (pctx->rewrite_vui) {
196 2 : GF_VUIInfo tmp_vui = pctx->vui;
197 2 : tmp_vui.update = GF_TRUE;
198 2 : e = gf_avc_change_vui(avcc, &tmp_vui);
199 2 : if (!e) {
200 2 : update_props(pctx, &tmp_vui);
201 : }
202 : }
203 :
204 6 : if ((ctx->lev>=0) || (ctx->prof>=0) || (ctx->pcomp>=0)) {
205 2 : u32 i, count = gf_list_count(avcc->sequenceParameterSets);
206 4 : for (i=0; i<count; i++) {
207 2 : GF_NALUFFParam *sps = gf_list_get(avcc->sequenceParameterSets, i);
208 : //first byte is nalu header, then profile_idc (8bits), prof_comp (8bits), and level_idc (8bits)
209 2 : if (ctx->prof>=0) {
210 2 : sps->data[1] = (u8) ctx->prof;
211 : }
212 2 : if (ctx->pcomp>=0) {
213 2 : sps->data[2] = (u8) ctx->pcomp;
214 : }
215 2 : if (ctx->lev>=0) {
216 2 : sps->data[3] = (u8) ctx->lev;
217 : }
218 : }
219 2 : if (ctx->lev>=0) avcc->AVCLevelIndication = ctx->lev;
220 2 : if (ctx->prof>=0) avcc->AVCProfileIndication = ctx->prof;
221 2 : if (ctx->pcomp>=0) avcc->profile_compatibility = ctx->pcomp;
222 : }
223 :
224 6 : gf_odf_avc_cfg_write(avcc, &dsi, &dsi_size);
225 6 : pctx->nalu_size_length = avcc->nal_unit_size;
226 :
227 6 : gf_odf_avc_cfg_del(avcc);
228 6 : if (e) return e;
229 :
230 6 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_size) );
231 :
232 6 : if (ctx->rmsei) {
233 0 : pctx->rewrite_packet = avc_rewrite_packet;
234 : } else {
235 6 : pctx->rewrite_packet = none_rewrite_packet;
236 : }
237 : return GF_OK;
238 : }
239 :
240 : #ifndef GPAC_DISABLE_HEVC
241 :
242 0 : static GF_Err hevc_rewrite_packet(GF_BSRWCtx *ctx, BSRWPid *pctx, GF_FilterPacket *pck)
243 : {
244 : u32 size, pck_size, final_size;
245 : GF_FilterPacket *dst;
246 : u8 *output;
247 0 : const u8 *data = gf_filter_pck_get_data(pck, &pck_size);
248 0 : if (!data)
249 0 : return gf_filter_pck_forward(pck, pctx->opid);
250 :
251 : final_size = 0;
252 : size=0;
253 0 : while (size<pck_size) {
254 : u8 nal_type=0;
255 0 : u32 nal_hdr = pctx->nalu_size_length;
256 : u32 nal_size = 0;
257 0 : while (nal_hdr) {
258 0 : nal_size |= data[size];
259 0 : size++;
260 0 : nal_hdr--;
261 0 : if (!nal_hdr) break;
262 0 : nal_size<<=8;
263 : }
264 0 : nal_type = data[size];
265 0 : nal_type = (nal_type & 0x7E) >> 1;
266 0 : if ((nal_type != GF_HEVC_NALU_SEI_PREFIX) && (nal_type != GF_HEVC_NALU_SEI_SUFFIX) ) {
267 0 : final_size += nal_size+pctx->nalu_size_length;
268 : }
269 0 : size += nal_size;
270 : }
271 0 : if (final_size == pck_size)
272 0 : return gf_filter_pck_forward(pck, pctx->opid);
273 :
274 0 : dst = gf_filter_pck_new_alloc(pctx->opid, final_size, &output);
275 0 : if (!dst) return GF_OUT_OF_MEM;
276 :
277 0 : gf_filter_pck_merge_properties(pck, dst);
278 :
279 : size=0;
280 0 : while (size<pck_size) {
281 : u8 nal_type=0;
282 0 : u32 nal_hdr = pctx->nalu_size_length;
283 : u32 nal_size = 0;
284 0 : while (nal_hdr) {
285 0 : nal_size |= data[size];
286 0 : size++;
287 0 : nal_hdr--;
288 0 : if (!nal_hdr) break;
289 0 : nal_size<<=8;
290 : }
291 0 : nal_type = data[size];
292 0 : nal_type = (nal_type & 0x7E) >> 1;
293 0 : if ((nal_type == GF_HEVC_NALU_SEI_PREFIX) || (nal_type == GF_HEVC_NALU_SEI_SUFFIX) ) {
294 0 : size += nal_size;
295 0 : continue;
296 : }
297 0 : memcpy(output, &data[size-pctx->nalu_size_length], pctx->nalu_size_length+nal_size);
298 0 : output += pctx->nalu_size_length+nal_size;
299 0 : size += nal_size;
300 : }
301 0 : return gf_filter_pck_send(dst);
302 : }
303 :
304 4 : static GF_Err hevc_rewrite_pid_config(GF_BSRWCtx *ctx, BSRWPid *pctx)
305 : {
306 : GF_HEVCConfig *hvcc;
307 : GF_Err e = GF_OK;
308 : u8 *dsi;
309 : u32 dsi_size;
310 : const GF_PropertyValue *prop;
311 :
312 4 : prop = gf_filter_pid_get_property(pctx->ipid, GF_PROP_PID_DECODER_CONFIG);
313 4 : if (!prop) return GF_OK;
314 4 : pctx->reconfigure = GF_FALSE;
315 :
316 4 : hvcc = gf_odf_hevc_cfg_read(prop->value.data.ptr, prop->value.data.size, (pctx->codec_id==GF_CODECID_LHVC) ? GF_TRUE : GF_FALSE);
317 4 : if (pctx->rewrite_vui) {
318 2 : GF_VUIInfo tmp_vui = pctx->vui;
319 2 : tmp_vui.update = GF_TRUE;
320 2 : e = gf_hevc_change_vui(hvcc, &tmp_vui);
321 2 : if (!e) {
322 2 : update_props(pctx, &tmp_vui);
323 : }
324 : }
325 :
326 4 : if (ctx->pidc>=0) hvcc->profile_idc = ctx->pidc;
327 4 : if (ctx->pspace>=0) hvcc->profile_space = ctx->pspace;
328 4 : if (ctx->gpcflags>=0) hvcc->general_profile_compatibility_flags = ctx->gpcflags;
329 :
330 :
331 4 : gf_odf_hevc_cfg_write(hvcc, &dsi, &dsi_size);
332 4 : pctx->nalu_size_length = hvcc->nal_unit_size;
333 4 : gf_odf_hevc_cfg_del(hvcc);
334 4 : if (e) return e;
335 :
336 4 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA_NO_COPY(dsi, dsi_size) );
337 :
338 4 : if (ctx->rmsei) {
339 0 : pctx->rewrite_packet = hevc_rewrite_packet;
340 : } else {
341 4 : pctx->rewrite_packet = none_rewrite_packet;
342 : }
343 : return GF_OK;
344 : }
345 : #endif // GPAC_DISABLE_HEVC
346 :
347 2 : static GF_Err none_rewrite_pid_config(GF_BSRWCtx *ctx, BSRWPid *pctx)
348 : {
349 2 : pctx->reconfigure = GF_FALSE;
350 2 : return GF_OK;
351 : }
352 :
353 : static GF_Err rewrite_pid_config(GF_BSRWCtx *ctx, BSRWPid *pctx)
354 : {
355 14 : GF_Err e = pctx->rewrite_pid_config(ctx, pctx);
356 14 : if (e) return e;
357 14 : pctx->prev_cprim = pctx->prev_ctfc = pctx->prev_cmx = pctx->prev_sar = -1;
358 : return GF_OK;
359 : }
360 :
361 14 : static void init_vui(GF_BSRWCtx *ctx, BSRWPid *pctx)
362 : {
363 14 : pctx->vui.ar_num = ctx->sar.num;
364 14 : pctx->vui.ar_den = ctx->sar.den;
365 14 : pctx->vui.color_matrix = ctx->cmx;
366 14 : pctx->vui.color_prim = ctx->cprim;
367 14 : pctx->vui.fullrange = ctx->fullrange;
368 14 : pctx->vui.remove_video_info = ctx->novsi;
369 14 : pctx->vui.color_tfc = ctx->ctfc;
370 14 : pctx->vui.video_format = ctx->vidfmt;
371 :
372 14 : pctx->rewrite_vui = GF_TRUE;
373 14 : if (ctx->sar.num>=0) return;
374 6 : if ((s32) ctx->sar.den>=0) return;
375 6 : if (ctx->cmx>-1) return;
376 6 : if (ctx->cprim>-1) return;
377 6 : if (ctx->fullrange) return;
378 6 : if (ctx->novsi) return;
379 6 : if (ctx->ctfc>-1) return;
380 6 : if (ctx->vidfmt>-1) return;
381 : //all default
382 6 : pctx->rewrite_vui = GF_FALSE;
383 : }
384 :
385 31 : static GF_Err prores_rewrite_packet(GF_BSRWCtx *ctx, BSRWPid *pctx, GF_FilterPacket *pck)
386 : {
387 : u8 *output;
388 31 : GF_FilterPacket *dst_pck = gf_filter_pck_new_clone(pctx->opid, pck, &output);
389 31 : if (!dst_pck) return GF_OUT_OF_MEM;
390 :
391 : //starting at offset 20 in frame:
392 : /*
393 : prores_frame->chroma_format = gf_bs_read_int(bs, 2);
394 : gf_bs_read_int(bs, 2);
395 : prores_frame->interlaced_mode = gf_bs_read_int(bs, 2);
396 : gf_bs_read_int(bs, 2);
397 : prores_frame->aspect_ratio_information = gf_bs_read_int(bs, 4);
398 : prores_frame->framerate_code = gf_bs_read_int(bs, 4);
399 : prores_frame->color_primaries = gf_bs_read_u8(bs);
400 : prores_frame->transfer_characteristics = gf_bs_read_u8(bs);
401 : prores_frame->matrix_coefficients = gf_bs_read_u8(bs);
402 : gf_bs_read_int(bs, 4);
403 : prores_frame->alpha_channel_type = gf_bs_read_int(bs, 4);
404 : */
405 :
406 31 : if (ctx->sar.num && ctx->sar.den) {
407 31 : u32 framerate_code = output[21] & 0xF;
408 : u32 new_ar = 0;
409 31 : if (ctx->sar.num==ctx->sar.den) new_ar = 1;
410 31 : else if (ctx->sar.num * 3 == ctx->sar.den * 4) new_ar = 2;
411 31 : else if (ctx->sar.num * 9 == ctx->sar.den * 16) new_ar = 3;
412 : else {
413 0 : if (pctx->prev_sar != new_ar) {
414 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[BSRW] Aspect ratio %d/%d not registered in ProRes, using 0 (unknown)\n", ctx->sar.num, ctx->sar.den));
415 : }
416 : }
417 31 : new_ar <<= 4;
418 31 : framerate_code |= new_ar;
419 31 : output[21] = (u8) framerate_code;
420 31 : if (pctx->prev_sar != new_ar) {
421 1 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_SAR, &PROP_FRAC(ctx->sar) );
422 1 : pctx->prev_sar = new_ar;
423 : }
424 : }
425 31 : if (ctx->cprim>=0) {
426 0 : output[22] = (u8) ctx->cprim;
427 0 : if (pctx->prev_cprim != ctx->cprim) {
428 0 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_COLR_PRIMARIES, &PROP_UINT(ctx->cprim) );
429 0 : pctx->prev_cprim = ctx->cprim;
430 : }
431 : }
432 31 : if (ctx->ctfc>=0) {
433 0 : output[23] = (u8) ctx->ctfc;
434 0 : if (ctx->ctfc != pctx->prev_ctfc) {
435 0 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_COLR_TRANSFER, &PROP_UINT(ctx->ctfc) );
436 0 : pctx->prev_ctfc = ctx->ctfc;
437 : }
438 : }
439 31 : if (ctx->cmx>=0) {
440 0 : output[24] = (u8) ctx->cmx;
441 0 : if (pctx->prev_cmx != ctx->cmx) {
442 0 : gf_filter_pid_set_property(pctx->opid, GF_PROP_PID_COLR_MX, &PROP_UINT(ctx->cmx) );
443 0 : pctx->prev_cmx = ctx->cmx;
444 : }
445 : }
446 31 : return gf_filter_pck_send(dst_pck);
447 : }
448 :
449 :
450 7 : static GF_Err bsrw_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
451 : {
452 : const GF_PropertyValue *prop;
453 7 : GF_BSRWCtx *ctx = (GF_BSRWCtx *) gf_filter_get_udta(filter);
454 7 : BSRWPid *pctx = gf_filter_pid_get_udta(pid);
455 :
456 : //disconnect of src pid (not yet supported)
457 7 : if (is_remove) {
458 0 : if (pctx) {
459 0 : if (pctx->opid) {
460 0 : gf_filter_pid_remove(pctx->opid);
461 0 : pctx->opid = NULL;
462 : }
463 0 : gf_filter_pid_set_udta(pid, NULL);
464 0 : gf_list_del_item(ctx->pids, pctx);
465 0 : gf_free(pctx);
466 : }
467 : return GF_OK;
468 : }
469 7 : if (! gf_filter_pid_check_caps(pid))
470 : return GF_NOT_SUPPORTED;
471 :
472 7 : if (!pctx) {
473 7 : GF_SAFEALLOC(pctx, BSRWPid);
474 7 : if (!pctx) return GF_OUT_OF_MEM;
475 7 : pctx->ipid = pid;
476 7 : gf_filter_pid_set_udta(pid, pctx);
477 7 : pctx->rewrite_pid_config = none_rewrite_pid_config;
478 7 : pctx->rewrite_packet = none_rewrite_packet;
479 7 : gf_list_add(ctx->pids, pctx);
480 7 : pctx->opid = gf_filter_pid_new(filter);
481 7 : if (!pctx->opid) return GF_OUT_OF_MEM;
482 7 : init_vui(ctx, pctx);
483 : }
484 :
485 7 : prop = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
486 : assert(prop);
487 7 : switch (prop->value.uint) {
488 3 : case GF_CODECID_AVC:
489 : case GF_CODECID_SVC:
490 : case GF_CODECID_MVC:
491 3 : pctx->rewrite_pid_config = avc_rewrite_pid_config;
492 3 : break;
493 : #ifndef GPAC_DISABLE_HEVC
494 2 : case GF_CODECID_HEVC:
495 : case GF_CODECID_HEVC_TILES:
496 : case GF_CODECID_LHVC:
497 2 : pctx->rewrite_pid_config = hevc_rewrite_pid_config;
498 2 : break;
499 : #endif
500 1 : case GF_CODECID_MPEG4_PART2:
501 1 : pctx->rewrite_pid_config = m4v_rewrite_pid_config;
502 1 : break;
503 1 : case GF_CODECID_AP4H:
504 : case GF_CODECID_AP4X:
505 : case GF_CODECID_APCH:
506 : case GF_CODECID_APCN:
507 : case GF_CODECID_APCO:
508 : case GF_CODECID_APCS:
509 1 : pctx->rewrite_pid_config = none_rewrite_pid_config;
510 1 : pctx->rewrite_packet = prores_rewrite_packet;
511 1 : break;
512 :
513 0 : default:
514 0 : pctx->rewrite_pid_config = none_rewrite_pid_config;
515 0 : pctx->rewrite_packet = none_rewrite_packet;
516 0 : break;
517 : }
518 :
519 7 : gf_filter_pid_copy_properties(pctx->opid, pctx->ipid);
520 7 : pctx->codec_id = prop->value.uint;
521 7 : pctx->reconfigure = GF_FALSE;
522 7 : gf_filter_pid_set_framing_mode(pid, GF_TRUE);
523 : //rewrite asap - waiting for first packet could lead to issues further down the chain, especially for movie fragments
524 : //were the init segment could have already been flushed at the time we will dispatch the first packet
525 : rewrite_pid_config(ctx, pctx);
526 : return GF_OK;
527 : }
528 :
529 :
530 1618 : static GF_Err bsrw_process(GF_Filter *filter)
531 : {
532 : u32 i, count;
533 1618 : GF_BSRWCtx *ctx = (GF_BSRWCtx *) gf_filter_get_udta(filter);
534 :
535 1618 : count = gf_filter_get_ipid_count(filter);
536 3236 : for (i=0; i<count; i++) {
537 : BSRWPid *pctx;
538 : GF_FilterPacket *pck;
539 1618 : GF_FilterPid *pid = gf_filter_get_ipid(filter, i);
540 1618 : if (!pid) break;
541 1618 : pctx = gf_filter_pid_get_udta(pid);
542 1618 : if (!pctx) break;
543 1618 : if (ctx->reconfigure)
544 7 : pctx->reconfigure = GF_TRUE;
545 :
546 1618 : if (pctx->reconfigure) {
547 7 : init_vui(ctx, pctx);
548 : GF_Err e = rewrite_pid_config(ctx, pctx);
549 : if (e) return e;
550 : }
551 1618 : pck = gf_filter_pid_get_packet(pid);
552 1618 : if (!pck) {
553 314 : if (gf_filter_pid_is_eos(pctx->ipid))
554 7 : gf_filter_pid_set_eos(pctx->opid);
555 314 : continue;
556 : }
557 1304 : pctx->rewrite_packet(ctx, pctx, pck);
558 1304 : gf_filter_pid_drop_packet(pid);
559 : }
560 1618 : ctx->reconfigure = GF_FALSE;
561 1618 : return GF_OK;
562 : }
563 :
564 0 : static GF_Err bsrw_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *new_val)
565 : {
566 7 : GF_BSRWCtx *ctx = (GF_BSRWCtx *) gf_filter_get_udta(filter);
567 7 : ctx->reconfigure = GF_TRUE;
568 0 : return GF_OK;
569 : }
570 :
571 7 : static GF_Err bsrw_initialize(GF_Filter *filter)
572 : {
573 7 : GF_BSRWCtx *ctx = (GF_BSRWCtx *) gf_filter_get_udta(filter);
574 7 : ctx->pids = gf_list_new();
575 :
576 : #ifdef GPAC_ENABLE_COVERAGE
577 : bsrw_update_arg(filter, NULL, NULL);
578 : #endif
579 7 : return GF_OK;
580 : }
581 7 : static void bsrw_finalize(GF_Filter *filter)
582 : {
583 7 : GF_BSRWCtx *ctx = (GF_BSRWCtx *) gf_filter_get_udta(filter);
584 21 : while (gf_list_count(ctx->pids)) {
585 7 : BSRWPid *pctx = gf_list_pop_back(ctx->pids);
586 7 : gf_free(pctx);
587 : }
588 7 : gf_list_del(ctx->pids);
589 7 : }
590 :
591 : #define OFFS(_n) #_n, offsetof(GF_BSRWCtx, _n)
592 : static GF_FilterArgs BSRWArgs[] =
593 : {
594 : ///do not change order of the first 3
595 : { OFFS(cprim), "color primaries according to ISO/IEC 23001-8 / 23091-2", GF_PROP_CICP_COL_PRIM, "-1", NULL, GF_FS_ARG_UPDATE},
596 : { OFFS(ctfc), "color transfer characteristics according to ISO/IEC 23001-8 / 23091-2", GF_PROP_CICP_COL_TFC, "-1", NULL, GF_FS_ARG_UPDATE},
597 : { OFFS(cmx), "color matrix coeficients according to ISO/IEC 23001-8 / 23091-2", GF_PROP_CICP_COL_MX, "-1", NULL, GF_FS_ARG_UPDATE},
598 : { OFFS(sar), "aspect ratio to rewrite - see filter help", GF_PROP_FRACTION, "-1/-1", NULL, GF_FS_ARG_UPDATE},
599 : { OFFS(m4vpl), "set ProfileLevel for MPEG-4 video part two", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
600 : { OFFS(fullrange), "video full range for AVC|H264 and HEVC", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE},
601 : { OFFS(novsi), "remove video_signal_type from VUI in AVC|H264 and HEVC", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE},
602 : { OFFS(prof), "profile indication for AVC|H264", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
603 : { OFFS(lev), "level indication for AVC|H264", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
604 : { OFFS(pcomp), "profile compatibility for AVC|H264", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
605 : { OFFS(pidc), "profile IDC for HEVC", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
606 : { OFFS(pspace), "profile space for HEVC", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
607 : { OFFS(gpcflags), "general compatibility flags for HEVC", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_UPDATE},
608 : { OFFS(rmsei), "remove SEI messages from bitstream for AVC|H264 and HEVC", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_UPDATE},
609 : { OFFS(vidfmt), "video format for AVC|H264 and HEVC", GF_PROP_UINT, "-1", "component|pal|ntsc|secam|mac|undef", GF_FS_ARG_UPDATE},
610 : {0}
611 : };
612 :
613 : static const GF_FilterCapability BSRWCaps[] =
614 : {
615 : //this is correct but we want the filter to act as passthrough for other media
616 : #if 0
617 : CAP_UINT(GF_CAPS_INPUT_STATIC ,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
618 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED|GF_CAPFLAG_STATIC , GF_PROP_PID_UNFRAMED, GF_TRUE),
619 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_AVC),
620 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_SVC),
621 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_MVC),
622 : {0},
623 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_HEVC),
624 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_HEVC_TILES),
625 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_LHVC),
626 : {0},
627 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
628 : {0},
629 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4H),
630 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_AP4X),
631 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_APCH),
632 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_APCN),
633 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_APCO),
634 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_APCS),
635 : #else
636 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
637 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
638 : CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
639 : CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE),
640 : #endif
641 :
642 : };
643 :
644 : GF_FilterRegister BSRWRegister = {
645 : .name = "bsrw",
646 : GF_FS_SET_DESCRIPTION("Compressed bitstream rewriter")
647 : GF_FS_SET_HELP("This filter rewrites some metadata of various bitstream formats.\n"
648 : "The filter can currently modify the following properties in video bitstreams:\n"
649 : "- MPEG-4 Visual:\n"
650 : " - sample aspect ratio\n"
651 : " - profile and level\n"
652 : "- AVC|H264 and HEVC:\n"
653 : " - sample aspect ratio\n"
654 : " - profile, level, profile compatibility\n"
655 : " - video format, video fullrange\n"
656 : " - color primaries, transfer characteristics and matrix coefficients (or remove all info)\n"
657 : "- ProRes:\n"
658 : " - sample aspect ratio\n"
659 : " - color primaries, transfer characteristics and matrix coefficients\n"
660 : " \n"
661 : "Values are by default initialized to -1, implying to keep the related info (present or not) in the bitstream.\n"
662 : "A [-sar]() value of `0/0` will remove sample aspect ratio info from bitstream if possible.\n"
663 : " \n"
664 : "The filter can currently modify the following properties in the stream configuration but not in the bitstream:\n"
665 : "- HEVC: profile IDC, profile space, general compatibility flags\n"
666 : " \n"
667 : "The filter will work in passthrough mode for all other codecs and media types.\n"
668 : )
669 : .private_size = sizeof(GF_BSRWCtx),
670 : .max_extra_pids = 0xFFFFFFFF,
671 : .flags = GF_FS_REG_EXPLICIT_ONLY,
672 : .args = BSRWArgs,
673 : SETCAPS(BSRWCaps),
674 : .initialize = bsrw_initialize,
675 : .finalize = bsrw_finalize,
676 : .configure_pid = bsrw_configure_pid,
677 : .process = bsrw_process,
678 : .update_arg = bsrw_update_arg
679 : };
680 :
681 2877 : const GF_FilterRegister *bsrw_register(GF_FilterSession *session)
682 : {
683 : //assign runtime caps on first load
684 2877 : if (gf_opts_get_bool("temp", "helponly")) {
685 31 : BSRWArgs[0].min_max_enum = gf_cicp_color_primaries_all_names();
686 31 : BSRWArgs[1].min_max_enum = gf_cicp_color_transfer_all_names();
687 31 : BSRWArgs[2].min_max_enum = gf_cicp_color_matrix_all_names();
688 : }
689 2877 : return (const GF_FilterRegister *) &BSRWRegister;
690 : }
|