Я пытаюсь передать видеозахват по сети. Я использовал для этого fastapi и uvicorn, и это сработало хорошо, но теперь я перехожу на беспроводную сеть, и сеть не может обрабатывать поток, я получаю 2-3 кадра в секунду с задержкой 5 секунд. Я читал, что gstreamer — лучший способ потоковой передачи кадров, хотя мне понадобится декодер на принимающей стороне потока.
это мой отправитель:
Отправитель.py
import time
import cv2
fps = 52
frame_width = 640
frame_height = 360
flip = 0
camSet='v4l2src device=/dev/video0 ! video/x-raw,width=640,height=360 ! nvvidconv flip-method='+str(flip)+' \
! video/x-raw(memory:NVMM), format=I420, width=640, height=360 ! nvvidconv ! video/x-raw, format=BGRx ! videoconvert \
! video/x-raw, format=BGR enable-max-performance=1 ! appsink '
cam=cv2.VideoCapture(camSet,cv2.CAP_GSTREAMER)
gst_str_rtp = " appsrc ! videoconvert ! videoscale ! video/x-raw,format=I420,width=640,height=360,framerate=52/1 ! videoconvert !\
x264enc tune=zerolatency bitrate=500 speed-preset=superfast ! rtph264pay ! \
udpsink host=0.0.0.0 port=8000"
if cam.isOpened() is not True:
print("Cannot open camera. Exiting.")
quit()
fourcc = cv2.VideoWriter_fourcc(*'H264')
out = cv2.VideoWriter(gst_str_rtp, fourcc, 52, (frame_width, frame_height), True)
while True:
ret, frame = cam.read()
cv2.imshow('webcam',frame)
out.write(frame)
cv2.moveWindow('webcam',0,0)
if cv2.waitKey(1)==ord('q'):
break
cam.release()
out.release()
cv2.destroyAllWindows()
У меня есть несколько примеров конвейера для выхода, но я не уверен, какой из них вообще работает, как это:
gst_str_rtp ="appsrc ! videoconvert ! video/x-raw,width=1280,height=720 ! queue ! x264enc ! h264parse\
! rtph264pay ! udpsink host=127.0.0.1 port=8000"
или
gst_str_rtp = "appsrc ! video/x-raw, format=I420 ! queue ! videoconvert ! \
width=640,height=360,framerate=52/1 ! nvvidconv ! omxh264enc ! \
video/x-h264, stream-format=byte-stream ! h264parse ! rtph264pay pt=96 config-interval=1 ! \
udpsink host=127.0.0.1 port=8000"
мой приемник это: приемник.py
global video_frame
video_frame = None
cv2.namedWindow('stream')
# Use locks for thread-safe viewing of frames in multiple browsers
# locks prevent the program from getting user inputs from multiple sources
# lock helps syncronize the program
global thread_lock
thread_lock = threading.Lock()
app = FastAPI()
def main():
global video_frame
camSet='udpsrc host=0.0.0.0 port=8000 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, \
encoding-name=(string)H264,\
payload=(int)96" ! rtph264depay ! decodebin ! videoconvert ! appsink'
video_capture = cv2.VideoCapture(camSet ,cv2.CAP_GSTREAMER)#initalizes our video feed
# video_capture.set(cv2.CAP_PROP_BUFFERSIZE, 0)#sets camera buffer to 0 meaning we wont get double frames
print("reading frames")
while True:
ret, frame = video_capture.read()
if not ret:
print('empty frame')
break
cv2.imshow(frame,'stream')
# with thread_lock:
# video_frame = frame.copy()
def encodeFrame():#encode frame function takes the frames and encoding them to jpg and encodes them again to bytes so we can stream them
global thread_lock
while True:
# Acquire thread_lock to access the global video_frame object
with thread_lock:
global video_frame
if video_frame is None:
continue
return_key, encoded_image = cv2.imencode(".jpg", video_frame)
if not return_key:
continue
# Output image as a byte array
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
bytearray(encoded_image) + b'\r\n')
@app.get("/")
async def video_feed():#our stream function, streams the frames encodeFrame has made to the IP and port we chose
return StreamingResponse(encodeFrame(), media_type="multipart/x-mixed-replace;boundary=frame")
if __name__ == '__main__':
# Create a thread and attach the method that captures the image frames, to it
process_thread = threading.Thread(target=main)
# Start the thread
process_thread.start()
uvicorn.run(app, host="0.0.0.0", port=9000, access_log=True)
Я использую flask и uvicorn для повторной передачи изображений на мой сервер Java, который может их прочитать. либо моя кодировка отправителя, либо декодирование получателя не работают, или, возможно, оба они неверны, и я не уверен, что, или даже если я иду правильным путем, я довольно новичок в gstreamer и конвейерах. Я был бы признателен за любую помощь в этом, и также необходимы предложения, которые не потребуют от меня рестриминга.
Не уверен, что это решит вашу проблему, но может помочь следующее:
enable-max-performance=1
не подходит в заголовках видео. Этот пункт скорее свойство плагина (вероятно, от энкодера). Может быть лучше установить частоту кадров, если ваш драйвер камеры обеспечивает другую частоту кадров с этим разрешением, иначе вы столкнетесь с несоответствием частоты кадров записи.camSet='v4l2src device=/dev/video0 ! video/x-raw,width=640,height=360,framerate=52/1 ! nvvidconv flip-method='+str(flip)+' ! video/x-raw(memory:NVMM), format=I420, width=640, height=360 ! nvvidconv ! video/x-raw, format=BGRx ! videoconvert ! video/x-raw, format=BGR ! queue ! appsink drop=1'
... ! udpsink host=<receiver_IP> port=8000 auto-multicast=0
Вы просто получите на принимающем хосте только:
'udpsrc port=8000 auto-multicast=0 ! application/x-rtp,media=video,encoding-name=H264 ! rtpjitterbuffer latency=300 ! rtph264depay ! decodebin ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1'
# Variant for NVIDIA:
'udpsrc port=8000 auto-multicast=0 ! application/x-rtp,media=video,encoding-name=H264 ! rtpjitterbuffer latency=300 ! rtph264depay ! decodebin ! nvvidconv ! video/x-raw,format=BGRx ! videoconvert ! video/x-raw,format=BGR ! appsink drop=1'
gst_str_rtp = "appsrc ! video/x-raw,format=BGR ! queue ! videoconvert ! video/x-raw,format=BGRx ! nvvidconv ! video/x-raw(memory:NVMM),format=NV12,width=640,height=360,framerate=52/1 ! nvv4l2h264enc insert-sps-pps=1 insert-vui=1 idrinterval=30 ! h264parse ! rtph264pay ! udpsink host=<receiver_IP> port=8000 auto-multicast=0"
out = cv2.VideoWriter(gst_str_rtp, cv2.CAP_GSTREAMER, 0, float(52), (frame_width, frame_height), True)
Извините, это была опечатка. Отредактировал мой ответ.
мой принимающий конец застрял на: Открытие в РЕЖИМЕ БЛОКИРОВКИ NvMMLiteOpen: Блок: BlockType = 261 NVMEDIA: Чтение vendor.tegra.display-size: статус: 6 NvMMLiteBlockCreate: Блок: BlockType = 261
Похоже, что приемник использует NVDEC. Вы пробовали конвейер NVIDIA в моем редактировании? Обратите внимание, что установка может занять некоторое время, дайте ей не менее 10 секунд.
конвейер nvidia работает отлично!! спасибо, теперь только для того, чтобы заставить сервер узла получать его и транслировать с использованием html. я буду работать над этим сейчас. после этого я буду больше изучать gstreamer и пойму все, что вы использовали.
еще один небольшой вопрос: при попытке потоковой передачи через Ethernet на другой хост-компьютер хост не получает кадры, хотя соединение хорошее и пинг возвращается, есть ли что-то, что нужно изменить при создании приемника на окнах, когда отправитель есть на ubuntu(мой случай на jetson NX)?
Если удаленный приемник не использует декодер NVIDIA, вы должны использовать первый конвейер приемника. Также убедитесь, что ни один брандмауэр не препятствует передаче UDP/8000 от отправителя к получателю.
да, по какой-то причине получатель не хочет правильно читать захват, я проверил с помощью wirehark, и поток работает нормально, и все брандмауэры не работают, единственным отличием в коде является хост, и захват возвращает None
На какой ОС работает ресивер? Также вы можете запустить прием и отображение конвейера gstreamer перед использованием opencv?
приемник находится в Windows 10, сервер, созданный в Windows, идентичен серверу в Ubuntu, за исключением аддона хоста, я пробовал все способы хостинга, такие как хостинг в Ubuntu и использование его IP на сервере Windows, и другой способ размещение на IP-адресе Windows в отправителе Ubuntu и размещение на локальном хосте на сервере Windows. я не пробовал gst-launch, но мой сервер ubuntu работает отлично, сервер Windows, похоже, не может читать из конвейера
привет, я получил ошибку gstreamer с предложенным вами набором камер: предупреждение GStreamer: ошибка при открытии конвейера записи: нет свойства «автоматическая многоадресная передача» в элементе «udpsink0». Открытие в РЕЖИМЕ БЛОКИРОВКИ. и при удалении многоадресной рассылки я получил это на принимающей стороне, а не видео: Открытие в РЕЖИМЕ БЛОКИРОВКИ NvMMLiteOpen : Block : BlockType = 261 NVMEDIA: Reading vendor.tegra.display-size : status: 6 NvMMLiteBlockCreate : Block : BlockType = 261