  void Compute(OpKernelContext *ctx) override {
    const Tensor *indices_t, *values_t, *shape_t, *dense_t;
    OP_REQUIRES_OK(ctx, ctx->input("sp_indices", &indices_t));
    OP_REQUIRES_OK(ctx, ctx->input("sp_values", &values_t));
    OP_REQUIRES_OK(ctx, ctx->input("sp_shape", &shape_t));
    OP_REQUIRES_OK(ctx, ctx->input("dense", &dense_t));

    // Validations.
    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(indices_t->shape()),
                errors::InvalidArgument(
                    "Input sp_indices should be a matrix but received shape: ",
                    indices_t->shape().DebugString()));
    OP_REQUIRES(ctx,
                TensorShapeUtils::IsVector(values_t->shape()) &&
                    TensorShapeUtils::IsVector(shape_t->shape()),
                errors::InvalidArgument(
                    "Inputs sp_values and sp_shape should be vectors "
                    "but received shapes: ",
                    values_t->shape().DebugString(), " and ",
                    shape_t->shape().DebugString()));
    OP_REQUIRES(
        ctx, values_t->dim_size(0) == indices_t->dim_size(0),
        errors::InvalidArgument(
            "The first dimension of values and indices should match. (",
            values_t->dim_size(0), " vs. ", indices_t->dim_size(0), ")"));

    const auto indices_mat = indices_t->matrix<int64>();
    const auto shape_vec = shape_t->vec<int64>();
    const auto lhs_dims = BCast::FromShape(TensorShape(shape_vec));
    const auto rhs_dims = BCast::FromShape(dense_t->shape());
    BCast b(lhs_dims, rhs_dims, false);  // false for keeping the same num dims.

    // True iff (size(lhs) >= size(rhs)) and all dims in lhs is greater or equal
    // to dims in rhs (from right to left).
    auto VecGreaterEq = [](ArraySlice<int64> lhs, ArraySlice<int64> rhs) {
      if (lhs.size() < rhs.size()) return false;
      for (size_t i = 0; i < rhs.size(); ++i) {
        if (lhs[lhs.size() - 1 - i] < rhs[rhs.size() - 1 - i]) return false;
      }
      return true;
    };
    OP_REQUIRES(ctx, VecGreaterEq(lhs_dims, rhs_dims) && b.IsValid(),
                errors::InvalidArgument(
                    "SparseDenseBinaryOpShared broadcasts dense to sparse "
                    "only; got incompatible shapes: [",
                    absl::StrJoin(lhs_dims, ","), "] vs. [",
                    absl::StrJoin(rhs_dims, ","), "]"));

    Tensor *output_values = nullptr;
    Tensor dense_gathered;
    const int64 nnz = indices_t->dim_size(0);
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(0, TensorShape({nnz}), &output_values));
    OP_REQUIRES_OK(
        ctx, ctx->allocate_temp(DataTypeToEnum<T>::value, TensorShape({nnz}),
                                &dense_gathered));
    bool op_is_div = false;
    if (absl::StrContains(ctx->op_kernel().type_string_view(), "Div")) {
      op_is_div = true;
    }
    // Pulls relevant entries from the dense side, with reshape and broadcasting
    // *of the dense side* taken into account.  Use a TensorRef to avoid blowing
    // up memory.
    //
    // We can directly use the sparse indices to look up dense side, because
    // "b.y_reshape()" and "b.y_bcast()" are guaranteed to have rank "ndims".
    auto dense_gathered_flat = dense_gathered.flat<T>();
    const int ndims = lhs_dims.size();
    switch (ndims) {
#define CASE(NDIM)                                                             \
  case NDIM: {                                                                 \
    TensorRef<Eigen::Tensor<const T, NDIM, Eigen::RowMajor>> rhs_ref =         \
        dense_t->shaped<T, NDIM>(b.y_reshape())                                \
            .broadcast(BCast::ToIndexArray<NDIM>(b.y_bcast()));                \
    Eigen::array<Eigen::DenseIndex, NDIM> idx;                                 \
    bool indices_valid = true;                                                 \
    for (int i = 0; i < nnz; ++i) {                                            \
      for (int d = 0; d < NDIM; ++d) {                                         \
        idx[d] = internal::SubtleMustCopy(indices_mat(i, d));                  \
        if (!FastBoundsCheck(idx[d], rhs_ref.dimension(d))) {                  \
          indices_valid = false;                                               \
        }                                                                      \
      }                                                                        \
      OP_REQUIRES(                                                             \
          ctx, indices_valid,                                                  \
          errors::InvalidArgument("Provided indices are out-of-bounds w.r.t. " \
                                  "dense side with broadcasted shape"));       \
      dense_gathered_flat(i) = rhs_ref.coeff(idx);                             \
      if (op_is_div) {                                                         \
        OP_REQUIRES(ctx, dense_gathered_flat(i) != 0,                          \
                    errors::InvalidArgument(                                   \
                        "SparseDenseCwiseDiv cannot divide by zero,"           \
                        "but input dense tensor contains zero "));             \
      }                                                                        \
    }                                                                          \
    break;                                                                     \
  }

      CASE(1);
      CASE(2);
      CASE(3);
      CASE(4);
      CASE(5);
      default:
        OP_REQUIRES(
            ctx, false,
            errors::InvalidArgument("Only tensors with ranks between 1 and 5 "
                                    "are currently supported.  Tensor rank: ",
                                    ndims));
#undef CASE
    }

    output_values->flat<T>().device(ctx->eigen_device<Device>()) =
        values_t->flat<T>().binaryExpr(dense_gathered_flat,
                                       typename Functor::func());
  }

Disallow division by zero FPE in tf.raw_ops.SparseDenseCwiseDiv

PiperOrigin-RevId: 383959809
Change-Id: Ibe88458bdf66a686c93e354b8255dec94285c560


const GF_FilterRegister *av1dmx_register(GF_FilterSession *session)
{
	return NULL;
}

fixed #1719


static const char * av1dmx_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
{
	GF_BitStream *bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
	Bool res;
	u32 lt;
	const char *mime = "video/av1";
	lt = gf_log_get_tool_level(GF_LOG_CODING);
	gf_log_set_tool_level(GF_LOG_CODING, GF_LOG_QUIET);

	res = gf_media_probe_ivf(bs);
	if (res) {
		*score = GF_FPROBE_SUPPORTED;
		mime = "video/x-ivf";
	} else {
		res = gf_media_aom_probe_annexb(bs);
		if (res) *score = GF_FPROBE_SUPPORTED;
		else {
			AV1State state;
			GF_Err e;
			u32 nb_units = 0;

			gf_av1_init_state(&state);
			state.config = gf_odf_av1_cfg_new();
			while (gf_bs_available(bs)) {
				e = aom_av1_parse_temporal_unit_from_section5(bs, &state);
				if ((e==GF_OK) || (nb_units && (e==GF_BUFFER_TOO_SMALL) ) ) {
					if (!nb_units || gf_list_count(state.frame_state.header_obus) || gf_list_count(state.frame_state.frame_obus)) {
						nb_units++;
						if (e==GF_BUFFER_TOO_SMALL)
							nb_units++;
					} else
						break;
				} else {
					break;
				}
				gf_av1_reset_state(&state, GF_FALSE);
				if (nb_units>2) break;
			}
			gf_odf_av1_cfg_del(state.config);
			gf_av1_reset_state(&state, GF_TRUE);
			if (nb_units>2) {
				res = GF_TRUE;
				*score = GF_FPROBE_MAYBE_SUPPORTED;
			}
		}
	}

	gf_log_set_tool_level(GF_LOG_CODING, lt);

	gf_bs_del(bs);
	if (res) return mime;
	return NULL;
}

fixed #1719


static GFINLINE void av1dmx_update_cts(GF_AV1DmxCtx *ctx)
{
	assert(ctx->cur_fps.num);
	assert(ctx->cur_fps.den);

	if (ctx->timescale) {
		u64 inc = ctx->cur_fps.den;
		inc *= ctx->timescale;
		inc /= ctx->cur_fps.num;
		ctx->cts += inc;
	} else {
		ctx->cts += ctx->cur_fps.den;
	}
}

fixed #1719


static void av1dmx_check_dur(GF_Filter *filter, GF_AV1DmxCtx *ctx)
{
	FILE *stream;
	GF_Err e;
	GF_BitStream *bs;
	u64 duration, cur_dur, last_cdur, rate;
	AV1State av1state;
	const char *filepath=NULL;
	const GF_PropertyValue *p;
	if (!ctx->opid || ctx->timescale || ctx->file_loaded) return;

	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILE_CACHED);
	if (p && p->value.boolean) ctx->file_loaded = GF_TRUE;

	p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_FILEPATH);
	if (!p || !p->value.string || !strncmp(p->value.string, "gmem://", 7)) {
		ctx->is_file = GF_FALSE;
		ctx->file_loaded = GF_TRUE;
		return;
	}
	filepath = p->value.string;
	ctx->is_file = GF_TRUE;

	if (ctx->index<0) {
		if (gf_opts_get_bool("temp", "force_indexing")) {
			ctx->index = 1.0;
		} else {
			p = gf_filter_pid_get_property(ctx->ipid, GF_PROP_PID_DOWN_SIZE);
			if (!p || (p->value.longuint > 100000000)) {
				GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[AV1/VP9] Source file larger than 100M, skipping indexing\n"));
			} else {
				ctx->index = -ctx->index;
			}
		}
	}
	if (ctx->index<=0)
		return;

	stream = gf_fopen(filepath, "rb");
	if (!stream) return;

	ctx->index_size = 0;

	bs = gf_bs_from_file(stream, GF_BITSTREAM_READ);

	if (ctx->file_hdr_size) {
		gf_bs_seek(bs, ctx->file_hdr_size);
	}
	gf_av1_init_state(&av1state);
	av1state.skip_frames = GF_TRUE;
	av1state.config = gf_odf_av1_cfg_new();

	duration = 0;
	cur_dur = last_cdur = 0;
	while (gf_bs_available(bs)) {
		Bool is_sap=GF_FALSE;
		u64 pts = GF_FILTER_NO_TS;
		u64 frame_start = gf_bs_get_position(bs);
		gf_av1_reset_state(&av1state, GF_FALSE);

		/*we process each TU and extract only the necessary OBUs*/
		switch (ctx->bsmode) {
		case OBUs:
			e = aom_av1_parse_temporal_unit_from_section5(bs, &av1state);
			break;
		case AnnexB:
			e = aom_av1_parse_temporal_unit_from_annexb(bs, &av1state);
			break;
		case IVF:
			if (ctx->is_av1) {
				e = aom_av1_parse_temporal_unit_from_ivf(bs, &av1state);
			} else {
				u64 frame_size;
				e = gf_media_parse_ivf_frame_header(bs, &frame_size, &pts);
				if (!e) gf_bs_skip_bytes(bs, frame_size);
		 		is_sap = GF_TRUE;
			}
			break;
		default:
			e = GF_NOT_SUPPORTED;
		}
		if (e)
		 	break;

		if (pts != GF_FILTER_NO_TS) {
			duration = pts;
			cur_dur = pts - last_cdur;
		} else {
			duration += ctx->cur_fps.den;
			cur_dur += ctx->cur_fps.den;
		}
		if (av1state.frame_state.key_frame)
		 	is_sap = GF_TRUE;

		//only index at I-frame start
		if (frame_start && is_sap && (cur_dur > ctx->index * ctx->cur_fps.num) ) {
			if (!ctx->index_alloc_size) ctx->index_alloc_size = 10;
			else if (ctx->index_alloc_size == ctx->index_size) ctx->index_alloc_size *= 2;
			ctx->indexes = gf_realloc(ctx->indexes, sizeof(AV1Idx)*ctx->index_alloc_size);
			ctx->indexes[ctx->index_size].pos = frame_start;
			ctx->indexes[ctx->index_size].duration = (Double) duration;
			ctx->indexes[ctx->index_size].duration /= ctx->cur_fps.num;
			ctx->index_size ++;
			last_cdur = cur_dur;
			cur_dur = 0;
		}
	}
	rate = gf_bs_get_position(bs);
	gf_bs_del(bs);
	gf_fclose(stream);
	gf_odf_av1_cfg_del(av1state.config);
	gf_av1_reset_state(&av1state, GF_TRUE);

	if (!ctx->duration.num || (ctx->duration.num  * ctx->cur_fps.num != duration * ctx->duration.den)) {
		ctx->duration.num = (s32) duration;
		ctx->duration.den = ctx->cur_fps.num;

		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));

		if (duration && (!gf_sys_is_test_mode() || gf_opts_get_bool("temp", "force_indexing"))) {
			rate *= 8 * ctx->duration.den;
			rate /= ctx->duration.num;
			ctx->bitrate = (u32) rate;
		}
	}

	//currently not supported because of OBU size field rewrite - could work on some streams but we would
	//need to analyse all OBUs in the stream for that
	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CAN_DATAREF, & PROP_BOOL(GF_FALSE) );
}

fixed #1719


static void av1dmx_check_pid(GF_Filter *filter, GF_AV1DmxCtx *ctx)
{
	u8 *dsi;
	u32 dsi_size, crc;

	//no config or no config change
	if (ctx->is_av1 && !gf_list_count(ctx->state.frame_state.header_obus)) return;

	if (!ctx->opid) {
		ctx->opid = gf_filter_pid_new(filter);
		av1dmx_check_dur(filter, ctx);
	}
	dsi = NULL;
	dsi_size = 0;

	if (ctx->vp_cfg) {
		gf_odf_vp_cfg_write(ctx->vp_cfg, &dsi, &dsi_size, ctx->vp_cfg->codec_initdata_size ? GF_TRUE : GF_FALSE);
	} else if (ctx->is_av1) {
		//first or config changed, compute dsi
		while (gf_list_count(ctx->state.config->obu_array)) {
			GF_AV1_OBUArrayEntry *a = (GF_AV1_OBUArrayEntry*) gf_list_pop_back(ctx->state.config->obu_array);
			if (a->obu) gf_free(a->obu);
			gf_free(a);
		}
		dsi = NULL;
		dsi_size = 0;
		while (gf_list_count(ctx->state.frame_state.header_obus)) {
			GF_AV1_OBUArrayEntry *a = (GF_AV1_OBUArrayEntry*) gf_list_get(ctx->state.frame_state.header_obus, 0);
			gf_list_add(ctx->state.config->obu_array, a);
			gf_list_rem(ctx->state.frame_state.header_obus, 0);
		}
		gf_odf_av1_cfg_write(ctx->state.config, &dsi, &dsi_size);

		if ((!ctx->fps.num || !ctx->fps.den) && ctx->state.tb_num && ctx->state.tb_den && ! ( (ctx->state.tb_num<=1) && (ctx->state.tb_den<=1) ) ) {
			ctx->cur_fps.num = ctx->state.tb_num;
			ctx->cur_fps.den = ctx->state.tb_den;
		}

	}
	crc = gf_crc_32(dsi, dsi_size);

	if (crc == ctx->dsi_crc) {
		gf_free(dsi);
		return;
	}
	ctx->dsi_crc = crc;

	//copy properties at init or reconfig
	gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, & PROP_UINT(GF_STREAM_VISUAL));

	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, & PROP_UINT(ctx->codecid));

	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, & PROP_UINT(ctx->cur_fps.num));
	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FPS, & PROP_FRAC(ctx->cur_fps));
	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, & PROP_UINT(ctx->state.width));
	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, & PROP_UINT(ctx->state.height));

	if (ctx->duration.num)
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DURATION, & PROP_FRAC64(ctx->duration));

	if (ctx->bitrate) {
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_BITRATE, & PROP_UINT(ctx->bitrate));
	}

	if (dsi && dsi_size)
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, & PROP_DATA_NO_COPY(dsi, dsi_size));

	if (ctx->is_file && ctx->index) {
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PLAYBACK_MODE, & PROP_UINT(GF_PLAYBACK_MODE_FASTFORWARD) );
	}

	if (ctx->is_av1) {
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_PRIMARIES, & PROP_UINT(ctx->state.color_primaries) );
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_TRANSFER, & PROP_UINT(ctx->state.transfer_characteristics) );
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_MX, & PROP_UINT(ctx->state.matrix_coefficients) );
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_COLR_RANGE, & PROP_BOOL(ctx->state.color_range) );
	}
}

