Skip to content

Requests: Add Deinterlacing Functionality #1192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/requesthandler/RequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ const std::unordered_map<std::string, RequestMethodHandler> RequestHandler::_han
{"GetSourceActive", &RequestHandler::GetSourceActive},
{"GetSourceScreenshot", &RequestHandler::GetSourceScreenshot},
{"SaveSourceScreenshot", &RequestHandler::SaveSourceScreenshot},
{"GetSourceDeinterlaceMode", &RequestHandler::GetSourceDeinterlaceMode},
{"SetSourceDeinterlaceMode", &RequestHandler::SetSourceDeinterlaceMode},
{"GetSourceDeinterlaceFieldOrder", &RequestHandler::GetSourceDeinterlaceFieldOrder},
{"SetSourceDeinterlaceFieldOrder", &RequestHandler::SetSourceDeinterlaceFieldOrder},
{"GetSourcePrivateSettings", &RequestHandler::GetSourcePrivateSettings},
{"SetSourcePrivateSettings", &RequestHandler::SetSourcePrivateSettings},

Expand Down
4 changes: 4 additions & 0 deletions src/requesthandler/RequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ class RequestHandler {
RequestResult GetSourceActive(const Request &);
RequestResult GetSourceScreenshot(const Request &);
RequestResult SaveSourceScreenshot(const Request &);
RequestResult GetSourceDeinterlaceMode(const Request &);
RequestResult SetSourceDeinterlaceMode(const Request &);
RequestResult GetSourceDeinterlaceFieldOrder(const Request &);
RequestResult SetSourceDeinterlaceFieldOrder(const Request &);
RequestResult GetSourcePrivateSettings(const Request &);
RequestResult SetSourcePrivateSettings(const Request &);

Expand Down
205 changes: 205 additions & 0 deletions src/requesthandler/RequestHandler_Sources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,211 @@ RequestResult RequestHandler::SaveSourceScreenshot(const Request &request)
return RequestResult::Success();
}

/**
* Gets the deinterlace mode of a source.
*
* Deinterlace modes:
*
* - `OBS_DEINTERLACE_MODE_DISABLE`
* - `OBS_DEINTERLACE_MODE_DISCARD`
* - `OBS_DEINTERLACE_MODE_RETRO`
* - `OBS_DEINTERLACE_MODE_BLEND`
* - `OBS_DEINTERLACE_MODE_BLEND_2X`
* - `OBS_DEINTERLACE_MODE_LINEAR`
* - `OBS_DEINTERLACE_MODE_LINEAR_2X`
* - `OBS_DEINTERLACE_MODE_YADIF`
* - `OBS_DEINTERLACE_MODE_YADIF_2X`
*
* **Compatible with inputs.**
*
* @requestField sourceName | String | Name of the source
*
* @responseField sourceDeinterlaceMode | String | Deinterlace mode
*
* @requestType GetSourceDeinterlaceMode
* @api requests
* @category sources
*/
RequestResult RequestHandler::GetSourceDeinterlaceMode(const Request &request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
if (!source)
return RequestResult::Error(statusCode, comment);

if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT)
return RequestResult::Error(RequestStatus::InvalidResourceType, "The specified source is not an input.");

auto deinterlaceMode = obs_source_get_deinterlace_mode(source);

json responseData;
switch (deinterlaceMode) {
case OBS_DEINTERLACE_MODE_DISABLE:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_DISABLE";
break;
case OBS_DEINTERLACE_MODE_DISCARD:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_DISCARD";
break;
case OBS_DEINTERLACE_MODE_RETRO:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_RETRO";
break;
case OBS_DEINTERLACE_MODE_BLEND:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_BLEND";
break;
case OBS_DEINTERLACE_MODE_BLEND_2X:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_BLEND_2X";
break;
case OBS_DEINTERLACE_MODE_LINEAR:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_LINEAR";
break;
case OBS_DEINTERLACE_MODE_LINEAR_2X:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_LINEAR_2X";
break;
case OBS_DEINTERLACE_MODE_YADIF:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_YADIF";
break;
case OBS_DEINTERLACE_MODE_YADIF_2X:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_YADIF_2X";
break;
default:
responseData["sourceDeinterlaceMode"] = "OBS_DEINTERLACE_MODE_DISABLE";
}
Comment on lines +360 to +389

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT, hardcoding these outputs with a switch is an anti-pattern.

