如何获得Microsoft MPEG4源来以高于4Gbps的比特率打开MOV

问题描述

似乎当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,&objectType,&result);

这也失败了。

为重现此内容,我上传一个小的400KB ZIP,其中包含:

  1. 3000x3000源图像
  2. .bat ffmpeg命令生成视频
  3. 3000x3000 @ 59fps的HapQ MOV文件-MPEG4源可以解决此问题,比特率仅低于4.2Gbps
  4. 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

有没有其他人以前见过这种行为,并且知道解决方法

谢谢

解决方法

就像@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,MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_READ | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE,callback,handler);
}