Jak nagrać strumień video w formacie m3u8 z konwersją do mp4?

Posiadam konto shell z dostępem przez ssh. Chciałbym w wybranych godzinach nagrać obraz video z kamery znajdującej się na stronie internetowej. Strumień jest w formacie m3u8, a chciałbym, aby został zapisany w formacie mp4.

Jakim poleceniem, przy użyciu wget i crona, zaplanować takie nagrywanie z automatyczną konwersją?

Plik m3u8 to tylko manifest strumienia - zawiera odwołanie do plików TS, z których składa się strumień.
Mp4 to tylko kontener, jeśli źródłowy strumień zawiera video w formacie H.264 i audio AAC to wystarczy go muxować, bez konwersji.

Proponuję użyć biblioteki ffmpeg:
ffmpeg -y -i adres_zrodlowy_m3u8 -c:v copy -c:a copy -o plik_docelowy.mp4

Takie polecenie zaciągnie video i audio ze źródła i zacznie zapisywać je do pliku .mp4

Możesz też uruchomić polecenie tak, aby po pewnym czasie zatrzymało nagrywanie, przykład z nagraniem do 1h:

ffmpeg -y -i adres_zrodlowy_m3u8 -to 01:00:00 -c:v copy -c:a copy plik_docelowy.mp4

1 polubienie

Działa znakomicie.
Dziękuję bardzo! :slight_smile:

No proszę warto wiedzieć

@MatX1, pozwolę sobie dopytać o jeszcze jedną rzecz. Czy w tym poleceniu da się, przy użyciu odpowiednich parametrów, sprawić, by nagrany plik mp4 był bez dźwięku oraz w rozdzielczości 480p? Jeśli tak, to jak powinno wyglądać takie zmodyfikowane polecenie?

1 polubienie

Jasne, jak najbardziej da się to zrobić:

ffmpeg -y -i adres_zrodlowy_m3u8 -an -c:v libx264 -preset veryfast -crf 23 -filter:v „scale=-2:480” plik_docelowy.mp4

To polecenie zignoruje audio i będzie transkodowało w locie strumień źródłowy video do H.264 z przyzwoitą jakością i rozdzielczością 480p.
Pamiętaj jednak, że transkodowanie video (w przeciwieństwie do zwykłego muxowania) to proces bardzo zasobożerny pod względem CPU, więc na publicznym shellu może to nie być dozwolone.

parametr „preset” odpowiada za to jak efektywne jest kodowanie. Im wolniejszy preset tym większe obciążenie CPU, ale jednocześnie mniejszy plik wynikowy.
-crf pozwala na dopasowanie oczekiwanej jakości, im wyższy tym gorsza jakość, ale mniejszy plik.
Pokombinuj z tymi parametrami, aby znaleźć złoty środek.

Poniżej jeszcze lista presetów i ogólnie dokumentacja H.264 do ffmpega:
http://trac.ffmpeg.org/wiki/Encode/H.264

@MatX1, w którym miejscu powinienem umieścić parametr określający, ile czasu ma trwać nagrywanie?

Gdziekolwiek, byle przed plikiem wyjściowym.

Jeszcze protip:
Proponuję zamiast .mp4 użyć kontenera .ts.
Niepoprawnie zapisany plik mp4 np. wskutek crashu programu będzie bezużyteczny.
Zamieniając kontener na mpegts masz pewność, że dotychczas zapisane nagranie będzie możliwe do odtworzenia (kosztem trochę większego overheada pliku)

@MatX1, wpisałem następujące zadanie cron:

00 22 * * * ffmpeg -y -i https://1808506050.rsc.cdn77.org/live/studiorw/chunklist.m3u8 -an 00:05:00 -c:v libx264 -preset veryfast -crf 23 -filter:v „scale=-2:480” /home/rostov/JW/live.mp4

ale po podanych 5 minutach nie otrzymałem we wskazanej lokalizacji żadnego pliku wynikowego. Czy coś zrobiłem źle?