Previous contributions all use the NLOHMANN_JSON_SERIALIZE_ENUM macro.

For example, take a look at RequestHandler::GetMediaInputStatus.

Specifically, these lines:

json responseData;
responseData["mediaState"] = obs_source_media_get_state(input);

obs_source_media_get_state returns enum obs_media_state not a string.

I suggest you follow the same pattern, if you want this to be merged.

See obs-studio\plugins\obs-websocket\src\utils\Json.h. This seems to be the place where this syntactic sugar is setup.

For example:

NLOHMANN_JSON_SERIALIZE_ENUM(obs_media_state, {
						      {OBS_MEDIA_STATE_NONE, "OBS_MEDIA_STATE_NONE"},
						      {OBS_MEDIA_STATE_PLAYING, "OBS_MEDIA_STATE_PLAYING"},
						      {OBS_MEDIA_STATE_OPENING, "OBS_MEDIA_STATE_OPENING"},
						      {OBS_MEDIA_STATE_BUFFERING, "OBS_MEDIA_STATE_BUFFERING"},
						      {OBS_MEDIA_STATE_PAUSED, "OBS_MEDIA_STATE_PAUSED"},
						      {OBS_MEDIA_STATE_STOPPED, "OBS_MEDIA_STATE_STOPPED"},
						      {OBS_MEDIA_STATE_ENDED, "OBS_MEDIA_STATE_ENDED"},
						      {OBS_MEDIA_STATE_ERROR, "OBS_MEDIA_STATE_ERROR"},
					      })


return RequestResult::Success(responseData);
}

/**
* Sets the deinterlace mode of a source.
*
* @requestField sourceName | String | Name of the source
* @requestField sourceDeinterlaceMode | String | Deinterlace mode
*
* @requestType SetSourceDeinterlaceMode
* @api requests
* @category sources
*/
RequestResult RequestHandler::SetSourceDeinterlaceMode(const Request &request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
if (!source || !request.ValidateString("sourceDeinterlaceMode", statusCode, comment))
return RequestResult::Error(statusCode, comment);

enum obs_deinterlace_mode deinterlaceMode;
std::string sourceDeinterlaceModeString = request.RequestData["sourceDeinterlaceMode"];

if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_DISABLE") {
deinterlaceMode = OBS_DEINTERLACE_MODE_DISABLE;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_DISCARD") {
deinterlaceMode = OBS_DEINTERLACE_MODE_DISCARD;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_RETRO") {
deinterlaceMode = OBS_DEINTERLACE_MODE_RETRO;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_BLEND") {
deinterlaceMode = OBS_DEINTERLACE_MODE_BLEND;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_BLEND_2X") {
deinterlaceMode = OBS_DEINTERLACE_MODE_BLEND_2X;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_LINEAR") {
deinterlaceMode = OBS_DEINTERLACE_MODE_LINEAR;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_LINEAR_2X") {
deinterlaceMode = OBS_DEINTERLACE_MODE_LINEAR_2X;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_YADIF") {
deinterlaceMode = OBS_DEINTERLACE_MODE_YADIF;
} else if (sourceDeinterlaceModeString == "OBS_DEINTERLACE_MODE_YADIF_2X") {
deinterlaceMode = OBS_DEINTERLACE_MODE_YADIF_2X;
} else {
return RequestResult::Error(RequestStatus::InvalidRequestField,
"Your specified deinterlace mode is invalid or not supported by this system.");
}
Comment on lines +415 to +436
Copy link

