From 911b2b8ded2e1d147fe32b800ae96885829c1525 Mon Sep 17 00:00:00 2001 From: Abhash Ekka <211720677+AbHash-RixE@users.noreply.github.com> Date: Wed, 3 Sep 2025 17:16:30 +0530 Subject: [PATCH] feat: add default X-TIMESTAMP-MAP header for empty subtitle files in WebVTT for HLS compatibility --- docs/CHANGES.TXT | 1 + src/ccextractor.c | 30 ++++++++++++++++++++++++- src/lib_ccx/ccx_common_option.h | 11 ++++++++++ src/lib_ccx/ccx_encoders_helpers.c | 35 ++++++++++++++++++++++++++++++ src/lib_ccx/ccx_encoders_helpers.h | 2 ++ 5 files changed, 78 insertions(+), 1 deletion(-) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index b3e53a195..367cda5ff 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 1.0 (to be released) ----------------- +- IMPROVEMENT: Add default X-TIMESTAMP-MAP header for empty subtitle files in WebVTT for better compatibility of HLS streaming (#1743) - Fix: HardSubX OCR on Rust - Removed the Share Module - Fix: Regression failures on DVD files diff --git a/src/ccextractor.c b/src/ccextractor.c index f2ef89a1d..14582423e 100644 --- a/src/ccextractor.c +++ b/src/ccextractor.c @@ -6,6 +6,7 @@ License: GPL 2.0 #include "ccextractor.h" #include #include +#include volatile int terminate_asap = 0; @@ -138,10 +139,27 @@ int start_ccx() #endif terminate_asap = 0; +#ifdef ENABLE_SHARING + if (ccx_options.translate_enabled && ctx->num_input_files > 1) + { + mprint("[share] WARNING: simultaneous translation of several input files is not supported yet\n"); + ccx_options.translate_enabled = 0; + ccx_options.sharing_enabled = 0; + } + if (ccx_options.translate_enabled) + { + mprint("[share] launching translate service\n"); + ccx_share_launch_translator(ccx_options.translate_langs, ccx_options.translate_key); + } +#endif // ENABLE_SHARING ret = 0; while (switch_to_next_file(ctx, 0)) { prepare_for_new_file(ctx); +#ifdef ENABLE_SHARING + if (ccx_options.sharing_enabled) + ccx_share_start(ctx->basefilename); +#endif // ENABLE_SHARING stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx); // Disable sync check for raw formats - they have the right timeline. @@ -293,6 +311,14 @@ int start_ccx() dec_ctx->timing->fts_now = 0; dec_ctx->timing->fts_max = 0; +#ifdef ENABLE_SHARING + if (ccx_options.sharing_enabled) + { + ccx_share_stream_done(ctx->basefilename); + ccx_share_stop(); + } +#endif // ENABLE_SHARING + if (dec_ctx->total_pulldownframes) mprint("incl. pulldown frames: %s (%u frames at %.2ffps)\n", print_mstime_static((LLONG)(dec_ctx->total_pulldownframes * 1000 / current_fps)), @@ -391,8 +417,10 @@ int start_ccx() dinit_libraries(&ctx); if (!ret) + { + webvtt_write_minimal_header(); mprint("\nNo captions were found in input.\n"); - + } print_end_msg(); if (show_myth_banner) diff --git a/src/lib_ccx/ccx_common_option.h b/src/lib_ccx/ccx_common_option.h index 104b6e027..7bc35ac1a 100644 --- a/src/lib_ccx/ccx_common_option.h +++ b/src/lib_ccx/ccx_common_option.h @@ -198,6 +198,17 @@ struct ccx_s_options // Options from user parameters #ifdef WITH_LIBCURL char *curlposturl; #endif + + +#ifdef ENABLE_SHARING + //CC sharing + int sharing_enabled; + char *sharing_url; + //Translating + int translate_enabled; + char *translate_langs; + char *translate_key; +#endif }; extern struct ccx_s_options ccx_options; diff --git a/src/lib_ccx/ccx_encoders_helpers.c b/src/lib_ccx/ccx_encoders_helpers.c index 00f96b45b..aef4947e3 100644 --- a/src/lib_ccx/ccx_encoders_helpers.c +++ b/src/lib_ccx/ccx_encoders_helpers.c @@ -3,6 +3,9 @@ #include "ccx_common_constants.h" #include "ccx_common_structs.h" #include "ccx_decoders_common.h" +#include "ccx_encoders_common.h" +#include "utility.h" +#include "lib_ccx.h" #include @@ -487,3 +490,35 @@ void ccx_encoders_helpers_perform_shellsort_words(void) shell_sort(capitalization_list.words, capitalization_list.len, sizeof(*capitalization_list.words), string_cmp_function, NULL); shell_sort(profane.words, profane.len, sizeof(*profane.words), string_cmp_function, NULL); } + +void webvtt_write_minimal_header() +{ + struct lib_ccx_ctx *ctx = NULL; + // Initialize CCExtractor libraries + ctx = init_libraries(&ccx_options); + + struct encoder_ctx *enc_ctx = NULL; + + if (ccx_options.write_format == CCX_OF_WEBVTT && ccx_options.timestamp_map) + { + // Initialize encoder with encoder_cfg + enc_ctx = init_encoder(&ccx_options.enc_cfg); + + if (enc_ctx) + { + const char *xtimestamp_line = ccx_options.enc_cfg.line_terminator_lf + ? "X-TIMESTAMP-MAP=MPEGTS:0,LOCAL:00:00:00.000\n\n" + : "X-TIMESTAMP-MAP=MPEGTS:0,LOCAL:00:00:00.000\r\n\r\n"; + + int used = encode_line(enc_ctx, enc_ctx->buffer, (unsigned char *)xtimestamp_line); + + // fh is already an int fd + write_wrapped(enc_ctx->out->fh, (const char *)enc_ctx->buffer, used); + + enc_ctx->wrote_webvtt_header = 1; + + // Proper cleanup + dinit_encoder(&enc_ctx, 0); + } + } +} diff --git a/src/lib_ccx/ccx_encoders_helpers.h b/src/lib_ccx/ccx_encoders_helpers.h index 2b1f24cb6..75347c348 100644 --- a/src/lib_ccx/ccx_encoders_helpers.h +++ b/src/lib_ccx/ccx_encoders_helpers.h @@ -49,4 +49,6 @@ void shell_sort(void *base, int nb, size_t size, int (*compar)(const void *p1, c void ccx_encoders_helpers_perform_shellsort_words(void); void ccx_encoders_helpers_setup(enum ccx_encoding_type encoding, int no_font_color, int no_type_setting, int trim_subs); + +void webvtt_write_minimal_header(void); #endif