Ejemplo n.º 1
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        video = await self.hass.async_add_executor_job(getattr, self._camera,
                                                       "last_video")

        if not video:
            error_msg = (
                f"Video not found for {self._name}. "
                f"Is it older than {self._camera.min_days_vdo_cache} days?")
            _LOGGER.error(error_msg)
            return

        stream = CameraMjpeg(self._ffmpeg.binary)
        await stream.open_camera(video.video_url,
                                 extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type,
            )
        finally:
            try:
                await stream.close()
            except:
                _LOGGER.debug(f"problem with stream close for {self._name}")
Ejemplo n.º 2
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        from haffmpeg.camera import CameraMjpeg

        video = self._camera.last_video
        if not video:
            error_msg = "Video not found for {0}. Is it older than {1} days?".format(
                self._name, self._camera.min_days_vdo_cache)
            _LOGGER.error(error_msg)
            return

        ffmpeg_manager = self.hass.data[DATA_FFMPEG]
        stream = CameraMjpeg(ffmpeg_manager.binary, loop=self.hass.loop)
        await stream.open_camera(video.video_url,
                                 extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                ffmpeg_manager.ffmpeg_stream_content_type,
            )

        finally:
            await stream.close()
Ejemplo n.º 3
0
    def __init__(self, hass, camera):
        """Initialize."""
        super().__init__()

        self._camera = camera
        self._name = camera._friendly_name
        self._state = camera._state
        self._ssid = camera._ssid
        self._local_ip = camera._ip
        self._ssid = camera._ssid
        self._device_mac = camera._device_mac
        self._device_model = camera._device_model
        self._username = "******"
        self._password = "******"
        self.is_streaming = False
        self._ffmpeg = hass.data[DATA_FFMPEG]
        self._ffmpeg_arguments = DEFAULT_FFMPEG_ARGUMENTS
        self._ffmpeg_arguments_image = DEFAULT_FFMPEG_ARGUMENTS_IMAGE
        self._ffmpeg_image_frame = ImageFrame(self._ffmpeg.binary,
                                              loop=hass.loop)
        self._ffmpeg_stream = CameraMjpeg(self._ffmpeg.binary, loop=hass.loop)
        self._last_image = None
        self._last_image_url = None
        self._local_rtsp_port = camera._local_rtsp_port
        self._stream_url = f"rtsp://{self._username}:{self._password}@{self._local_ip}:{self._local_rtsp_port}/live"
        self.access_tokens = self.update_tokens()
