Files
scrypted/plugins/python-codecs/src/libav.py

87 lines
3.3 KiB
Python

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()