From aa7f3e5bd86e4f77bc0da3fe1430204befd98f76 Mon Sep 17 00:00:00 2001
From: Thomas Guillem <thomas@gllm.fr>
Date: Tue, 25 Mar 2025 12:15:18 +0100
Subject: [PATCH 1/4] hxxx_helper: add get_current_frame_rate()

---
 modules/codec/hxxx_helper.c | 22 ++++++++++++++++++++++
 modules/codec/hxxx_helper.h |  3 +++
 2 files changed, 25 insertions(+)

diff --git a/modules/codec/hxxx_helper.c b/modules/codec/hxxx_helper.c
index aa2d57e32617..4287fa708d03 100644
--- a/modules/codec/hxxx_helper.c
+++ b/modules/codec/hxxx_helper.c
@@ -879,6 +879,28 @@ hxxx_helper_get_current_profile_level(const struct hxxx_helper *hh,
     return VLC_EGENERIC;
 }
 
+int
+hxxx_helper_get_current_frame_rate(const struct hxxx_helper *hh,
+                                   unsigned *num, unsigned *den)
+{
+    if (hh->i_codec == VLC_CODEC_H264)
+    {
+        const struct hxxx_helper_nal *hsps = h264_helper_get_current_sps(hh);
+        if (hsps && hsps->h264_sps &&
+            h264_get_frame_rate(hsps->h264_sps, num, den))
+            return VLC_SUCCESS;
+    }
+    else if (hh->i_codec == VLC_CODEC_HEVC)
+    {
+        const struct hxxx_helper_nal *hsps = &hh->hevc.sps_list[hh->hevc.i_current_sps];
+        const struct hxxx_helper_nal *hvps = &hh->hevc.vps_list[hh->hevc.i_current_vps];
+        if (hsps && hsps->hevc_sps && hvps && hvps->hevc_vps &&
+            hevc_get_frame_rate(hsps->hevc_sps, hvps->hevc_vps, num, den))
+            return VLC_SUCCESS;
+    }
+    return VLC_EGENERIC;
+}
+
 int
 hxxx_helper_get_chroma_chroma(const struct hxxx_helper *hh, uint8_t *pi_chroma_format,
                               uint8_t *pi_depth_luma, uint8_t *pi_depth_chroma)
