GF_Err gf_webvtt_dump_iso_sample(FILE *dump, u32 timescale, GF_ISOSample *iso_sample) { GF_Err e; GF_BitStream *bs; bs = gf_bs_new(iso_sample->data, iso_sample->dataLength, GF_BITSTREAM_READ); while(gf_bs_available(bs)) { GF_Box *box; GF_WebVTTTimestamp ts; e = gf_isom_parse_box(&box, bs); if (e) return e; if (box->type == GF_ISOM_BOX_TYPE_VTCU) { GF_VTTCueBox *cuebox = (GF_VTTCueBox *)box; if (cuebox->id) fprintf(dump, "%s", cuebox->id->string); gf_webvtt_timestamp_set(&ts, (iso_sample->DTS * 1000) / timescale); gf_webvtt_timestamp_dump(&ts, dump, GF_FALSE); fprintf(dump, " --> NEXT"); if (cuebox->settings) fprintf(dump, " %s", cuebox->settings->string); fprintf(dump, "\n"); if (cuebox->payload) fprintf(dump, "%s", cuebox->payload->string); fprintf(dump, "\n"); } else if (box->type == GF_ISOM_BOX_TYPE_VTTE) { gf_webvtt_timestamp_set(&ts, (iso_sample->DTS * 1000) / timescale); gf_webvtt_timestamp_dump(&ts, dump, GF_FALSE); fprintf(dump, " --> NEXT\n\n"); } else if (box->type == GF_ISOM_BOX_TYPE_VTTA) { fprintf(dump, "%s\n\n", ((GF_StringBox *)box)->string); } gf_isom_box_del(box); } gf_bs_del(bs); return GF_OK; }
GF_List *gf_webvtt_parse_iso_cues(GF_ISOSample *iso_sample, u64 start) { GF_List *cues; GF_WebVTTCue *cue; GF_VTTCueBox *cuebox; GF_BitStream *bs; cues = gf_list_new(); bs = gf_bs_new(iso_sample->data, iso_sample->dataLength, GF_BITSTREAM_READ); while(gf_bs_available(bs)) { GF_Err e; GF_Box *box; e = gf_isom_parse_box(&box, bs); if (e) return NULL; if (box->type == GF_ISOM_BOX_TYPE_VTCU) { cuebox = (GF_VTTCueBox *)box; cue = gf_webvtt_cue_new(); gf_list_add(cues, cue); gf_webvtt_timestamp_set(&cue->start, start); if (cuebox->id) { gf_webvtt_cue_add_property(cue, WEBVTT_ID, cuebox->id->string, (u32) strlen(cuebox->id->string)); } if (cuebox->settings) { gf_webvtt_cue_add_property(cue, WEBVTT_SETTINGS, cuebox->settings->string, (u32) strlen(cuebox->settings->string)); } if (cuebox->payload) { gf_webvtt_cue_add_property(cue, WEBVTT_PAYLOAD, cuebox->payload->string, (u32) strlen(cuebox->payload->string)); } } gf_isom_box_del(box); } gf_bs_del(bs); return cues; }
GF_Err gf_webvtt_dump_iso_sample(FILE *dump, u32 timescale, GF_ISOSample *iso_sample, Bool box_mode) { GF_Err e; GF_BitStream *bs; if (box_mode) { fprintf(dump, "<WebVTTSample decodingTimeStamp=\""LLU"\" compositionTimeStamp=\""LLD"\" RAP=\"%d\" dataLength=\"%d\" >\n", iso_sample->DTS, (s64)iso_sample->DTS + iso_sample->CTS_Offset, iso_sample->IsRAP, iso_sample->dataLength); } bs = gf_bs_new(iso_sample->data, iso_sample->dataLength, GF_BITSTREAM_READ); while(gf_bs_available(bs)) { GF_Box *box; GF_WebVTTTimestamp ts; e = gf_isom_box_parse(&box, bs); if (e) return e; if (box_mode) { gf_isom_box_dump(box, dump); } else if (box->type == GF_ISOM_BOX_TYPE_VTCC_CUE) { GF_VTTCueBox *cuebox = (GF_VTTCueBox *)box; if (cuebox->id) fprintf(dump, "%s", cuebox->id->string); gf_webvtt_timestamp_set(&ts, (iso_sample->DTS * 1000) / timescale); gf_webvtt_timestamp_dump(&ts, dump, GF_FALSE); fprintf(dump, " --> NEXT"); if (cuebox->settings) fprintf(dump, " %s", cuebox->settings->string); fprintf(dump, "\n"); if (cuebox->payload) fprintf(dump, "%s", cuebox->payload->string); fprintf(dump, "\n"); } else if (box->type == GF_ISOM_BOX_TYPE_VTTE) { gf_webvtt_timestamp_set(&ts, (iso_sample->DTS * 1000) / timescale); gf_webvtt_timestamp_dump(&ts, dump, GF_FALSE); fprintf(dump, " --> NEXT\n\n"); } else if (box->type == GF_ISOM_BOX_TYPE_VTTA) { fprintf(dump, "%s\n\n", ((GF_StringBox *)box)->string); } gf_isom_box_del(box); } gf_bs_del(bs); if (box_mode) { fprintf(dump, "</WebVTTSample>\n"); } return GF_OK; }
GF_EXPORT GF_List *gf_webvtt_parse_cues_from_data(const char *data, u32 dataLength, u64 start) { GF_List *cues; GF_WebVTTCue *cue; GF_VTTCueBox *cuebox; GF_BitStream *bs; char *pre_text; cue = NULL; pre_text = NULL; cues = gf_list_new(); bs = gf_bs_new(data, dataLength, GF_BITSTREAM_READ); while(gf_bs_available(bs)) { GF_Err e; GF_Box *box; e = gf_isom_parse_box(&box, bs); if (e) return NULL; if (box->type == GF_ISOM_BOX_TYPE_VTCU) { cuebox = (GF_VTTCueBox *)box; cue = gf_webvtt_cue_new(); if (pre_text) { gf_webvtt_cue_add_property(cue, WEBVTT_PRECUE_TEXT, pre_text, (u32) strlen(pre_text)); gf_free(pre_text); pre_text = NULL; } gf_list_add(cues, cue); gf_webvtt_timestamp_set(&cue->start, start); if (cuebox->id) { gf_webvtt_cue_add_property(cue, WEBVTT_ID, cuebox->id->string, (u32) strlen(cuebox->id->string)); } if (cuebox->settings) { gf_webvtt_cue_add_property(cue, WEBVTT_SETTINGS, cuebox->settings->string, (u32) strlen(cuebox->settings->string)); } if (cuebox->payload) { gf_webvtt_cue_add_property(cue, WEBVTT_PAYLOAD, cuebox->payload->string, (u32) strlen(cuebox->payload->string)); } } else if (box->type == GF_ISOM_BOX_TYPE_VTTA) { GF_StringBox *sbox = (GF_StringBox *)box; if (cue) { gf_webvtt_cue_add_property(cue, WEBVTT_POSTCUE_TEXT, sbox->string, (u32) strlen(sbox->string)); } else { pre_text = gf_strdup(sbox->string); } } gf_isom_box_del(box); } gf_bs_del(bs); return cues; }
static GF_Err gf_webvtt_parser_dump_finalize(GF_WebVTTParser *parser, u64 duration) { GF_WebVTTSample *sample; assert(gf_list_count(parser->samples) <= 1); sample = (GF_WebVTTSample *)gf_list_get(parser->samples, 0); if (sample) { while (gf_list_count(sample->cues)) { GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(sample->cues, 0); gf_list_rem(sample->cues, 0); if (gf_webvtt_timestamp_is_zero(&cue->end)) { gf_webvtt_timestamp_set(&cue->end, duration); } parser->on_cue_read(parser->user, cue); } gf_webvtt_sample_del(sample); gf_list_rem(parser->samples, 0); } return GF_OK; }
GF_Err gf_webvtt_merge_cues(GF_WebVTTParser *parser, u64 start, GF_List *cues) { GF_WebVTTSample *wsample; GF_WebVTTSample *prev_wsample; Bool has_continuation_cue = GF_FALSE; assert(gf_list_count(parser->samples) <= 1); wsample = gf_webvtt_sample_new(); wsample->start = start; prev_wsample = (GF_WebVTTSample *)gf_list_last(parser->samples); while (gf_list_count(cues)) { GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, 0); gf_list_rem(cues, 0); /* add the cue to the current sample */ gf_list_add(wsample->cues, cue); /* update with the previous sample */ if (prev_wsample) { Bool found = GF_FALSE; while (!found && gf_list_count(prev_wsample->cues)) { GF_WebVTTCue *old_cue = (GF_WebVTTCue *)gf_list_get(prev_wsample->cues, 0); gf_list_rem(prev_wsample->cues, 0); if ( ((!cue->id && !old_cue->id) || (old_cue->id && cue->id && !strcmp(old_cue->id, cue->id))) && ((!cue->settings && !old_cue->settings) || (old_cue->settings && cue->settings && !strcmp(old_cue->settings, cue->settings))) && ((!cue->text && !old_cue->text) || (old_cue->text && cue->text && !strcmp(old_cue->text, cue->text))) ) { /* if it is the same cue, update its start with the initial start */ cue->start = old_cue->start; has_continuation_cue = GF_TRUE; found = GF_TRUE; if (old_cue->pre_text) { cue->pre_text = old_cue->pre_text; old_cue->pre_text = NULL; } if (old_cue->post_text) { cue->post_text = old_cue->post_text; old_cue->post_text = NULL; } /* delete the old cue */ gf_webvtt_cue_del(old_cue); } else { /* finalize the end cue time */ if (gf_webvtt_timestamp_is_zero(&old_cue->end)) { gf_webvtt_timestamp_set(&old_cue->end, wsample->start); } /* transfer the cue */ if (!has_continuation_cue) { /* the cue can be safely serialized while keeping the order */ parser->on_cue_read(parser->user, old_cue); } else { /* keep the cue in the current sample to respect cue start ordering */ gf_list_add(wsample->cues, old_cue); } } } } } /* No cue in the current sample */ if (prev_wsample) { while (gf_list_count(prev_wsample->cues)) { GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(prev_wsample->cues, 0); gf_list_rem(prev_wsample->cues, 0); /* finalize the end cue time */ if (gf_webvtt_timestamp_is_zero(&cue->end)) { gf_webvtt_timestamp_set(&cue->end, wsample->start); } /* transfer the cue */ if (!has_continuation_cue) { /* the cue can be safely serialized while keeping the order */ parser->on_cue_read(parser->user, cue); } else { /* keep the cue in the current sample to respect cue start ordering */ gf_list_add(wsample->cues, cue); } } gf_webvtt_sample_del(prev_wsample); gf_list_rem_last(parser->samples); prev_wsample = NULL; } else { /* nothing to do */ } if (gf_list_count(wsample->cues)) { gf_list_add(parser->samples, wsample); } else { gf_webvtt_sample_del(wsample); } return GF_OK; }