@NoTalkOnlyProx NoTalkOnlyProx Feb 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here. This can all be replaced by taking advantage of the NLOHMANN_JSON_SERIALIZE_ENUM macro. Possibly there is other setup required for it to work, too, but you can find that out by trying it out yourself


obs_source_set_deinterlace_mode(source, deinterlaceMode);

return RequestResult::Success();
}

/**
* Gets the deinterlace field order of a source.
*
* Deinterlace field orders:
*
* - `OBS_DEINTERLACE_FIELD_ORDER_TOP`
* - `OBS_DEINTERLACE_FIELD_ORDER_BOTTOM`
*
* **Compatible with inputs.**
*
* @requestField sourceName | String | Name of the source
*
* @responseField sourceDeinterlaceFieldOrder | String | Deinterlace field order
*
* @requestType GetSourceDeinterlaceFieldOrder
* @api requests
* @category sources
*/
RequestResult RequestHandler::GetSourceDeinterlaceFieldOrder(const Request &request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
if (!source)
return RequestResult::Error(statusCode, comment);

if (obs_source_get_type(source) != OBS_SOURCE_TYPE_INPUT)
return RequestResult::Error(RequestStatus::InvalidResourceType, "The specified source is not an input.");

auto deinterlaceFieldOrder = obs_source_get_deinterlace_field_order(source);

json responseData;
switch (deinterlaceFieldOrder) {
case OBS_DEINTERLACE_FIELD_ORDER_TOP:
responseData["sourceDeinterlaceFieldOrder"] = "OBS_DEINTERLACE_FIELD_ORDER_TOP";
break;
case OBS_DEINTERLACE_FIELD_ORDER_BOTTOM:
responseData["sourceDeinterlaceFieldOrder"] = "OBS_DEINTERLACE_FIELD_ORDER_BOTTOM";
break;
default:
responseData["sourceDeinterlaceFieldOrder"] = "OBS_DEINTERLACE_FIELD_ORDER_TOP";
break;
}

return RequestResult::Success(responseData);
}

/**
* Sets the deinterlace field order of a source.
*
* @requestField sourceName | String | Name of the source
* @requestField sourceDeinterlaceFieldOrder | String | Deinterlace field order
*
* @requestType SetSourceDeinterlaceFieldOrder
* @api requests
* @category sources
*/
RequestResult RequestHandler::SetSourceDeinterlaceFieldOrder(const Request &request)
{
RequestStatus::RequestStatus statusCode;
std::string comment;
OBSSourceAutoRelease source = request.ValidateSource("sourceName", statusCode, comment);
if (!source || !request.ValidateString("sourceDeinterlaceFieldOrder", statusCode, comment))
return RequestResult::Error(statusCode, comment);

enum obs_deinterlace_field_order deinterlaceFieldOrder;
std::string sourceDeinterlaceFieldOrderString = request.RequestData["sourceDeinterlaceFieldOrder"];

if (sourceDeinterlaceFieldOrderString == "OBS_DEINTERLACE_FIELD_ORDER_TOP") {
deinterlaceFieldOrder = OBS_DEINTERLACE_FIELD_ORDER_TOP;
} else if (sourceDeinterlaceFieldOrderString == "OBS_DEINTERLACE_FIELD_ORDER_BOTTOM") {
deinterlaceFieldOrder = OBS_DEINTERLACE_FIELD_ORDER_BOTTOM;
} else {
return RequestResult::Error(RequestStatus::InvalidRequestField,
"Your specified deinterlace field order is invalid or not supported by this system.");
}

obs_source_set_deinterlace_field_order(source, deinterlaceFieldOrder);

return RequestResult::Success();
}

// Intentionally undocumented
RequestResult RequestHandler::GetSourcePrivateSettings(const Request &request)
{
Expand Down