k4a_result_t CMFCameraReader::Start()

in src/color/mfcamerareader.cpp [292:492]


k4a_result_t CMFCameraReader::Start(const UINT32 width,
                                    const UINT32 height,
                                    const float fps,
                                    const k4a_image_format_t imageFormat,
                                    color_cb_stream_t *pCallback,
                                    void *pCallbackContext)
{
    RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, pCallback == nullptr);
    RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, pCallbackContext == nullptr);
    HRESULT hr = S_OK;
    GUID guidDeviceSubType = GUID_NULL;
    GUID guidOutputSubType = GUID_NULL;

    switch (imageFormat)
    {
    case K4A_IMAGE_FORMAT_COLOR_NV12:
        guidDeviceSubType = MFVideoFormat_NV12;
        guidOutputSubType = MFVideoFormat_NV12;
        break;
    case K4A_IMAGE_FORMAT_COLOR_YUY2:
        guidDeviceSubType = MFVideoFormat_YUY2;
        guidOutputSubType = MFVideoFormat_YUY2;
        break;
    case K4A_IMAGE_FORMAT_COLOR_MJPG:
        guidDeviceSubType = MFVideoFormat_MJPG;
        guidOutputSubType = MFVideoFormat_MJPG;
        break;
    case K4A_IMAGE_FORMAT_COLOR_BGRA32:
        if (width == 1280 && height == 720)
        {
            guidDeviceSubType = MFVideoFormat_NV12;
        }
        else
        {
            guidDeviceSubType = MFVideoFormat_MJPG;
        }
        guidOutputSubType = MFVideoFormat_ARGB32;
        break;
    default:
        LOG_ERROR("Image Format %d is invalid", imageFormat);
        return K4A_RESULT_FAILED;
    }

    if (!m_started)
    {
        bool typeFound = false;
        DWORD typeIndex = 0;
        ComPtr<IMFMediaType> spMediaType;

        // Find target media type
        while (!typeFound)
        {
            hr = m_spSourceReader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                                                      typeIndex,
                                                      &spMediaType);

            if (SUCCEEDED(hr))
            {
                UINT32 tempWidth = 0;
                UINT32 tempHeight = 0;
                UINT32 tempFpsNumerator = 0;
                UINT32 tempFpsDenominator = 0;
                GUID tempSubType = GUID_NULL;

                if (FAILED(hr = MFGetAttributeSize(spMediaType.Get(), MF_MT_FRAME_SIZE, &tempWidth, &tempHeight)))
                {
                    LOG_ERROR("Failed to get available frame size at start: 0x%08x", hr);
                    return k4aResultFromHRESULT(hr);
                }
                if (FAILED(hr = MFGetAttributeRatio(spMediaType.Get(),
                                                    MF_MT_FRAME_RATE,
                                                    &tempFpsNumerator,
                                                    &tempFpsDenominator)))
                {
                    LOG_ERROR("Failed to get available frame rate at start: 0x%08x", hr);
                    return k4aResultFromHRESULT(hr);
                }
                if (FAILED(hr = spMediaType->GetGUID(MF_MT_SUBTYPE, &tempSubType)))
                {
                    LOG_ERROR("Failed to get available color format at start: 0x%08x", hr);
                    return k4aResultFromHRESULT(hr);
                }

                if (width == tempWidth && height == tempHeight &&
                    fps == ((float)tempFpsNumerator / (float)tempFpsDenominator) && guidDeviceSubType == tempSubType)
                {
                    typeFound = true;
                }
            }
            else if (hr == MF_E_NO_MORE_TYPES)
            {
                break;
            }
            else
            {
                LOG_ERROR("Failed to enumerate media type at start: 0x%08x", hr);
                return k4aResultFromHRESULT(hr);
            }

            typeIndex++;
        }

        if (typeFound)
        {
            ComPtr<IMFSourceReaderEx> spSourceReaderEx;
            ComPtr<IMFMediaType> spOutputMediaType;

            if (FAILED(hr = m_spSourceReader.As(&spSourceReaderEx)))
            {
                LOG_ERROR("Failed to get source reader extension at start: 0x%08x", hr);
                return k4aResultFromHRESULT(hr);
            }
            DWORD dwStreamFlags = 0;

            if (FAILED(hr = spSourceReaderEx->SetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                                                                 spMediaType.Get(),
                                                                 &dwStreamFlags)))
            {
                LOG_ERROR("Failed to set media type at start: 0x%08x", hr);
                return k4aResultFromHRESULT(hr);
            }

            if (guidDeviceSubType != guidOutputSubType)
            {
                // Create Output Media type
                if (FAILED(hr = MFCreateMediaType(&spOutputMediaType)))
                {
                    LOG_ERROR("Failed to create output media type at start: 0x%08x", hr);
                    return k4aResultFromHRESULT(hr);
                }

                // Copy all items from device type to output type
                if (FAILED(hr = spMediaType->CopyAllItems(spOutputMediaType.Get())))
                {
                    LOG_ERROR("Failed to copy device type to output type at start: 0x%08x", hr);
                    return k4aResultFromHRESULT(hr);
                }

                // Modify output media type
                if (FAILED(hr = spOutputMediaType->SetGUID(MF_MT_SUBTYPE, guidOutputSubType)))
                {
                    LOG_ERROR("Failed to set output subtype at start: 0x%08x", hr);
                    return k4aResultFromHRESULT(hr);
                }
            }
            else
            {
                spOutputMediaType = spMediaType;
            }

            if (FAILED(hr = m_spSourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                                                                  nullptr,
                                                                  spOutputMediaType.Get())))
            {
                LOG_ERROR("Failed to set output media type at start: 0x%08x", hr);
                return k4aResultFromHRESULT(hr);
            }
        }
        else
        {
            LOG_ERROR("Can not find requested sensor mode", 0);
            return K4A_RESULT_FAILED;
        }

        if (SUCCEEDED(hr = m_spSourceReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE)))
        {
            auto lock = m_lock.LockExclusive();

            m_width_pixels = width;
            m_height_pixels = height;
            m_image_format = imageFormat;

            m_pCallback = pCallback;
            m_pCallbackContext = pCallbackContext;

            if (SUCCEEDED(hr = m_spSourceReader->ReadSample(
                              (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, nullptr, nullptr, nullptr, nullptr)))
            {
                m_started = true;
            }
            else
            {
                LOG_ERROR("Failed to request first sample at start: 0x%08x", hr);
            }
        }
        else
        {
            LOG_ERROR("Failed to select stream at start: 0x%08x", hr);
        }
    }
    else
    {
        LOG_WARNING("Start request in started state", 0);
    }

    if (FAILED(hr))
    {
        LOG_ERROR("Failing with HRESULT:%08X", hr);
    }
    return k4aResultFromHRESULT(hr);
}