mirror of
https://github.com/koush/scrypted.git
synced 2026-02-07 16:02:13 +00:00
114 lines
4.2 KiB
Python
114 lines
4.2 KiB
Python
from gst_generator import createPipelineIterator
|
|
from util import optional_chain
|
|
import scrypted_sdk
|
|
from typing import Any
|
|
from urllib.parse import urlparse
|
|
import vipsimage
|
|
import pilimage
|
|
import platform
|
|
|
|
Gst = None
|
|
try:
|
|
import gi
|
|
gi.require_version('Gst', '1.0')
|
|
gi.require_version('GstBase', '1.0')
|
|
|
|
from gi.repository import Gst
|
|
except:
|
|
pass
|
|
|
|
async def generateVideoFramesGstreamer(mediaObject: scrypted_sdk.MediaObject, options: scrypted_sdk.VideoFrameGeneratorOptions = None, filter: Any = None, h264Decoder: str = None) -> scrypted_sdk.VideoFrame:
|
|
ffmpegInput: scrypted_sdk.FFmpegInput = await scrypted_sdk.mediaManager.convertMediaObjectToJSON(mediaObject, scrypted_sdk.ScryptedMimeTypes.FFmpegInput.value)
|
|
container = ffmpegInput.get('container', None)
|
|
videosrc = ffmpegInput.get('url')
|
|
videoCodec = optional_chain(ffmpegInput, 'mediaStreamOptions', 'video', 'codec')
|
|
|
|
if videosrc.startswith('tcp://'):
|
|
parsed_url = urlparse(videosrc)
|
|
videosrc = 'tcpclientsrc port=%s host=%s' % (
|
|
parsed_url.port, parsed_url.hostname)
|
|
if container == 'mpegts':
|
|
videosrc += ' ! tsdemux'
|
|
elif container == 'sdp':
|
|
videosrc += ' ! sdpdemux'
|
|
else:
|
|
raise Exception('unknown container %s' % container)
|
|
elif videosrc.startswith('rtsp'):
|
|
videosrc = 'rtspsrc buffer-mode=0 location=%s protocols=tcp latency=0 is-live=false' % videosrc
|
|
if videoCodec == 'h264':
|
|
videosrc += ' ! rtph264depay ! h264parse'
|
|
|
|
videocaps = 'video/x-raw'
|
|
# if options and options.get('resize'):
|
|
# videocaps = 'videoscale ! video/x-raw,width={width},height={height}'.format(width=options['resize']['width'], height=options['resize']['height'])
|
|
|
|
format = options and options.get('format')
|
|
# I420 is a cheap way to get gray out of an h264 stream without color conversion.
|
|
if format == 'gray':
|
|
format = 'I420'
|
|
bands = 1
|
|
else:
|
|
format = 'RGB'
|
|
bands = 3
|
|
|
|
videocaps += ',format={format}'.format(format=format)
|
|
|
|
decoder = None
|
|
def setDecoderClearDefault(value: str):
|
|
nonlocal decoder
|
|
decoder = value
|
|
if decoder == 'Default':
|
|
decoder = None
|
|
|
|
setDecoderClearDefault(None)
|
|
|
|
if videoCodec == 'h264':
|
|
setDecoderClearDefault(h264Decoder)
|
|
|
|
if not decoder:
|
|
# hw acceleration is "safe" to use on mac, but not
|
|
# on other hosts where it may crash.
|
|
# defaults must be safe.
|
|
if platform.system() == 'Darwin':
|
|
decoder = 'vtdec_hw'
|
|
else:
|
|
decoder = 'avdec_h264'
|
|
else:
|
|
# decodebin may pick a hardware accelerated decoder, which isn't ideal
|
|
# so use a known software decoder for h264 and decodebin for anything else.
|
|
decoder = 'decodebin'
|
|
|
|
videosrc += ' ! {decoder} ! queue leaky=downstream max-size-buffers=0 ! videoconvert ! {videocaps}'.format(decoder=decoder, videocaps=videocaps)
|
|
|
|
gst, gen = createPipelineIterator(videosrc)
|
|
async for gstsample in gen():
|
|
caps = gstsample.get_caps()
|
|
height = caps.get_structure(0).get_value('height')
|
|
width = caps.get_structure(0).get_value('width')
|
|
gst_buffer = gstsample.get_buffer()
|
|
result, info = gst_buffer.map(Gst.MapFlags.READ)
|
|
if not result:
|
|
continue
|
|
|
|
try:
|
|
if vipsimage.pyvips:
|
|
vips = vipsimage.new_from_memory(info.data, width, height, bands)
|
|
vipsImage = vipsimage.VipsImage(vips)
|
|
try:
|
|
mo = await vipsimage.createVipsMediaObject(vipsImage)
|
|
yield mo
|
|
finally:
|
|
vipsImage.vipsImage = None
|
|
vips.invalidate()
|
|
else:
|
|
pil = pilimage.new_from_memory(info.data, width, height, bands)
|
|
pilImage = pilimage.PILImage(pil)
|
|
try:
|
|
mo = await pilimage.createPILMediaObject(pilImage)
|
|
yield mo
|
|
finally:
|
|
pilImage.pilImage = None
|
|
pil.close()
|
|
finally:
|
|
gst_buffer.unmap(info)
|