Udostępnij przez


Tworzenie niestandardowego źródła multimediów

W tym temacie opisano sposób implementowania niestandardowego źródła multimediów w programie Microsoft Media Foundation. Zawiera on następujące sekcje:

Tworzenie deskryptora prezentacji

Metoda IMFMediaSource::CreatePresentationDescriptor zwraca kopię deskryptora prezentacji źródła. Aby utworzyć deskryptor prezentacji, musisz znać liczbę strumieni w zawartości źródłowej oraz możliwe formaty każdego strumienia. Dla każdego strumienia utwórz deskryptor strumienia w następujący sposób:

  1. Utwórz tablicę typów multimediów. Każdy typ nośnika w tablicy reprezentuje możliwy format strumienia. Aby uzyskać więcej informacji na temat tworzenia typów multimediów, zobacz Typy multimediów.
  2. Wywołaj MFCreateStreamDescriptor, aby utworzyć deskryptor strumienia. Przekaż tablicę typów multimediów. Funkcja zwraca wskaźnik IMFStreamDescriptor.
  3. Wywołaj IMFStreamDescriptor::GetMediaTypeHandler, aby pobrać menedżera typów multimediów deskryptora strumieniowego.
  4. Wywołaj IMFMediaTypeHandler::SetCurrentMediaType, aby ustawić domyślny format strumienia. Użyj jednego z typów multimediów utworzonych w kroku 1. Ogólnie rzecz biorąc, należy użyć formatu z najwyższą jakością.
  5. Opcjonalnie ustaw atrybuty dla deskryptora strumienia. Aby uzyskać listę atrybutów, które mają zastosowanie do deskryptorów strumienia, zobacz Atrybuty deskryptora strumienia.

Teraz utwórz deskryptor prezentacji:

  1. Wywołaj MFCreatePresentationDescriptor i przekaż tablicę deskryptorów strumienia. Funkcja zwraca wskaźnik IMFPresentationDescriptor.
  2. Wybierz domyślny wybór strumienia, wywołując IMFPresentationDescriptor::SelectStream, aby wybrać co najmniej jeden strumień. W konfiguracji domyślnej należy wybrać co najmniej jeden strumień.
  3. Ustaw atrybuty deskryptora prezentacji, opcjonalnie. Aby uzyskać listę atrybutów, które mają zastosowanie do deskryptorów strumienia, zobacz Atrybuty deskryptora prezentacji.

Deskryptor prezentacji należy utworzyć raz przy uruchamianiu lub po przeanalizowaniu przez źródło wystarczającej ilości danych źródłowych, aby określić zawartość. Metoda CreatePresentationDescriptor powinna zwrócić kopię deskryptora prezentacji. Aby utworzyć kopię, wywołaj metodę IMFPresentationDescriptor::Clone. Zwracanie kopii uniemożliwia klientowi modyfikowanie stanu deskryptora oryginalnej prezentacji, takiego jak atrybuty lub wybór strumienia. Należy jednak pamiętać, że Clone tworzy płytkią kopię, dzięki czemu klient może potencjalnie modyfikować deskryptory bazowego strumienia.

Uruchamianie źródła multimediów

