123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- #include "MFTDecoder.h"
- #include <Mfapi.h>
- #include <wmcodecdsp.h>
- #include <Mferror.h>
- //-----------------------------------------------------------------------------
- // GetDefaultStride
- //
- // Gets the default stride for a video frame, assuming no extra padding bytes.
- //
- //-----------------------------------------------------------------------------
- HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride)
- {
- LONG lStride = 0;
- // Try to get the default stride from the media type.
- HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
- if (FAILED(hr))
- {
- // Attribute not set. Try to calculate the default stride.
- GUID subtype = GUID_NULL;
- UINT32 width = 0;
- UINT32 height = 0;
- // Get the subtype and the image size.
- hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
- if (SUCCEEDED(hr))
- {
- hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lStride);
- }
- // Set the attribute for later reference.
- if (SUCCEEDED(hr))
- {
- (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride));
- }
- }
- if (SUCCEEDED(hr))
- {
- *plStride = lStride;
- }
- return hr;
- }
- MFTDecoder::MFTDecoder()
- {
- decoder = 0;
- stride = 0;
- width = 0;
- height = 0;
- }
- MFTDecoder::~MFTDecoder()
- {
- if (decoder) {
- decoder->Release();
- }
- }
- static HRESULT CreateInputMediaType(IMFMediaType **_media_type)
- {
- HRESULT hr=E_FAIL;
- IMFMediaType *media_type=0;
- do {
- hr = MFCreateMediaType(&media_type);
- if (FAILED(hr)) {
- break;
- }
- hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
- if (FAILED(hr)) {
- break;
- }
- hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
- if (FAILED(hr)) {
- break;
- }
- *_media_type = media_type;
- return S_OK;
- } while(0);
- if (media_type) {
- media_type->Release();
- }
- return hr;
- }
- HRESULT MFTDecoder::Open()
- {
- HRESULT hr=E_FAIL;
- hr = CoCreateInstance(CLSID_CMSH264DecoderMFT, NULL, CLSCTX_INPROC_SERVER, __uuidof(IMFTransform), (void**)&decoder);
- if (FAILED(hr)) {
- return hr;
- }
- /* set input */
- IMFMediaType *media_type=0;
- hr = CreateInputMediaType(&media_type);
- if (FAILED(hr)) {
- return hr;
- }
- hr = decoder->SetInputType(0, media_type, 0);
- media_type->Release();
- if (FAILED(hr)) {
- return hr;
- }
- /* set output */
- hr = decoder->GetOutputAvailableType(0, 0, &media_type);
- if (FAILED(hr)) {
- return hr;
- }
- hr = decoder->SetOutputType(0, media_type, 0);
- media_type->Release();
- if (FAILED(hr)) {
- return hr;
- }
- decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
- decoder->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
- return S_OK;
- }
- MFOffset MFTDecoder::MakeOffset(float v)
- {
- MFOffset offset{};
- offset.value = short(v);
- offset.fract = WORD(65536 * (v - offset.value));
- return offset;
- }
- MFVideoArea MFTDecoder::MakeArea(float x, float y, DWORD width, DWORD height)
- {
- MFVideoArea area{};
- area.OffsetX = MakeOffset(x);
- area.OffsetY = MakeOffset(y);
- area.Area.cx = width;
- area.Area.cy = height;
- return area;
- }
- HRESULT MFTDecoder::GetVideoDisplayArea(IMFMediaType* pType, MFVideoArea* pArea)
- {
- HRESULT hr = S_OK;
- BOOL bPanScan = FALSE;
- UINT32 width = 0, height = 0;
- bPanScan = MFGetAttributeUINT32(pType, MF_MT_PAN_SCAN_ENABLED, FALSE);
- // In pan-and-scan mode, try to get the pan-and-scan region.
- if (bPanScan)
- {
- hr = pType->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)pArea,
- sizeof(MFVideoArea), NULL);
- }
- // If not in pan-and-scan mode, or the pan-and-scan region is not set,
- // get the minimimum display aperture.
- if (!bPanScan || hr == MF_E_ATTRIBUTENOTFOUND)
- {
- hr = pType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)pArea,
- sizeof(MFVideoArea), NULL);
- if (hr == MF_E_ATTRIBUTENOTFOUND)
- {
- // Minimum display aperture is not set.
- // For backward compatibility with some components,
- // check for a geometric aperture.
- hr = pType->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)pArea,
- sizeof(MFVideoArea), NULL);
- }
- // Default: Use the entire video area.
- if (hr == MF_E_ATTRIBUTENOTFOUND)
- {
- hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
- if (SUCCEEDED(hr))
- {
- *pArea = MakeArea(0.0, 0.0, width, height);
- }
- }
- }
- return hr;
- }
- HRESULT MFTDecoder::GetOutputFormat(UINT *width, UINT *height, bool *flip, double *aspect)
- {
- HRESULT hr=E_FAIL;
- IMFMediaType *media_type = 0;
- MFVideoArea pArea;
- do {
- hr = decoder->GetOutputCurrentType(0, &media_type);
- if (FAILED(hr)) {
- break;
- }
- //if (width && height) {
- // hr = MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, width, height);
- // if (FAILED(hr)) {
- // break;
- // }
- //}
- if (width && height) {
- hr = GetVideoDisplayArea(media_type, &pArea);
- if (FAILED(hr)) {
- break;
- }
- *width = pArea.Area.cx;
- *height = pArea.Area.cy;
- }
- if (flip) {
- LONG stride;
- hr = GetDefaultStride(media_type, &stride);
- if (FAILED(hr)) {
- break;
- }
- *flip = stride<0;
- }
- if (aspect) {
- MFRatio PAR = {0};
- hr = MFGetAttributeRatio(media_type, MF_MT_PIXEL_ASPECT_RATIO,
- (UINT32*)&PAR.Numerator,
- (UINT32*)&PAR.Denominator);
- if (FAILED(hr)) {
- *aspect = 1.0;
- } else {
- *aspect = (double)PAR.Numerator / (double)PAR.Denominator;
- }
- }
- } while(0);
- if (media_type) {
- media_type->Release();
- }
- return hr;
- }
- static HRESULT ConfigureOutput(IMFTransform *decoder, LONG *stride)
- {
- HRESULT hr = S_OK;
- IMFMediaType *media_type = 0;
- AM_MEDIA_TYPE *format = NULL;
- int index=0;
- while(SUCCEEDED(hr)) {
- hr = decoder->GetOutputAvailableType(0, index++, &media_type);
- if (FAILED(hr)) {
- break;
- }
- media_type->GetRepresentation(FORMAT_MFVideoFormat, (LPVOID*)&format);
- MFVIDEOFORMAT* z = (MFVIDEOFORMAT*)format->pbFormat;
- unsigned int surface_format = z->surfaceInfo.Format;
- media_type->FreeRepresentation(FORMAT_MFVideoFormat, (LPVOID)format);
- if (surface_format == '21VY') { // MFVideoFormat_YV12
- hr = GetDefaultStride(media_type, stride);
- hr = decoder->SetOutputType(0, media_type, 0);
- break;
- }
- }
- if(media_type) {
- media_type->Release();
- }
- return hr;
- }
- HRESULT MFTDecoder::Feed(const void *data, size_t data_size, uint64_t timestamp_hundred_nanos)
- {
- HRESULT hr=E_FAIL;
- const BYTE start_code[] = {0, 0, 0, 1};
- IMFMediaBuffer *buffer = 0;
- BYTE *buffer_pointer = 0;
- IMFSample *sample = 0;
- do {
- hr = MFCreateMemoryBuffer((DWORD)data_size+4, &buffer);
- if (FAILED(hr)) {
- break;
- }
- hr = buffer->Lock(&buffer_pointer, NULL, NULL);
- if (FAILED(hr)) {
- break;
- }
- memcpy(buffer_pointer, start_code, 4);
- memcpy(buffer_pointer+4, data, data_size);
- hr = buffer->Unlock();
- if (FAILED(hr)) {
- break;
- }
- hr = buffer->SetCurrentLength((DWORD)data_size+4);
- if (FAILED(hr)) {
- break;
- }
- hr = MFCreateSample(&sample);
- if (FAILED(hr)) {
- break;
- }
- hr = sample->AddBuffer(buffer);
- if (FAILED(hr)) {
- break;
- }
- hr = sample->SetSampleTime(timestamp_hundred_nanos);
- if (FAILED(hr)) {
- break;
- }
- hr = decoder->ProcessInput(0, sample, 0);
- if (FAILED(hr)) {
- break;
- }
- } while(0);
- if (buffer) {
- buffer->Release();
- }
- if (sample) {
- sample->Release();
- }
- return hr;
- }
- HRESULT MFTDecoder::FeedRaw(const void *data, size_t data_size, uint64_t timestamp_hundred_nanos)
- {
- HRESULT hr=E_FAIL;
- IMFMediaBuffer *buffer = 0;
- BYTE *buffer_pointer = 0;
- IMFSample *sample = 0;
- do {
- hr = MFCreateMemoryBuffer((DWORD)data_size, &buffer);
- if (FAILED(hr)) {
- break;
- }
- hr = buffer->Lock(&buffer_pointer, NULL, NULL);
- if (FAILED(hr)) {
- break;
- }
- memcpy(buffer_pointer, data, data_size);
- hr = buffer->Unlock();
- if (FAILED(hr)) {
- break;
- }
- hr = buffer->SetCurrentLength((DWORD)data_size);
- if (FAILED(hr)) {
- break;
- }
- hr = MFCreateSample(&sample);
- if (FAILED(hr)) {
- break;
- }
- hr = sample->AddBuffer(buffer);
- if (FAILED(hr)) {
- break;
- }
- hr = sample->SetSampleTime(timestamp_hundred_nanos);
- if (FAILED(hr)) {
- break;
- }
- hr = decoder->ProcessInput(0, sample, 0);
- if (FAILED(hr)) {
- break;
- }
- } while(0);
- if (buffer) {
- buffer->Release();
- }
- if (sample) {
- sample->Release();
- }
- return hr;
- }
- static HRESULT CreateOutputSample(IMFTransform *decoder, IMFSample **_output_sample)
- {
- HRESULT hr=E_FAIL;
- MFT_OUTPUT_STREAM_INFO stream_info;
- IMFMediaBuffer *media_buffer = 0;
- IMFSample *sample = 0;
- do {
- hr = MFCreateSample(&sample);
- if (FAILED(hr)) {
- break;
- }
- hr = decoder->GetOutputStreamInfo(0, &stream_info);
- if (FAILED(hr)) {
- break;
- }
- hr = MFCreateAlignedMemoryBuffer(stream_info.cbSize, MF_16_BYTE_ALIGNMENT, &media_buffer);
- if (FAILED(hr)) {
- break;
- }
- hr = sample->AddBuffer(media_buffer);
- if (FAILED(hr)) {
- break;
- }
- if (media_buffer) {
- media_buffer->Release();
- }
- *_output_sample = sample;
- return S_OK;
- } while(0);
- if (sample) {
- sample->Release();
- }
- if (media_buffer) {
- media_buffer->Release();
- }
- return hr;
- }
- // Release the events that an MFT might allocate in IMFTransform::ProcessOutput().
- static void ReleaseEventCollection(MFT_OUTPUT_DATA_BUFFER &pBuffers)
- {
- if (pBuffers.pEvents) {
- pBuffers.pEvents->Release();
- pBuffers.pEvents = NULL;
- }
- }
- HRESULT MFTDecoder::GetFrame(IMFMediaBuffer **out_buffer, uint64_t *hundrednanos)
- {
- HRESULT hr=E_FAIL;
- IMFSample *output_sample=0;
- DWORD mftStatus;
- do {
- hr = CreateOutputSample(decoder, &output_sample);
- if (FAILED(hr)) {
- break;
- }
- MFT_OUTPUT_DATA_BUFFER mftDataBuffer = {0, };
- mftDataBuffer.pSample = output_sample;
- mftStatus = 0;
- hr = decoder->ProcessOutput(0, 1, &mftDataBuffer, &mftStatus);
- if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
- break;
- }
- if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
- ConfigureOutput(decoder, &stride);
- width=0;
- height=0;
- } else if (FAILED(hr)) {
- break;
- } else {
- if (mftDataBuffer.pSample) {
- IMFMediaBuffer *mediaBuffer;
- hr = mftDataBuffer.pSample->GetBufferByIndex(0, &mediaBuffer);
- if (FAILED(hr)) {
- break;
- }
- LONGLONG sample_time;
- output_sample->GetSampleTime(&sample_time);
- if (hundrednanos) {
- *hundrednanos = sample_time;
- }
- *out_buffer = mediaBuffer;
- }
- ReleaseEventCollection(mftDataBuffer);
- }
- } while (0);
- if (output_sample) {
- output_sample->Release();
- }
- return hr;
- }
- HRESULT MFTDecoder::Flush()
- {
- return decoder->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
- }
- HRESULT MFTDecoder::Drain()
- {
- return decoder->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
- }
- HRESULT MFTDecoder::GetFrame(YV12_PLANES **data, void **decoder_data, uint64_t *mft_timestamp)
- {
- HRESULT hr=E_FAIL;
- IMFMediaBuffer *media_buffer = 0;
- IMFMediaType *media_type = 0;
- do {
- if (!height || !stride) {
- hr = decoder->GetOutputCurrentType(0, &media_type);
- if (FAILED(hr)) {
- break;
- }
- hr = MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, &width, &height);
- if (FAILED(hr)) {
- break;
- }
- hr = GetDefaultStride(media_type, &stride);
- if (FAILED(hr)) {
- break;
- }
- }
- hr = this->GetFrame(&media_buffer, mft_timestamp);
- if (FAILED(hr)) {
- break;
- }
- YV12_PLANES *planes = (YV12_PLANES *)malloc(sizeof(YV12_PLANES));
- IMF2DBuffer *buffer2d=0;
- if (SUCCEEDED(media_buffer->QueryInterface(&buffer2d))) {
- BYTE *pbScanline0;
- LONG pitch;
- buffer2d->Lock2D(&pbScanline0, &pitch);
- planes->y.baseAddr = pbScanline0;
- planes->y.rowBytes = pitch;
- pbScanline0 += pitch * height;
- planes->v.baseAddr = pbScanline0;
- planes->v.rowBytes = pitch/2;
- pbScanline0 += pitch * height/4;
- planes->u.baseAddr = pbScanline0;
- planes->u.rowBytes = pitch/2;
- buffer2d->Release();
- } else {
- DWORD length, max_length;
- BYTE *video_data;
- media_buffer->Lock(&video_data, &length, &max_length);
- planes->y.baseAddr = video_data;
- planes->y.rowBytes = stride;
- video_data += stride * height;
- planes->v.baseAddr = video_data;
- planes->v.rowBytes = stride/2;
- video_data += (stride/2) * (height/2);
- planes->u.baseAddr = video_data;
- planes->u.rowBytes = stride/2;
- }
- *data = planes;
- *decoder_data = media_buffer;
- } while(0);
- if (media_type) {
- media_type->Release();
- }
- return hr;
- }
- HRESULT MFTDecoder::FreeFrame(YV12_PLANES *data, void *decoder_data)
- {
- IMFMediaBuffer *buffer= (IMFMediaBuffer *)decoder_data;
- if (buffer) {
- IMF2DBuffer *buffer2d=0;
- if (SUCCEEDED(buffer->QueryInterface(&buffer2d))) {
- buffer2d->Unlock2D();
- buffer2d->Release();
- } else {
- buffer->Unlock();
- }
- buffer->Release();
- }
- free(data);
- return S_OK;
- }
|