mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 04:42:18 +02:00
obs-qsv11: Add ROI support
This commit is contained in:
parent
730ab5e6d1
commit
0510d673d3
@ -206,6 +206,22 @@ int qsv_encoder_headers(qsv_t *pContext, uint8_t **pSPS, uint8_t **pPPS,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qsv_encoder_add_roi(qsv_t *pContext, const obs_encoder_roi *roi)
|
||||||
|
{
|
||||||
|
QSV_Encoder_Internal *pEncoder = (QSV_Encoder_Internal *)pContext;
|
||||||
|
|
||||||
|
/* QP value is range 0..51 */
|
||||||
|
// ToDo figure out if this is different for AV1
|
||||||
|
mfxI16 delta = (mfxI16)(-51.0f * roi->priority);
|
||||||
|
pEncoder->AddROI(roi->left, roi->top, roi->right, roi->bottom, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qsv_encoder_clear_roi(qsv_t *pContext)
|
||||||
|
{
|
||||||
|
QSV_Encoder_Internal *pEncoder = (QSV_Encoder_Internal *)pContext;
|
||||||
|
pEncoder->ClearROI();
|
||||||
|
}
|
||||||
|
|
||||||
int qsv_encoder_encode(qsv_t *pContext, uint64_t ts, uint8_t *pDataY,
|
int qsv_encoder_encode(qsv_t *pContext, uint64_t ts, uint8_t *pDataY,
|
||||||
uint8_t *pDataUV, uint32_t strideY, uint32_t strideUV,
|
uint8_t *pDataUV, uint32_t strideY, uint32_t strideUV,
|
||||||
mfxBitstream **pBS)
|
mfxBitstream **pBS)
|
||||||
|
@ -160,6 +160,8 @@ int qsv_encoder_reconfig(qsv_t *, qsv_param_t *);
|
|||||||
void qsv_encoder_version(unsigned short *major, unsigned short *minor);
|
void qsv_encoder_version(unsigned short *major, unsigned short *minor);
|
||||||
qsv_t *qsv_encoder_open(qsv_param_t *, enum qsv_codec codec);
|
qsv_t *qsv_encoder_open(qsv_param_t *, enum qsv_codec codec);
|
||||||
bool qsv_encoder_is_dgpu(qsv_t *);
|
bool qsv_encoder_is_dgpu(qsv_t *);
|
||||||
|
void qsv_encoder_add_roi(qsv_t *, const struct obs_encoder_roi *roi);
|
||||||
|
void qsv_encoder_clear_roi(qsv_t *pContext);
|
||||||
int qsv_encoder_encode(qsv_t *, uint64_t, uint8_t *, uint8_t *, uint32_t,
|
int qsv_encoder_encode(qsv_t *, uint64_t, uint8_t *, uint8_t *, uint32_t,
|
||||||
uint32_t, mfxBitstream **pBS);
|
uint32_t, mfxBitstream **pBS);
|
||||||
int qsv_encoder_encode_tex(qsv_t *, uint64_t, uint32_t, uint64_t, uint64_t *,
|
int qsv_encoder_encode_tex(qsv_t *, uint64_t, uint32_t, uint64_t, uint64_t *,
|
||||||
|
@ -442,6 +442,9 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&m_ctrl, 0, sizeof(m_ctrl));
|
||||||
|
memset(&m_roi, 0, sizeof(m_roi));
|
||||||
|
|
||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,7 +779,7 @@ mfxStatus QSV_Encoder_Internal::Encode(uint64_t ts, uint8_t *pDataY,
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Encode a frame asynchronously (returns immediately)
|
// Encode a frame asynchronously (returns immediately)
|
||||||
sts = m_pmfxENC->EncodeFrameAsync(NULL, pSurface,
|
sts = m_pmfxENC->EncodeFrameAsync(&m_ctrl, pSurface,
|
||||||
&m_pTaskPool[nTaskIdx].mfxBS,
|
&m_pTaskPool[nTaskIdx].mfxBS,
|
||||||
&m_pTaskPool[nTaskIdx].syncp);
|
&m_pTaskPool[nTaskIdx].syncp);
|
||||||
|
|
||||||
@ -841,7 +844,7 @@ mfxStatus QSV_Encoder_Internal::Encode_tex(uint64_t ts, uint32_t tex_handle,
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Encode a frame asynchronously (returns immediately)
|
// Encode a frame asynchronously (returns immediately)
|
||||||
sts = m_pmfxENC->EncodeFrameAsync(NULL, pSurface,
|
sts = m_pmfxENC->EncodeFrameAsync(&m_ctrl, pSurface,
|
||||||
&m_pTaskPool[nTaskIdx].mfxBS,
|
&m_pTaskPool[nTaskIdx].mfxBS,
|
||||||
&m_pTaskPool[nTaskIdx].syncp);
|
&m_pTaskPool[nTaskIdx].syncp);
|
||||||
|
|
||||||
@ -939,3 +942,39 @@ mfxStatus QSV_Encoder_Internal::Reset(qsv_param_t *pParams,
|
|||||||
|
|
||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QSV_Encoder_Internal::AddROI(mfxU32 left, mfxU32 top, mfxU32 right,
|
||||||
|
mfxU32 bottom, mfxI16 delta)
|
||||||
|
{
|
||||||
|
if (m_roi.NumROI == 256) {
|
||||||
|
warn("Maximum number of ROIs hit, ignoring additional ROI!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_roi.Header.BufferId = MFX_EXTBUFF_ENCODER_ROI;
|
||||||
|
m_roi.Header.BufferSz = sizeof(mfxExtEncoderROI);
|
||||||
|
m_roi.ROIMode = MFX_ROI_MODE_QP_DELTA;
|
||||||
|
/* The SDK will automatically align the values to block sizes so we
|
||||||
|
* don't have to do any maths here. */
|
||||||
|
m_roi.ROI[m_roi.NumROI].Left = left;
|
||||||
|
m_roi.ROI[m_roi.NumROI].Top = top;
|
||||||
|
m_roi.ROI[m_roi.NumROI].Right = right;
|
||||||
|
m_roi.ROI[m_roi.NumROI].Bottom = bottom;
|
||||||
|
m_roi.ROI[m_roi.NumROI].DeltaQP = delta;
|
||||||
|
m_roi.NumROI++;
|
||||||
|
|
||||||
|
/* Right now ROI is the only thing we add so this is fine */
|
||||||
|
if (m_extbuf.empty())
|
||||||
|
m_extbuf.push_back((mfxExtBuffer *)&m_roi);
|
||||||
|
|
||||||
|
m_ctrl.ExtParam = m_extbuf.data();
|
||||||
|
m_ctrl.NumExtParam = (mfxU16)m_extbuf.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QSV_Encoder_Internal::ClearROI()
|
||||||
|
{
|
||||||
|
m_roi.NumROI = 0;
|
||||||
|
m_ctrl.ExtParam = nullptr;
|
||||||
|
m_ctrl.NumExtParam = 0;
|
||||||
|
m_extbuf.clear();
|
||||||
|
}
|
||||||
|
@ -81,6 +81,9 @@ public:
|
|||||||
mfxStatus Reset(qsv_param_t *pParams, enum qsv_codec codec);
|
mfxStatus Reset(qsv_param_t *pParams, enum qsv_codec codec);
|
||||||
mfxStatus ReconfigureEncoder();
|
mfxStatus ReconfigureEncoder();
|
||||||
bool UpdateParams(qsv_param_t *pParams);
|
bool UpdateParams(qsv_param_t *pParams);
|
||||||
|
void AddROI(mfxU32 left, mfxU32 top, mfxU32 right, mfxU32 bottom,
|
||||||
|
mfxI16 delta);
|
||||||
|
void ClearROI();
|
||||||
|
|
||||||
bool IsDGPU() const { return m_isDGPU; }
|
bool IsDGPU() const { return m_isDGPU; }
|
||||||
|
|
||||||
@ -135,4 +138,8 @@ private:
|
|||||||
static mfxU16 g_numEncodersOpen;
|
static mfxU16 g_numEncodersOpen;
|
||||||
static mfxHDL
|
static mfxHDL
|
||||||
g_DX_Handle; // we only want one handle for all instances to use;
|
g_DX_Handle; // we only want one handle for all instances to use;
|
||||||
|
|
||||||
|
mfxEncodeCtrl m_ctrl;
|
||||||
|
mfxExtEncoderROI m_roi;
|
||||||
|
std::vector<mfxExtBuffer *> m_extbuf;
|
||||||
};
|
};
|
||||||
|
@ -99,6 +99,8 @@ struct obs_qsv {
|
|||||||
size_t sei_size;
|
size_t sei_size;
|
||||||
|
|
||||||
os_performance_token_t *performance_token;
|
os_performance_token_t *performance_token;
|
||||||
|
|
||||||
|
uint32_t roi_increment;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
@ -1377,6 +1379,37 @@ static void parse_packet_hevc(struct obs_qsv *obsqsv,
|
|||||||
g_bFirst = false;
|
g_bFirst = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void roi_cb(void *param, struct obs_encoder_roi *roi)
|
||||||
|
{
|
||||||
|
struct darray *da = param;
|
||||||
|
darray_push_back(sizeof(struct obs_encoder_roi), da, roi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void obs_qsv_setup_rois(struct obs_qsv *obsqsv)
|
||||||
|
{
|
||||||
|
const uint32_t increment =
|
||||||
|
obs_encoder_get_roi_increment(obsqsv->encoder);
|
||||||
|
if (obsqsv->roi_increment == increment)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qsv_encoder_clear_roi(obsqsv->context);
|
||||||
|
/* Because we pass-through the ROIs more or less directly we need to
|
||||||
|
* pass them in reverse order, so make a temporary copy and then use
|
||||||
|
* that instead. */
|
||||||
|
DARRAY(struct obs_encoder_roi) rois;
|
||||||
|
da_init(rois);
|
||||||
|
|
||||||
|
obs_encoder_enum_roi(obsqsv->encoder, roi_cb, &rois);
|
||||||
|
|
||||||
|
size_t idx = rois.num;
|
||||||
|
while (idx)
|
||||||
|
qsv_encoder_add_roi(obsqsv->context, &rois.array[--idx]);
|
||||||
|
|
||||||
|
da_free(rois);
|
||||||
|
|
||||||
|
obsqsv->roi_increment = increment;
|
||||||
|
}
|
||||||
|
|
||||||
static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
|
static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
|
||||||
struct encoder_packet *packet, bool *received_packet)
|
struct encoder_packet *packet, bool *received_packet)
|
||||||
{
|
{
|
||||||
@ -1396,6 +1429,9 @@ static bool obs_qsv_encode(void *data, struct encoder_frame *frame,
|
|||||||
|
|
||||||
mfxU64 qsvPTS = ts_obs_to_mfx(frame->pts, voi);
|
mfxU64 qsvPTS = ts_obs_to_mfx(frame->pts, voi);
|
||||||
|
|
||||||
|
if (obs_encoder_has_roi(obsqsv->encoder))
|
||||||
|
obs_qsv_setup_rois(obsqsv);
|
||||||
|
|
||||||
// FIXME: remove null check from the top of this function
|
// FIXME: remove null check from the top of this function
|
||||||
// if we actually do expect null frames to complete output.
|
// if we actually do expect null frames to complete output.
|
||||||
if (frame)
|
if (frame)
|
||||||
@ -1452,6 +1488,9 @@ static bool obs_qsv_encode_tex(void *data, uint32_t handle, int64_t pts,
|
|||||||
|
|
||||||
mfxU64 qsvPTS = ts_obs_to_mfx(pts, voi);
|
mfxU64 qsvPTS = ts_obs_to_mfx(pts, voi);
|
||||||
|
|
||||||
|
if (obs_encoder_has_roi(obsqsv->encoder))
|
||||||
|
obs_qsv_setup_rois(obsqsv);
|
||||||
|
|
||||||
ret = qsv_encoder_encode_tex(obsqsv->context, qsvPTS, handle, lock_key,
|
ret = qsv_encoder_encode_tex(obsqsv->context, qsvPTS, handle, lock_key,
|
||||||
next_key, &pBS);
|
next_key, &pBS);
|
||||||
|
|
||||||
@ -1516,7 +1555,8 @@ struct obs_encoder_info obs_qsv_encoder_tex_v2 = {
|
|||||||
.get_name = obs_qsv_getname,
|
.get_name = obs_qsv_getname,
|
||||||
.create = obs_qsv_create_tex_h264_v2,
|
.create = obs_qsv_create_tex_h264_v2,
|
||||||
.destroy = obs_qsv_destroy,
|
.destroy = obs_qsv_destroy,
|
||||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE,
|
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE |
|
||||||
|
OBS_ENCODER_CAP_ROI,
|
||||||
.encode_texture = obs_qsv_encode_tex,
|
.encode_texture = obs_qsv_encode_tex,
|
||||||
.update = obs_qsv_update,
|
.update = obs_qsv_update,
|
||||||
.get_properties = obs_qsv_props_h264_v2,
|
.get_properties = obs_qsv_props_h264_v2,
|
||||||
@ -1540,7 +1580,8 @@ struct obs_encoder_info obs_qsv_encoder_v2 = {
|
|||||||
.get_extra_data = obs_qsv_extra_data,
|
.get_extra_data = obs_qsv_extra_data,
|
||||||
.get_sei_data = obs_qsv_sei,
|
.get_sei_data = obs_qsv_sei,
|
||||||
.get_video_info = obs_qsv_video_info,
|
.get_video_info = obs_qsv_video_info,
|
||||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL,
|
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL |
|
||||||
|
OBS_ENCODER_CAP_ROI,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct obs_encoder_info obs_qsv_av1_encoder_tex = {
|
struct obs_encoder_info obs_qsv_av1_encoder_tex = {
|
||||||
@ -1550,7 +1591,8 @@ struct obs_encoder_info obs_qsv_av1_encoder_tex = {
|
|||||||
.get_name = obs_qsv_getname_av1,
|
.get_name = obs_qsv_getname_av1,
|
||||||
.create = obs_qsv_create_tex_av1,
|
.create = obs_qsv_create_tex_av1,
|
||||||
.destroy = obs_qsv_destroy,
|
.destroy = obs_qsv_destroy,
|
||||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE,
|
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE |
|
||||||
|
OBS_ENCODER_CAP_ROI,
|
||||||
.encode_texture = obs_qsv_encode_tex,
|
.encode_texture = obs_qsv_encode_tex,
|
||||||
.update = obs_qsv_update,
|
.update = obs_qsv_update,
|
||||||
.get_properties = obs_qsv_props_av1,
|
.get_properties = obs_qsv_props_av1,
|
||||||
@ -1572,7 +1614,8 @@ struct obs_encoder_info obs_qsv_av1_encoder = {
|
|||||||
.get_defaults = obs_qsv_defaults_av1,
|
.get_defaults = obs_qsv_defaults_av1,
|
||||||
.get_extra_data = obs_qsv_extra_data,
|
.get_extra_data = obs_qsv_extra_data,
|
||||||
.get_video_info = obs_qsv_video_plus_hdr_info,
|
.get_video_info = obs_qsv_video_plus_hdr_info,
|
||||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL,
|
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL |
|
||||||
|
OBS_ENCODER_CAP_ROI,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct obs_encoder_info obs_qsv_hevc_encoder_tex = {
|
struct obs_encoder_info obs_qsv_hevc_encoder_tex = {
|
||||||
@ -1582,7 +1625,8 @@ struct obs_encoder_info obs_qsv_hevc_encoder_tex = {
|
|||||||
.get_name = obs_qsv_getname_hevc,
|
.get_name = obs_qsv_getname_hevc,
|
||||||
.create = obs_qsv_create_tex_hevc,
|
.create = obs_qsv_create_tex_hevc,
|
||||||
.destroy = obs_qsv_destroy,
|
.destroy = obs_qsv_destroy,
|
||||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE,
|
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_PASS_TEXTURE |
|
||||||
|
OBS_ENCODER_CAP_ROI,
|
||||||
.encode_texture = obs_qsv_encode_tex,
|
.encode_texture = obs_qsv_encode_tex,
|
||||||
.update = obs_qsv_update,
|
.update = obs_qsv_update,
|
||||||
.get_properties = obs_qsv_props_hevc,
|
.get_properties = obs_qsv_props_hevc,
|
||||||
@ -1604,5 +1648,6 @@ struct obs_encoder_info obs_qsv_hevc_encoder = {
|
|||||||
.get_defaults = obs_qsv_defaults_hevc,
|
.get_defaults = obs_qsv_defaults_hevc,
|
||||||
.get_extra_data = obs_qsv_extra_data,
|
.get_extra_data = obs_qsv_extra_data,
|
||||||
.get_video_info = obs_qsv_video_plus_hdr_info,
|
.get_video_info = obs_qsv_video_plus_hdr_info,
|
||||||
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL,
|
.caps = OBS_ENCODER_CAP_DYN_BITRATE | OBS_ENCODER_CAP_INTERNAL |
|
||||||
|
OBS_ENCODER_CAP_ROI,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user