Metoda IMFMediaSource::Start uruchamia źródło multimediów lub szuka nowej pozycji. Wywołanie Start powoduje wyszukiwania, gdy poprzedni stan został wstrzymany lub uruchomiony, a określono nowy czas rozpoczęcia. W przeciwnym razie metoda Start powoduje uruchomienie . Po zakończeniu operacji Start wyślij następujące zdarzenia.

  1. Wyślij zdarzenie MENewStream dla każdego nowego strumienia — oznacza to, że każdy strumień, który został wcześniej wybrany i jest teraz wybrany. Dane dotyczące zdarzenia są wskaźnikiem do strumienia.
  2. Wyślij zdarzenie MEUpdatedStream dla każdego strumienia, który był wybrany wcześniej i jest nadal wybrany. Dane zdarzenia są wskaźnikiem do strumienia. (Nie wysyłaj zdarzenia dla odznaczonych strumieni).
  3. Jeśli źródło poszukuje, wyślij zdarzenie MESourceSeeked. W przeciwnym razie wyślij zdarzenie MESourceStarted. Dane zdarzenia to godzina rozpoczęcia określona w metodzie Start. W przypadku zdarzenia MESourceStarted, jeśli godzina rozpoczęcia jest VT_EMPTY, ustaw na zdarzeniu atrybut MF_EVENT_SOURCE_ACTUAL_START. Wartość atrybutu to rzeczywisty czas rozpoczęcia.
  4. Dla każdego strumienia, jeśli źródło poszukuje, wyślij zdarzenie MEStreamSeeked. W przeciwnym razie wyślij zdarzenie MEStreamStarted. Dane zdarzenia to godzina rozpoczęcia. (Źródło multimediów może kolejkować zdarzenie w strumieniu, wywołując metodę IMFMediaEventGenerator::QueueEvent).

Po odznaczeniu strumienia zamknij go. Strumień nie powinien kolejkować więcej zdarzeń w tym momencie.

Format czasu dla metody Start jest podany w parametrze pguidTimeFormat. Format czasu standardowego, wskazywany przez GUID_NULL, to 100-nanosekundowe jednostki. Źródło multimediów musi obsługiwać ten format czasu.

Poszukiwanie

Podczas wyszukiwania żądana pozycja początkowa może nie należeć do dokładnej granicy próbki. Ponadto w przypadku skompresowanej zawartości pozycja początkowa może znajdować się pomiędzy klatkami kluczowymi. Strumień powinien dostarczać próbki z najwcześniejszego punktu potrzebnego do utworzenia nieskompresowanej próbki na żądanej pozycji początkowej. W przypadku wideo oznacza to rozpoczęcie od poprzedniej klatki kluczowej. Rurociąg jest odpowiedzialny za usunięcie dodatkowych ramek z dekodera, aby odtwarzanie rozpoczynało się w żądanym czasie.

Czas rozpoczęcia podany w zdarzeniach źródłowych (MESourceStarted, MESourceSeeked, MEStreamStartedi MEStreamSeeked) jest tożsam z żądanym czasem rozpoczęcia (wartość podana w metodzie Start), niezależnie od rzeczywistej pozycji początkowej.

Załóżmy na przykład, że kilka pierwszych ramek strumienia wideo ma następujące cechy:

Próbka 1 2 3 4
Czas 33 msec 66 msec 100 msec 133 msec
Klatka kluczowa? Tak Nie Nie Tak

 

Jeśli metoda Start jest wywoływana z wartością 100 milisekund, źródło musi wyświetlić wideo wyjściowe począwszy od ramki 1, pierwszej ramki klucza przed tym czasem. Zdarzenie początkowe nadal będzie wskazywać 100 milisekund w danych zdarzenia.

Pauzowanie źródła multimediów

Metoda IMFMediaSource::Pause wstrzymuje źródło multimediów.

Gdy źródło jest wstrzymane, strumień może tworzyć nowe próbki i przechowywać je w kolejce, ale ich nie dostarcza. Oto kilka wyjątków od tej reguły:

  • Źródła na żywo powinny usuwać dane podczas wstrzymania.
  • Jeśli źródło pobiera dane z sieci, może wstrzymać serwer.

Jeśli klient wywołuje IMFMediaStream::RequestSample podczas wstrzymania źródła, żądanie jest również kolejkowane do momentu ponownego uruchomienia źródła. Żądania nie powinny być odrzucane.

Wstrzymanie jest dozwolone tylko ze stanu uruchomionego. W przeciwnym razie wstrzymaj powinna zwrócić MF_E_INVALID_STATE_TRANSITION.

Generowanie danych źródłowych

