h264parse, h265parse: Fix timecode parsing

The scaling factor for nFrame part should be "(1 + nuit_field_based_flag) / 2"

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5254>
This commit is contained in:
Seungha Yang 2023-08-29 03:23:21 +09:00 committed by GStreamer Marge Bot
parent 22c8d1890e
commit 2c4cb82afc
2 changed files with 76 additions and 7 deletions

View file

@ -3208,6 +3208,7 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
GstEvent *event;
GstBuffer *parse_buffer = NULL;
gboolean is_interlaced = FALSE;
GstH264SPS *sps;
h264parse = GST_H264_PARSE (parse);
@ -3369,8 +3370,15 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
parse_buffer = frame->buffer = gst_buffer_make_writable (frame->buffer);
}
if (!gst_buffer_get_video_time_code_meta (parse_buffer)) {
sps = h264parse->nalparser->last_sps;
if (sps && sps->vui_parameters_present_flag &&
sps->vui_parameters.timing_info_present_flag &&
sps->vui_parameters.time_scale > 0 &&
sps->vui_parameters.num_units_in_tick > 0 &&
h264parse->parsed_fps_n > 0 && h264parse->parsed_fps_d > 0 &&
!gst_buffer_get_video_time_code_meta (parse_buffer)) {
guint i = 0;
GstH264VUIParams *vui = &sps->vui_parameters;
for (i = 0; i < 3 && h264parse->num_clock_timestamp; i++) {
GstH264ClockTimestamp *tim =
@ -3378,6 +3386,7 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gint field_count = -1;
guint n_frames;
GstVideoTimeCodeFlags flags = 0;
guint64 scale_n, scale_d;
if (!h264parse->pic_timing_sei.clock_timestamp_flag[i])
continue;
@ -3424,9 +3433,37 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
is_interlaced = TRUE;
}
n_frames =
gst_util_uint64_scale_int (tim->n_frames, 1,
2 - tim->nuit_field_based_flag);
/* Equation D-1 (without and tOffset)
*
* clockTimestamp = ( ( hH * 60 + mM ) * 60 + sS ) * time_scale +
* nFrames * ( num_units_in_tick * ( 1 + nuit_field_based_flag ) )
* => timestamp = clockTimestamp / time_scale
*
* <taking only frame part>
* timestamp = nFrames * ( num_units_in_tick * ( 1 + nuit_field_based_flag ) ) / time_scale
*
* <timecode's timestamp of frame part>
* timecode_timestamp = n_frames * fps_d / fps_n
*
* <Scaling Equation>
* n_frames = nFrames * ( num_units_in_tick * ( 1 + nuit_field_based_flag ) ) / time_scale
* * fps_n / fps_d
*
* fps_n * ( num_units_in_tick * ( 1 + nuit_field_based_flag ) )
* = nFrames * --------------------------------------------------------------
* fps_d * time_scale
*
* NOTE: "time_scale / num_units_in_tick" value is expected field rate
* (i.e., framerate = time_scale / (2 * num_units_in_tick)), so the above
* equation can be simplified if the bitstream is conveying field rate
* using time_scale / num_units_in_tick
* => "n_frames = nFrames * (1 + nuit_field_based_flag) / 2".
*/
scale_n = h264parse->parsed_fps_n * vui->num_units_in_tick
* (1 + tim->nuit_field_based_flag);
scale_d = h264parse->parsed_fps_d * vui->time_scale;
n_frames = gst_util_uint64_scale (tim->n_frames, scale_n, scale_d);
GST_LOG_OBJECT (h264parse,
"Add time code meta %02u:%02u:%02u:%02u",

View file

@ -2910,6 +2910,7 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
GstBuffer *buffer;
GstEvent *event;
GstBuffer *parse_buffer = NULL;
GstH265SPS *sps;
h265parse = GST_H265_PARSE (parse);
@ -3043,13 +3044,20 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
break;
}
{
sps = h265parse->nalparser->last_sps;
if (sps && sps->vui_parameters_present_flag &&
sps->vui_params.timing_info_present_flag &&
sps->vui_params.time_scale > 0 &&
sps->vui_params.num_units_in_tick > 0 &&
!gst_buffer_get_video_time_code_meta (parse_buffer)) {
guint i = 0;
GstH265VUIParams *vui = &sps->vui_params;
for (i = 0; i < h265parse->time_code.num_clock_ts; i++) {
gint field_count = -1;
guint n_frames;
GstVideoTimeCodeFlags flags = 0;
guint64 scale_n, scale_d;
if (!h265parse->time_code.clock_timestamp_flag[i])
break;
@ -3100,9 +3108,33 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
if (h265parse->sei_pic_struct != GST_H265_SEI_PIC_STRUCT_FRAME)
flags |= GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
/* Equation D-26 (without and tOffset)
*
* clockTimestamp[i] = ( ( hH * 60 + mM ) * 60 + sS ) * vui_time_scale +
* nFrames * ( vui_num_units_in_tick * ( 1 + unit_field_based_flag[i] ) )
* => timestamp = clockTimestamp / time_scale
*
* <taking only frame part>
* timestamp = nFrames * ( vui_num_units_in_tick * ( 1 + unit_field_based_flag ) ) / vui_time_scale
*
* <timecode's timestamp of frame part>
* timecode_timestamp = n_frames * fps_d / fps_n
*
* <Scaling Equation>
* n_frames = nFrames * ( vui_num_units_in_tick * ( 1 + unit_field_based_flag ) ) / vui_time_scale
* * fps_n / fps_d
*
* fps_n * ( vui_num_units_in_tick * ( 1 + unit_field_based_flag ) )
* = nFrames * ------------------------------------------------------------------
* fps_d * vui_time_scale
*/
scale_n = h265parse->parsed_fps_n * vui->num_units_in_tick
* (1 + h265parse->time_code.units_field_based_flag[i]);
scale_d = h265parse->parsed_fps_d * vui->time_scale;
n_frames =
gst_util_uint64_scale_int (h265parse->time_code.n_frames[i], 1,
2 - h265parse->time_code.units_field_based_flag[i]);
gst_util_uint64_scale_int (h265parse->time_code.n_frames[i], scale_n,
scale_d);
gst_buffer_add_video_time_code_meta_full (parse_buffer,
h265parse->parsed_fps_n,