【问题标题】:Use Source Reader to get H264 samples from webcam source使用 Source Reader 从网络摄像头源获取 H264 样本
【发布时间】:2020-01-23 12:19:03
【问题描述】:

当使用Source Reader 时,我可以使用它来获取解码后的 YUV 样本,使用 mp4 文件源 (example code)。

如何使用网络摄像头源做相反的事情?使用 Source Reader 提供编码的 H264 样本?我的网络摄像头支持 RGB24 和 I420 像素格式,如果我手动连接 H264 MFT 变换,我可以获得 H264 样本。但似乎源阅读器应该能够为我处理转换。每当我尝试在 Source Reader 上设置 MF_MT_SUBTYPEMFVideoFormat_H264 时都会出错。

示例 sn-p 如下所示,完整示例为 here

  // Get the first available webcam.
  CHECK_HR(MFCreateAttributes(&videoConfig, 1), "Error creating video configuration.");

  // Request video capture devices.
  CHECK_HR(videoConfig->SetGUID(
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID), "Error initialising video configuration object.");

  CHECK_HR(videoConfig->SetGUID(MF_MT_SUBTYPE, WMMEDIASUBTYPE_I420),
    "Failed to set video sub type to I420.");

  CHECK_HR(MFEnumDeviceSources(videoConfig, &videoDevices, &videoDeviceCount), "Error enumerating video devices.");

  CHECK_HR(videoDevices[WEBCAM_DEVICE_INDEX]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &webcamFriendlyName, &nameLength),
    "Error retrieving video device friendly name.\n");

  wprintf(L"First available webcam: %s\n", webcamFriendlyName);

  CHECK_HR(videoDevices[WEBCAM_DEVICE_INDEX]->ActivateObject(IID_PPV_ARGS(&pVideoSource)), 
    "Error activating video device.");

  CHECK_HR(MFCreateAttributes(&pAttributes, 1),
    "Failed to create attributes.");

  // Adding this attribute creates a video source reader that will handle
  // colour conversion and avoid the need to manually convert between RGB24 and RGB32 etc.
  CHECK_HR(pAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, 1),
    "Failed to set enable video processing attribute.");

  CHECK_HR(pAttributes->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), "Failed to set major video type.");

  // Create a source reader.
  CHECK_HR(MFCreateSourceReaderFromMediaSource(
    pVideoSource,
    pAttributes,
    &pVideoReader), "Error creating video source reader.");

  MFCreateMediaType(&pSrcOutMediaType);
  CHECK_HR(pSrcOutMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), "Failed to set major video type.");
  CHECK_HR(pSrcOutMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264), "Error setting video sub type.");
  CHECK_HR(pSrcOutMediaType->SetUINT32(MF_MT_AVG_BITRATE, 240000), "Error setting average bit rate.");
  CHECK_HR(pSrcOutMediaType->SetUINT32(MF_MT_INTERLACE_MODE, 2), "Error setting interlace mode.");

  CHECK_HR(pVideoReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pSrcOutMediaType),
    "Failed to set media type on source reader.");

  CHECK_HR(pVideoReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pFirstOutputType),
    "Error retrieving current media type from first video stream.");

  std::cout << "Source reader output media type: " << GetMediaTypeDescription(pFirstOutputType) << std::endl << std::endl;

输出:

bind returned success
First available webcam: Logitech QuickCam Pro 9000
Failed to set media type on source reader. Error: C00D5212.
finished.

