使用 Source Reader 从网络摄像头源获取 H264 样本
Use Source Reader to get H264 samples from webcam source
当使用 Source Reader I can use it to get decoded YUV samples using an mp4 file source (example code).
如何使用网络摄像头源执行相反操作?使用 Source Reader 提供编码的 H264 样本?我的网络摄像头支持 RGB24 和 I420 像素格式,如果我手动连接 H264 MFT 转换,我可以获得 H264 样本。但似乎 Source Reader 应该能够为我处理转换。每当我尝试在 Source Reader.
上设置 MF_MT_SUBTYPE
of MFVideoFormat_H264
时,我都会收到错误消息
示例片段如下所示,完整示例为 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.
Source Reader does not look like suitable API here. It is API to implement "half of pipeline" which includes necessary decoding but not encoding. The other half is Sink Writer API 能够处理编码,并且可以编码 H.264。
或者你的另一个选择是 Media Session API,它实现了一个端到端的管道。
即使在技术上(理论上)您可以将编码 MFT 作为 Source Reader 管道的一部分,Source Reader API 本身不够灵活,无法添加编码样式转换基于请求的媒体类型。
因此,一种解决方案可能是让 Source Reader 通过必要的解码进行读取(例如最多具有 RGB32 或 NV12 视频帧),然后 Sink Writer 通过其上相应的适当媒体接收器来管理编码结束(或 Sample Grabber 作为媒体接收器)。另一种解决方案是将 Media Foundation 原语放入 Media Session 管道中,该管道可以管理连接在一起的解码和编码部分。
现在,您的用例更清晰了。
对我来说,您的 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协议。
编辑
No I'm not having synchronisation issues. The Source Reader and Sample Grabber both provide correct timestamps which I can use in the RTP header. Likewise no problems with RTP/UDP etc. that's the bit I do know about. My questions are originating from a desire to understand the most efficient (least amount of plumbing code) and flexible solution. And yes it does look like a custom sink writer is the optimal solution.
事情又清楚了。如果您需要有关自定义 RTP 接收器的帮助,我会在那里。
当使用 Source Reader I can use it to get decoded YUV samples using an mp4 file source (example code).
如何使用网络摄像头源执行相反操作?使用 Source Reader 提供编码的 H264 样本?我的网络摄像头支持 RGB24 和 I420 像素格式,如果我手动连接 H264 MFT 转换,我可以获得 H264 样本。但似乎 Source Reader 应该能够为我处理转换。每当我尝试在 Source Reader.
上设置MF_MT_SUBTYPE
of MFVideoFormat_H264
时,我都会收到错误消息
示例片段如下所示,完整示例为 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.
Source Reader does not look like suitable API here. It is API to implement "half of pipeline" which includes necessary decoding but not encoding. The other half is Sink Writer API 能够处理编码,并且可以编码 H.264。
或者你的另一个选择是 Media Session API,它实现了一个端到端的管道。
即使在技术上(理论上)您可以将编码 MFT 作为 Source Reader 管道的一部分,Source Reader API 本身不够灵活,无法添加编码样式转换基于请求的媒体类型。
因此,一种解决方案可能是让 Source Reader 通过必要的解码进行读取(例如最多具有 RGB32 或 NV12 视频帧),然后 Sink Writer 通过其上相应的适当媒体接收器来管理编码结束(或 Sample Grabber 作为媒体接收器)。另一种解决方案是将 Media Foundation 原语放入 Media Session 管道中,该管道可以管理连接在一起的解码和编码部分。
现在,您的用例更清晰了。
对我来说,您的 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协议。
编辑
No I'm not having synchronisation issues. The Source Reader and Sample Grabber both provide correct timestamps which I can use in the RTP header. Likewise no problems with RTP/UDP etc. that's the bit I do know about. My questions are originating from a desire to understand the most efficient (least amount of plumbing code) and flexible solution. And yes it does look like a custom sink writer is the optimal solution.
事情又清楚了。如果您需要有关自定义 RTP 接收器的帮助,我会在那里。