obs-qsv11: Fix timestamp for fractional frame rate

This commit rounds the timestamp to the integer multiple of fps_den.
Prior to this change, since the timestamp in MFX is defined in units of
90 kHz, timestamps for 60000/1001 fps is not accurately expressed. Also
the encoder sometimes returns the decode time stamp slightly off.
Hence, the timestamp in OBS becomes not a multiple of fps_den after
converting back from the timestamp in MFX.
This commit is contained in:
Norihiro Kamae 2022-07-03 14:43:38 +09:00 committed by Ryan Foster
parent b65411c343
commit 56c502b254

View File

@ -826,8 +826,23 @@ static void obs_qsv_video_info(void *data, struct video_scale_info *info)
cap_resolution(obsqsv->encoder, info);
}
static mfxU64 ts_obs_to_mfx(int64_t ts, const struct video_output_info *voi)
{
return ts * 90000 / voi->fps_num;
}
static int64_t ts_mfx_to_obs(mfxI64 ts, const struct video_output_info *voi)
{
int64_t div = 90000 * (int64_t)voi->fps_den;
/* Round to the nearest integer multiple of `voi->fps_den`. */
if (ts < 0)
return (ts * voi->fps_num - div / 2) / div * voi->fps_den;
else
return (ts * voi->fps_num + div / 2) / div * voi->fps_den;
}
static void parse_packet(struct obs_qsv *obsqsv, struct encoder_packet *packet,
mfxBitstream *pBS, uint32_t fps_num,
mfxBitstream *pBS, const struct video_output_info *voi,
bool *received_packet)
{
uint8_t *start, *end;
@ -845,7 +860,7 @@ static void parse_packet(struct obs_qsv *obsqsv, struct encoder_packet *packet,
packet->data = obsqsv->packet_data.array;
packet->size = obsqsv->packet_data.num;
packet->type = OBS_ENCODER_VIDEO;
packet->pts = pBS->TimeStamp * fps_num / 90000;
packet->pts = ts_mfx_to_obs((mfxI64)pBS->TimeStamp, voi);
packet->keyframe = (pBS->FrameType & MFX_FRAMETYPE_IDR);
uint16_t frameType = pBS->FrameType;
@ -906,7 +921,7 @@ static void parse_packet(struct obs_qsv *obsqsv, struct encoder_packet *packet,
g_prevDts = packet->dts;
}
} else {
packet->dts = pBS->DecodeTimeStamp * fps_num / 90000;
packet->dts = ts_mfx_to_obs(pBS->DecodeTimeStamp, voi);
}
#if 0
@ -940,7 +955,7 @@ static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
int ret;
mfxU64 qsvPTS = frame->pts * 90000 / voi->fps_num;
mfxU64 qsvPTS = ts_obs_to_mfx(frame->pts, voi);
// FIXME: remove null check from the top of this function
// if we actually do expect null frames to complete output.
@ -959,7 +974,7 @@ static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
return false;
}
parse_packet(obsqsv, packet, pBS, voi->fps_num, received_packet);
parse_packet(obsqsv, packet, pBS, voi, received_packet);
LeaveCriticalSection(&g_QsvCs);
@ -991,7 +1006,7 @@ static bool obs_qsv_encode_tex(void *data, uint32_t handle, int64_t pts,
int ret;
mfxU64 qsvPTS = pts * 90000 / voi->fps_num;
mfxU64 qsvPTS = ts_obs_to_mfx(pts, voi);
ret = qsv_encoder_encode_tex(obsqsv->context, qsvPTS, handle, lock_key,
next_key, &pBS);
@ -1002,7 +1017,7 @@ static bool obs_qsv_encode_tex(void *data, uint32_t handle, int64_t pts,
return false;
}
parse_packet(obsqsv, packet, pBS, voi->fps_num, received_packet);
parse_packet(obsqsv, packet, pBS, voi, received_packet);
LeaveCriticalSection(&g_QsvCs);