Udostępnij przez


Krok 5. Przekształcanie obrazu

[Funkcja skojarzona z tą stroną, DirectShow, jest starszą funkcją. Został zastąpiony przez MediaPlayer, IMFMediaEnginei Audio/Video Capture w Media Foundation. Te funkcje zostały zoptymalizowane pod kątem systemów Windows 10 i Windows 11. Firma Microsoft zdecydowanie zaleca, aby nowy kod używał MediaPlayer, IMFMediaEngine i Audio/Video Capture w programie Media Foundation zamiast DirectShow, jeśli to możliwe. Firma Microsoft sugeruje, że istniejący kod, który używa starszych interfejsów API, należy przepisać go do korzystania z nowych interfejsów API, jeśli to możliwe.]

To jest piąty krok samouczka tworzenie filtrów transformacji.

Filtr nadrzędny dostarcza próbki multimediów do filtru transformacji, wywołując metodę IMemInputPin::Receive na pinie wejściowym filtru przekształcania. Aby przetworzyć dane, filtr przekształcania wywołuje metodę Transform, która jest czystą wirtualną. Klasy CTransformFilter i CTransInPlaceFilter używają dwóch różnych wersji tej metody:

  • CTransformFilter::Transform pobiera wskaźnik do próbki wejściowej i wskaźnik do próbki wyjściowej. Przed wywołaniem filtru metoda kopiuje przykładowe właściwości z przykładu wejściowego do przykładu wyjściowego, w tym sygnatury czasowe.
  • CTransInPlaceFilter::Transform pobiera wskaźnik do próbki wejściowej. Filtr modyfikuje wprowadzone dane.

Jeśli metoda Transform zwróci S_OK, filtr dostarcza próbkę dalej w strumieniu. Aby pominąć ramkę, wróć S_FALSE. Jeśli wystąpi błąd przesyłania strumieniowego, zwróć kod błędu.

W poniższym przykładzie pokazano, jak koder RLE może zaimplementować tę metodę. Własna implementacja może się znacznie różnić w zależności od tego, co robi filtr.

HRESULT CRleFilter::Transform(IMediaSample *pSource, IMediaSample *pDest)
{
    // Get pointers to the underlying buffers.
    BYTE *pBufferIn, *pBufferOut;
    hr = pSource->GetPointer(&pBufferIn);
    if (FAILED(hr))
    {
        return hr;
    }
    hr = pDest->GetPointer(&pBufferOut);
    if (FAILED(hr))
    {
        return hr;
    }
    // Process the data.
    DWORD cbDest = EncodeFrame(pBufferIn, pBufferOut);
    KASSERT((long)cbDest <= pDest->GetSize());

    pDest->SetActualDataLength(cbDest);
    pDest->SetSyncPoint(TRUE);
    return S_OK;
}

W tym przykładzie przyjęto założenie, że EncodeFrame jest prywatną metodą implementjącą kodowanie RLE. Sam algorytm kodowania nie został opisany w tym miejscu; Aby uzyskać szczegółowe informacje, zobacz temat "Kompresja mapy bitowej" w dokumentacji zestawu SDK platformy.

Najpierw przykład wywołuje IMediaSample::GetPointer w celu pobrania adresów bazowych buforów. Przekazuje je do metody private EncoderFrame. Następnie wywołuje IMediaSample::SetActualDataLength w celu określenia długości zakodowanych danych. Filtr podrzędny wymaga tych informacji, aby mógł prawidłowo zarządzać buforem. Na koniec metoda wywołuje IMediaSample::SetSyncPoint, aby ustawić flagę ramki kluczowej na TRUE. Kodowanie długości przebiegu nie używa żadnych ramek delta, więc każda ramka jest ramką kluczową. W przypadku ramek różnicowych ustaw wartość na FALSE.

Inne problemy, które należy wziąć pod uwagę, obejmują:

  • Znaczniki czasowe. Klasa CTransformFilter znaczy czasem próbkę wyjściową przed wywołaniem metody Transform. Kopiuje wartości sygnatur czasowych z przykładu wejściowego bez ich modyfikowania. Jeśli filtr musi zmienić znaczniki czasowe, wywołaj metodę IMediaSample::SetTime dla próbki wyjściowej.

  • Zmiany formatu. Filtr nadrzędny może zmieniać formaty w trakcie strumienia, dołączając typ nośnika do próbki. Przed wykonaniem tej czynności wywołuje IPin::QueryAccept na wejściowym pinu filtru. W klasie CTransformFilter powoduje to wywołanie metody CheckInputType a następnie CheckTransform. Filtr podrzędny może również zmieniać typy multimediów przy użyciu tego samego mechanizmu. W swoim filtrze są dwie rzeczy, na które warto zwrócić uwagę:

    • Upewnij się, że QueryAccept nie zwraca fałszywych akceptacji.
    • Jeśli filtr akceptuje zmiany formatu, sprawdź je wewnątrz metody Transform, wywołując metodę IMediaSample::GetMediaType. Jeśli ta metoda zwraca S_OK, filtr musi odpowiadać na zmianę formatu.

    Aby uzyskać więcej informacji, zobacz Zmiany formatu dynamicznego.

  • Wątki. W przypadku zarówno CTransformFilter, jak i CTransInPlaceFilter, filtr przekształcania dostarcza próbki danych wyjściowych synchronicznie w metodzie Receive. Filtr nie tworzy żadnych wątków roboczych do przetwarzania danych. Zazwyczaj nie ma powodu, dla którego filtr przekształcania tworzy wątki robocze.

Następnie: Krok 6. Dodaj obsługę COM.

Tworzenie filtrów DirectShow