From d33bcc51a75d32eaf76ec6b95fe758ab3c020b6b Mon Sep 17 00:00:00 2001 From: llyyr Date: Mon, 23 Sep 2024 04:08:22 +0200 Subject: [PATCH] command: add video-frame-info/{gop,smpte,estimated-smpte}-timecode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kacper Michajłow --- .../video-frame-info-timecode.txt | 1 + DOCS/man/input.rst | 9 ++++++ player/command.c | 30 +++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 DOCS/interface-changes/video-frame-info-timecode.txt diff --git a/DOCS/interface-changes/video-frame-info-timecode.txt b/DOCS/interface-changes/video-frame-info-timecode.txt new file mode 100644 index 0000000000..320a5ebdc6 --- /dev/null +++ b/DOCS/interface-changes/video-frame-info-timecode.txt @@ -0,0 +1 @@ +add `video-frame-info/gop-timecode`, `video-frame-info/smpte-timecode` and `video-frame-info/estimated-smpte-timecode` diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index be206173dc..87b8a03f22 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -2733,6 +2733,15 @@ Property list ``video-frame-info/repeat`` Whether the frame must be delayed when decoding. + ``video-frame-info/gop-timecode`` + String with the GOP timecode encoded in the frame. + + ``video-frame-info/smpte-timecode`` + String with the SMPTE timecode encoded in the frame. + + ``video-frame-info/estimated-smpte-timecode`` + Estimated timecode based on the current playback position and frame count. + ``container-fps`` Container FPS. This can easily contain bogus values. For videos that use modern container formats or video codecs, this will often be incorrect. diff --git a/player/command.c b/player/command.c index 6891f4e70f..b3908e8fb2 100644 --- a/player/command.c +++ b/player/command.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "mpv_talloc.h" #include "client.h" @@ -2524,11 +2525,40 @@ static int mp_property_video_frame_info(void *ctx, struct m_property *prop, const char *pict_type = f->pict_type >= 1 && f->pict_type <= 3 ? pict_types[f->pict_type] : NULL; + char gop_tc[AV_TIMECODE_STR_SIZE] = {0}; + char s12m_tc[AV_TIMECODE_STR_SIZE] = {0}; + for (int n = 0; n < f->num_ff_side_data; n++) { + + struct mp_ff_side_data *mpsd = &f->ff_side_data[n]; + if (mpsd->type == AV_FRAME_DATA_GOP_TIMECODE) + av_timecode_make_mpeg_tc_string(gop_tc, *(int64_t*)(mpsd->buf->data)); + if (mpctx->vo_chain && mpsd->type == AV_FRAME_DATA_S12M_TIMECODE) { + av_timecode_make_smpte_tc_string2(s12m_tc, + av_d2q(mpctx->vo_chain->filter->container_fps, INT_MAX), + *(uint32_t*)(mpsd->buf->data), 0, 0); + } + } + + char approx_smpte[AV_TIMECODE_STR_SIZE] = {0}; + if (s12m_tc[0] == '\0' && mpctx->vo_chain) { + const AVTimecode tcr = { + .start = 0, + .flags = AV_TIMECODE_FLAG_DROPFRAME, + .rate = av_d2q(mpctx->vo_chain->filter->container_fps, INT_MAX), + .fps = lrint(mpctx->vo_chain->filter->container_fps), + }; + int frame = lrint(get_current_pos_ratio(mpctx, false) * get_frame_count(mpctx)); + av_timecode_make_string(&tcr, approx_smpte, frame); + } + struct m_sub_property props[] = { {"picture-type", SUB_PROP_STR(pict_type), .unavailable = !pict_type}, {"interlaced", SUB_PROP_BOOL(!!(f->fields & MP_IMGFIELD_INTERLACED))}, {"tff", SUB_PROP_BOOL(!!(f->fields & MP_IMGFIELD_TOP_FIRST))}, {"repeat", SUB_PROP_BOOL(!!(f->fields & MP_IMGFIELD_REPEAT_FIRST))}, + {"gop-timecode", SUB_PROP_STR(gop_tc), .unavailable = gop_tc[0] == '\0'}, + {"smpte-timecode", SUB_PROP_STR(s12m_tc), .unavailable = s12m_tc[0] == '\0'}, + {"estimated-smpte-timecode", SUB_PROP_STR(approx_smpte), .unavailable = approx_smpte[0] == '\0'}, {0} };