DirectShow — невозможно создать новые темы

У меня возникают странные проблемы с интеграцией графа DirectShow в существующее приложение.

Пара вещей, которые нужно охватить в первую очередь:

  1. Целью графика является получение необработанного видео из FrameGrabber с открытым интерфейсом DirectShow. График берет видео прямо для отображения через VMR9, а также подвергает необработанные кадры некоторым алгоритмам через ISampleGrabber (примеры DirectShow).
  2. График был построен и успешно запущен в отдельном проекте. Видео отображается нормально и все устраивает.

Теперь проблема возникает, когда я интегрирую это в существующий код. Из инициализации приложения я сначала создаю и запускаю график, работая с VMR9 в безоконном режиме. Позже при инициализации я создаю пару рабочих потоков через _beginthreadex. Вызовы _beginthreadex терпят неудачу с кодом возврата 12 (недостаточно памяти), когда и ТОЛЬКО когда граф построен и запущен.

Теперь очевидный ответ: у меня закончилась память или, возможно, какой-то другой ресурс. Однако в тот момент, когда потоки пытаются запуститься, я использую около 420 МБ системной памяти объемом 2 ГБ. Размер стека потоков был явно установлен равным 1 МБ. Так что я не потерял память, насколько я могу судить. Кроме того, в работающем приложении всего 15 потоков, поэтому я не создаю абсурдную сумму.

У кого-нибудь была/испытывала подобную проблему с DirectShow? Я вообще ищу какие-либо данные, мы уже довольно давно пытаемся решить эту проблему, но безуспешно.

Я опубликую любой код, который вам потребуется, так как в большинстве графов DirectShow код длинный.

Изменить

Как просили. Я не уверен, какая часть кода DirectShow приводит к сбою запуска потоков. Однако, если я только строю, но не запускаю график, потоки работают нормально. Поэтому я бы предположил, что сбой происходит после вызова запуска. Мой код для запуска графика выглядит следующим образом:

    if (CurrentState != Stopped)
        return WrongState;

    HRESULT hr;
    printf("Attempting to run graph... ");
    Timer->Start();
    hr = pMediaControl->Run();
    if (FAILED(hr))
    {
        OAFilterState State;
        hr = pMediaControl->GetState(1000, &State);     
        if ((SUCCEEDED(hr) && State != State_Running) || FAILED(hr))
        {
            return FailedToStartGraph;
        }
    }
    CurrentState = Streaming;
    SetVMRSize();
    Timer->Stop();
    RunTime->Start();
    FrameRate->Reset();

    return NoError;

Функция SetVMRSize просто изменяет размер VMR до его родительского окна:

void KontronGraph::SetVMRSize()
{
    if (CurrentState == Disconnected || VideoMode != ParentWindow)
        return;
    long lWidth, lHeight; 
    HRESULT hr = pWindowController->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL); 
    if (SUCCEEDED(hr))
    {
        RECT rcSrc, rcDest; 
        // Set the source rectangle.
        rcSrc.left = 0;
        rcSrc.right = lWidth;
        rcSrc.top = 0;
        rcSrc.bottom = lHeight;

        // Get the window client area.
        GetClientRect(MyHwnd, &rcDest); 
        // Set the destination rectangle.
        rcDest.right = rcDest.right - rcDest.left;
        rcDest.bottom = rcDest.bottom - rcDest.top;
        rcDest.left = 0;
        rcDest.top = 0;

        // Set the video position.
        hr = pWindowController->SetVideoPosition(&rcSrc, &rcDest); 
    }
}

Следует отметить, что pWindowController — это IVMRWindowlessControl9, а pMediaControl — это IMediaControl.

Изменить 2

Протестировал код, используя CreateThread вместо __beginthreadex. После неудачного запуска потоков GetLastError() возвращает:

8 : Недостаточно памяти для обработки этой команды.

Код для создания потоков выглядит так:

HANDLE worker_thread = CreateThread(0, 
Thread_Stack_Size, worker_thread_op, thread_param, 0, 0);

