LCOV - code coverage report
Current view: top level - filters - rewrite_nalu.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 211 295 71.5 %
Date: 2021-04-29 23:48:07 Functions: 8 9 88.9 %

          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             : }

Generated by: LCOV version 1.13