[FFmpeg-devel] [PATCH] libavformat/hlsenc: Add option to correct subtitles duration in webvtt subtitles

Vladimir Kharchevin vkharchevin at gmail.com
Mon Dec 9 13:24:01 EET 2024


When importing text subtitles from libzvbi_teletext stream the duration of subtitle 
frames is -1 by default or fixed value per codec setting. 
For hls webvtt stream it makes disappear time always 1193:02:47.295 for every subtitle. 
Suggested to add hls option fix_teletext_durations to fix this behavior and set subtitle 
duration to the next subtitle packet time.

Signed-off-by: Vladimir Kharchevin <vkharchevin at gmail.com>
---
libavformat/hlsenc.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 6148685f40..2e67790482 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -109,6 +109,7 @@ typedef enum HLSFlags {
   HLS_PERIODIC_REKEY = (1 << 12),
   HLS_INDEPENDENT_SEGMENTS = (1 << 13),
   HLS_I_FRAMES_ONLY = (1 << 14),
+    HLS_FIX_TELETEXT_DURATIONS = (1 << 14),
} HLSFlags;

typedef enum {
@@ -165,6 +166,8 @@ typedef struct VariantStream {
   char *vtt_m3u8_name;
   char *m3u8_name;

+    AVPacket *vtt_prev_pkt;
+
   double initial_prog_date_time;
   char current_segment_final_filename_fmt[MAX_URL_SIZE]; // when renaming segments

@@ -2559,6 +2562,29 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
       }
   }

+    if((hls->flags & HLS_FIX_TELETEXT_DURATIONS) &&
+       st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+        if(!vs->vtt_prev_pkt) {
+            /**
+             * due to some types difference between basic types and codec and formats
+             * it transforms into uint32_t and assigned then to uint64_t
+             * so it becomes a positive integer value finally instead of -1.
+             * Fix duration to not have first phrase on the screen forever
+             * because of disappear time 1193:02:47.295
+             */
+            if(pkt->duration == (uint32_t)-1) {
+                pkt->duration = 0;
+            }
+            vs->vtt_prev_pkt = av_packet_clone(pkt);
+        } else {
+            AVPacket *temp;
+            vs->vtt_prev_pkt->duration = pkt->pts - vs->vtt_prev_pkt->pts;
+            temp = av_packet_clone(pkt);
+            pkt = vs->vtt_prev_pkt;
+            vs->vtt_prev_pkt = temp;
+        }
+    }
+
   can_split = can_split && (pkt->pts - vs->end_pts > 0);
   if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base,
                                                         end_pts, AV_TIME_BASE_Q) >= 0) {
@@ -2749,6 +2775,12 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
           ret = 0;
   }

+    /* free previously cloned packet */
+    if((hls->flags & HLS_FIX_TELETEXT_DURATIONS) &&
+       st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+        if(vs->vtt_prev_pkt)
+            av_packet_unref(pkt);
+    }
   return ret;
}

@@ -2767,6 +2799,9 @@ static void hls_deinit(AVFormatContext *s)
       av_freep(&vs->vtt_basename);
       av_freep(&vs->vtt_m3u8_name);

+        if(vs->vtt_prev_pkt)
+                av_packet_free(&vs->vtt_prev_pkt);
+
       avformat_free_context(vs->vtt_avf);
       avformat_free_context(vs->avf);
       if (hls->resend_init_file)
@@ -3035,6 +3070,8 @@ static int hls_init(AVFormatContext *s)
       vs->current_segment_final_filename_fmt[0] = '\0';
       vs->initial_prog_date_time = initial_program_date_time;

+        vs->vtt_prev_pkt = NULL;
+
       for (j = 0; j < vs->nb_streams; j++) {
           vs->has_video += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
           /* Get one video stream to reference for split segments
@@ -3218,6 +3255,7 @@ static const AVOption options[] = {
   {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PERIODIC_REKEY }, 0, UINT_MAX,   E, .unit = "flags"},
   {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, .unit = "flags"},
   {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_I_FRAMES_ONLY }, 0, UINT_MAX, E, .unit = "flags"},
+    {"fix_teletext_durations", "Calculate durations for teletext subtitle frames", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_FIX_TELETEXT_DURATIONS}, 0, UINT_MAX, E, .unit = "flags"},
   {"strftime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
   {"strftime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
   {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, .unit = "pl_type" },
-- 
2.43.0



More information about the ffmpeg-devel mailing list