-o przed nazwą pliku wyjściowego

Zapomniałeś podać „-to” przed czasem.

Nie, przy ffmpegu nie podaje się „-o”, tutaj mój błąd kilka postów wyżej :wink:

@MatX1, w podanej lokalizacji pojawił się plik wynikowy live.mp4, ale wielkości 0 bajtów.

From rostov  Thu Sep  9 22:48:00 2021
From: Cron Daemon <rostov@s0.small.pl>
To: rostov
Subject: Cron <rostov@s0.small.pl> ffmpeg -y -i https://1808506050.rsc.cdn77.org/live/studiorw/chunklist.m3u8 -an -to 00:05:00 -c:v libx264 -preset veryfast -crf 23 -filter:v „scale=-2:480” /home/rostov/JW/live.mp4
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/rostov>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin>
X-Cron-Env: <LOGNAME=rostov>
X-Cron-Env: <USER=rostov>

ffmpeg version 4.3.1 Copyright (c) 2000-2020 the FFmpeg developers
  built with FreeBSD clang version 10.0.1 (git@github.com:llvm/llvm-project.git llvmorg-10.0.1-0-gef32c611aa2)
  configuration: --prefix=/usr/local --mandir=/usr/local/man --datadir=/usr/local/share/ffmpeg --pkgconfigdir=/usr/local/libdata/pkgconfig --enable-shared --enable-pic --enable-gpl --enable-avresample --cc=cc --cxx=c++ --disable-alsa --disable-libopencore-amrnb --disable-libopencore-amrwb --enable-libaom --disable-libaribb24 --enable-asm --enable-libass --disable-libbs2b --disable-libcaca --disable-libcdio --disable-libcelt --disable-libcodec2 --enable-libdav1d --disable-libdavs2 --disable-libdc1394 --disable-debug --enable-htmlpages --enable-libdrm --disable-libfdk-aac --disable-libflite --enable-fontconfig --enable-libfreetype --enable-frei0r --disable-libfribidi --disable-gcrypt --disable-libglslang --disable-libgme --enable-gmp --enable-gnutls --enable-version3 --disable-libgsm --enable-iconv --disable-libilbc --disable-libjack --disable-libklvanc --disable-libkvazaar --disable-ladspa --enable-libmp3lame --disable-liblensfun --disable-libbluray --disable-librsvg --disable-librtmp --enable-libxml2 --disable-lto --disable-lv2 --disable-mbedtls --disable-libmfx --disable-libmodplug --disable-libmysofa --disable-nonfree --disable-openal --disable-opencl --enable-libopencv --disable-opengl --disable-libopenh264 --disable-libopenjpeg --disable-libopenmpt --disable-openssl --enable-optimizations --enable-libopus --disable-pocketsphinx --disable-libpulse --disable-librabbitmq --disable-librav1e --enable-runtime-cpudetect --disable-librubberband --disable-sdl2 --disable-libsmbclient --disable-libsnappy --disable-sndio --disable-libsoxr --disable-libspeex --disable-libsrt --disable-libssh --disable-libtensorflow --disable-libtesseract --enable-libtheora --disable-libtwolame --enable-libv4l2 --enable-vaapi --disable-vapoursynth --enable-vdpau --disable-libvidstab --disable-libvmaf --enable-libvorbis --disable-libvo-amrwbenc --enable-libvpx --disable-vulkan --disable-libwavpack --disable-libwebp --enable-libx264 --enable-libx265 --disable-libxavs2 --enable-libxcb --enable-libxvid --disable-outdev=xv --disable-libzimg --disable-libzmq --disable-libzvbi
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
[hls @ 0x806511000] Skip ('#EXT-X-VERSION:3')
[hls @ 0x806511000] Opening 'https://1808506050.rsc.cdn77.org/live/studiorw/media-ubkjar4hc_65406.ts' for reading
[hls @ 0x806511000] Opening 'https://1808506050.rsc.cdn77.org/live/studiorw/media-ubkjar4hc_65407.ts' for reading
Input #0, hls, from 'https://1808506050.rsc.cdn77.org/live/studiorw/chunklist.m3u8':
  Duration: N/A, start: 81387.736867, bitrate: N/A
  Program 0
    Metadata:
      variant_bitrate : 0
    Stream #0:0: Data: timed_id3 (ID3  / 0x20334449)
    Metadata:
      variant_bitrate : 0
    Stream #0:1: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p, 1276x720, 25 fps, 25 tbr, 90k tbn, 50 tbc
    Metadata:
      variant_bitrate : 0
    Stream #0:2: Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp
    Metadata:
      variant_bitrate : 0
