LCOV - code coverage report
Current view: top level - filters - tilesplit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 208 248 83.9 %
Date: 2021-04-29 23:48:07 Functions: 7 7 100.0 %

          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 / tile splitting 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             : 
      27             : #include <gpac/filters.h>
      28             : #include <gpac/avparse.h>
      29             : #include <gpac/constants.h>
      30             : #include <gpac/internal/media_dev.h>
      31             : 
      32             : #if !defined(GPAC_DISABLE_HEVC) && !defined(GPAC_DISABLE_AV_PARSERS)
      33             : 
      34             : typedef struct
      35             : {
      36             :         GF_FilterPid *opid;
      37             :         u32 x, y, w, h;
      38             :         GF_BitStream *pck_bs;
      39             :         u8 *pck_buf;
      40             :         u32 pck_buf_alloc;
      41             :         Bool all_intra;
      42             : } TileSplitPid;
      43             : 
      44             : 
      45             : typedef struct
      46             : {
      47             :         //options
      48             :         GF_PropUIntList tiledrop;
      49             : 
      50             :         //internal
      51             :         GF_FilterPid *ipid;
      52             :         GF_FilterPid *base_opid;
      53             :         u32 base_id;
      54             : 
      55             :         u32 nb_tiles, nb_alloc_tiles;
      56             :         TileSplitPid *opids;
      57             : 
      58             :         HEVCState hevc;
      59             :         u32 nalu_size_length;
      60             : 
      61             :         Bool filter_disabled, passthrough;
      62             :         s32 cur_pps_idx;
      63             : 
      64             :         u32 width, height;
      65             : 
      66             :         GF_BitStream *pck_bs;
      67             :         u8 *pck_buf;
      68             :         u32 pck_buf_alloc;
      69             : } GF_TileSplitCtx;
      70             : 
      71          24 : static void tilesplit_update_pid_props(GF_TileSplitCtx *ctx, TileSplitPid *tinfo)
      72             : {
      73          24 :         gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_WIDTH, &PROP_UINT(tinfo->w) );
      74          24 :         gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(tinfo->h) );
      75             : 
      76             : #if 0
      77             :         GF_PropertyValue pval;
      78             :         pval.type = GF_PROP_VEC2I;
      79             :         pval.value.vec2i.x = ctx->width;
      80             :         pval.value.vec2i.y = ctx->height;
      81             :         gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_SRD_REF, &pval);
      82             : 
      83             :         pval.type = GF_PROP_VEC4I;
      84             :         pval.value.vec4i.x = tinfo->x;
      85             :         pval.value.vec4i.y = tinfo->y;
      86             :         pval.value.vec4i.z = tinfo->w;
      87             :         pval.value.vec4i.w = tinfo->h;
      88             :         gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_SRD, &pval);
      89             : #else
      90             : 
      91          24 :         gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_CROP_POS, &PROP_VEC2I_INT(tinfo->x, tinfo->y) );
      92             : 
      93             : #endif
      94          24 : }
      95             : 
      96           3 : static GF_Err tilesplit_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
      97             : {
      98             :         GF_PropertyValue pval;
      99             :         const GF_PropertyValue *p;
     100             :         GF_HEVCConfig *hvcc;
     101             :         GF_HEVCConfig tile_cfg;
     102             :         HEVC_PPS *pps;
     103             :         HEVC_SPS *sps;
     104             :         u8 *dsi;
     105             :         u32 dsi_size, bitrate;
     106             :         u32 i, j, count, nb_tiles, PicWidthInCtbsY, PicHeightInCtbsY, tile_y, active_tiles;
     107             :         s32 pps_idx=-1, sps_idx=-1;
     108           3 :         GF_TileSplitCtx *ctx = (GF_TileSplitCtx *) gf_filter_get_udta(filter);
     109             : 
     110           3 :         if (is_remove) {
     111           0 :                 if (ctx->ipid == pid) {
     112           0 :                         for (i=0; i<ctx->nb_tiles; i++) {
     113           0 :                                 if (ctx->opids[i].opid) {
     114           0 :                                         gf_filter_pid_remove(ctx->opids[i].opid);
     115           0 :                                         ctx->opids[i].opid = NULL;
     116             :                                 }
     117             :                         }
     118           0 :                         ctx->nb_tiles = 0;
     119           0 :                         ctx->ipid = NULL;
     120             :                 }
     121             :                 return GF_OK;
     122             :         }
     123             : 
     124           3 :         if (!ctx->ipid) {
     125           3 :                 ctx->ipid = pid;
     126           3 :                 ctx->base_opid = gf_filter_pid_new(filter);
     127           3 :                 gf_filter_pid_set_framing_mode(pid, GF_TRUE);
     128             :         }
     129           3 :         gf_filter_pid_copy_properties(ctx->base_opid, pid);
     130             :         //set SABT to true by default for link resolution
     131           3 :         gf_filter_pid_set_property(ctx->base_opid, GF_PROP_PID_TILE_BASE, &PROP_BOOL(GF_TRUE) );
     132             : 
     133           3 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
     134           3 :         if (!p) return GF_OK;
     135             : 
     136           3 :         hvcc = gf_odf_hevc_cfg_read(p->value.data.ptr, p->value.data.size, GF_FALSE);
     137           3 :         if (!hvcc) return GF_NON_COMPLIANT_BITSTREAM;
     138             : 
     139           3 :         ctx->nalu_size_length = hvcc->nal_unit_size;
     140           3 :         memset(&ctx->hevc, 0, sizeof(HEVCState));
     141             : 
     142           3 :         count = gf_list_count(hvcc->param_array);
     143          12 :         for (i=0; i<count; i++) {
     144           9 :                 GF_NALUFFParamArray *ar = gf_list_get(hvcc->param_array, i);
     145          18 :                 for (j=0; j < gf_list_count(ar->nalus); j++) {
     146           9 :                         GF_NALUFFParam *sl = gf_list_get(ar->nalus, j);
     147           9 :                         if (!sl) continue;
     148           9 :                         switch (ar->type) {
     149           3 :                         case GF_HEVC_NALU_PIC_PARAM:
     150           3 :                                 pps_idx = gf_hevc_read_pps(sl->data, sl->size, &ctx->hevc);
     151           3 :                                 break;
     152           3 :                         case GF_HEVC_NALU_SEQ_PARAM:
     153           3 :                                 sps_idx = gf_hevc_read_sps(sl->data, sl->size, &ctx->hevc);
     154           3 :                                 break;
     155           3 :                         case GF_HEVC_NALU_VID_PARAM:
     156           3 :                                 gf_hevc_read_vps(sl->data, sl->size, &ctx->hevc);
     157           3 :                                 break;
     158             :                         }
     159             :                 }
     160             :         }
     161           3 :         if (pps_idx==-1) return GF_NON_COMPLIANT_BITSTREAM;
     162           3 :         if (sps_idx==-1) return GF_NON_COMPLIANT_BITSTREAM;
     163             : 
     164           3 :         if (ctx->hevc.pps[pps_idx].loop_filter_across_tiles_enabled_flag)
     165           0 :                 ctx->filter_disabled = GF_FALSE;
     166             :         else
     167           3 :                 ctx->filter_disabled = GF_TRUE;
     168             : 
     169           3 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
     170           3 :         if (p) ctx->base_id = p->value.uint;
     171             : 
     172           3 :         if (! ctx->hevc.pps[pps_idx].tiles_enabled_flag) {
     173           0 :                 gf_odf_hevc_cfg_del(hvcc);
     174           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[TileSplit] Tiles not enabled, using passthrough\n"));
     175           0 :                 gf_filter_pid_set_property(ctx->base_opid, GF_PROP_PID_TILE_BASE, NULL);
     176           0 :                 ctx->passthrough = GF_TRUE;
     177           0 :                 return GF_OK;
     178             :         }
     179           3 :         ctx->passthrough = GF_FALSE;
     180           3 :         nb_tiles = ctx->hevc.pps[pps_idx].num_tile_columns * ctx->hevc.pps[pps_idx].num_tile_rows;
     181             : 
     182           6 :         while (nb_tiles < ctx->nb_tiles) {
     183           0 :                 ctx->nb_tiles--;
     184           0 :                 if (ctx->opids[ctx->nb_tiles].opid) {
     185           0 :                         gf_filter_pid_remove(ctx->opids[ctx->nb_tiles].opid);
     186           0 :                         ctx->opids[ctx->nb_tiles].opid = NULL;
     187             :                 }
     188             :         }
     189             : 
     190           3 :         if (nb_tiles>ctx->nb_alloc_tiles) {
     191           3 :                 ctx->opids = gf_realloc(ctx->opids, sizeof(TileSplitPid) * nb_tiles);
     192           3 :                 memset(&ctx->opids[ctx->nb_alloc_tiles], 0, sizeof(TileSplitPid) * (nb_tiles-ctx->nb_alloc_tiles) );
     193           3 :                 ctx->nb_alloc_tiles = nb_tiles;
     194             :         }
     195             : 
     196             :         /*setup tile info*/
     197           3 :         ctx->cur_pps_idx = pps_idx;
     198             :         pps = &ctx->hevc.pps[pps_idx];
     199             :         sps = &ctx->hevc.sps[sps_idx];
     200             : 
     201           3 :         ctx->width = sps->width;
     202           3 :         ctx->height = sps->height;
     203             : 
     204           3 :         PicWidthInCtbsY = sps->width / sps->max_CU_width;
     205           3 :         if (PicWidthInCtbsY * sps->max_CU_width < sps->width) PicWidthInCtbsY++;
     206           3 :         PicHeightInCtbsY = sps->height / sps->max_CU_width;
     207           3 :         if (PicHeightInCtbsY * sps->max_CU_width < sps->height) PicHeightInCtbsY++;
     208             : 
     209             :         //setup grid info before sending data
     210             :         //we fill the grid in order of the tiling
     211             :         tile_y = 0;
     212          12 :         for (i=0; i<pps->num_tile_rows; i++) {
     213             :                 u32 tile_x = 0;
     214             :                 u32 tile_height;
     215           9 :                 if (pps->uniform_spacing_flag) {
     216           9 :                         tile_height = (i+1)*PicHeightInCtbsY / pps->num_tile_rows - i * PicHeightInCtbsY / pps->num_tile_rows;
     217             :                 } else {
     218           0 :                         if (i < pps->num_tile_rows-1) {
     219           0 :                                 tile_height = pps->row_height[i];
     220           0 :                         } else if (i) {
     221           0 :                                 tile_height = (PicHeightInCtbsY - pps->row_height[i-1]);
     222             :                         } else {
     223             :                                 tile_height = PicHeightInCtbsY;
     224             :                         }
     225             :                 }
     226             : 
     227          36 :                 for (j=0; j < pps->num_tile_columns; j++) {
     228             :                         TileSplitPid *tinfo;
     229             :                         u32 tile_width;
     230             : 
     231          27 :                         if (pps->uniform_spacing_flag) {
     232          27 :                                 tile_width = (j+1) * PicWidthInCtbsY / pps->num_tile_columns - j * PicWidthInCtbsY / pps->num_tile_columns;
     233             :                         } else {
     234           0 :                                 if (j<pps->num_tile_columns-1) {
     235           0 :                                         tile_width = pps->column_width[j];
     236             :                                 } else {
     237           0 :                                         tile_width = (PicWidthInCtbsY - pps->column_width[j-1]);
     238             :                                 }
     239             :                         }
     240             : 
     241          27 :                         tinfo = &ctx->opids[i * pps->num_tile_columns + j];
     242          27 :                         tinfo->x = tile_x * sps->max_CU_width;
     243          27 :                         tinfo->w = tile_width * sps->max_CU_width;
     244          27 :                         tinfo->y = tile_y * sps->max_CU_width;
     245          27 :                         tinfo->h = tile_height * sps->max_CU_width;
     246          27 :                         tinfo->all_intra = GF_TRUE;
     247             : 
     248          27 :                         if (tinfo->x + tinfo->w > sps->width)
     249           0 :                                 tinfo->w = sps->width - tinfo->x;
     250          27 :                         if (tinfo->y + tinfo->h > sps->height)
     251           9 :                                 tinfo->h = sps->height - tinfo->y;
     252             : 
     253          27 :                         tile_x += tile_width;
     254             :                 }
     255           9 :                 tile_y += tile_height;
     256             :         }
     257             : 
     258           3 :         pval.type = GF_PROP_VEC2I;
     259           3 :         pval.value.vec2i.x = ctx->width;
     260           3 :         pval.value.vec2i.y = ctx->height;
     261             : 
     262             :         memcpy(&tile_cfg, hvcc, sizeof(GF_HEVCConfig));
     263           3 :         tile_cfg.param_array = NULL;
     264           3 :         gf_odf_hevc_cfg_write(&tile_cfg, &dsi, &dsi_size);
     265             : 
     266           3 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_BITRATE);
     267             :         bitrate = 0;
     268           3 :         if (p && (p->value.uint>10000)) {
     269           1 :                 bitrate = p->value.uint - 10000;
     270           1 :                 bitrate /= nb_tiles-ctx->tiledrop.nb_items;
     271             :         }
     272             : 
     273           3 :         const char *pname = gf_filter_pid_get_name(ctx->ipid);
     274           3 :         if (pname) pname = gf_file_basename(pname);
     275           3 :         if (!pname) pname = "video";
     276             : 
     277             : 
     278          30 :         for (i=ctx->nb_tiles; i<nb_tiles; i++) {
     279             :                 char szName[GF_MAX_PATH];
     280          27 :                 TileSplitPid *tinfo = &ctx->opids[i];
     281          27 :                 if (!tinfo->opid) {
     282             :                         Bool drop = GF_FALSE;
     283          21 :                         for (j=0; j<ctx->tiledrop.nb_items; j++) {
     284          24 :                                 if (ctx->tiledrop.vals[j]==i) {
     285             :                                         drop = GF_TRUE;
     286             :                                         break;
     287             :                                 }
     288             : 
     289             :                         }
     290          27 :                         if (!drop)
     291          24 :                                 tinfo->opid = gf_filter_pid_new(filter);
     292             :                 }
     293             : 
     294          27 :                 if (!tinfo->opid) continue;
     295             : 
     296          24 :                 gf_filter_pid_copy_properties(tinfo->opid, pid);
     297          24 :                 gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_HEVC_TILES) );
     298          24 :                 if (dsi)
     299          24 :                         gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA(dsi, dsi_size) );
     300             :                 else
     301           0 :                         gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
     302             : 
     303          24 :                 gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_BITRATE, bitrate ? &PROP_UINT(bitrate) : NULL);
     304             : 
     305          24 :                 gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_ID, &PROP_UINT(ctx->base_id + i + 1 ) );
     306          24 :                 gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_TILE_ID, &PROP_UINT(i + 1 ) );
     307          24 :                 gf_filter_pid_set_property(tinfo->opid, GF_PROP_PID_DEPENDENCY_ID, &PROP_UINT(ctx->base_id) );
     308          24 :                 tilesplit_update_pid_props(ctx, tinfo);
     309             : 
     310             :                 sprintf(szName, "%s_tile%d", pname, i+1);
     311          24 :                 gf_filter_pid_set_name(tinfo->opid, szName);
     312             :         }
     313           3 :         if (dsi) gf_free(dsi);
     314           3 :         ctx->nb_tiles = nb_tiles;
     315             :         active_tiles = 0;
     316             :         //setup tbas track ref
     317          30 :         for (i=0; i<nb_tiles; i++) {
     318          27 :                 if (!ctx->opids[i].opid)
     319           3 :                         continue;
     320          24 :                 pval.type = GF_PROP_4CC_LIST;
     321          24 :                 pval.value.uint_list.nb_items = 1;
     322          24 :                 pval.value.uint_list.vals = &ctx->base_id;
     323          24 :                 active_tiles ++;
     324          24 :                 gf_filter_pid_set_property_str(ctx->opids[i].opid, "isom:tbas", &pval);
     325             :         }
     326             :         //setup sabt track ref
     327           3 :         pval.type = GF_PROP_4CC_LIST;
     328           3 :         pval.value.uint_list.nb_items = active_tiles;
     329           3 :         pval.value.uint_list.vals = gf_malloc(sizeof(u32) * active_tiles);
     330             :         active_tiles = 0;
     331          30 :         for (i=0; i<nb_tiles; i++) {
     332          27 :                 if (!ctx->opids[i].opid)
     333           3 :                         continue;
     334          24 :                 pval.value.uint_list.vals[active_tiles] = ctx->base_id + i + 1;
     335          24 :                 active_tiles++;
     336             :         }
     337           3 :         gf_filter_pid_set_property_str(ctx->base_opid, "isom:sabt", &pval);
     338           3 :         gf_free(pval.value.uint_list.vals);
     339             : 
     340           3 :         gf_filter_pid_set_property(ctx->base_opid, GF_PROP_PID_ORIG_SIZE, &PROP_VEC2I_INT(ctx->width, ctx->height) );
     341           3 :         gf_filter_pid_set_property(ctx->base_opid, GF_PROP_PID_BITRATE, bitrate ? &PROP_UINT(10000) : NULL);
     342             : 
     343           3 :         gf_odf_hevc_cfg_del(hvcc);
     344           3 :         return GF_OK;
     345             : }
     346             : 
     347           3 : static GF_Err tilesplit_set_eos(GF_Filter *filter, GF_TileSplitCtx *ctx)
     348             : {
     349             :         u32 i;
     350          27 :         for (i=0; i<ctx->nb_tiles; i++) {
     351          27 :                 if (ctx->opids[i].opid)
     352          24 :                         gf_filter_pid_set_eos(ctx->opids[i].opid);
     353             :         }
     354           3 :         gf_filter_pid_set_eos(ctx->base_opid);
     355           3 :         return GF_EOS;
     356             : }
     357             : 
     358             : u32 hevc_get_tile_id(HEVCState *hevc, u32 *tile_x, u32 *tile_y, u32 *tile_width, u32 *tile_height);
     359             : 
     360        4575 : static GF_Err tilesplit_process(GF_Filter *filter)
     361             : {
     362        4575 :         GF_TileSplitCtx *ctx = (GF_TileSplitCtx *) gf_filter_get_udta(filter);
     363             :         GF_FilterPacket *in_pck, *opck;
     364             :         u32 pck_size, i;
     365             :         GF_Err e = GF_OK;
     366             :         const u8 *in_data;
     367             :         u8 *output;
     368             : 
     369        4575 :         in_pck = gf_filter_pid_get_packet(ctx->ipid);
     370        4575 :         if (!in_pck) {
     371        2325 :                 if (gf_filter_pid_is_eos(ctx->ipid)) {
     372           3 :                         return tilesplit_set_eos(filter, ctx);
     373             :                 }
     374             :                 return GF_OK;
     375             :         }
     376             : 
     377        2250 :         if (ctx->passthrough) {
     378           0 :                 gf_filter_pck_forward(in_pck, ctx->base_opid);
     379           0 :                 gf_filter_pid_drop_packet(ctx->ipid);
     380           0 :                 return GF_OK;
     381             :         }
     382             : 
     383        2250 :         in_data = gf_filter_pck_get_data(in_pck, &pck_size);
     384        2250 :         if (!in_data) {
     385           0 :                 gf_filter_pid_drop_packet(ctx->ipid);
     386           0 :                 return GF_OK;
     387             :         }
     388             : 
     389        2250 :         if (!ctx->pck_bs) ctx->pck_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     390        2247 :         else gf_bs_reassign_buffer(ctx->pck_bs, ctx->pck_buf, ctx->pck_buf_alloc);
     391             : 
     392       20250 :         for (i=0; i<ctx->nb_tiles; i++) {
     393       20250 :                 TileSplitPid *tinfo = &ctx->opids[i];
     394       20250 :                 if (!tinfo->opid)
     395        2250 :                         continue;
     396       18000 :                 if (!tinfo->pck_bs) tinfo->pck_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     397       17976 :                 else gf_bs_reassign_buffer(tinfo->pck_bs, tinfo->pck_buf, tinfo->pck_buf_alloc);
     398             :         }
     399             : 
     400       24753 :         while (pck_size) {
     401             :                 TileSplitPid *tinfo;
     402             :                 u8 temporal_id, layer_id;
     403       22503 :                 u8 nal_type = 0;
     404             :                 u32 nalu_size = 0;
     405             :                 s32 ret;
     406             :                 u32 cur_tile;
     407             :                 u32 tx, ty, tw, th;
     408      112515 :                 for (i=0; i<ctx->nalu_size_length; i++) {
     409       90012 :                         nalu_size = (nalu_size<<8) + in_data[i];
     410             :                 }
     411             : 
     412       22503 :                 if (pck_size < nalu_size + ctx->nalu_size_length) {
     413           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[TileSplit] Corrupted NAL size, %d indicated but %d remaining\n", nalu_size + ctx->nalu_size_length, pck_size));
     414           0 :                         break;
     415             :                 }
     416             : 
     417       22503 :                 ret = gf_hevc_parse_nalu((u8 *) in_data + ctx->nalu_size_length, nalu_size, &ctx->hevc, &nal_type, &temporal_id, &layer_id);
     418             : 
     419             :                 //error parsing NAL, set nal to fallback to regular import
     420       22503 :                 if (ret<0) nal_type = GF_HEVC_NALU_VID_PARAM;
     421             : 
     422       22503 :                 switch (nal_type) {
     423       20250 :                 case GF_HEVC_NALU_SLICE_TRAIL_N:
     424             :                 case GF_HEVC_NALU_SLICE_TRAIL_R:
     425             :                 case GF_HEVC_NALU_SLICE_TSA_N:
     426             :                 case GF_HEVC_NALU_SLICE_TSA_R:
     427             :                 case GF_HEVC_NALU_SLICE_STSA_N:
     428             :                 case GF_HEVC_NALU_SLICE_STSA_R:
     429             :                 case GF_HEVC_NALU_SLICE_BLA_W_LP:
     430             :                 case GF_HEVC_NALU_SLICE_BLA_W_DLP:
     431             :                 case GF_HEVC_NALU_SLICE_BLA_N_LP:
     432             :                 case GF_HEVC_NALU_SLICE_IDR_W_DLP:
     433             :                 case GF_HEVC_NALU_SLICE_IDR_N_LP:
     434             :                 case GF_HEVC_NALU_SLICE_CRA:
     435             :                 case GF_HEVC_NALU_SLICE_RADL_R:
     436             :                 case GF_HEVC_NALU_SLICE_RADL_N:
     437             :                 case GF_HEVC_NALU_SLICE_RASL_R:
     438             :                 case GF_HEVC_NALU_SLICE_RASL_N:
     439       20250 :                         tx = ty = tw = th = 0;
     440       20250 :                         cur_tile = hevc_get_tile_id(&ctx->hevc, &tx, &ty, &tw, &th);
     441       20250 :                         if (cur_tile >= ctx->nb_tiles) {
     442           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[TileSplit] Tile index %d is greater than number of tiles %d in PPS\n", cur_tile, ctx->nb_tiles));
     443             :                                 e = GF_NON_COMPLIANT_BITSTREAM;
     444           0 :                                 goto err_exit;
     445             :                         }
     446       20250 :                         tinfo = &ctx->opids[cur_tile];
     447       20250 :                         if (!tinfo->opid)
     448             :                                 break;
     449             : 
     450       18000 :                         if ((tinfo->x != tx) || (tinfo->w != tw) || (tinfo->y != ty) || (tinfo->h != th)) {
     451           0 :                                 tinfo->x = tx;
     452           0 :                                 tinfo->y = ty;
     453           0 :                                 tinfo->w = tw;
     454           0 :                                 tinfo->h = th;
     455             : 
     456           0 :                                 tilesplit_update_pid_props(ctx, tinfo);
     457             :                         }
     458             : 
     459       18000 :                         if (ctx->hevc.s_info.slice_type != GF_HEVC_SLICE_TYPE_I) {
     460       17280 :                                 tinfo->all_intra = GF_FALSE;
     461             :                         }
     462             : 
     463       18000 :                         gf_bs_write_data(tinfo->pck_bs, (u8 *) in_data, nalu_size + ctx->nalu_size_length);
     464       18000 :                         break;
     465             :                 //note we don't need to care about sps or pps here, they are not in the bitstream
     466        2253 :                 default:
     467        2253 :                         gf_bs_write_data(ctx->pck_bs, (u8 *) in_data, nalu_size + ctx->nalu_size_length);
     468        2253 :                         break;
     469             :                 }
     470             : 
     471       24753 :                 in_data += nalu_size + ctx->nalu_size_length;
     472       22503 :                 pck_size -= nalu_size + ctx->nalu_size_length;
     473             :         }
     474             : 
     475        2250 : err_exit:
     476             :         //and flush
     477             : 
     478        2250 :         gf_bs_get_content_no_truncate(ctx->pck_bs, &ctx->pck_buf, &pck_size, &ctx->pck_buf_alloc);
     479        2250 :         opck = gf_filter_pck_new_alloc(ctx->base_opid, pck_size, &output);
     480        2250 :         if (opck) {
     481        2250 :                 memcpy(output, ctx->pck_buf, pck_size);
     482        2250 :                 gf_filter_pck_merge_properties(in_pck, opck);
     483        2250 :                 gf_filter_pck_send(opck);
     484             :         } else {
     485             :                 e = GF_OUT_OF_MEM;
     486             :         }
     487             : 
     488       20250 :         for (i=0; i<ctx->nb_tiles; i++) {
     489       20250 :                 TileSplitPid *tinfo = &ctx->opids[i];
     490       20250 :                 if (!tinfo->opid) continue;
     491             : 
     492       18000 :                 gf_bs_get_content_no_truncate(tinfo->pck_bs, &tinfo->pck_buf, &pck_size, &tinfo->pck_buf_alloc);
     493       18000 :                 opck = gf_filter_pck_new_alloc(tinfo->opid, pck_size, &output);
     494       18000 :                 if (opck) {
     495       18000 :                         memcpy(output, tinfo->pck_buf, pck_size);
     496       18000 :                         gf_filter_pck_merge_properties(in_pck, opck);
     497       18000 :                         gf_filter_pck_send(opck);
     498             :                 } else {
     499             :                         e = GF_OUT_OF_MEM;
     500             :                 }
     501             :         }
     502             : 
     503        2250 :         gf_filter_pid_drop_packet(ctx->ipid);
     504        2250 :         return e;
     505             : }
     506             : 
     507           3 : static GF_Err tilesplit_initialize(GF_Filter *filter)
     508             : {
     509             : //      GF_TileSplitCtx *ctx = (GF_TileSplitCtx *) gf_filter_get_udta(filter);
     510             : 
     511           3 :         return GF_OK;
     512             : }
     513             : 
     514           3 : static void tilesplit_finalize(GF_Filter *filter)
     515             : {
     516             :         u32 i;
     517           3 :         GF_TileSplitCtx *ctx = (GF_TileSplitCtx *) gf_filter_get_udta(filter);
     518             : 
     519          30 :         for (i=0; i<ctx->nb_alloc_tiles; i++) {
     520          27 :                 TileSplitPid *tinfo = &ctx->opids[i];
     521          27 :                 if (tinfo->pck_buf) gf_free(tinfo->pck_buf);
     522          27 :                 if (tinfo->pck_bs) gf_bs_del(tinfo->pck_bs);
     523             :         }
     524           3 :         if (ctx->opids)
     525           3 :                 gf_free(ctx->opids);
     526             : 
     527           3 :         if (ctx->pck_bs) gf_bs_del(ctx->pck_bs);
     528           3 :         if (ctx->pck_buf) gf_free(ctx->pck_buf);
     529           3 : }
     530             : 
     531             : #else
     532             : static GF_Err tilesplit_process(GF_Filter *filter)
     533             : {
     534             :         return GF_NOT_SUPPORTED;
     535             : }
     536             : #endif
     537             : 
     538             : static const GF_FilterCapability TileSplitCaps[] =
     539             : {
     540             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     541             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     542             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_HEVC),
     543             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_TILE_BASE, GF_TRUE),
     544             : 
     545             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     546             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_HEVC),
     547             :         CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_TILE_BASE, GF_TRUE),
     548             :         {0},
     549             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     550             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
     551             :         CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_HEVC),
     552             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_TILE_BASE, GF_TRUE),
     553             : 
     554             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
     555             :         CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_HEVC_TILES)
     556             : };
     557             : 
     558             : #define OFFS(_n)        #_n, offsetof(GF_TileSplitCtx, _n)
     559             : 
     560             : static const GF_FilterArgs TileSplitArgs[] =
     561             : {
     562             :         { OFFS(tiledrop), "specify indexes of tiles to drop (0-based, in tile raster scan order)", GF_PROP_UINT_LIST, "", NULL, GF_FS_ARG_UPDATE},
     563             :         {0}
     564             : };
     565             : 
     566             : GF_FilterRegister TileSplitRegister = {
     567             :         .name = "tilesplit",
     568             :         .flags = GF_FS_REG_EXPLICIT_ONLY,
     569             :         GF_FS_SET_DESCRIPTION("HEVC tile bitstream splitter")
     570             :         GF_FS_SET_HELP("This filter splits an HEVC tiled stream into tiled HEVC streams (`hvt1` or `hvt2` in isobmff)."
     571             :         "\n"
     572             :         "The filter will move to passthrough mode if the bitstream is not tiled.\n"
     573             :         "If the `Bitrate` property is set on the input PID, the output tile PIDs will have a bitrate set to `(Bitrate - 10k)/nb_opids`, 10 kbps being reserved for the base.\n"
     574             :         "\n"
     575             :         "Each tile PID will be assigned the following properties:\n"
     576             :         "- `ID`: equal to the base PID ID (same as input) plus the 1-based index of the tile in raster scan order.\n"
     577             :         "- `TileID`: equal to the 1-based index of the tile in raster scan order.\n"
     578             :         "\n"
     579             :         "Warning: The filter does not check if tiles are independently-coded (MCTS) !\n"
     580             :         "\n"
     581             :         "Warning: Support for dynamic changes of tiling grid has not been tested !\n"
     582             :         )
     583             :         .private_size = sizeof(GF_TileSplitCtx),
     584             :         SETCAPS(TileSplitCaps),
     585             : #if !defined(GPAC_DISABLE_HEVC) && !defined(GPAC_DISABLE_AV_PARSERS)
     586             :         .initialize = tilesplit_initialize,
     587             :         .finalize = tilesplit_finalize,
     588             :         .args = TileSplitArgs,
     589             :         .configure_pid = tilesplit_configure_pid,
     590             : #endif
     591             :         .process = tilesplit_process,
     592             : 
     593             : };
     594             : 
     595             : 
     596        2877 : const GF_FilterRegister *tilesplit_register(GF_FilterSession *session)
     597             : {
     598             : #if defined(GPAC_DISABLE_HEVC) || defined(GPAC_DISABLE_AV_PARSERS)
     599             :         if (!gf_opts_get_bool("temp", "gendoc"))
     600             :                 return NULL;
     601             :         TileSplitRegister.version = "! Warning: NOT AVAILABLE IN THIS BUILD !";
     602             : #endif
     603        2877 :         return &TileSplitRegister;
     604             : }
     605             : 
     606             : 

Generated by: LCOV version 1.13