fixed #1719


GF_Err av1dmx_parse_vp9(GF_Filter *filter, GF_AV1DmxCtx *ctx)
{
	Bool key_frame = GF_FALSE;
	u64 frame_size = 0, pts = 0;
	u64 pos, pos_ivf_hdr;
	u32 width = 0, height = 0, renderWidth, renderHeight;
	u32 num_frames_in_superframe = 0, superframe_index_size = 0, i = 0;
	u32 frame_sizes[VP9_MAX_FRAMES_IN_SUPERFRAME];
	u8 *output;
	GF_Err e;

	pos_ivf_hdr = gf_bs_get_position(ctx->bs);
	e = gf_media_parse_ivf_frame_header(ctx->bs, &frame_size, &pts);
	if (e) return e;

	pos = gf_bs_get_position(ctx->bs);
	if (gf_bs_available(ctx->bs) < frame_size) {
		gf_bs_seek(ctx->bs, pos_ivf_hdr);
		return GF_EOS;
	}

	if (ctx->pts_from_file) {
		pts += ctx->cumulated_dur;
		if (ctx->last_pts && (ctx->last_pts>pts)) {
			pts -= ctx->cumulated_dur;
			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF/VP9] Corrupted timestamp "LLU" less than previous timestamp "LLU", assuming concatenation\n", pts, ctx->last_pts));
			ctx->cumulated_dur = ctx->last_pts + ctx->cur_fps.den;
			ctx->cumulated_dur -= pts;
			pts = ctx->cumulated_dur;
		}
		ctx->last_pts = pts;
	}

	/*check if it is a superframe*/
	e = gf_media_vp9_parse_superframe(ctx->bs, frame_size, &num_frames_in_superframe, frame_sizes, &superframe_index_size);
	if (e) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VP9Dmx] Error parsing superframe structure\n"));
		return e;
	}

	for (i = 0; i < num_frames_in_superframe; ++i) {
		u64 pos2 = gf_bs_get_position(ctx->bs);
		if (gf_media_vp9_parse_sample(ctx->bs, ctx->vp_cfg, &key_frame, &width, &height, &renderWidth, &renderHeight) != GF_OK) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VP9Dmx] Error parsing frame\n"));
			return e;
		}
		e = gf_bs_seek(ctx->bs, pos2 + frame_sizes[i]);
		if (e) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[VP9Dmx] Seek bad param (offset "LLU") (1)", pos2 + frame_sizes[i]));
			return e;
		}
	}
	if (gf_bs_get_position(ctx->bs) + superframe_index_size != pos + frame_size) {
		GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[VP9Dmx] Inconsistent IVF frame size of "LLU" bytes.\n", frame_size));
		GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("      Detected %d frames (+ %d bytes for the superframe index):\n", num_frames_in_superframe, superframe_index_size));
		for (i = 0; i < num_frames_in_superframe; ++i) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("         superframe %d, size is %u bytes\n", i, frame_sizes[i]));
		}
		GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("\n"));
	}
	e = gf_bs_seek(ctx->bs, pos + frame_size);
	if (e) {
		GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[VP9Dmx] Seek bad param (offset "LLU") (2)", pos + frame_size));
		return e;
	}

	u32 pck_size = (u32)(gf_bs_get_position(ctx->bs) - pos);
	assert(pck_size == frame_size);

	//check pid state
	av1dmx_check_pid(filter, ctx);

	if (!ctx->opid) {
		return GF_OK;
	}

	if (!ctx->is_playing) {
		gf_bs_seek(ctx->bs, pos_ivf_hdr);
		return GF_EOS;
	}

	GF_FilterPacket *pck = gf_filter_pck_new_alloc(ctx->opid, pck_size, &output);
	if (!pck) {
		gf_bs_seek(ctx->bs, pos_ivf_hdr);
		return GF_OUT_OF_MEM;
	}
	if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, pck);

	if (ctx->pts_from_file) {
		gf_filter_pck_set_cts(pck, pts);
	} else {
		gf_filter_pck_set_cts(pck, ctx->cts);
	}

	if (key_frame) {
		gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
	}

	if (ctx->deps) {
		u8 flags = 0;
		//dependsOn
		flags = (key_frame) ? 2 : 1;
		flags <<= 2;
		//dependedOn
		//flags |= 2;
		flags <<= 2;
		//hasRedundant
		//flags |= ctx->has_redundant ? 1 : 2;
		gf_filter_pck_set_dependency_flags(pck, flags);
	}

	gf_bs_seek(ctx->bs, pos);
	gf_bs_read_data(ctx->bs, output, pck_size);
	gf_filter_pck_send(pck);

	av1dmx_update_cts(ctx);
	return GF_OK;
}

fixed #1719


static void av1dmx_finalize(GF_Filter *filter)
{
	GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);
	if (ctx->bs) gf_bs_del(ctx->bs);
	if (ctx->indexes) gf_free(ctx->indexes);

	gf_av1_reset_state(&ctx->state, GF_TRUE);
	if (ctx->state.config) gf_odf_av1_cfg_del(ctx->state.config);
	if (ctx->state.bs) gf_bs_del(ctx->state.bs);
	if (ctx->state.frame_obus) gf_free(ctx->state.frame_obus);
	if (ctx->buffer) gf_free(ctx->buffer);

	if (ctx->vp_cfg) gf_odf_vp_cfg_del(ctx->vp_cfg);
}

fixed #1719


static void av1dmx_bs_log(void *udta, const char *field_name, u32 nb_bits, u64 field_val, s32 idx1, s32 idx2, s32 idx3)
{
	GF_AV1DmxCtx *ctx = (GF_AV1DmxCtx *) udta;
	GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, (" %s", field_name));
	if (idx1>=0) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("_%d", idx1));
		if (idx2>=0) {
			GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("_%d", idx2));
			if (idx3>=0) {
				GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("_%d", idx3));
			}
		}
	}
	GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("=\""LLD, field_val));
	if ((ctx->bsdbg==2) && ((s32) nb_bits > 1) )
		GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("(%u)", nb_bits));

	GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("\" "));
}

fixed #1719


GF_Err av1dmx_process(GF_Filter *filter)
{
	GF_Err e;
	GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);
	GF_FilterPacket *pck;
	char *data;
	u32 pck_size;

	if (ctx->bsmode == UNSUPPORTED) return GF_EOS;

	//always reparse duration
	if (!ctx->duration.num)
		av1dmx_check_dur(filter, ctx);

	if (!ctx->is_playing && ctx->opid)
		return GF_OK;

	pck = gf_filter_pid_get_packet(ctx->ipid);
	if (!pck) {
		if (gf_filter_pid_is_eos(ctx->ipid)) {
			//flush
			while (ctx->buf_size) {
				u32 buf_size = ctx->buf_size;
				e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
				if (e) break;
				if (buf_size == ctx->buf_size) {
					break;
				}
			}
			if (ctx->state.bs && gf_bs_get_position(ctx->state.bs))
				av1dmx_parse_flush_sample(filter, ctx);

			ctx->buf_size = 0;
			if (ctx->opid)
				gf_filter_pid_set_eos(ctx->opid);
			if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
			ctx->src_pck = NULL;
			return GF_EOS;
		}
		return GF_OK;
	}

	if (ctx->opid) {
		if (!ctx->is_playing || gf_filter_pid_would_block(ctx->opid))
			return GF_OK;
	}

	data = (char *) gf_filter_pck_get_data(pck, &pck_size);

	//input pid sets some timescale - we flushed pending data , update cts
	if (ctx->timescale) {
		Bool start, end;
		u64 cts;

		e = GF_OK;

		gf_filter_pck_get_framing(pck, &start, &end);
		//middle or end of frame, reaggregation
		if (!start) {
			if (ctx->alloc_size < ctx->buf_size + pck_size) {
				ctx->alloc_size = ctx->buf_size + pck_size;
				ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
			}
			memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
			ctx->buf_size += pck_size;

			//end of frame, process av1
			if (end) {
				e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
			}
			ctx->buf_size=0;
			gf_filter_pid_drop_packet(ctx->ipid);
			return e;
		}
		//flush of pending frame (might have lost something)
		if (ctx->buf_size) {
			e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
			ctx->buf_size = 0;
			if (e) return e;
		}

		//begining of a new frame
		cts = gf_filter_pck_get_cts(pck);
		if (cts != GF_FILTER_NO_TS)
			ctx->cts = cts;
		if (ctx->src_pck) gf_filter_pck_unref(ctx->src_pck);
		ctx->src_pck = pck;
		gf_filter_pck_ref_props(&ctx->src_pck);
		ctx->buf_size = 0;

		if (!end) {
			if (ctx->alloc_size < ctx->buf_size + pck_size) {
				ctx->alloc_size = ctx->buf_size + pck_size;
				ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
			}
			memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
			ctx->buf_size += pck_size;
			gf_filter_pid_drop_packet(ctx->ipid);
			return GF_OK;
		}
		assert(start && end);
		//process
		e = av1dmx_process_buffer(filter, ctx, data, pck_size, GF_FALSE);

		gf_filter_pid_drop_packet(ctx->ipid);
		return e;
	}

	//not from framed stream, copy buffer
	if (ctx->alloc_size < ctx->buf_size + pck_size) {
		ctx->alloc_size = ctx->buf_size + pck_size;
		ctx->buffer = gf_realloc(ctx->buffer, ctx->alloc_size);
	}
	memcpy(ctx->buffer+ctx->buf_size, data, pck_size);
	ctx->buf_size += pck_size;
	e = av1dmx_process_buffer(filter, ctx, ctx->buffer, ctx->buf_size, GF_TRUE);
	gf_filter_pid_drop_packet(ctx->ipid);
	return e;
}

fixed #1719


static Bool av1dmx_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
{
	u32 i;
	u64 file_pos = 0;
	GF_FilterEvent fevt;
	GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);

	switch (evt->base.type) {
	case GF_FEVT_PLAY:
		if (!ctx->is_playing) {
			ctx->is_playing = GF_TRUE;
			ctx->cts = 0;
		}
		if (! ctx->is_file) {
			ctx->buf_size = 0;
			return GF_FALSE;
		}
		ctx->start_range = evt->play.start_range;
		ctx->in_seek = GF_TRUE;

		if (ctx->start_range) {

			if (ctx->index<0) {
				ctx->index = -ctx->index;
				ctx->file_loaded = GF_FALSE;
				ctx->duration.den = ctx->duration.num = 0;
				GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[AV1/VP9Demx] Play request from %d, building index\n", ctx->start_range));
				av1dmx_check_dur(filter, ctx);
			}

			for (i=1; i<ctx->index_size; i++) {
				if (ctx->indexes[i].duration>ctx->start_range) {
					ctx->cts = (u64) (ctx->indexes[i-1].duration * ctx->cur_fps.num);
					file_pos = ctx->indexes[i-1].pos;
					break;
				}
			}
		}
		if (!ctx->initial_play_done) {
			ctx->initial_play_done = GF_TRUE;
			//seek will not change the current source state, don't send a seek
			if (!file_pos)
				return GF_TRUE;
		}
		ctx->buf_size = 0;
		if (!file_pos)
			file_pos = ctx->file_hdr_size;

		//post a seek
		GF_FEVT_INIT(fevt, GF_FEVT_SOURCE_SEEK, ctx->ipid);
		fevt.seek.start_offset = file_pos;
		gf_filter_pid_send_event(ctx->ipid, &fevt);

		//cancel event
		return GF_TRUE;

	case GF_FEVT_STOP:
		//don't cancel event
		ctx->is_playing = GF_FALSE;
		return GF_FALSE;

	case GF_FEVT_SET_SPEED:
		//cancel event
		return GF_TRUE;
	default:
		break;
	}
	//by default don't cancel event - to rework once we have downloading in place
	return GF_FALSE;
}

fixed #1719


GF_Err av1dmx_parse_av1(GF_Filter *filter, GF_AV1DmxCtx *ctx)
{
	GF_Err e = GF_OK;
	u64 start;

	if (!ctx->is_playing) {
		ctx->state.frame_state.is_first_frame = GF_TRUE;
	}

	/*we process each TU and extract only the necessary OBUs*/
	start = gf_bs_get_position(ctx->bs);
	switch (ctx->bsmode) {
	case OBUs:
		//first frame loaded !
		if (ctx->state.bs && gf_bs_get_position(ctx->state.bs) && (ctx->state.obu_type == OBU_TEMPORAL_DELIMITER)) {
			e = GF_OK;
		} else {
			e = aom_av1_parse_temporal_unit_from_section5(ctx->bs, &ctx->state);
		}
		break;
	case AnnexB:
		//first TU loaded !
		if (ctx->state.bs && gf_bs_get_position(ctx->state.bs)) {
			e = GF_OK;
		} else {
			e = aom_av1_parse_temporal_unit_from_annexb(ctx->bs, &ctx->state);
			if (e==GF_BUFFER_TOO_SMALL) {
				gf_av1_reset_state(&ctx->state, GF_FALSE);
				gf_bs_seek(ctx->bs, start);
			}
		}
		break;
	case IVF:
		//first frame loaded !
		if (ctx->state.bs && gf_bs_get_position(ctx->state.bs)) {
			e = GF_OK;
		} else {
			e = aom_av1_parse_temporal_unit_from_ivf(ctx->bs, &ctx->state);
		}
		break;
	default:
		e = GF_NOT_SUPPORTED;
	}

	//check pid state
	av1dmx_check_pid(filter, ctx);

	if (e) return e;

	if (!ctx->opid) {
		if (ctx->state.obu_type != OBU_TEMPORAL_DELIMITER) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[AV1Dmx] output pid not configured (no sequence header yet ?), skipping OBU\n"));
		}
		gf_av1_reset_state(&ctx->state, GF_FALSE);
		return GF_OK;
	}

	if (!ctx->is_playing) {
		//don't reset state we would skip seq header obu in first frame
		//gf_av1_reset_state(&ctx->state, GF_FALSE);
		return GF_OK;
	}

	return av1dmx_parse_flush_sample(filter, ctx);

}

fixed #1719


