From 1123951b1e1c45b8bc6e629d0f984bf691a96a57 Mon Sep 17 00:00:00 2001 From: "juan.adarve" Date: Mon, 23 Dec 2024 16:38:11 -0500 Subject: [PATCH 1/7] added reframer_ts_vtt filter. --- include/gpac/internal/media_dev.h | 12 +- include/gpac/mpegts.h | 2 + src/Makefile | 2 +- src/filter_core/filter_register.c | 6 +- src/filters/dmx_m2ts.c | 39 +++- src/filters/passthrough.c | 265 ++++++++++++++++++++++++ src/filters/reframe_ts_wvtt.c | 327 ++++++++++++++++++++++++++++++ src/media_tools/mpegts.c | 14 ++ src/media_tools/webvtt.c | 20 +- 9 files changed, 671 insertions(+), 16 deletions(-) create mode 100644 src/filters/passthrough.c create mode 100644 src/filters/reframe_ts_wvtt.c diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h index 4e7c98f880..b2c841cfb2 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, // 0 + WEBVTT_PARSER_STATE_WAITING_HEADER, // 1 + WEBVTT_PARSER_STATE_WAITING_CUE, // 2 + WEBVTT_PARSER_STATE_WAITING_CUE_TIMESTAMP, // 3 + WEBVTT_PARSER_STATE_WAITING_CUE_PAYLOAD // 4 +} 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); @@ -1153,6 +1162,7 @@ GF_Err gf_webvtt_parser_finalize(GF_WebVTTParser *parser, u64 duration); void gf_webvtt_sample_del(GF_WebVTTSample * samp); u64 gf_webvtt_sample_get_start(GF_WebVTTSample * samp); u64 gf_webvtt_sample_get_end(GF_WebVTTSample * samp); +GF_List* gf_webvtt_sample_get_cues(GF_WebVTTSample * samp); 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..13d58c943d 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/passthrough.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..23051634b5 100644 --- a/src/filter_core/filter_register.c +++ b/src/filter_core/filter_register.c @@ -103,6 +103,8 @@ REG_DEC(writegen) REG_DEC(ufnalu) REG_DEC(writeqcp) REG_DEC(ufvtt) +REG_DEC(rftsvtt) +REG_DEC(passthrough) REG_DEC(nhntw) REG_DEC(nhmlw) REG_DEC(vobsubdmx) @@ -205,7 +207,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 +272,8 @@ BuiltinReg BuiltinFilters [] = { REG_IT(ufnalu), REG_IT(writeqcp), REG_IT(ufvtt), + REG_IT(rftsvtt), + REG_IT(passthrough), 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..a0e1daca9f 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_CODECID_SIMPLE_TEXT; + 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; @@ -428,16 +433,21 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD } opid = NULL; + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: searching for output PID for stream %d\n", stream->pid)); 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)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: output PID found\n")); break; + } opid = NULL; } - if (!opid) + if (!opid) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: creating output PID for stream %d\n", stream->pid)); opid = gf_filter_pid_new(ctx->filter); + } stream->user = opid; stream->flags |= GF_M2TS_ES_ALREADY_DECLARED; @@ -460,6 +470,8 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD gf_filter_pid_set_property(opid, GF_PROP_PID_ID, &PROP_UINT(stream->pid) ); gf_filter_pid_set_property(opid, GF_PROP_PID_ESID, stream->mpeg4_es_id ? &PROP_UINT(stream->mpeg4_es_id) : NULL); + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: output PID \"%s\" created for TS stream %d\n", szName, stream->pid)); + if (m4sys_stream) { if (stream->slcfg) gf_free(stream->slcfg); @@ -479,6 +491,7 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD if (esd->decoderConfig && (esd->decoderConfig->streamType==GF_STREAM_OD)) stream->flags |= GF_M2TS_ES_IS_MPEG4_OD; } else { + // TODO: Adarve this is the path for WVTT gf_filter_pid_set_property(opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(stype) ); gf_filter_pid_set_property(opid, GF_PROP_PID_CODECID, &PROP_UINT(codecid) ); @@ -496,7 +509,11 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD gf_filter_pid_set_property(opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(90000) ); gf_filter_pid_set_property(opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(stream->program->pcr_pid) ); + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: checking (stream->flags&GF_M2TS_ES_IS_PES) && stream->gpac_meta_dsi\n")); if ((stream->flags&GF_M2TS_ES_IS_PES) && stream->gpac_meta_dsi) { + // TODO: Adarve, WVTT does not take this path + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: PASSED\n")); + char *cname; GF_BitStream *bs = gf_bs_new(stream->gpac_meta_dsi, stream->gpac_meta_dsi_size, GF_BITSTREAM_READ); u32 val = gf_bs_read_u32(bs); //codec ID (meta codec identifier) @@ -592,6 +609,7 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD m2tsdmx_update_sdt(ctx->ts, opid); + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: setting default PES framing\n")); gf_m2ts_set_pes_framing((GF_M2TS_PES *)stream, GF_M2TS_PES_FRAMING_DEFAULT); } @@ -745,7 +763,13 @@ 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->pid == 65) GF_LOG(GF_LOG_ERROR, GF_LOG_CONDITION, ("m2tsdmx_send_packet: PID 65")); + + if (!pck->stream->user) { + if (pck->stream->pid == 65) GF_LOG(GF_LOG_ERROR, GF_LOG_CONDITION, ("m2tsdmx_send_packet: no opid")); + return; + } opid = pck->stream->user; u8 *ptr = pck->data; @@ -795,6 +819,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 +1363,13 @@ static GF_Err m2tsdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool i } return GF_OK; } - if (! gf_filter_pid_check_caps(pid)) + + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDMx] m2tsdmx_configure_pid: checking caps for pid \"%s\"\n", gf_filter_pid_get_name(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/passthrough.c b/src/filters/passthrough.c new file mode 100644 index 0000000000..9f1d4830b8 --- /dev/null +++ b/src/filters/passthrough.c @@ -0,0 +1,265 @@ +#include +#include + +///////////////////////////////////////////////// +// TYPES +///////////////////////////////////////////////// + +struct _passthrough_pid_ctx +{ + GF_FilterPid *input_pid; + GF_FilterPid *output_pid; + + // any other attribute needed for this PID +}; + +struct _passthrough_ctx +{ + char *name; + + // "private" attributes + GF_List *pids; + Bool reconfigure; +}; + +///////////////////////////////////////////////// +// FORWARD DECLARATIONS +///////////////////////////////////////////////// + +// GS: create filter: declare filter PID and Context types +typedef struct _passthrough_pid_ctx PassthroughPid; +typedef struct _passthrough_ctx GF_PassthroughCtx; + +///////////////////////////////////////////////// +// METHOD IMPLEMENTATIONS +///////////////////////////////////////////////// + +/** + * GS: create filter: function to configure input PIDs into the filter. + * @param filter a pointer to this filter instance. + * @param pid input PID + * @param is_remove whether or not the PID has been removed + * @return + */ +static GF_Err passthrough_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) +{ + // obtain the user-defined filter data from the filter parameter + GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); + PassthroughPid *pidctx = NULL; + + if (!is_remove) + { + + const char *pidName = gf_filter_pid_get_name(pid); + // register a new PID + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] configure_pid: registering new PID: %5s\n", ctx->name, pidName)) + GF_SAFEALLOC(pidctx, PassthroughPid); + if (!pidctx) + { + GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[passthrough][%s] configure_pid: error registering new PID: %5s: bad allocation\n", ctx->name, pidName)) + return GF_OUT_OF_MEM; + } + + // store the pid parameter as input + pidctx->input_pid = pid; + + // create a new PID for the passthrough output + pidctx->output_pid = gf_filter_pid_new(filter); + + // as the passthrough filter does nothing to the PID packets, + // we copy all the properties of the input PID into the output. + gf_filter_pid_copy_properties(pidctx->output_pid, pidctx->input_pid); + + // finally, add the newly created PID to the filters user-defined data + gf_list_add(ctx->pids, pidctx); + + return GF_OK; + } + else + { + + // delete the PID from the filter + const u32 count = gf_list_count(ctx->pids); + for (u32 i = 0; i < count; i++) + { + + pidctx = (PassthroughPid *)gf_list_get(ctx->pids, i); + + // check if this PID context contains the input PID, and if so + // deletes the entry from the filter context + if (pidctx->input_pid == pid) + { + + const char *pidName = gf_filter_pid_get_name(pid); + // register a new PID + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] configure_pid: deleting PID: %5s\n", ctx->name, pidName)) + + // delete the passthrough output as well. This will + // trigger other filters down the chain to be reconfigured. + gf_filter_pid_remove(pidctx->output_pid); + + // delete the item from the filter context + gf_list_del_item(ctx->pids, pidctx); + break; + } + } + + return GF_OK; + } +} + +/** + * GS: create filter: callback function called when there is data available + * in the input PIDs for processing. + * @param filter + * @return + */ +static GF_Err passthrough_process(GF_Filter *filter) +{ + // obtain the filter's internal user-data + GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); + + // iterate over all PIDs to check which ones have available data + const u32 count = gf_list_count(ctx->pids); + for (u32 i = 0; i < count; i++) + { + const PassthroughPid *pidctx = gf_list_get(ctx->pids, i); + + // read one packet from the input PID + GF_FilterPacket *packet = gf_filter_pid_get_packet(pidctx->input_pid); + if (packet != NULL) + { + + u32 inputSizeBytes = 0; + + // DTS: Decoding Timestamp + const u64 dts = gf_filter_pck_get_dts(packet); + + // this function returns a pointer to the packet data, but + // we don't use it. + gf_filter_pck_get_data(packet, &inputSizeBytes); + + // create a new packet, as a clone of the input, to be sent through the + // output PID. All the properties of the input packet are copied, so we + // do not need to set them manually. + u8 *outData = NULL; + GF_FilterPacket *outPacket = gf_filter_pck_new_clone(pidctx->output_pid, packet, &outData); + gf_filter_pck_send(outPacket); + + // drop the packet from the input PID buffer, effectively marking it + // as processed. This allows for new packets to arrive in the next + // invocation of gf_filter_pid_get_packet + gf_filter_pid_drop_packet(pidctx->input_pid); + + const char *pidName = gf_filter_pid_get_name(pidctx->input_pid); + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] process: PID: %4s, size: %6u, DTS: %6u\n", ctx->name, pidName, inputSizeBytes, dts)) + } + // check if an EndOfStream signal has been received in the input PID + // and if so, propagate it to the output. + else if (gf_filter_pid_eos_received(pidctx->input_pid)) + { + gf_filter_pid_set_eos(pidctx->output_pid); + } + } + + // processing was successful, return OK + return GF_OK; +} + +static GF_Err passthrough_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *new_val) +{ + // TODO + const GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); + + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] update_arg\n", ctx->name)) + return GF_OK; +} + +/** + * GS: create filter: initialize the filter's internal user data + * @param filter + * @return + */ +static GF_Err passthrough_initialize(GF_Filter *filter) +{ + GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); + + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] initialize\n", ctx->name)) + + // initialize any internal attribute in ctx + ctx->pids = gf_list_new(); + + return GF_OK; +} + +/** + * GS: create filter: finalize the filter's internal user data + * + * @param filter + */ +static void passthrough_finalize(GF_Filter *filter) +{ + GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); + + GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] finalize\n", ctx->name)) + + while (gf_list_count(ctx->pids)) + { + PassthroughPid *pctx = gf_list_pop_back(ctx->pids); + + // FIXME: Adarve: should the output PID be removed here? + + // free memory + gf_free(pctx); + } + gf_list_del(ctx->pids); +} + +#define OFFS(_n) #_n, offsetof(GF_PassthroughCtx, _n) +static GF_FilterArgs PassthroughArgs[] = + { + {OFFS(name), "A name assigned to the passthrough filter.", GF_PROP_STRING, "", NULL, GF_FS_ARG_UPDATE}, + {0}}; + +static const GF_FilterCapability PassthroughCaps[] = + { + // FIXME: Adarve: figure out these + CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), + CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), + CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), + CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), + CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), +}; + +/** + * GS: create filter: Registry struct with all pieces that form the filter. + * + */ +GF_FilterRegister PassthroughRegister = { + .name = "passthrough", + GF_FS_SET_DESCRIPTION("Passthrough filter") + GF_FS_SET_HELP("Passthrough FILTER HELP STRING\n") + .private_size = sizeof(GF_PassthroughCtx), + .max_extra_pids = 0xFFFFFFFF, + .flags = GF_FS_REG_EXPLICIT_ONLY | GF_FS_REG_ALLOW_CYCLIC, + .args = PassthroughArgs, + SETCAPS(PassthroughCaps), + .initialize = passthrough_initialize, + .finalize = passthrough_finalize, + .configure_pid = passthrough_configure_pid, + .process = passthrough_process, + .update_arg = passthrough_update_arg}; + +/** + * GS: create filter: filter registration function + * + * This function is called in filter_register.c to include this filter + * as part of the filter collection available to GPAC. + * + * @param session + * @return + */ +const GF_FilterRegister *passthrough_register(GF_FilterSession *session) +{ + return (const GF_FilterRegister *)&PassthroughRegister; +} \ No newline at end of file diff --git a/src/filters/reframe_ts_wvtt.c b/src/filters/reframe_ts_wvtt.c new file mode 100644 index 0000000000..628eede164 --- /dev/null +++ b/src/filters/reframe_ts_wvtt.c @@ -0,0 +1,327 @@ +/* + * GPAC - Multimedia Framework C SDK + * + * Authors: Jean Le Feuvre + * Copyright (c) Telecom ParisTech 2000-2023 + * All rights reserved + * + * This file is part of GPAC / WebVTT stream unframer filter + * + * GPAC is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GPAC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#ifndef GPAC_DISABLE_VTT + +/////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + // // opts + // Bool exporter, merge_cues; + + // // only one input pid declared + // GF_FilterPid *ipid; + // // only one output pid declared + // GF_FilterPid *opid; + + // u32 codecid; + // u32 timescale; + + // GF_Fraction64 duration; + // s64 delay; + + // u8 *cues_buffer; + // u32 cues_buffer_size; + + // GF_WebVTTParser *parser; + + // GF_FilterPacket *src_pck; + // Bool dash_mode; + // u32 seg_pck_in, seg_pck_out; + + 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) +{ + // GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_parse_callback_header: %s\n", config)); + // nothing to d +} + +static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *sample) { + + if (!sample) { + return; + } + + u64 start = gf_webvtt_sample_get_start(sample); + u64 end = gf_webvtt_sample_get_end(sample); + + /////////////////////////////////////////////////////// + // GF_List* cues = gf_webvtt_sample_get_cues(sample); + + // for (u32 i = 0; i < gf_list_count(cues); i++) { + // GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, i); + // GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_parse_callback_sample: %llu -> %llu cue: %u: %s\n", start, end, i, cue->text)); + // // reframe_ts_wvtt_cue_callback(user, cue); + // } + /////////////////////////////////////////////////////// + + if (!gf_isom_webvtt_cues_count(sample)) { + return; + } + + // u64 start = gf_webvtt_sample_get_start(sample); + // u64 end = gf_webvtt_sample_get_end(sample); + 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); + + // TODO: receive GF_PROP_PID_TIMESCALE + gf_filter_pck_set_cts(pck, (u64)(90000 * start / 1000)); + gf_filter_pck_set_sap(pck, GF_FILTER_SAP_1); + + if (end && (end >= start)) + { + // TODO: receive GF_PROP_PID_TIMESCALE + gf_filter_pck_set_duration(pck, (u32)(90000 * (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) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_cue_callback:\n")); +} + + + +/////////////////////////////////////////////////////////////////////////////// +// Filter callbacks + +static GF_Err reframe_ts_wvtt_initialize(GF_Filter *filter) +{ + // GF_ReframeTsVttCtx *ctx = (GF_ReframeTsVttCtx *)gf_filter_get_udta(filter); + + // initialize any internal attribute in ctx + // ctx->parser = gf_webvtt_parser_new(); + // gf_webvtt_parser_cue_callback(ctx->parser, reframe_ts_wvtt_cue_callback, ctx); + + return GF_OK; +} + +GF_Err reframe_ts_wvtt_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) +{ + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid\n")); + 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; + } + + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: OK\n")); + + char *pid_name = gf_filter_pid_get_name(pid); + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: PID name: %s\n", pid_name)); + + 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_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(90000)); + + 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); + + /////////////////////////////////////////////////////// + + // GF_FilterPacket *dst = gf_filter_pck_new_alloc(ctx->opid, 0, NULL); + + // u8 *dst_data = NULL; + // GF_FilterPacket *dst_pck = gf_filter_pck_new_copy(ctx->opid, pck, &dst_data); + + // gf_filter_pck_send(dst_pck); + // gf_filter_pid_drop_packet(ctx->ipid); + + return GF_OK; +} + +static void reframe_ts_wvtt_finalize(GF_Filter *filter) +{ + // GF_ReframeTsVttCtx *ctx = gf_filter_get_udta(filter); + // if (ctx->cues_buffer) + // gf_free(ctx->cues_buffer); + + // if (ctx->parser) + // gf_webvtt_parser_del(ctx->parser); + + // if (ctx->src_pck) + // { + // gf_filter_pck_unref(ctx->src_pck); + // ctx->src_pck = NULL; + // } +} + +static const GF_FilterCapability ReframeTsVttCaps[] = + { + // receive a text stream without any codec + CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT), + CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_SIMPLE_TEXT), + + // TODO: 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_SIMPLE_TEXT), + CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_WEBVTT), + CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_FALSE), + // CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), + {0}, + + // CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), + // CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), + // CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), + // CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), + // CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), + + // CAP_BOOL(GF_CAPS_INPUT, GF_PROP_PID_UNFRAMED, GF_TRUE), // without this caps, it connects to the TS demuxer + // CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), + // CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE), +}; + +#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..a0fa6396d0 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,11 @@ GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, GF_M2TSPesFraming mode) pes->reframe = gf_m2ts_reframe_add_prop; break; + // TODO: Adarve check what to do with WVTT regarding the reframing + 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..8615fc4f85 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; @@ -556,6 +548,10 @@ u64 gf_webvtt_sample_get_end(GF_WebVTTSample * samp) return samp->end; } +GF_List* gf_webvtt_sample_get_cues(GF_WebVTTSample * samp) { + return samp->cues; +} + void gf_webvtt_sample_del(GF_WebVTTSample * samp) { while (gf_list_count(samp->cues)) { @@ -611,6 +607,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 +1185,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; @@ -1512,6 +1513,7 @@ GF_Err gf_webvtt_dump_iso_sample(FILE *dump, u32 timescale, GF_ISOSample *iso_sa #ifndef GPAC_DISABLE_ISOM GF_Err gf_webvtt_parser_finalize(GF_WebVTTParser *parser, u64 duration) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("gf_webvtt_parser_finalize: %u\n", gf_list_count(parser->samples))); GF_WebVTTSample *sample; gf_assert(gf_list_count(parser->samples) <= 1); sample = (GF_WebVTTSample *)gf_list_get(parser->samples, 0); From aa4ceab3e4a183d1d984d97f7eb046046e4e1423 Mon Sep 17 00:00:00 2001 From: "juan.adarve" Date: Tue, 7 Jan 2025 11:07:53 -0500 Subject: [PATCH 2/7] Removed logs --- src/filters/dmx_m2ts.c | 15 +------- src/filters/reframe_ts_wvtt.c | 64 +++++------------------------------ src/media_tools/mpegts.c | 1 - 3 files changed, 10 insertions(+), 70 deletions(-) diff --git a/src/filters/dmx_m2ts.c b/src/filters/dmx_m2ts.c index a0e1daca9f..06134b4001 100644 --- a/src/filters/dmx_m2ts.c +++ b/src/filters/dmx_m2ts.c @@ -423,7 +423,7 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD 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_CODECID_SIMPLE_TEXT; + codecid = GF_M2TS_META_WVTT; stream->flags |= GF_M2TS_ES_FULL_AU; break; default: @@ -433,19 +433,16 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD } opid = NULL; - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: searching for output PID for stream %d\n", stream->pid)); 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)) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: output PID found\n")); break; } opid = NULL; } if (!opid) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: creating output PID for stream %d\n", stream->pid)); opid = gf_filter_pid_new(ctx->filter); } @@ -470,8 +467,6 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD gf_filter_pid_set_property(opid, GF_PROP_PID_ID, &PROP_UINT(stream->pid) ); gf_filter_pid_set_property(opid, GF_PROP_PID_ESID, stream->mpeg4_es_id ? &PROP_UINT(stream->mpeg4_es_id) : NULL); - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: output PID \"%s\" created for TS stream %d\n", szName, stream->pid)); - if (m4sys_stream) { if (stream->slcfg) gf_free(stream->slcfg); @@ -509,11 +504,7 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD gf_filter_pid_set_property(opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(90000) ); gf_filter_pid_set_property(opid, GF_PROP_PID_CLOCK_ID, &PROP_UINT(stream->program->pcr_pid) ); - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: checking (stream->flags&GF_M2TS_ES_IS_PES) && stream->gpac_meta_dsi\n")); if ((stream->flags&GF_M2TS_ES_IS_PES) && stream->gpac_meta_dsi) { - // TODO: Adarve, WVTT does not take this path - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: PASSED\n")); - char *cname; GF_BitStream *bs = gf_bs_new(stream->gpac_meta_dsi, stream->gpac_meta_dsi_size, GF_BITSTREAM_READ); u32 val = gf_bs_read_u32(bs); //codec ID (meta codec identifier) @@ -608,8 +599,6 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD } m2tsdmx_update_sdt(ctx->ts, opid); - - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDmx] m2tsdmx_declare_pid: setting default PES framing\n")); gf_m2ts_set_pes_framing((GF_M2TS_PES *)stream, GF_M2TS_PES_FRAMING_DEFAULT); } @@ -1364,8 +1353,6 @@ static GF_Err m2tsdmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool i return GF_OK; } - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TSDMx] m2tsdmx_configure_pid: checking caps for pid \"%s\"\n", gf_filter_pid_get_name(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; diff --git a/src/filters/reframe_ts_wvtt.c b/src/filters/reframe_ts_wvtt.c index 628eede164..61210cf997 100644 --- a/src/filters/reframe_ts_wvtt.c +++ b/src/filters/reframe_ts_wvtt.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -38,29 +39,6 @@ typedef struct { - // // opts - // Bool exporter, merge_cues; - - // // only one input pid declared - // GF_FilterPid *ipid; - // // only one output pid declared - // GF_FilterPid *opid; - - // u32 codecid; - // u32 timescale; - - // GF_Fraction64 duration; - // s64 delay; - - // u8 *cues_buffer; - // u32 cues_buffer_size; - - // GF_WebVTTParser *parser; - - // GF_FilterPacket *src_pck; - // Bool dash_mode; - // u32 seg_pck_in, seg_pck_out; - GF_FilterPid *ipid; GF_FilterPid *opid; @@ -76,8 +54,7 @@ static GF_Err reframe_ts_wvtt_parse_callback_report(void *user, GF_Err e, char * static void reframe_ts_wvtt_parse_callback_header(void *user, const char *config) { - // GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_parse_callback_header: %s\n", config)); - // nothing to d + // nothing to do } static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *sample) { @@ -103,8 +80,6 @@ static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *s return; } - // u64 start = gf_webvtt_sample_get_start(sample); - // u64 end = gf_webvtt_sample_get_end(sample); GF_ISOSample *iso_sample = NULL; iso_sample = gf_isom_webvtt_to_sample(sample); @@ -137,7 +112,7 @@ static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *s } static void reframe_ts_wvtt_cue_callback(void *user, GF_WebVTTCue *cue) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_cue_callback:\n")); + // nothing to do } @@ -147,18 +122,11 @@ static void reframe_ts_wvtt_cue_callback(void *user, GF_WebVTTCue *cue) { static GF_Err reframe_ts_wvtt_initialize(GF_Filter *filter) { - // GF_ReframeTsVttCtx *ctx = (GF_ReframeTsVttCtx *)gf_filter_get_udta(filter); - - // initialize any internal attribute in ctx - // ctx->parser = gf_webvtt_parser_new(); - // gf_webvtt_parser_cue_callback(ctx->parser, reframe_ts_wvtt_cue_callback, ctx); - return GF_OK; } GF_Err reframe_ts_wvtt_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid\n")); GF_ReframeTsVttCtx *ctx = gf_filter_get_udta(filter); if (is_remove) @@ -183,16 +151,14 @@ GF_Err reframe_ts_wvtt_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool return GF_NOT_SUPPORTED; } - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: OK\n")); - char *pid_name = gf_filter_pid_get_name(pid); - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_configure_pid: PID name: %s\n", pid_name)); 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)); @@ -278,27 +244,15 @@ static void reframe_ts_wvtt_finalize(GF_Filter *filter) static const GF_FilterCapability ReframeTsVttCaps[] = { - // receive a text stream without any codec - CAP_UINT(GF_CAPS_INPUT_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT), - CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_CODECID, GF_CODECID_SIMPLE_TEXT), + // 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), - // TODO: 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_SIMPLE_TEXT), + // 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), - // CAP_BOOL(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), {0}, - - // CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), - // CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), - // CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), - // CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), - // CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), - - // CAP_BOOL(GF_CAPS_INPUT, GF_PROP_PID_UNFRAMED, GF_TRUE), // without this caps, it connects to the TS demuxer - // CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), - // CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE), }; #define OFFS(_n) #_n, offsetof(GF_ReframeTsVttCtx, _n) diff --git a/src/media_tools/mpegts.c b/src/media_tools/mpegts.c index a0fa6396d0..462fbce012 100644 --- a/src/media_tools/mpegts.c +++ b/src/media_tools/mpegts.c @@ -3037,7 +3037,6 @@ GF_Err gf_m2ts_set_pes_framing(GF_M2TS_PES *pes, GF_M2TSPesFraming mode) pes->reframe = gf_m2ts_reframe_add_prop; break; - // TODO: Adarve check what to do with WVTT regarding the reframing case GF_M2TS_METADATA_WVTT: pes->reframe = gf_m2ts_reframe_default; break; From cdaefa2e70702af957bebbff1968ee8dc9a87d6a Mon Sep 17 00:00:00 2001 From: "juan.adarve" Date: Tue, 7 Jan 2025 11:46:22 -0500 Subject: [PATCH 3/7] Consume timescale from input PID --- src/filters/reframe_ts_wvtt.c | 24 ++++++++++++++++-------- src/media_tools/webvtt.c | 1 - 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/filters/reframe_ts_wvtt.c b/src/filters/reframe_ts_wvtt.c index 61210cf997..6507678110 100644 --- a/src/filters/reframe_ts_wvtt.c +++ b/src/filters/reframe_ts_wvtt.c @@ -35,13 +35,16 @@ #ifndef GPAC_DISABLE_VTT + +#define REFRAME_TS_WVTT_DEFAULT_TIMESCALE 90000 + /////////////////////////////////////////////////////////////////////////////// typedef struct { + u32 timescale; GF_FilterPid *ipid; GF_FilterPid *opid; - } GF_ReframeTsVttCtx; /////////////////////////////////////////////////////////////////////////////// @@ -63,6 +66,7 @@ static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *s return; } + // in milliseconds u64 start = gf_webvtt_sample_get_start(sample); u64 end = gf_webvtt_sample_get_end(sample); @@ -92,15 +96,12 @@ static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *s if (pck) { memcpy(pck_data, iso_sample->data, iso_sample->dataLength); - - // TODO: receive GF_PROP_PID_TIMESCALE - gf_filter_pck_set_cts(pck, (u64)(90000 * start / 1000)); + 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)) { - // TODO: receive GF_PROP_PID_TIMESCALE - gf_filter_pck_set_duration(pck, (u32)(90000 * (end - start) / 1000)); + gf_filter_pck_set_duration(pck, (u32)(ctx->timescale * (end - start) / 1000)); } gf_filter_pck_send(pck); } @@ -116,7 +117,6 @@ static void reframe_ts_wvtt_cue_callback(void *user, GF_WebVTTCue *cue) { } - /////////////////////////////////////////////////////////////////////////////// // Filter callbacks @@ -153,6 +153,14 @@ GF_Err reframe_ts_wvtt_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool 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); @@ -162,7 +170,7 @@ GF_Err reframe_ts_wvtt_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool 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(90000)); + gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(ctx->timescale)); return GF_OK; } diff --git a/src/media_tools/webvtt.c b/src/media_tools/webvtt.c index 8615fc4f85..c2f96b25c2 100644 --- a/src/media_tools/webvtt.c +++ b/src/media_tools/webvtt.c @@ -1513,7 +1513,6 @@ GF_Err gf_webvtt_dump_iso_sample(FILE *dump, u32 timescale, GF_ISOSample *iso_sa #ifndef GPAC_DISABLE_ISOM GF_Err gf_webvtt_parser_finalize(GF_WebVTTParser *parser, u64 duration) { - GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("gf_webvtt_parser_finalize: %u\n", gf_list_count(parser->samples))); GF_WebVTTSample *sample; gf_assert(gf_list_count(parser->samples) <= 1); sample = (GF_WebVTTSample *)gf_list_get(parser->samples, 0); From adf9ba4e0f504cccd9e1abd6356813dc64bcb385 Mon Sep 17 00:00:00 2001 From: "juan.adarve" Date: Tue, 7 Jan 2025 11:48:12 -0500 Subject: [PATCH 4/7] Removed access to list of VTT cues. --- include/gpac/internal/media_dev.h | 1 - src/filters/reframe_ts_wvtt.c | 10 ---------- src/media_tools/webvtt.c | 4 ---- 3 files changed, 15 deletions(-) diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h index b2c841cfb2..8417be6eef 100644 --- a/include/gpac/internal/media_dev.h +++ b/include/gpac/internal/media_dev.h @@ -1162,7 +1162,6 @@ GF_Err gf_webvtt_parser_finalize(GF_WebVTTParser *parser, u64 duration); void gf_webvtt_sample_del(GF_WebVTTSample * samp); u64 gf_webvtt_sample_get_start(GF_WebVTTSample * samp); u64 gf_webvtt_sample_get_end(GF_WebVTTSample * samp); -GF_List* gf_webvtt_sample_get_cues(GF_WebVTTSample * samp); diff --git a/src/filters/reframe_ts_wvtt.c b/src/filters/reframe_ts_wvtt.c index 6507678110..ac7f58085c 100644 --- a/src/filters/reframe_ts_wvtt.c +++ b/src/filters/reframe_ts_wvtt.c @@ -70,16 +70,6 @@ static void reframe_ts_wvtt_parse_callback_sample(void *user, GF_WebVTTSample *s u64 start = gf_webvtt_sample_get_start(sample); u64 end = gf_webvtt_sample_get_end(sample); - /////////////////////////////////////////////////////// - // GF_List* cues = gf_webvtt_sample_get_cues(sample); - - // for (u32 i = 0; i < gf_list_count(cues); i++) { - // GF_WebVTTCue *cue = (GF_WebVTTCue *)gf_list_get(cues, i); - // GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("reframe_ts_wvtt_parse_callback_sample: %llu -> %llu cue: %u: %s\n", start, end, i, cue->text)); - // // reframe_ts_wvtt_cue_callback(user, cue); - // } - /////////////////////////////////////////////////////// - if (!gf_isom_webvtt_cues_count(sample)) { return; } diff --git a/src/media_tools/webvtt.c b/src/media_tools/webvtt.c index c2f96b25c2..0f4a33fe49 100644 --- a/src/media_tools/webvtt.c +++ b/src/media_tools/webvtt.c @@ -548,10 +548,6 @@ u64 gf_webvtt_sample_get_end(GF_WebVTTSample * samp) return samp->end; } -GF_List* gf_webvtt_sample_get_cues(GF_WebVTTSample * samp) { - return samp->cues; -} - void gf_webvtt_sample_del(GF_WebVTTSample * samp) { while (gf_list_count(samp->cues)) { From e6b79b198512529dec63d523c214f60b78f14347 Mon Sep 17 00:00:00 2001 From: "juan.adarve" Date: Tue, 7 Jan 2025 12:34:01 -0500 Subject: [PATCH 5/7] removed passthrough filter --- src/Makefile | 2 +- src/filter_core/filter_register.c | 2 - src/filters/passthrough.c | 265 ------------------------------ 3 files changed, 1 insertion(+), 268 deletions(-) delete mode 100644 src/filters/passthrough.c diff --git a/src/Makefile b/src/Makefile index 13d58c943d..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/reframe_ts_wvtt.o filters/passthrough.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 23051634b5..4fb449a333 100644 --- a/src/filter_core/filter_register.c +++ b/src/filter_core/filter_register.c @@ -104,7 +104,6 @@ REG_DEC(ufnalu) REG_DEC(writeqcp) REG_DEC(ufvtt) REG_DEC(rftsvtt) -REG_DEC(passthrough) REG_DEC(nhntw) REG_DEC(nhmlw) REG_DEC(vobsubdmx) @@ -273,7 +272,6 @@ BuiltinReg BuiltinFilters[] = { REG_IT(writeqcp), REG_IT(ufvtt), REG_IT(rftsvtt), - REG_IT(passthrough), REG_IT(nhntw), REG_IT(nhmlw), REG_IT(vobsubdmx), diff --git a/src/filters/passthrough.c b/src/filters/passthrough.c deleted file mode 100644 index 9f1d4830b8..0000000000 --- a/src/filters/passthrough.c +++ /dev/null @@ -1,265 +0,0 @@ -#include -#include - -///////////////////////////////////////////////// -// TYPES -///////////////////////////////////////////////// - -struct _passthrough_pid_ctx -{ - GF_FilterPid *input_pid; - GF_FilterPid *output_pid; - - // any other attribute needed for this PID -}; - -struct _passthrough_ctx -{ - char *name; - - // "private" attributes - GF_List *pids; - Bool reconfigure; -}; - -///////////////////////////////////////////////// -// FORWARD DECLARATIONS -///////////////////////////////////////////////// - -// GS: create filter: declare filter PID and Context types -typedef struct _passthrough_pid_ctx PassthroughPid; -typedef struct _passthrough_ctx GF_PassthroughCtx; - -///////////////////////////////////////////////// -// METHOD IMPLEMENTATIONS -///////////////////////////////////////////////// - -/** - * GS: create filter: function to configure input PIDs into the filter. - * @param filter a pointer to this filter instance. - * @param pid input PID - * @param is_remove whether or not the PID has been removed - * @return - */ -static GF_Err passthrough_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove) -{ - // obtain the user-defined filter data from the filter parameter - GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); - PassthroughPid *pidctx = NULL; - - if (!is_remove) - { - - const char *pidName = gf_filter_pid_get_name(pid); - // register a new PID - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] configure_pid: registering new PID: %5s\n", ctx->name, pidName)) - GF_SAFEALLOC(pidctx, PassthroughPid); - if (!pidctx) - { - GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("[passthrough][%s] configure_pid: error registering new PID: %5s: bad allocation\n", ctx->name, pidName)) - return GF_OUT_OF_MEM; - } - - // store the pid parameter as input - pidctx->input_pid = pid; - - // create a new PID for the passthrough output - pidctx->output_pid = gf_filter_pid_new(filter); - - // as the passthrough filter does nothing to the PID packets, - // we copy all the properties of the input PID into the output. - gf_filter_pid_copy_properties(pidctx->output_pid, pidctx->input_pid); - - // finally, add the newly created PID to the filters user-defined data - gf_list_add(ctx->pids, pidctx); - - return GF_OK; - } - else - { - - // delete the PID from the filter - const u32 count = gf_list_count(ctx->pids); - for (u32 i = 0; i < count; i++) - { - - pidctx = (PassthroughPid *)gf_list_get(ctx->pids, i); - - // check if this PID context contains the input PID, and if so - // deletes the entry from the filter context - if (pidctx->input_pid == pid) - { - - const char *pidName = gf_filter_pid_get_name(pid); - // register a new PID - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] configure_pid: deleting PID: %5s\n", ctx->name, pidName)) - - // delete the passthrough output as well. This will - // trigger other filters down the chain to be reconfigured. - gf_filter_pid_remove(pidctx->output_pid); - - // delete the item from the filter context - gf_list_del_item(ctx->pids, pidctx); - break; - } - } - - return GF_OK; - } -} - -/** - * GS: create filter: callback function called when there is data available - * in the input PIDs for processing. - * @param filter - * @return - */ -static GF_Err passthrough_process(GF_Filter *filter) -{ - // obtain the filter's internal user-data - GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); - - // iterate over all PIDs to check which ones have available data - const u32 count = gf_list_count(ctx->pids); - for (u32 i = 0; i < count; i++) - { - const PassthroughPid *pidctx = gf_list_get(ctx->pids, i); - - // read one packet from the input PID - GF_FilterPacket *packet = gf_filter_pid_get_packet(pidctx->input_pid); - if (packet != NULL) - { - - u32 inputSizeBytes = 0; - - // DTS: Decoding Timestamp - const u64 dts = gf_filter_pck_get_dts(packet); - - // this function returns a pointer to the packet data, but - // we don't use it. - gf_filter_pck_get_data(packet, &inputSizeBytes); - - // create a new packet, as a clone of the input, to be sent through the - // output PID. All the properties of the input packet are copied, so we - // do not need to set them manually. - u8 *outData = NULL; - GF_FilterPacket *outPacket = gf_filter_pck_new_clone(pidctx->output_pid, packet, &outData); - gf_filter_pck_send(outPacket); - - // drop the packet from the input PID buffer, effectively marking it - // as processed. This allows for new packets to arrive in the next - // invocation of gf_filter_pid_get_packet - gf_filter_pid_drop_packet(pidctx->input_pid); - - const char *pidName = gf_filter_pid_get_name(pidctx->input_pid); - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] process: PID: %4s, size: %6u, DTS: %6u\n", ctx->name, pidName, inputSizeBytes, dts)) - } - // check if an EndOfStream signal has been received in the input PID - // and if so, propagate it to the output. - else if (gf_filter_pid_eos_received(pidctx->input_pid)) - { - gf_filter_pid_set_eos(pidctx->output_pid); - } - } - - // processing was successful, return OK - return GF_OK; -} - -static GF_Err passthrough_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *new_val) -{ - // TODO - const GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); - - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] update_arg\n", ctx->name)) - return GF_OK; -} - -/** - * GS: create filter: initialize the filter's internal user data - * @param filter - * @return - */ -static GF_Err passthrough_initialize(GF_Filter *filter) -{ - GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); - - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] initialize\n", ctx->name)) - - // initialize any internal attribute in ctx - ctx->pids = gf_list_new(); - - return GF_OK; -} - -/** - * GS: create filter: finalize the filter's internal user data - * - * @param filter - */ -static void passthrough_finalize(GF_Filter *filter) -{ - GF_PassthroughCtx *ctx = (GF_PassthroughCtx *)gf_filter_get_udta(filter); - - GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("[passthrough][%s] finalize\n", ctx->name)) - - while (gf_list_count(ctx->pids)) - { - PassthroughPid *pctx = gf_list_pop_back(ctx->pids); - - // FIXME: Adarve: should the output PID be removed here? - - // free memory - gf_free(pctx); - } - gf_list_del(ctx->pids); -} - -#define OFFS(_n) #_n, offsetof(GF_PassthroughCtx, _n) -static GF_FilterArgs PassthroughArgs[] = - { - {OFFS(name), "A name assigned to the passthrough filter.", GF_PROP_STRING, "", NULL, GF_FS_ARG_UPDATE}, - {0}}; - -static const GF_FilterCapability PassthroughCaps[] = - { - // FIXME: Adarve: figure out these - CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), - CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE), - CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), - CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE), - CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_CODECID, GF_CODECID_NONE), -}; - -/** - * GS: create filter: Registry struct with all pieces that form the filter. - * - */ -GF_FilterRegister PassthroughRegister = { - .name = "passthrough", - GF_FS_SET_DESCRIPTION("Passthrough filter") - GF_FS_SET_HELP("Passthrough FILTER HELP STRING\n") - .private_size = sizeof(GF_PassthroughCtx), - .max_extra_pids = 0xFFFFFFFF, - .flags = GF_FS_REG_EXPLICIT_ONLY | GF_FS_REG_ALLOW_CYCLIC, - .args = PassthroughArgs, - SETCAPS(PassthroughCaps), - .initialize = passthrough_initialize, - .finalize = passthrough_finalize, - .configure_pid = passthrough_configure_pid, - .process = passthrough_process, - .update_arg = passthrough_update_arg}; - -/** - * GS: create filter: filter registration function - * - * This function is called in filter_register.c to include this filter - * as part of the filter collection available to GPAC. - * - * @param session - * @return - */ -const GF_FilterRegister *passthrough_register(GF_FilterSession *session) -{ - return (const GF_FilterRegister *)&PassthroughRegister; -} \ No newline at end of file From 997155f6e921f255397489fce39712756cf476b5 Mon Sep 17 00:00:00 2001 From: "juan.adarve" Date: Tue, 7 Jan 2025 12:38:52 -0500 Subject: [PATCH 6/7] clean up --- include/gpac/internal/media_dev.h | 10 +++---- src/filters/reframe_ts_wvtt.c | 48 +------------------------------ 2 files changed, 6 insertions(+), 52 deletions(-) diff --git a/include/gpac/internal/media_dev.h b/include/gpac/internal/media_dev.h index 8417be6eef..7d00feedc2 100644 --- a/include/gpac/internal/media_dev.h +++ b/include/gpac/internal/media_dev.h @@ -1131,11 +1131,11 @@ void gf_media_format_ttxt_sdp(GP_RTPPacketizer *builder, char *payload_name, cha #include typedef enum { - WEBVTT_PARSER_STATE_WAITING_SIGNATURE, // 0 - WEBVTT_PARSER_STATE_WAITING_HEADER, // 1 - WEBVTT_PARSER_STATE_WAITING_CUE, // 2 - WEBVTT_PARSER_STATE_WAITING_CUE_TIMESTAMP, // 3 - WEBVTT_PARSER_STATE_WAITING_CUE_PAYLOAD // 4 + 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; diff --git a/src/filters/reframe_ts_wvtt.c b/src/filters/reframe_ts_wvtt.c index ac7f58085c..6463e6d5e1 100644 --- a/src/filters/reframe_ts_wvtt.c +++ b/src/filters/reframe_ts_wvtt.c @@ -1,28 +1,3 @@ -/* - * GPAC - Multimedia Framework C SDK - * - * Authors: Jean Le Feuvre - * Copyright (c) Telecom ParisTech 2000-2023 - * All rights reserved - * - * This file is part of GPAC / WebVTT stream unframer filter - * - * GPAC is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GPAC is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - #include #include #include @@ -211,33 +186,12 @@ GF_Err reframe_ts_wvtt_process(GF_Filter *filter) gf_filter_pid_drop_packet(ctx->ipid); fclose(mem_file); - /////////////////////////////////////////////////////// - - // GF_FilterPacket *dst = gf_filter_pck_new_alloc(ctx->opid, 0, NULL); - - // u8 *dst_data = NULL; - // GF_FilterPacket *dst_pck = gf_filter_pck_new_copy(ctx->opid, pck, &dst_data); - - // gf_filter_pck_send(dst_pck); - // gf_filter_pid_drop_packet(ctx->ipid); - return GF_OK; } static void reframe_ts_wvtt_finalize(GF_Filter *filter) { - // GF_ReframeTsVttCtx *ctx = gf_filter_get_udta(filter); - // if (ctx->cues_buffer) - // gf_free(ctx->cues_buffer); - - // if (ctx->parser) - // gf_webvtt_parser_del(ctx->parser); - - // if (ctx->src_pck) - // { - // gf_filter_pck_unref(ctx->src_pck); - // ctx->src_pck = NULL; - // } + // nothing to do } static const GF_FilterCapability ReframeTsVttCaps[] = From b5649da1302aaff52ce3d615ac51560617c6f680 Mon Sep 17 00:00:00 2001 From: "juan.adarve" Date: Tue, 7 Jan 2025 13:24:51 -0500 Subject: [PATCH 7/7] clean up --- src/filters/dmx_m2ts.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/filters/dmx_m2ts.c b/src/filters/dmx_m2ts.c index 06134b4001..b8fe85c428 100644 --- a/src/filters/dmx_m2ts.c +++ b/src/filters/dmx_m2ts.c @@ -486,7 +486,6 @@ static void m2tsdmx_declare_pid(GF_M2TSDmxCtx *ctx, GF_M2TS_PES *stream, GF_ESD if (esd->decoderConfig && (esd->decoderConfig->streamType==GF_STREAM_OD)) stream->flags |= GF_M2TS_ES_IS_MPEG4_OD; } else { - // TODO: Adarve this is the path for WVTT gf_filter_pid_set_property(opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(stype) ); gf_filter_pid_set_property(opid, GF_PROP_PID_CODECID, &PROP_UINT(codecid) ); @@ -753,10 +752,7 @@ 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->pid == 65) GF_LOG(GF_LOG_ERROR, GF_LOG_CONDITION, ("m2tsdmx_send_packet: PID 65")); - if (!pck->stream->user) { - if (pck->stream->pid == 65) GF_LOG(GF_LOG_ERROR, GF_LOG_CONDITION, ("m2tsdmx_send_packet: no opid")); return; } opid = pck->stream->user;