Как перехватить исключение UWP MediaCapture, когда устройство захвата используется другим приложением? - PullRequest
1 голос
/ 25 октября 2019

Я работаю над добавлением простого предварительного просмотра веб-камеры в приложение UWP. Подготовка и запуск предварительного просмотра работают нормально, поэтому я работаю над правильной обработкой исключений, генерируемых InitializeAsync() и StartPreviewAsync(), и не могу правильно перехватить исключения для второго.

Я основываю свой кодoff of Отобразите предварительный просмотр камеры , и он говорит, что, если приложению не предоставлен доступ к устройству захвата, оно вызовет UnauthorizedAccessException при вызове InitializeAsync(). Для C ++ / WinRT это, кажется, работает для перехвата hresult_error кода E_ACCESSDENIED, как показано ниже. Я проверил это, отключив доступ к веб-камере в настройках приложения, и блок try / catch работает точно так же, как и следовало ожидать, когда всплыло диалоговое окно с содержимым, объясняющее проблему пользователю.

Ссылкатакже говорит, что если другое приложение имеет исключительный контроль над устройством захвата, то StartPreviewAsync() должно выдать FileLoadException. Для начала я не могу понять, что такое эквивалент C ++ / WinRT для этого исключения. Во-вторых, я не могу поймать никаких исключений вообще. Я попытался использовать тот же тип блока перехвата, который я использовал для InitializeAsync(), поскольку это то, что описано в Перехват исключений , но когда это не сработало, я прибег к попытке перехватить что-нибудь с помощью блока ниже. В документах говорится, что вы можете зарегистрироваться на событие CaptureDeviceExclusiveControlStatusChanged, когда вы поймаете исключение, но так как я не могу поймать исключение, я не уверен, где будет подходящее место для этого или если событие сработает, если мое приложение запущенопосле того, как другое приложение уже имеет контроль над устройством захвата. Я никогда не вижу текст из OutputDebugString() в блоке catch, но я получаю следующее сообщение (дважды) в окне вывода отладки:

Исключение, сгенерированное в 0x00007FFC7114A839 (KernelBase.dll) в DBRacing. exe: ошибка инициализации WinRT - 0xC00D3704: «Аппаратному MFT не удалось начать потоковую передачу из-за нехватки аппаратных ресурсов.».

Похоже, генерируется исключение, я просто не могу уловитьпо какой-то причине.

В приведенном ниже коде методы, используемые с моей ViewModel (), просто для обеспечения доступа к локальным настройкам, где я храню последний использованный идентификатор устройства, и все работает нормально, когда мое приложение имеет эксклюзивный контрольвеб-камеры.

Итак, мой вопрос: как правильно определить, когда другое приложение имеет исключительный контроль над устройством захвата?

У меня есть переменная класса приватной страницы для объекта MediaCapture:

private:
    Windows::Media::Capture::MediaCapture m_mediaCapture;

Предварительный просмотр камеры начинается при переходе на страницу:

void VideoPage::OnNavigatedTo(NavigationEventArgs /*e*/) {

    StartPreviewAsync();
}

StartPreviewAsync () определяется какэто:

Windows::Foundation::IAsyncAction VideoPage::StartPreviewAsync() {

    // if we have a previously used device, then we should check if it's valid and use it
    if (!ViewModel().hasDeviceID()) {

        // device picker to choose camera
        DevicePicker picker;

        // create a filter that only looks for video capture devices
        picker.Filter().SupportedDeviceClasses().Append(DeviceClass::VideoCapture);

        // show the picker below the button that opens it and get the chosen device
        DeviceInformation device = co_await picker.PickSingleDeviceAsync({ 0,0,100,100 });

        // the user can cancel the dialog before picking something
        if (!device)
            return;

        // store the device ID
        ViewModel().deviceID(device.Id());

        // store the device name
        ViewModel().deviceName(device.Name());
    }

    // settings for the media capture object (such as which camera to use)
    MediaCaptureInitializationSettings settings;

    // add the chosen device to the settings so we initialize on that camera
    settings.VideoDeviceId(ViewModel().deviceID());

    try {

        // initialize the mediacapture object using the chosen camera
        co_await m_mediaCapture.InitializeAsync(settings);

        // dont let the screen go to sleep while the preview is active
        m_displayRequest.RequestActive();
    }

    // an exception is thrown if the user does not allow access to the camera
    catch (winrt::hresult_error const& ex) {

        winrt::hresult hr = ex.to_abi();

        if (hr == E_ACCESSDENIED) {

            ContentDialog msg;

            // set all the options for the dialog
            msg.Title(box_value(L"Access Denied"));
            msg.Content(box_value(L"This App has not been given permission to use the Camera and/or Microphone.\nPlease go to the settings in Windows for this App to allow access."));
            msg.CloseButtonText(L"OK");

            // Show the message dialog.
            msg.ShowAsync();
        }

        return;
    }

    try {

        // assign the source to the Capture Element on the XAML page
        capturePreview().Source(m_mediaCapture);

        co_await m_mediaCapture.StartPreviewAsync();
    }

    // This method should throw a FileLoadException (0x80070020) if another app has exclusive control of the capture device
    catch(...) {

        OutputDebugString(L"Exception Message\n");

        return;
    }
}

1 Ответ

0 голосов
/ 25 октября 2019

По моим тестам, когда я впервые зарегистрировался для события CaptureDeviceExclusiveControlStatusChanged, прежде чем перехватить исключение, и одно из приложений использовало камеру. После этого я запускаю другое приложение, которое также будет использовать ту же камеру, оно может поймать исключение. Вы можете попробовать сначала добавить событие для проверки, как показано ниже, и событие mediaCapture.Failed имеет тот же эффект.

try 
{
    DisplayRequest displayRequest = DisplayRequest();
    m_mediaCapture = MediaCapture();
    // initialize the mediacapture object using the chosen camera
    co_await m_mediaCapture.InitializeAsync();
    //Register
    m_mediaCapture.CaptureDeviceExclusiveControlStatusChanged({ this, &MainPage::MediaCapture_CaptureDeviceExclusiveControlStatusChanged });

    displayRequest.RequestActive();
}
catch (winrt::hresult_error const& ex) 
{
    winrt::hresult hr = ex.to_abi();
    if (hr == E_ACCESSDENIED) {
    }

    return;
}

try 
{
    PreviewControl().Source(m_mediaCapture);
    co_await m_mediaCapture.StartPreviewAsync();
}
catch (winrt::hresult_error const& ex)
{
    winrt::hresult hr = ex.to_abi(); // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND).
    winrt::hstring message = ex.message(); // The system cannot find the file specified.
}

//event
void MainPage::MediaCapture_CaptureDeviceExclusiveControlStatusChanged(MediaCapture const&, MediaCaptureDeviceExclusiveControlStatusChangedEventArgs const&)
{
    throw hresult_not_implemented();
}
...