GF_Err av1dmx_check_format(GF_Filter *filter, GF_AV1DmxCtx *ctx, GF_BitStream *bs, u32 *last_obu_end)
{
	GF_Err e;
	if (last_obu_end) (*last_obu_end) = 0;
	//probing av1 bs mode
	if (ctx->bsmode != NOT_SET) return GF_OK;

	if (!ctx->state.config)
		ctx->state.config = gf_odf_av1_cfg_new();

	ctx->is_av1 = ctx->is_vp9 = ctx->is_vpX = GF_FALSE;
	ctx->codecid = 0;
	if (ctx->vp_cfg) gf_odf_vp_cfg_del(ctx->vp_cfg);
	ctx->vp_cfg = NULL;
	ctx->cur_fps = ctx->fps;
	if (!ctx->fps.num || !ctx->fps.den) {
		ctx->cur_fps.num = 25000;
		ctx->cur_fps.den = 1000;
	}

	ctx->pts_from_file = GF_FALSE;
	if (gf_media_probe_ivf(bs)) {
		u32 width = 0, height = 0;
		u32 codec_fourcc = 0, timebase_den = 0, timebase_num = 0, num_frames = 0;
		ctx->bsmode = IVF;

		e = gf_media_parse_ivf_file_header(bs, &width, &height, &codec_fourcc, &timebase_num, &timebase_den, &num_frames);
		if (e) return e;

		switch (codec_fourcc) {
		case GF_4CC('A', 'V', '0', '1'):
			ctx->is_av1 = GF_TRUE;
			ctx->codecid = GF_CODECID_AV1;
			break;
		case GF_4CC('V', 'P', '9', '0'):
			ctx->is_vp9 = GF_TRUE;
			ctx->codecid = GF_CODECID_VP9;
			ctx->vp_cfg = gf_odf_vp_cfg_new();
			break;
		case GF_4CC('V', 'P', '8', '0'):
			ctx->codecid = GF_CODECID_VP8;
			ctx->vp_cfg = gf_odf_vp_cfg_new();
			break;
		case GF_4CC('V', 'P', '1', '0'):
			ctx->codecid = GF_CODECID_VP10;
			ctx->vp_cfg = gf_odf_vp_cfg_new();
			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF] %s parsing not implemented, import might be uncomplete or broken\n", gf_4cc_to_str(codec_fourcc) ));
			break;
		default:
			ctx->codecid = codec_fourcc;
			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF] Unsupported codec FourCC %s\n", gf_4cc_to_str(codec_fourcc) ));
			return GF_NON_COMPLIANT_BITSTREAM;
		}
		if (ctx->vp_cfg && !ctx->is_vp9) {
			ctx->is_vpX = GF_TRUE;
			ctx->vp_cfg->profile = 1;
			ctx->vp_cfg->level = 10;
			ctx->vp_cfg->bit_depth = 8;
			//leave the rest as 0
		}

		ctx->state.width = ctx->state.width < width ? width : ctx->state.width;
		ctx->state.height = ctx->state.height < height ? height : ctx->state.height;
		ctx->state.tb_num = timebase_num;
		ctx->state.tb_den = timebase_den;

		if ((!ctx->fps.num || !ctx->fps.den) && ctx->state.tb_num && ctx->state.tb_den && ! ( (ctx->state.tb_num<=1) && (ctx->state.tb_den<=1) ) ) {
			ctx->cur_fps.num = ctx->state.tb_num;
			ctx->cur_fps.den = ctx->state.tb_den;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[AV1Dmx] Detected IVF format FPS %d/%d\n", ctx->cur_fps.num, ctx->cur_fps.den));
			ctx->pts_from_file = GF_TRUE;
		} else {
			GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[AV1Dmx] Detected IVF format\n"));
		}
		ctx->file_hdr_size = (u32) gf_bs_get_position(bs);
		if (last_obu_end) (*last_obu_end) = (u32) gf_bs_get_position(bs);
		return GF_OK;
	} else if (gf_media_aom_probe_annexb(bs)) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[AV1Dmx] Detected Annex B format\n"));
		ctx->bsmode = AnnexB;
	} else {
		gf_bs_seek(bs, 0);
		e = aom_av1_parse_temporal_unit_from_section5(bs, &ctx->state);
		if (e && !gf_list_count(ctx->state.frame_state.frame_obus) ) {
			gf_filter_setup_failure(filter, e);
			ctx->bsmode = UNSUPPORTED;
			return e;
		}
		if (ctx->state.obu_type != OBU_TEMPORAL_DELIMITER) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[AV1Dmx] Error OBU stream start with %s, not a temporal delimiter - NOT SUPPORTED\n", gf_av1_get_obu_name(ctx->state.obu_type) ));
			gf_filter_setup_failure(filter, e);
			ctx->bsmode = UNSUPPORTED;
			return e;
		}
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[AV1Dmx] Detected OBUs Section 5 format\n"));
		ctx->bsmode = OBUs;

		gf_av1_reset_state(&ctx->state, GF_FALSE);
		gf_bs_seek(bs, 0);
	}
	ctx->is_av1 = GF_TRUE;
	ctx->state.unframed = GF_TRUE;
	ctx->codecid = GF_CODECID_AV1;
	return GF_OK;
}

fixed #1719


GF_Err av1dmx_process_buffer(GF_Filter *filter, GF_AV1DmxCtx *ctx, const char *data, u32 data_size, Bool is_copy)
{
	u32 last_obu_end = 0;
	GF_Err e = GF_OK;

	if (!ctx->bs) ctx->bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
	else gf_bs_reassign_buffer(ctx->bs, data, data_size);

#ifndef GPAC_DISABLE_LOG
	if (ctx->bsdbg && gf_log_tool_level_on(GF_LOG_PARSER, GF_LOG_DEBUG))
		gf_bs_set_logger(ctx->bs, av1dmx_bs_log, ctx);
#endif

	//check ivf vs obu vs annexB
	e = av1dmx_check_format(filter, ctx, ctx->bs, &last_obu_end);
	if (e) return e;

	while (gf_bs_available(ctx->bs)) {

		if (ctx->is_vp9) {
			e = av1dmx_parse_vp9(filter, ctx);
		} else if (ctx->is_av1) {
			e = av1dmx_parse_av1(filter, ctx);
		} else {
			e = av1dmx_parse_ivf(filter, ctx);
		}

		if (e!=GF_EOS)
			last_obu_end = (u32) gf_bs_get_position(ctx->bs);

		if (e) {
			break;
		}
		if (!ctx->is_playing && ctx->opid)
			break;
	}

	if (is_copy && last_obu_end) {
		assert(ctx->buf_size>=last_obu_end);
		memmove(ctx->buffer, ctx->buffer+last_obu_end, sizeof(char) * (ctx->buf_size-last_obu_end));
		ctx->buf_size -= last_obu_end;
	}
	if (e==GF_EOS) return GF_OK;
	if (e==GF_BUFFER_TOO_SMALL) return GF_OK;
	return e;
}

fixed #1719


const GF_FilterRegister *av1dmx_register(GF_FilterSession *session)
{
	return &AV1DmxRegister;
}

fixed #1719


GF_Err av1dmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
{
	const GF_PropertyValue *p;
	GF_AV1DmxCtx *ctx = gf_filter_get_udta(filter);

	if (is_remove) {
		ctx->ipid = NULL;
		if (ctx->opid) {
			gf_filter_pid_remove(ctx->opid);
			ctx->opid = NULL;
		}
		return GF_OK;
	}
	if (! gf_filter_pid_check_caps(pid))
		return GF_NOT_SUPPORTED;

	ctx->ipid = pid;
	p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
	if (p) ctx->timescale = p->value.uint;
	ctx->state.mem_mode = GF_TRUE;
	if (ctx->timescale && !ctx->opid) {
		ctx->opid = gf_filter_pid_new(filter);
		gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
	}
	if (ctx->timescale) {
		//if we have a FPS prop, use it
		p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
		if (p) ctx->cur_fps = p->value.frac;
	}
	return GF_OK;
}

fixed #1719


static GF_Err av1dmx_parse_flush_sample(GF_Filter *filter, GF_AV1DmxCtx *ctx)
{
	u32 pck_size;
	GF_FilterPacket *pck;
	u8 *output;

	if (!ctx->opid)
		return GF_NON_COMPLIANT_BITSTREAM;

	gf_bs_get_content_no_truncate(ctx->state.bs, &ctx->state.frame_obus, &pck_size, &ctx->state.frame_obus_alloc);

	if (!pck_size) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[AV1Dmx] no frame OBU, skipping OBU\n"));
		return GF_OK;
	}

	pck = gf_filter_pck_new_alloc(ctx->opid, pck_size, &output);
	if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, pck);

	gf_filter_pck_set_cts(pck, ctx->cts);
	gf_filter_pck_set_sap(pck, ctx->state.frame_state.key_frame ? GF_FILTER_SAP_1 : 0);

	memcpy(output, ctx->state.frame_obus, pck_size);

	if (ctx->deps) {
		u8 flags = 0;
		//dependsOn
		flags = ( ctx->state.frame_state.key_frame) ? 2 : 1;
		flags <<= 2;
		//dependedOn
	 	flags |= ctx->state.frame_state.refresh_frame_flags ? 1 : 2;
		flags <<= 2;
		//hasRedundant
	 	//flags |= ctx->has_redundant ? 1 : 2;
	 	gf_filter_pck_set_dependency_flags(pck, flags);
	}

	gf_filter_pck_send(pck);

	av1dmx_update_cts(ctx);
	gf_av1_reset_state(&ctx->state, GF_FALSE);

	return GF_OK;

}

fixed #1719


GF_Err av1dmx_parse_ivf(GF_Filter *filter, GF_AV1DmxCtx *ctx)
{
	GF_Err e;
	u32 pck_size;
	u64 frame_size = 0, pts = GF_FILTER_NO_TS;
	GF_FilterPacket *pck;
	u64 pos, pos_ivf_hdr;
	u8 *output;

	pos_ivf_hdr = gf_bs_get_position(ctx->bs);
	e = gf_media_parse_ivf_frame_header(ctx->bs, &frame_size, &pts);
	if (e) return e;

	pos = gf_bs_get_position(ctx->bs);
	if (gf_bs_available(ctx->bs) < frame_size) {
		gf_bs_seek(ctx->bs, pos_ivf_hdr);
		return GF_EOS;
	}

	if (ctx->pts_from_file) {
		pts += ctx->cumulated_dur;
		if (ctx->last_pts && (ctx->last_pts>pts)) {
			pts -= ctx->cumulated_dur;
			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[IVF/AV1] Corrupted timestamp "LLU" less than previous timestamp "LLU", assuming concatenation\n", pts, ctx->last_pts));
			ctx->cumulated_dur = ctx->last_pts + ctx->cur_fps.den;
			ctx->cumulated_dur -= pts;
			pts = ctx->cumulated_dur;
		}
		ctx->last_pts = pts;
	}

	//check pid state
	av1dmx_check_pid(filter, ctx);

	if (!ctx->opid) {
		return GF_OK;
	}

	if (!ctx->is_playing) {
		gf_bs_seek(ctx->bs, pos_ivf_hdr);
		return GF_EOS;
	}

	pck_size = (u32)frame_size;
	pck = gf_filter_pck_new_alloc(ctx->opid, pck_size, &output);
	if (!pck) {
		gf_bs_seek(ctx->bs, pos_ivf_hdr);
		return GF_OUT_OF_MEM;
	}
	if (ctx->src_pck) gf_filter_pck_merge_properties(ctx->src_pck, pck);

	if (ctx->pts_from_file) {
		gf_filter_pck_set_cts(pck, pts);
	} else {
		gf_filter_pck_set_cts(pck, ctx->cts);
	}

	gf_bs_seek(ctx->bs, pos);
	gf_bs_read_data(ctx->bs, output, pck_size);

	if (output[0] & 0x80)
		gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1);
	else
		gf_filter_pck_set_sap(pck, GF_FILTER_SAP_NONE);

	gf_filter_pck_send(pck);

	av1dmx_update_cts(ctx);
	return GF_OK;
}

fixed #1719


auto NativeModuleHandle::NativeModuleTransferable::TransferIn() -> Local<Value> {
	return ClassHandle::NewInstance<NativeModuleHandle>(module);
}

Disallow NativeModule creation unless main isolate


NativeModule::~NativeModule() {
	uv_dlclose(&lib);
}


auto NativeModuleHandle::TransferOut() -> unique_ptr<Transferable> {
	return std::make_unique<NativeModuleTransferable>(module);
}


auto NativeModuleHandle::Definition() -> Local<FunctionTemplate> {
	return Inherit<TransferableHandle>(MakeClass(
		"NativeModule", ConstructorFunction<decltype(&New), &New>{},
		"create", MemberFunction<decltype(&NativeModuleHandle::Create<1>), &NativeModuleHandle::Create<1>>{},
		"createSync", MemberFunction<decltype(&NativeModuleHandle::Create<0>), &NativeModuleHandle::Create<0>>{}
	));
}


CreateRunner(RemoteHandle<Context> context, shared_ptr<NativeModule> module) : context(std::move(context)), module(std::move(module)) {}


void NativeModule::InitForContext(Isolate* isolate, Local<Context> context, Local<Object> target) {
	init(isolate, context, target);
}


auto NativeModuleHandle::Create(class ContextHandle& context_handle) -> Local<Value> {
	// TODO: This should probably throw from the promise, but ThreePhaseTask can't handle invalid
	// isolate references for now.
	auto context = context_handle.GetContext();
	return ThreePhaseTask::Run<async, CreateRunner>(*context.GetIsolateHolder(), context, module);
}


NativeModuleHandle::NativeModuleHandle(shared_ptr<NativeModule> module) : module(std::move(module)) {}


		auto Phase3() -> Local<Value> final {
			return result->TransferIn();
		}


auto NativeModuleHandle::New(Local<String> value) -> unique_ptr<NativeModuleHandle> {
	return std::make_unique<NativeModuleHandle>(
		std::make_shared<NativeModule>(*String::Utf8Value{Isolate::GetCurrent(), value})
	);
}


		void Phase2() final {
			Isolate* isolate = Isolate::GetCurrent();
			Local<Context> context_handle = Deref(context);
			Context::Scope context_scope(context_handle);
			Local<Object> exports = Object::New(isolate);
			module->InitForContext(isolate, context_handle, exports);
			// Once a native module is imported into an isolate, that isolate holds a reference to the module forever
			auto* ptr = module.get();
			Executor::GetCurrentEnvironment()->native_modules.emplace(ptr, std::move(module));
			result = std::make_unique<ReferenceHandleTransferable>(exports);
		}


NativeModule::NativeModule(const std::string& filename) : init(nullptr) {
	if (!IsolateEnvironment::GetCurrent()->IsDefault()) {
		throw RuntimeGenericError("NativeModule may only be instantiated from default nodejs isolate");
	}
	if (uv_dlopen(filename.c_str(), &lib) != 0) {
		throw RuntimeGenericError("Failed to load module");
	}
	if (uv_dlsym(&lib, "InitForContext", reinterpret_cast<void**>(&init)) != 0 || init == nullptr) {
		uv_dlclose(&lib);
		throw RuntimeGenericError("Module is not isolated-vm compatible");
	}
}


NativeModuleHandle::NativeModuleTransferable::NativeModuleTransferable(shared_ptr<NativeModule> module) : module(std::move(module)) {}


GF_Err btrt_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_BitRateBox *ptr = (GF_BitRateBox *)s;
	ISOM_DECREASE_SIZE(ptr, 12)
	ptr->bufferSizeDB = gf_bs_read_u32(bs);
	ptr->maxBitrate = gf_bs_read_u32(bs);
	ptr->avgBitrate = gf_bs_read_u32(bs);
	return GF_OK;
}

fixed #1785 (fuzz)


GF_Err gf_isom_hevc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_HEVCConfig *cfg)
{
	return gf_isom_hevc_config_update_ex(the_file, trackNumber, DescriptionIndex, cfg, GF_ISOM_HVCC_UPDATE, GF_FALSE);
}