Media Foundation używa modelu pull , co oznacza, że strumienie generują i dostarczają próbki w odpowiedzi na żądania z potoku. Strumień może dostarczać próbki, gdy źródło multimedialne jest uruchomione, a strumień jest wybrany. Strumień dostarcza dane tylko wtedy, gdy klient zażąda nowego przykładu.

Przykładowe żądania

Klient żąda nowego przykładu, wywołując IMFMediaStream::RequestSample. Oto sekwencja operacji:

  1. Klient wywołuje IMFMediaStream::RequestSample. Argument jest wskaźnikiem do obiektu opcjonalnego tokenu , którego klient używa do śledzenia żądania. Klient implementuje token. Tokeny muszą uwidaczniać interfejs IUnknown. Klient może również przekazać wskaźnik o wartości NULL zamiast tokenu.

  2. Jeśli klient dostarczył token, strumień multimediów wywołuje AddRef na tokenie i umieszcza token w kolejce FIFO (pierwsze weszło, pierwsze wyszło). Metoda zwraca, a pozostałe kroki są wykonywane asynchronicznie.

  3. Gdy dostępnych jest więcej danych, strumień multimediów tworzy nową próbkę. (Ten krok został opisany bardziej szczegółowo w następnej sekcji).

  4. Strumień multimediów pobiera pierwszy token z kolejki.

  5. Jeśli token nie jest NULL, strumień multimediów ustawia atrybut MFSampleExtension_Token w próbie multimedialnej. Wartość atrybutu jest wskaźnikiem do tokenu.

  6. Strumień multimediów wysyła zdarzenie MEMediaSample. Dane zdarzenia to wskaźnik na interfejs IMFSample obiektu próbki.

  7. Jeśli klient dostarczył token, strumień multimediów wywołuje Release na obiekcie tokenu.

Jeśli strumień multimediów nie może spełnić żądania klienta RequestSample, ściąga token z kolejki i wywołuje Release na tokenie, ale nie wysyła MEMediaSample event.

Klient może użyć tokenu do śledzenia stanu żądania. Gdy klient odbiera zdarzenie MEMediaSample, może pobrać token z próbki i dopasować go do oryginalnego żądania. Klient może również użyć tokenu, aby wykryć, czy źródło multimediów porzuciło żądanie. Jeśli liczba odwołań tokenu spadnie do zera, a strumień multimediów nie wysyła zdarzenia MEMediaSample, oznacza to, że żądanie zostało odrzucone.

Kroki wymienione w tym miejscu zakładają, że RequestSample metoda jest implementowana jako operacja asynchroniczna. Jeśli metoda jest synchroniczna, nie trzeba umieszczać tokenu żądania w kolejce. Jeśli jednak generowanie danych zajmuje znaczną ilość czasu, zalecane jest podejście asynchroniczne — na przykład jeśli źródło odczytuje dane ze strumienia bajtowego.

Strumień jest odpowiedzialny za buforowanie wszystkich danych, które gromadzą się między wywołaniami RequestSample.

Gdy strumień multimediów dociera do końca, wysyła zdarzenie MEEndOfStream po ostatniej próbce. Po zakończeniu każdego strumienia źródło multimediów wysyła zdarzenie MEEndOfPresentation. Po wysłaniu zdarzenia MEEndOfStream przez strumień multimediów, metoda RequestSample zwraca MF_E_END_OF_STREAM do momentu ponownego uruchomienia źródła.

Przydzielanie przykładów

Gdy strumień jest gotowy do wypełnienia oczekującego żądania próbki, tworzy nową próbkę i dodaje do niej jeden lub więcej buforów multimedialnych. Aby uzyskać więcej informacji na temat tworzenia buforów multimediów, zobacz Bufory multimediów.

Strumień musi ustawić sygnaturę czasową i czas trwania, jeśli jest on znany. Sygnatura czasowa jest względna względem źródła. W większości przypadków początek zawartości odpowiada sygnaturze czasowej zero. Jeśli na przykład źródło odczytuje z pliku multimedialnego, początek pliku będzie miał sygnaturę czasową o wartości zero.

