如何在媒体基础中有自定义视频媒体/流接收器请求 RGB32 帧?

Posted

技术标签:

【中文标题】如何在媒体基础中有自定义视频媒体/流接收器请求 RGB32 帧?【英文标题】:How to have custom video media/stream sink request RGB32 frames in media foundation? 【发布时间】:2018-09-06 07:06:15 【问题描述】:

我正在尝试为 OpenGL 应用程序中的视频播放制作一个自定义媒体接收器(没有各种 WGL_NV_DX_INTEROP,因为我不确定我的所有目标设备是否都支持这个)。

到目前为止,我所做的是编写一个自定义流接收器,它接受 RGB32 样本并使用媒体会话设置播放,但是我在播放 mp4 文件的初始测试时遇到了问题:

生成的拓扑中的一个(或多个)MFT不断失败,并出现错误代码MF_E_TRANSFORM_NEED_MORE_INPUT,因此我的流接收器从不接收样本 请求了几个样本后,媒体会话收到事件 MF_E_ATTRIBUTENOTFOUND,但我仍然不知道它来自哪里

但是,如果我将流接收器配置为接收 NV12 样本,那么一切似乎都可以正常工作。

我的最佳猜测是 TopologyLoader 生成的颜色转换器 MFT 需要更多配置,但考虑到我需要保持整个过程与原始文件类型无关,我不知道该怎么做。

【问题讨论】:

可以提供mp4文件吗?你能解释一下 TopologyLoader 是如何设置的吗? 对各种 mp4 文件有同样的效果。通过将 MediaSource 连接到 MediaSink 来设置拓扑,然后通过默认拓扑加载器进行解析 好的,你能用这个文件测试一下吗:big_buck_bunny_720p_50mb.mp4,所以我也可以测试一下吗? 我开始使用 SourceReader,因此无法再进行测试。但是我仍然有代码,我将在明天或后天测试。感谢您的回复! 【参考方案1】:

我制作了一个最小的测试用例,演示了自定义视频渲染器与经典媒体会话的使用。

我使用 big_buck_bunny_720p_50mb.mp4,使用 RGB32 格式没有发现任何问题。

此处的示例代码:https://github.com/mofo7777/*** 在 MinimalSinkRenderer 下。

编辑

您的程序适用于 big_buck_bunny_720p_50mb.mp4。我认为您的 mp4 文件是问题所在。如果可以,请分享。

我只是做了一些更改:

您在 MESessionEnded 上停止,并在 MESessionStopped 上关闭。

case MediaEventType.MESessionEnded:
    Debug.WriteLine("MediaSession:SesssionEndedEvent");
    hr = mediaSession.Stop();
    break;
case MediaEventType.MESessionClosed:
    Debug.WriteLine("MediaSession:SessionClosedEvent");
    receiveSessionEvent = false;
    break;
case MediaEventType.MESessionStopped:
    Debug.WriteLine("MediaSession:SesssionStoppedEvent");
    hr = mediaSession.Close();
    break;
default:
    Debug.WriteLine("MediaSession:Event: " + eventType);
    break;

添加这个等待声音,然后检查样本就可以了:

internal HResult ProcessSample(IMFSample s)

    //Debug.WriteLine("Received sample!");

    CurrentFrame++;

    if (s != null)
    
        long llSampleTime = 0;
        HResult hr = s.GetSampleTime(out llSampleTime);

        if (hr == HResult.S_OK && ((CurrentFrame % 50) == 0))
        
            TimeSpan ts = TimeSpan.FromMilliseconds(llSampleTime / (10000000 / 1000));
            Debug.WriteLine("Frame 0 : 1", CurrentFrame.ToString(), ts.ToString());
        

        // Do not call SafeRelease here, it is done by the caller, it is a parameter
        //SafeRelease(s);
    

    System.Threading.Thread.Sleep(26);

    return HResult.S_OK;

public HResult SetPresentationClock(IMFPresentationClock pPresentationClock)

添加

SafeRelease(PresentationClock);

之前

if (pPresentationClock != null)
    PresentationClock = pPresentationClock;

【讨论】:

嗨,很抱歉回复晚了,但我一直很忙。我一直在快速查看您的代码,并且在逻辑上似乎没有任何区别(我使用的是 C#)。我会尝试用你的作为 bse 重新实现我的 我尝试在 C# 中重现您的示例,但失败了。运行 MFTrace 我得到了我上次得到的确切错误 (MF_E_TRANSFORM_NEED_MORE_INPUT)。存储库可用here 您好,再次感谢您的帮助!我已经实现了你建议的 chagnes(除了示例中的那些,因为我只需要得到一个然后做一些详细说明),我没有任何运气。不幸的是,出于版权原因,我无法将文件发送给您,但我在各种视频上都注意到了同样的问题。我开始认为这可能与我的系统有关。我也没有你的 Big Buck Bunny 视频,你能分享一下吗,我可以用我的系统测试它吗? 很奇怪!使用该视频,它可以正常工作。我会尝试获取有关我要播放的视频的格式和编解码器的更准确信息,然后再与您联系。 我运行了 ffprobe,发现视频编解码器格式有一些非常细微的差异。仍然不知道为什么它可以与 SourceReader 一起正常工作...您可以检查 ffprobe 输出 here

以上是关于如何在媒体基础中有自定义视频媒体/流接收器请求 RGB32 帧?的主要内容,如果未能解决你的问题,请参考以下文章

媒体基础视频重新编码产生音频流同步偏移

在 Javascript 中监控 WebRTC 视频(媒体)流质量

切换音轨时是不是可以阻止 Chromecast 自定义媒体接收器发出许可请求?

使用 WebRTC 从网络摄像头捕获媒体流,将流发布到媒体服务器并从那里分发

如何在媒体播放器中播放流(破折号)视频

如何用VLC接收不同视频格式(H263、H264 CIF 4CIF)的组播媒体流