diff --git a/include/gpac/filters.h b/include/gpac/filters.h index d084a7b6a..4f604abab 100644 --- a/include/gpac/filters.h +++ b/include/gpac/filters.h @@ -4867,6 +4867,19 @@ GF_Err gf_filter_pck_set_sap(GF_FilterPacket *pck, GF_FilterSAPType sap_type); */ GF_FilterSAPType gf_filter_pck_get_sap(GF_FilterPacket *pck); +/*! Sets packet switch frame flag +\param pck target packet +\param is_switch_frame switch frame flag of the packet +\return error code if any +*/ +GF_Err gf_filter_pck_set_switch_frame(GF_FilterPacket *pck, Bool is_switch_frame); + +/*! Sets packet switch frame flag +\param pck target packet +\return switch frame flag of the packet +*/ +Bool gf_filter_pck_get_switch_frame(GF_FilterPacket *pck); + /*! Sets packet video interlacing flag \param pck target packet diff --git a/include/gpac/internal/isomedia_dev.h b/include/gpac/internal/isomedia_dev.h index cfcee3377..d335f09f2 100644 --- a/include/gpac/internal/isomedia_dev.h +++ b/include/gpac/internal/isomedia_dev.h @@ -3588,6 +3588,12 @@ typedef struct u8 *data; } GF_DefaultSampleGroupDescriptionEntry; +/*AV1 Switching Entry - Switching Frames*/ +typedef struct +{ + int unused; // C requires that a struct or union has at least one member +} GF_AV1SwitchingEntry; + /*VisualRandomAccessEntry - 'rap ' type*/ typedef struct { diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h index b1074d1f1..1d49e0d38 100644 --- a/include/gpac/internal/media_dev.h +++ b/include/gpac/internal/media_dev.h @@ -932,7 +932,7 @@ typedef struct { Bool is_first_frame; Bool seen_frame_header, seen_seq_header; - Bool key_frame, show_frame; + Bool key_frame, switch_frame, show_frame; AV1FrameType frame_type; GF_List *header_obus, *frame_obus; /*GF_AV1_OBUArrayEntry*/ AV1Tile tiles[AV1_MAX_TILE_ROWS * AV1_MAX_TILE_COLS]; diff --git a/include/gpac/isomedia.h b/include/gpac/isomedia.h index 0940fa96b..a570d4749 100644 --- a/include/gpac/isomedia.h +++ b/include/gpac/isomedia.h @@ -5071,6 +5071,16 @@ GF_Err gf_isom_fragment_set_sample_roll_group(GF_ISOFile *isom_file, GF_ISOTrack */ GF_Err gf_isom_fragment_set_sample_rap_group(GF_ISOFile *isom_file, GF_ISOTrackID trackID, u32 sample_number_in_frag, Bool is_rap, u32 num_leading_samples); +/*! sets AV1 Switching Frame information for a sample in a track fragment +\param isom_file the target ISO file +\param trackID the ID of the target track +\param sample_number_in_frag the sample number of the sample in the traf +\param is_rap set to GF_TRUE to indicate the sample is a RAP sample (open-GOP), GF_FALSE otherwise +\param num_leading_samples set to the number of leading pictures for a RAP sample +\return error if any +*/ +GF_Err gf_isom_fragment_set_sample_av1_switch_frame_group(GF_ISOFile *isom_file, GF_ISOTrackID trackID, u32 sample_number_in_frag, Bool is_switch_Frame); + /*! sets sample dependency flags in a track fragment - see ISO/IEC 14496-12 and \ref gf_filter_pck_set_dependency_flags \param isom_file the target ISO file \param trackID the ID of the target track @@ -7253,6 +7263,7 @@ enum { GF_ISOM_SAMPLE_GROUP_VIPR = GF_4CC( 'v', 'i', 'p', 'r'), //p15 GF_ISOM_SAMPLE_GROUP_LBLI = GF_4CC( 'l', 'b', 'l', 'i'), //p15 GF_ISOM_SAMPLE_GROUP_3GAG = GF_4CC( '3', 'g', 'a', 'g'), //3gpp + GF_ISOM_SAMPLE_GROUP_AV1S = GF_4CC( 'a', 'v', '1', 's'), //av1-isobmff GF_ISOM_SAMPLE_GROUP_AVCB = GF_4CC( 'a', 'v', 'c', 'b'), //avif GF_ISOM_SAMPLE_GROUP_SPOR = GF_4CC( 's', 'p', 'o', 'r'), //p15 GF_ISOM_SAMPLE_GROUP_SULM = GF_4CC( 's', 'u', 'l', 'm'), //p15 @@ -7286,7 +7297,7 @@ Bool gf_isom_get_sample_group_info(GF_ISOFile *isom_file, u32 trackNumber, u32 s \param trackNumber the target track \param sample_number sample number to query \param grouping_type four character code of grouping type of sample group description to query -\param grouping_type_parameter grouping type parameter of sample group description to query +\param grouping_type_parameter grouping type parameter of sample group description to query \param sampleGroupDescIndex set to the 1-based sample group description index, or 0 if no sample group of this type is associated \return error if any */ @@ -7357,6 +7368,18 @@ GF_Err gf_isom_enum_sample_aux_data(GF_ISOFile *isom_file, u32 trackNumber, u32 */ GF_Err gf_isom_set_sample_rap_group(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, Bool is_rap, u32 num_leading_samples); +/*! sets AV1 Switching Frame info for sample_number +\warning Sample group info MUST be added in order (no insertion in the tables) + +\param isom_file the target ISO file +\param trackNumber the target track +\param sampleNumber the target sample number +\param is_rap indicates if the sample is a RAP (open gop) sample +\param num_leading_samples indicates the number of leading samples (samples after this RAP that have dependences on samples before this RAP and hence should be discarded when tuning in) +\return error if any +*/ +GF_Err gf_isom_set_sample_av1_switch_frame_group(GF_ISOFile *isom_file, u32 trackNumber, u32 sampleNumber, Bool is_switch_Frame); + /*! sets roll_distance info for sample_number (number of frames before (<0) or after (>0) this sample to have a complete refresh of the decoded data (used by GDR in AVC) \warning Sample group info MUST be added in order (no insertion in the tables) diff --git a/src/export.cpp b/src/export.cpp index f976f8737..a43587ac1 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -2695,6 +2695,8 @@ #pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_get_timescale ) ) #pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_set_sap ) ) #pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_get_sap ) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_set_switch_frame ) ) +#pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_get_switch_frame ) ) #pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_set_roll_info ) ) #pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_get_roll_info ) ) #pragma comment (linker, EXPORT_SYMBOL(gf_filter_pck_set_interlaced ) ) diff --git a/src/filter_core/filter_pck.c b/src/filter_core/filter_pck.c index 2631edc6e..3aa34ddf0 100644 --- a/src/filter_core/filter_pck.c +++ b/src/filter_core/filter_pck.c @@ -1748,6 +1748,25 @@ GF_FilterSAPType gf_filter_pck_get_sap(GF_FilterPacket *pck) return (GF_FilterSAPType) ( (pck->pck->info.flags & GF_PCK_SAP_MASK) >> GF_PCK_SAP_POS); } +GF_EXPORT +GF_Err gf_filter_pck_set_switch_frame(GF_FilterPacket *pck, Bool is_switch_frame) +{ + PCK_SETTER_CHECK("switch_frame") + pck->info.flags &= ~GF_PCKF_IS_SWITCH_FRAME; + if (is_switch_frame) { + pck->info.flags |= GF_PCKF_IS_SWITCH_FRAME; + } + return GF_OK; +} + +GF_EXPORT +Bool gf_filter_pck_get_switch_frame(GF_FilterPacket *pck) +{ + gf_assert(pck); + //get true packet pointer + return (Bool) (pck->pck->info.flags & GF_PCKF_IS_SWITCH_FRAME) ? GF_TRUE : GF_FALSE; +} + GF_EXPORT GF_Err gf_filter_pck_set_roll_info(GF_FilterPacket *pck, s16 roll_count) { diff --git a/src/filter_core/filter_session.h b/src/filter_core/filter_session.h index bf8feb3ca..2c3738550 100644 --- a/src/filter_core/filter_session.h +++ b/src/filter_core/filter_session.h @@ -196,7 +196,8 @@ enum GF_PCKF_FORCE_MAIN = 1<<12, //only valid when GF_PCK_CMD_PID_EOS is set GF_PCKF_IS_FLUSH = 1<<11, - //RESERVED bits [8,10] + GF_PCKF_IS_SWITCH_FRAME = 1<<10, + //RESERVED bits [8,9] //2 bits for is_leading GF_PCK_ISLEADING_POS = 6, diff --git a/src/filters/dasher.c b/src/filters/dasher.c index 264db593a..53f2dac1d 100644 --- a/src/filters/dasher.c +++ b/src/filters/dasher.c @@ -9394,6 +9394,7 @@ static GF_Err dasher_process(GF_Filter *filter) } GF_FilterPacket *pck = gf_filter_pid_get_packet(ds->ipid); if (!pck) continue; + u64 ts = gf_filter_pck_get_cts(pck); if (ts != GF_FILTER_NO_TS) { //only adjust if delay is negative (skip), otherwise (delay) keep min ts as is. @@ -9452,6 +9453,7 @@ static GF_Err dasher_process(GF_Filter *filter) if (!ds->request_period_switch) { gf_assert(ds->period == ctx->current_period); pck = gf_filter_pid_get_packet(ds->ipid); + //we may change period after a packet fetch (reconfigure of input pid) if ((ds->period != ctx->current_period) || ds->request_period_switch) { //in closest mode, flush queue @@ -10022,8 +10024,9 @@ static GF_Err dasher_process(GF_Filter *filter) } if (is_cue_split) { - if (!sap_type) { - GF_LOG(ctx->strict_cues ? GF_LOG_ERROR : GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] cue found (sn %d - dts "LLD" - cts "LLD") for PID %s but packet %d is not RAP !\n", cue->sample_num, cue->dts, cue->cts, gf_filter_pid_get_name(ds->ipid), ds->nb_pck)); + Bool switch_frame = gf_filter_pck_get_switch_frame(pck); + if (!sap_type && !switch_frame) { + GF_LOG(ctx->strict_cues ? GF_LOG_ERROR : GF_LOG_WARNING, GF_LOG_DASH, ("[DASH] cue found (sn %d - dts "LLD" - cts "LLD") for PID %s but packet %d is not a RAP nor a switch frame!\n", cue->sample_num, cue->dts, cue->cts, gf_filter_pid_get_name(ds->ipid), ds->nb_pck)); if (ctx->strict_cues) { gf_filter_pid_drop_packet(ds->ipid); gf_filter_pid_set_discard(ds->ipid, GF_TRUE); @@ -10054,7 +10057,6 @@ static GF_Err dasher_process(GF_Filter *filter) ds->set->starts_with_sap = sap_type; } - seg_over = GF_TRUE; if (ds == base_ds) { base_ds->adjusted_next_seg_start = cts; diff --git a/src/filters/isoffin.h b/src/filters/isoffin.h index 19b3b7176..d17b077dd 100644 --- a/src/filters/isoffin.h +++ b/src/filters/isoffin.h @@ -161,7 +161,7 @@ typedef struct GF_ISOSample *sample; u64 sample_data_offset, last_valid_sample_data_offset; GF_Err last_state; - Bool sap_3; + Bool sap_3, switch_frame; GF_ISOSampleRollType sap_4_type; s32 roll; u32 xps_mask; diff --git a/src/filters/isoffin_read.c b/src/filters/isoffin_read.c index 260c91a4a..db72b7e48 100644 --- a/src/filters/isoffin_read.c +++ b/src/filters/isoffin_read.c @@ -1189,7 +1189,7 @@ static Bool isoffin_process_event(GF_Filter *filter, const GF_FilterEvent *evt) } } } - //activate first channel - if input is loaded and we canceled the event, remember we may no onger receive eos signals from source + //activate first channel - if input is loaded and we canceled the event, remember we may no longer receive eos signals from source //this happens because the last playing track may have send a STOP to the source but we here no longer send play if (!read->nb_playing) { read->in_is_eos = (read->input_loaded && cancel_event) ? GF_TRUE : GF_FALSE; @@ -1652,7 +1652,7 @@ static GF_Err isoffin_process(GF_Filter *filter) } gf_filter_pck_set_dts(pck, ch->dts); gf_filter_pck_set_cts(pck, ch->cts + ch->cts_offset); - if (ch->sample->IsRAP==-1) { + if (ch->sample->IsRAP==RAP_REDUNDANT) { gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1); ch->redundant = 1; } else { @@ -1666,6 +1666,10 @@ static GF_Err isoffin_process(GF_Filter *filter) gf_filter_pck_set_roll_info(pck, ch->roll); } + if (ch->switch_frame) { + gf_filter_pck_set_switch_frame(pck, GF_TRUE); + } + sample_dur = ch->sample->duration; if (ch->sample->nb_pack) sample_dur *= ch->sample->nb_pack; diff --git a/src/filters/isoffin_read_ch.c b/src/filters/isoffin_read_ch.c index 913c15125..eb17902ae 100644 --- a/src/filters/isoffin_read_ch.c +++ b/src/filters/isoffin_read_ch.c @@ -611,12 +611,16 @@ void isor_reader_get_sample(ISOMChannel *ch) ch->last_state = GF_OK; ch->sap_3 = GF_FALSE; + ch->switch_frame = GF_FALSE; ch->sap_4_type = 0; ch->roll = 0; if (ch->sample) { gf_isom_get_sample_rap_roll_info(ch->owner->mov, ch->track, ch->sample_num, &ch->sap_3, &ch->sap_4_type, &ch->roll); + GF_Err isom_get_sample_switch_frame(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *switch_frame); + isom_get_sample_switch_frame(ch->owner->mov, ch->track, ch->sample_num, &ch->switch_frame); + /*still seeking or not ? 1- when speed is negative, the RAP found is "after" the seek point in playback order since we used backward RAP search: nothing to do 2- otherwise set DTS+CTS to start value @@ -1170,7 +1174,6 @@ void isor_set_sample_groups_and_aux_data(ISOMReader *read, ISOMChannel *ch, GF_F gf_filter_pck_set_property_dyn(pck, szPName, &PROP_DATA_NO_COPY(sai_data, sai_size) ); } - while (1) { GF_Err gf_isom_pop_emsg(GF_ISOFile *the_file, u8 **emsg_data, u32 *emsg_size); u8 *data=NULL; @@ -1180,7 +1183,6 @@ void isor_set_sample_groups_and_aux_data(ISOMReader *read, ISOMChannel *ch, GF_F gf_filter_pck_set_property_str(pck, "emsg", &PROP_DATA_NO_COPY(data, size)); } - } diff --git a/src/filters/mux_isom.c b/src/filters/mux_isom.c index e3b4c121f..94bea0d5d 100644 --- a/src/filters/mux_isom.c +++ b/src/filters/mux_isom.c @@ -5207,15 +5207,15 @@ static GF_Err mp4_mux_process_sample(GF_MP4MuxCtx *ctx, TrackWriter *tkw, GF_Fil } //compat with old arch: write sample to group info for all samples - if ((sap_type==3) || tkw->has_open_gop) { + if ((sap_type==GF_FILTER_SAP_3) || tkw->has_open_gop) { if (!ctx->norap) { if (for_fragment) { #ifndef GPAC_DISABLE_ISOM_FRAGMENTS - e = gf_isom_fragment_set_sample_rap_group(ctx->file, tkw->track_id, tkw->samples_in_frag, (sap_type==3) ? GF_TRUE : GF_FALSE, 0); + e = gf_isom_fragment_set_sample_rap_group(ctx->file, tkw->track_id, tkw->samples_in_frag, (sap_type==GF_FILTER_SAP_3) ? GF_TRUE : GF_FALSE, 0); #else e = GF_NOT_SUPPORTED; #endif - } else if (sap_type==3) { + } else if (sap_type==GF_FILTER_SAP_3) { e = gf_isom_set_sample_rap_group(ctx->file, tkw->track_num, tkw->nb_samples, GF_TRUE /*(sap_type==3) ? GF_TRUE : GF_FALSE*/, 0); } if (e) { @@ -5224,6 +5224,22 @@ static GF_Err mp4_mux_process_sample(GF_MP4MuxCtx *ctx, TrackWriter *tkw, GF_Fil } tkw->has_open_gop = GF_TRUE; } + + if (gf_filter_pck_get_switch_frame(pck)) { + if (for_fragment) { +#ifndef GPAC_DISABLE_ISOM_FRAGMENTS + e = gf_isom_fragment_set_sample_av1_switch_frame_group(ctx->file, tkw->track_id, tkw->samples_in_frag, GF_TRUE); +#else + e = GF_NOT_SUPPORTED; +#endif + } else { + e = gf_isom_set_sample_av1_switch_frame_group(ctx->file, tkw->track_num, tkw->nb_samples, GF_TRUE); + } + if (e) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set sample DTS "LLU" SAP 3 in RAP group: %s\n", tkw->sample.DTS, gf_error_to_string(e) )); + } + } + if (!ctx->noroll) { if ((sap_type==GF_FILTER_SAP_4) || (sap_type==GF_FILTER_SAP_4_PROL) || tkw->gdr_type) { GF_ISOSampleRollType roll_type = 0; diff --git a/src/filters/reframe_av1.c b/src/filters/reframe_av1.c index fc7716a8b..22d47c39d 100644 --- a/src/filters/reframe_av1.c +++ b/src/filters/reframe_av1.c @@ -1051,6 +1051,7 @@ static GF_Err av1dmx_parse_flush_sample(GF_Filter *filter, GF_AV1DmxCtx *ctx) 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); + gf_filter_pck_set_switch_frame(pck, ctx->state.frame_state.switch_frame); if (ctx->is_iamf) { memcpy(output, ctx->iamfstate.temporal_unit_obus, pck_size); @@ -1069,7 +1070,7 @@ static GF_Err av1dmx_parse_flush_sample(GF_Filter *filter, GF_AV1DmxCtx *ctx) if (ctx->deps) { u8 flags = 0; //dependsOn - flags = ( ctx->state.frame_state.key_frame) ? 2 : 1; + flags = (ctx->state.frame_state.key_frame || ctx->state.frame_state.switch_frame) ? 2 : 1; flags <<= 2; //dependedOn flags |= ctx->state.frame_state.refresh_frame_flags ? 1 : 2; diff --git a/src/isomedia/box_code_base.c b/src/isomedia/box_code_base.c index 3818e222d..6efcbadb4 100644 --- a/src/isomedia/box_code_base.c +++ b/src/isomedia/box_code_base.c @@ -10372,6 +10372,7 @@ void *sgpd_parse_entry(GF_SampleGroupDescriptionBox *p, GF_BitStream *bs, s32 by } break; + case GF_ISOM_SAMPLE_GROUP_AV1S: case GF_ISOM_SAMPLE_GROUP_TSAS: case GF_ISOM_SAMPLE_GROUP_STSA: null_size_ok = GF_TRUE; @@ -10708,6 +10709,7 @@ static u32 sgpd_size_entry(u32 grouping_type, void *entry) return 20; case GF_ISOM_SAMPLE_GROUP_LBLI: return 2; + case GF_ISOM_SAMPLE_GROUP_AV1S: case GF_ISOM_SAMPLE_GROUP_TSAS: case GF_ISOM_SAMPLE_GROUP_STSA: return 0; diff --git a/src/isomedia/box_funcs.c b/src/isomedia/box_funcs.c index f1cd9d08f..f4a3e1149 100644 --- a/src/isomedia/box_funcs.c +++ b/src/isomedia/box_funcs.c @@ -1439,6 +1439,7 @@ static struct box_registry_entry { //AV1 in ISOBMFF boxes BOX_DEFINE_S_CHILD(GF_ISOM_BOX_TYPE_AV01, video_sample_entry, "stsd", "av1"), BOX_DEFINE_S(GF_ISOM_BOX_TYPE_AV1C, av1c, "av01 encv resv ipco dav1", "av1"), + SGPD_DEFINE( GF_ISOM_BOX_TYPE_SGPD, sgpd, "stbl traf", GF_ISOM_SAMPLE_GROUP_AV1S, "av1"), // VP8-9 boxes FBOX_DEFINE_FLAGS_S( GF_ISOM_BOX_TYPE_VPCC, vpcc, "vp08 vp09 vp10 encv resv", 1, 0, "vp"), diff --git a/src/isomedia/isom_read.c b/src/isomedia/isom_read.c index c07fa89ce..473c1264c 100644 --- a/src/isomedia/isom_read.c +++ b/src/isomedia/isom_read.c @@ -5051,6 +5051,70 @@ Bool gf_isom_has_cenc_sample_group(GF_ISOFile *the_file, u32 trackNumber, Bool * return GF_TRUE; } +GF_Err isom_get_sample_switch_frame(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *switch_frame) +{ + GF_TrackBox *trak; + u32 i, count; + + if (switch_frame) *switch_frame = GF_FALSE; + + trak = gf_isom_get_track_box(the_file, trackNumber); + if (!trak) return GF_BAD_PARAM; + if (!trak->Media->information->sampleTable->sampleGroups) return GF_OK; + + if (!sample_number) { + count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); + for (i=0; iMedia->information->sampleTable->sampleGroupsDescription, i); + switch (sgdesc->grouping_type) { + case GF_ISOM_SAMPLE_GROUP_AV1S: + if (switch_frame) *switch_frame = GF_TRUE; + break; + } + } + return GF_OK; + } + + count = gf_list_count(trak->Media->information->sampleTable->sampleGroups); + for (i=0; iMedia->information->sampleTable->sampleGroups, i); + for (j=0; jentry_count; j++) { + last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1; + if ((sample_numberlast_sample_in_entry)) { + first_sample_in_entry = last_sample_in_entry+1; + continue; + } + /*we found our sample*/ + group_desc_index = sg->sample_entries[j].group_description_index; + break; + } + /*no sampleGroup info associated*/ + if (!group_desc_index) continue; + + sgdesc = NULL; + for (j=0; jMedia->information->sampleTable->sampleGroupsDescription); j++) { + sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j); + if (sgdesc->grouping_type==sg->grouping_type) break; + sgdesc = NULL; + } + /*no sampleGroup description found for this group (invalid file)*/ + if (!sgdesc) continue; + + switch (sgdesc->grouping_type) { + case GF_ISOM_SAMPLE_GROUP_AV1S: + if (switch_frame) *switch_frame = GF_TRUE; + break; + } + } + return GF_OK; +} + GF_EXPORT GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *is_rap, GF_ISOSampleRollType *roll_type, s32 *roll_distance) { diff --git a/src/isomedia/isom_write.c b/src/isomedia/isom_write.c index 3e5d2a58b..746703c3a 100644 --- a/src/isomedia/isom_write.c +++ b/src/isomedia/isom_write.c @@ -7673,6 +7673,7 @@ GF_Err gf_isom_add_sample_info(GF_ISOFile *movie, u32 track, u32 sample_number, return gf_isom_add_sample_group_entry(groupList, sample_number, sgdesc, grouping_type_parameter, sampleGroupDescriptionIndex, trak->Media->information->sampleTable->child_boxes, trak->Media->information->sampleTable); } + void *sg_rap_create_entry(void *udta) { GF_VisualRandomAccessEntry *entry; @@ -7704,6 +7705,31 @@ GF_Err gf_isom_fragment_set_sample_rap_group(GF_ISOFile *movie, GF_ISOTrackID tr } +void *sg_av1s_create_entry(void *udta) +{ + GF_AV1SwitchingEntry *entry; + GF_SAFEALLOC(entry, GF_AV1SwitchingEntry); + if (!entry) return NULL; + return entry; +} + +Bool sg_av1s_compare_entry(void *udta, void *entry) +{ + return GF_TRUE; +} + +GF_EXPORT +GF_Err gf_isom_set_sample_av1_switch_frame_group(GF_ISOFile *movie, u32 track, u32 sample_number, Bool is_switch_Frame) +{ + return gf_isom_set_sample_group_info_internal(movie, track, 0, sample_number, GF_ISOM_SAMPLE_GROUP_AV1S, 0, NULL, is_switch_Frame ? sg_av1s_create_entry : NULL, is_switch_Frame ? sg_av1s_compare_entry : NULL); +} + +GF_Err gf_isom_fragment_set_sample_av1_switch_frame_group(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 sample_number_in_frag, Bool is_switch_Frame) +{ + return gf_isom_set_sample_group_info_internal(movie, 0, trackID, sample_number_in_frag, GF_ISOM_SAMPLE_GROUP_AV1S, 0, NULL, is_switch_Frame ? sg_av1s_create_entry : NULL, is_switch_Frame ? sg_av1s_compare_entry : NULL); +} + + void *sg_roll_create_entry(void *udta) { diff --git a/src/media_tools/av_parsers.c b/src/media_tools/av_parsers.c index 2e69b6d72..f20e94771 100644 --- a/src/media_tools/av_parsers.c +++ b/src/media_tools/av_parsers.c @@ -3515,6 +3515,9 @@ static void av1_parse_uncompressed_header(GF_BitStream *bs, AV1State *state) if (frame_state->is_first_frame) { frame_state->key_frame = frame_state->seen_seq_header && frame_state->show_frame && frame_state->frame_type == AV1_KEY_FRAME && frame_state->seen_frame_header; } + if (frame_state->frame_type == AV1_SWITCH_FRAME) { + frame_state->switch_frame = GF_TRUE; + } if (frame_state->show_frame && state->decoder_model_info_present_flag && !state->equal_picture_interval) { gf_bs_read_int_log(bs, state->frame_presentation_time_length, "frame_presentation_time"); }