如何复制 IMFSample 对象

Posted

技术标签:

【中文标题】如何复制 IMFSample 对象【英文标题】:How to duplicate IMFSample object 【发布时间】:2016-07-13 14:42:46 【问题描述】:

我需要复制IMFSample 对象,以便拥有单独的独立对象。 Microsoft API 不提供复制IMFSample 视频帧的简便方法。

【问题讨论】:

【参考方案1】:

这是一个示例代码:

#define MmfThrowIfError(hrVal) \
 \
    HRESULT hrMmfTraceInternal = (hrVal); \
    if (FAILED(hrMmfTraceInternal)) \
     \
        /* LOG_F(LS_ERROR)<<"MMF hr: 0x"<<std::hex<<hrMmfTraceInternal; */ \
        throw ref new ::Platform::Exception(hrMmfTraceInternal); \
     \


MFComPtr<IMFMediaBuffer> DuplicateBuffer(const MFComPtr<IMFMediaBuffer>& srcBuf)

    byte* srcByteBuffer = nullptr;
    DWORD srcBuffMaxLen = 0;
    DWORD srcBuffCurrLen = 0;
    MmfThrowIfError(srcBuf->Lock(&srcByteBuffer, &srcBuffMaxLen, &srcBuffCurrLen));

    MFComPtr<IMFMediaBuffer> destBuf = nullptr;
    MmfThrowIfError(MFCreateMemoryBuffer(srcBuffCurrLen, &destBuf));

    byte* destByteBuffer = nullptr;
    MmfThrowIfError(destBuf->Lock(&destByteBuffer, nullptr, nullptr));
    memcpy(destByteBuffer, srcByteBuffer, srcBuffCurrLen);
    MmfThrowIfError(destBuf->Unlock());
    MmfThrowIfError(srcBuf->Unlock());

    MmfThrowIfError(destBuf->SetCurrentLength(srcBuffCurrLen));
    return destBuf;


SampleComPtr DuplicateSample(const SampleComPtr& sample)

    if (!sample)
        return nullptr;

    DWORD sampleFlags = 0;
    LONGLONG llVideoTimeStamp = 0;
    LONGLONG llSampleDuration = 0;
    MmfThrowIfError(sample->GetSampleFlags(&sampleFlags));
    MmfThrowIfError(sample->GetSampleTime(&llVideoTimeStamp));
    MmfThrowIfError(sample->GetSampleDuration(&llSampleDuration));

    SampleComPtr outSample;
    MFCreateSample(&outSample);
    MmfThrowIfError(outSample->SetSampleFlags(sampleFlags));
    MmfThrowIfError(outSample->SetSampleTime(llVideoTimeStamp));
    MmfThrowIfError(outSample->SetSampleDuration(llSampleDuration));

    DWORD bufferCount = 0;
    MmfThrowIfError(sample->GetBufferCount(&bufferCount));

    for (DWORD index = 0; index < bufferCount; ++index)
    
        MFComPtr<IMFMediaBuffer> srcBuf = nullptr;
        MmfThrowIfError(sample->GetBufferByIndex(index, &srcBuf));

        MFComPtr<IMFMediaBuffer> reConstructedBuffer = DuplicateBuffer(srcBuf);
        srcBuf = nullptr;
        MmfThrowIfError(outSample->AddBuffer(reConstructedBuffer.Get()));
    

    return outSample;

【讨论】:

这适用于大多数情况,但不是准确的副本。副本总是一个简单的样本,而原始样本可能有 Direct3D 纹理等支持。 “不准确”是什么意思?丢失了哪些样本方面? (除了缓冲区大小减少到它们的实际(非最大)大小)。 “准确”是指精确复制,它复制了所有功能。我在上面举了一个例子。此外,这正是示例复制 API 不存在的原因:Media Foundation 根本无法生成精确的副本,因为通常示例是特定于实现的,即使遵循通用接口集。

以上是关于如何复制 IMFSample 对象的主要内容,如果未能解决你的问题,请参考以下文章

如何将 IMFSample 发送到 EVR 媒体接收器

如何从 H.264 NV12 IMFSample 输出渲染到 DirectX11 纹理?

处理来自 IMFSourceReader 和 IMFSample 的图像数据

有没有更快的方法从 IMFSample 读取样本?

如何为 WindowsMediaFoundation H.264 编码器 MFT 创建 IMFSample

如何将月份值从一个 Date 对象复制到另一个对象? [复制]