async def async_get_still_stream( request: web.Request, image_cb: Callable[[], Awaitable[bytes | None]], content_type: str, interval: float, ) -> web.StreamResponse: """Generate an HTTP MJPEG stream from camera images. This method must be run in the event loop. """ response = web.StreamResponse() response.content_type = CONTENT_TYPE_MULTIPART.format("--frameboundary") await response.prepare(request) async def write_to_mjpeg_stream(img_bytes: bytes) -> None: """Write image to stream.""" await response.write( bytes( "--frameboundary\r\n" "Content-Type: {}\r\n" "Content-Length: {}\r\n\r\n".format(content_type, len(img_bytes)), "utf-8", ) + img_bytes + b"\r\n" ) last_image = None while True: img_bytes = await image_cb() if not img_bytes: break if img_bytes != last_image: await write_to_mjpeg_stream(img_bytes) # Chrome seems to always ignore first picture, # print it twice. if last_image is None: await write_to_mjpeg_stream(img_bytes) last_image = img_bytes await asyncio.sleep(interval) return response
async def async_get_still_stream(request, image_cb, content_type, interval): """Generate an HTTP MJPEG stream from camera images. The original implementation in the HA core camera component, had some issues in displaying the images The view was always 1 frame behind so thats why it was in the original code to send twice at start. Normally not a problem, but in this component it is essential that the image that is served is also displayed """ response = web.StreamResponse() response.content_type = CONTENT_TYPE_MULTIPART.format("--frameboundary") await response.prepare(request) async def write_to_mjpeg_stream(img_bytes): """Write image to stream.""" await response.write( bytes( "--frameboundary\r\n" "Content-Type: {}\r\n" "Content-Length: {}\r\n\r\n".format(content_type, len( img_bytes)), "utf-8", ) + img_bytes + b"\r\n") LastImage = None SameImagecount = 0 while True: img_bytes = await image_cb() if not img_bytes: break # Send same image max 2 times, to fix browserproblem if img_bytes == LastImage: SameImagecount += 1 else: SameImagecount = 0 if SameImagecount < 2: await write_to_mjpeg_stream(img_bytes) LastImage = img_bytes await asyncio.sleep(interval) return response
def ffmpeg_stream_content_type(self): """Return HTTP content type for ffmpeg stream.""" if self._major_version is not None and self._major_version > 3: return CONTENT_TYPE_MULTIPART.format("ffmpeg") return CONTENT_TYPE_MULTIPART.format("ffserver")