bropat / eufy-security-ws

Small server wrapper around eufy-security-client library to access it via a WebSocket.
MIT License
184 stars 29 forks source link

[Bug]: incomplete H264 video buffer #301

Closed yarin177 closed 8 months ago

yarin177 commented 9 months ago

Version

1.7.1

Node version

20.11.0

Operating System type

Windows

Operating system version

Windows 10

Describe the bug

After sending the device.start_livestream command, I start recieving the buffer containng the video data, but I don't always get completed buffer, which casues the codec decode command to return error.

Here is my Python implemention of the client and showing a live video from the server:

def on_message(ws, message):
    data = json.loads(message)
    message_type = data["type"]
    if message_type == "event" and data["event"]["event"] == "livestream video data":
        image_buffer = data["event"]["buffer"]["data"]
        if not is_h264_complete(image_buffer):
            print("Error! incomplete h264 data")
            return
        buffer_bytes = bytes(image_buffer)
        packet = av.Packet(buffer_bytes)
        codec = av.CodecContext.create('h264', 'r')
        frames = codec.decode(packet)

        # Display the image
        for frame in frames:
            image = frame.to_ndarray(format='bgr24')
            cv2.imshow('Image', image)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

To reproduce

Run eufy-security-server with node (you may need to change the serial number) And then run this python file:

import websocket
import json
import av
import numpy as np
import cv2

def is_h264_complete(buffer):
    # Convert the buffer to bytes
    buffer_bytes = bytes(buffer)

    # Look for the start code in the buffer
    start_code = bytes([0, 0, 0, 1])
    positions = [i for i in range(len(buffer_bytes)) if buffer_bytes.startswith(start_code, i)]

    # Check for the presence of SPS and PPS
    has_sps = any(buffer_bytes[i+4] & 0x1F == 7 for i in positions)
    has_pps = any(buffer_bytes[i+4] & 0x1F == 8 for i in positions)

    return has_sps and has_pps

def on_message(ws, message):
    data = json.loads(message)
    message_type = data["type"]
    if message_type == "event" and data["event"]["event"] == "livestream video data":
        image_buffer = data["event"]["buffer"]["data"]
        if not is_h264_complete(image_buffer):
            print("Error! incomplete h264 data")
            return
        buffer_bytes = bytes(image_buffer)
        packet = av.Packet(buffer_bytes)
        codec = av.CodecContext.create('h264', 'r')
        frames = codec.decode(packet)

        # Display the image
        for frame in frames:
            image = frame.to_ndarray(format='bgr24')
            cv2.imshow('Image', image)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
    '''
    if message_type == "event" and "name" in message_type:
        if message_type["name"] == "personName":
            print(f"Person Detected!")
    '''

def on_error(ws, error):
    print(f"Error: {error}")

def on_close(ws):
    print("Connection closed")

def on_open(ws):
    print("Connection opened")
    # Send a message to the server
    ws.send(json.dumps({"messageId" : "start_listening", "command": "start_listening"}))  # replace with your command and parameters
    ws.send(json.dumps({"command": "set_api_schema", "schemaVersion" : 20}))

    ws.send(json.dumps({"messageId" : "start_livestream", "command": "device.start_livestream", "serialNumber": "T8410P4223334EBE"}))  # replace with your command and parameters

if __name__ == "__main__":
    websocket.enableTrace(False)
    ws = websocket.WebSocketApp("ws://localhost:3000",  # replace with your server URI
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)
    ws.on_open = on_open
    ws.run_forever()

Screenshots & Logfiles

Seems like I get different lengths of the buffer every time, such as:

48774 1728 3467 11949 14267 11974 13556 17097 8486 6615 9923 8697 5014

Additional context

No response

bropat commented 8 months ago

I can guarantee that others are already using live streaming without any problems, so I assume that the problem lies with your implementation.