Jak wymusić, aby pierwsza klatka była klatką kluczową?

2

Chcę zakodować po wyszukaniu określonej pozycji i chcę, aby pierwsza klatka była klatką kluczową, tutaj użyłem polecenia:

ffmpeg -ss 300  -i howimet.mp4 -acodec libfaac -ar 48000 -ab 128k -ac 2  -vcodec libx264 -vf "scale=480:270" -f mpegts -force_key_frames 300 -t 120 howimet2.ts

-force_key_frames jest ustawiony na szukanie pozycji, aby utworzyć tam klatkę kluczową. Używam następującego skryptu ( stąd ), aby sprawdzić, czy pierwsza klatka jest klatką kluczową

ffprobe -show_frames -v quiet howimet2.ts | awk -F= '   /pict_type=/ { if (index($2, "I")) { i=1; } else { i=0; } } 
  /pkt_pts_time/ { if (i && ($2 >= 0)) print $2; }  
' | head -n 1

Wynik pokazuje, że pierwsza klatka kluczowa nie jest zlokalizowana w drugim 0.

Wydaje mi się, że moje polecenie jest nieprawidłowe. czego mi brakuje?

jackode
źródło
Nie powinieneś nic robić, aby zmusić koder do utworzenia pierwszej klatki jako klatki kluczowej. Naprawdę nic innego nie miałoby sensu. Zauważ też, że -force_key_framespowinno być względne w stosunku do danych wejściowych, więc 300 też nie ma sensu - powinno być 0, jeśli się nie mylę. Czy wideo jest w porządku, czy dlaczego pytasz? (Innymi
słowy
mam taki sam wynik z -force_key_frames 0. Powodem, dla którego tego chcę, jest implementacja segmentatora ffmpeg, który będzie generował segment HSL w locie. Gdy użytkownik szuka pozycji, segmentator powinien być w stanie wygenerować odpowiedni segment; segment zostanie wysłany do odtwarzacza klienta (odtwarzacz filmów na iOS); domyślnie odtwarzacz rozpocznie odtwarzanie od pierwszej klatki kluczowej w odebranym segmencie. Chcę, aby gracz zaczął grać od pierwszej klatki. Mam nadzieję, że moje wyjaśnienie ma sens
jackode
Widzę. Muszę przyznać, że nie jestem ekspertem w dziedzinie przesyłania strumieniowego, ale tak naprawdę nie ma powodu, aby koder nie używał klatki kluczowej jako pierwszej klatki. Jeśli użyjesz -vcodec libx264, FFmpeg zrobi to, co otrzyma zdekodowane zdjęcie, poda je do x264, a pierwszą rzeczą, którą zrobi x264, jest utworzenie klatki kluczowej. Nie można rozpocząć filmu z ramką bez odniesienia. Jeśli ręcznie sprawdzisz wynik ffprobe, co to powie o pierwszej ramce?
slhck
powyższy kod skryptu ffprobe powiedział, że pierwsza kframe jest gdzieś na drugim 1.441711. ffprobe -v quiet -print_format json -show_streams howimet2.tsmówi mi to "start_time": "1.400000", czy to jest powód?
jackode
1
Tak, w twoim przypadku początkowy PTS (i czas) mają przesunięcie. Nie wiem, dlaczego tak się dzieje, ale powinieneś być w stanie zrekompensować przesunięcie, odejmując je.
slhck

Odpowiedzi:

4

Podczas kodowania wideo pierwsza klatka musi być klatką kluczową. Będzie to pierwsza w pełni zakodowana, a kolejne ramki mogą jej używać do przewidywania między ramkami. Ponadto na początku zakodowanej sekwencji wideo będzie dostępna jednostka dostępu H.264, która nakazuje dekoderowi odświeżenie.

Niezależnie od tego, co robisz: chyba że skopiujesz strumień bitów, ponownie kodujesz wideo, a Twoja pierwsza klatka musi być klatką kluczową.

Teraz, z jakiegokolwiek powodu, twój strumień ma przesunięcie w czasie rozpoczęcia. Oznacza to, że wszystkie znaczniki czasu prezentacji są również przesuwane zgodnie z tym przesunięciem. Jeśli sprawdzisz nagłówek ffprobe -show_frameswyjścia, zobaczysz, że klatka 0 rzeczywiście będzie klatką kluczową, ale z innym PTS.

Aby to zrekompensować, możesz odjąć czas rozpoczęcia od wszystkich PTS.

slhck
źródło
Pierwsza ramka nie musi być ramką I (KeyFrame), może to być ramka B (zależna od przyszłych ramek, z których jedna prawdopodobnie będzie ramką I).
Adisak
@Adisak To nieprawda. Jeśli pierwsza zakodowana ramka nie jest ramką I, dekoder nie może rozpocząć dekodowania, ponieważ ma tylko różnice predykcyjne, ale nie ma rzeczywistego sygnału. Obraz AB lub P zawsze ma co najmniej jedną ramkę odniesienia, którą należy najpierw zdekodować.
slhck
0

Jak wspomniano, pierwszą klatką filmu musi być I-Frame. Twój problem pochodzi nie z kodowania (lub kopiowania, jeśli taki jest twój gust), ale z dekodowania. Posiadanie -ss przed wejściem jest niedokładne, więc ffmpeg robi wszystko, co w jego mocy, aby dostać się tam, gdzie chcesz. Ffmpeg przekazał tę lokalizację, a zatem podaje niezerowy pierwszy znacznik czasu.

Poleciłbym wypróbowanie drugiego -ss po twoim -i. Wzdłuż linii -ss 299 -i wpisz -ss 1.

Oznacza to, że przejdź do wybranej lokalizacji, a następnie dekoduj przez 1 sekundę przed przetworzeniem. Nie jestem pewien, czy to rozwiąże problem z pts, ale mam nadzieję, że poprowadzi cię we właściwym kierunku.

Aby wskazać, nie sądzę, że polecenie force_key_frames robi to, co myślisz. Jeśli coś robi, prawdopodobnie po prostu każe mu dodawać klatkę kluczową do wyjścia co 300 sekund, ale to tylko przypuszczenie. Oznacza to, że tylko pierwsza ramka wyniku byłaby ramką kluczową (t = 120).

https://ffmpeg.org/ffmpeg.html

dstob
źródło
0

Ustaw rozmiar GOP za pomocą „-g”

Aby pokazać dokładność, oto 1-sekundowy segment

ffmpeg -i  in.mkv -g 30  -hls_time 1 -hls_list_size 0 index.m3u8

Oto jak wygląda m3u8:

    #EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:1.001000,
index0.ts
#EXTINF:1.001000,
index1.ts
#EXTINF:1.001000,
index2.ts
#EXTINF:1.001000,
index3.ts
#EXTINF:1.001000,
index4.ts
#EXTINF:1.001000,
index5.ts
#EXTINF:1.001000,
index6.ts
#EXTINF:1.001000,
index7.ts
#EXTINF:1.001000,
index8.ts
#EXTINF:1.001000,
index9.ts
#EXTINF:1.001000,
index10.ts
#EXTINF:1.001000,
index11.ts
#EXTINF:1.001000,
index12.ts
#EXTINF:1.001000,
index13.ts
#EXTINF:1.001000,
....
Leroy Scandal
źródło