Sygnatura czasowa w przykładzie nie musi być równa czasowi prezentacji. Sesja multimedialna tłumaczy czas źródłowy na czas prezentacji. W przypadku skompresowanych danych strumień powinien generować dane rozpoczynające się od najbliższej ramki klucza przed godziną rozpoczęcia. Dzięki temu dekoder może dostarczyć klatkę wyświetlaną w żądanym momencie rozpoczęcia. (W przeciwnym razie dekoder musi poczekać na następną ramkę kluczową).

Jeśli szybkość odtwarzania jest szybsza lub wolniejsza niż 1,0, potok dostosowuje częstotliwość zegara prezentacji. Źródło nie dostosowuje sygnatur czasowych na próbkach.

Źródło może ustawić dodatkowe informacje na temat przykładu, ustawiając atrybuty. Aby uzyskać listę przykładowych atrybutów, zobacz Przykładowe atrybuty.

Luki w strumieniu

Jeśli strumień zawiera lukę o znacznej długości, zaleca się, aby strumień wysyłał zdarzenie MEStreamTick. To zdarzenie powiadamia klienta, że brakuje próbki. Dane zdarzenia to sygnatura czasowa brakującej próbki w 100-nanosekundowych jednostkach (VT_I8). To zdarzenie może uchronić komponenty w dalszej części procesu przed oczekiwaniem na próbki, które nie zostaną dostarczone. Strumień może wysyłać dowolną liczbę zdarzeń MEStreamTick w razie potrzeby, aby wypełnić lukę w strumieniu.

Zamykanie źródła multimediów

Po zakończeniu korzystania ze źródła multimediów klient wywołuje IMFMediaSource::Shutdown. Wewnątrz tej metody źródło nośnika powinno przerwać wszystkie cykliczne liczby odwołań. Zazwyczaj istnieją odwołania cykliczne między źródłem multimediów a strumieniami multimediów.

Jeśli używasz kolejki zdarzeń do implementowania IMFMediaEventGenerator, wywołaj IMFMediaEventQueue::Shutdown w kolejce zdarzeń. Ta metoda wyłącza kolejkę zdarzeń i sygnalizuje każdemu wywołującemu, który aktualnie czeka na zdarzenie.

Po zamknięciu wszystkie metody na źródle zwracają MF_E_SHUTDOWN, z wyjątkiem metod IUnknown.

Źródła na żywo

Począwszy od systemu Windows 7, program Media Foundation automatycznie obsługuje urządzenia do przechwytywania audio i wideo. W przypadku wideo urządzenie musi zapewnić minidriver jądra przesyłania strumieniowego (KS) w kategorii przechwytywania wideo. Program Media Foundation używa ścieżki PnP do wyliczania urządzenia. W przypadku dźwięku program Media Foundation używa interfejsu API urządzenia multimedialnego z systemem Windows (MMDevice) do wyliczania urządzeń punktu końcowego audio. Jeśli urządzenie spełnia te kryteria, nie ma potrzeby implementowania niestandardowego źródła multimediów.

Można jednak zaimplementować niestandardowe źródło multimediów dla innego typu urządzenia lub innego źródła danych na żywo. Istnieje tylko kilka różnic między źródłem na żywo a innymi źródłami multimediów:

  • W metodzie IMFMediaSource::GetCharacteristics zwróć flagę MFMEDIASOURCE_IS_LIVE.
  • Pierwsza próbka powinna mieć sygnaturę czasową zero.
  • Zdarzenia i stany streamingu są obsługiwane tak samo jak źródła multimediów, z wyjątkiem stanu pauzy.
  • Podczas zatrzymania nie należy kolejkować próbek. Usuń wszystkie dane wygenerowane podczas pauzy.
  • Źródła na żywo zwykle nie obsługują wyszukiwania, odtwarzania odwrotnego ani kontroli szybkości.

źródła multimediów

Samouczek : Tworzenie niestandardowego źródła multimedialnego