fixed #1785 (fuzz)


GF_Err avcc_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i, count;
	GF_AVCConfigurationBox *ptr = (GF_AVCConfigurationBox *)s;

	if (ptr->config) gf_odf_avc_cfg_del(ptr->config);
	ptr->config = gf_odf_avc_cfg_new();

	ISOM_DECREASE_SIZE(ptr, 7) //7 includes the 2 counts of sps and pps

	ptr->config->configurationVersion = gf_bs_read_u8(bs);
	ptr->config->AVCProfileIndication = gf_bs_read_u8(bs);
	ptr->config->profile_compatibility = gf_bs_read_u8(bs);
	ptr->config->AVCLevelIndication = gf_bs_read_u8(bs);
	if (ptr->type==GF_ISOM_BOX_TYPE_AVCC) {
		gf_bs_read_int(bs, 6);
	} else {
		ptr->config->complete_representation = gf_bs_read_int(bs, 1);
		gf_bs_read_int(bs, 5);
	}
	ptr->config->nal_unit_size = 1 + gf_bs_read_int(bs, 2);
	gf_bs_read_int(bs, 3);
	count = gf_bs_read_int(bs, 5);

	for (i=0; i<count; i++) {
		ISOM_DECREASE_SIZE(ptr, 2)
		GF_NALUFFParam *sl = (GF_NALUFFParam *) gf_malloc(sizeof(GF_NALUFFParam));
		sl->size = gf_bs_read_u16(bs);
		if (!sl->size || (gf_bs_available(bs) < sl->size) || (ptr->size < sl->size) ) {
			gf_free(sl);
			GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("AVCC: Not enough bits to parse. Aborting.\n"));
			return GF_ISOM_INVALID_FILE;
		}
		sl->data = (char *)gf_malloc(sizeof(char) * sl->size);
		gf_bs_read_data(bs, sl->data, sl->size);
		gf_list_add(ptr->config->sequenceParameterSets, sl);
		ptr->size -= sl->size;
	}

	count = gf_bs_read_u8(bs);
	for (i=0; i<count; i++) {
		ISOM_DECREASE_SIZE(ptr, 2)
		GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_malloc(sizeof(GF_NALUFFParam));
		sl->size = gf_bs_read_u16(bs);
		if (!sl->size || (gf_bs_available(bs) < sl->size) || (ptr->size<sl->size)) {
			gf_free(sl);
			GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("AVCC: Not enough bits to parse. Aborting.\n"));
			return GF_ISOM_INVALID_FILE;
		}
		sl->data = (char *)gf_malloc(sizeof(char) * sl->size);
		gf_bs_read_data(bs, sl->data, sl->size);
		gf_list_add(ptr->config->pictureParameterSets, sl);
		ptr->size -= sl->size;
	}

	if (ptr->type==GF_ISOM_BOX_TYPE_AVCC) {
		if (gf_avc_is_rext_profile(ptr->config->AVCProfileIndication)) {
			if (!ptr->size) {
#ifndef GPAC_DISABLE_AV_PARSERS
				AVCState avc;
				s32 idx;
				GF_NALUFFParam *sl = (GF_NALUFFParam*)gf_list_get(ptr->config->sequenceParameterSets, 0);
				idx = sl ? gf_avc_read_sps(sl->data+1, sl->size-1, &avc, 0, NULL) : -1;

				if (idx>=0) {
					ptr->config->chroma_format = avc.sps[idx].chroma_format;
					ptr->config->luma_bit_depth = 8 + avc.sps[idx].luma_bit_depth_m8;
					ptr->config->chroma_bit_depth = 8 + avc.sps[idx].chroma_bit_depth_m8;
				}
#else
				/*set default values ...*/
				ptr->config->chroma_format = 1;
				ptr->config->luma_bit_depth = 8;
				ptr->config->chroma_bit_depth = 8;
#endif
				return GF_OK;
			}
			ISOM_DECREASE_SIZE(ptr, 4)
			gf_bs_read_int(bs, 6);
			ptr->config->chroma_format = gf_bs_read_int(bs, 2);
			gf_bs_read_int(bs, 5);
			ptr->config->luma_bit_depth = 8 + gf_bs_read_int(bs, 3);
			gf_bs_read_int(bs, 5);
			ptr->config->chroma_bit_depth = 8 + gf_bs_read_int(bs, 3);

			count = gf_bs_read_int(bs, 8);
			if (count*2 > ptr->size) {
				//ffmpeg just ignores this part while allocating bytes (filled with garbage?)
				GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("AVCC: invalid numOfSequenceParameterSetExt value. Skipping.\n"));
				return GF_OK;
			}
			if (count) {
				ptr->config->sequenceParameterSetExtensions = gf_list_new();
				for (i=0; i<count; i++) {
					ISOM_DECREASE_SIZE(ptr, 2)
					GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_malloc(sizeof(GF_NALUFFParam));
					sl->size = gf_bs_read_u16(bs);
					if ((gf_bs_available(bs) < sl->size) || (ptr->size<sl->size)) {
						gf_free(sl);
						GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("AVCC: Not enough bits to parse. Aborting.\n"));
						return GF_ISOM_INVALID_FILE;
					}
					sl->data = (char *)gf_malloc(sizeof(char) * sl->size);
					gf_bs_read_data(bs, sl->data, sl->size);
					gf_list_add(ptr->config->sequenceParameterSetExtensions, sl);
					ptr->size -= sl->size;
				}
			}
		}
	}
	return GF_OK;
}

fixed #1785 (fuzz)


static GF_Err gf_isom_svc_mvc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfig *cfg, Bool is_mvc, char *URLname, char *URNname, u32 *outDescriptionIndex)
{
	GF_TrackBox *trak;
	GF_Err e;
	u32 dataRefIndex;
	GF_SampleDescriptionBox *stsd;
	GF_MPEGVisualSampleEntryBox *entry;

	e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
	if (e) return e;

	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !trak->Media || !cfg) return GF_BAD_PARAM;

	//get or create the data ref
	e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
	if (e) return e;
	if (!dataRefIndex) {
		e = Media_CreateDataRef(the_file, trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
		if (e) return e;
	}
	if (!the_file->keep_utc)
		trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();

	stsd = trak->Media->information->sampleTable->SampleDescription;
	//create a new entry
	if (is_mvc) {
		entry = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new_parent(&stsd->child_boxes, GF_ISOM_BOX_TYPE_MVC1);
		if (!entry) return GF_OUT_OF_MEM;
		entry->mvc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_MVCC);
		if (!entry->mvc_config) return GF_OUT_OF_MEM;
		entry->mvc_config->config = AVC_DuplicateConfig(cfg);
		if (!entry->mvc_config->config) return GF_OUT_OF_MEM;
	} else {
		entry = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new_parent(&stsd->child_boxes,GF_ISOM_BOX_TYPE_SVC1);
		if (!entry) return GF_OUT_OF_MEM;
		entry->svc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes,GF_ISOM_BOX_TYPE_SVCC);
		if (!entry->svc_config) return GF_OUT_OF_MEM;
		entry->svc_config->config = AVC_DuplicateConfig(cfg);
		if (!entry->svc_config->config) return GF_OUT_OF_MEM;
	}
	entry->dataReferenceIndex = dataRefIndex;
	*outDescriptionIndex = gf_list_count(stsd->child_boxes);
	AVC_RewriteESDescriptor(entry);
	return e;
}

fixed #1785 (fuzz)


GF_VPConfig *gf_isom_vp_config_get(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
{
	GF_TrackBox *trak;
	GF_MPEGVisualSampleEntryBox *entry;
	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !trak->Media || !DescriptionIndex) return NULL;
	entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex - 1);
	if (!entry || !entry->vp_config) return NULL;
	return VP_DuplicateConfig(entry->vp_config->config);
}

fixed #1785 (fuzz)


void HEVC_RewriteESDescriptor(GF_MPEGVisualSampleEntryBox *hevc)
{
	HEVC_RewriteESDescriptorEx(hevc, NULL);
}

fixed #1785 (fuzz)


GF_Err hvcc_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_HEVCConfigurationBox *ptr = (GF_HEVCConfigurationBox *) s;
	if (!s) return GF_BAD_PARAM;
	if (!ptr->config) return GF_OK;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;

	return gf_odf_hevc_cfg_write_bs(ptr->config, bs);
}

fixed #1785 (fuzz)


GF_Err SmDm_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_SMPTE2086MasteringDisplayMetadataBox *p = (GF_SMPTE2086MasteringDisplayMetadataBox*)s;
	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u16(bs, p->primaryRChromaticity_x);
	gf_bs_write_u16(bs, p->primaryRChromaticity_y);
	gf_bs_write_u16(bs, p->primaryGChromaticity_x);
	gf_bs_write_u16(bs, p->primaryGChromaticity_y);
	gf_bs_write_u16(bs, p->primaryBChromaticity_x);
	gf_bs_write_u16(bs, p->primaryBChromaticity_y);
	gf_bs_write_u16(bs, p->whitePointChromaticity_x);
	gf_bs_write_u16(bs, p->whitePointChromaticity_y);
	gf_bs_write_u32(bs, p->luminanceMax);
	gf_bs_write_u32(bs, p->luminanceMin);

	return GF_OK;
}

fixed #1785 (fuzz)


GF_Err gf_isom_avc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfig *cfg, const char *URLname, const char *URNname, u32 *outDescriptionIndex)
{
	GF_TrackBox *trak;
	GF_Err e;
	GF_SampleDescriptionBox *stsd;
	u32 dataRefIndex;
	GF_MPEGVisualSampleEntryBox *entry;

	e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
	if (e) return e;

	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !trak->Media || !cfg) return GF_BAD_PARAM;

	//get or create the data ref
	e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
	if (e) return e;
	if (!dataRefIndex) {
		e = Media_CreateDataRef(the_file, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
		if (e) return e;
	}
	if (!the_file->keep_utc && !gf_sys_is_test_mode() )
		trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();

	stsd = trak->Media->information->sampleTable->SampleDescription;

	//create a new entry
	entry = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new_parent(&stsd->child_boxes, GF_ISOM_BOX_TYPE_AVC1);
	if (!entry) return GF_OUT_OF_MEM;
	*outDescriptionIndex = gf_list_count(stsd->child_boxes);

	entry->avc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_AVCC);
	if (!entry->avc_config) return GF_OUT_OF_MEM;
	entry->avc_config->config = AVC_DuplicateConfig(cfg);
	if (!entry->avc_config->config) return GF_OUT_OF_MEM;
	entry->dataReferenceIndex = dataRefIndex;
	AVC_RewriteESDescriptor(entry);
	return e;
}

fixed #1785 (fuzz)


GF_Box *btrt_box_new()
{
	GF_BitRateBox *tmp = (GF_BitRateBox *) gf_malloc(sizeof(GF_BitRateBox));
	if (tmp == NULL) return NULL;
	memset(tmp, 0, sizeof(GF_BitRateBox));
	tmp->type = GF_ISOM_BOX_TYPE_BTRT;
	return (GF_Box *)tmp;
}

fixed #1785 (fuzz)


static GF_Err gf_isom_check_mvc(GF_ISOFile *the_file, GF_TrackBox *trak, GF_MPEGVisualSampleEntryBox *entry)
{
	u32 i;
	GF_Box *mvci;
	GF_MultiviewGroupBox *mvcg;
	GF_ViewIdentifierBox *vwid;

	if (entry->mvc_config) {}
	else if (entry->avc_config && entry->avc_config->config && entry->avc_config->config->sequenceParameterSetExtensions) {}
	else
		return GF_OK;

	mvci = gf_isom_box_find_child(trak->Media->information->child_boxes, GF_ISOM_BOX_TYPE_MVCI);
	if (!mvci) {
		mvci = gf_isom_box_new_parent(&trak->Media->information->child_boxes, GF_ISOM_BOX_TYPE_MVCI);
		if (!mvci) return GF_OUT_OF_MEM;
	}
	mvcg = (GF_MultiviewGroupBox *) gf_isom_box_find_child(mvci->child_boxes, GF_ISOM_BOX_TYPE_MVCG);
	if (!mvcg) {
		mvcg = (GF_MultiviewGroupBox *)gf_isom_box_new_parent(&mvci->child_boxes, GF_ISOM_BOX_TYPE_MVCG);
		if (!mvcg) return GF_OUT_OF_MEM;
	}
	//this is very crude, we should try to parse the bitstream to fill these
	mvcg->num_entries = 0;
	if (mvcg->entries) {
		gf_free(mvcg->entries);
		mvcg->entries = NULL;
	}
	if (entry->avc_config) {
		if (gf_list_count(entry->avc_config->config->sequenceParameterSets))
			mvcg->num_entries += 1;
		mvcg->num_entries += gf_list_count(entry->avc_config->config->sequenceParameterSetExtensions);
	}
	if (entry->mvc_config && entry->mvc_config->config) {
		mvcg->num_entries += gf_list_count(entry->mvc_config->config->sequenceParameterSets);
	}
	mvcg->entries = gf_malloc(sizeof(MVCIEntry)*mvcg->num_entries);
	if (!mvcg->entries) return GF_OUT_OF_MEM;
	memset(mvcg->entries, 0, sizeof(MVCIEntry)*mvcg->num_entries);
	for (i=0; i<mvcg->num_entries; i++) {
		mvcg->entries[i].entry_type = 2;
		mvcg->entries[i].output_view_id = i;
	}
	vwid = (GF_ViewIdentifierBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_VWID);
	if (!vwid) {
		vwid = (GF_ViewIdentifierBox *)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_VWID);
		if (!mvcg) return GF_OUT_OF_MEM;
	}
	if (vwid->views) gf_free(vwid->views);
	vwid->num_views = mvcg->num_entries;
	vwid->views = gf_malloc(sizeof(ViewIDEntry)*vwid->num_views);
	if (!vwid->views) return GF_OUT_OF_MEM;
	memset(vwid->views, 0, sizeof(ViewIDEntry)*vwid->num_views);

	for (i=0; i<vwid->num_views; i++) {
		vwid->views[i].base_view_type = i ? 0 : 1;
		vwid->views[i].view_id = i;
		vwid->views[i].view_order_index = i;
	}

	return GF_OK;
}

fixed #1785 (fuzz)


GF_Err av1c_box_read(GF_Box *s, GF_BitStream *bs)
{
	u64 pos, read;
	GF_AV1ConfigurationBox *ptr = (GF_AV1ConfigurationBox*)s;

	if (ptr->config) gf_odf_av1_cfg_del(ptr->config);

	pos = gf_bs_get_position(bs);

	ptr->config = gf_odf_av1_cfg_read_bs_size(bs, (u32) ptr->size);

	read = gf_bs_get_position(bs) - pos;

	if (read < ptr->size)
		GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[ISOBMFF] AV1ConfigurationBox: read only "LLU" bytes (expected "LLU").\n", read, ptr->size));
	if (read > ptr->size)
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] AV1ConfigurationBox overflow read "LLU" bytes, of box size "LLU".\n", read, ptr->size));

	return GF_OK;
}

fixed #1785 (fuzz)


GF_Box *m4ds_box_new()
{
	GF_MPEG4ExtensionDescriptorsBox *tmp = (GF_MPEG4ExtensionDescriptorsBox *) gf_malloc(sizeof(GF_MPEG4ExtensionDescriptorsBox));
	if (tmp == NULL) return NULL;
	memset(tmp, 0, sizeof(GF_MPEG4ExtensionDescriptorsBox));
	tmp->type = GF_ISOM_BOX_TYPE_M4DS;
	tmp->descriptors = gf_list_new();
	return (GF_Box *)tmp;
}

