Jak bezstratnie zakodować sekwencję obrazów jpg na wideo w ffmpeg?

21

Mam duży zestaw plików JPG, które chcę bezstratnie przekonwertować na wideo (lub przynajmniej bardzo blisko bezstratnie, o ile czas kodowania nie jest znacznie dłuższy niż w innym przypadku).

Naiwnie sądzę, że powinien istnieć kodek, który może przechowywać każdą indywidualną ramkę jpg w stanie niezmienionym (bez ponownej kompresji) i być może osiągnąć pewną dobrą kompresję, zastępując niektóre ramki tylko informacjami o delcie z poprzedniej ramki. W moim przypadku istnieje wiele sekwencji ramek, które są identyczne lub mają niewielką różnicę między nimi.

Czy jest jakiś kodek i odpowiednie ustawienia dla ffmpeg, które mogą to osiągnąć?

GJ
źródło
Powiązane: avp.stackexchange.com/questions/4642/…
Friend Of George
Powiązane również: avp.stackexchange.com/questions/7300/…
Friend Of George
1
ciąg-JPEG-ów był kodekiem przez długi czas. Myślę, że aparaty cyfrowe, które nie używają h.264 niezmiennie rejestrują MJPEG, i karty przechwytujące wideo, które go używały.
Peter Cordes

Odpowiedzi:

24

Po prostu zmiksuj obrazy

Możesz po prostu zmiksować obrazy JPG, aby utworzyć wideo:

ffmpeg -framerate 30 -i input%03d.jpg -codec copy output.mkv

Zauważ, że jeśli pominiesz, -frameratewówczas -framerate 25do danych wejściowych zostanie zastosowana wartość domyślna .

Bezstratna optymalizacja

Możesz użyć jpegtrando bezstratnej optymalizacji każdej ramki, co może zapewnić znaczne oszczędności rozmiaru pliku:

mkdir outputdir
for f in *.jpg; do jpegtran -optimize -copy none -perfect -v "$f" > "outputdir/$f"; done

Teraz wymieszaj z ffmpegjak pokazano powyżej.

Sprawdzanie, czy faktycznie jest bezstratne

Framehash muxer mogą być wykorzystane w celu porównania unikalny hash każdej ramki, aby zapewnić, że wynik jest naprawdę bezstratne:

$ ffmpeg -i input%03d.jpg -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

$ ffmpeg -i output.mkv -map 0:v -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

W powyższych przykładach każda powiązana ramka dla wejścia i wyjścia ma ten sam skrót, zapewniając, że ramki są identyczne i że dane wyjściowe są bezstratne.

Zobacz także

Llogan
źródło
czy mógłbyś wyjaśnić, co te dwa framemd5polecenia mają osiągnąć poza zwykłą listą skrótów? jak uzyskać dodatkową kompresję, gdy w ten sposób zostaną zidentyfikowane identyczne ramki?
GJ.
1
Skróty zostały dołączone tylko po to, aby pokazać, że ramki są takie same jak poszczególne obrazy, dlatego spełnienie wymogu przechowywania „każdej indywidualnej ramki jpg w stanie, w jakim jest (bez rekompresji)”.
llogan
Wysłałem własną odpowiedź z niesprawdzonym pomysłem na upuszczenie zduplikowanych ramek, aby otrzymać VFR MJPEG.mkv. VFR to jedyny sposób na skorzystanie z tymczasowej redundancji w MJPEG. : P
Peter Cordes,
SSIM może być szybszym sposobem na porównanie wierności.
Gyan
11

Spowoduje to wygenerowanie bezstratnego wideo H.264, w którym klatki będą wykorzystywać informacje z innych klatek

ffmpeg -f image2 -r 30 -i %09d.jpg -vcodec libx264 -profile:v high444 -refs 16 -crf 0 -preset ultrafast a.mp4

