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_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; }
GF_Err gf_webvtt_parser_parse(GF_WebVTTParser *parser, u32 duration) { char szLine[2048]; char *sOK; u32 len; GF_Err e; Bool do_parse = GF_TRUE; GF_WebVTTCue *cue = NULL; u32 start = 0; u32 end = 0; char *prevLine = NULL; char *header = NULL; u32 header_len = 0; Bool had_marks = GF_FALSE; if (!parser) return GF_BAD_PARAM; if (parser->is_srt) { parser->on_header_parsed(parser->user, gf_strdup("WEBVTT\n")); } while (do_parse) { sOK = gf_text_get_utf8_line(szLine, 2048, parser->vtt_in, parser->unicode_type); REM_TRAIL_MARKS(szLine, "\r\n") len = (u32) strlen(szLine); switch (parser->state) { case WEBVTT_PARSER_STATE_WAITING_SIGNATURE: if (!sOK || len < 6 || strnicmp(szLine, "WEBVTT", 6) || (len > 6 && szLine[6] != ' ' && szLine[6] != '\t')) { e = GF_CORRUPTED_DATA; parser->report_message(parser->user, e, "Bad WEBVTT file signature %s", szLine); goto exit; } else { if (had_marks) { szLine[len] = '\n'; len++; } header = gf_strdup(szLine); header_len = len; parser->state = WEBVTT_PARSER_STATE_WAITING_HEADER; } break; /* proceed to next line */ case WEBVTT_PARSER_STATE_WAITING_HEADER: if (prevLine) { u32 prev_len = (u32) strlen(prevLine); header = (char *)gf_realloc(header, header_len + prev_len + 1); strcpy(header+header_len,prevLine); header_len += prev_len; gf_free(prevLine); prevLine = NULL; } if (sOK && len) { if (strstr(szLine, "-->")) { parser->on_header_parsed(parser->user, header); /* continue to the next state without breaking */ parser->state = WEBVTT_PARSER_STATE_WAITING_CUE_TIMESTAMP; /* no break, continue to the next state*/ } else { if (had_marks) { szLine[len] = '\n'; len++; } prevLine = gf_strdup(szLine); break; /* proceed to next line */ } } else { parser->on_header_parsed(parser->user, header); if (!sOK) { /* end of file, parsing is done */ do_parse = GF_FALSE; break; } else { /* empty line means end of header */ parser->state = WEBVTT_PARSER_STATE_WAITING_CUE; /* no break, continue to the next state*/ } } case WEBVTT_PARSER_STATE_WAITING_CUE: if (sOK && len) { if (strstr(szLine, "-->")) { parser->state = WEBVTT_PARSER_STATE_WAITING_CUE_TIMESTAMP; /* continue to the next state without breaking */ } else { /* discard the previous line */ /* should we do something with it ? callback ?*/ if (prevLine) { gf_free(prevLine); prevLine = NULL; } /* save this new line */ if (had_marks) { szLine[len] = '\n'; len++; } prevLine = gf_strdup(szLine); /* stay in the same state */ break; } } else { /* discard the previous line */ /* should we do something with it ? callback ?*/ if (prevLine) { gf_free(prevLine); prevLine = NULL; } if (!sOK) { do_parse = GF_FALSE; break; } else { /* remove empty lines and stay in the same state */ break; } } case WEBVTT_PARSER_STATE_WAITING_CUE_TIMESTAMP: if (sOK && len) { if (cue == NULL) { cue = gf_webvtt_cue_new(); } if (prevLine) { gf_webvtt_cue_add_property(cue, WEBVTT_ID, prevLine, (u32) strlen(prevLine)); gf_free(prevLine); prevLine = NULL; } e = gf_webvtt_parser_parse_timings_settings(parser, cue, szLine, len); if (e) { if (cue) gf_webvtt_cue_del(cue); cue = NULL; parser->state = WEBVTT_PARSER_STATE_WAITING_CUE; } else { start = (u32)gf_webvtt_timestamp_get(&cue->start); end = (u32)gf_webvtt_timestamp_get(&cue->end); parser->state = WEBVTT_PARSER_STATE_WAITING_CUE_PAYLOAD; } } else { /* not possible */ assert(0); } break; case WEBVTT_PARSER_STATE_WAITING_CUE_PAYLOAD: if (sOK && len) { if (had_marks) { szLine[len] = '\n'; len++; } gf_webvtt_cue_add_property(cue, WEBVTT_PAYLOAD, szLine, len); /* remain in the same state as a cue payload can have multiple lines */ break; } else { /* end of the current cue */ gf_webvtt_add_cue_to_samples(parser, parser->samples, cue); cue = NULL; gf_set_progress("Importing WebVTT", gf_ftell(parser->vtt_in), parser->file_size); if ((duration && (end >= duration)) || !sOK) { do_parse = GF_FALSE; break; } else { /* empty line, move to next cue */ parser->state = WEBVTT_PARSER_STATE_WAITING_CUE; break; } } } if (duration && (start >= duration)) { do_parse = GF_FALSE; break; } } /* no more cues to come, flush everything */ if (cue) { gf_webvtt_add_cue_to_samples(parser, parser->samples, cue); cue = NULL; } while (gf_list_count(parser->samples) > 0) { GF_WebVTTSample *sample = (GF_WebVTTSample *)gf_list_get(parser->samples, 0); parser->last_duration = sample->end - sample->start; gf_list_rem(parser->samples, 0); parser->on_sample_parsed(parser->user, sample); } gf_set_progress("Importing WebVTT", parser->file_size, parser->file_size); e = GF_OK; exit: if (cue) gf_webvtt_cue_del(cue); if (prevLine) gf_free(prevLine); if (header) gf_free(header); return e; }