Python FFmpeg слишком медленный RTSP-запрос - PullRequest
1 голос
/ 06 февраля 2020

В настоящее время я пытаюсь использовать python с FFmpeg для запроса данных rtsp с исходным форматом h264.

Информация о видео в реальном времени: fps: 29; разрешение: 1280 * 720.

Я могу sh, чтобы я мог запросить данные в том же формате "h264" и поместить в очередь python для будущего использования.

Вот мой код:

class CCTVReader(threading.Thread):
def __init__(self, queue, URL, fps=29):
    super().__init__()
    self.queue = queue
    self.command = ["ffmpeg",  "-y",
                    "-hwaccel",  "nvdec",
                    "-c:v",  "h264_cuvid",
                    "-vsync", "0",
                    "-max_delay", "500000",
                    "-reorder_queue_size", "10000",
                    "-i",  "rtsp://xxx.xxx.xxx.xxx:xxx/Streaming/Channels/101?transportmode=multicast",
                    "-pix_fmt", "yuv420p",
                    "-preset", "slow",
                    "-an", "-sn",
                    "-vf", "fps=29",
                    "-"]
def run(self):
    pipe = sp.Popen(self.command, stdout = sp.PIPE, bufsize=1024**3, shell=True)
    timer = time.time()
    counter = 0
    while True:
        self.queue.put(pipe.stdout.read(int(1280*720*6//4)))

Однако, после запуска этой программы примерно через 10 секунд, моя консоль показывает предупреждение:

[rtsp @ 0000020be0fbb9c0] max delay reached. need to consume packet
[rtsp @ 0000020be0fbb9c0] RTP: missed 127 packets

Похоже, моя команда не введите соответственно.

Не могли бы вы дать мне несколько советов о том, как решить эту проблему?

Большое спасибо

1 Ответ

2 голосов
/ 06 февраля 2020

Предполагая, что вы хотите захватить видеопоток без изменения данных, вам нужно установить другой набор аргументов в FFmpeg:

  • Установить "-c:v", "h264" в качестве входного аргумента (до "-i"), для информирования FFmpeg, что на входе h264 видеопоток.
  • Установить "-c:v", "copy" в качестве выходного аргумента (после "-i"), поэтому FFmpeg копирует входной видеопоток в выходную PIPE без изменений (без декодирования и кодирования).
  • Установить "-f", "h264" в качестве выходного аргумента для установки формата вывода PIPE на h264.

Вот пример рабочего кода (пожалуйста, прочтите комментарии):

import ffmpeg
import numpy as np
import subprocess as sp
import threading
import queue

class CCTVReader(threading.Thread):
    def __init__(self, q, in_stream):
        super().__init__()
        self.q = q
        self.command = ["ffmpeg",
                        "-c:v", "h264",     # Tell ffmpeg that input stream codec is h264
                        "-i", in_stream,    # Read stream from file vid.264
                        "-c:v", "copy",     # Tell ffmpeg to copy the video stream as is (without decding and encoding)
                        "-an", "-sn",       # No audio an no subtites
                        "-f", "h264",       # Define pipe format to be h264
                        "-"]                # Output is a pipe

    def run(self):
        pipe = sp.Popen(self.command, stdout=sp.PIPE, bufsize=1024**3)  # Don't use shell=True (you don't need to execute the command through the shell).

        # while True:
        for i in range(100):  # Read up to 100KBytes for testing
            data = pipe.stdout.read(1024)  # Read data from pip in chunks of 1024 bytes
            self.q.put(data)

            # Break loop if less than 1024 bytes read (not going to work with CCTV, but works with input file)
            if len(data) < 1024:
                break

        try:
            pipe.wait(timeout=1)  # Wait for subprocess to finish (with timeout of 1 second).
        except sp.TimeoutExpired:
            pipe.kill()           # Kill subprocess in case of a timeout (there should be a timeout because input stream still lives).


# Build synthetic video, for testing begins:
################################################
# width, height = 1280, 720
# in_stream = "vid.264"
# sp.Popen("ffmpeg -y -f lavfi -i testsrc=size=1280x720:duration=5:rate=1 -c:v libx264 -crf 23 -pix_fmt yuv420p " + in_stream).wait()
################################################

#in_stream = "rtsp://xxx.xxx.xxx.xxx:xxx/Streaming/Channels/101?transportmode=multicast",

#Use public RTSP Streaming for testing
in_stream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"

q = queue.Queue()

cctv_reader = CCTVReader(q, in_stream)
cctv_reader.start()
cctv_reader.join()

if q.empty():
    print("There is a problem (queue is empty)!!!")
else:
    # Write data from queue to file vid_from_queue.264 (for testingg)
    with open("vid_from_queue.264", "wb") as queue_save_file:
        while not q.empty():
            queue_save_file.write(q.get())

Я протестировал код, используя publi c RTSP Streaming и используя сгенерированный синтетический c видео файл (код для тестирования с файлом прокомментирован).

Код сохраняет выходные данные в vid_from_queue.264.
Файл .264 воспроизводится - формат файла представляет собой элементарный видеопоток h264.


Вот последний кадр захваченного видеопотока:
BigBuckBunny_115k

...