From 8f83894e4989e8b5eb65c616b5b103aded88d3bc Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Sun, 11 Jun 2023 14:24:53 -0700 Subject: [PATCH] python-codecs: implement hang protection --- plugins/python-codecs/.vscode/settings.json | 8 ++--- plugins/python-codecs/package-lock.json | 4 +-- plugins/python-codecs/package.json | 2 +- plugins/python-codecs/src/gst_generator.py | 1 - plugins/python-codecs/src/main.py | 33 +++++++++++---------- 5 files changed, 25 insertions(+), 23 deletions(-) diff --git a/plugins/python-codecs/.vscode/settings.json b/plugins/python-codecs/.vscode/settings.json index 8d2e2a41e4..086185fc61 100644 --- a/plugins/python-codecs/.vscode/settings.json +++ b/plugins/python-codecs/.vscode/settings.json @@ -1,8 +1,8 @@ { // docker installation - "scrypted.debugHost": "koushik-ubuntu", - "scrypted.serverRoot": "/server", + // "scrypted.debugHost": "koushik-ubuntu", + // "scrypted.serverRoot": "/server", // windows installation // "scrypted.debugHost": "koushik-windows", @@ -13,8 +13,8 @@ // "scrypted.serverRoot": "/home/pi/.scrypted", // local checkout - // "scrypted.debugHost": "127.0.0.1", - // "scrypted.serverRoot": "/Users/koush/.scrypted", + "scrypted.debugHost": "127.0.0.1", + "scrypted.serverRoot": "/Users/koush/.scrypted", "scrypted.pythonRemoteRoot": "${config:scrypted.serverRoot}/volume/plugin.zip", "python.analysis.extraPaths": [ diff --git a/plugins/python-codecs/package-lock.json b/plugins/python-codecs/package-lock.json index f200e72b11..a1fc1e04d7 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.73", + "version": "0.1.74", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@scrypted/python-codecs", - "version": "0.1.73", + "version": "0.1.74", "devDependencies": { "@scrypted/sdk": "file:../../sdk" } diff --git a/plugins/python-codecs/package.json b/plugins/python-codecs/package.json index dda45b075e..c0c04294bb 100644 --- a/plugins/python-codecs/package.json +++ b/plugins/python-codecs/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/python-codecs", - "version": "0.1.73", + "version": "0.1.74", "description": "Python Codecs for Scrypted", "keywords": [ "scrypted", diff --git a/plugins/python-codecs/src/gst_generator.py b/plugins/python-codecs/src/gst_generator.py index 2827f6dd8b..76c989e594 100644 --- a/plugins/python-codecs/src/gst_generator.py +++ b/plugins/python-codecs/src/gst_generator.py @@ -20,7 +20,6 @@ async def createPipelineIterator(pipeline: str, gst = None): print(pipeline) finished = concurrent.futures.Future() - newGst = not gst if gst: bin = Gst.parse_bin_from_description(pipeline, False) gst.add(bin) diff --git a/plugins/python-codecs/src/main.py b/plugins/python-codecs/src/main.py index 15ad418bd6..8dba45399d 100644 --- a/plugins/python-codecs/src/main.py +++ b/plugins/python-codecs/src/main.py @@ -149,30 +149,33 @@ def multiprocess_exit(): os._exit(os.EX_OK) class CodecFork: - async def generateVideoFramesGstreamer(self, mediaObject: scrypted_sdk.MediaObject, options: scrypted_sdk.VideoFrameGeneratorOptions, filter: Any, h264Decoder: str, postProcessPipeline: str) -> scrypted_sdk.VideoFrame: + async def generateVideoFrames(self, iter, src: str): start = time.time() - try: - async for data in gstreamer.generateVideoFramesGstreamer(mediaObject, options, filter, h264Decoder, postProcessPipeline): - yield data - except Exception as e: - traceback.print_exc() - raise - finally: - print('gstreamer finished after %s' % (time.time() - start)) - asyncio.get_event_loop().call_later(1, multiprocess_exit) + loop = asyncio.get_event_loop() + def timeoutExit(): + print('Frame yield timed out, exiting pipeline.') + multiprocess_exit() - async def generateVideoFramesLibav(self, mediaObject: scrypted_sdk.MediaObject, options: scrypted_sdk.VideoFrameGeneratorOptions = None, filter: Any = None) -> scrypted_sdk.VideoFrame: - start = time.time() try: - async for data in libav.generateVideoFramesLibav(mediaObject, options, filter): + while True: + data = await asyncio.wait_for(iter.__anext__(), timeout=10) + timeout = loop.call_later(10, timeoutExit) yield data - except Exception as e: + timeout.cancel() + except Exception: traceback.print_exc() raise finally: - print('libav finished after %s' % (time.time() - start)) + print('%s finished after %s' % (src, time.time() - start)) asyncio.get_event_loop().call_later(1, multiprocess_exit) + async def generateVideoFramesGstreamer(self, mediaObject: scrypted_sdk.MediaObject, options: scrypted_sdk.VideoFrameGeneratorOptions, filter: Any, h264Decoder: str, postProcessPipeline: str) -> scrypted_sdk.VideoFrame: + async for data in self.generateVideoFrames(gstreamer.generateVideoFramesGstreamer(mediaObject, options, filter, h264Decoder, postProcessPipeline), "gstreamer"): + yield data + + async def generateVideoFramesLibav(self, mediaObject: scrypted_sdk.MediaObject, options: scrypted_sdk.VideoFrameGeneratorOptions = None, filter: Any = None) -> scrypted_sdk.VideoFrame: + async for data in self.generateVideoFrames(libav.generateVideoFramesLibav(mediaObject, options, filter), "libav"): + yield data async def fork(): return CodecFork()