Objaśnienie opcji:

  • -f image2 - mówi ffmpeg, aby wybrał grupę obrazów
  • -r 30 - mówi ffmpeg do kodowania z prędkością 30 klatek (lub obrazów) na sekundę (zmień to na żądaną szybkość klatek)
  • -i %09d.jpg- informuje ffmpeg, aby używał obrazów 000000000.jpg do 999999999.jpg jako danych wejściowych. Zmień 9in %09d.jpgna ile zer ma nazwa sekwencji obrazów. Jeśli twoje nazwy plików to na przykład img0001.jpg, wówczas będzie to wyrażone jako img% 04d.jpg
  • -vcodec libx264 - informuje ffmpeg, aby wyprowadzał dane do pliku zgodnego z H.264
  • -profile:v high444 - mówi libx264, aby używał profilu predykcyjnego bezstratnego High 4: 4: 4, umożliwiając bezstratne kodowanie
  • -refs 16 - mówi libx264, aby 16 buforów zapisało 16 obrazów, aby mogły się do nich odwoływać inne obrazy w filmie
  • -crf 0 - nakazuje libx264 wykonanie bezstratnego kodowania
  • -preset ultrafast - mówi libx264, aby priorytetem była szybkość kodowania nad rozmiarem pliku wyjściowego
  • a.mp4- informuje ffmpeg, aby zapisał dane wyjściowe w pliku MP4 o nazwie a.mp4. Zmień to na nazwę pliku i format, którego chcesz używać
Adam Chance
źródło
3
Kilka uwag: -f image2tutaj jest zbyteczne. Plik obrazu demuxer powinien używać -frameratezamiast -r. libx264 automatycznie wybierze odpowiednie -profiledla bezstratnych i -presetzajmie się tym -refs.
llogan
-refs 5w MOST, chyba że wiesz, że twoja treść ma identyczne obrazy oddzielone kilkoma innymi, co może spowodować, że x264 straci referencję, zanim dotrze do duplikatu. Wyższy niż ultrafastniewiele różni się w trybie bezstratnym, inny niż ~ 10% zysk CABAC w porównaniu z CAVLC (dla wysokiego kosztu procesora przy przepływności wymaganej dla bezstratnej). Poważnie, w niektórych działaniach na żywo 720x480p60 (wyjście z przeplotem), superfastbyło 28 GB, slowerbyło 27 GB. Jeśli czas kodowania nie ma znaczenia, ale czas dekodowania ma znaczenie, pamiętaj, aby unikać CABAC. Może nawet -tune fastdecode. Umiarkowana liczba referencji nie powinna boleć.
Peter Cordes,
A jeśli masz procesor do wypalenia, możesz nawet spróbować -preset placebouzyskać kilka dodatkowych ułamków procent.
DrYak,
Również dla kompletności h265 ma również swój własny tryb bezstratny. -vcodec libx265 -x265-params lossless=1jest równoważną opcją. (Ale z mojego doświadczenia (= nagrywanie prezentacji pokazu slajdów Powerpoint), niekoniecznie jest to lepsze i jest znacznie wolniejsze niż h264) Bądź na bieżąco z przyszłoroczną AVOM A1 / IETF NETVC1 / Xiph Daala / cokolwiek, do tego czasu zostanie zmieniona ... tryb bezstratny
DrYak
5

Możesz utworzyć avianimację jako serię pngobrazów ( png jest bezstratna, więc jpeg => pngkonwersja nie powinna degradować twoich zdjęć):

jeśli twoje zdjęcia są nazwane img_0001.jpg

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec png video.avi

gdzie „25” to żądana liczba klatek na sekundę w powstałym filmie. -start_numbernie jest potrzebny, jeśli jest to 1, ale jest przydatny, jeśli Twój pierwszy numer wideo nie jest 1.

Jeśli chcesz zakodować za mjpegpomocą wiersza polecenia najwyższej jakości:

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec mjpeg -qscale 1 video.avi

Zaletą tego jest to, że możesz przekonwertować wideo z powrotem na serię zdjęć:

ffmpeg -i video.avi "img_series_%04d.png"
ffmpeg -i video.avi "img_series_%04d.jpg"

itp...

