使用硬件编码器时遇到问题

我搭建了一个从摄像头读取视频流然后目标检测后再推流的框架,现在我想进行16路推流。 :face_with_monocle:

我试了一下发现最多只能推出8路视频流,下图是7路视频流的情况,一切正常。

但是在8路视频流时出现问题

我查看手册,说是编码器通道0-31都可以。

现在想请问一下,是不是理论上可以推32*8=256路,还是说整个板子只能推8路视频流。

以下是我的相关代码,希望有大佬和官方大佬进行解答,谢谢各位 :

class RtspYoloEncoder:
  def __init__(self, rtsp_stream, rtsp_url, encode_channel):
      self.rtsp_stream = rtsp_stream
      self.encode_queue = queue.Queue(maxsize=5)
      self.encoder_thread = EncoderThread(self.encode_queue, rtsp_stream.width, rtsp_stream.height, rtsp_url, encode_channel)

  def start(self):
      self.encoder_thread.start()

  def stop(self):
      self.encoder_thread.stop()

  def enqueue(self, frame):
      if not self.encode_queue.full():
          self.encode_queue.put(frame.copy())

class EncoderThread(threading.Thread):
  def __init__(self, encode_queue, width, height, rtsp_url, encode_channel):
      super().__init__()
      self.encode_queue = encode_queue
      self.width = width
      self.height = height
      self.rtsp_url = rtsp_url
      self.running = True
      self.encode_channel = encode_channel

      # 启动 ffmpeg 子进程进行 RTSP 推流
      self.ffmpeg_process = subprocess.Popen(
          [
              'ffmpeg',
              '-f', 'h264',
              '-i', '-',  # 从 stdin 读取 H.264 数据
              '-c:v', 'copy',  # 直接复制 H.264 流
              '-f', 'rtsp',
              '-rtsp_transport', 'tcp',
              rtsp_url  # 目标 RTSP 地址
          ],
          stdin=subprocess.PIPE
      )

      # 初始化编码器
      self.encoder = srcampy.Encoder()
      self.encoder.encode(self.encode_channel, 1, self.width, self.height)

  def run(self):
      global is_stop
      start = time()
      count = 0
      while self.running or not self.encode_queue.empty():
          if is_stop and self.encode_queue.empty():
              break
          try:
              frame = self.encode_queue.get(timeout=0.5)
          except queue.Empty:
              continue
          try:
              yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420)
              h, w = frame.shape[:2]
              y = yuv[0:h, :]
              u = yuv[h:h + h // 4, :].reshape(h // 2, w // 2)
              v = yuv[h + h // 4:, :].reshape(h // 2, w // 2)
              uv = np.empty((h // 2, w), dtype=np.uint8)
              uv[:, 0::2] = u
              uv[:, 1::2] = v
              nv12 = np.vstack((y, uv))

              ret = self.encoder.encode_file(nv12.tobytes())
              if ret == 0:
                  out = self.encoder.get_img()
                  if out:
                      self.ffmpeg_process.stdin.write(out)
                      self.ffmpeg_process.stdin.flush()
                      count += 1
          except Exception as e:
              print("Encoder thread error:", e)

          if time() - start >= 5:
              print("Encode FPS:", count / 5)
              count = 0
              start = time()

  def stop(self):
      self.running = False
      self.join()
      self.encoder.close()
      self.ffmpeg_process.stdin.close()
      self.ffmpeg_process.terminate()
      try:
          self.ffmpeg_process.wait(timeout=2)
      except subprocess.TimeoutExpired:
          self.ffmpeg_process.kill()
      print("FFmpeg process terminated.")

if __name__ == '__main__':
  rtsp_url = "rtsp://admin:Xyh523523@192.168.30.64/102"
  is_stop = False
  signal.signal(signal.SIGINT, signal_handler)

  print(rtsp_url)

  vdec_chan = 0
  rtsp_stream = DecodeRtspStream(rtsp_url)
  ret = rtsp_stream.open(vdec_chan, 1)
  if ret != 0:
      quit(ret)
  rtsp_stream.start()

  # 创建多个 RtspYoloEncoder 实例
  rtsp_urls = [
      "rtsp://192.168.3.33:8554/test1",
      "rtsp://192.168.3.33:8554/test2",
      "rtsp://192.168.3.33:8554/test3",
      "rtsp://192.168.3.33:8554/test4",
      "rtsp://192.168.3.33:8554/test5",
      "rtsp://192.168.3.33:8554/test6",
      "rtsp://192.168.3.33:8554/test7",
      "rtsp://192.168.3.33:8554/test8",
      # "rtsp://192.168.3.33:8554/test9",
      # "rtsp://192.168.3.33:8554/test10",
      # "rtsp://192.168.3.33:8554/test11",
      # "rtsp://192.168.3.33:8554/test12",
      # "rtsp://192.168.3.33:8554/test13",
      # "rtsp://192.168.3.33:8554/test14",
      # "rtsp://192.168.3.33:8554/test15",
      # "rtsp://192.168.3.33:8554/test16"
  ]

  # 分配编码通道
  encoder_channels = [0]*8
  encoder_managers = [RtspYoloEncoder(rtsp_stream, url, channel) for url, channel in zip(rtsp_urls, encoder_channels)]

  for encoder in encoder_managers:
      encoder.start()

  while not is_stop:
      frame = rtsp_stream.get_frame()
      if frame is not None:
          bgr_frame = nv12_to_bgr(frame, rtsp_stream.width, rtsp_stream.height)
          detect_and_display(bgr_frame)
          for encoder in encoder_managers:
              encoder.enqueue(bgr_frame)
      else:
          sleep(0.01)

  for encoder in encoder_managers:
      encoder.stop()

您好,在X3,X5平台,USB摄像头会被抽象为/dev/video*的设备,而X3, X5的mipi摄像头和编解码器目前不支持v4l2框架,只能通过特定的接口来调用。同样的硬件编解码器也只能通过特定的接口来调用,不支持ffmpeg来调用。

多媒体接口(Python):

X3 & X5:RDK DOC

多媒体接口(C/C++, 简易好用的sp*接口):

X3 & X5:RDK DOC

ffmpeg默认CPU推流,与硬件编码器描述的0-31路无关。