fixed #1785 (fuzz)


GF_Err gf_isom_vvc_set_inband_config(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, Bool keep_xps)
{
	return gf_isom_vvc_config_update_ex(the_file, trackNumber, DescriptionIndex, NULL, GF_ISOM_VVCC_SET_INBAND, keep_xps);
}

fixed #1785 (fuzz)


GF_Err btrt_box_size(GF_Box *s)
{
	GF_BitRateBox *ptr = (GF_BitRateBox *)s;
	ptr->size += 12;
	return GF_OK;
}

fixed #1785 (fuzz)


static GF_Err gf_isom_avc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_AVCConfig *cfg, u32 op_type, Bool keep_xps)
{
	GF_TrackBox *trak;
	GF_Err e;
	u32 i;
	GF_MPEGVisualSampleEntryBox *entry;

	e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
	if (e) return e;
	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !trak->Media || !DescriptionIndex) return GF_BAD_PARAM;
	entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
	if (!entry) return GF_BAD_PARAM;
	switch (entry->type) {
	case GF_ISOM_BOX_TYPE_AVC1:
	case GF_ISOM_BOX_TYPE_AVC2:
	case GF_ISOM_BOX_TYPE_AVC3:
	case GF_ISOM_BOX_TYPE_AVC4:
	case GF_ISOM_BOX_TYPE_SVC1:
	case GF_ISOM_BOX_TYPE_MVC1:
		break;
	default:
		return GF_BAD_PARAM;
	}

	switch (op_type) {
	/*AVCC replacement*/
	case 0:
		if (!cfg) return GF_BAD_PARAM;
		if (!entry->avc_config) {
			entry->avc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_AVCC);
			if (!entry->avc_config) return GF_OUT_OF_MEM;
		}
		if (entry->avc_config->config) gf_odf_avc_cfg_del(entry->avc_config->config);
		entry->avc_config->config = AVC_DuplicateConfig(cfg);
		if (!entry->avc_config->config) return GF_OUT_OF_MEM;
		entry->type = GF_ISOM_BOX_TYPE_AVC1;
		break;
	/*SVCC replacement*/
	case 1:
		if (!cfg) return GF_BAD_PARAM;
		if (!entry->svc_config) {
			entry->svc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_SVCC);
			if (!entry->svc_config) return GF_OUT_OF_MEM;
		}
		if (entry->svc_config->config) gf_odf_avc_cfg_del(entry->svc_config->config);
		entry->svc_config->config = AVC_DuplicateConfig(cfg);
		if (!entry->svc_config->config) return GF_OUT_OF_MEM;
		entry->type = GF_ISOM_BOX_TYPE_AVC1;
		break;
	/*SVCC replacement and AVC removal*/
	case 2:
		if (!cfg) return GF_BAD_PARAM;
		if (entry->avc_config) {
			gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)entry->avc_config);
			entry->avc_config = NULL;
		}
		if (!entry->svc_config) {
			entry->svc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_SVCC);
			if (!entry->svc_config) return GF_OUT_OF_MEM;
		}
		if (entry->svc_config->config) gf_odf_avc_cfg_del(entry->svc_config->config);
		entry->svc_config->config = AVC_DuplicateConfig(cfg);
		if (!entry->svc_config->config) return GF_OUT_OF_MEM;
		entry->type = GF_ISOM_BOX_TYPE_SVC1;
		break;
	/*AVCC removal and switch to avc3*/
	case 3:
		if (!entry->avc_config || !entry->avc_config->config)
			return GF_BAD_PARAM;
		if (!keep_xps) {
			for (i=0; i<3; i++) {
				GF_AVCConfigurationBox *a_cfg = entry->avc_config;
				if (i==1) a_cfg = entry->svc_config;
				else if (i==2) a_cfg = entry->mvc_config;
				if (!a_cfg) continue;

				while (gf_list_count(a_cfg->config->sequenceParameterSets)) {
					GF_NALUFFParam *sl = (GF_NALUFFParam*)gf_list_get(a_cfg->config->sequenceParameterSets, 0);
					gf_list_rem(a_cfg->config->sequenceParameterSets, 0);
					if (sl->data) gf_free(sl->data);
					gf_free(sl);
				}

				while (gf_list_count(a_cfg->config->pictureParameterSets)) {
					GF_NALUFFParam *sl = (GF_NALUFFParam*)gf_list_get(a_cfg->config->pictureParameterSets, 0);
					gf_list_rem(a_cfg->config->pictureParameterSets, 0);
					if (sl->data) gf_free(sl->data);
					gf_free(sl);
				}

				while (gf_list_count(a_cfg->config->sequenceParameterSetExtensions)) {
					GF_NALUFFParam *sl = (GF_NALUFFParam*)gf_list_get(a_cfg->config->sequenceParameterSetExtensions, 0);
					gf_list_rem(a_cfg->config->sequenceParameterSetExtensions, 0);
					if (sl->data) gf_free(sl->data);
					gf_free(sl);
				}
			}
		}

		if (entry->type == GF_ISOM_BOX_TYPE_AVC1)
			entry->type = GF_ISOM_BOX_TYPE_AVC3;
		else if (entry->type == GF_ISOM_BOX_TYPE_AVC2)
			entry->type = GF_ISOM_BOX_TYPE_AVC4;
		break;
	/*MVCC replacement*/
	case 4:
		if (!cfg) return GF_BAD_PARAM;
		if (!entry->mvc_config) {
			entry->mvc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_MVCC);
			if (!entry->mvc_config) return GF_OUT_OF_MEM;
		}
		if (entry->mvc_config->config) gf_odf_avc_cfg_del(entry->mvc_config->config);
		entry->mvc_config->config = AVC_DuplicateConfig(cfg);
		if (!entry->mvc_config->config) return GF_OUT_OF_MEM;
		entry->type = GF_ISOM_BOX_TYPE_AVC1;
		e = gf_isom_check_mvc(the_file, trak, entry);
		if (e) return e;
		break;
	/*MVCC replacement and AVC removal*/
	case 5:
		if (!cfg) return GF_BAD_PARAM;
		if (entry->avc_config) {
			gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)entry->avc_config);
			entry->avc_config = NULL;
		}
		if (!entry->mvc_config) {
			entry->mvc_config = (GF_AVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_MVCC);
			if (!entry->mvc_config) return GF_OUT_OF_MEM;
		}
		if (entry->mvc_config->config) gf_odf_avc_cfg_del(entry->mvc_config->config);
		entry->mvc_config->config = AVC_DuplicateConfig(cfg);
		if (!entry->mvc_config->config) return GF_OUT_OF_MEM;
		entry->type = GF_ISOM_BOX_TYPE_MVC1;
		e = gf_isom_check_mvc(the_file, trak, entry);
		if (e) return e;
		break;
	}
	AVC_RewriteESDescriptor(entry);
	return GF_OK;
}

fixed #1785 (fuzz)


GF_HEVCConfig *gf_isom_lhvc_config_get(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
{
	GF_HEVCConfig *lhvc;
	GF_OperatingPointsInformation *oinf=NULL;
	GF_TrackBox *trak;
	GF_MPEGVisualSampleEntryBox *entry;
	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !trak->Media || !DescriptionIndex) return NULL;
	if (gf_isom_get_hevc_lhvc_type(the_file, trackNumber, DescriptionIndex)==GF_ISOM_HEVCTYPE_NONE)
		return NULL;
	entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
	if (!entry) return NULL;
	if (!entry->lhvc_config) return NULL;
	lhvc = HEVC_DuplicateConfig(entry->lhvc_config->config);
	if (!lhvc) return NULL;

	gf_isom_get_oinf_info(the_file, trackNumber, &oinf);
	if (oinf) {
		LHEVC_ProfileTierLevel *ptl = (LHEVC_ProfileTierLevel *)gf_list_last(oinf->profile_tier_levels);
		if (ptl) {
			lhvc->profile_space  = ptl->general_profile_space;
			lhvc->tier_flag = ptl->general_tier_flag;
			lhvc->profile_idc = ptl->general_profile_idc;
			lhvc->general_profile_compatibility_flags = ptl->general_profile_compatibility_flags;
			lhvc->constraint_indicator_flags = ptl->general_constraint_indicator_flags;
		}
	}
	return lhvc;
}

fixed #1785 (fuzz)


void hvcc_box_del(GF_Box *s)
{
	GF_HEVCConfigurationBox *ptr = (GF_HEVCConfigurationBox*)s;
	if (ptr->config) gf_odf_hevc_cfg_del(ptr->config);
	gf_free(ptr);
}

fixed #1785 (fuzz)


void m4ds_box_del(GF_Box *s)
{
	GF_MPEG4ExtensionDescriptorsBox *ptr = (GF_MPEG4ExtensionDescriptorsBox *)s;
	gf_odf_desc_list_del(ptr->descriptors);
	gf_list_del(ptr->descriptors);
	gf_free(ptr);
}

fixed #1785 (fuzz)


GF_Err gf_isom_hevc_set_tile_config(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_HEVCConfig *cfg, Bool is_base_track)
{
	return gf_isom_hevc_config_update_ex(the_file, trackNumber, DescriptionIndex, cfg, is_base_track ? GF_ISOM_HVCC_SET_TILE_BASE_TRACK : GF_ISOM_HVCC_SET_TILE, GF_FALSE);
}

fixed #1785 (fuzz)


void SmDm_box_del(GF_Box *a)
{
	GF_SMPTE2086MasteringDisplayMetadataBox *p = (GF_SMPTE2086MasteringDisplayMetadataBox *)a;
	gf_free(p);
}

fixed #1785 (fuzz)


GF_LHVCLayerInformation *gf_isom_linf_new_entry()
{
	GF_LHVCLayerInformation* ptr;
	GF_SAFEALLOC(ptr, GF_LHVCLayerInformation);
	if (ptr) ptr->num_layers_in_track = gf_list_new();

	return ptr;

}

fixed #1785 (fuzz)


GF_Box *vpcc_box_new()
{
	GF_VPConfigurationBox *tmp = (GF_VPConfigurationBox *) gf_malloc(sizeof(GF_VPConfigurationBox));
	if (tmp == NULL) return NULL;
	memset(tmp, 0, sizeof(GF_VPConfigurationBox));
	tmp->type = GF_ISOM_BOX_TYPE_VPCC;
	tmp->version = 1;
	return (GF_Box *)tmp;
}

fixed #1785 (fuzz)


GF_Box *SmDm_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_SMPTE2086MasteringDisplayMetadataBox, GF_ISOM_BOX_TYPE_SMDM);
	return (GF_Box *)tmp;
}

fixed #1785 (fuzz)


GF_Err gf_isom_hevc_config_update_ex(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_HEVCConfig *cfg, u32 operand_type, Bool keep_xps)
{
	u32 array_incomplete;
	GF_TrackBox *trak;
	GF_Err e;
	GF_MPEGVisualSampleEntryBox *entry;
	GF_SampleDescriptionBox *stsd;

	e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
	if (e) return e;
	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !trak->Media || !DescriptionIndex) return GF_BAD_PARAM;
	stsd = trak->Media->information->sampleTable->SampleDescription;
	entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(stsd->child_boxes, DescriptionIndex-1);
	if (!entry) return GF_BAD_PARAM;
	switch (entry->type) {
	case GF_ISOM_BOX_TYPE_HVC1:
	case GF_ISOM_BOX_TYPE_HEV1:
	case GF_ISOM_BOX_TYPE_HVC2:
	case GF_ISOM_BOX_TYPE_HEV2:
	case GF_ISOM_BOX_TYPE_LHV1:
	case GF_ISOM_BOX_TYPE_LHE1:
	case GF_ISOM_BOX_TYPE_HVT1:
		break;
	default:
		return GF_BAD_PARAM;
	}

	if (operand_type == GF_ISOM_HVCC_SET_TILE_BASE_TRACK) {
		if (entry->type==GF_ISOM_BOX_TYPE_HVC1)
			entry->type = GF_ISOM_BOX_TYPE_HVC2;
		else if (entry->type==GF_ISOM_BOX_TYPE_HEV1)
			entry->type = GF_ISOM_BOX_TYPE_HEV2;
	} else if (operand_type == GF_ISOM_HVCC_SET_TILE) {
		if (!entry->hevc_config) entry->hevc_config = (GF_HEVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_HVCC);
		if (!entry->hevc_config) return GF_OUT_OF_MEM;
		if (entry->hevc_config->config) gf_odf_hevc_cfg_del(entry->hevc_config->config);
		entry->hevc_config->config = NULL;
		entry->type = GF_ISOM_BOX_TYPE_HVT1;
	} else if (operand_type < GF_ISOM_HVCC_SET_LHVC) {
		if ((operand_type != GF_ISOM_HVCC_SET_INBAND) && !entry->hevc_config) {
			entry->hevc_config = (GF_HEVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_HVCC);
			if (!entry->hevc_config) return GF_OUT_OF_MEM;
		}

		if (cfg) {
			if (entry->hevc_config->config) gf_odf_hevc_cfg_del(entry->hevc_config->config);
			entry->hevc_config->config = HEVC_DuplicateConfig(cfg);
		} else {
			operand_type=GF_ISOM_HVCC_SET_INBAND;
		}
		array_incomplete = (operand_type==GF_ISOM_HVCC_SET_INBAND) ? 1 : 0;
		if (entry->hevc_config && nalu_cleanup_config(entry->hevc_config->config ? entry->hevc_config->config->param_array : NULL,
			(operand_type==GF_ISOM_HVCC_SET_INBAND) ? GF_TRUE:GF_FALSE,
			keep_xps)
		) {
			array_incomplete=1;
		}

		if (entry->lhvc_config && nalu_cleanup_config(entry->lhvc_config->config ? entry->lhvc_config->config->param_array : NULL,
			(operand_type==GF_ISOM_HVCC_SET_INBAND),
			keep_xps)
		)
			array_incomplete=1;

		switch (entry->type) {
		case GF_ISOM_BOX_TYPE_HEV1:
		case GF_ISOM_BOX_TYPE_HVC1:
			entry->type = array_incomplete ? GF_ISOM_BOX_TYPE_HEV1 : GF_ISOM_BOX_TYPE_HVC1;
			break;
		case GF_ISOM_BOX_TYPE_HEV2:
		case GF_ISOM_BOX_TYPE_HVC2:
			entry->type = array_incomplete ? GF_ISOM_BOX_TYPE_HEV2 : GF_ISOM_BOX_TYPE_HVC2;
			break;
		case GF_ISOM_BOX_TYPE_LHE1:
		case GF_ISOM_BOX_TYPE_LHV1:
			entry->type = array_incomplete ? GF_ISOM_BOX_TYPE_LHE1 : GF_ISOM_BOX_TYPE_LHV1;
			break;
		}
	} else {

		/*SVCC replacement/removal with HEVC base, backward compatible signaling*/
		if ((operand_type==GF_ISOM_HVCC_SET_LHVC_WITH_BASE_BACKWARD) || (operand_type==GF_ISOM_HVCC_SET_LHVC_WITH_BASE) || (operand_type==GF_ISOM_HVCC_SET_HEVC_TILE_BASE) ) {
			if (!entry->hevc_config) return GF_BAD_PARAM;
			if (!cfg) {
				if (entry->lhvc_config) {
					gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)entry->lhvc_config);
					entry->lhvc_config = NULL;
				}
				if (entry->type==GF_ISOM_BOX_TYPE_LHE1) entry->type = (operand_type==GF_ISOM_HVCC_SET_LHVC_WITH_BASE) ? GF_ISOM_BOX_TYPE_HEV2 : GF_ISOM_BOX_TYPE_HEV1;
				else if (entry->type==GF_ISOM_BOX_TYPE_HEV1) entry->type = (operand_type==GF_ISOM_HVCC_SET_LHVC_WITH_BASE) ? GF_ISOM_BOX_TYPE_HEV2 : GF_ISOM_BOX_TYPE_HEV1;
				else entry->type =  (operand_type==GF_ISOM_HVCC_SET_LHVC_WITH_BASE) ? GF_ISOM_BOX_TYPE_HVC2 : GF_ISOM_BOX_TYPE_HVC1;
			} else {
				if (operand_type != GF_ISOM_HVCC_SET_HEVC_TILE_BASE) {
					if (!entry->lhvc_config) {
						entry->lhvc_config = (GF_HEVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_LHVC);
						if (!entry->lhvc_config) return GF_OUT_OF_MEM;
					}
					if (entry->lhvc_config->config) gf_odf_hevc_cfg_del(entry->lhvc_config->config);
					entry->lhvc_config->config = HEVC_DuplicateConfig(cfg);
					if (!entry->lhvc_config->config) return GF_OUT_OF_MEM;
				}

				if (operand_type==GF_ISOM_HVCC_SET_LHVC_WITH_BASE_BACKWARD) {
					if (entry->type==GF_ISOM_BOX_TYPE_HEV2) entry->type = GF_ISOM_BOX_TYPE_HEV1;
					else entry->type = GF_ISOM_BOX_TYPE_HVC1;
				} else {
					if (entry->type==GF_ISOM_BOX_TYPE_HEV1) entry->type = GF_ISOM_BOX_TYPE_HEV2;
					else entry->type = GF_ISOM_BOX_TYPE_HVC2;
				}
			}
		}
		/*LHEVC track without base*/
		else if (operand_type==GF_ISOM_HVCC_SET_LHVC) {
			if (entry->hevc_config) {
				gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)entry->hevc_config);
				entry->hevc_config=NULL;
			}
			if (!cfg) return GF_BAD_PARAM;

			if (!entry->lhvc_config) {
				entry->lhvc_config = (GF_HEVCConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_LHVC);
				if (!entry->lhvc_config) return GF_OUT_OF_MEM;
			}
			if (entry->lhvc_config->config) gf_odf_hevc_cfg_del(entry->lhvc_config->config);
			entry->lhvc_config->config = HEVC_DuplicateConfig(cfg);
			if (!entry->lhvc_config->config) return GF_OUT_OF_MEM;

			if ((entry->type==GF_ISOM_BOX_TYPE_HEV1) || (entry->type==GF_ISOM_BOX_TYPE_HEV2)) entry->type = GF_ISOM_BOX_TYPE_LHE1;
			else entry->type = GF_ISOM_BOX_TYPE_LHV1;
		}
		/*LHEVC inband, no config change*/
		else if (operand_type==GF_ISOM_LHCC_SET_INBAND) {
			entry->type = GF_ISOM_BOX_TYPE_LHE1;
		}
	}

	HEVC_RewriteESDescriptor(entry);
	return GF_OK;
}