Некоторые параметры CreateThread:

Thread_Stack_Size = 1024 * 1024;
typedef DWORD (WINAPI *worker_thread_op_type)(LPVOID params);

person DeusAduro    schedule 20.01.2011    source источник
comment
Возможно ли, что вы работаете на своей видеопамяти?   -  person StefanE    schedule 31.01.2011


Ответы (3)


Для начала я бы посоветовал вам заменить _beginthreadex на CreateThread, а затем используйте GetLastError для определения причины любой ошибки, которая часто является более конкретной, чем коды ошибок CRT, установленные _beginthreadex. Дайте мне знать, что вы наблюдаете, делая это, и я обновлю свой ответ.

Кроме того, можете ли вы опубликовать часть вашего (DirectShow) кода, которая приводит к сбою создания потока, а также строки кода, создающие поток?

Обновление: что бы я ни нашел относительно конкретной ошибки, вы получаете намеки на возможную утечку памяти. Обратите внимание, что только 420 МБ (как вы упомянули) могут быть зарезервированы, но больше страниц могло быть зарезервировано, и эти страницы по-прежнему учитываются при расчете ограничения виртуального пространства вашего приложения в 2 ГБ. Запуск графа DirectShow мог израсходовать все, что осталось от этого пространства.

Таким образом, наиболее вероятно, что DirectShow сам по себе не является причиной ошибки, а вместо этого обнаружил существующую ошибку в вашем приложении.

Вот некоторая дополнительная информация из MSDN, которая может быть вам полезна, особенно если ранее вы создали другие потоки в своей программе (Размер стека потоков):

Каждый новый поток получает собственное пространство стека, состоящее как из зарезервированной, так и из первоначально выделенной памяти. Зарезервированный размер памяти представляет собой общий объем стека, выделенный в виртуальной памяти. Таким образом, зарезервированный размер ограничен диапазоном виртуальных адресов. Первоначально зафиксированные страницы не используют физическую память до тех пор, пока на них не будет сделана ссылка; ... Стек освобождается при выходе из его потока. Он не освобождается, если поток прерывается другим потоком.

person casablanca    schedule 24.01.2011
comment
Добавлен код Directshow, будут добавлены комментарии о CreateThread, как только я его протестирую. - person DeusAduro; 24.01.2011
comment
Я добавил результаты теста CreateThread. Кроме того, график DirectShow находится в отдельной DLL от основного приложения. Я не уверен, может ли/как это добавить к проблемам, но я подумал, что об этом стоит упомянуть. - person DeusAduro; 24.01.2011

На веб-страницах sysinternals есть несколько видеороликов, посвященных тому, как и кем используется память. Может быть, они могут помочь вам с вашей проблемой.

http://technet.microsoft.com/en-us/sysinternals/bb963887

http://player.microsoftpdc.com/Session/1689962d-dea2-48bd-80d8-96e954fa5329

http://player.microsoftpdc.com/Session/1c97b279-d7e3-4a3e-9a76-0dac23dfddb5

Надеюсь, что это поможет вам.

person engf-010    schedule 25.01.2011

Из вашего объяснения мне не совсем понятно, является ли это проблемой или нет, но с большинством инструментов, связанных с DirectX (которые, как я полагаю, включают DirectShow), вам необходимо убедиться, что все ваши связанные вызовы происходят в одном и том же потоке; другими словами, если вы настроили DirectShow для данного потока, выполняйте все вызовы к нему, используя этот же поток. Прошло много времени с тех пор, как я использовал DirectShow, поэтому я не уверен на 100%, что это применимо, но это определенно решает много проблем с D3D, который является тесно связанной технологией.

ПОМОЩЬ.

person taxilian    schedule 31.01.2011
comment
Привет, я считаю, что это применимо к DirectShow, однако я уже делаю это (все вызовы DS в том же потоке, в котором он создается). Спасибо за вклад, хотя. - person DeusAduro; 16.02.2011