diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h index 4e7c98f880..7d00feedc2 100644 --- a/include/gpac/internal/media_dev.h +++ b/include/gpac/internal/media_dev.h @@ -1128,6 +1128,15 @@ void gf_media_format_ttxt_sdp(GP_RTPPacketizer *builder, char *payload_name, cha #ifndef GPAC_DISABLE_VTT +#include + +typedef enum { + WEBVTT_PARSER_STATE_WAITING_SIGNATURE, + WEBVTT_PARSER_STATE_WAITING_HEADER, + WEBVTT_PARSER_STATE_WAITING_CUE, + WEBVTT_PARSER_STATE_WAITING_CUE_TIMESTAMP, + WEBVTT_PARSER_STATE_WAITING_CUE_PAYLOAD +} GF_WebVTTParserState; typedef struct _webvtt_parser GF_WebVTTParser; typedef struct _webvtt_sample GF_WebVTTSample; @@ -1141,11 +1150,11 @@ GF_Err gf_webvtt_parser_parse(GF_WebVTTParser *parser); void gf_webvtt_parser_del(GF_WebVTTParser *parser); void gf_webvtt_parser_suspend(GF_WebVTTParser *vttparser); void gf_webvtt_parser_restart(GF_WebVTTParser *parser); +void gf_webvtt_parser_force_state(GF_WebVTTParser *parser, GF_WebVTTParserState state); GF_Err gf_webvtt_parser_parse_payload(GF_WebVTTParser *parser, u64 start, u64 end, const char *vtt_pre, const char *vtt_cueid, const char *vtt_settings); GF_Err gf_webvtt_parser_flush(GF_WebVTTParser *parser); GF_Err gf_webvtt_parser_parse_ext(GF_WebVTTParser *parser, FILE *ext_file, Bool in_eos); -#include void gf_webvtt_parser_cue_callback(GF_WebVTTParser *parser, void (*on_cue_read)(void *, GF_WebVTTCue *), void *udta); GF_Err gf_webvtt_merge_cues(GF_WebVTTParser *parser, u64 start, GF_List *cues); GF_Err gf_webvtt_parser_finalize(GF_WebVTTParser *parser, u64 duration); diff --git a/include/gpac/mpegts.h b/include/gpac/mpegts.h index abf4f876a8..a45e2cf01c 100644 --- a/include/gpac/mpegts.h +++ b/include/gpac/mpegts.h @@ -56,6 +56,7 @@ extern "C" { enum { GF_M2TS_META_ID3 = GF_4CC('I','D','3',' '), GF_M2TS_META_KLVA = GF_4CC('K','L','V','A'), + GF_M2TS_META_WVTT = GF_4CC('W','V','T','T'), }; @@ -298,6 +299,7 @@ typedef enum GF_M2TS_DVB_SUBTITLE = 0x154, GF_M2TS_METADATA_ID3_HLS = 0x155, GF_M2TS_METADATA_ID3_KLVA = 0x156, + GF_M2TS_METADATA_WVTT = 0x157, } GF_M2TSStreamType; diff --git a/src/Makefile b/src/Makefile index e3e8ecc362..8bd4665411 100644 --- a/src/Makefile +++ b/src/Makefile @@ -215,7 +215,7 @@ endif SCENEGRAPH_CFLAGS= MEDIATOOLS_CFLAGS= -LIBGPAC_FILTERS+=filters/bs_agg.o filters/bs_split.o filters/bsrw.o filters/compose.o filters/dasher.o filters/dec_ac52.o filters/dec_bifs.o filters/dec_faad.o filters/dec_img.o filters/dec_j2k.o filters/dec_laser.o filters/dec_mad.o filters/dec_mediacodec.o filters/dec_nvdec.o filters/dec_nvdec_sdk.o filters/dec_odf.o filters/dec_theora.o filters/dec_ttml.o filters/dec_ttxt.o filters/dec_uncv.o filters/dec_vorbis.o filters/dec_vtb.o filters/dec_webvtt.o filters/dec_xvid.o filters/decrypt_cenc_isma.o filters/dmx_avi.o filters/dmx_dash.o filters/dmx_ghi.o filters/dmx_gsf.o filters/dmx_m2ts.o filters/dmx_mpegps.o filters/dmx_nhml.o filters/dmx_nhnt.o filters/dmx_ogg.o filters/dmx_saf.o filters/dmx_vobsub.o filters/enc_jpg.o filters/enc_png.o filters/encrypt_cenc_isma.o filters/evg_rescale.o filters/filelist.o filters/hevcmerge.o filters/hevcsplit.o filters/in_dvb4linux.o filters/in_file.o filters/in_http.o filters/in_pipe.o filters/in_route.o filters/in_route_repair.o filters/in_rtp.o filters/in_rtp_rtsp.o filters/in_rtp_sdp.o filters/in_rtp_signaling.o filters/in_rtp_stream.o filters/in_sock.o filters/inspect.o filters/io_fcryp.o filters/isoffin_load.o filters/isoffin_read.o filters/isoffin_read_ch.o filters/jsfilter.o filters/load_bt_xmt.o filters/load_svg.o filters/load_text.o filters/mux_avi.o filters/mux_gsf.o filters/mux_isom.o filters/mux_ts.o filters/mux_ogg.o filters/out_audio.o filters/out_file.o filters/out_http.o filters/out_pipe.o filters/out_route.o filters/out_rtp.o filters/out_rtsp.o filters/out_sock.o filters/out_video.o filters/reframer.o filters/reframe_ac3.o filters/reframe_adts.o filters/reframe_latm.o filters/reframe_amr.o filters/reframe_av1.o filters/reframe_flac.o filters/reframe_h263.o filters/reframe_img.o filters/reframe_mhas.o filters/reframe_mp3.o filters/reframe_mpgvid.o filters/reframe_nalu.o filters/reframe_prores.o filters/reframe_qcp.o filters/reframe_rawvid.o filters/reframe_rawpcm.o filters/reframe_truehd.o filters/resample_audio.o filters/restamp.o filters/tileagg.o filters/tilesplit.o filters/tssplit.o filters/ttml_conv.o filters/unit_test_filter.o filters/rewind.o filters/rewrite_adts.o filters/rewrite_mhas.o filters/rewrite_mp4v.o filters/rewrite_nalu.o filters/rewrite_obu.o filters/vflip.o filters/vcrop.o filters/write_generic.o filters/write_nhml.o filters/write_nhnt.o filters/write_qcp.o filters/write_tx3g.o filters/write_vtt.o ../modules/dektec_out/dektec_video_decl.o filters/dec_opensvc.o filters/unframer.o filters/dec_scte35.o +LIBGPAC_FILTERS+=filters/bs_agg.o filters/bs_split.o filters/bsrw.o filters/compose.o filters/dasher.o filters/dec_ac52.o filters/dec_bifs.o filters/dec_faad.o filters/dec_img.o filters/dec_j2k.o filters/dec_laser.o filters/dec_mad.o filters/dec_mediacodec.o filters/dec_nvdec.o filters/dec_nvdec_sdk.o filters/dec_odf.o filters/dec_theora.o filters/dec_ttml.o filters/dec_ttxt.o filters/dec_uncv.o filters/dec_vorbis.o filters/dec_vtb.o filters/dec_webvtt.o filters/dec_xvid.o filters/decrypt_cenc_isma.o filters/dmx_avi.o filters/dmx_dash.o filters/dmx_ghi.o filters/dmx_gsf.o filters/dmx_m2ts.o filters/dmx_mpegps.o filters/dmx_nhml.o filters/dmx_nhnt.o filters/dmx_ogg.o filters/dmx_saf.o filters/dmx_vobsub.o filters/enc_jpg.o filters/enc_png.o filters/encrypt_cenc_isma.o filters/evg_rescale.o filters/filelist.o filters/hevcmerge.o filters/hevcsplit.o filters/in_dvb4linux.o filters/in_file.o filters/in_http.o filters/in_pipe.o filters/in_route.o filters/in_route_repair.o filters/in_rtp.o filters/in_rtp_rtsp.o filters/in_rtp_sdp.o filters/in_rtp_signaling.o filters/in_rtp_stream.o filters/in_sock.o filters/inspect.o filters/io_fcryp.o filters/isoffin_load.o filters/isoffin_read.o filters/isoffin_read_ch.o filters/jsfilter.o filters/load_bt_xmt.o filters/load_svg.o filters/load_text.o filters/mux_avi.o filters/mux_gsf.o filters/mux_isom.o filters/mux_ts.o filters/mux_ogg.o filters/out_audio.o filters/out_file.o filters/out_http.o filters/out_pipe.o filters/out_route.o filters/out_rtp.o filters/out_rtsp.o filters/out_sock.o filters/out_video.o filters/reframer.o filters/reframe_ac3.o filters/reframe_adts.o filters/reframe_latm.o filters/reframe_amr.o filters/reframe_av1.o filters/reframe_flac.o filters/reframe_h263.o filters/reframe_img.o filters/reframe_mhas.o filters/reframe_mp3.o filters/reframe_mpgvid.o filters/reframe_nalu.o filters/reframe_prores.o filters/reframe_qcp.o filters/reframe_rawvid.o filters/reframe_rawpcm.o filters/reframe_truehd.o filters/resample_audio.o filters/restamp.o filters/tileagg.o filters/tilesplit.o filters/tssplit.o filters/ttml_conv.o filters/unit_test_filter.o filters/rewind.o filters/rewrite_adts.o filters/rewrite_mhas.o filters/rewrite_mp4v.o filters/rewrite_nalu.o filters/rewrite_obu.o filters/vflip.o filters/vcrop.o filters/write_generic.o filters/write_nhml.o filters/write_nhnt.o filters/write_qcp.o filters/write_tx3g.o filters/reframe_ts_wvtt.o filters/write_vtt.o ../modules/dektec_out/dektec_video_decl.o filters/dec_opensvc.o filters/unframer.o filters/dec_scte35.o LIBGPAC_FILTERS_FFMPEG=filters/ff_common.o filters/ff_avf.o filters/ff_dec.o filters/ff_dmx.o filters/ff_enc.o filters/ff_rescale.o filters/ff_mx.o filters/ff_bsf.o LIBGPAC_FILTERS_LIBCAPTION=filters/dec_cc.o LIBGPAC_FILTERS_MPEGHDEC=filters/dec_mpeghdec.o diff --git a/src/filter_core/filter_register.c b/src/filter_core/filter_register.c index 044f236585..4fb449a333 100644 --- a/src/filter_core/filter_register.c +++ b/src/filter_core/filter_register.c @@ -103,6 +103,7 @@ REG_DEC(writegen) REG_DEC(ufnalu) REG_DEC(writeqcp) REG_DEC(ufvtt) +REG_DEC(rftsvtt) REG_DEC(nhntw) REG_DEC(nhmlw) REG_DEC(vobsubdmx) @@ -205,7 +206,7 @@ typedef struct #define REG_IT(__n) { #__n , __n##_register } -BuiltinReg BuiltinFilters [] = { +BuiltinReg BuiltinFilters[] = { REG_IT(inspect), REG_IT(probe), REG_IT(compositor), @@ -270,6 +271,7 @@ BuiltinReg BuiltinFilters [] = { REG_IT(ufnalu), REG_IT(writeqcp), REG_IT(ufvtt), + REG_IT(rftsvtt), REG_IT(nhntw), REG_IT(nhmlw), REG_IT(vobsubdmx), diff --git a/src/filters/dmx_m2ts.c b/src/filters/dmx_m2ts.c index c7280c5fa2..b8fe85c428 100644 --- a/src/filters/dmx_m2ts.c +++ b/src/filters/dmx_m2ts.c @@ -421,6 +421,11 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD //fallthrough case GF_M2TS_SCTE35_SPLICE_INFO_SECTIONS: return; //ignore actively: these streams will be attached verbatim as properties to audio and/or video packets + case GF_M2TS_METADATA_WVTT: + stype = GF_STREAM_TEXT; + codecid = GF_M2TS_META_WVTT; + stream->flags |= GF_M2TS_ES_FULL_AU; + break; default: GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TSDmx] Stream type 0x%02X not supported - ignoring pid\n", stream->stream_type)); return; @@ -431,13 +436,15 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD for (i=0; ifilter); i++) { opid = gf_filter_get_opid(ctx->filter, i); const GF_PropertyValue *p = gf_filter_pid_get_property(opid, GF_PROP_PID_ID); - if (p && (p->value.uint == stream->pid)) + if (p && (p->value.uint == stream->pid)) { break; + } opid = NULL; } - if (!opid) + if (!opid) { opid = gf_filter_pid_new(ctx->filter); + } stream->user = opid; stream->flags |= GF_M2TS_ES_ALREADY_DECLARED; @@ -591,7 +598,6 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD } m2tsdmx_update_sdt(ctx->ts, opid); - gf_m2ts_set_pes_framing((GF_M2TS_PES *)stream, GF_M2TS_PES_FRAMING_DEFAULT); } @@ -745,7 +751,10 @@ static void m2tsdmx_send_packet(GF_M2TSDmxCtx *ctx, GF_M2TS_PES_PCK *pck) /*pcr not initialized, don't send any data*/ // if (! pck->stream->program->first_dts) return; - if (!pck->stream->user) return; + + if (!pck->stream->user) { + return; + } opid = pck->stream->user; u8 *ptr = pck->data; @@ -795,6 +804,8 @@ static void m2tsdmx_send_packet(GF_M2TSDmxCtx *ctx, GF_M2TS_PES_PCK *pck) } + // if (pck->stream->pid == 65) GF_LOG(GF_LOG_ERROR, GF_LOG_CONDITION, ("m2tsdmx_send_packet: creating packet %llu\n", len)); + dst_pck = gf_filter_pck_new_alloc(opid, len, &data); if (!dst_pck) return; memcpy(data, ptr, len); @@ -1337,8 +1348,11 @@ static GF_Err m2tsdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool i } return GF_OK; } - if (! gf_filter_pid_check_caps(pid)) + + if (! gf_filter_pid_check_caps(pid)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDMx] caps not supported \"%s\"\n", gf_filter_pid_get_name(pid))); return GF_NOT_SUPPORTED; + } //by default for all URLs, send packets as soon as the program is configured ctx->mux_tune_state = DMX_TUNE_DONE; diff --git a/src/filters/reframe_ts_wvtt.c b/src/filters/reframe_ts_wvtt.c new file mode 100644 index 0000000000..6463e6d5e1 --- /dev/null +++ b/src/filters/reframe_ts_wvtt.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef GPAC_DISABLE_VTT + + +#define REFRAME_TS_WVTT_DEFAULT_TIMESCALE 90000 + +/////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + u32 timescale; + GF_FilterPid *ipid; + GF_FilterPid *opid; +} GF_ReframeTsVttCtx; + +/////////////////////////////////////////////////////////////////////////////// +// Callbacks for WebVTT parser + +static GF_Err reframe_ts_wvtt_parse_callback_report(void *user, GF_Err e, char *message, const char *line) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_parse_callback_report: line: %s, message: %s\n", line, message)); + return e; +} + +static void reframe_ts_wvtt_parse_callback_header(void *user, const char *config) +{ + // nothing to do +} + +static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *sample) { + + if (!sample) { + return; + } + + // in milliseconds + u64 start = gf_webvtt_sample_get_start(sample); + u64 end = gf_webvtt_sample_get_end(sample); + + if (!gf_isom_webvtt_cues_count(sample)) { + return; + } + + GF_ISOSample *iso_sample = NULL; + iso_sample = gf_isom_webvtt_to_sample(sample); + + if (iso_sample) { + GF_ReframeTsVttCtx* ctx = (GF_ReframeTsVttCtx*) user; + GF_FilterPacket *pck; + u8 *pck_data; + + pck = gf_filter_pck_new_alloc(ctx->opid, iso_sample->dataLength, &pck_data); + if (pck) + { + memcpy(pck_data, iso_sample->data, iso_sample->dataLength); + gf_filter_pck_set_cts(pck, (u64)(ctx->timescale * start / 1000)); + gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1); + + if (end && (end >= start)) + { + gf_filter_pck_set_duration(pck, (u32)(ctx->timescale * (end - start) / 1000)); + } + gf_filter_pck_send(pck); + } + + gf_isom_sample_del(&iso_sample); + } + + gf_webvtt_sample_del(sample); +} + +static void reframe_ts_wvtt_cue_callback(void *user, GF_WebVTTCue *cue) { + // nothing to do +} + + +/////////////////////////////////////////////////////////////////////////////// +// Filter callbacks + +static GF_Err reframe_ts_wvtt_initialize(GF_Filter *filter) +{ + return GF_OK; +} + +GF_Err reframe_ts_wvtt_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) +{ + GF_ReframeTsVttCtx *ctx = gf_filter_get_udta(filter); + + if (is_remove) + { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: is_remove\n")); + 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)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: not supported\n")); + return GF_NOT_SUPPORTED; + } + + GF_PropertyValue *p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID); + if (!p) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: no codec id\n")); + return GF_NOT_SUPPORTED; + } + + char *pid_name = gf_filter_pid_get_name(pid); + + GF_PropertyValue* timescale = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE); + if (!timescale) { + GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: no timescale using default value\n")); + ctx->timescale = REFRAME_TS_WVTT_DEFAULT_TIMESCALE; + } else { + ctx->timescale = timescale->value.uint; + } + + ctx->ipid = pid; + ctx->opid = gf_filter_pid_new(filter); + + // configure output PID properties + gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, &PROP_DATA((u8 *)"WEBVTT", 7)); + gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_MIME, &PROP_DATA((u8 *)"text/vtt", 9)); + gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_TEXT)); + gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_WEBVTT)); + gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_FALSE)); + gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(ctx->timescale)); + + return GF_OK; +} + +GF_Err reframe_ts_wvtt_process(GF_Filter *filter) +{ + GF_ReframeTsVttCtx *ctx = gf_filter_get_udta(filter); + GF_FilterPacket *pck = NULL; + u32 pck_size; + u8 *pck_data = NULL; + // u64 start_ts, end_ts; + + // GF_List *cues; + // Bool keep_ref = GF_TRUE; + + pck = gf_filter_pid_get_packet(ctx->ipid); + if (!pck) { + if (gf_filter_pid_is_eos(ctx->ipid)) { + gf_filter_pid_set_eos(ctx->opid); + return GF_EOS; + } + return GF_OK; + } + + pck_data = (char *)gf_filter_pck_get_data(pck, &pck_size); + // GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_process: len %d\n", pck_size)); + + + /////////////////////////////////////////////////////// + GF_WebVTTParser *parser = gf_webvtt_parser_new(); + + // create a memory file to read the packet data + FILE *mem_file = fmemopen(pck_data, pck_size, "r"); + + // Assume UTF-8 encoding + gf_webvtt_parser_init(parser, mem_file, 0, GF_FALSE, ctx, reframe_ts_wvtt_parse_callback_report, reframe_ts_wvtt_parse_callback_sample, reframe_ts_wvtt_parse_callback_header); + + // as the input packets do not contain the WEBVTT signature at the beginning + // we have to force the parser to start looking for cues immediately + gf_webvtt_parser_force_state(parser, WEBVTT_PARSER_STATE_WAITING_CUE); + + // the parser will call reframe_ts_wvtt_parse_callback_sample for each sample found + gf_webvtt_parser_parse(parser); + gf_webvtt_parser_del(parser); + + /////////////////////////////////////////////////////// + // cleanup + gf_filter_pid_drop_packet(ctx->ipid); + fclose(mem_file); + + return GF_OK; +} + +static void reframe_ts_wvtt_finalize(GF_Filter *filter) +{ + // nothing to do +} + +static const GF_FilterCapability ReframeTsVttCaps[] = + { + // receive a text stream using the custom 4CC code for WVTT in TS + CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT), + CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_M2TS_META_WVTT), + + // then, produce a Metadata stream with WebVTT cues + CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT), + CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_WEBVTT), + CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_FALSE), + {0}, +}; + +#define OFFS(_n) #_n, offsetof(GF_ReframeTsVttCtx, _n) + +GF_FilterRegister ReframeTsWebVTT = { + .name = "rftsvtt", + GF_FS_SET_DESCRIPTION("Reframer for WebVTT subtitles in Transport Stream") + GF_FS_SET_HELP("Transform Transport Stream PES metadata content to WebVTT cues") + .private_size = sizeof(GF_ReframeTsVttCtx), + .initialize = reframe_ts_wvtt_initialize, + .finalize = reframe_ts_wvtt_finalize, + SETCAPS(ReframeTsVttCaps), + .configure_pid = reframe_ts_wvtt_configure_pid, + .process = reframe_ts_wvtt_process}; + +const GF_FilterRegister *rftsvtt_register(GF_FilterSession *session) +{ + return &ReframeTsWebVTT; +} +#else +const GF_FilterRegister *rftsvtt_register(GF_FilterSession *session) +{ + return NULL; +} + +#endif /*GPAC_DISABLE_VTT*/ diff --git a/src/media_tools/mpegts.c b/src/media_tools/mpegts.c index ff4b6a138e..462fbce012 100644 --- a/src/media_tools/mpegts.c +++ b/src/media_tools/mpegts.c @@ -1606,6 +1606,15 @@ static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, GF pes->metadata_descriptor = metad; pes->stream_type = GF_M2TS_METADATA_ID3_KLVA; } + } else if (metad->format_identifier == GF_M2TS_META_WVTT && metad->application_format_identifier == GF_M2TS_META_WVTT) { + if (pes) + { + if (pes->metadata_descriptor) { + gf_m2ts_metadata_descriptor_del(pes->metadata_descriptor); + } + pes->metadata_descriptor = metad; + pes->stream_type = GF_M2TS_METADATA_WVTT; + } } else { /* don't know what to do with it for now, delete */ gf_m2ts_metadata_descriptor_del(metad); @@ -3028,6 +3037,10 @@ GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, GF_M2TSPesFraming mode) pes->reframe = gf_m2ts_reframe_add_prop; break; + case GF_M2TS_METADATA_WVTT: + pes->reframe = gf_m2ts_reframe_default; + break; + default: pes->reframe = gf_m2ts_reframe_default; break; diff --git a/src/media_tools/webvtt.c b/src/media_tools/webvtt.c index 9596cac951..0f4a33fe49 100644 --- a/src/media_tools/webvtt.c +++ b/src/media_tools/webvtt.c @@ -298,7 +298,7 @@ static GF_Err wvtt_write_cue(GF_BitStream *bs, GF_WebVTTCue *cue) return e; } -GF_ISOSample *gf_isom_webvtt_to_sample(void *s) +GF_ISOSample* gf_isom_webvtt_to_sample(void *s) { GF_Err e = GF_OK; GF_ISOSample *res; @@ -414,14 +414,6 @@ GF_Err wvtt_box_dump(GF_Box *a, FILE * trace) #endif /*GPAC_DISABLE_ISOM*/ -typedef enum { - WEBVTT_PARSER_STATE_WAITING_SIGNATURE, - WEBVTT_PARSER_STATE_WAITING_HEADER, - WEBVTT_PARSER_STATE_WAITING_CUE, - WEBVTT_PARSER_STATE_WAITING_CUE_TIMESTAMP, - WEBVTT_PARSER_STATE_WAITING_CUE_PAYLOAD -} GF_WebVTTParserState; - struct _webvtt_parser { GF_WebVTTParserState state; Bool is_srt, suspend, is_eof, prev_line_empty, in_comment; @@ -611,6 +603,10 @@ void gf_webvtt_parser_suspend(GF_WebVTTParser *vttparser) vttparser->suspend = GF_TRUE; } +void gf_webvtt_parser_force_state(GF_WebVTTParser *parser, GF_WebVTTParserState state) { + parser->state = state; +} + void gf_webvtt_parser_restart(GF_WebVTTParser *parser) { if (!parser->vtt_in) return; @@ -1185,6 +1181,7 @@ void gf_webvtt_parser_not_done(GF_WebVTTParser *parser) GF_Err gf_webvtt_parser_flush(GF_WebVTTParser *parser) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("gf_webvtt_parser_flush: %u\n", gf_list_count(parser->samples))); 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) ? sample->end - sample->start : 0;