fixed #1785 (fuzz)


GF_Err hvcc_box_read(GF_Box *s, GF_BitStream *bs)
{
	u64 consumed;
	GF_HEVCConfigurationBox *ptr = (GF_HEVCConfigurationBox *)s;

	if (ptr->config) gf_odf_hevc_cfg_del(ptr->config);

	consumed = gf_bs_get_position(bs);
	ptr->config = gf_odf_hevc_cfg_read_bs(bs, (s->type == GF_ISOM_BOX_TYPE_HVCC) ? GF_FALSE : GF_TRUE);
	consumed = gf_bs_get_position(bs) - consumed ;
	ISOM_DECREASE_SIZE(ptr, (u32)consumed)

	return ptr->config ? GF_OK : GF_ISOM_INVALID_FILE;
}

fixed #1785 (fuzz)


void vpcc_box_del(GF_Box *s)
{
	GF_VPConfigurationBox *ptr = (GF_VPConfigurationBox*)s;
	if (ptr->config) gf_odf_vp_cfg_del(ptr->config);
	ptr->config = NULL;
	gf_free(ptr);
}

fixed #1785 (fuzz)


GF_Err gf_isom_mvc_config_del(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
{
	return gf_isom_svc_mvc_config_del(the_file, trackNumber, DescriptionIndex, GF_TRUE);
}

fixed #1785 (fuzz)


GF_HEVCConfig *HEVC_DuplicateConfig(GF_HEVCConfig *cfg)
{
	u8 *data;
	u32 data_size;
	GF_HEVCConfig *new_cfg;
	GF_BitStream *bs;

	if (!cfg) return NULL;
	bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
	gf_odf_hevc_cfg_write_bs(cfg, bs);

	gf_bs_get_content(bs, &data, &data_size);
	gf_bs_del(bs);
	bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);

	new_cfg = gf_odf_hevc_cfg_read_bs(bs, cfg->is_lhvc);
	new_cfg->is_lhvc = cfg->is_lhvc;
	gf_bs_del(bs);
	gf_free(data);
	return new_cfg;
}

fixed #1785 (fuzz)


GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 sampleNumber, GF_MPEGVisualSampleEntryBox *entry)
{
	Bool is_hevc = GF_FALSE;
	//if only one sync given in the sample sync table, insert sps/pps/vps before cra/bla in hevc
//	Bool check_cra_bla = (mdia->information->sampleTable->SyncSample && mdia->information->sampleTable->SyncSample->nb_entries>1) ? 0 : 1;
	Bool check_cra_bla = GF_TRUE;
	Bool insert_nalu_delim = GF_TRUE;
	Bool force_sei_inspect = GF_FALSE;
	GF_Err e = GF_OK;
	GF_BitStream *sei_suffix_bs = NULL;
	Bool ps_transfered = GF_FALSE;
	u32 nal_size, nal_unit_size_field, extractor_mode;
	Bool rewrite_ps, rewrite_start_codes, insert_vdrd_code;
	u8 nal_type;
	u32 nal_hdr, sabt_ref, i, track_num;
	u32 temporal_id = 0;
	GF_ISOFile *file = mdia->mediaTrack->moov->mov;
	GF_TrackReferenceTypeBox *scal = NULL;

	Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_SCAL, &scal);

	rewrite_ps = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG) ? GF_TRUE : GF_FALSE;
	rewrite_start_codes = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG) ? GF_TRUE : GF_FALSE;
	insert_vdrd_code = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_VDRD_FLAG) ? GF_TRUE : GF_FALSE;
	if (!entry->svc_config && !entry->mvc_config && !entry->lhvc_config) insert_vdrd_code = GF_FALSE;
	extractor_mode = mdia->mediaTrack->extractor_mode&0x0000FFFF;

	if (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_TILE_ONLY) {
		insert_nalu_delim = GF_FALSE;
	}

	track_num = 1 + gf_list_find(mdia->mediaTrack->moov->trackList, mdia->mediaTrack);

	if ( (extractor_mode != GF_ISOM_NALU_EXTRACT_INSPECT) && !(mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_TILE_ONLY) ) {
		u32 ref_track, di;
		//aggregate all sabt samples with the same DTS
		if (entry->lhvc_config && !entry->hevc_config && !(mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_LAYER_ONLY)) {
			if (gf_isom_get_reference_count(mdia->mediaTrack->moov->mov, track_num, GF_ISOM_REF_SCAL) <= 0) {
				//FIXME - for now we only support two layers (base + enh) in implicit
				if ( gf_isom_get_reference_count(mdia->mediaTrack->moov->mov, track_num, GF_ISOM_REF_BASE) >= 1) {
					GF_ISOSample *base_samp;
					gf_isom_get_reference(mdia->mediaTrack->moov->mov, track_num, GF_ISOM_REF_BASE, 1, &ref_track);
					switch (gf_isom_get_media_subtype(mdia->mediaTrack->moov->mov , ref_track, 1)) {
					case GF_ISOM_SUBTYPE_HVC1:
					case GF_ISOM_SUBTYPE_HVC2:
					case GF_ISOM_SUBTYPE_HEV1:
					case GF_ISOM_SUBTYPE_HEV2:

						if (!mdia->extracted_samp) {
							mdia->extracted_samp = gf_isom_sample_new();
							if (!mdia->extracted_samp) return GF_OUT_OF_MEM;
						}

						base_samp = gf_isom_get_sample_ex(mdia->mediaTrack->moov->mov, ref_track, sampleNumber + mdia->mediaTrack->sample_count_at_seg_start, &di, mdia->extracted_samp, NULL);
						if (base_samp && base_samp->data) {
							if (!sample->alloc_size || (sample->alloc_size<sample->dataLength+base_samp->dataLength) ) {
								sample->data = gf_realloc(sample->data, sample->dataLength+base_samp->dataLength);
								if (sample->alloc_size) sample->alloc_size = sample->dataLength+base_samp->dataLength;
							}
							memmove(sample->data + base_samp->dataLength, sample->data , sample->dataLength);
							memcpy(sample->data, base_samp->data, base_samp->dataLength);
							sample->dataLength += base_samp->dataLength;
						}
						Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_BASE, &scal);
						break;
					}
				}
			}
		}

		sabt_ref = gf_isom_get_reference_count(mdia->mediaTrack->moov->mov, track_num, GF_ISOM_REF_SABT);
		if ((s32) sabt_ref > 0) {
			force_sei_inspect = GF_TRUE;
			for (i=0; i<sabt_ref; i++) {
				GF_ISOSample *tile_samp;
				gf_isom_get_reference(mdia->mediaTrack->moov->mov, track_num, GF_ISOM_REF_SABT, i+1, &ref_track);

				if (!mdia->extracted_samp) {
					mdia->extracted_samp = gf_isom_sample_new();
					if (!mdia->extracted_samp) return GF_OUT_OF_MEM;
				}

				tile_samp = gf_isom_get_sample_ex(mdia->mediaTrack->moov->mov, ref_track, sampleNumber + mdia->mediaTrack->sample_count_at_seg_start, &di, mdia->extracted_samp, NULL);
				if (tile_samp  && tile_samp ->data) {
					if (!sample->alloc_size || (sample->alloc_size<sample->dataLength+tile_samp->dataLength) ) {
						sample->data = gf_realloc(sample->data, sample->dataLength+tile_samp->dataLength);
						if (sample->alloc_size) sample->alloc_size = sample->dataLength+tile_samp->dataLength;
					}
					memcpy(sample->data + sample->dataLength, tile_samp->data, tile_samp->dataLength);
					sample->dataLength += tile_samp->dataLength;
				}
			}
		}
	}

	if ( gf_isom_get_reference_count(mdia->mediaTrack->moov->mov, track_num, GF_ISOM_REF_TBAS) >= 1) {
		u32 ref_track;
		u32 idx = gf_list_find(mdia->information->sampleTable->SampleDescription->child_boxes, entry);
		GF_TrackBox *tbas;
		gf_isom_get_reference(mdia->mediaTrack->moov->mov, track_num, GF_ISOM_REF_TBAS, 1, &ref_track);
		tbas = (GF_TrackBox *)gf_list_get(mdia->mediaTrack->moov->trackList, ref_track-1);
		entry = gf_list_get(tbas->Media->information->sampleTable->SampleDescription->child_boxes, idx);
	}

	if (sample->IsRAP < SAP_TYPE_2) {
		if (mdia->information->sampleTable->no_sync_found || (!sample->IsRAP && check_cra_bla) ) {
			sample->IsRAP = is_sample_idr(mdia, sample, entry);
		}
	}
	if (!sample->IsRAP)
		rewrite_ps = GF_FALSE;

	if (extractor_mode != GF_ISOM_NALU_EXTRACT_LAYER_ONLY)
		insert_vdrd_code = GF_FALSE;

	if (!entry) return GF_BAD_PARAM;

	//this is a compatible HEVC, don't insert VDRD, insert NALU delim
	if (entry->lhvc_config && entry->hevc_config)
		insert_vdrd_code = GF_FALSE;

	if (extractor_mode == GF_ISOM_NALU_EXTRACT_INSPECT) {
		if (!rewrite_ps && !rewrite_start_codes)
			return GF_OK;
	}

	nal_unit_size_field = 0;
	/*if svc rewrite*/
	if (entry->svc_config && entry->svc_config->config)
		nal_unit_size_field = entry->svc_config->config->nal_unit_size;
	/*if mvc rewrite*/
	if (entry->mvc_config && entry->mvc_config->config)
		nal_unit_size_field = entry->mvc_config->config->nal_unit_size;

	/*if lhvc rewrite*/
	else if (entry->lhvc_config && entry->lhvc_config->config)  {
		is_hevc = GF_TRUE;
		nal_unit_size_field = entry->lhvc_config->config->nal_unit_size;
	}

	/*otherwise do nothing*/
	else if (!rewrite_ps && !rewrite_start_codes && !scal && !force_sei_inspect) {
		return GF_OK;
	}

	if (!nal_unit_size_field) {
		if (entry->avc_config && entry->avc_config->config)
			nal_unit_size_field = entry->avc_config->config->nal_unit_size;
		else if (entry->lhvc_config && entry->lhvc_config->config) {
			nal_unit_size_field = entry->lhvc_config->config->nal_unit_size;
			is_hevc = GF_TRUE;
		}
		else if (entry->hevc_config && entry->hevc_config->config) {
			nal_unit_size_field = entry->hevc_config->config->nal_unit_size;
			is_hevc = GF_TRUE;
		}
	}

	if (!nal_unit_size_field) return GF_ISOM_INVALID_FILE;

	//setup PS rewriter
	if (!mdia->nalu_ps_bs)
		mdia->nalu_ps_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
	gf_bs_seek(mdia->nalu_ps_bs, 0);

	//setup sample reader
	if (mdia->in_sample_buffer_alloc<sample->dataLength) {
		mdia->in_sample_buffer_alloc = sample->dataLength;
		mdia->in_sample_buffer = gf_realloc(mdia->in_sample_buffer, sample->dataLength);
	}
	memcpy(mdia->in_sample_buffer, sample->data, sample->dataLength);

	if (!mdia->nalu_parser) {
		mdia->nalu_parser = gf_bs_new(mdia->in_sample_buffer, sample->dataLength, GF_BITSTREAM_READ);
		if (!mdia->nalu_parser && sample->data) return GF_ISOM_INVALID_FILE;
	} else {
		e = gf_bs_reassign_buffer(mdia->nalu_parser, mdia->in_sample_buffer, sample->dataLength);
		if (e) return e;
	}
	//setup ouput
	if (!mdia->nalu_out_bs) {
		u8 *output;
		u32 outSize;
		mdia->nalu_out_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
		gf_bs_get_content(mdia->nalu_out_bs, &output, &outSize);
	}

	gf_bs_reassign_buffer(mdia->nalu_out_bs, sample->data, sample->alloc_size ? sample->alloc_size : sample->dataLength);

	/*rewrite start code with NALU delim*/
	if (rewrite_start_codes) {

		//we are SVC, don't write NALU delim, only insert VDRD NALU
		if (insert_vdrd_code) {
			if (is_hevc) {
				//spec is not clear here, we don't insert an NALU AU delimiter before the layer starts since it breaks openHEVC
//				insert_nalu_delim=0;
			} else {
				gf_bs_write_int(mdia->nalu_out_bs, 1, 32);
				gf_bs_write_int(mdia->nalu_out_bs, GF_AVC_NALU_VDRD , 8);
				insert_nalu_delim=0;
			}
		}

		//AVC/HEVC base, insert NALU delim
		if (insert_nalu_delim) {
			gf_bs_write_int(mdia->nalu_out_bs, 1, 32);
			if (is_hevc) {
#ifndef GPAC_DISABLE_HEVC
				gf_bs_write_int(mdia->nalu_out_bs, 0, 1);
				gf_bs_write_int(mdia->nalu_out_bs, GF_HEVC_NALU_ACCESS_UNIT, 6);
				gf_bs_write_int(mdia->nalu_out_bs, insert_vdrd_code ? 1 : 0, 6); //we should pick the layerID of the following nalus ...
				gf_bs_write_int(mdia->nalu_out_bs, 1, 3); //nuh_temporal_id_plus1 - cannot be 0, we use 1 by default, and overwrite it if needed at the end

				/*pic-type - by default we signal all slice types possible*/
				gf_bs_write_int(mdia->nalu_out_bs, 2, 3);
				gf_bs_write_int(mdia->nalu_out_bs, 0, 5);
#endif
			} else {
				gf_bs_write_int(mdia->nalu_out_bs, (sample->data[0] & 0x60) | GF_AVC_NALU_ACCESS_UNIT, 8);
				gf_bs_write_int(mdia->nalu_out_bs, 0xF0 , 8); /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
			}
		}
	}

	if (rewrite_ps) {
		Bool has_vps = GF_FALSE;
		//in inspect mode or single-layer mode just use the xPS from this layer
		if (extractor_mode == GF_ISOM_NALU_EXTRACT_DEFAULT) {
			if (scal) {
				for (i=0; i<scal->trackIDCount; i++) {
					GF_TrackBox *a_track = GetTrackbyID(mdia->mediaTrack->moov, scal->trackIDs[i]);
					GF_MPEGVisualSampleEntryBox *an_entry = NULL;
					if (a_track && a_track->Media && a_track->Media->information && a_track->Media->information->sampleTable && a_track->Media->information->sampleTable->SampleDescription)
						an_entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(a_track->Media->information->sampleTable->SampleDescription->child_boxes, 0);

					if (an_entry)
						nalu_merge_ps(mdia->nalu_ps_bs, rewrite_start_codes, nal_unit_size_field, an_entry, is_hevc, &has_vps);
				}
			}
		}
		nalu_merge_ps(mdia->nalu_ps_bs, rewrite_start_codes, nal_unit_size_field, entry, is_hevc, &has_vps);

		if (is_hevc) {
			/*little optimization if we are not asked to start codes: copy over the sample*/
			if (!rewrite_start_codes && !entry->lhvc_config && !scal) {
				if (! ps_transfered) {
					nal_type = (sample->data[nal_unit_size_field] & 0x7E) >> 1;
					//temp fix - if we detect xPS in the beginning of the sample do NOT copy the ps bitstream
					//this is not correct since we are not sure whether they are the same xPS or not, but it crashes openHEVC ...
					switch (nal_type) {
#ifndef GPAC_DISABLE_HEVC
					case GF_HEVC_NALU_VID_PARAM:
					case GF_HEVC_NALU_SEQ_PARAM:
					case GF_HEVC_NALU_PIC_PARAM:
						break;
#endif
					default:
						gf_bs_transfer(mdia->nalu_out_bs, mdia->nalu_ps_bs, GF_TRUE);
						break;
					}
				}
				gf_bs_write_data(mdia->nalu_out_bs, mdia->in_sample_buffer, sample->dataLength);
				gf_bs_get_content_no_truncate(mdia->nalu_out_bs, &sample->data, &sample->dataLength, &sample->alloc_size);

				return GF_OK;
			}
		}
	} else {
		ps_transfered = GF_TRUE;
	}

	/*little optimization if we are not asked to rewrite extractors or start codes: copy over the sample*/
	if (!scal && !rewrite_start_codes && !rewrite_ps && !force_sei_inspect) {
		if (! ps_transfered)
		{
			gf_bs_transfer(mdia->nalu_out_bs, mdia->nalu_ps_bs, GF_TRUE);
		}
		gf_bs_write_data(mdia->nalu_out_bs, mdia->in_sample_buffer, sample->dataLength);
		gf_bs_get_content_no_truncate(mdia->nalu_out_bs, &sample->data, &sample->dataLength, &sample->alloc_size);
		return GF_OK;
	}

	if (!mdia->tmp_nal_copy_buffer) {
		mdia->tmp_nal_copy_buffer = gf_malloc(sizeof(char) * 4096);
		mdia->tmp_nal_copy_buffer_alloc = 4096;
	}

	while (gf_bs_available(mdia->nalu_parser)) {
		nal_size = gf_bs_read_int(mdia->nalu_parser, 8*nal_unit_size_field);
		if (gf_bs_get_position(mdia->nalu_parser) + nal_size > sample->dataLength) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("Sample %u (size %u) rewrite: corrupted NAL Unit (size %u)\n", sampleNumber, sample->dataLength, nal_size));
			goto exit;
		}
		if (nal_size > mdia->tmp_nal_copy_buffer_alloc) {
			mdia->tmp_nal_copy_buffer_alloc = nal_size;
			mdia->tmp_nal_copy_buffer = (char*) gf_realloc(mdia->tmp_nal_copy_buffer, sizeof(char)*nal_size);
		}
		if (is_hevc) {
			nal_hdr = gf_bs_read_u16(mdia->nalu_parser);
			nal_type = (nal_hdr&0x7E00) >> 9;
		} else {
			nal_hdr = gf_bs_read_u8(mdia->nalu_parser);
			nal_type = nal_hdr & 0x1F;
		}

		if (is_hevc) {
#ifndef GPAC_DISABLE_HEVC
			GF_BitStream *write_to_bs = mdia->nalu_out_bs;
#endif

			if (!ps_transfered) {
				gf_bs_transfer(mdia->nalu_out_bs, mdia->nalu_ps_bs, GF_TRUE);
				ps_transfered = GF_TRUE;
			}

#ifndef GPAC_DISABLE_HEVC
			/*we already wrote this stuff*/
			if (nal_type==GF_HEVC_NALU_ACCESS_UNIT) {
				gf_bs_skip_bytes(mdia->nalu_parser, nal_size-2);
				continue;
			}
			switch (nal_type) {
			//extractor
			case 49:
				e = process_extractor(file, mdia, sampleNumber, sample->DTS, nal_size, nal_hdr, nal_unit_size_field, GF_TRUE, rewrite_ps, rewrite_start_codes, extractor_mode);
				if (e) goto exit;
				break;

			case GF_HEVC_NALU_SLICE_TSA_N:
			case GF_HEVC_NALU_SLICE_STSA_N:
			case GF_HEVC_NALU_SLICE_TSA_R:
			case GF_HEVC_NALU_SLICE_STSA_R:
				if (temporal_id < (nal_hdr & 0x7))
					temporal_id = (nal_hdr & 0x7);
				/*rewrite nal*/
				gf_bs_read_data(mdia->nalu_parser, mdia->tmp_nal_copy_buffer, nal_size-2);
				if (rewrite_start_codes)
					gf_bs_write_u32(mdia->nalu_out_bs, 1);
				else
					gf_bs_write_int(mdia->nalu_out_bs, nal_size, 8*nal_unit_size_field);

				gf_bs_write_u16(mdia->nalu_out_bs, nal_hdr);
				gf_bs_write_data(mdia->nalu_out_bs, mdia->tmp_nal_copy_buffer, nal_size-2);
				break;

			case GF_HEVC_NALU_SLICE_BLA_W_LP:
			case GF_HEVC_NALU_SLICE_BLA_W_DLP:
			case GF_HEVC_NALU_SLICE_BLA_N_LP:
			case GF_HEVC_NALU_SLICE_IDR_W_DLP:
			case GF_HEVC_NALU_SLICE_IDR_N_LP:
			case GF_HEVC_NALU_SLICE_CRA:
				//insert xPS before CRA/BLA
				if (check_cra_bla && !sample->IsRAP) {
					sample->IsRAP = sap_type_from_nal_type(nal_type);
					if (sei_suffix_bs) gf_bs_del(sei_suffix_bs);
					return gf_isom_nalu_sample_rewrite(mdia, sample, sampleNumber, entry);
				}
			default:
				/*rewrite nal*/
				if (nal_size<2) {
					GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid nal size %d in sample %d\n", nal_type, sampleNumber));
					e = GF_NON_COMPLIANT_BITSTREAM;
					goto exit;
				}

				gf_bs_read_data(mdia->nalu_parser, mdia->tmp_nal_copy_buffer, nal_size-2);

				if (nal_type==GF_HEVC_NALU_SEI_SUFFIX) {
					if (!sei_suffix_bs) sei_suffix_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
					write_to_bs = sei_suffix_bs;
				}

				if (rewrite_start_codes)
					gf_bs_write_u32(write_to_bs, 1);
				else
					gf_bs_write_int(write_to_bs, nal_size, 8*nal_unit_size_field);

				gf_bs_write_u16(write_to_bs, nal_hdr);
				gf_bs_write_data(write_to_bs, mdia->tmp_nal_copy_buffer, nal_size-2);
			}
#endif

			//done with HEVC
			continue;
		}

		switch(nal_type) {
		case GF_AVC_NALU_ACCESS_UNIT:
			/*we already wrote this stuff*/
			gf_bs_skip_bytes(mdia->nalu_parser, nal_size-1);
			continue;
		//extractor
		case 31:
			e = process_extractor(file, mdia, sampleNumber, sample->DTS, nal_size, nal_hdr, nal_unit_size_field, GF_FALSE, rewrite_ps, rewrite_start_codes, extractor_mode);
			if (e) goto exit;
			break;
//			case GF_AVC_NALU_SEI:
		case GF_AVC_NALU_SEQ_PARAM:
		case GF_AVC_NALU_PIC_PARAM:
		case GF_AVC_NALU_SEQ_PARAM_EXT:
		case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
			// we will rewrite the sps/pps if and only if there is no sps/pps in bistream
			if (!ps_transfered) {
				ps_transfered = GF_TRUE;
			}
		default:
			if (!ps_transfered) {
				gf_bs_transfer(mdia->nalu_out_bs, mdia->nalu_ps_bs, GF_TRUE);
				ps_transfered = GF_TRUE;
			}
			gf_bs_read_data(mdia->nalu_parser, mdia->tmp_nal_copy_buffer, nal_size-1);
			if (rewrite_start_codes)
				gf_bs_write_u32(mdia->nalu_out_bs, 1);
			else
				gf_bs_write_int(mdia->nalu_out_bs, nal_size, 8*nal_unit_size_field);

			gf_bs_write_u8(mdia->nalu_out_bs, nal_hdr);
			gf_bs_write_data(mdia->nalu_out_bs, mdia->tmp_nal_copy_buffer, nal_size-1);
		}
	}

	if (sei_suffix_bs) {
		gf_bs_transfer(mdia->nalu_out_bs, sei_suffix_bs, GF_FALSE);
	}
	/*done*/
	gf_bs_get_content_no_truncate(mdia->nalu_out_bs, &sample->data, &sample->dataLength, &sample->alloc_size);

	/*rewrite temporal ID of AU Ddelim NALU (first one)*/
	if (rewrite_start_codes && is_hevc && temporal_id) {
		sample->data[6] = (sample->data[6] & 0xF8) | (temporal_id+1);
	}

exit:
	if (sei_suffix_bs)
		gf_bs_del(sei_suffix_bs);

	return e;
}

fixed #1785 (fuzz)


GF_Err CoLL_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_VPContentLightLevelBox *p = (GF_VPContentLightLevelBox*)s;
	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u16(bs, p->maxCLL);
	gf_bs_write_u16(bs, p->maxFALL);

	return GF_OK;
}

fixed #1785 (fuzz)


GF_Err gf_isom_hevc_set_inband_config(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, Bool keep_xps)
{
	return gf_isom_hevc_config_update_ex(the_file, trackNumber, DescriptionIndex, NULL, GF_ISOM_HVCC_SET_INBAND, keep_xps);
}

fixed #1785 (fuzz)


static GF_ISOSAPType sap_type_from_nal_type(u8 nal_type) {
	switch (nal_type) {
	case GF_HEVC_NALU_SLICE_CRA:
		return SAP_TYPE_3;
	case GF_HEVC_NALU_SLICE_IDR_N_LP:
	case GF_HEVC_NALU_SLICE_BLA_N_LP:
		return SAP_TYPE_1;
	case GF_HEVC_NALU_SLICE_IDR_W_DLP:
	case GF_HEVC_NALU_SLICE_BLA_W_DLP:
	case GF_HEVC_NALU_SLICE_BLA_W_LP:
		return SAP_TYPE_2;
	default:
		return RAP_NO;
	}
}

fixed #1785 (fuzz)


static GF_DOVIDecoderConfigurationRecord* DOVI_DuplicateConfig(GF_DOVIDecoderConfigurationRecord *cfg)
{
	GF_DOVIDecoderConfigurationRecord* out = NULL;
	GF_SAFEALLOC(out, GF_DOVIDecoderConfigurationRecord);
	if (!out) return NULL;

	out->dv_version_major = cfg->dv_version_major;
	out->dv_version_minor = cfg->dv_version_minor;
	out->dv_profile = cfg->dv_profile;
	out->dv_level = cfg->dv_level;
	out->rpu_present_flag = cfg->rpu_present_flag;
	out->el_present_flag = cfg->el_present_flag;
	out->bl_present_flag = cfg->bl_present_flag;

	return out;
}

fixed #1785 (fuzz)


void AV1_RewriteESDescriptorEx(GF_MPEGVisualSampleEntryBox *av1, GF_MediaBox *mdia)
{
	GF_BitRateBox *btrt = gf_isom_sample_entry_get_bitrate((GF_SampleEntryBox *)av1, GF_FALSE);

	if (av1->emul_esd) gf_odf_desc_del((GF_Descriptor *)av1->emul_esd);
	av1->emul_esd = gf_odf_desc_esd_new(2);
	av1->emul_esd->decoderConfig->streamType = GF_STREAM_VISUAL;
	av1->emul_esd->decoderConfig->objectTypeIndication = GF_CODECID_AV1;

	if (btrt) {
		av1->emul_esd->decoderConfig->bufferSizeDB = btrt->bufferSizeDB;
		av1->emul_esd->decoderConfig->avgBitrate = btrt->avgBitrate;
		av1->emul_esd->decoderConfig->maxBitrate = btrt->maxBitrate;
	}
	if (av1->av1_config && av1->av1_config->config) {
		GF_AV1Config *av1_cfg = AV1_DuplicateConfig(av1->av1_config->config);
		if (av1_cfg) {
			gf_odf_av1_cfg_write(av1_cfg, &av1->emul_esd->decoderConfig->decoderSpecificInfo->data, &av1->emul_esd->decoderConfig->decoderSpecificInfo->dataLength);
			gf_odf_av1_cfg_del(av1_cfg);
		}
	}
}

fixed #1785 (fuzz)


