4

メディア ファンデーション アプリケーションでフレーム レート コンバーター DSPを使用したいと考えています。「SourceReader」を使用してビデオ ファイルを読み取ります。DMO を MF と統合してフレームレート変換を行う場所と方法を教えてください。新しいフレーム レートを取得するために DMO にフィードするサンプル (圧縮/非圧縮) の種類を理解していないようです。DMO はフレーム レートをどのように変更しますか? 新しいサンプルに新しいタイムスタンプを付与しますか? その使用法を示すコード例はありません。助けてください、私は立ち往生しています。

ありがとう、モッツ

4

1 に答える 1

0

それは古い質問です。

SourceReader でフレーム レート変換を行うには、DMO を手動で統合する必要があります。

アイデアは、SourceReader から互換性のあるサンプルを取得することです。たとえば、DMO によって処理されるビデオ サブタイプです。

DMO はどのようにフレーム レートを変更しますか?

フレーム レート コンバーター DSP によると、次のようになります。

この DSP は、フレームの繰り返しまたはドロップによってフレーム レートを変更します。

.

新しいサンプルに新しいタイムスタンプを付与しますか?

DMO は、サンプル時間とサンプル期間を変更します。ただし、ビデオ ファイルの長さが 1 分間の場合、最後は同じままです。

たとえば、ビデオ ファイルに 1800 フレームがあり、期間が 1 分間、フレーム レートが 30 フレーム/秒の場合。60 フレーム/秒が必要なので、3600 フレームになり、期間は変わりません (常に 1 分)。

#pragma once
#define WIN32_LEAN_AND_MEAN
#define STRICT

#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "wmcodecdspuuid")

#include <WinSDKVer.h>
#include <new>
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <mferror.h>
#include <Wmcodecdsp.h>

template <class T> inline void SAFE_RELEASE(T*& p){

    if(p){
        p->Release();
        p = NULL;
    }
}

HRESULT ProcessConverter();
HRESULT InitDMO(IMFTransform**, IMFMediaType*);
HRESULT ProcessSample(IMFSourceReader*, IMFTransform*);
HRESULT ProcessDMO(IMFTransform*, IMFSample*, DWORD&, const UINT32);
HRESULT InitOutputDataBuffer(IMFTransform*, MFT_OUTPUT_DATA_BUFFER*, const UINT32);

void main(){

    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    if(SUCCEEDED(hr)){

        hr = MFStartup(MF_VERSION, MFSTARTUP_LITE);

        if(SUCCEEDED(hr)){

            hr = ProcessConverter();

            hr = MFShutdown();
        }

        CoUninitialize();
    }
}

HRESULT ProcessConverter(){

    HRESULT hr;
    IMFSourceReader* pReader = NULL;

    // Change the URL
    if(FAILED(hr = MFCreateSourceReaderFromURL(L"Wildlife.wmv", NULL, &pReader))){
        return hr;
    }

    DWORD dwMediaTypeIndex = 0;
    IMFMediaType* pType = NULL;

    hr = pReader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, dwMediaTypeIndex, &pType);

    if(SUCCEEDED(hr)){

        // We must ask for a subtype compatible with DMO :
        // ARGB32 RGB24 RGB32 RGB555 RGB565 AYUV IYUV UYVY Y211 Y411 Y41P YUY2 YUYV YV12 YVYU
        hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12);

        if(SUCCEEDED(hr)){
          hr = pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pType);
        }

        // We need this because we use the MediaType to initialize the Transform
        if(SUCCEEDED(hr)){
          SAFE_RELEASE(pType);
          hr = pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pType);
        }

        if(SUCCEEDED(hr)){

            IMFTransform* pTransform = NULL;
            hr = InitDMO(&pTransform, pType);

            if(SUCCEEDED(hr)){

                hr = ProcessSample(pReader, pTransform);

                // Seems not really needed with the DMO
                /*hr = */ pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL);
                /*hr = */ pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, NULL);
                /*hr = */ pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, NULL);
            }

            SAFE_RELEASE(pTransform);
        }
    }

    SAFE_RELEASE(pType);
    SAFE_RELEASE(pReader);

    return hr;
}

HRESULT InitDMO(IMFTransform** ppTransform, IMFMediaType* pType){

    HRESULT hr = CoCreateInstance(CLSID_CFrameRateConvertDmo, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, reinterpret_cast<void**>(ppTransform));

    if(SUCCEEDED(hr)){
        hr = (*ppTransform)->SetInputType(0, pType, 0);
    }

    if(SUCCEEDED(hr)){
        // Change the frame rate as needed, here num = 60000 and den = 1001
        hr = MFSetAttributeRatio(pType, MF_MT_FRAME_RATE, 60000, 1001);
    }

    if(SUCCEEDED(hr)){
        hr = (*ppTransform)->SetOutputType(0, pType, 0);
    }

    if(SUCCEEDED(hr)){
        hr = (*ppTransform)->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
    }

    if(SUCCEEDED(hr)){
        hr = (*ppTransform)->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL);
    }

    return hr;
}

