python-codecs: fix potential leak/hang

This commit is contained in:
Koushik Dutta
2023-10-25 08:49:10 -07:00
parent 476bd3b427
commit 52692c0912
3 changed files with 59 additions and 29 deletions

View File

@@ -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"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/python-codecs",
"version": "0.1.89",
"version": "0.1.90",
"description": "Python Codecs for Scrypted",
"keywords": [
"scrypted",

View File

@@ -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