xpra icon
Bug tracker and wiki

Opened 2 years ago

Last modified 5 months ago

#1872 assigned task

use AVCaptureSession API for macos shadow servers

Reported by: Antoine Martin Owned by: Antoine Martin
Priority: major Milestone: future
Component: platforms Version: trunk
Keywords: Cc:

Description

The API we currently use (CGRegisterScreenRefreshCallback)is deprecated, we have to switch to AVCaptureSession and AVCaptureScreenInput.

This may be blocked by the same bug as #1231, see attachment/ticket/1231/webcam_avfoundation.py.

Attachments (1)

avf.py (5.2 KB) - added by Antoine Martin 5 months ago.
more complete example

Download all attachments as: .zip

Change History (4)

comment:1 Changed 5 months ago by Antoine Martin

Status: newassigned

Found a better code sample to start from : PyImageSnap.
It doesn't work for me, but that could just be virtualbox's USB pass-through causing problems.

comment:2 Changed 5 months ago by Antoine Martin

And a screen recording example here https://gist.github.com/timsutton/0c6439eb6eb1621a5964:

#!/usr/bin/python

# pylint: disable-msg=e1101,e0611
import time
import AVFoundation as AVF
import Quartz

from Foundation import NSObject, NSURL

def main():
    display_id = Quartz.CGMainDisplayID()

    session = AVF.AVCaptureSession.alloc().init()
    screen_input = AVF.AVCaptureScreenInput.alloc().initWithDisplayID_(display_id)
    file_output = AVF.AVCaptureMovieFileOutput.alloc().init()

    session.addInput_(screen_input)
    session.addOutput_(file_output)
    session.startRunning()

    file_url = NSURL.fileURLWithPath_('foo.mov')
    # Cheat and pass a dummy delegate object where normally we'd have a
    # AVCaptureFileOutputRecordingDelegate
    file_url = file_output.startRecordingToOutputFileURL_recordingDelegate_(
                file_url, NSObject.alloc().init())
    time.sleep(10)
    session.stopRunning()

if __name__ == '__main__':
    main()

comment:3 Changed 5 months ago by Antoine Martin

Managed to put together a screen recording-to-delegate example based on the one above

#!/usr/bin/python

import time
import AVFoundation as AVF
import Quartz
import libdispatch

from Foundation import NSObject, NSURL

def main():
    display_id = Quartz.CGMainDisplayID()

    session = AVF.AVCaptureSession.alloc().init()
    screen_input = AVF.AVCaptureScreenInput.alloc().initWithDisplayID_(display_id)
    screen_input.setCapturesCursor_(True)
    screen_input.setCapturesMouseClicks_(True)
    screen_input.setScaleFactor_(1.0)
    output = AVF.AVCaptureVideoDataOutput.alloc().init()
    output.setAlwaysDiscardsLateVideoFrames_(True)
    print("codecs:", output.availableVideoCodecTypes())
    print("pixel formats:", output.availableVideoCVPixelFormatTypes())

    class SampleBufferDelegate(NSObject):
        def captureOutput_didOutputSampleBuffer_fromConnection_(self, captureOutput, sampleBuffer, connection):
            print("captureOutput: captureOutput=%s, sampleBuffer=%s, connection=%s",
                  captureOutput, sampleBuffer, connection,
                )
        def captureOutput_didDropSampleBuffer_fromConnection_(self, captureOutput, sampleBuffer, connection):
            print("dropped a frame!")
    delegate = SampleBufferDelegate.alloc().init()

    queue = libdispatch.dispatch_queue_create(b"Image Queue", None)
    output.setSampleBufferDelegate_queue_(delegate, queue)

    session.addInput_(screen_input)
    session.addOutput_(output)
    session.startRunning()

    print("connections=", output.connections())

    time.sleep(10)
    session.stopRunning()

if __name__ == '__main__':
    main()
Last edited 5 months ago by Antoine Martin (previous) (diff)

Changed 5 months ago by Antoine Martin

Attachment: avf.py added

more complete example

Note: See TracTickets for help on using tickets.