【问题讨论】:

    标签: c++ ms-media-foundation


    【解决方案1】:

    Source Reader 在这里看起来不像是合适的 API。它是实现“一半管道”的 API,其中包括必要的解码但不包括编码。另一半是Sink Writer API,可以处理编码,可以编码H.264。

    或者,除非您正在开发 UWP 项目,否则您的另一个选择是 Media Session API,它实现了端到端的管道。

    尽管从技术上(理论上)您可以将编码 MFT 作为 Source Reader 管道的一部分,但 Source Reader API 本身不够灵活,无法根据请求的媒体类型添加编码样式转换。

    因此,一种解决方案可能是让 Source Reader 通过必要的解码来读取(例如最多具有 RGB32 或 NV12 视频帧),然后 Sink Writer 在其末端使用相应的媒体接收器管理编码(或 Sample Grabber 作为媒体接收器)。另一种解决方案是将媒体基础原语放入媒体会话管道中,该管道可以管理解码和编码部分,连接在一起。

    【讨论】:

    • 在媒体会话中,通常会使用 Sample Grabber 来访问 IMFSample 的?对于 Sink Writer,我的理解是没有相当于 Source Reader 的东西吗?要访问原始示例,需要自定义 Sink Writer?
    • Source Reader 是从“某处”读取的,并且有一些视频和/或音频可用于编码。 Sink Writer 则相反:您有一些数据,并且如果需要,您可以通过编码将数据写入“其他地方”。通常,Sink Writer 的此类结果是文件或流协议,如果您想重新获得对生成数据的访问权限,则可以使用 Sample Grabbers 设置 Sink Writer。
    • 就像使用 DirectShow 一样,我个人从不使用采样采集器,因为自定义过滤器总是更灵活的选择。在 Media Foundation 中也是如此,自定义接收器总体上更加灵活。 Still Sample Grabber sink 确实有效,并且是一种更简单的输出方式。
    • 知道了,谢谢。 @mofo77 让我有些困惑,建议在此答案 stackoverflow.com/questions/59839187/… 中使用 Source Reader 替代 Sample Grabber。但我现在明白这仅对解码场景有意义。
    【解决方案2】:

    现在,您的用例更清晰了。

    对我来说,您的 MFWebCamRtp 是最佳优化方式:WebCam Source Reader -> Encoding -> RTP Streaming。

    但是您遇到了演示时钟问题、同步问题或不同步的音频视频问题。我说的对吗?

    所以您尝试了 Sample Grabber Sink,现在又尝试了 Source Reader,就像我向您建议的那样。当然,您可以认为 Media Session 将能够做得更好。 我想是的,但需要额外的工作。

    在你的情况下我会这样做:

    • 编写自定义 RTP 接收器
    • 使用网络摄像头源、h264 编码器、您的自定义 RTP 接收器创建拓扑
    • 将拓扑添加到 MediaSession
    • 使用MediaSession播放进程

    如果您想要网络流接收器示例,请参阅:MFSkJpegHttpStreamer

    这是旧的,但这是一个好的开始。这个程序也使用了winsock,就像你的一样。

    您应该知道 RTP 协议使用 UDP。一个解决同步问题的好方法……我猜这绝对是你的主要问题。

    我的想法。您正试图通过管理 MediaFoundation 的音频/视频同步来弥补 RTP 协议 (UDP) 的弱点。我认为这种方法只会失败。

    我认为你的主要问题是 RTP 协议。

    编辑

    不,我没有同步问题。 Source Reader 和 Sample Grabber 都提供了我可以在 RTP 标头中使用的正确时间戳。同样,RTP/UDP 等也没有问题,这就是我所知道的。我的问题源于希望了解最有效(最少的管道代码)和灵活的解决方案。是的,看起来自定义接收器编写器是最佳解决方案。

    事情再次变得清晰起来。如果您需要有关自定义 RTP 接收器的帮助,我会在那里。

    【讨论】:

    • 不,我没有同步问题。 Source Reader 和 Sample Grabber 都提供了我可以在 RTP 标头中使用的正确时间戳。同样,RTP/UDP 等也没有问题,这就是我所知道的。我的问题源于希望了解最有效(最少的管道代码)和灵活的解决方案。是的,看起来自定义接收器编写器是最佳解决方案。
    猜你喜欢
    • 2013-08-12
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多