msdkvpp: Fix frc from lower fps to higher fps

There are three framerate conversion algorithms described in
<https://github.com/Intel-Media-SDK/MediaSDK/blob/master/doc/mediasdk-man.md>,
interpolation is not implemented so far and thus distributed timestamp algorihtm
is considered to be more practical which evenly distributes output timestamps
according to output framerate. In this case, newly generated frames are inserted
between current frame and previous one, timestamp is calculated by msdk API.

This implementation first pushes newly generated buffers(outbuf_new) forward and
the current buffer(outbuf) is handled at last round by base transform automatically.
A flag "create_new_surface" is used to indicate if new surfaces have been generated
and then push new outbuf forward accordingly.

Considering the upstream element may not be the msdk element, it is necessary to
always set the input surface timestamp as same as input buffer's timestamp and
convert it to msdk timestamp.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2418>
This commit is contained in:
Mengkejiergeli Ba 2021-07-20 18:15:11 +08:00 committed by GStreamer Marge Bot
parent 18314764fc
commit 86872b1b46

View file

@ -867,9 +867,10 @@ gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
mfxFrameInfo *in_info = NULL;
MsdkSurface *in_surface = NULL;
MsdkSurface *out_surface = NULL;
GstBuffer *outbuf_new = NULL;
gboolean locked_by_others;
gboolean create_new_surface = FALSE;
timestamp = GST_BUFFER_TIMESTAMP (inbuf);
free_unlocked_msdk_surfaces (thiz);
in_surface = get_msdk_surface_from_input_buffer (thiz, inbuf);
@ -883,6 +884,13 @@ gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
}
locked_by_others = ! !in_surface->surface->Data.Locked;
/* always convert timestamp of input surface as msdk timestamp */
if (inbuf->pts == GST_CLOCK_TIME_NONE)
in_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
else
in_surface->surface->Data.TimeStamp =
gst_util_uint64_scale_round (inbuf->pts, 90000, GST_SECOND);
if (gst_msdk_is_msdk_buffer (outbuf)) {
out_surface = g_slice_new0 (MsdkSurface);
out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf);
@ -912,11 +920,18 @@ gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
status =
MFXVideoVPP_RunFrameVPPAsync (session, in_surface->surface,
out_surface->surface, NULL, &sync_point);
timestamp = out_surface->surface->Data.TimeStamp;
if (status != MFX_WRN_DEVICE_BUSY)
break;
/* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
g_usleep (1000);
};
}
if (timestamp == MFX_TIMESTAMP_UNKNOWN)
timestamp = GST_CLOCK_TIME_NONE;
else
timestamp = gst_util_uint64_scale_round (timestamp, GST_SECOND, 90000);
if (status == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM)
GST_WARNING_OBJECT (thiz, "VPP returned: %s",
@ -937,16 +952,29 @@ gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
MFXVideoCORE_SyncOperation (session, sync_point,
300000) != MFX_ERR_NONE)
GST_WARNING_OBJECT (thiz, "failed to do sync operation");
/* push new output buffer forward after sync operation */
if (create_new_surface) {
create_new_surface = FALSE;
ret = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (trans), outbuf_new);
if (ret != GST_FLOW_OK)
goto error_push_buffer;
}
/* More than one output buffers are generated */
if (status == MFX_ERR_MORE_SURFACE) {
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
GST_BUFFER_DURATION (outbuf) = thiz->buffer_duration;
timestamp += thiz->buffer_duration;
ret = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (trans), outbuf);
if (ret != GST_FLOW_OK)
goto error_push_buffer;
outbuf = create_output_buffer (thiz);
outbuf_new = create_output_buffer (thiz);
GST_BUFFER_TIMESTAMP (outbuf_new) = timestamp;
GST_BUFFER_DURATION (outbuf_new) = thiz->buffer_duration;
if (gst_msdk_is_msdk_buffer (outbuf_new)) {
release_out_surface (thiz, out_surface);
out_surface = g_slice_new0 (MsdkSurface);
out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf_new);
create_new_surface = TRUE;
} else {
GST_ERROR_OBJECT (thiz, "Failed to get msdk outsurface!");
goto vpp_error;
}
} else {
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
GST_BUFFER_DURATION (outbuf) = thiz->buffer_duration;
@ -1175,8 +1203,10 @@ gst_msdkvpp_initialize (GstMsdkVPP * thiz)
|| GST_VIDEO_INFO_FPS_D (&thiz->sinkpad_info) !=
GST_VIDEO_INFO_FPS_D (&thiz->srcpad_info))) {
thiz->flags |= GST_MSDK_FLAG_FRC;
/* So far this is the only algorithm which is working somewhat good */
thiz->frc_algm = MFX_FRCALGM_PRESERVE_TIMESTAMP;
/* manually set distributed timestamp as frc algorithm
* as it is more resonable for framerate conversion
*/
thiz->frc_algm = MFX_FRCALGM_DISTRIBUTED_TIMESTAMP;
}
/* work-around to avoid zero fps in msdk structure */