QVideoSurfaceFormat MFTransform::videoFormatForMFMediaType(IMFMediaType *mediaType, int *bytesPerLine) { UINT32 stride; if (FAILED(mediaType->GetUINT32(MF_MT_DEFAULT_STRIDE, &stride))) { *bytesPerLine = 0; return QVideoSurfaceFormat(); } *bytesPerLine = (int)stride; QSize size; UINT32 width, height; if (FAILED(MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height))) return QVideoSurfaceFormat(); size.setWidth(width); size.setHeight(height); GUID subtype = GUID_NULL; if (FAILED(mediaType->GetGUID(MF_MT_SUBTYPE, &subtype))) return QVideoSurfaceFormat(); QVideoFrame::PixelFormat pixelFormat = formatFromSubtype(subtype); QVideoSurfaceFormat format(size, pixelFormat); UINT32 num, den; if (SUCCEEDED(MFGetAttributeRatio(mediaType, MF_MT_PIXEL_ASPECT_RATIO, &num, &den))) { format.setPixelAspectRatio(num, den); } if (SUCCEEDED(MFGetAttributeRatio(mediaType, MF_MT_FRAME_RATE, &num, &den))) { format.setFrameRate(qreal(num)/den); } return format; }
HRESULT MediaInfo::InternalInitVideo(IMFMediaType* mediaType, StreamInfo& info) { MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &info.video.width, &info.video.height); MFGetAttributeRatio(mediaType, MF_MT_PIXEL_ASPECT_RATIO, &info.video.pixelAR0, &info.video.pixelAR1); UINT32 fps_den = 0, fps_num = 0; MFGetAttributeRatio(mediaType, MF_MT_FRAME_RATE, &fps_num, &fps_den); info.video.frameRate = float(fps_num) / float(fps_den); info.video.fps_den = fps_den; info.video.fps_num = fps_num; info.video.profile = MFGetAttributeUINT32(mediaType, MF_MT_MPEG2_PROFILE, 0); info.video.profileLevel = MFGetAttributeUINT32(mediaType, MF_MT_MPEG2_LEVEL, 0); return S_OK; }
HRESULT WMFVideoMFTManager::ConfigureVideoFrameGeometry() { RefPtr<IMFMediaType> mediaType; HRESULT hr = mDecoder->GetOutputMediaType(mediaType); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Verify that the video subtype is what we expect it to be. // When using hardware acceleration/DXVA2 the video format should // be NV12, which is DXVA2's preferred format. For software decoding // we use YV12, as that's easier for us to stick into our rendering // pipeline than NV12. NV12 has interleaved UV samples, whereas YV12 // is a planar format. GUID videoFormat; hr = mediaType->GetGUID(MF_MT_SUBTYPE, &videoFormat); NS_ENSURE_TRUE(videoFormat == MFVideoFormat_NV12 || !mUseHwAccel, E_FAIL); NS_ENSURE_TRUE(videoFormat == MFVideoFormat_YV12 || mUseHwAccel, E_FAIL); nsIntRect pictureRegion; hr = GetPictureRegion(mediaType, pictureRegion); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); UINT32 width = 0, height = 0; hr = MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); uint32_t aspectNum = 0, aspectDenom = 0; hr = MFGetAttributeRatio(mediaType, MF_MT_PIXEL_ASPECT_RATIO, &aspectNum, &aspectDenom); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Calculate and validate the picture region and frame dimensions after // scaling by the pixel aspect ratio. nsIntSize frameSize = nsIntSize(width, height); nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height); ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom)); if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) { // Video track's frame sizes will overflow. Ignore the video track. return E_FAIL; } // Success! Save state. mVideoInfo.mDisplay = displaySize; mVideoInfo.mHasVideo = true; GetDefaultStride(mediaType, &mVideoStride); mVideoWidth = width; mVideoHeight = height; mPictureRegion = pictureRegion; LOG("WMFVideoMFTManager frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d) PAR=%d:%d", width, height, mVideoStride, mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height, displaySize.width, displaySize.height, aspectNum, aspectDenom); return S_OK; }
//------------------------------------------------------------------- // getVideoFormat: Gets format information for the video stream. // HRESULT VidReader::getVideoFormat() { HRESULT hr = S_OK; IMFMediaType *pType = NULL; GUID subtype = { 0 }; // Get the media type from the stream. hr = m_pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pType); if (FAILED(hr)) goto done; // Make sure it is a video format. hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (subtype != MFVideoFormat_RGB32) { hr = E_UNEXPECTED; goto done; } // Get the width and height hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &m_imagewidth, &m_imageheight); if (FAILED(hr)) goto done; // Get the frame rate UINT32 frN, frD; hr = MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, &frN, &frD); if (FAILED(hr)) goto done; m_framerate = (double)frN / (double)frD; done: SafeRelease(&pType); return hr; }
MFRatio qt_wmf_getPixelAspectRatio(IMFMediaType *type) { MFRatio ratio = { 0, 0 }; HRESULT hr = S_OK; hr = MFGetAttributeRatio(type, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&ratio.Numerator, (UINT32*)&ratio.Denominator); if (FAILED(hr)) { ratio.Numerator = 1; ratio.Denominator = 1; } return ratio; }
HRESULT tTVPMFPlayer::CreateMediaSinkActivate( IMFStreamDescriptor *pSourceSD, HWND hVideoWindow, IMFActivate **ppActivate ) { HRESULT hr; CComPtr<IMFMediaTypeHandler> pHandler; // Get the media type handler for the stream. if( FAILED(hr = pSourceSD->GetMediaTypeHandler(&pHandler)) ) { TVPThrowExceptionMessage(L"Faild to get media type handler."); } // Get the major media type. GUID guidMajorType; if( FAILED(hr = pHandler->GetMajorType(&guidMajorType)) ) { TVPThrowExceptionMessage(L"Faild to get major type."); } CComPtr<IMFActivate> pActivate; if( MFMediaType_Audio == guidMajorType ) { // Create the audio renderer. if( FAILED(hr = MFCreateAudioRendererActivate(&pActivate) )) { TVPThrowExceptionMessage(L"Faild to create audio render."); } } else if( MFMediaType_Video == guidMajorType ) { // Get FPS CComPtr<IMFMediaType> pMediaType; if( SUCCEEDED(hr = pHandler->GetCurrentMediaType(&pMediaType)) ) { hr = MFGetAttributeRatio( pMediaType, MF_MT_FRAME_RATE, &FPSNumerator, &FPSDenominator ); } // Create the video renderer. if( FAILED(hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate) ) ) { TVPThrowExceptionMessage(L"Faild to create video render."); } // ここでカスタムEVRをつなぐようにすると自前で色々描画できるようになる // 現状は標準のものを使っている #if 0 tTVPEVRCustomPresenter* my_activate_obj = new tTVPEVRCustomPresenter(hr); my_activate_obj->AddRef(); CComPtr<IUnknown> unk; my_activate_obj->QueryInterface( IID_IUnknown, (void**)&unk ); if( FAILED(hr = pActivate->SetUnknown(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, unk)) ) { my_activate_obj->Release(); TVPThrowExceptionMessage(L"Faild to add custom EVR presenter video render."); } my_activate_obj->Release(); #endif } else { hr = E_FAIL; } if( SUCCEEDED(hr) ) { // Return IMFActivate pointer to caller. *ppActivate = pActivate; (*ppActivate)->AddRef(); } return hr; }
// Helper function to get the frame rate from a video media type. inline HRESULT GetFrameRate( IMFMediaType *pType, UINT32 *pNumerator, UINT32 *pDenominator ) { return MFGetAttributeRatio( pType, MF_MT_FRAME_RATE, pNumerator, pDenominator ); }
// Called by the DecoderMF class when the media type // changes. // // Thread context: decoder thread bool PreviewWindow::SetMediaType(IMFMediaType* mediaType) { HRESULT hr; bool ret = false; GUID subtype; UINT width, height; LONG defaultStride; MFRatio PAR = { 0 }; EnterCriticalSection(&m_criticalSection); hr = mediaType->GetGUID(MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) goto bail; hr = MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height); if (FAILED(hr)) goto bail; // TODO: get if it's interlaced / progressive (MF_MT_INTERLACE_MODE) hr = GetDefaultStride(mediaType, &defaultStride); if (FAILED(hr)) goto bail; // Get the pixel aspect ratio. Default: Assume square pixels (1:1) hr = MFGetAttributeRatio(mediaType, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&PAR.Numerator, (UINT32*)&PAR.Denominator); if (FAILED(hr)) { PAR.Numerator = PAR.Denominator = 1; } // Creates a new RGBA (32bpp) buffer for the converted frame m_width = width; m_height = height; m_defaultStride = defaultStride; m_newTextureInBuffer = false; ret = true; bail: LeaveCriticalSection(&m_criticalSection); return ret; }
HRESULT DrawDevice::SetVideoType(IMFMediaType *pType) { HRESULT hr = S_OK; GUID subtype = { 0 }; MFRatio PAR = { 0 }; // Find the video subtype. hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) { goto done; } // Choose a conversion function. // (This also validates the format type.) hr = SetConversionFunction(subtype); if (FAILED(hr)) { goto done; } // // Get some video attributes. // // Get the frame size. hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &m_width, &m_height); if (FAILED(hr)) { goto done; } // Get the interlace mode. Default: assume progressive. m_interlace = (MFVideoInterlaceMode)MFGetAttributeUINT32( pType, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive ); // Get the image stride. hr = GetDefaultStride(pType, &m_lDefaultStride); if (FAILED(hr)) { goto done; } // Get the pixel aspect ratio. Default: Assume square pixels (1:1) hr = MFGetAttributeRatio( pType, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&PAR.Numerator, (UINT32*)&PAR.Denominator ); if (SUCCEEDED(hr)) { m_PixelAR = PAR; } else { m_PixelAR.Numerator = m_PixelAR.Denominator = 1; } m_format = (D3DFORMAT)subtype.Data1; // Create Direct3D swap chains. hr = CreateSwapChains(); if (FAILED(hr)) { goto done; } // Update the destination rectangle for the correct // aspect ratio. UpdateDestinationRect(); if (m_pBuf) delete [] m_pBuf; m_pBuf = new BYTE[m_height * m_width * 3]; done: if (FAILED(hr)) { m_format = D3DFMT_UNKNOWN; m_convertFn = NULL; } return hr; }
STDMETHODIMP CDecWMV9MFT::ProcessOutput() { HRESULT hr = S_OK; DWORD dwStatus = 0; MFT_OUTPUT_STREAM_INFO outputInfo = {0}; m_pMFT->GetOutputStreamInfo(0, &outputInfo); IMFMediaBuffer *pMFBuffer = nullptr; ASSERT(!(outputInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)); MFT_OUTPUT_DATA_BUFFER OutputBuffer = {0}; if (!(outputInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)) { pMFBuffer = GetBuffer(outputInfo.cbSize); if (!pMFBuffer) { DbgLog((LOG_TRACE, 10, L"Unable to allocate media buffere")); return E_FAIL; } IMFSample *pSampleOut = nullptr; hr = MF.CreateSample(&pSampleOut); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"Unable to allocate MF sample, hr: 0x%x", hr)); ReleaseBuffer(pMFBuffer); return E_FAIL; } pSampleOut->AddBuffer(pMFBuffer); OutputBuffer.pSample = pSampleOut; } hr = m_pMFT->ProcessOutput(0, 1, &OutputBuffer, &dwStatus); // We don't process events, just release them SafeRelease(&OutputBuffer.pEvents); // handle stream format changes if (hr == MF_E_TRANSFORM_STREAM_CHANGE || OutputBuffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE ) { SafeRelease(&OutputBuffer.pSample); ReleaseBuffer(pMFBuffer); hr = SelectOutputType(); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> Failed to handle stream change, hr: %x", hr)); return E_FAIL; } // try again with the new type, it should work now! return ProcessOutput(); } // the MFT generated no output, discard the sample and return if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT || OutputBuffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE) { SafeRelease(&OutputBuffer.pSample); ReleaseBuffer(pMFBuffer); return S_FALSE; } // unknown error condition if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> ProcessOutput failed with hr: %x", hr)); SafeRelease(&OutputBuffer.pSample); ReleaseBuffer(pMFBuffer); return E_FAIL; } LAVFrame *pFrame = nullptr; AllocateFrame(&pFrame); IMFMediaType *pMTOut = nullptr; m_pMFT->GetOutputCurrentType(0, &pMTOut); MFGetAttributeSize(pMTOut, MF_MT_FRAME_SIZE, (UINT32 *)&pFrame->width, (UINT32 *)&pFrame->height); pFrame->format = m_OutPixFmt; AVRational pixel_aspect_ratio = {1, 1}; MFGetAttributeRatio(pMTOut, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&pixel_aspect_ratio.num, (UINT32*)&pixel_aspect_ratio.den); AVRational display_aspect_ratio = {0, 0}; av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, (int64_t)pixel_aspect_ratio.num * pFrame->width, (int64_t)pixel_aspect_ratio.den * pFrame->height, INT_MAX); pFrame->aspect_ratio = display_aspect_ratio; pFrame->interlaced = MFGetAttributeUINT32(OutputBuffer.pSample, MFSampleExtension_Interlaced, FALSE); pFrame->repeat = MFGetAttributeUINT32(OutputBuffer.pSample, MFSampleExtension_RepeatFirstField, FALSE); LAVDeintFieldOrder fo = m_pSettings->GetDeintFieldOrder(); pFrame->tff = (fo == DeintFieldOrder_Auto) ? !MFGetAttributeUINT32(OutputBuffer.pSample, MFSampleExtension_BottomFieldFirst, FALSE) : (fo == DeintFieldOrder_TopFieldFirst); if (pFrame->interlaced && !m_bInterlaced) m_bInterlaced = TRUE; pFrame->interlaced = (pFrame->interlaced || (m_bInterlaced && m_pSettings->GetDeinterlacingMode() == DeintMode_Aggressive) || m_pSettings->GetDeinterlacingMode() == DeintMode_Force) && !(m_pSettings->GetDeinterlacingMode() == DeintMode_Disable); pFrame->ext_format.VideoPrimaries = MFGetAttributeUINT32(pMTOut, MF_MT_VIDEO_PRIMARIES, MFVideoPrimaries_Unknown); pFrame->ext_format.VideoTransferFunction = MFGetAttributeUINT32(pMTOut, MF_MT_TRANSFER_FUNCTION, MFVideoTransFunc_Unknown); pFrame->ext_format.VideoTransferMatrix = MFGetAttributeUINT32(pMTOut, MF_MT_YUV_MATRIX, MFVideoTransferMatrix_Unknown); pFrame->ext_format.VideoChromaSubsampling = MFGetAttributeUINT32(pMTOut, MF_MT_VIDEO_CHROMA_SITING, MFVideoChromaSubsampling_Unknown); pFrame->ext_format.NominalRange = MFGetAttributeUINT32(pMTOut, MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Unknown); // HACK: don't flag range=limited if its the only value set, since its also the implied default, this helps to avoid a reconnect // The MFT always sets this value, even if the bitstream says nothing about it, causing a reconnect on every vc1/wmv3 file if (pFrame->ext_format.value == 0x2000) pFrame->ext_format.value = 0; // Timestamps if (m_bManualReorder) { if (!m_timestampQueue.empty()) { pFrame->rtStart = m_timestampQueue.front(); m_timestampQueue.pop(); LONGLONG llDuration = 0; hr = OutputBuffer.pSample->GetSampleDuration(&llDuration); if (SUCCEEDED(hr) && llDuration > 0) { pFrame->rtStop = pFrame->rtStart + llDuration; } } } else { LONGLONG llTimestamp = 0; hr = OutputBuffer.pSample->GetSampleTime(&llTimestamp); if (SUCCEEDED(hr)) { pFrame->rtStart = llTimestamp; LONGLONG llDuration = 0; hr = OutputBuffer.pSample->GetSampleDuration(&llDuration); if (SUCCEEDED(hr) && llDuration > 0) { pFrame->rtStop = pFrame->rtStart + llDuration; } } } SafeRelease(&pMTOut); // Lock memory in the buffer BYTE *pBuffer = nullptr; pMFBuffer->Lock(&pBuffer, NULL, NULL); // Check alignment // If not properly aligned, we need to make the data aligned. int alignment = (m_OutPixFmt == LAVPixFmt_NV12) ? 16 : 32; if ((pFrame->width % alignment) != 0) { hr = AllocLAVFrameBuffers(pFrame); if (FAILED(hr)) { pMFBuffer->Unlock(); ReleaseBuffer(pMFBuffer); SafeRelease(&OutputBuffer.pSample); return hr; } size_t ySize = pFrame->width * pFrame->height; memcpy_plane(pFrame->data[0], pBuffer, pFrame->width, pFrame->stride[0], pFrame->height); if (m_OutPixFmt == LAVPixFmt_NV12) { memcpy_plane(pFrame->data[1], pBuffer + ySize, pFrame->width, pFrame->stride[1], pFrame->height / 2); } else if (m_OutPixFmt == LAVPixFmt_YUV420) { size_t uvSize = ySize / 4; memcpy_plane(pFrame->data[2], pBuffer + ySize, pFrame->width / 2, pFrame->stride[2], pFrame->height / 2); memcpy_plane(pFrame->data[1], pBuffer + ySize + uvSize, pFrame->width / 2, pFrame->stride[1], pFrame->height / 2); } pMFBuffer->Unlock(); ReleaseBuffer(pMFBuffer); } else { if (m_OutPixFmt == LAVPixFmt_NV12) { pFrame->data[0] = pBuffer; pFrame->data[1] = pBuffer + pFrame->width * pFrame->height; pFrame->stride[0] = pFrame->stride[1] = pFrame->width; } else if (m_OutPixFmt == LAVPixFmt_YUV420) { pFrame->data[0] = pBuffer; pFrame->data[2] = pBuffer + pFrame->width * pFrame->height; pFrame->data[1] = pFrame->data[2] + (pFrame->width / 2) * (pFrame->height / 2); pFrame->stride[0] = pFrame->width; pFrame->stride[1] = pFrame->stride[2] = pFrame->width / 2; } pFrame->data[3] = (BYTE *)pMFBuffer; pFrame->destruct = wmv9_buffer_destruct; pFrame->priv_data = this; } pFrame->flags |= LAV_FRAME_FLAG_BUFFER_MODIFY; Deliver(pFrame); SafeRelease(&OutputBuffer.pSample); if (OutputBuffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE) return ProcessOutput(); return hr; }
HRESULT HDMediaSource::FindBestVideoStreamIndex(IMFPresentationDescriptor* ppd,PDWORD pdwStreamId,UINT* width,UINT* height,float* fps) { if (ppd == nullptr) return E_INVALIDARG; DWORD dwCount = 0; HRESULT hr = ppd->GetStreamDescriptorCount(&dwCount); if (FAILED(hr)) return hr; int vid_count = 0; auto pw = std::unique_ptr<unsigned[]>(new unsigned[dwCount]); auto ph = std::unique_ptr<unsigned[]>(new unsigned[dwCount]); auto psid = std::unique_ptr<DWORD[]>(new DWORD[dwCount]); for (unsigned i = 0;i < dwCount;i++) { BOOL fSelected; ComPtr<IMFStreamDescriptor> psd; hr = ppd->GetStreamDescriptorByIndex(i,&fSelected,psd.GetAddressOf()); if (FAILED(hr)) break; DWORD dwStreamId = 0; hr = psd->GetStreamIdentifier(&dwStreamId); if (FAILED(hr)) break; ComPtr<IMFMediaTypeHandler> pHandler; hr = psd->GetMediaTypeHandler(pHandler.GetAddressOf()); if (FAILED(hr)) return hr; ComPtr<IMFMediaType> pMediaType; hr = pHandler->GetCurrentMediaType(pMediaType.GetAddressOf()); if (FAILED(hr)) break; if (FAILED(WMF::Misc::IsVideoMediaType(pMediaType.Get()))) continue; UINT nWidth = 0,nHeight = 0; hr = MFGetAttributeSize(pMediaType.Get(),MF_MT_FRAME_SIZE,&nWidth,&nHeight); if (FAILED(hr)) continue; MFRatio fps_ratio = {0,0}; MFGetAttributeRatio(pMediaType.Get(),MF_MT_FRAME_RATE, (PUINT32)&fps_ratio.Numerator,(PUINT32)&fps_ratio.Denominator); if (fps && fps_ratio.Denominator != 0 && fps_ratio.Numerator != 0) *fps = (float)fps_ratio.Numerator / (float)fps_ratio.Denominator; pw[vid_count] = nWidth; ph[vid_count] = nHeight; psid[vid_count] = dwStreamId; vid_count++; } if (FAILED(hr)) return hr; if (vid_count == 0) return MF_E_NOT_FOUND; unsigned cur_wh = pw[0] + ph[0]; int max_index = 0; for (int i = 0;i < vid_count;i++) { if ((pw[i] + ph[i]) > cur_wh) { cur_wh = pw[i] + ph[i]; max_index = i; } } if (pdwStreamId) *pdwStreamId = psid[max_index]; if (width) *width = pw[max_index]; if (height) *height = ph[max_index]; return S_OK; }
static HRESULT GetFrameRate(IMFMediaType *pType, uint32_t& numer, uint32_t& denum) { HRESULT hr; hr = MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, &numer, &denum); return hr; }