void merge_all_config(GF_AVCConfig *avc_cfg, GF_HEVCConfig *hevc_cfg, GF_MediaBox *mdia)
{
	u32 i;
	GF_TrackReferenceTypeBox *scal = NULL;
	Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_SCAL, &scal);

	if (!scal) return;

	for (i=0; i<scal->trackIDCount; i++) {
		GF_TrackBox *a_track = GetTrackbyID(mdia->mediaTrack->moov, scal->trackIDs[i]);
		GF_MPEGVisualSampleEntryBox *an_entry = NULL;
		if (a_track && a_track->Media && a_track->Media->information && a_track->Media->information->sampleTable && a_track->Media->information->sampleTable->SampleDescription)
			an_entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(a_track->Media->information->sampleTable->SampleDescription->child_boxes, 0);

		if (!an_entry) continue;

		if (avc_cfg && an_entry->svc_config && an_entry->svc_config->config)
			merge_avc_config(avc_cfg, an_entry->svc_config->config);

		if (avc_cfg && an_entry->mvc_config && an_entry->mvc_config->config)
			merge_avc_config(avc_cfg, an_entry->mvc_config->config);

		if (avc_cfg && an_entry->avc_config && an_entry->avc_config->config)
			merge_avc_config(avc_cfg, an_entry->avc_config->config);

		if (hevc_cfg && an_entry->lhvc_config && an_entry->lhvc_config->config)
			merge_hevc_config(hevc_cfg, an_entry->lhvc_config->config, GF_TRUE);

		if (hevc_cfg && an_entry->hevc_config && an_entry->hevc_config->config)
			merge_hevc_config(hevc_cfg, an_entry->hevc_config->config, GF_TRUE);
	}

	if (hevc_cfg) hevc_cfg->is_lhvc = GF_FALSE;
}

fixed #1785 (fuzz)


GF_Err gf_isom_av1_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AV1Config *cfg, const char *URLname, const char *URNname, u32 *outDescriptionIndex)
{
	GF_TrackBox *trak;
	GF_Err e;
	u32 dataRefIndex;
	GF_MPEGVisualSampleEntryBox *entry;
	GF_SampleDescriptionBox *stsd;

	e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
	if (e) return e;

	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak || !trak->Media || !cfg) return GF_BAD_PARAM;

	//get or create the data ref
	e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
	if (e) return e;
	if (!dataRefIndex) {
		e = Media_CreateDataRef(the_file, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
		if (e) return e;
	}
	if (!the_file->keep_utc)
		trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();

	stsd = trak->Media->information->sampleTable->SampleDescription;
	//create a new entry
	entry = (GF_MPEGVisualSampleEntryBox *)gf_isom_box_new_parent(&stsd->child_boxes, GF_ISOM_BOX_TYPE_AV01);
	if (!entry) return GF_OUT_OF_MEM;
	entry->av1_config = (GF_AV1ConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_AV1C);
	if (!entry->av1_config) return GF_OUT_OF_MEM;
	entry->av1_config->config = AV1_DuplicateConfig(cfg);
	if (!entry->av1_config->config) return GF_OUT_OF_MEM;
	entry->dataReferenceIndex = dataRefIndex;
	*outDescriptionIndex = gf_list_count(stsd->child_boxes);
	return e;
}

fixed #1785 (fuzz)


GF_Err gf_isom_linf_write_entry(void *entry, GF_BitStream *bs)
{
	GF_LHVCLayerInformation* ptr = (GF_LHVCLayerInformation *)entry;
	u32 i, count;
	if (!ptr) return GF_OK;

	gf_bs_write_int(bs, 0, 2);
	count=gf_list_count(ptr->num_layers_in_track);
	gf_bs_write_int(bs, count, 6);
	for (i = 0; i < count; i++) {
		LHVCLayerInfoItem *li = (LHVCLayerInfoItem *)gf_list_get(ptr->num_layers_in_track, i);
		gf_bs_write_int(bs, 0, 4);
		gf_bs_write_int(bs, li->layer_id, 6);
		gf_bs_write_int(bs, li->min_TemporalId, 3);
		gf_bs_write_int(bs, li->max_TemporalId, 3);
		gf_bs_write_int(bs, 0, 1);
		gf_bs_write_int(bs, li->sub_layer_presence_flags, 7);
	}
	return GF_OK;
}

fixed #1785 (fuzz)


GF_Err gf_isom_lhvc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_HEVCConfig *cfg, GF_ISOMLHEVCTrackType track_type)
{
	if (cfg) cfg->is_lhvc = GF_TRUE;
	switch (track_type) {
	case GF_ISOM_LEHVC_ONLY:
		return gf_isom_hevc_config_update_ex(the_file, trackNumber, DescriptionIndex, cfg, GF_ISOM_HVCC_SET_LHVC, GF_FALSE);
	case GF_ISOM_LEHVC_WITH_BASE:
		return gf_isom_hevc_config_update_ex(the_file, trackNumber, DescriptionIndex, cfg, GF_ISOM_HVCC_SET_LHVC_WITH_BASE, GF_FALSE);
	case GF_ISOM_LEHVC_WITH_BASE_BACKWARD:
		return gf_isom_hevc_config_update_ex(the_file, trackNumber, DescriptionIndex, cfg, GF_ISOM_HVCC_SET_LHVC_WITH_BASE_BACKWARD, GF_FALSE);
	case GF_ISOM_HEVC_TILE_BASE:
		return gf_isom_hevc_config_update_ex(the_file, trackNumber, DescriptionIndex, cfg, GF_ISOM_HVCC_SET_HEVC_TILE_BASE, GF_FALSE);
	default:
		return GF_BAD_PARAM;
	}
}

fixed #1785 (fuzz)


GF_Box *avcc_box_new()
{
	GF_AVCConfigurationBox *tmp = (GF_AVCConfigurationBox *) gf_malloc(sizeof(GF_AVCConfigurationBox));
	if (tmp == NULL) return NULL;
	memset(tmp, 0, sizeof(GF_AVCConfigurationBox));
	tmp->type = GF_ISOM_BOX_TYPE_AVCC;
	return (GF_Box *)tmp;
}

fixed #1785 (fuzz)


static GF_Err process_extractor(GF_ISOFile *file, GF_MediaBox *mdia, u32 sampleNumber, u64 sampleDTS, u32 nal_size, u16 nal_hdr, u32 nal_unit_size_field, Bool is_hevc, Bool rewrite_ps, Bool rewrite_start_codes, u32 extractor_mode)
{
	GF_Err e;
	u32 di, ref_track_index, ref_track_num, data_offset, data_length, cur_extract_mode, ref_extract_mode, ref_nalu_size, nb_bytes_nalh;
	GF_TrackReferenceTypeBox *dpnd;
	GF_TrackBox *ref_trak;
	s8 sample_offset;
	u32 last_byte, ref_sample_num, prev_ref_sample_num;
	Bool header_written = GF_FALSE;
	nb_bytes_nalh = is_hevc ? 2 : 1;

	switch (extractor_mode) {
	case 0:
		last_byte = (u32) gf_bs_get_position(mdia->nalu_parser) + nal_size - (is_hevc ? 2 : 1);
		if (!is_hevc) gf_bs_read_int(mdia->nalu_parser, 24); //1 byte for HEVC , 3 bytes for AVC of NALUHeader in extractor
		while (gf_bs_get_position(mdia->nalu_parser) < last_byte) {
			u32 xmode = 0;
			//hevc extractors use constructors
			if (is_hevc) xmode = gf_bs_read_u8(mdia->nalu_parser);
			if (xmode) {
				u8 done=0, len = gf_bs_read_u8(mdia->nalu_parser);
				while (done<len) {
					u8 c = gf_bs_read_u8(mdia->nalu_parser);
					done++;
					if (header_written) {
						gf_bs_write_u8(mdia->nalu_out_bs, c);
					} else if (done==nal_unit_size_field) {
						if (rewrite_start_codes) {
							gf_bs_write_int(mdia->nalu_out_bs, 1, 32);
						} else {
							gf_bs_write_u8(mdia->nalu_out_bs, c);
						}
						header_written = GF_TRUE;
					} else if (!rewrite_start_codes) {
						gf_bs_write_u8(mdia->nalu_out_bs, c);
					}
				}
				continue;
			}

			ref_track_index = gf_bs_read_u8(mdia->nalu_parser);
			sample_offset = (s8) gf_bs_read_int(mdia->nalu_parser, 8);
			data_offset = gf_bs_read_int(mdia->nalu_parser, nal_unit_size_field*8);
			data_length = gf_bs_read_int(mdia->nalu_parser, nal_unit_size_field*8);

			Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_SCAL, &dpnd);
			ref_track_num = 0;
			if (dpnd && ref_track_index && (ref_track_index<=dpnd->trackIDCount))
				ref_track_num = gf_isom_get_track_by_id(file, dpnd->trackIDs[ref_track_index-1]);

			if (!ref_track_num) {
				GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("ISOBMF: Extractor target track is not present in file - skipping.\n"));
				return GF_OK;
			}

			cur_extract_mode = gf_isom_get_nalu_extract_mode(file, ref_track_num);

			//we must be in inspect mode only otherwise the reference sample will not be the one stored on file (change in start codes, PS inserted or other NALUs inserted)
			//and this will corrupt extraction (wrong data offsets)
			ref_extract_mode = GF_ISOM_NALU_EXTRACT_INSPECT;
			gf_isom_set_nalu_extract_mode(file, ref_track_num, ref_extract_mode);

			ref_trak = gf_isom_get_track_from_file(file, ref_track_num);
			if (!ref_trak) return GF_ISOM_INVALID_FILE;

			if (!mdia->extracted_samp) {
				mdia->extracted_samp = gf_isom_sample_new();
				if (!mdia->extracted_samp) return GF_IO_ERR;
			}
			if (!mdia->extracted_bs) {
				mdia->extracted_bs = gf_bs_new("a", 1, GF_BITSTREAM_READ);
				if (!mdia->extracted_bs) return GF_IO_ERR;
			}

			e = stbl_findEntryForTime(ref_trak->Media->information->sampleTable, sampleDTS, 0, &ref_sample_num, &prev_ref_sample_num);
			if (e) return e;
			if (!ref_sample_num) ref_sample_num = prev_ref_sample_num;
			if (!ref_sample_num) return GF_ISOM_INVALID_FILE;
			if ((sample_offset<0) && (ref_sample_num > (u32) -sample_offset)) return GF_ISOM_INVALID_FILE;
			ref_sample_num = (u32) ( (s32) ref_sample_num + sample_offset);

			e = Media_GetSample(ref_trak->Media, ref_sample_num, &mdia->extracted_samp, &di, GF_FALSE, NULL);
			if (e) return e;
			if (!mdia->extracted_samp->alloc_size)
				mdia->extracted_samp->alloc_size = mdia->extracted_samp->dataLength;
#if 0
			if (!header_written && rewrite_start_codes) {
				gf_bs_write_int(dst_bs, 1, 32);
				if (is_hevc) {
					gf_bs_write_int(dst_bs, 0, 1);
					gf_bs_write_int(dst_bs, GF_HEVC_NALU_ACCESS_UNIT, 6);
					gf_bs_write_int(dst_bs, 0, 9);
					/*pic-type - by default we signal all slice types possible*/
					gf_bs_write_int(dst_bs, 2, 3);
					gf_bs_write_int(dst_bs, 0, 5);
				} else {
					gf_bs_write_int(dst_bs, (ref_samp->data[0] & 0x60) | GF_AVC_NALU_ACCESS_UNIT, 8);
					gf_bs_write_int(dst_bs, 0xF0 , 8); /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/;
				}
			}
#endif
			gf_bs_reassign_buffer(mdia->extracted_bs, mdia->extracted_samp->data + data_offset, mdia->extracted_samp->dataLength - data_offset);

			if (mdia->extracted_samp->dataLength - data_offset >= data_length) {

				while (data_length && gf_bs_available(mdia->extracted_bs)) {
					if (!header_written) {
						ref_nalu_size = gf_bs_read_int(mdia->extracted_bs, 8*nal_unit_size_field);

						assert(data_length>nal_unit_size_field);
						data_length -= nal_unit_size_field;
						if (data_length > gf_bs_available(mdia->extracted_bs)) {
							data_length = (u32)gf_bs_available(mdia->extracted_bs);
						}
					} else {
						ref_nalu_size = data_length;
					}

					if (ref_nalu_size > mdia->tmp_nal_copy_buffer_alloc) {
						mdia->tmp_nal_copy_buffer_alloc = ref_nalu_size;
						mdia->tmp_nal_copy_buffer = (char*) gf_realloc(mdia->tmp_nal_copy_buffer, sizeof(char) * ref_nalu_size );
					}
					gf_bs_read_data(mdia->extracted_bs, mdia->tmp_nal_copy_buffer, ref_nalu_size);

					if (!header_written) {
						if (rewrite_start_codes)
							gf_bs_write_u32(mdia->nalu_out_bs, 1);
						else
							gf_bs_write_int(mdia->nalu_out_bs, ref_nalu_size, 8*nal_unit_size_field);
					}
					assert(data_length >= ref_nalu_size);
					gf_bs_write_data(mdia->nalu_out_bs, mdia->tmp_nal_copy_buffer, ref_nalu_size);
					data_length -= ref_nalu_size;

					header_written = GF_FALSE;

				}
			} else {
				GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("ISOBMF: Extractor size is larger than referred sample size - skipping.\n"));
			}
			gf_isom_set_nalu_extract_mode(file, ref_track_num, cur_extract_mode);

			if (!is_hevc) break;
		}
		break;
	case 1:
		//skip to end of this NALU
		gf_bs_skip_bytes(mdia->nalu_parser, nal_size - nb_bytes_nalh);
		break;
	case 2:
		if (nal_size - nb_bytes_nalh > mdia->tmp_nal_copy_buffer_alloc) {
			mdia->tmp_nal_copy_buffer_alloc = nal_size - nb_bytes_nalh;
			mdia->tmp_nal_copy_buffer = (char*) gf_realloc(mdia->tmp_nal_copy_buffer, sizeof(char) * (nal_size - nb_bytes_nalh) );
		}
		gf_bs_read_data(mdia->nalu_parser, mdia->tmp_nal_copy_buffer, nal_size - nb_bytes_nalh);
		if (rewrite_start_codes)
			gf_bs_write_u32(mdia->nalu_out_bs, 1);
		else
			gf_bs_write_int(mdia->nalu_out_bs, nal_size, 8*nal_unit_size_field);

		gf_bs_write_u8(mdia->nalu_out_bs, nal_hdr);
		gf_bs_write_data(mdia->nalu_out_bs, mdia->tmp_nal_copy_buffer, nal_size - nb_bytes_nalh);
		break;
	}
	return GF_OK;
}

fixed #1785 (fuzz)


GF_Err gf_isom_mvc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfig *cfg, const char *URLname, const char *URNname, u32 *outDescriptionIndex)
{
	return gf_isom_svc_mvc_config_new(the_file, trackNumber, cfg, GF_TRUE, (char *) URLname, (char *) URNname,outDescriptionIndex);
}

fixed #1785 (fuzz)


GF_Err gf_isom_svc_config_new(GF_ISOFile *the_file, u32 trackNumber, GF_AVCConfig *cfg, const char *URLname, const char *URNname, u32 *outDescriptionIndex)
{
	return gf_isom_svc_mvc_config_new(the_file, trackNumber, cfg, GF_FALSE, (char *) URLname, (char *) URNname,outDescriptionIndex);
}

fixed #1785 (fuzz)