如何让 Microsoft MPEG4 Source 打开比特率高于 4Gbps 的 MOV

Posted

技术标签:

【中文标题】如何让 Microsoft MPEG4 Source 打开比特率高于 4Gbps 的 MOV【英文标题】:How to get Microsoft MPEG4 Source to open MOV with bitrate higher than 4Gbps 【发布时间】:2020-09-03 23:21:36 【问题描述】:

似乎当 MOV 的比特率太高且无法适应 32 位时,Microsoft MPEG 4 Source 将无法解析它。有谁知道这种行为的解决方法?

我很确定它与比特率有关,因为我已经生成了测试文件,并且通过仅调整帧速率我生成了两个文件 - 一个比特率超过 4.2Gbps(32 位)的文件无法打开,但是另一个比特率低于 4.2Gps 的打开文件。

我尝试使用 IMFSourceReader 打开文件:

            IMFSourceReader* reader = nullptr;
            hr = MFCreateSourceReaderFromURL(L"input.mov", nullptr, &reader);
            SAFE_RELEASE(reader);

但这只是返回 E_FAIL。

我尝试通过 IMFSourceResolver 打开它:

        IMFMediaSource* source = nullptr;

        IMFSourceResolver* resolver = nullptr;
        MFCreateSourceResolver(&resolver);

        MF_OBJECT_TYPE objectType;
        IUnknown* result = nullptr;
        hr = resolver->CreateObjectFromURL(L"input.mov", MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | MF_RESOLUTION_READ, nullptr, &objectType, &result);

这也失败了。

为了重现这一点,我上传了一个小的400KB ZIP,其中包含:

    3000x3000 源图片 .bat ffmpeg 命令生成视频 一个 3000x3000 @ 59fps HapQ MOV 文件 - MPEG4 源可以解决这个问题,比特率低于 4.2Gbps 3000x3000 @ 60fps HapQ MOV 文件 - MPEG4 源无法解决此问题,比特率仅为 4.2Gbps

这里生成的视频供参考:

ffmpeg -y -loop 1 -i black3000.png -t 0.2 -r 59 -s 3000x3000 -c:v hap -format hap_q -compressor none output-good.mov
ffmpeg -y -loop 1 -i black3000.png -t 0.2 -r 60 -s 3000x3000 -c:v hap -format hap_q -compressor none output-bad.mov
pause

之前有没有其他人看到过这种行为并知道解决方法?

谢谢,

【问题讨论】:

如果您激活 MF 跟踪,您将看到 MF 尝试它拥有的所有字节流处理程序 (IMFByteStreamHandler) 以及所有(在我的 PC 上,即 MPEG4、ADTS、AC-3、MF AMRNB、ASF、 AVI、WTV、MF FLAC、MPEG2、MKV、MP3、NSC、SAMI、WAV、LPCM) 报告 MF_E_INVALID_FILE_FORMAT 错误。因此,没有字节流处理程序支持该流。要解决此问题,您可以尝试添加自己的 MFRegisterLocalByteStreamHandler。 是的,我一直在使用 MFTrace - 对于良好的流,它能够找到处理程序 - MPEG 4 源。对于坏流(比特率太高),它确实失败了。 实际上,MF_MT_AVG_BITRATE 是一个 UINT32 docs.microsoft.com/en-us/windows/win32/medfound/…,在好的情况下,您可以清楚地看到 MPEG4 添加了“MF_MT_AVG_BITRATE=4235297882”。所以我猜,MPEG4 处理程序计算这个并且可能溢出。 MF_MT_AVG_BITRATE 更像是一个输出的东西,不确定它在做什么。你可以尝试用你自己的包装它并使用 MFRegisterLocalByteStreamHandler 注册它。 哦,我明白你的意思了 - 好的,我会尝试并更新如果它有效。 (顺便说一句,您的幻数数据库很棒,我已经多次使用它来查找晦涩的 GUIDS)。 谢谢 :-) 对所有 MF 的指导特别有用!例如,CLSID_MPEG4ByteStreamPlugin,它是 MPEG4 字节流处理程序。 【参考方案1】:

看起来就像@Simon Mourier 建议的那样,解决这个问题的唯一方法是实现自定义ByteStreamHandler 并将其注册到MFRegisterLocalByteStreamHandler,但您还必须创建自定义IMFMediaSource,因为我找不到任何方法简单地实例化 MPEG4 源,因为您似乎只能通过它的 ByteStreamHandler 来创建它。

作为参考,这是我用来手动创建 MPEG4 源而不使用 Source Resolver 的伪测试代码:

#include <initguid.h>
DEFINE_GUID(CLSID_MPEG4ByteStreamPlugin, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);


class CallbackTest : public IMFAsyncCallback

public:
    CallbackTest(IMFByteStreamHandler* handler)
    
        _handler = handler;
    

    IMFByteStreamHandler* _handler;

    virtual HRESULT QueryInterface(REFIID riid, void ** ppvObject) override
    
        return HRESULT();
    
    virtual ULONG AddRef(void) override
    
        return 1;
    
    virtual ULONG Release(void) override
    
        return 1;
    
    virtual HRESULT GetParameters(DWORD * pdwFlags, DWORD * pdwQueue) override
    
        return E_NOTIMPL;
    
    virtual HRESULT __stdcall Invoke(IMFAsyncResult * pAsyncResult) override
    
        // At this point HR = E_FAIL for > 4.2Gbps MOV
        HRESULT hr = pAsyncResult->GetStatus();

        MF_OBJECT_TYPE objectType;
        IUnknown* unknownObject = nullptr;
        hr = _handler->EndCreateObject(pAsyncResult, &objectType, &unknownObject);

// NOTE: I also tried to just force creating the MPEG 4 Source by calling
// EndCreateObject with a dummy IMFAsyncResult but that always failed..

        IMFMediaSource* mediaSource = nullptr;
        hr = unknownObject->QueryInterface(&mediaSource);

        return S_OK;
    
;

void Test()

    HRESULT hr;

    // Create a bytestream from the file
    IMFByteStream* byteStream = nullptr;
    hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NOBUFFERING, fileUrl, &byteStream);

// Create the MPEG4 ByteStreamHandler
    IMFByteStreamHandler* handler = nullptr;
    hr = CoCreateInstance(CLSID_MPEG4ByteStreamPlugin, nullptr, CLSCTX_ALL, IID_IMFByteStreamHandler, (void**)&handler);
    
    IMFAsyncCallback* callback = new CallbackTest(handler);
    hr = handler->BeginCreateObject(byteStream, nullptr, MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_READ | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, nullptr, nullptr, callback, handler);

【讨论】:

以上是关于如何让 Microsoft MPEG4 Source 打开比特率高于 4Gbps 的 MOV的主要内容,如果未能解决你的问题,请参考以下文章

如何附加到录制的 MPEG4 AAC 文件?

怎么让 html5 的 video标签在 ios播放

如何查看视频文件是不是是mpeg4的,还是h264的?

如何编程实现视频转码? 用C/C++实现将MPEG4标准的视频转化为H.264标准的视频

视频编码:MPEG4(Xvid),MPEG4(DivX) 和 AVC(H264) 这三个都是啥意思?

视频编码:MPEG4(Xvid),MPEG4(DivX) 和 AVC(H264) 这三个都是啥意思?