LINUX.ORG.RU

Декодирование потока h.264 из COM-порта

 , , ,


0

2

Доброго времени суток. Я хотел бы знать, существует ли «несложный» способ декодирования потока H.264 в формате NAL, поступающего через COM-порт, с помощью программного обеспечения?

В настоящий момент я могу покадрово декодировать поток с помощью скрипта на python. В этом скрипте я сначала записываю входящие данные в файл, и когда появляется маркер конца кадра 00_00_00_01, я отображаю кадр с помощью медиаплеера от ffmpeg - ffplay.

import serial
import subprocess
import os
import time

# Открываем последовательный порт (замени 'COM3' на свой порт)
ser = serial.Serial('COM3', 115200, timeout=1)
# Путь к файлу
output_file = "output.264"
# Переменная для хранения процесса ffplay
ffplay_process = None
# Открываем файл для записи в бинарном режиме
with open(output_file, "wb") as file:
    print("Запись байтов в output.264. Ожидание окончания кадра 0x00000001.")
    buffer = bytearray()
    marker = b'\x00\x00\x00\x01'
    try:
        while True:
            if ser.in_waiting:  # Если в буфере есть данные
                data = ser.read(ser.in_waiting)  # Читаем все доступные байты
                buffer.extend(data)
                
                # Проверяем, есть ли маркер окончания кадра в буфере
                while marker in buffer:
                    index = buffer.index(marker) + len(marker)  # Позиция после маркера
                    frame = buffer[:index]  # Извлекаем кадр
                    buffer = buffer[index:]  # Оставляем остаток
                    
                    print(f"Кадр записан: {len(frame)} байт")
                    file.write(frame)  # Записываем кадр в файл
                    file.flush()  # Принудительная запись на диск
                    
                    # Закрываем окно ffplay, если оно уже открыто
                    if ffplay_process and ffplay_process.poll() is None:
                        ffplay_process.terminate()
                        ffplay_process.wait()  # Дожидаемся завершения процесса
                    
                    # Воспроизводим записанный кадр, окно открывается заново
                    ffplay_process = subprocess.Popen(["ffplay", "-f", "h264", "-i", output_file])

    except KeyboardInterrupt:
        print("\nЗапись завершена.")
    finally:
        # Закрываем порт и процесс ffplay
        ser.close()

Однако каждый раз, когда обнаруживается новый маркер конца кадра, окно ffplay закрывается и снова открывается для отображения следующего кадра. При передаче видео это окно будет открываться-закрываться 30 раз в секунду :) Есть ли способ отображать кадры в одном окне для плавного воспроизведения при потоковой передаче видео?

Вообще я сомневаюсь что это правильный и оптимальный подход. Может есть какие-то общепринятые решения? Или может кто знает другое ПО, которое больше подходит для этой задачи? Я не знаю с чего начать, я нашел мало информации в интернете, поэтому буду рад любым подсказкам.



Последнее исправление: bomvar74 (всего исправлений: 1)

Не смогу подсказать предметно, но 10 лет назад я декодировал такие потоки из UDP порта, и из файлов своего формата. Если там заменить на данные из COM порта - всё точно так же будет работать, вот именно в «формате NAL» со всеми этими маркерами

Но для этого я писал свою программу, никакие ffplay не применял

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

А можно поподробнее про структуры программы? То есть у вас был какой-то медиаплеер которому вы передавали данные для воспроизведения с помощью своей программы, которая в свою очередь принимала данные по UDP? Или как?

bomvar74
() автор топика

phind в ответ на «write python script which receive h.264 from com port and show it using ffplay as streaming video» сказал, что надо инициализировать ffplay таким образом:

def setup_ffplay():
    """Initialize ffplay process for streaming."""
    return subprocess.Popen([
        "ffplay", "-f", "h264", "-framerate", "30",
        "-probesize", "32", "-analyzeduration", "1",
        "-fflags", "nobuffer", "-flags", "low_delay",
        "-"
    ], stdin=subprocess.PIPE)

Вот. Передаю таинственные письмена как есть.

Irma ★★★
()

Через gstreamer пробуй. Код от нейросети, не проверял. Поменяй на свой порт и скорость.

import serial
from gi.repository import Gst, GLib

Gst.init(None)
pipeline = Gst.parse_launch("appsrc name=src ! video/x-h264,stream-format=byte-stream,alignment=nal ! h264parse ! avdec_h264 ! videoconvert ! autovideosink")
src = pipeline.get_by_name("src")
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
pipeline.set_state(Gst.State.PLAYING)

try:
    while True:
        data = ser.read(1024)
        if data:
            buffer = Gst.Buffer.new_wrapped(data)
            src.emit("push-buffer", buffer)
except KeyboardInterrupt:
    pass

pipeline.set_state(Gst.State.NULL)
ox55ff ★★★★★
()

И как ты себе представляешь 30 кадров в секунду на скорости 115200 бод?

А так, тебе по сути промежуточный скрипт на питоне не нужен. «Всё есть файл» же. Ты можешь натравить ffplay прямо на /dev/ttyUSB0 или как там зовут твой COM-порт предварительно задав его параметры (скорость, чётность и т. д.) stty.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Ну я щас по UART на компьютер по 1 кадру отправляю на этой скорости. Я подумал если получиться непрерывно воспроизводить их на мониторе, потом можно будет передавать видео по USB интерфейсу.

bomvar74
() автор топика
Ответ на: комментарий от bomvar74

Функциями ffmpeg я декодировал эти данные в некий YCbCr буфер, затем перегонял в RGB и вываливал на форму Qt. Кажется у ffmpeg можно задействовать ускоренные SIMD функции конверсии цветового формата, ведь очевидно почему YCbCr-подобные форматы являются родными для видео-кодеков, поэтому там идут конверторы чуть ли отдельной кажется либой

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от luke

На самом деле, COM порты бывают и до мегабита массовые, бывают также до 6 мегабит. Чтобы успокоить общественность, уточню что речь про USB-COM/UART

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от luke

Скорость может быть и выше 115200, у меня ещё диалап-модем 25 лет назад умел 230400 работать, как и комп. Емнип до мегабита должно раскочегариваться

anonymous
()

Аж олдскулы свело, вспомнил как в нортон коммандере файл передавал по lpt с одного компа на другой.

Автор, делись результатом потом, интересно.

skyman ★★★★
()