Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2017-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / NALU video AnnexB write filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/filters.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/bitstream.h>
29 : #include <gpac/internal/media_dev.h>
30 :
31 : enum
32 : {
33 : UFNAL_AVC,
34 : UFNAL_HEVC,
35 : UFNAL_VVC,
36 : };
37 :
38 : typedef struct
39 : {
40 : //opts
41 : Bool rcfg, delim, pps_inband;
42 : u32 extract;
43 :
44 : //only one input pid declared
45 : GF_FilterPid *ipid;
46 : //only one output pid declared
47 : GF_FilterPid *opid;
48 :
49 : u32 vtype;
50 :
51 : u32 nal_hdr_size, crc, crc_enh;
52 : u8 *dsi, *dsi_non_rap;
53 : u32 dsi_size, dsi_non_rap_size;
54 :
55 : GF_BitStream *bs_w, *bs_r;
56 : u32 nb_nalu, nb_nalu_in_hdr, nb_nalu_in_hdr_non_rap;
57 : u32 width, height;
58 : } GF_NALUMxCtx;
59 :
60 :
61 :
62 :
63 181 : static void nalumx_write_ps_list(GF_NALUMxCtx *ctx, GF_BitStream *bs, GF_List *list, Bool for_non_rap)
64 : {
65 181 : u32 i, count = list ? gf_list_count(list) : 0;
66 180 : for (i=0; i<count; i++) {
67 180 : GF_NALUFFParam *sl = gf_list_get(list, i);
68 180 : gf_bs_write_u32(bs, 1);
69 180 : gf_bs_write_data(bs, sl->data, sl->size);
70 180 : if (for_non_rap)
71 0 : ctx->nb_nalu_in_hdr_non_rap++;
72 : else
73 180 : ctx->nb_nalu_in_hdr++;
74 : }
75 181 : }
76 :
77 135 : static GF_List *nalumx_get_hevc_ps(GF_HEVCConfig *cfg, u8 type)
78 : {
79 135 : u32 i, count = gf_list_count(cfg->param_array);
80 270 : for (i=0; i<count; i++) {
81 269 : GF_NALUFFParamArray *pa = gf_list_get(cfg->param_array, i);
82 269 : if (pa->type == type) return pa->nalus;
83 : }
84 : return NULL;
85 : }
86 0 : static GF_List *nalumx_get_vvc_ps(GF_VVCConfig *cfg, u8 type)
87 : {
88 0 : u32 i, count = gf_list_count(cfg->param_array);
89 0 : for (i=0; i<count; i++) {
90 0 : GF_NALUFFParamArray *pa = gf_list_get(cfg->param_array, i);
91 0 : if (pa->type == type) return pa->nalus;
92 : }
93 : return NULL;
94 : }
95 :
96 67 : static GF_Err nalumx_make_inband_header(GF_NALUMxCtx *ctx, char *dsi, u32 dsi_len, char *dsi_enh, u32 dsi_enh_len, Bool for_non_rap)
97 : {
98 : GF_BitStream *bs;
99 : GF_AVCConfig *avcc = NULL;
100 : GF_AVCConfig *svcc = NULL;
101 : GF_HEVCConfig *hvcc = NULL;
102 : GF_HEVCConfig *lvcc = NULL;
103 : GF_VVCConfig *vvcc = NULL;
104 : GF_VVCConfig *s_vvcc = NULL;
105 :
106 67 : if (ctx->vtype==UFNAL_HEVC) {
107 44 : if (dsi) hvcc = gf_odf_hevc_cfg_read(dsi, dsi_len, GF_FALSE);
108 44 : if (dsi_enh) lvcc = gf_odf_hevc_cfg_read(dsi_enh, dsi_enh_len, GF_TRUE);
109 44 : if (!hvcc && !lvcc) return GF_NON_COMPLIANT_BITSTREAM;
110 44 : ctx->nal_hdr_size = hvcc ? hvcc->nal_unit_size : lvcc->nal_unit_size;
111 23 : } else if (ctx->vtype==UFNAL_VVC) {
112 0 : if (dsi) vvcc = gf_odf_vvc_cfg_read(dsi, dsi_len);
113 0 : if (dsi_enh) s_vvcc = gf_odf_vvc_cfg_read(dsi_enh, dsi_enh_len);
114 0 : if (!vvcc && !s_vvcc) return GF_NON_COMPLIANT_BITSTREAM;
115 0 : ctx->nal_hdr_size = vvcc ? vvcc->nal_unit_size : s_vvcc->nal_unit_size;
116 : } else {
117 23 : if (dsi) avcc = gf_odf_avc_cfg_read(dsi, dsi_len);
118 23 : if (dsi_enh) svcc = gf_odf_avc_cfg_read(dsi_enh, dsi_enh_len);
119 23 : if (!avcc && !svcc) return GF_NON_COMPLIANT_BITSTREAM;
120 23 : ctx->nal_hdr_size = avcc ? avcc->nal_unit_size : svcc->nal_unit_size;
121 : }
122 67 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
123 67 : if (avcc || svcc) {
124 23 : if (avcc && !for_non_rap) {
125 23 : nalumx_write_ps_list(ctx, bs, avcc->sequenceParameterSets, for_non_rap);
126 : }
127 :
128 23 : if (svcc && !for_non_rap)
129 0 : nalumx_write_ps_list(ctx, bs, svcc->sequenceParameterSets, for_non_rap);
130 :
131 23 : if (avcc && avcc->sequenceParameterSetExtensions && !for_non_rap)
132 0 : nalumx_write_ps_list(ctx, bs, avcc->sequenceParameterSetExtensions, for_non_rap);
133 :
134 23 : if (svcc && svcc->sequenceParameterSetExtensions && !for_non_rap)
135 0 : nalumx_write_ps_list(ctx, bs, svcc->sequenceParameterSetExtensions, for_non_rap);
136 :
137 23 : if (avcc)
138 23 : nalumx_write_ps_list(ctx, bs, avcc->pictureParameterSets, for_non_rap);
139 :
140 23 : if (svcc)
141 0 : nalumx_write_ps_list(ctx, bs, svcc->pictureParameterSets, for_non_rap);
142 : }
143 67 : if (hvcc || lvcc) {
144 44 : if (hvcc && !for_non_rap)
145 44 : nalumx_write_ps_list(ctx, bs, nalumx_get_hevc_ps(hvcc, GF_HEVC_NALU_VID_PARAM), for_non_rap);
146 44 : if (lvcc && !for_non_rap)
147 1 : nalumx_write_ps_list(ctx, bs, nalumx_get_hevc_ps(lvcc, GF_HEVC_NALU_VID_PARAM), for_non_rap);
148 44 : if (hvcc && !for_non_rap)
149 44 : nalumx_write_ps_list(ctx, bs, nalumx_get_hevc_ps(hvcc, GF_HEVC_NALU_SEQ_PARAM), for_non_rap);
150 44 : if (lvcc && !for_non_rap)
151 1 : nalumx_write_ps_list(ctx, bs, nalumx_get_hevc_ps(lvcc, GF_HEVC_NALU_SEQ_PARAM), for_non_rap);
152 44 : if (hvcc)
153 44 : nalumx_write_ps_list(ctx, bs, nalumx_get_hevc_ps(hvcc, GF_HEVC_NALU_PIC_PARAM), for_non_rap);
154 44 : if (lvcc)
155 1 : nalumx_write_ps_list(ctx, bs, nalumx_get_hevc_ps(lvcc, GF_HEVC_NALU_PIC_PARAM), for_non_rap);
156 : }
157 :
158 67 : if (vvcc || s_vvcc) {
159 0 : u32 dump_types[] = {GF_VVC_NALU_VID_PARAM, GF_VVC_NALU_DEC_PARAM, GF_VVC_NALU_SEQ_PARAM, GF_VVC_NALU_PIC_PARAM, GF_VVC_NALU_APS_PREFIX, GF_VVC_NALU_SEI_PREFIX};
160 0 : u32 i = for_non_rap ? 3 : 0;
161 :
162 0 : for (; i< GF_ARRAY_LENGTH(dump_types); i++) {
163 0 : if (vvcc)
164 0 : nalumx_write_ps_list(ctx, bs, nalumx_get_vvc_ps(vvcc, dump_types[i]), for_non_rap);
165 0 : if (s_vvcc)
166 0 : nalumx_write_ps_list(ctx, bs, nalumx_get_vvc_ps(s_vvcc, dump_types[i]), for_non_rap);
167 : }
168 : }
169 :
170 67 : if (for_non_rap) {
171 0 : if (ctx->dsi_non_rap) gf_free(ctx->dsi_non_rap);
172 0 : gf_bs_get_content(bs, &ctx->dsi_non_rap, &ctx->dsi_non_rap_size);
173 : } else {
174 67 : if (ctx->dsi) gf_free(ctx->dsi);
175 67 : gf_bs_get_content(bs, &ctx->dsi, &ctx->dsi_size);
176 : }
177 67 : gf_bs_del(bs);
178 :
179 67 : if (avcc) gf_odf_avc_cfg_del(avcc);
180 67 : if (svcc) gf_odf_avc_cfg_del(svcc);
181 67 : if (hvcc) gf_odf_hevc_cfg_del(hvcc);
182 67 : if (lvcc) gf_odf_hevc_cfg_del(lvcc);
183 67 : if (vvcc) gf_odf_vvc_cfg_del(vvcc);
184 67 : if (s_vvcc) gf_odf_vvc_cfg_del(s_vvcc);
185 :
186 67 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
187 67 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, NULL);
188 :
189 67 : return GF_OK;
190 : }
191 :
192 87 : GF_Err nalumx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
193 : {
194 : GF_Err e;
195 : u32 crc, crc_enh, codecid;
196 : const GF_PropertyValue *p, *dcd, *dcd_enh;
197 87 : GF_NALUMxCtx *ctx = gf_filter_get_udta(filter);
198 :
199 87 : if (is_remove) {
200 0 : ctx->ipid = NULL;
201 0 : if (ctx->opid) {
202 0 : gf_filter_pid_remove(ctx->opid);
203 0 : ctx->opid = NULL;
204 : }
205 : return GF_OK;
206 : }
207 87 : if (! gf_filter_pid_check_caps(pid))
208 : return GF_NOT_SUPPORTED;
209 :
210 87 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
211 87 : if (!p) return GF_NOT_SUPPORTED;
212 87 : codecid = p->value.uint;
213 :
214 : //it may happen we don't have anything yet ...
215 87 : dcd = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
216 87 : if (!dcd) {
217 : crc = -1;
218 : } else {
219 87 : crc = gf_crc_32(dcd->value.data.ptr, dcd->value.data.size);
220 : }
221 87 : dcd_enh = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT);
222 :
223 87 : crc_enh = dcd_enh ? gf_crc_32(dcd_enh->value.data.ptr, dcd_enh->value.data.size) : 0;
224 87 : if ((ctx->crc == crc) && (ctx->crc_enh == crc_enh)) return GF_OK;
225 67 : ctx->crc = crc;
226 67 : ctx->crc_enh = crc_enh;
227 :
228 67 : if ((codecid==GF_CODECID_HEVC) || (codecid==GF_CODECID_LHVC)) {
229 44 : ctx->vtype = UFNAL_HEVC;
230 23 : } else if (codecid==GF_CODECID_VVC) {
231 0 : ctx->vtype = UFNAL_VVC;
232 : } else {
233 23 : ctx->vtype = UFNAL_AVC;
234 : }
235 :
236 67 : ctx->width = ctx->height = 0;
237 67 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
238 67 : if (p) ctx->width = p->value.uint;
239 67 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
240 67 : if (p) ctx->height = p->value.uint;
241 :
242 67 : if (!ctx->opid) {
243 67 : ctx->opid = gf_filter_pid_new(filter);
244 : }
245 : //copy properties at init or reconfig
246 67 : gf_filter_pid_copy_properties(ctx->opid, pid);
247 67 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
248 67 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL );
249 67 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, NULL );
250 :
251 67 : ctx->ipid = pid;
252 67 : gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
253 67 : if (!dcd && !dcd_enh)
254 : return GF_OK;
255 :
256 67 : e = nalumx_make_inband_header(ctx, dcd ? dcd->value.data.ptr : NULL, dcd ? dcd->value.data.size : 0, dcd_enh ? dcd_enh->value.data.ptr : NULL, dcd_enh ? dcd_enh->value.data.size : 0, GF_FALSE);
257 67 : if (e) return e;
258 :
259 67 : if (!ctx->pps_inband || !ctx->rcfg) return GF_OK;
260 0 : return nalumx_make_inband_header(ctx, dcd ? dcd->value.data.ptr : NULL, dcd ? dcd->value.data.size : 0, dcd_enh ? dcd_enh->value.data.ptr : NULL, dcd_enh ? dcd_enh->value.data.size : 0, GF_TRUE);
261 : }
262 :
263 :
264 136330 : static Bool nalumx_is_nal_skip(GF_NALUMxCtx *ctx, u8 *data, u32 pos, Bool *has_nal_delim, u32 *out_temporal_id, u32 *out_layer_id, u8 *avc_hdr)
265 : {
266 : Bool is_layer = GF_FALSE;
267 136330 : if (ctx->vtype==UFNAL_HEVC) {
268 122488 : u8 nal_type = (data[pos] & 0x7E) >> 1;
269 122488 : u8 temporal_id = data[pos+1] & 0x7;
270 : u8 layer_id = data[pos] & 1;
271 122488 : layer_id <<= 5;
272 122488 : layer_id |= (data[pos+1]>>3) & 0x1F;
273 122488 : if (temporal_id > *out_temporal_id) *out_temporal_id = temporal_id;
274 122488 : if (! (*out_layer_id) ) *out_layer_id = 1+layer_id;
275 :
276 122488 : switch (nal_type) {
277 : case GF_HEVC_NALU_VID_PARAM:
278 : break;
279 0 : case GF_HEVC_NALU_ACCESS_UNIT:
280 0 : *has_nal_delim = GF_TRUE;
281 : break;
282 122488 : default:
283 122488 : if (layer_id) is_layer = GF_TRUE;
284 : break;
285 : }
286 13842 : } else if (ctx->vtype==UFNAL_VVC) {
287 0 : u8 nal_type = data[pos+1] >> 3;
288 0 : u8 temporal_id = data[pos+1] & 0x7;
289 0 : u8 layer_id = data[pos] & 0x3f;
290 0 : if (temporal_id > *out_temporal_id) *out_temporal_id = temporal_id;
291 0 : if (! (*out_layer_id) ) *out_layer_id = 1+layer_id;
292 :
293 0 : switch (nal_type) {
294 : case GF_VVC_NALU_VID_PARAM:
295 : break;
296 0 : case GF_VVC_NALU_ACCESS_UNIT:
297 0 : *has_nal_delim = GF_TRUE;
298 : break;
299 0 : default:
300 0 : if (layer_id) is_layer = GF_TRUE;
301 : break;
302 : }
303 : } else {
304 13842 : u32 nal_type = data[pos] & 0x1F;
305 : switch (nal_type) {
306 : case GF_AVC_NALU_SVC_PREFIX_NALU:
307 : case GF_AVC_NALU_SVC_SLICE:
308 : case GF_AVC_NALU_VDRD:
309 : case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
310 : case GF_AVC_NALU_SEQ_PARAM:
311 : case GF_AVC_NALU_SEQ_PARAM_EXT:
312 : case GF_AVC_NALU_PIC_PARAM:
313 : is_layer = GF_TRUE;
314 : break;
315 0 : case GF_AVC_NALU_ACCESS_UNIT:
316 0 : *has_nal_delim = GF_TRUE;
317 : break;
318 13842 : default:
319 13842 : if (! (*avc_hdr))
320 6899 : (*avc_hdr) = data[pos];
321 : break;
322 : }
323 : }
324 136330 : if (ctx->extract==1) return is_layer ? GF_TRUE : GF_FALSE;
325 136330 : else if (ctx->extract==2) return is_layer ? GF_FALSE : GF_TRUE;
326 : return GF_FALSE;
327 : }
328 :
329 40061 : GF_Err nalumx_process(GF_Filter *filter)
330 : {
331 40061 : GF_NALUMxCtx *ctx = gf_filter_get_udta(filter);
332 : GF_FilterPacket *pck, *dst_pck;
333 : u8 *data, *output;
334 : u32 pck_size, size, sap=0, temporal_id, layer_id;
335 : u8 avc_hdr;
336 : u8 *dsi_buf = NULL;
337 : u32 dsi_buf_size = 0, dsi_nb_nal = 0;
338 :
339 : Bool has_nalu_delim = GF_FALSE;
340 :
341 40061 : pck = gf_filter_pid_get_packet(ctx->ipid);
342 40061 : if (!pck) {
343 14574 : if (gf_filter_pid_is_eos(ctx->ipid)) {
344 67 : if (!ctx->nb_nalu && ctx->dsi) {
345 0 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->dsi_size, &output);
346 0 : if (!dst_pck) return GF_OUT_OF_MEM;
347 :
348 0 : memcpy(output, ctx->dsi, ctx->dsi_size);
349 0 : gf_filter_pck_set_sap(dst_pck, GF_FILTER_SAP_1);
350 0 : gf_filter_pck_send(dst_pck);
351 0 : ctx->nb_nalu += ctx->nb_nalu_in_hdr;
352 : }
353 67 : gf_filter_pid_set_eos(ctx->opid);
354 67 : return GF_EOS;
355 : }
356 : return GF_OK;
357 : }
358 :
359 25487 : if (!ctx->nal_hdr_size) {
360 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[NALWrite] no NAL size length field set, assuming 4\n"));
361 0 : ctx->nal_hdr_size = 4;
362 : }
363 :
364 25487 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
365 25487 : if (!pck_size || !data) {
366 0 : gf_filter_pid_drop_packet(ctx->ipid);
367 0 : return GF_OK;
368 : }
369 25487 : if (!ctx->bs_r) ctx->bs_r = gf_bs_new(data, pck_size, GF_BITSTREAM_READ);
370 25420 : else gf_bs_reassign_buffer(ctx->bs_r, data, pck_size);
371 :
372 : size = 0;
373 25487 : temporal_id = layer_id = 0;
374 25487 : avc_hdr = 0;
375 :
376 119139 : while (gf_bs_available((ctx->bs_r))) {
377 : Bool skip_nal = GF_FALSE;
378 68165 : Bool is_nalu_delim = GF_FALSE;
379 : u32 pos;
380 68165 : u32 nal_size = gf_bs_read_int(ctx->bs_r, 8*ctx->nal_hdr_size);
381 68165 : if (nal_size > gf_bs_available(ctx->bs_r) ) {
382 0 : gf_filter_pid_drop_packet(ctx->ipid);
383 0 : return GF_NON_COMPLIANT_BITSTREAM;
384 : }
385 68165 : pos = (u32) gf_bs_get_position(ctx->bs_r);
386 : //even if not filtering, parse to check for AU delim
387 68165 : skip_nal = nalumx_is_nal_skip(ctx, data, pos, &is_nalu_delim, &layer_id, &temporal_id, &avc_hdr);
388 68165 : if (!ctx->extract) {
389 : skip_nal = GF_FALSE;
390 : }
391 68165 : if (is_nalu_delim) {
392 : has_nalu_delim = GF_TRUE;
393 0 : if (!ctx->delim)
394 : skip_nal = GF_TRUE;
395 : }
396 68165 : if (!skip_nal) {
397 68165 : size += nal_size + 4;
398 : }
399 68165 : gf_bs_skip_bytes(ctx->bs_r, nal_size);
400 : }
401 25487 : gf_bs_seek(ctx->bs_r, 0);
402 :
403 25487 : if (!ctx->delim)
404 : has_nalu_delim = GF_TRUE;
405 :
406 : //we need to insert NALU delim (2 bytes for avc, 3 for hevc or vvc)
407 25487 : if (!has_nalu_delim) {
408 25487 : size += (ctx->vtype != UFNAL_AVC) ? 3 : 2;
409 25487 : size += 4;
410 : }
411 :
412 25487 : if (ctx->dsi) {
413 : Bool insert_dsi = GF_FALSE;
414 25487 : sap = gf_filter_pck_get_sap(pck);
415 25487 : if (sap && (sap <= GF_FILTER_SAP_3) ) {
416 : insert_dsi = GF_TRUE;
417 : }
418 : if (!insert_dsi) {
419 24499 : u8 flags = gf_filter_pck_get_dependency_flags(pck);
420 : //get dependsOn
421 24499 : if (flags) {
422 94 : flags>>=4;
423 94 : flags &= 0x3;
424 94 : if (flags==2) insert_dsi = GF_TRUE; //could be SAP 1, 2 or 3
425 : }
426 : }
427 :
428 25487 : if (insert_dsi) {
429 988 : dsi_buf = ctx->dsi;
430 988 : dsi_buf_size = ctx->dsi_size;
431 988 : dsi_nb_nal = ctx->nb_nalu_in_hdr;
432 24499 : } else if (ctx->dsi_non_rap) {
433 : dsi_buf = ctx->dsi_non_rap;
434 0 : dsi_buf_size = ctx->dsi_non_rap_size;
435 0 : dsi_nb_nal = ctx->nb_nalu_in_hdr_non_rap;
436 : }
437 25487 : size += dsi_buf_size;
438 : }
439 :
440 25487 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
441 25487 : if (!dst_pck) return GF_OUT_OF_MEM;
442 :
443 25487 : if (!ctx->bs_w) ctx->bs_w = gf_bs_new(output, size, GF_BITSTREAM_WRITE);
444 25420 : else gf_bs_reassign_buffer(ctx->bs_w, output, size);
445 :
446 : // nalu delimiter is not present, write it first
447 25487 : if (!has_nalu_delim) {
448 25487 : gf_bs_write_u32(ctx->bs_w, 1);
449 25487 : if (ctx->vtype==UFNAL_HEVC) {
450 18588 : if (!layer_id)
451 0 : layer_id=1;
452 18588 : if (!temporal_id)
453 0 : temporal_id=1;
454 : #ifndef GPAC_DISABLE_HEVC
455 18588 : gf_bs_write_int(ctx->bs_w, 0, 1);
456 18588 : gf_bs_write_int(ctx->bs_w, GF_HEVC_NALU_ACCESS_UNIT, 6);
457 18588 : gf_bs_write_int(ctx->bs_w, layer_id-1, 6); //we should pick the layerID of the following nalus ...
458 18588 : gf_bs_write_int(ctx->bs_w, temporal_id, 3);
459 : /*pic-type - by default we signal all slice types possible*/
460 18588 : gf_bs_write_int(ctx->bs_w, 2, 3);
461 18588 : gf_bs_write_int(ctx->bs_w, 1, 1); //stop bit
462 18588 : gf_bs_write_int(ctx->bs_w, 0, 4); //4 bits to 0
463 : #endif
464 6899 : } else if (ctx->vtype==UFNAL_VVC) {
465 0 : if (!layer_id)
466 0 : layer_id=1;
467 0 : if (!temporal_id)
468 0 : temporal_id=1;
469 0 : gf_bs_write_int(ctx->bs_w, 0, 1);
470 0 : gf_bs_write_int(ctx->bs_w, 0, 1);
471 0 : gf_bs_write_int(ctx->bs_w, layer_id-1, 6); //we should pick the layerID of the following nalus ...
472 0 : gf_bs_write_int(ctx->bs_w, GF_VVC_NALU_ACCESS_UNIT, 5);
473 0 : gf_bs_write_int(ctx->bs_w, temporal_id, 3);
474 0 : gf_bs_write_int(ctx->bs_w, sap ? 1 : 0, 1);
475 : /*pic-type - by default we signal all slice types possible*/
476 0 : gf_bs_write_int(ctx->bs_w, 2, 3);
477 :
478 0 : gf_bs_write_int(ctx->bs_w, 1, 1); //stop bit
479 0 : gf_bs_write_int(ctx->bs_w, 0, 3); //3 bits to 0
480 : } else {
481 6899 : gf_bs_write_int(ctx->bs_w, (avc_hdr & 0x60) | GF_AVC_NALU_ACCESS_UNIT, 8);
482 6899 : gf_bs_write_int(ctx->bs_w, 0xF0 , 8); /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
483 : }
484 25487 : ctx->nb_nalu++;
485 : }
486 :
487 93652 : while (gf_bs_available((ctx->bs_r))) {
488 : u32 pos;
489 : Bool skip_nal = GF_FALSE;
490 68165 : Bool is_nalu_delim = GF_FALSE;
491 68165 : u32 nal_size = gf_bs_read_int(ctx->bs_r, 8*ctx->nal_hdr_size);
492 68165 : if (nal_size > gf_bs_available(ctx->bs_r) ) {
493 0 : gf_filter_pid_drop_packet(ctx->ipid);
494 0 : return GF_NON_COMPLIANT_BITSTREAM;
495 : }
496 68165 : pos = (u32) gf_bs_get_position(ctx->bs_r);
497 :
498 68165 : skip_nal = nalumx_is_nal_skip(ctx, data, pos, &is_nalu_delim, &layer_id, &temporal_id, &avc_hdr);
499 68165 : if (!ctx->extract) {
500 : skip_nal = GF_FALSE;
501 : }
502 : //we don't serialize nalu delimiter, skip nal
503 0 : else if (!ctx->delim && is_nalu_delim) {
504 : skip_nal = GF_TRUE;
505 : }
506 :
507 :
508 0 : if (skip_nal) {
509 0 : gf_bs_skip_bytes(ctx->bs_r, nal_size);
510 0 : continue;
511 : }
512 :
513 : //insert dsi only after NALUD if any
514 68165 : if (dsi_buf && !is_nalu_delim) {
515 988 : gf_bs_write_data(ctx->bs_w, dsi_buf, dsi_buf_size);
516 988 : ctx->nb_nalu += dsi_nb_nal;
517 : dsi_buf = NULL;
518 :
519 988 : if (!ctx->rcfg) {
520 0 : gf_free(ctx->dsi);
521 0 : ctx->dsi = NULL;
522 0 : ctx->dsi_size = 0;
523 : }
524 : }
525 :
526 68165 : gf_bs_write_u32(ctx->bs_w, 1);
527 68165 : gf_bs_write_data(ctx->bs_w, data+pos, nal_size);
528 :
529 68165 : gf_bs_skip_bytes(ctx->bs_r, nal_size);
530 68165 : ctx->nb_nalu++;
531 : }
532 25487 : gf_filter_pck_merge_properties(pck, dst_pck);
533 25487 : gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
534 :
535 25487 : gf_filter_pck_set_framing(dst_pck, GF_TRUE, GF_TRUE);
536 25487 : gf_filter_pck_send(dst_pck);
537 :
538 25487 : gf_filter_pid_drop_packet(ctx->ipid);
539 :
540 25487 : if (gf_filter_reporting_enabled(filter)) {
541 : char szStatus[1024];
542 :
543 0 : sprintf(szStatus, "%s Annex-B %dx%d % 10d NALU", (ctx->vtype==UFNAL_HEVC) ? "HEVC" : ((ctx->vtype==UFNAL_VVC) ? "VVC" : "AVC|H264"), ctx->width, ctx->height, ctx->nb_nalu);
544 0 : gf_filter_update_status(filter, -1, szStatus);
545 :
546 : }
547 : return GF_OK;
548 : }
549 :
550 67 : static void nalumx_finalize(GF_Filter *filter)
551 : {
552 67 : GF_NALUMxCtx *ctx = gf_filter_get_udta(filter);
553 67 : if (ctx->bs_r) gf_bs_del(ctx->bs_r);
554 67 : if (ctx->bs_w) gf_bs_del(ctx->bs_w);
555 67 : if (ctx->dsi) gf_free(ctx->dsi);
556 67 : if (ctx->dsi_non_rap) gf_free(ctx->dsi_non_rap);
557 67 : }
558 :
559 : static const GF_FilterCapability NALUMxCaps[] =
560 : {
561 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
562 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_AVC),
563 : CAP_UINT(GF_CAPS_INPUT_OUTPUT_OPT,GF_PROP_PID_CODECID, GF_CODECID_AVC_PS),
564 : CAP_UINT(GF_CAPS_INPUT_OUTPUT_OPT,GF_PROP_PID_CODECID, GF_CODECID_SVC),
565 : CAP_UINT(GF_CAPS_INPUT_OUTPUT_OPT,GF_PROP_PID_CODECID, GF_CODECID_MVC),
566 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
567 : CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE),
568 : {0},
569 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
570 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_HEVC),
571 : CAP_UINT(GF_CAPS_INPUT_OUTPUT_OPT,GF_PROP_PID_CODECID, GF_CODECID_LHVC),
572 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
573 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_TILE_BASE, GF_TRUE),
574 : CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE),
575 : {0},
576 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
577 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_VVC),
578 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
579 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_TILE_BASE, GF_TRUE),
580 : CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE),
581 : };
582 :
583 :
584 : #define OFFS(_n) #_n, offsetof(GF_NALUMxCtx, _n)
585 : static const GF_FilterArgs NALUMxArgs[] =
586 : {
587 : { OFFS(rcfg), "force repeating decoder config at each I-frame", GF_PROP_BOOL, "true", NULL, 0},
588 : { OFFS(extract), "layer extraction mode\n"
589 : "- all: extracts all layers\n"
590 : "- base: extract base layer only\n"
591 : "- layer: extract non-base layer(s) only", GF_PROP_UINT, "all", "all|base|layer", GF_FS_ARG_HINT_ADVANCED},
592 : { OFFS(delim), "insert AU Delimiter NAL", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
593 : { OFFS(pps_inband), "inject PPS at each non SAP frame, ignored if rcfg is not set", GF_PROP_BOOL, "false", NULL, 0},
594 : {0}
595 : };
596 :
597 :
598 : GF_FilterRegister NALUMxRegister = {
599 : .name = "ufnalu",
600 : GF_FS_SET_DESCRIPTION("AVC/HEVC to AnnexB writer")
601 : GF_FS_SET_HELP("This filter converts AVC|H264 and HEVC streams into AnnexB format, with inband parameter sets and start codes.")
602 : .private_size = sizeof(GF_NALUMxCtx),
603 : .args = NALUMxArgs,
604 : .finalize = nalumx_finalize,
605 : SETCAPS(NALUMxCaps),
606 : .configure_pid = nalumx_configure_pid,
607 : .process = nalumx_process
608 : };
609 :
610 :
611 2877 : const GF_FilterRegister *nalumx_register(GF_FilterSession *session)
612 : {
613 2877 : return &NALUMxRegister;
614 : }
|