import time import scrypted_sdk from typing import Any import vipsimage import pilimage from generator_common import createVideoFrame, createImageMediaObject av = None try: import av av.logging.set_level(av.logging.PANIC) except: pass async def generateVideoFramesLibav(mediaObject: scrypted_sdk.MediaObject, options: scrypted_sdk.VideoFrameGeneratorOptions = None, filter: Any = None) -> scrypted_sdk.VideoFrame: ffmpegInput: scrypted_sdk.FFmpegInput = await scrypted_sdk.mediaManager.convertMediaObjectToJSON(mediaObject, scrypted_sdk.ScryptedMimeTypes.FFmpegInput.value) videosrc = ffmpegInput.get('url') container = av.open(videosrc) # none of this stuff seems to work. might be libav being slow with rtsp. # container.no_buffer = True # container.gen_pts = False # container.options['-analyzeduration'] = '0' # container.options['-probesize'] = '500000' stream = container.streams.video[0] # stream.codec_context.thread_count = 1 # stream.codec_context.low_delay = True # stream.codec_context.options['-analyzeduration'] = '0' # stream.codec_context.options['-probesize'] = '500000' gray = options and options.get('format') == 'gray' start = 0 try: vipsImage: vipsimage.VipsImage = None pilImage: pilimage.PILImage = None mo: scrypted_sdk.MediaObject = None for idx, frame in enumerate(container.decode(stream)): now = time.time() if not start: start = now elapsed = now - start if (frame.time or 0) < elapsed - 0.500: # print('too slow, skipping frame') continue # print(frame) if vipsimage.pyvips: if gray and frame.format.name.startswith('yuv') and frame.planes and len(frame.planes): vips = vipsimage.new_from_memory(memoryview(frame.planes[0]), frame.width, frame.height, 1) elif gray: vips = vipsimage.pyvips.Image.new_from_array(frame.to_ndarray(format='gray')) else: vips = vipsimage.pyvips.Image.new_from_array(frame.to_ndarray(format='rgb24')) if not mo: vipsImage = vipsimage.VipsImage(vips) mo = await createImageMediaObject(vipsImage) vipsImage.vipsImage = vips try: yield createVideoFrame(mo) finally: await vipsImage.close() else: if gray and frame.format.name.startswith('yuv') and frame.planes and len(frame.planes): pil = pilimage.new_from_memory(memoryview(frame.planes[0]), frame.width, frame.height, 1) elif gray: rgb = frame.to_image() try: pil = rgb.convert('L') finally: rgb.close() else: pil = frame.to_image() if not mo: pilImage = pilimage.PILImage(pil) mo = await createImageMediaObject(pilImage) pilImage.pilImage = pil try: yield createVideoFrame(mo) finally: await pilImage.close() finally: container.close()