Podczas warunkowania strumienia do odtwarzania w trybie DASH losowe punkty dostępu muszą mieć dokładnie taki sam czas strumienia źródłowego we wszystkich strumieniach. Typowym sposobem na to jest wymuszenie stałej liczby klatek i stałej długości GOP (tj. Klatka kluczowa co N klatek).
W FFmpeg stała liczba klatek na sekundę jest łatwa (-r NUMBER).
Ale dla ustalonych lokalizacji klatek kluczowych (długość GOP) istnieją trzy metody ... która z nich jest „poprawna”? Dokumentacja FFmpeg jest frustrująco niejasna w tej kwestii.
Metoda 1: mieszanie się z argumentami libx264
-c:v libx264 -x264opts keyint=GOPSIZE:min-keyint=GOPSIZE:scenecut=-1
Wydaje się, że toczy się debata, czy scenariusz powinien zostać wyłączony, czy nie, ponieważ nie jest jasne, czy „licznik” klatki kluczowej zostanie ponownie uruchomiony, gdy nastąpi wycięcie sceny.
Metoda 2: Ustawienie stałego rozmiaru GOP:
-g GOP_LEN_IN_FRAMES
Jest to niestety udokumentowane tylko w dokumentacji FFMPEG, a zatem efekt tego argumentu jest bardzo niejasny.
Metoda 3: wstaw klatkę kluczową co N sekund ( może? ):
-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
Jest to wyraźnie udokumentowane. Ale nadal nie jest od razu jasne, czy „licznik czasu” uruchamia się ponownie po każdej klatce kluczowej. Na przykład, jeśli w oczekiwanym 5-sekundowym GOP, jeśli scenecut
libx264 ma wstrzyknąć klatkę kluczową 3 sekundy, czy następna klatka kluczowa miałaby 5 sekund później czy 2 sekundy później?
W rzeczywistości dokumentacja FFmpeg rozróżnia tę -g
opcję od opcji, ale tak naprawdę nie mówi, jak te dwie powyższe opcje są nieco inne (oczywiście -g
będzie wymagać stałej liczby klatek na sekundę).
Który jest poprawny?
Wydawałoby się, że -force_key_frames
byłby lepszy , ponieważ nie wymagałby stałej liczby klatek na sekundę. Wymaga to jednak tego
- jest zgodny ze specyfikacjami GOP w H.264 ( jeśli istnieje )
- GWARANTUJE, że istniałaby klatka kluczowa o stałej kadencji, niezależnie od
scenecut
klatek kluczowych libx264 .
Wydawałoby się również, że -g
nie mogłoby działać bez wymuszenia stałej liczby klatek na sekundę ( -r
) , ponieważ nie ma gwarancji, że wiele przebiegów ffmpeg
z różnymi argumentami kodeków zapewni tę samą chwilową liczbę klatek w każdej rozdzielczości. Stała liczba klatek na sekundę może obniżyć wydajność kompresji (WAŻNE w scenariuszu DASH!).
Wreszcie metoda po prostu wydaje się hackkeyint
. Mam nadzieję, że nie jest to prawidłowa odpowiedź.
Referencje:
Przykład z wykorzystaniem -force_key_frames
metody
źródło
ffprobe -i input.mp4 -select_streams v -show_frames -of csv -show_entries frame=pict_type
, a następnie kolorując komórki. Obawiam się, że nie ma publicznych dyskusji, ale zobaczę, czy uda mi się wykopać niektóre linki, które wtedy znalazłem.-force_key_frames expr:gte(t,n_forced*GOP_LEN_IN_SECONDS)
formularzem? Właśnie go wypróbowałem i odkryłem, że chociaż w strumieniu były dodatkowe ramki I, wydaje się, że DID przestrzega mojej reguły. Program PERL pojawi się jako „odpowiedź”, ponieważ najwyraźniej nie można używać znaczników w komentarzach.-force_key_frames
nie działało dla mnie, więc nigdy więcej nie spróbowałem. To było ponad rok temu. Być może był to błąd. Spróbuję wkrótce.Oto moje pięćdziesiąt centów za tę sprawę.
Generuj iframe tylko w pożądanych odstępach czasu.
Przykład 1:
Wygeneruj iframe zgodnie z oczekiwaniami:
Metoda 2 jest amortyzowana. Ommitted.
Przykład 2
Wygeneruj iframe w nieco inny sposób:
Jak widać, umieszcza iframe co 2 sekundy ORAZ w scenecut (sekundy z częścią ruchomą), co moim zdaniem jest ważne dla złożoności strumienia wideo.
Rozbierane rozmiary plików są prawie takie same. Bardzo dziwne, że nawet przy większej liczbie klatek kluczowych w Metodzie 3 generuje czasem mniej plików niż standardowy algorytm biblioteki x264.
Do generowania wielu plików bitrate dla strumienia HLS wybieramy metodę trzecią. Jest idealnie wyrównany z 2 sekundami między częściami, mają one iframe na początku każdej części i mają dodatkowe iframe w złożonych scenach, co zapewnia lepsze wrażenia dla użytkowników, którzy mają nieaktualne urządzenia i nie mogą odtwarzać wysokich profili x264.
Mam nadzieję, że to komuś pomoże.
źródło
Wydaje się zatem, że odpowiedź brzmi:
libx264
kątem działania, ale jest specyficzna i wiąże się z nią koszt wyeliminowania bardzo przydatnejscenecut
opcji wlibx264
.-g
wydaje się być przestarzała. Wydaje się, że nie działa, ani nie jest wyraźnie zdefiniowany w dokumentacji, ani nie znajduje się w pomocy, ani nie wydaje się, aby był używany w kodzie. Kontrola kodu pokazuje, że ta-g
opcja jest prawdopodobnie przeznaczona dla strumieni MPEG-2 (istnieją nawet zwrotki kodu odnoszące się do PAL i NTSC!).Również:
Skrypt dla
-force_key_frames
opcjiOto krótki program PERL, którego użyłem do weryfikacji kadencji I-frame na podstawie wyniku sugestii ffprobe z slhck. Wydaje się, że sprawdza, czy
-force_key_frames
metoda będzie również działać, i ma dodatkową zaletę polegającą na umożliwieniuscenecut
ramki. Absolutnie nie mam pojęcia, jak FFMPEG sprawia, że to działa, czy po prostu jakoś mi się poszczęściło, ponieważ moje transmisje są dobrze warunkowane.W moim przypadku zakodowałem przy 30 klatkach na sekundę z oczekiwanym rozmiarem GOP wynoszącym 6 sekund lub 180 klatek. Użyłem 180 jako argumentu gopsize dla tego programu, który weryfikował ramkę I przy każdej wielokrotności 180, ale ustawienie jej na 181 (lub dowolną inną liczbę nie będącą wielokrotnością 180) spowodowało, że narzeka.
źródło
force_key_frames
, to w pewnym sensie psuje algorytm alokacji bitów x264, więc może dać gorszą jakość niż po prostu ustawienie stałego interwału klatki kluczowej.-g
, mówisz: „Wygląda na to, że nie działa, ... ani nie wydaje się, aby był używany w kodzie”. Sprawdziłem i wejścieg
jest przechowywany wavctx->gop_size
i że libx264 korzysta z niego:x4->params.i_keyint_max = avctx->gop_size;
. Kiedy sonduję ten wygenerowany plik testowy:ffmpeg -i a-test-file.mp4 -g 37 -t 15 gtest.mp4
otrzymuję klatki kluczowe dokładnie0,37,74,111,148,185,222,259,296,333,370
. GOP może zostać skrócony, jeśli nastąpi zmiana sceny, i-sc_threshold
można to ustawić, co jest również wychwytywane przez x264.Chciałem tutaj dodać trochę informacji, ponieważ mój googling dość mocno przywołał tę dyskusję w mojej próbie znalezienia informacji o próbie znalezienia sposobu na segmentację mojego kodowania DASH tak, jak chciałem, i żadna z tych informacji nie była całkowicie poprawna.
Najpierw kilka nieporozumień, aby pozbyć się:
Nie wszystkie I-ramki są takie same. Istnieją duże ramki „I” i małe ramki „I”. Lub użyć poprawnej terminologii, ramek I IDR i ramek I innych niż IDR. Ramki I IDR (czasami nazywane „klatkami kluczowymi”) utworzą nowy GOP. Ramki inne niż IDR nie będą. Są przydatne, aby mieć wewnątrz GOP, gdzie następuje zmiana sceny.
-x264opts keyint=GOPSIZE:min-keyint=GOPSIZE
← To nie robi tego, co myślisz. Zajęło mi to trochę czasu. Okazuje się,min-keyint
że kod jest ograniczony. Nie może być większy niż(keyint / 2) + 1
. Tak więc przypisanie tej samej wartości do tych dwóch zmiennych skutkuje wartościąmin-keyint
przewróconą o połowę podczas kodowania.Oto rzecz: wycinanie scen jest naprawdę świetne, szczególnie w filmach z szybkimi cięciami. To sprawia, że jest ładny i wyraźny, więc nie chcę go wyłączać, ale jednocześnie nie mogłem uzyskać ustalonego rozmiaru GOP, dopóki był włączony. Chciałem włączyć wycinanie scen, ale chcę, aby używało tylko ramek I bez IDR. Ale to nie działało. Dopóki nie zorientowałem się (z wielu lektur) o nieporozumieniu # 2.
Okazuje się, że musiałem ustawić
keyint
podwoić mój pożądany rozmiar GOP. To znaczy żemin-keyint
można ustawić żądany rozmiar GOP (bez wewnętrznego kodu dzielącego go na pół), co zapobiega wykrywaniu sceny przy użyciu ramek I IDR wewnątrz rozmiaru GOP, ponieważ liczba klatek od ostatniej ramki I IDR zawsze mniej niżmin-keyinit
.I wreszcie ustawienie
force_key_frame
opcji zastępuje podwójny rozmiarkeyint
. Oto co działa:Wolę segmenty w 2-sekundowych porcjach, więc mój GOPSIZE = Framerate * 2
Możesz zweryfikować za pomocą ffprobe:
W wygenerowanym pliku CSV każda linia powie
frame, [is_an_IDR_?], [frame_type], [frame_number]
:Powoduje to, że powinieneś widzieć I-ramki IDR tylko w ustalonych
GOPSIZE
odstępach czasu, podczas gdy wszystkie inne ramki I są ramkami I innymi niż IDR wstawionymi w razie potrzeby przez wykrywanie wycięcia sceny.źródło
Wygląda na to, że ta składnia nie zawsze działa. Testowałem całkiem sporo na naszej zawartości VOD, jak również na żywo (zrzuty plików), a czasami scenecut nie działa i wyzwala pomiędzy nimi iframe:
Składnia dla konwersji w górę i50-> p50, 2 sek. Gop / segment, IDR na początku, iframe pomiędzy nimi w razie potrzeby
źródło
Twitch ma post na ten temat. Wyjaśniają, że postanowili skorzystać z własnego programu z kilku powodów; jednym z nich było to, że ffmpeg nie pozwala na uruchamianie różnych instancji x264 w różnych wątkach, ale zamiast tego poświęca wszystkie określone wątki jednej ramce na jednym wyjściu przed przejściem do następnego.
Jeśli nie korzystasz z transmisji strumieniowej w czasie rzeczywistym, masz więcej luksusu. „Prawidłowym” sposobem jest prawdopodobnie zakodowanie w jednej rozdzielczości tylko z rozmiarem GOP określonym za pomocą -g, a następnie zakodowanie innych rozdzielczości wymuszających klatki kluczowe w tych samych miejscach.
Jeśli chcesz to zrobić, możesz użyć ffprobe, aby uzyskać czasy klatki kluczowej, a następnie użyć skryptu powłoki lub rzeczywistego języka programowania, aby przekonwertować to na polecenie ffmpeg.
Jednak w przypadku większości treści różnica między jedną klatką kluczową co 5 sekund a dwiema klatkami kluczowymi co 5 sekund jest bardzo niewielka (jedna wymuszona, a druga ze scenariusza). Jest to około średniego rozmiaru ramki I w porównaniu do rozmiaru ramek P i ramek B. Jeśli używasz x264 z typowymi ustawieniami (jedyny powód, dla którego uważam, że powinieneś zrobić cokolwiek, aby na nie wpłynąć, to ustawienie -qmin, jako zły sposób na zapobieganie używaniu bitrate x264 dla łatwej zawartości; ogranicza to wszystkie typy ramek do tej samej wartości , Tak myślę) i uzyskaj wynik, taki jak średni rozmiar ramki I wynoszący 46 kB, ramkę P 24 kB, ramkę B 17 kB (o połowę częściej niż ramki P), a następnie dodatkową ramkę I co sekundę przy 30 fps to tylko 3% wzrost rozmiaru pliku. Różnica między h264 i h263 może składać się z 3% spadków, ale pojedynczy nie jest bardzo ważny.
W przypadku innych rodzajów treści rozmiary ramek będą się różnić. Szczerze mówiąc, chodzi o złożoność czasową, a nie złożoność przestrzenną, więc nie jest to po prostu łatwa zawartość a twarda treść. Ale ogólnie rzecz biorąc, witryny wideo z transmisją strumieniową mają limit bitrate, a treść ze stosunkowo dużymi ramkami I jest łatwą treścią, która będzie kodowana w wysokiej jakości bez względu na to, ile dodatkowych klatek kluczowych zostanie dodanych. To marnotrawstwo, ale marnotrawstwo zwykle nie zostanie zauważone. Najbardziej marnotrawnym przypadkiem jest prawdopodobnie wideo, które jest statycznym obrazem towarzyszącym utworowi, w którym każda klatka kluczowa jest dokładnie taka sama.
Jednej rzeczy, której nie jestem pewien, to jak wymuszone klatki kluczowe współdziałają z ogranicznikiem prędkości ustawionym za pomocą opcji -maxrate i -bufsize. Myślę, że nawet YouTube miał ostatnio problemy z prawidłową konfiguracją ustawień bufora, aby zapewnić stałą jakość. Jeśli używasz tylko średnich ustawień szybkości transmisji bitów, co widać na niektórych stronach (ponieważ możesz sprawdzić opcje x264 w nagłówku / mov atom? Za pomocą edytora szesnastkowego), to model bufora nie stanowi problemu, ale jeśli jesteś wyświetlając treści generowane przez użytkowników, średnia szybkość transmisji zachęca użytkowników do dodania czarnego ekranu na końcu filmu.
Opcja -g Ffmpeg lub dowolna inna używana opcja enkodera jest mapowana na opcję specyficzną dla enkodera. Zatem „-x264-params keyint = GOPSIZE” jest równoważne „-g GOPSIZE”.
Jednym z problemów z używaniem wykrywania scen jest to, że wolisz klatki kluczowe w pobliżu określonych liczb z jakiegokolwiek powodu. Jeśli określisz klatki kluczowe co 5 sekund i użyjesz wykrywania scen, a nastąpi zmiana sceny na 4.5, to powinna zostać wykryta, ale następna klatka kluczowa będzie na 9.5. Jeśli czas będzie się zwiększał w ten sposób, możesz skończyć z klatkami kluczowymi w 42,5, 47,5, 52,5 itd. Zamiast 40, 45, 50, 55. I odwrotnie, jeśli nastąpi zmiana sceny w 5.5, to będzie klatka kluczowa w 5 i 5,5 będzie za wcześnie na kolejną. Ffmpeg nie pozwala na określenie „utwórz tutaj klatkę kluczową, jeśli nie nastąpi zmiana sceny w ciągu następnych 30 klatek”. Jednak ktoś, kto rozumie C, może dodać tę opcję.
W przypadku wideo o zmiennej liczbie klatek na sekundę, gdy nie korzystasz z transmisji strumieniowej na żywo, takiej jak Twitch, powinieneś być w stanie korzystać ze zmian scen bez ciągłej konwersji na stałą częstotliwość klatek. Jeśli użyjesz filtru „select” w ffmpeg i użyjesz stałej „scene” w wyrażeniu, wówczas dane wyjściowe debugowania (-v debugowania lub naciśnij kilkakrotnie „+” podczas kodowania) pokazują numer zmiany sceny. Prawdopodobnie różni się to od liczby używanej przez x264 i nie jest tak przydatne, ale może być nadal przydatne.
Procedura prawdopodobnie polegałaby na zrobieniu filmu testowego, który dotyczyłby tylko zmian klatki kluczowej, ale może być wykorzystany do kontroli prędkości transmisji danych, jeśli używany jest 2-przebieg. (Nie jestem pewien, czy wygenerowane dane są w ogóle przydatne dla różnych rozdzielczości i ustawień; dane drzewa makrobloków nie będą.) Konwertuj je na wideo o stałej szybkości klatek, ale zobacz ten błąd dotyczący zacinania się wyjścia podczas zmniejszania liczby klatek na sekundę, jeśli kiedykolwiek zdecydujesz użyć filtra fps do innych celów. Uruchom go przez x264 z wybraną klatką kluczową i ustawieniami GOP.
Następnie użyj tych czasów klatek kluczowych z oryginalnym wideo o zmiennej liczbie klatek na sekundę.
Jeśli dopuścisz całkowicie szaloną zawartość generowaną przez użytkownika z 20-sekundową przerwą między ramkami, to w przypadku kodowania ze zmienną liczbą klatek na sekundę możesz podzielić dane wyjściowe, użyć filtra fps, w jakiś sposób użyć filtra select (być może zbudować naprawdę długie wyrażenie, które ma za każdym razem klatki kluczowej) ... a może możesz użyć testowego wideo jako wejścia i albo dekodować tylko klatki kluczowe, jeśli ta opcja ffmpeg działa, lub użyj filtra wyboru, aby wybrać klatki kluczowe. Następnie przeskaluj go do odpowiedniego rozmiaru (istnieje nawet filtr scale2ref) i nałóż na niego oryginalny film. Następnie użyj filtra przeplotu, aby połączyć te przeznaczone do wymuszenia klatki kluczowe z oryginalnym wideo. Jeśli wynikiem tego są dwie ramki, które są w odległości 0,001 s od siebie, że filtr przeplotu nie zapobiega, rozwiąż ten problem sam z innym wybranym filtrem. Głównym problemem może być obsługa limitów bufora ramki dla filtra przeplotu. Wszystko to może działać: użyć jakiegoś filtra do buforowania gęstszego strumienia (filtr FIFO?); odwołać się do pliku wejściowego wiele razy, więc jest dekodowany więcej niż jeden raz, a ramki nie muszą być przechowywane; użyj filtru „streamselect”, czego nigdy wcześniej nie robiłem, dokładnie w czasach klatek kluczowych; popraw filtr przeplotu, zmieniając jego domyślne zachowanie lub dodając opcję wyświetlania najstarszej ramki w buforze zamiast upuszczania ramki. czego nigdy nie zrobiłem, dokładnie w czasach klatek kluczowych; popraw filtr przeplotu, zmieniając jego domyślne zachowanie lub dodając opcję wyświetlania najstarszej ramki w buforze zamiast upuszczania ramki. czego nigdy nie zrobiłem, dokładnie w czasach klatek kluczowych; popraw filtr przeplotu, zmieniając jego domyślne zachowanie lub dodając opcję wyświetlania najstarszej ramki w buforze zamiast upuszczania ramki.
źródło