Olivier S.
źródło
To naprawdę nie spełnia wymagań osób pytających. Szuka sposobu, aby ramkę można było bezstratnie aktualizować tylko po zmianie obrazu. Oznacza to, że ten sam obraz może być użyty więcej niż jeden raz. Również JPEG z natury nie jest bezstratny, ponieważ uważam, że używa kompresji JPEG nawet przy maksymalnej jakości.
AJ Henderson
Wydaje mi się, że był gotowy na kompresję, choć nie jestem pewien, jak to będzie wyglądać na długich sekwencjach tej samej klatki. Nadal uważam, że potrzebny jest format prezentacji ze zmienną liczbą klatek na sekundę, choć nie jestem pewien, czy ffmpeg go obsługuje.
AJ Henderson
CorePNG może również tworzyć ramki P. Zazwyczaj jpeg nie jest kompresją bezstratną i wątpię, czy mjpeg może tworzyć ramki P. Zgadzam się, że nie odpowiadam na zadane pytanie, ale daję rozwiązanie, aby mieć bezstratne wideo z ffmpeg.
Olivier S
4

Aby rozwinąć odpowiedź LordNeckbearda, tak, po prostu zmiksuj dane JPEG w strumieniu wideo MJPEG. Będzie to najmniejsza reprezentacja dokładnej sekwencji obrazów wyjściowych, mimo że MJPEG jest okropnie nieefektywnym kodekiem według dzisiejszych standardów. (brak czasowej redundancji, a nawet brak prognoz wewnętrznych).

Możesz utworzyć wideo MJPEG ze zmienną liczbą klatek na sekundę, aby wykorzystać zduplikowane obrazy na wejściu.

ffmpeg -framerate 30 -i input%03d.jpg -vf mpdecimate -codec copy output.mkv  # doesn't work.

Hmm, to nie zadziała, ponieważ mpdecimate nie będzie działać na skompresowanych danych i nie możemy pozwolić, aby ffmpeg zdekodował, a następnie ponownie JPEG zdjęć bez strat i kosztów procesora.

Może jeśli zastąpisz zduplikowane pliki źródłowe jpg pustymi plikami o tym numerze sekwencji lub coś takiego?

Ponieważ to pytanie nie jest jeszcze aktualne, nie będę się zastanawiać, jak to zrobić, chyba że ktoś odpowie na pytanie, jak to zrobić. Ale ponieważ MJPEG może przejść do kontenera mkv, jestem pewien, że możliwe jest posiadanie pliku, który nie powiela danych jpeg dla powtarzających się ramek, ale zamiast tego nie ma ramki wyjściowej do zdekodowania, dopóki sekwencja duplikatów nie będzie koniec.

Och, oto pomysł:

ffmpeg -framerate blah -input blah -vf mpdecimate -f mkvtimestamp_v2 mpdecimate.timestamps

Następnie usuń (lub przenieś na bok) wszystkie pliki JPEG dla ramek, które mpdecimate chce upuścić (prawdopodobnie ma kilka opcji rejestrowania? Lub -vf showinfo i przeanalizuj to, i przenieś lub dowiązaj tylko ramki, które pojawiają się na wyjściu, pozostawiając za sobą upuszczone pliki JPEG?). prześlij to do pliku MJPEG.mkv, a następnie zrób coś z mkvmerge, aby zastąpić znaczniki czasu ramki znacznikami czasu z mpdecimate.timestamps.

Gdybyś był kodowaniem x, zamiast po prostu miksować dane jpeg do MJPEG, byłoby to DUŻO łatwiejsze, ponieważ użyłbyś mojej pierwszej komendy z mpdecimate i dowolnym innym kodekiem innym niż copyi działałoby to po prostu (tm).

Nie próbowałem tego, ponieważ było to stare pytanie. Również powód, dla którego nie uzupełniałem luk w sposobie filtrowania katalogu plików JPEG w oparciu o dane wyjściowe mpdecimate lub w jaki sposób faktycznie korzystać ze strumienia sygnatury czasowej.

Peter Cordes
źródło