HRESULT ProcessSample(IMFSourceReader* pReader, IMFTransform* pTransform){

    HRESULT hr;
    IMFMediaType* pType = NULL;

    if(FAILED(hr = pTransform->GetOutputCurrentType(0, &pType))){
        return hr;
    }

    // We need the frame size to create the sample buffer.
    UINT32 uiFrameSize = 0;
    hr = pType->GetUINT32(MF_MT_SAMPLE_SIZE, &uiFrameSize);

    SAFE_RELEASE(pType);

    if(FAILED(hr) || uiFrameSize == 0){
        return hr;
    }

    BOOL bProcess = TRUE;
    DWORD streamIndex;
    DWORD flags;
    LONGLONG llTimeStamp;
    IMFSample* pSample = NULL;
    DWORD dwReaderCount = 0;
    DWORD dwDMOCount = 0;

    while(bProcess){

        hr = pReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &streamIndex, &flags, &llTimeStamp, &pSample);

        if(FAILED(hr) || flags != 0){
            bProcess = FALSE;
        }
        else{

            hr = ProcessDMO(pTransform, pSample, dwDMOCount, uiFrameSize);

            // You can check timestamp from the SourceReader
            //hr = pSample->GetSampleDuration(&llTimeStamp);
            //hr = pSample->GetSampleTime(&llTimeStamp);

            SAFE_RELEASE(pSample);
            dwReaderCount++;
        }
    }

    // Todo : check dwReaderCount and dwDMOCount here.
    // For example with native frame rate = 30000/1001 and dwReaderCount = 900
    // DMO frame rate = 30000/1001 -> dwReaderCount = 900
    // DMO frame rate = 60000/1001 -> dwReaderCount = 1800
    // DMO frame rate = 25/1 -> dwReaderCount = 750

    SAFE_RELEASE(pSample);

    return hr;
}

HRESULT ProcessDMO(IMFTransform* pTransform, IMFSample* pSample, DWORD& dwDMOCount, const UINT32 uiFrameSize){

    HRESULT hr = S_OK;

    MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
    DWORD processOutputStatus = 0;

    // Todo : we should avoid recreating the buffer...
    hr = InitOutputDataBuffer(pTransform, &outputDataBuffer, uiFrameSize);

    while(hr == S_OK){

        hr = pTransform->ProcessOutput(0, 1, &outputDataBuffer, &processOutputStatus);

        if(hr == MF_E_TRANSFORM_NEED_MORE_INPUT){
            break;
        }

        // You can check new timestamp from the DMO
        /*if(outputDataBuffer.pSample != NULL){

            LONGLONG llTimeStamp = 0;
            hr = outputDataBuffer.pSample->GetSampleTime(&llTimeStamp);
            hr = outputDataBuffer.pSample->GetSampleDuration(&llTimeStamp);
        }*/

        dwDMOCount++;
    }

    if(hr == MF_E_TRANSFORM_NEED_MORE_INPUT){
        hr = pTransform->ProcessInput(0, pSample, 0);
    }

    if(outputDataBuffer.pSample != NULL){
        SAFE_RELEASE(outputDataBuffer.pSample);
    }

    return hr;
}

HRESULT InitOutputDataBuffer(IMFTransform* pMFTransform, MFT_OUTPUT_DATA_BUFFER* pOutputBuffer, const UINT32 uiFrameSize){

    MFT_OUTPUT_STREAM_INFO outputStreamInfo;
    DWORD outputStreamId = 0;

    ZeroMemory(&outputStreamInfo, sizeof(outputStreamInfo));
    ZeroMemory(pOutputBuffer, sizeof(*pOutputBuffer));

    HRESULT hr = pMFTransform->GetOutputStreamInfo(outputStreamId, &outputStreamInfo);

    if(SUCCEEDED(hr)){

        if((outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) == 0 &&
            (outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) == 0){

            IMFSample* pOutputSample = NULL;
            IMFMediaBuffer* pMediaBuffer = NULL;

            hr = MFCreateSample(&pOutputSample);

            if(SUCCEEDED(hr)){
                hr = MFCreateMemoryBuffer(uiFrameSize, &pMediaBuffer);
            }

            if(SUCCEEDED(hr)){
                hr = pOutputSample->AddBuffer(pMediaBuffer);
            }

            if(SUCCEEDED(hr)){
                pOutputBuffer->pSample = pOutputSample;
                pOutputBuffer->pSample->AddRef();
            }

            SAFE_RELEASE(pMediaBuffer);
            SAFE_RELEASE(pOutputSample);
        }
    }

    return hr;
}
于 2015-12-02T16:01:48.673 に答える