FFmpeg PTS/DTS probléma

 ( persicsb | 2013. február 27., szerda - 22:46 )

Sziasztok!

A következő problémám lenne:
szeretném egy MP4 konténerből (ami H.264 videot és AAC audiot tartalmaz) programozottan kinyerni az audiostreamet és egy wav-ba menteni. A tesztvideo a Big Buck Bunny.
Az FFmpeg parancssori meghívása most nem megoldás.

Csak az audio kell nekem.

A forrás paraméterei:
AAC, 48Khz, stereo, 320kbit.
A cél maraméterei:
WAV (PCM 16-bit signed), 44.1Khz, mono

A következőféleképpen álltam neki:

  1. AVFormatContextek inicializálása a megfelelő módon, 1 a demuxernek, 1 a muxernek
  2. AVCodecContext-ek inicializálása, 1 a dekódernek, 1 az enkódernek.
  3. amíg filevége nincs (av_read_frame)
    1. avcodec_decode_audio4-gyel dekódolom a kapott AVPacket-et
    2. A dekódolt AVFrame-et avcodec_encode_audio2-vel enkódolom, kapok egy AVPacketet
    3. avformat_interleaved_write_frame() segítségével kiírom a fileba (természetesen a header és a trailer is kiírásra kerül a megfelelő alkalomkor).

A probléma a következő:
a WAV előáll, azonban rendkívül zajos, és a hossza nagyobb, mint a forrás hossza (9:56 azaz 596 másodperc helyett 10:48, azaz 648 másodperc).

Arra már rájöttem, hogy valószínűleg a nem megfelelő PTS beállítás okozza a gondot.
A következő time_base-ek vannak:
1. Demuxer audio time_base, 1/48000
2. Audio decoder time_base, 1/48000
3. Audio encoder time_base, 1/44100
4. Muxer audio time_base, 1/90000

A bajom az, hogy az encode után keletkező AVPacket-nek a pts-e AV_NOPTS_VALUE, pedig az encode-nak átadott AVFrame-nek még létezik PTS információja.

A következővel próbálkoztam:
1. Forrás PTS konvertálása (rescale) az audio decoder time_base-re (ez a példában éppen 1:1 konvertálás, azaz nem csinál semmit).
2. Audio decoder time_base-ről konvertálás audio encoder time_base-re. Mármint a keletkező AV_NOPTS_VALUE-val rendelkező AVPacket PTS-t átalakítom az 1-es pontban előálló PTS-nek skálázott értékére. Ez egy 44100/48000-rel való szorzás.
3. A 2-es pontban megkapott PTS-t skálázom a muxer time_base-re (ez ugyebár egy 90000/441000-zal való szorzás).

Ezek után írom ki a file-ba az AVFrame-et, a dts minden esetben a pts értékére van állítva.

Azonban a keletkező file zajos lesz, és a hossza nem megfelelő. Érdekes módon 648 másodperc = 596 másodperc * 48000/44100, szóval tuti valamilyen skálázási probléma van.

Sajnos a Google, az FFmpeg forrás olvasása és a StackOverflow sem segített. Az FFmpeg forrása kimondottan kusza, a doxygenes dokumentáció pedig szegényes.

Azt kérdezem valaki FFmpeg szakértőtől (van jópár a HUP-on talán), hogy mikor melyik lépésben a megfelleő AVPacket/AVFrame struktúráknak milyen PTS-sel kell rendelkezniük?

A segítséget előre is köszönöm, 1-2 jófajta sört tudok felajánlani (amíg nincs a HUP-on reputation rendszer).

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

en anno az ffplay forraskodjabol indultam ki, az sem segit? az viszonylag atirhato erre a feladatra konnyen.

FFplay-ben nincs encode, es nekem pont az a bajom, hogy az encode utan cseszodik el a PTS, es lesz AV_NOPTS_VALUE a kimenet.

Nekem pedig kell encode, ugyanis a kimenet mas formatumu, mind a bemenet, ugymond vegrehajtok transzkodolast, de csak az audio erdekel.

Ha csak az a cel, h egy wav kimenetet kapj minek szivatod ezzel magad es nem teszel magasrol az egesz timestampezosdire? Az ms wav egy raw adatformatum aminek van az elejen egy 54 bajtos fejlece es amen. Resampler meg van ffmpegben.

---
pontscho / fresh!mindworkz

Hosszu tavon nyilvan nem ez a cel. Barmikor bejohet, hogy a kimenet legyen MP3 vagy Vorbis, vagy barmi mas.
Nem quick win-t keresek, az sem gond, ha ket hetet olvasnom kell (de ne forraskodot), meg szeretnem erteni az FFmpeg mukodeset, hasznalatat. Ha meg egyszer library, akkor szeretnem hasznalni.
"Resampler meg van ffmpegben"
Van ketfele, ahogy lattam, van az AVAudioConvert temakor, illetve az swresample. Melyik a stabilabb, megbizhatobb, hasznalando?
A dokumentacio ezzel kapcsolatban konkretan 0, marmint itt: http://ffmpeg.org/doxygen/1.0/modules.html
Nincs szo az swresample-rol, a libavcodec audio resample resz pedig AVResampleContext es ResampleContext strukturakkal is operal, baromira nem egyertelmu, hogy melyiket kell eppen hasznalni, es melyik deprecated. Pelda persze sehol.

