How to Resize Output (Source size) from python after hook

npatch

New Member
Making some automations for game testing and I want to do what the Resize Output menu item does from python.
Specifically I have a hook callback which allows me to get the resolution of the game's window (I test in windowed mode usually).

I've figured out that Resize changes at least 2 different locations. One is the Video Settings' Base and Output Resolution, which I've found how to do through the obs_frontend_get_profile_config , "Video" section and "BaseCX/Y" and "OutputCX/Y" for the resolutions. I also use obs.obs_frontend_save() and obs.obs_frontend_reset_video() to make sure the values are actually changed in the Settings. But using obs_frontend_reset_video in the hooked callback crashes obs and also corrupts the source and deletes it.
The second location is the transform_info's size (scale*window width, height) and bounding box size. But these alone don't have the exact result.

I've also tried to use obs_reset_video with the modified sizes, which does seem to be also executed during the Resize Output, but it doesn't affect the transform.

My question is twofold: A) Am I missing sth? Are all 3 of the above needed? Am I doing something wrong out of those? and B) what's the appropriate way to commit the changes to the profile's settings for the base and output resolutions without corrupting the source, after hook is fired?
 

npatch

New Member
Looked through github for the equivalent code in C/C++. The relevant part is [here](https://github.com/obsproject/obs-studio/blob/06642fdee48477ab85f89ff670f105affe402df7/UI/window-basic-main.cpp#L10632).

This is what I have so far, trying to replicate the native code in python:
Python:
def reset_video(config):

    bwidth = obs.config_get_uint(config, "Video", "BaseCX")
    bheight = obs.config_get_uint(config, "Video", "BaseCY")
    owidth = obs.config_get_uint(config, "Video", "OutputCX")
    oheight = obs.config_get_uint(config, "Video", "OutputCY")

    vid_settings = obs.obs_video_info()
    obs.obs_get_video_info(vid_settings)
    vid_settings.base_width = bwidth
    vid_settings.base_height = bheight
    vid_settings.output_width = owidth
    vid_settings.output_height = oheight

    ret = obs.obs_reset_video(vid_settings)
    if ret == -4: # Currently Active
        obs.script_log(obs.LOG_WARNING, "Tried to reset when already active")
        return ret
  
    if ret == 0:
        obs.script_log(obs.LOG_INFO, "Successful video reset")
        # resize preview....seems to be relavant for Studio mode

        #set video levels for white and hdr nominal peak
        #Can't implement. Error: Obspython has no obs_set_video_sdr_white_level

        #basic stats initialize values
        #No idea how to implement/access

        #remigrate scene collection
        #no idea if needed and how to implement

    return ret

def reset_transform_and_crop(scene_item_ref, width = -1, height = -1):
    transform_info = obs.obs_transform_info()
    obs.obs_sceneitem_get_info(scene_item_ref, transform_info)
    obs.vec2_set(transform_info.pos, 0.0, 0.0)
    transform_info.rot = 0.0
    transform_info.alignment = Alignment.ALIGN_LEFT | Alignment.ALIGN_TOP
    if width > -1 and height > -1:
        transform_info.scale.x  = 1.0
        transform_info.scale.y  = 1.0

    transform_info.bounds_type = obs.OBS_BOUNDS_SCALE_INNER
    transform_info.bounds_alignment = Alignment.ALIGN_CENTER.value
    if width > -1 and height > -1:
        transform_info.bounds.x = width
        transform_info.bounds.y = height
    obs.obs_sceneitem_set_info(scene_item_ref, transform_info)

    crop_info = obs.obs_sceneitem_crop()
    obs.obs_sceneitem_get_crop(scene_item_ref, crop_info)
    crop_info.left = 0
    crop_info.right = 0
    crop_info.top = 0
    crop_info.bottom = 0
    obs.obs_sceneitem_set_crop(scene_item_ref, crop_info)

def on_actionFitToScreen_triggered(scene_ref, scene_item_ref, config):
    ovi = obs.obs_video_info()
    obs.obs_get_video_info(ovi)

    ovi.base_width = obs.config_get_uint(config, "Video", "BaseCX")
    ovi.base_height = obs.config_get_uint(config, "Video", "BaseCY")
    ovi.output_width = obs.config_get_uint(config, "Video", "OutputCX")
    ovi.output_height = obs.config_get_uint(config, "Video", "OutputCY")

    obsutil.reset_transform_and_crop(scene_item_ref,float(ovi.base_width), float(ovi.base_height))

def resize_output_to_source_size():
    if obs.obs_video_active():
        return
  
    profile_config = obs.obs_frontend_get_profile_config()
  
    scene_ref = obsutil.find_scene(ags_data.scene_name)
    scene_item_ref = obsutil.find_scene_item(scene_ref, ags_data.source_name)
    source_ref = obs.obs_sceneitem_get_source(scene_item_ref)

    source_width = obs.obs_source_get_width(source_ref)
    source_height = obs.obs_source_get_height(source_ref)

    obs.config_set_uint(profile_config, "Video", "BaseCX", source_width)
    obs.config_set_uint(profile_config, "Video", "BaseCY", source_height)
    obs.config_set_uint(profile_config, "Video", "OutputCX", source_width)
    obs.config_set_uint(profile_config, "Video", "OutputCY", source_height)
  
    #profile config save
    print("config save safe")
    obs.config_save_safe(profile_config, "tmp", None)
  
    #on_actionFitToScreen_triggered
    print("onActionFitToScreenTriggered")
    on_actionFitToScreen_triggered(scene_ref, scene_item_ref, profile_config)

    #reset_video
    print("reset_video_attempt")
    reset_video(profile_config)

There are various parts of the code on github which are either meant for streaming or group handling etc, which I do not care for, this is very specific, so I trimmed it down. But there are some parts which I just don't know if they can be implemented due to them being in native side and I can't find out some connection in the documentation.

Right now, if I put resize_output_to_source_size in a timer within the hook signal's callback, it will change the Base/Output Resolution settings, it will also mess with the source's transform so that size and bounding box size are equal to the base/output resolution and the rest are more or less what FitToScreen would do. Finally, reset_video will try to apply the new base/output res to the everything rendering related (or I assume so).

And even though this works to a point, once the app is closed and the script unhook callback is called, I disconnect from the signals and then obs crashes silently so I'm not sure what causes it. Feed is correct up until either the app closes or you start recording while hooked and then stop recording, which also crashes obs silently.

Any ideas?

PS: I fear this might be sth that cannot be done in scripting land just because it seems to require UI access, but I'm trying to do this in a hooked_signal, just so I can get the native res of the app/game I've hooked on and use it to set everything else.
 
Last edited:
Top