Ejemplo n.º 4
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        video = await self.hass.async_add_executor_job(
            getattr, self._camera, "last_video"
        )

        if not video:
            error_msg = "Video not found for {0}. Is it older than {1} days?".format(
                self.name, self._camera.min_days_vdo_cache
            )
            _LOGGER.error(error_msg)
            return

        stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
        await stream.open_camera(video.video_url, extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 5
0
 async def handle_async_mjpeg_stream(self, request):
     if not self.is_on:
         _LOGGER.debug('Miot camera: %s is off. %s', self.name,
                       self._state_attrs)
         return
     url = await self.stream_source()
     if not url:
         _LOGGER.debug('Miot camera: %s url is empty. %s', self.name,
                       self._state_attrs)
         return
     stream = CameraMjpeg(self._manager.binary)
     await stream.open_camera(url, extra_cmd=self._extra_arguments)
     try:
         stream_reader = await stream.get_reader()
         return await async_aiohttp_proxy_stream(
             self.hass,
             request,
             stream_reader,
             self._manager.ffmpeg_stream_content_type,
             timeout=60,
         )
     finally:
         try:
             await stream.close()
         except BrokenPipeError as exc:
             _LOGGER.error('Got BrokenPipeError when close stream: %s', url)
Ejemplo n.º 6
0
 async def handle_async_mjpeg_stream(self, request):
     if not self.is_on:
         _LOGGER.debug('%s: camera is off. %s', self.name,
                       self._state_attrs)
         return
     url = await self.stream_source()
     if not url:
         _LOGGER.debug('%s: stream source is empty. %s', self.name,
                       self._state_attrs)
         return
     if '-i ' not in str(url):
         url = f'-i "{url}"'
     stream = CameraMjpeg(self._manager.binary)
     await stream.open_camera(
         f'{self._ffmpeg_options or ""} {url}'.strip(),
         extra_cmd=self._extra_arguments,
     )
     try:
         stream_reader = await stream.get_reader()
         return await async_aiohttp_proxy_stream(
             self.hass,
             request,
             stream_reader,
             self._manager.ffmpeg_stream_content_type,
             timeout=60,
         )
     finally:
         try:
             await stream.close()
         except BrokenPipeError:
             _LOGGER.error('%s: Got BrokenPipeError when close stream: %s',
                           self.name, url)
Ejemplo n.º 7
0
    async def handle_async_mjpeg_stream(self, request):
        """Return an MJPEG stream."""
        # The snapshot implementation is handled by the parent class
        if self._stream_source == STREAM_SOURCE_LIST['snapshot']:
            return await super().handle_async_mjpeg_stream(request)

        if self._stream_source == STREAM_SOURCE_LIST['mjpeg']:
            # stream an MJPEG image stream directly from the camera
            websession = async_get_clientsession(self.hass)
            streaming_url = self._camera.mjpeg_url(typeno=self._resolution)
            stream_coro = websession.get(streaming_url,
                                         auth=self._token,
                                         timeout=TIMEOUT)

            return await async_aiohttp_proxy_web(self.hass, request,
                                                 stream_coro)

        # streaming via ffmpeg
        from haffmpeg.camera import CameraMjpeg

        streaming_url = self._camera.rtsp_url(typeno=self._resolution)
        stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
        await stream.open_camera(streaming_url,
                                 extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type)
        finally:
            await stream.close()
Ejemplo n.º 8
0
    def __init__(self, ffmpeg, device, coordinator):
        """Initialize."""
        super().__init__(device, coordinator)
        Camera.__init__(self)

        self._async_unsub_dispatcher_connect = None
        self._ffmpeg = ffmpeg
        self._ffmpeg_arguments = DEFAULT_FFMPEG_ARGUMENTS
        self._ffmpeg_image_frame = ImageFrame(ffmpeg.binary)
        self._ffmpeg_stream = CameraMjpeg(ffmpeg.binary)
        self._last_image = None
        self._last_image_url = None
        self._stream_url = None
Ejemplo n.º 9
0
    def __init__(self, hass, camera):
        """Initialize."""
        super().__init__()

        self._async_unsub_dispatcher_connect = None
        self._camera = camera
        self._ffmpeg = hass.data[DATA_FFMPEG]
        self._ffmpeg_arguments = DEFAULT_FFMPEG_ARGUMENTS
        self._ffmpeg_image_frame = ImageFrame(self._ffmpeg.binary)
        self._ffmpeg_stream = CameraMjpeg(self._ffmpeg.binary)
        self._last_image = None
        self._last_image_url = None
        self._stream_url = None
Ejemplo n.º 10
0
    async def handle_async_mjpeg_stream(self, request):
        """Return an MJPEG stream."""
        assert self.hass is not None
        # The snapshot implementation is handled by the parent class
        if self._stream_source == "snapshot":
            _LOGGER.debug("Handling snapshot request")
            return await super().handle_async_mjpeg_stream(request)

        if not self.available:
            _LOGGER.warning(
                "Attempt to stream %s when %s camera is offline",
                self._stream_source,
                self.name,
            )
            return None

        if self._stream_source == "mjpeg":
            # stream an MJPEG image stream directly from the camera
            _LOGGER.debug("Using mjpeg streaming")
            websession = async_get_clientsession(self.hass)
            streaming_url = self._api.mjpeg_url(
                typeno=self._resolution, channel=self._channel + 1
            )
            stream_coro = websession.get(
                streaming_url, auth=self._token, timeout=CAMERA_WEB_SESSION_TIMEOUT
            )

            return await async_aiohttp_proxy_web(self.hass, request, stream_coro)

        # streaming via ffmpeg
        _LOGGER.debug("Using rtsp streaming")
        streaming_url = "-rtsp_transport tcp -i {}".format(self._rtsp_url)
        _LOGGER.debug("Using ffmpeg binary %s", self._ffmpeg.binary)
        stream = CameraMjpeg(self._ffmpeg.binary)
        await stream.open_camera(streaming_url, extra_cmd=self._ffmpeg_arguments)
        _LOGGER.debug(
            "Camera opened with url %s and arguments %s",
            streaming_url,
            self._ffmpeg_arguments,
        )

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 11
0
 async def handle_async_mjpeg_stream(self, request):
     streaming_url = self.getStreamSource()
     stream = CameraMjpeg(self._ffmpeg.binary)
     await stream.open_camera(streaming_url)
     try:
         stream_reader = await stream.get_reader()
         return await async_aiohttp_proxy_stream(
             self.hass,
             request,
             stream_reader,
             self._ffmpeg.ffmpeg_stream_content_type,
         )
     finally:
         await stream.close()
Ejemplo n.º 12
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        from haffmpeg.camera import CameraMjpeg

        stream = CameraMjpeg(self._manager.binary, loop=self.hass.loop)
        await stream.open_camera(self._input, extra_cmd=self._extra_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream_reader,
                self._manager.ffmpeg_stream_content_type)
        finally:
            await stream.close()
Ejemplo n.º 13
0
    async def handle_async_mjpeg_stream(
            self, request: web.Request) -> web.StreamResponse:
        """Generate an HTTP MJPEG stream from the latest recorded activity."""
        stream = CameraMjpeg(get_ffmpeg_manager(self.hass).binary)
        url = await self.coordinator.device.async_get_activity_video_url()
        await stream.open_camera(url, extra_cmd="-r 210")

        try:
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                await stream.get_reader(),
                get_ffmpeg_manager(self.hass).ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 14
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        stream_source = await self.stream_source()

        stream = CameraMjpeg(self._manager.binary, loop=self._hass.loop)
        await stream.open_camera(stream_source)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self._hass,
                request,
                stream_reader,
                self._manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 15
0
    async def handle_async_mjpeg_stream(
            self, request: web.Request) -> web.StreamResponse:
        """Generate an HTTP MJPEG stream from the camera."""

        stream = CameraMjpeg(self._manager.binary)
        await stream.open_camera(self._input, extra_cmd=self._extra_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 16
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        if self._video_url is None:
            return

        stream = CameraMjpeg(self._ffmpeg_manager.binary)
        await stream.open_camera(self._video_url)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._ffmpeg_manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 17
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        from haffmpeg.camera import CameraMjpeg

        _LOGGER.debug("Handling mjpeg stream from camera '%s'", self._name)

        ffmpeg_manager = self.hass.data[DATA_FFMPEG]
        stream = CameraMjpeg(ffmpeg_manager.binary, loop=self.hass.loop)

        await stream.open_camera(self._input, extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream_reader,
                ffmpeg_manager.ffmpeg_stream_content_type)
        finally:
            await stream.close()
Ejemplo n.º 18
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        if not self._is_on:
            return

        stream = CameraMjpeg(self._manager.binary)
        await stream.open_camera(self._last_url, extra_cmd=self._extra_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 19
0
    def __init__(
        self,
        coordinator: EufySecurityDataUpdateCoordinator,
        config_entry: ConfigEntry,
        device: Device,
    ) -> None:
        Camera.__init__(self)
        EufySecurityEntity.__init__(self, coordinator, config_entry, device)

        self.device.set_streaming_status_callback(self.set_is_streaming)
        self._attr_frontend_stream_type = STREAM_TYPE_HLS

        # camera image
        self.picture_bytes = None
        self.picture_url = None

        # p2p streaming
        self.start_stream_function = self.async_start_p2p_livestream
        self.stop_stream_function = self.async_stop_p2p_livestream

        # video generation using ffmpeg for p2p
        self.ffmpeg_binary = self.coordinator.hass.data[DATA_FFMPEG].binary
        self.ffmpeg = CameraMjpeg(self.ffmpeg_binary)
        self.default_codec = DEFAULT_CODEC
        self.is_ffmpeg_running = False

        # when HA started, p2p streaming was active, catch up with p2p streaming
        if self.device.is_p2p_streaming is True:
            async_call_later(self.coordinator.hass, 0,
                             self.async_start_p2p_livestream)

        if self.coordinator.config.use_rtsp_server_addon is True:
            self.p2p_url = f"rtsp://{self.coordinator.config.rtsp_server_address}:{self.coordinator.config.rtsp_server_port}/{self.device.serial_number}"
            self.ffmpeg_output = f"-f rtsp -rtsp_transport tcp {self.p2p_url}"
        else:
            self.ffmpeg_output = f"{DOMAIN}-{self.device.serial_number}.m3u8"
            self.p2p_url = self.ffmpeg_output

        # for rtsp streaming
        if self.device.state.get("rtspStream", None) is not None:
            self.start_stream_function = self.async_start_rtsp_livestream
            self.stop_stream_function = self.async_stop_rtsp_livestream

        self.set_is_streaming()
Ejemplo n.º 20
0
    async def handle_async_mjpeg_stream(
            self, request: web.Request) -> web.StreamResponse | None:
        """Return an MJPEG stream."""
        assert self.hass is not None
        # The snapshot implementation is handled by the parent class
        if self._stream_source == "snapshot":
            return await super().handle_async_mjpeg_stream(request)

        if not self.available:
            _LOGGER.warning(
                "Attempt to stream %s when %s camera is offline",
                self._stream_source,
                self.name,
            )
            return None

        if self._stream_source == "mjpeg":
            # stream an MJPEG image stream directly from the camera
            websession = async_get_clientsession(self.hass)
            streaming_url = self._api.mjpeg_url(typeno=self._resolution)
            stream_coro = websession.get(streaming_url,
                                         auth=self._token,
                                         timeout=CAMERA_WEB_SESSION_TIMEOUT)

            return await async_aiohttp_proxy_web(self.hass, request,
                                                 stream_coro)

        # streaming via ffmpeg
        assert self._rtsp_url is not None
        streaming_url = self._rtsp_url
        stream = CameraMjpeg(self._ffmpeg.binary)
        await stream.open_camera(streaming_url,
                                 extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 21
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        stream_source = "rtmp://{}:{}/bcs/channel0_{}.bcs?channel=0&stream=0&user={}&password={}".format(
            self._host, self._reolinkSession.rtmpport, self._stream,
            self._username, self._password)

        stream = CameraMjpeg(self._manager.binary, loop=self._hass.loop)
        await stream.open_camera(stream_source)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self._hass,
                request,
                stream_reader,
                self._manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 22
0
    async def handle_async_mjpeg_stream(self, request) -> Optional[StreamResponse]:
        """Generate an HTTP MJPEG stream from the camera."""
        if not self._stream_url:
            return None

        ffmpeg_manager = self.hass.data[DATA_FFMPEG]
        stream = CameraMjpeg(ffmpeg_manager.binary, loop=self.hass.loop)
        await stream.open_camera(self._ffmpeg_input, extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                ffmpeg_manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 23
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        if self._live_stream_session is None:
            return

        stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
        await stream.open_camera(self._live_stream_session.live_stream_url,
                                 extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 24
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        from haffmpeg.camera import CameraMjpeg

        if not self._input:
            await self.hass.async_add_executor_job(self.obtain_input_uri)
            if not self._input:
                return None

        ffmpeg_manager = self.hass.data[DATA_FFMPEG]
        stream = CameraMjpeg(ffmpeg_manager.binary, loop=self.hass.loop)
        await stream.open_camera(self._input, extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream_reader,
                ffmpeg_manager.ffmpeg_stream_content_type)
        finally:
            await stream.close()
Ejemplo n.º 25
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        from haffmpeg.camera import CameraMjpeg
        video = self._camera.last_video
        if not video:
            error_msg = \
                'Video not found for {0}. Is it older than {1} days?'.format(
                    self.name, self._camera.min_days_vdo_cache)
            _LOGGER.error(error_msg)
            return

        stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
        await stream.open_camera(video.video_url,
                                 extra_cmd=self._ffmpeg_arguments)

        try:
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream,
                'multipart/x-mixed-replace;boundary=ffserver')
        finally:
            await stream.close()
Ejemplo n.º 26
0
    async def handle_async_mjpeg_stream(
            self, request: Request) -> StreamResponse | None:
        """Generate an HTTP MJPEG stream from the camera."""
        if self._live_stream_session is None:
            return None

        live_stream_url = await self.hass.async_add_executor_job(
            getattr, self._live_stream_session, "live_stream_url")
        stream = CameraMjpeg(self._ffmpeg.binary)
        await stream.open_camera(live_stream_url,
                                 extra_cmd=self._ffmpeg_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 27
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        _LOGGER.debug("Handling mjpeg stream from camera '%s'", self._name)

        stream_source = await self.stream_source()
        if not stream_source:
            return super().handle_async_mjpeg_stream(request)

        stream = CameraMjpeg(self._manager.binary)
        await stream.open_camera(stream_source,
                                 extra_cmd=self._extra_arguments)

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                self._manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 28
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera's last activity."""
        from haffmpeg.camera import CameraMjpeg

        last_activity = await self._camera.last_activity
        session_cookie = self._camera._logi._cache['cookie']
        header = '"X-Logi-Auth: %s"' % (session_cookie)

        stream = CameraMjpeg(self._ffmpeg.binary, loop=self.hass.loop)
        await stream.open_camera('-headers %s -i %s' %
                                 (header, last_activity.download_url))

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass, request, stream_reader,
                self._ffmpeg.ffmpeg_stream_content_type)
        finally:
            try:
                await stream.close()
            except BrokenPipeError:
                return
Ejemplo n.º 29
0
    async def handle_async_mjpeg_stream(self, request):
        """Generate an HTTP MJPEG stream from the camera."""
        LOGGER.debug("Handling mjpeg stream from camera '%s'", self.device.name)

        ffmpeg_manager = self.hass.data[DATA_FFMPEG]
        stream = CameraMjpeg(ffmpeg_manager.binary)

        await stream.open_camera(
            self._stream_uri,
            extra_cmd=self.device.config_entry.options.get(CONF_EXTRA_ARGUMENTS),
        )

        try:
            stream_reader = await stream.get_reader()
            return await async_aiohttp_proxy_stream(
                self.hass,
                request,
                stream_reader,
                ffmpeg_manager.ffmpeg_stream_content_type,
            )
        finally:
            await stream.close()
Ejemplo n.º 30
0
def cli(ffmpeg, source, output, extra):
    """FFMPEG capture frame as image."""
    loop = asyncio.get_event_loop()
    stream = CameraMjpeg(ffmpeg_bin=ffmpeg, loop=loop)

    async def read_stream():
        """Read stream inside loop."""
        await stream.open_camera(source, extra)

        reader = await stream.get_reader()
        try:
            while True:
                data = await reader.read(2048)
                print(data)
        except OSError:
            pass

    future = asyncio.ensure_future(read_stream())
    try:
        loop.run_until_complete(future)
    finally:
        loop.call_soon_threadsafe(future.cancel)
        loop.run_until_complete(stream.close())