Added support to Amcrest camera to feed using RTSP via ffmpeg (#7646)

* Implemented ffmpeg option on Amcrest camera and upgraded to version 1.2.0

* Added ffmpeg arguments and binary options to Amcrest camera

* Added ffmpeg as dependencies

* Makes lint happy and fixed requirements_all.txt

* Inherent the ffmpeg.binary configuration from ffmpeg component

* Update amcrest.py
This commit is contained in:
Marcelo Moreira de Mello 2017-05-18 04:06:24 -04:00 committed by Pascal Vizeli
parent 0eb6540fe7
commit 0fd415d7fb
3 changed files with 33 additions and 13 deletions

View file

@ -12,18 +12,22 @@ import voluptuous as vol
import homeassistant.loader as loader import homeassistant.loader as loader
from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA) from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA)
from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.const import ( from homeassistant.const import (
CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_PORT) CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_PORT)
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import ( from homeassistant.helpers.aiohttp_client import (
async_get_clientsession, async_aiohttp_proxy_web) async_get_clientsession, async_aiohttp_proxy_web,
async_aiohttp_proxy_stream)
REQUIREMENTS = ['amcrest==1.1.9'] REQUIREMENTS = ['amcrest==1.2.0']
DEPENDENCIES = ['ffmpeg']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_RESOLUTION = 'resolution' CONF_RESOLUTION = 'resolution'
CONF_STREAM_SOURCE = 'stream_source' CONF_STREAM_SOURCE = 'stream_source'
CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments'
DEFAULT_NAME = 'Amcrest Camera' DEFAULT_NAME = 'Amcrest Camera'
DEFAULT_PORT = 80 DEFAULT_PORT = 80
@ -40,7 +44,8 @@ RESOLUTION_LIST = {
STREAM_SOURCE_LIST = { STREAM_SOURCE_LIST = {
'mjpeg': 0, 'mjpeg': 0,
'snapshot': 1 'snapshot': 1,
'rtsp': 2,
} }
CONTENT_TYPE_HEADER = 'Content-Type' CONTENT_TYPE_HEADER = 'Content-Type'
@ -56,6 +61,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE): vol.Optional(CONF_STREAM_SOURCE, default=DEFAULT_STREAM_SOURCE):
vol.All(vol.In(STREAM_SOURCE_LIST)), vol.All(vol.In(STREAM_SOURCE_LIST)),
vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string,
}) })
@ -92,8 +98,9 @@ class AmcrestCam(Camera):
super(AmcrestCam, self).__init__() super(AmcrestCam, self).__init__()
self._camera = camera self._camera = camera
self._base_url = self._camera.get_base_url() self._base_url = self._camera.get_base_url()
self._hass = hass
self._name = device_info.get(CONF_NAME) self._name = device_info.get(CONF_NAME)
self._ffmpeg = hass.data[DATA_FFMPEG]
self._ffmpeg_arguments = device_info.get(CONF_FFMPEG_ARGUMENTS)
self._resolution = RESOLUTION_LIST[device_info.get(CONF_RESOLUTION)] self._resolution = RESOLUTION_LIST[device_info.get(CONF_RESOLUTION)]
self._stream_source = STREAM_SOURCE_LIST[ self._stream_source = STREAM_SOURCE_LIST[
device_info.get(CONF_STREAM_SOURCE) device_info.get(CONF_STREAM_SOURCE)
@ -117,15 +124,28 @@ class AmcrestCam(Camera):
yield from super().handle_async_mjpeg_stream(request) yield from super().handle_async_mjpeg_stream(request)
return return
# Otherwise, stream an MJPEG image stream directly from the camera elif self._stream_source == STREAM_SOURCE_LIST['mjpeg']:
websession = async_get_clientsession(self.hass) # stream an MJPEG image stream directly from the camera
streaming_url = '{0}mjpg/video.cgi?channel=0&subtype={1}'.format( websession = async_get_clientsession(self.hass)
self._base_url, self._resolution) streaming_url = self._camera.mjpeg_url(typeno=self._resolution)
stream_coro = websession.get(
streaming_url, auth=self._token, timeout=TIMEOUT)
stream_coro = websession.get( yield from async_aiohttp_proxy_web(self.hass, request, stream_coro)
streaming_url, auth=self._token, timeout=TIMEOUT)
yield from async_aiohttp_proxy_web(self.hass, request, stream_coro) else:
# streaming via fmpeg
from haffmpeg import CameraMjpeg
streaming_url = self._camera.rtsp_url(typeno=self._resolution)
stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
yield from stream.open_camera(
streaming_url, extra_cmd=self._ffmpeg_arguments)
yield from async_aiohttp_proxy_stream(
self.hass, request, stream,
'multipart/x-mixed-replace;boundary=ffserver')
yield from stream.close()
@property @property
def name(self): def name(self):

View file

@ -19,7 +19,7 @@ import homeassistant.loader as loader
from requests.exceptions import HTTPError, ConnectTimeout from requests.exceptions import HTTPError, ConnectTimeout
REQUIREMENTS = ['amcrest==1.1.9'] REQUIREMENTS = ['amcrest==1.2.0']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -56,7 +56,7 @@ alarmdecoder==0.12.1.0
# homeassistant.components.camera.amcrest # homeassistant.components.camera.amcrest
# homeassistant.components.sensor.amcrest # homeassistant.components.sensor.amcrest
amcrest==1.1.9 amcrest==1.2.0
# homeassistant.components.media_player.anthemav # homeassistant.components.media_player.anthemav
anthemav==1.1.8 anthemav==1.1.8