Как добавить код из четырех символов «dmb1» в ffmpeg?

#ffmpeg #avfoundation #chromium #pixelformat #fourcc

Вопрос:

Я пытаюсь транслировать видео с веб — камеры на локальный компьютер. Поток имеет разрешение 3840×2160 и 30 кадров в секунду. Компьютер, которым я пользуюсь, — 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];  

Я попытался сделать то же самое в ffmpeg, изменив файл avfoundation.m. Сначала я добавил новый формат пикселей 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 amp;amp; __MAC_OS_X_VERSION_MIN_REQUIRED gt;= 1080  { AV_PIX_FMT_GRAY8, kCVPixelFormatType_OneComponent8 }, #endif  { AV_PIX_FMT_NONE, 0 } };  

After that I tried to hardcode it:

 pxl_fmt_spec = avf_pixel_formats[22];  ctx-gt;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-gt;video_output setVideoSettings:capture_dict];  

Code compiles and builds successfully, but when I run it with above command, without -pix_fmt specified, program enters infinite loop in get_video_config function:

 while (ctx-gt;frames_captured lt; 1) {  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);  }  

Очевидно, что ffmpeg не может загрузить первый кадр. Моя камера более чем способна поддерживать эти форматы пикселей и потоков. Я доказал это с помощью этого фрагмента кода, который появляется после того, как ffmpeg выбирает, какой формат использовать для указанной ширины, высоты и кадров в секунду:

 FourCharCode fcc = CMFormatDescriptionGetMediaSubType([selected_format formatDescription]);  char fcc_string[5] = { 0, 0, 0, 0, ''};   fcc_string[0] = (char) (fcc gt;gt; 24);  fcc_string[1] = (char) (fcc gt;gt; 16);  fcc_string[2] = (char) (fcc gt;gt; 8);  fcc_string[3] = (char) fcc;   av_log(s, AV_LOG_ERROR, "Selected format: %sn", fcc_string);  

Приведенный выше код выводит «Выбранный формат: dmb1».

Может кто-нибудь сказать мне, почему ffmpeg не может загрузить первый кадр и как добавить новый формат пикселей в эту библиотеку?

Кроме того, любое предложение о том, как разрешить задержку ввода в 3 секунды каким-либо другим способом, более чем приветствуется.

Редактировать:

Если вы попытаетесь установить любой другой формат пикселей в Chromium, отличный от MJPEG, задержка составит 2 секунды. Когда я говорю «настройка», я имею в виду изменение исходного кода Chromium и его перекомпиляцию. Я почти уверен, что проблема в формате пикселей, потому что камера отправляет dmb1, а ffmpeg не знает об этом формате.

Кроме того, задержка присутствует только в macOS.

Комментарии:

1. AFAIK для добавления нового формата пикселей в ffmpeg требуется отредактировать код ffmpeg и скомпилировать его

2. MJPEG-это кодек, а не пиксельный формат. Вы получаете задержку из-за длины GOP, т. е. интервала ключевых кадров. Добавьте -g X в свою команду и замените X небольшим целым числом. 1 для всего внутреннего потока до 15 0,5 секунды GOP.

3. @404pio Я знаю, что изменения, которые я внес, находятся в исходном коде ffmpeg. @Gyan Я запустил команду ffmpeg -f avfoundation -framerate 30 -video_size 3840x2160 -pix_fmt nv12 -probesize "50M" -i "0" -pix_fmt nv12 -preset ultrafast -vcodec libx264 -tune zerolatency -g 1 -f mpegts udp://192.168.1.5:5100/mystream , и задержка ввода все еще была там. Да, MJPEG-это кодек, но в Chromium он рассматривается как пиксельный формат.