letmaik/pyvirtualcam

Cannot open installed OBS camera when running from a service

Closed this issue · 3 comments

  • Operating system: Winwdows 10
  • pyvirtualcam version: 0.8.0
  • Virtual camera (OBS, v4l2loopback, UnityCapture): OBS
  • Virtual camera version: win-dshow

Decription
Using pywin32==301 and auto-py-to-exe==2.9.0 to install pyvirtualcam as Windows service, I'm getting following error:
'obs' backend: virtual camera output could not be started

To Reproduce

def main():
    try:
        with pyvirtualcam.Camera(width=1280, height=720, fps=20, backend='obs') as cam:
            print(f'Using virtual camera: {cam.device}\n')
            frame = np.zeros((cam.height, cam.width, 3), np.uint8)  # RGB
            while True:
                frame[:] = cam.frames_sent % 255  # grayscale animation
                cam.send(frame)
                cam.sleep_until_next_frame()
    except Exception as e:
        with open(r"C:\ProgramData\error.txt", 'a') as f:
            f.write(str(e)+'\n')


class Service(win32serviceutil.ServiceFramework):
    _svc_name_ = "TEST_VID0"
    _svc_display_name_ = "test video zeros 0"

    def __init__(self, *args):
        # win32serviceutil.ServiceFramework.__init__(self, *args)
        super().__init__(*args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(5)
        self.stop_requested = False

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)
        self.stop_requested = True

    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        self.main()

    def main(self):
        main()


if __name__ == '__main__':
    if len(sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(Service)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(Service)
  • compile main() function using auto-py-to-exe - works like a charm (writing to programdata requires administrative priveleges, so it's recommended to start exe as admin, or change destination folder to where all users can write), you should see in any camera preview gray screen that changes color
  • then compile whole file using auto-py-to-exe and use file.exe install then file.exe start, you should see specified error in the text file - C:\ProgramData\error.txt

NOTE: It's not first time when i'm using pywin32 to install python programs as a service, it definetely works, provided code is a default code to create any service which main loop lies in main() function. To delete service use file.exe remove. My guess is that system services somehow cannot access camera from where they are started, but i have no clue why and thats why i ask for help, any comment on this would be helpful.

I'm not exactly sure why it fails at this stage already, but even if it worked, I doubt it is possible to then connect to this camera from a client. The reason is that there is a split between local (logged in users) and global (kernel, services, etc.) namespace when it comes to shared memory (which is what the OBS virtual camera uses), see also https://docs.microsoft.com/en-us/windows/win32/termserv/kernel-object-namespaces. I think services always create in the global namespace, but logged in users always under the local one, except if they override this behavior. Since in the context of OBS it doesn't make sense that the virtual camera data comes from somewhere that is not the user session (like a service), the OBS camera device would never try to access the global namespace. I have a feeling this is a dead end. You should see the same issue with the Unity Capture backend, but it may be worth a try.

Thing that bothers me most is that opencv can read from camera while being a windows service, but we can't send image back, this is sad ;(

I tried with Unity backend, and it's is even more disturbing. In logs i see that there were frames sent, I print out "frame sent" in while loop, but image on preview is not changing. Almost same situation, standalone version works, service version dont, but this time there's no error. Anyway thank you for quick reply, I guess I'll have to stick to autolaunch script and no-console mode while compiling exe.

Thanks for trying out Unity Capture as well. I'll close this issue since there isn't anything I can do here, but if you or someone else finds a better solution, please comment.