Hosszu tavon nyilvan nem ez a cel. Barmikor bejohet, hogy a kimenet legyen MP3 vagy Vorbis, vagy barmi mas.

Ha csak egy kimeno audio stream a lenyeg video nelkul, akkor a timestamp felejtheto.

Van ketfele, ahogy lattam, van az AVAudioConvert temakor, illetve az swresample. Melyik a stabilabb, megbizhatobb, hasznalando?

Egyik sem allando, ffmpeg "api" nagyjabol harom havonta valtozik. De nem muszaj az ebbe epitett alfas resamplereket hasznalni (btw, a libavcodec-ben levo nekem boven eleg volt), van egy csomo ilyen ext lib.

En mindent kihajitottam a francba a kodbazisomban ami ffmpeg, csak a libavcodec dekoderei maradtak meg hellyel kozzel, pont azert, mert egy parastabil vacak amivel nincs idom szarakodni. Meg a libswscale is repult es lecserelodott intel ipp-re, mert ez utobbi gyorsabb, es az elobbivel ellentetben szinhelyes.

---
pontscho / fresh!mindworkz

Koszi a segitseget. Amugy nem csak az API instabil :) Pontosabban nagyon sok buveszkedes kell, hogy egy adott hivas midnig mukodjon: minden strukturat pontosan ugy kell kezelni, ahogy az ffmpeg.c-ben van, a dokumentacio nem sokat szamit.

Kesobbiekben kell video demux es transcode is, egyelore az egeszet koncepcionalisan szeretnem megerteni. Az a baj, hogy x ev Java programozas utan, ami joval magasabb absztrakcios szinteket hasznal, megerteni egy elegge alacsonyszintu es proceduralis API-t elegge lassan megy.

Milyen mas hasznalhato audio resamplerek vannak? Olyan kene, ami tamogat ARM CPU-t is, azaz nincs benne kizarolagos x86 ASM betet (ha egyaltalan van benne).

Van egy libresample is pl, de igazabol nem nehez leprototipizalni c-ben es ha kell akkor utanahuzni sse-vel/neonnal. Sot, a neont az isten is erre teremtette. :)

---
pontscho / fresh!mindworkz

lehet, hogy túl vagy már ezen a szinten, meg kicsit "out of date", de a következő leírás: An ffmpeg and SDL Tutorial or How to Write a Video Player in Less Than 1000 Lines elég értelmesnek tűnik, hátha tudsz hasznosítani belőle valamit...

Köszönöm, a dranger tutorialt ismerem, a problémám az vele, hogy az encoding részre ez sem tér ki, mindenki videolejátszót épít csak :)

Raadasul abbol is egy eleg szar fajtat. :)

---
pontscho / fresh!mindworkz

Nem csinalhat mindenki mplayert :)

Mi benne a rossz?

A hang megfelelőségére az egyetlen teszt, ha belehallgatsz (illetve generált szinusz hullámokat talán lehet ellenőrizni audacityben szemmel is). Ezért én kettészedném a problémát, csinálnék egy lejátszót és egy enkódolót (pl 440 Hz szinusz hullám lenne a forrás) külön. Ha külön már biztosan mennek, akkor kötném össze.

libav lejátszóval kapcsolatban vicces, hogy piszkálás nélkül _működő_ példát nem sikerült találnom. Úgy kellett összecsipegetni az infót, hogy valami kijöjjön. Aztán meg Ubuntu upgrade-kor bele kellett javítanom a kódba, ami most tele van feltételes ágakkal multiverziós karbantartás miatt :-). A dekódolt hangcsomagok időkódjai nálam is össze-vissza jöttek, ha jól emlékszem. A megoldás az lett, hogy teljesen figyelmen kívül hagytam az ott lévő infót, és a hangmintákat számolva rendeltem hozzá az időbélyeget a folyamhoz. Szóval ez a lib mindenképpen szívás.

Video encodingra én olyat csináltam, hogy egy külön processzt indítottam, amihez egy pipe-on keresztül raw formátumban feedeltem a képkockákat. Ez teljesítményben szinte olyan, mintha lib lenne, viszont programozi egy nagyságrendel egyszerűbb (főleg Javából :-). De nekem csak video kellett, nem hang. Érdemes ezt az utat végiggondolni szerintem. Az biztos, hogy elsőre nem tűnik elegánsnak. Aludni kell rá néhányat és azzal a szemmel újranézni :-). Ha már írtál 2000 sor C programot, és még mindig nem érted mitől torzít, akkor új perspektívába kerül az "elegáns".

Kizárt dolog, hogy ezt programozással csinálnám. Audacity pont jó erre. Tud batch feldolgozást is.

--
GPLv3-as hozzászólás.

A feladat ismeretenek hianyaban ezt igy kijelenteni akkora nagy marhasag, mint ide Nagykata.

---
pontscho / fresh!mindworkz

Nagy Kata?

Biztos hogy PTS gondod van neked? Én a helyedben kiírnám egy fájlba raw audio dataként a már 48 kHz-re átalakított hangot, és megnézném, hogy az jó-e. Libswresample a javasolt ffmpeg-ben mostanság, ffplay.c-ből ki lehet nézni hogy hogy kell használni. Ha resampling nélkül csak simán beadod az enkódernek a 44.1 kHz-es AVFrame-et, az biztos nem lesz jó.