diff --git a/plugins/python-codecs/package-lock.json b/plugins/python-codecs/package-lock.json index 965e5ac19..8a87d7807 100644 --- a/plugins/python-codecs/package-lock.json +++ b/plugins/python-codecs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/python-codecs", - "version": "0.1.89", + "version": "0.1.90", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@scrypted/python-codecs", - "version": "0.1.89", + "version": "0.1.90", "devDependencies": { "@scrypted/sdk": "file:../../sdk" } diff --git a/plugins/python-codecs/package.json b/plugins/python-codecs/package.json index 9abed1b09..bda0051a0 100644 --- a/plugins/python-codecs/package.json +++ b/plugins/python-codecs/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/python-codecs", - "version": "0.1.89", + "version": "0.1.90", "description": "Python Codecs for Scrypted", "keywords": [ "scrypted", diff --git a/plugins/python-codecs/src/libav.py b/plugins/python-codecs/src/libav.py index b2bca2864..20d247f0e 100644 --- a/plugins/python-codecs/src/libav.py +++ b/plugins/python-codecs/src/libav.py @@ -6,44 +6,56 @@ import pilimage from generator_common import createVideoFrame, createImageMediaObject import threading import asyncio +import traceback av = None try: import av - av.logging.set_level(av.logging.PANIC) + + 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' +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") + + gray = options and options.get("format") == "gray" sampleQueue = asyncio.Queue(1) loop = asyncio.get_event_loop() + finished = False def threadMain(): try: + container = av.open(videosrc) + container.options["analyzeduration"] = "0" + container.options["probesize"] = "500000" + stream = container.streams.video[0] + for idx, frame in enumerate(container.decode(stream)): + if finished: + break + try: # non blocking put may fail if queue is not empty sampleQueue.put_nowait(frame) except: pass except: - asyncio.run_coroutine_threadsafe(sampleQueue.put(None), loop = loop) + traceback.print_exc() + raise + finally: + asyncio.run_coroutine_threadsafe(sampleQueue.put(None), loop=loop) thread = threading.Thread(target=threadMain) thread.start() @@ -61,17 +73,28 @@ async def generateVideoFramesLibav(mediaObject: scrypted_sdk.MediaObject, option break if not firstFrame: - print('first frame') + print("first frame") print(time.time()) firstFrame = True 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) + 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')) + 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')) + vips = vipsimage.pyvips.Image.new_from_array( + frame.to_ndarray(format="rgb24") + ) if not mo: vipsImage = vipsimage.VipsImage(vips) @@ -83,12 +106,19 @@ async def generateVideoFramesLibav(mediaObject: scrypted_sdk.MediaObject, option 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) + 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') + pil = rgb.convert("L") finally: rgb.close() else: @@ -104,4 +134,4 @@ async def generateVideoFramesLibav(mediaObject: scrypted_sdk.MediaObject, option finally: await pilImage.close() finally: - container.close() + finished = True