diff --git a/modules/codec/hxxx_helper.h b/modules/codec/hxxx_helper.h
index 730f40419084..a7e1944c054a 100644
--- a/modules/codec/hxxx_helper.h
+++ b/modules/codec/hxxx_helper.h
@@ -121,6 +121,9 @@ int hxxx_helper_get_current_sar(const struct hxxx_helper *hh, int *p_num, int *p
 int hxxx_helper_get_current_profile_level(const struct hxxx_helper *hh,
                                           uint8_t *p_profile, uint8_t *p_level);
 
+int hxxx_helper_get_current_frame_rate(const struct hxxx_helper *hh,
+                                       unsigned *num, unsigned *den);
+
 int
 hxxx_helper_get_chroma_chroma(const struct hxxx_helper *hh, uint8_t *pi_chroma_format,
                               uint8_t *pi_depth_luma, uint8_t *pi_depth_chroma);
-- 
GitLab


From 7c69ff2967c70138eee00194fa61b123a9462d1a Mon Sep 17 00:00:00 2001
From: Thomas Guillem <thomas@gllm.fr>
Date: Tue, 25 Mar 2025 13:41:15 +0100
Subject: [PATCH 2/4] mediacodec: parse fmt_out.video.i_frame_rate*

Will be used by the next commit.
---
 modules/codec/omxil/mediacodec.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c
index ba4443180989..8438384b1bd3 100644
--- a/modules/codec/omxil/mediacodec.c
+++ b/modules/codec/omxil/mediacodec.c
@@ -266,10 +266,22 @@ static int CSDDup(decoder_sys_t *p_sys, const void *p_buf, size_t i_buf)
 
 static void HXXXInitSize(decoder_t *p_dec, bool *p_size_changed)
 {
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    struct hxxx_helper *hh = &p_sys->video.hh;
+
+    unsigned frame_rate, frame_rate_base;
+    int ret = hxxx_helper_get_current_frame_rate(hh, &frame_rate, &frame_rate_base);
+    if (ret == VLC_SUCCESS)
+    {
+        frame_rate_base *= 2;
+        p_dec->fmt_out.video.i_frame_rate = frame_rate;
+        p_dec->fmt_out.video.i_frame_rate_base = frame_rate_base;
+    }
+    else
+        msg_Warn(p_dec, "could not parse video frame_rate");
+
     if (p_size_changed)
     {
-        decoder_sys_t *p_sys = p_dec->p_sys;
-        struct hxxx_helper *hh = &p_sys->video.hh;
         unsigned i_ox, i_oy, i_w, i_h, i_vw, i_vh;
         if(hxxx_helper_get_current_picture_size(hh, &i_ox, &i_oy, &i_w, &i_h, &i_vw, &i_vh)
            == VLC_SUCCESS)
-- 
GitLab


From 3101c43446671481dd94ba0db879060e0c59d097 Mon Sep 17 00:00:00 2001
From: Thomas Guillem <thomas@gllm.fr>
Date: Tue, 25 Mar 2025 13:58:36 +0100
Subject: [PATCH 3/4] mediacodec: try to calculate missing PTS

From the MediaCodec documentation
The presentation timestamp in microseconds for this buffer. This is
normally the media time at which this buffer should be presented
(rendered). When using an output surface, this will be propagated as the
timestamp for the frame (after conversion to nanoseconds).

So we should never pass DTS here as it can decrease and increase. That's
was what the timestamp_Fifo was working arround. So instead, in case of
missing PTS, calculate the PTS from the first DTS.
---
 modules/codec/omxil/mediacodec.c | 39 ++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c
index 8438384b1bd3..264ea6b9697d 100644
--- a/modules/codec/omxil/mediacodec.c
+++ b/modules/codec/omxil/mediacodec.c
@@ -140,6 +140,8 @@ typedef struct decoder_sys_t
             timestamp_fifo_t *timestamp_fifo;
             int i_mpeg_dar_num, i_mpeg_dar_den;
             struct vlc_asurfacetexture *surfacetexture;
+            date_t pts;
+            bool pts_warned;
         } video;
         struct {
             date_t i_end_date;
@@ -276,6 +278,8 @@ static void HXXXInitSize(decoder_t *p_dec, bool *p_size_changed)
         frame_rate_base *= 2;
         p_dec->fmt_out.video.i_frame_rate = frame_rate;
         p_dec->fmt_out.video.i_frame_rate_base = frame_rate_base;
+
+        date_Change(&p_sys->video.pts, frame_rate, frame_rate_base);
     }
     else
         msg_Warn(p_dec, "could not parse video frame_rate");
@@ -1031,6 +1035,8 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
             p_dec->fmt_out.video.i_height = p_dec->fmt_in->video.i_height;
         }
         p_sys->cat = VIDEO_ES;
+        date_Init(&p_sys->video.pts, 1, 0);
+        p_sys->video.pts_warned = false;
     }
     else
     {
@@ -1627,11 +1633,7 @@ static int QueueBlockLocked(decoder_t *p_dec, block_t *p_in_block,
             {
                 b_config = (p_block->i_flags & BLOCK_FLAG_CSD);
                 if (!b_config)
-                {
                     i_ts = p_block->i_pts;
-                    if (!i_ts && p_block->i_dts)
-                        i_ts = p_block->i_dts;
-                }
                 p_buf = p_block->p_buffer;
                 i_size = p_block->i_buffer;
             }
@@ -1811,6 +1813,34 @@ static int Video_OnNewBlock(decoder_t *p_dec, block_t **pp_block)
     timestamp_FifoPut(p_sys->video.timestamp_fifo,
                       p_block->i_pts ? VLC_TICK_INVALID : p_block->i_dts);
 
+    if (p_block->i_pts != VLC_TICK_INVALID)
+        return 1;
+
+    /* PTS fallback: calculate it from first_dts + frame_rate */
+    if (p_sys->video.pts.i_divider_den == 0)
+    {
+        p_block->i_pts = p_block->i_dts;
+        goto nopts;
+    }
+
+    if (date_Get(&p_sys->video.pts) == VLC_TICK_INVALID)
+        date_Set(&p_sys->video.pts, p_block->i_dts);
+
+    p_block->i_pts = date_Get(&p_sys->video.pts);
+
+    if (p_block->i_pts == VLC_TICK_INVALID)
+        goto nopts;
+
+    date_Increment(&p_sys->video.pts, 1);
+
+    return 1;
+
+nopts:
+    if (!p_sys->video.pts_warned)
+    {
+        msg_Warn(p_dec, "no valid PTS, video timing might be bogus");
+        p_sys->video.pts_warned = true;
+    }
     return 1;
 }
 
@@ -1910,6 +1940,7 @@ static int VideoVC1_OnNewBlock(decoder_t *p_dec, block_t **pp_block)
 
 static void Video_OnFlush(decoder_sys_t *p_sys)
 {
+    date_Set(&p_sys->video.pts, VLC_TICK_INVALID);
     timestamp_FifoEmpty(p_sys->video.timestamp_fifo);
     /* Invalidate all pictures that are currently in flight
      * since flushing make all previous indices returned by
-- 
GitLab


From 062ca2d98b0316058d58ce80baae67af5b469a8b Mon Sep 17 00:00:00 2001
From: Thomas Guillem <thomas@gllm.fr>
Date: Tue, 25 Mar 2025 13:59:14 +0100
Subject: [PATCH 4/4] mediacodec: remove timestamp_Fifo

Superseded by the previous commit.
---
 modules/codec/omxil/mediacodec.c | 34 +++++++-------------------------
 1 file changed, 7 insertions(+), 27 deletions(-)

diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c
index 264ea6b9697d..eff23807d3d0 100644
--- a/modules/codec/omxil/mediacodec.c
+++ b/modules/codec/omxil/mediacodec.c
@@ -36,7 +36,6 @@
 #include <vlc_plugin.h>
 #include <vlc_codec.h>
 #include <vlc_block_helper.h>
-#include <vlc_timestamp_helper.h>
 #include <vlc_threads.h>
 #include <vlc_bits.h>
 
@@ -137,7 +136,6 @@ typedef struct decoder_sys_t
             unsigned int i_stride, i_slice_height;
             int i_pixel_format;
             struct hxxx_helper hh;
-            timestamp_fifo_t *timestamp_fifo;
             int i_mpeg_dar_num, i_mpeg_dar_den;
             struct vlc_asurfacetexture *surfacetexture;
             date_t pts;
@@ -976,10 +974,6 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
         p_sys->pf_on_flush = Video_OnFlush;
         p_sys->pf_process_output = Video_ProcessOutput;
 
-        p_sys->video.timestamp_fifo = timestamp_FifoNew(32);
-        if (!p_sys->video.timestamp_fifo)
-            goto bailout;
-
         if (var_InheritBool(p_dec, CFG_PREFIX "dr"))
         {
             /* Direct rendering: Request a valid OPAQUE Vout in order to get
@@ -1129,9 +1123,6 @@ static void CleanDecoder(decoder_sys_t *p_sys)
     if (p_sys->video.surfacetexture)
         vlc_asurfacetexture_Delete(p_sys->video.surfacetexture);
 
-    if (p_sys->video.timestamp_fifo)
-        timestamp_FifoRelease(p_sys->video.timestamp_fifo);
-
     free(p_sys);
 }
 
@@ -1182,13 +1173,6 @@ static int Video_ProcessOutput(decoder_t *p_dec, mc_api_out *p_out,
     {
         picture_t *p_pic = NULL;
 
-        /* If the oldest input block had no PTS, the timestamp of
-         * the frame returned by MediaCodec might be wrong so we
-         * overwrite it with the corresponding dts. Call FifoGet
-         * first in order to avoid a gap if buffers are released
-         * due to an invalid format or a preroll */
-        int64_t forced_ts = timestamp_FifoGet(p_sys->video.timestamp_fifo);
-
         if (!p_sys->b_has_format) {
             msg_Warn(p_dec, "Buffers returned before output format is set, dropping frame");
             return p_sys->api.release_out(&p_sys->api, p_out->buf.i_index, false);
@@ -1210,10 +1194,7 @@ static int Video_ProcessOutput(decoder_t *p_dec, mc_api_out *p_out,
             return p_sys->api.release_out(&p_sys->api, p_out->buf.i_index, false);
         }
 
-        if (forced_ts == VLC_TICK_INVALID)
-            p_pic->date = p_out->buf.i_ts;
-        else
-            p_pic->date = forced_ts;
+        p_pic->date = p_out->buf.i_ts;
         p_pic->b_progressive = true;
 
         if (p_sys->api.b_direct_rendering)
@@ -1810,9 +1791,6 @@ static int Video_OnNewBlock(decoder_t *p_dec, block_t **pp_block)
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_block = *pp_block;
 
-    timestamp_FifoPut(p_sys->video.timestamp_fifo,
-                      p_block->i_pts ? VLC_TICK_INVALID : p_block->i_dts);
-
     if (p_block->i_pts != VLC_TICK_INVALID)
         return 1;
 
@@ -1823,11 +1801,14 @@ static int Video_OnNewBlock(decoder_t *p_dec, block_t **pp_block)
         goto nopts;
     }
 
-    if (date_Get(&p_sys->video.pts) == VLC_TICK_INVALID)
-        date_Set(&p_sys->video.pts, p_block->i_dts);
-
     p_block->i_pts = date_Get(&p_sys->video.pts);
 
+    if (p_block->i_pts == VLC_TICK_INVALID)
+    {
+        date_Set(&p_sys->video.pts, p_block->i_dts);
+        p_block->i_pts = p_block->i_dts;
+    }
+
     if (p_block->i_pts == VLC_TICK_INVALID)
         goto nopts;
 
@@ -1941,7 +1922,6 @@ static int VideoVC1_OnNewBlock(decoder_t *p_dec, block_t **pp_block)
 static void Video_OnFlush(decoder_sys_t *p_sys)
 {
     date_Set(&p_sys->video.pts, VLC_TICK_INVALID);
-    timestamp_FifoEmpty(p_sys->video.timestamp_fifo);
     /* Invalidate all pictures that are currently in flight
      * since flushing make all previous indices returned by
      * MediaCodec invalid. */
-- 
GitLab