Stream mapping:
  Stream #0:1 -> #0:0 (h264 (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[AVFilterGraph @ 0x80887ac80] No such filter: '„scale'
Error reinitializing filters!
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #0:1
Conversion failed!

Forum zrobiło polski cudzysłów i jest błąd składni.
Spróbuj bez niego:

ffmpeg -y -i https://1808506050.rsc.cdn77.org/live/studiorw/chunklist.m3u8 -an -to 00:05:00 -c:v libx264 -preset veryfast -crf 23 -filter:v scale=-2:480 /home/rostov/JW/live.mp4

@MatX1, działa. Jednak widzę we właściwościach, że nagrany plik ma bardzo małą szybkość danych i całkowitą szybkość transmisji: 62 kb/s. Którym parametrem ją zwiększyć? Ewentualnie, jak zachować oryginalny bitrate?

Dlatego wstawia się je w pole na kod, nawet na smartfonie znak ` jest łatwo dostępny by zrobić pole na kod liniowe/blokowe (o ile nie walniesz literówki pisząc dwoma palcami na powierzchni „2 cali kwadratowych”).

Raczej 4 spacje przed są problematyczne jak to będzie dłuższy kod „programistyczny”, opcjonalnie BBcode liniowe już działa poprawnie a nie jak w 2017, że są posty @marcin82 bez poleceń widocznych a i on ich nie skorygował w 60 dni od otrzymania PW.

Pożądaną jakość możesz zmienić schodząc niżej z -crf.
Nie polecam jednak ustawiać wartości niższych niż 18 - prawdopodobnie będzie to strata miejsca.

Nie przejmowałbym się takim niskim bitratem - będzie on dobierany w zależności od potrzeb i nie ma sensu sztucznie go podbijać.
Dla statycznej sceny w 480p taki bitrate jest w porządku :wink:

Historia PW nie przypomina sobie PW ani od ciebie, ani od systemu ani od moderatora w kwestii poprawy składni jakichkolwiek postów. Pamięć zawodzi czy co sobie wymyśliłeś?

Zmieniał się silnik, kody w jakiejś formie przestały działać albo przy aktualizacji silnika, etc.

@MatX1, na razie wszystko działa bez zarzutu. Mam jeszcze 2 pytania:

  1. Wspomniałeś o parametrze ‘preset’, że im wolniejszy, tym większe obciążenie CPU. Czy zatem im szybszy, tym konwersja trwa dłużej? Czy to oznacza, że wówczas plik będzie gotowy dopiero po jakimś czasie od zakończenia nagrywania?

  2. Jakim poleceniem zatrzymać nagrywanie?

Nie, im szybszy tym kompresja trwa krócej, bo jest mniej wymagająca (i efektywna) niż preset wolniejszy.
Jeśli CPU „nie wyrabia” przy transkodowaniu na żywo, to ffmpeg obniża liczbę klatek na sekundę w danym momencie.

Czyli np. źródło ma stałe 30 fps, ale z uwagi na brak mocy docelowy klip momentami ma 20 fps.

Nie wydaje mi się, żeby było jakieś polecenie zatrzymujące nagrywanie, możesz spróbować standardowo ctrl+c.