1

我正在尝试将视频从网络摄像头传输到本地计算机。该流的分辨率为 3840x2160 和 30fps。我使用的计算机是 Mac Pro。但是,当我使用下一个命令运行它时:

ffmpeg -f avfoundation -framerate 30 -video_size 3840x2160 -pix_fmt nv12 -probesize "50M" -i "0" -pix_fmt nv12 -preset ultrafast -vcodec libx264 -tune zerolatency -f mpegts udp://192.168.1.5:5100/mystream

它的延迟为 3-4 秒。这个问题在 Chromium 中不存在,当使用 MediaStream API 流实时显示时。

我相信这是因为 Chromium 支持“dmb1”四个字符代码:

+ (media::VideoPixelFormat)FourCCToChromiumPixelFormat:(FourCharCode)code {
  switch (code) {
    case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
      return media::PIXEL_FORMAT_NV12;  // Mac fourcc: "420v".
    case kCVPixelFormatType_422YpCbCr8:
      return media::PIXEL_FORMAT_UYVY;  // Mac fourcc: "2vuy".
    case kCMPixelFormat_422YpCbCr8_yuvs:
      return media::PIXEL_FORMAT_YUY2;
    case kCMVideoCodecType_JPEG_OpenDML:
      return media::PIXEL_FORMAT_MJPEG;  // Mac fourcc: "dmb1".
    default:
      return media::PIXEL_FORMAT_UNKNOWN;
  }
}

要设置像素格式,Chromium 正在使用下一段代码:

NSDictionary* videoSettingsDictionary = @{
    (id)kCVPixelBufferWidthKey : @(width),
    (id)kCVPixelBufferHeightKey : @(height),
    (id)kCVPixelBufferPixelFormatTypeKey : @(best_fourcc),
    AVVideoScalingModeKey : AVVideoScalingModeResizeAspectFill
  };
  [_captureVideoDataOutput setVideoSettings:videoSettingsDictionary];

我尝试通过更改 avfoundation.m 文件在 ffmpeg 中做同样的事情。首先我添加了新的像素格式AV_PIX_FMT_MJPEG

static const struct AVFPixelFormatSpec avf_pixel_formats[] = {
    { AV_PIX_FMT_MONOBLACK,    kCVPixelFormatType_1Monochrome },
    { AV_PIX_FMT_RGB555BE,     kCVPixelFormatType_16BE555 },
    { AV_PIX_FMT_RGB555LE,     kCVPixelFormatType_16LE555 },
    { AV_PIX_FMT_RGB565BE,     kCVPixelFormatType_16BE565 },
    { AV_PIX_FMT_RGB565LE,     kCVPixelFormatType_16LE565 },
    { AV_PIX_FMT_RGB24,        kCVPixelFormatType_24RGB },
    { AV_PIX_FMT_BGR24,        kCVPixelFormatType_24BGR },
    { AV_PIX_FMT_0RGB,         kCVPixelFormatType_32ARGB },
    { AV_PIX_FMT_BGR0,         kCVPixelFormatType_32BGRA },
    { AV_PIX_FMT_0BGR,         kCVPixelFormatType_32ABGR },
    { AV_PIX_FMT_RGB0,         kCVPixelFormatType_32RGBA },
    { AV_PIX_FMT_BGR48BE,      kCVPixelFormatType_48RGB },
    { AV_PIX_FMT_UYVY422,      kCVPixelFormatType_422YpCbCr8 },
    { AV_PIX_FMT_YUVA444P,     kCVPixelFormatType_4444YpCbCrA8R },
    { AV_PIX_FMT_YUVA444P16LE, kCVPixelFormatType_4444AYpCbCr16 },
    { AV_PIX_FMT_YUV444P,      kCVPixelFormatType_444YpCbCr8 },
    { AV_PIX_FMT_YUV422P16,    kCVPixelFormatType_422YpCbCr16 },
    { AV_PIX_FMT_YUV422P10,    kCVPixelFormatType_422YpCbCr10 },
    { AV_PIX_FMT_YUV444P10,    kCVPixelFormatType_444YpCbCr10 },
    { AV_PIX_FMT_YUV420P,      kCVPixelFormatType_420YpCbCr8Planar },
    { AV_PIX_FMT_NV12,         kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange },
    { AV_PIX_FMT_YUYV422,      kCVPixelFormatType_422YpCbCr8_yuvs },
    { AV_PIX_FMT_MJPEG,        kCMVideoCodecType_JPEG_OpenDML }, //dmb1
#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
    { AV_PIX_FMT_GRAY8,        kCVPixelFormatType_OneComponent8 },
#endif
    { AV_PIX_FMT_NONE, 0 }
};

之后,我尝试对其进行硬编码:

        pxl_fmt_spec = avf_pixel_formats[22];
        ctx->pixel_format = pxl_fmt_spec.ff_id;

        pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id];

        capture_dict = [NSDictionary dictionaryWithObject:pixel_format
                                                   forKey:(id)kCVPixelBufferPixelFormatTypeKey];

        [ctx->video_output setVideoSettings:capture_dict];

代码编译成功,但是当我使用上面的命令运行它时,没有指定 -pix_fmt,程序在get_video_config函数中进入无限循环:

    while (ctx->frames_captured < 1) {
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
    }

很明显,ffmpeg 无法加载第一帧。我的相机完全能够支持这种像素和流格式。我用这段代码证明了这一点,这段代码在 ffmpeg 选择用于指定宽度、高度和 fps 的格式之后:

            FourCharCode fcc = CMFormatDescriptionGetMediaSubType([selected_format formatDescription]);
            char fcc_string[5] = { 0, 0, 0, 0, '\0'};

            fcc_string[0] = (char) (fcc >> 24);
            fcc_string[1] = (char) (fcc >> 16);
            fcc_string[2] = (char) (fcc >> 8);
            fcc_string[3] = (char) fcc;

            av_log(s, AV_LOG_ERROR, "Selected format: %s\n", fcc_string);

上面的代码打印“选定格式:dmb1”。

有人能告诉我为什么 ffmpeg 无法加载第一帧以及如何在这个库中添加新的像素格式吗?

此外,任何关于如何以其他方式解决 3 秒输入延迟的建议都非常受欢迎。

编辑:

如果您尝试在 Chromium 中设置除 MJPEG 之外的任何其他像素格式,则延迟为 2 秒。当我说“设置”时,我的意思是更改 Chromium 源代码并重新编译它。我很确定问题出在像素格式上,因为相机正在发送 dmb1 而 ffmpeg 不知道该格式。

此外,延迟仅存在于 MacOS 上。

4

0 回答 0