Buduję aplikację NodeJS, która konwertuje statyczny plik wideo na wideo przesyłane strumieniowo, które jest wysyłane do klienta (iPada lub przeglądarki) w locie (przy użyciu modułu fluent-ffmpeg).
Wszystko jest ustawione i wszystko, czego teraz potrzebuję, to poprawnie skonfigurować ffmpeg. Ale mam wiele problemów z ffmpeg. Najpierw zbudowałem strumień flash (flv z kodekiem lib264, który działał świetnie, ale oczywiście nie działa na iPadzie).
Przy moich bieżących ustawieniach od razu słyszę dźwięk, ale obraz zaczyna się kilka sekund później. Następnie mój 30-sekundowy plik testowy został skompresowany do 3 sekund szybkich zdjęć.
Jak mogę skonfigurować mój ffmpeg, aby poprawnie przesyłać strumieniowo mp4 (oczywiście za jednym przejściem). Wygląda na to, że przesyła strumieniowo raw h264, jeśli tak, to w jaki sposób mogę wymusić kontener MP4. Myślałem, że robię to, używając „-f mp4”
moje prawidłowe ustawienia to:
'-crf 22','-c:v libx264','-f mp4','-movflags','faststart+frag_keyframe'
Próbowałem też:
'-r 30','-crf 30','-analyzeduration 0','-probesize 1000','-rc_lookahead 0','-fflags nobuffer','-g 75','-ss 0','-threads 0','-vcodec libx264','-qcomp 0.6','-qmin 10','-qmax 51','-qdiff 4','-b:v 400k','-maxrate 400k','-bufsize 800k','-acodec mp3','-ab 192k','-ar 44100','-tune zerolatency','-f mp4','-movflags','faststart+frag_keyframe'
Jak widać po liczbie wypróbowanych przeze mnie opcji, zaczynam się rozpaczać. Po prostu biegam w ciemności.
Nie sądzę, żeby to miało duże znaczenie, ale oto moje nagłówki żądań:
res.writeHead(200, {
'Content-Type':'video/mp4',
'Content-Length':stat.size,
'Content-Range':'bytes '+start+'-'+end+'/'+stat.size,
'Transfer-Encoding':'chunked'
});
Dziennik FFmpeg:
file conversion error ffmpeg version N-52458-gaa96439 Copyright (c) 2000-2013 the FFmpeg developers
built on Apr 24 2013 22:19:32 with gcc 4.8.0 (GCC)
configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libcaca --enable-libfreetype --enable
-libgsm --enable-libilbc --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwola
me --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid --enable-zlib
libavutil 52. 27.101 / 52. 27.101
libavcodec 55. 6.100 / 55. 6.100
libavformat 55. 3.100 / 55. 3.100
libavdevice 55. 0.100 / 55. 0.100
libavfilter 3. 60.101 / 3. 60.101
libswscale 2. 2.100 / 2. 2.100
libswresample 0. 17.102 / 0. 17.102
libpostproc 52. 3.100 / 52. 3.100
Input #0, avi, from 'C:/temp/avatar.avi':
Metadata:
encoder : Nandub v1.0rc2
Duration: 00:01:09.78, start: 0.000000, bitrate: 1517 kb/s
Stream #0:0: Video: msmpeg4v3 (DIV3 / 0x33564944), yuv420p, 640x352, 23.98 tbr, 23.98 tbn, 23.98 tbc
Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 48000 Hz, stereo, s16p, 222 kb/s
[libx264 @ 0218d480] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264 @ 0218d480] profile High, level 3.0
[libx264 @ 0218d480] 264 - core 130 r2274 c832fe9 - H.264/MPEG-4 AVC codec - Copyleft 2003-2013 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16
chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 w
eightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=23 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=22.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'pipe:1':
Metadata:
encoder : Lavf55.3.100
Stream #0:0: Video: h264 ([33][0][0][0] / 0x0021), yuv420p, 640x352, q=-1--1, 11988 tbn, 23.98 tbc
Stream #0:1: Audio: aac ([64][0][0][0] / 0x0040), 48000 Hz, stereo, s16, 128 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (msmpeg4 -> libx264)
Stream #0:1 -> #0:1 (mp3 -> libvo_aacenc)
Press [q] to stop, [?] for help
frame= 103 fps=0.0 q=27.0 size= 0kB time=00:00:04.70 bitrate= 0.1kbits/s
frame= 162 fps=161 q=27.0 size= 278kB time=00:00:07.15 bitrate= 317.9kbits/s
frame= 214 fps=141 q=27.0 size= 463kB time=00:00:09.33 bitrate= 406.3kbits/s
frame= 277 fps=137 q=27.0 size= 673kB time=00:00:11.95 bitrate= 461.3kbits/s
frame= 334 fps=132 q=27.0 size= 826kB time=00:00:14.32 bitrate= 472.5kbits/s
frame= 386 fps=127 q=27.0 size= 1061kB time=00:00:16.52 bitrate= 526.2kbits/s
frame= 428 fps=120 q=27.0 size= 1061kB time=00:00:18.27 bitrate= 475.9kbits/s
frame= 472 fps=116 q=27.0 size= 1061kB time=00:00:20.08 bitrate= 432.9kbits/s
frame= 525 fps=115 q=27.0 size= 1562kB time=00:00:22.30 bitrate= 573.7kbits/s
frame= 589 fps=116 q=27.0 size= 1804kB time=00:00:24.99 bitrate= 591.4kbits/s
frame= 690 fps=124 q=27.0 size= 1804kB time=00:00:29.19 bitrate= 506.2kbits/s
frame= 827 fps=136 q=27.0 size= 2191kB time=00:00:34.91 bitrate= 514.1kbits/s
frame= 921 fps=140 q=27.0 size= 2540kB time=00:00:38.81 bitrate= 536.1kbits/s
frame= 1015 fps=143 q=27.0 size= 2540kB time=00:00:42.74 bitrate= 486.9kbits/s
frame= 1124 fps=148 q=27.0 size= 3531kB time=00:00:47.30 bitrate= 611.5kbits/s
frame= 1248 fps=154 q=27.0 size= 3727kB time=00:00:52.46 bitrate= 581.9kbits/s
frame= 1371 fps=160 q=27.0 size= 4251kB time=00:00:57.58 bitrate= 604.7kbits/s
frame= 1516 fps=167 q=27.0 size= 4684kB time=00:01:03.62 bitrate= 603.0kbits/s
frame= 1632 fps=170 q=27.0 size= 4932kB time=00:01:08.46 bitrate= 590.1kbits/s
frame= 1673 fps=167 q=2686559.0 Lsize= 5507kB time=00:01:09.76 bitrate= 646.6kbits/s
video:4385kB audio:1091kB subtitle:0 global headers:0kB muxing overhead 0.582195%
[libx264 @ 0218d480] frame I:17 Avg QP:18.90 size: 11501
[libx264 @ 0218d480] frame P:1467 Avg QP:21.41 size: 2825
[libx264 @ 0218d480] frame B:189 Avg QP:24.42 size: 788
[libx264 @ 0218d480] consecutive B-frames: 84.5% 1.0% 1.4% 13.2%
[libx264 @ 0218d480] mb I I16..4: 21.5% 75.6% 2.9%
[libx264 @ 0218d480] mb P I16..4: 1.0% 2.8% 0.2% P16..4: 39.6% 13.7% 8.2% 0.0% 0.0% skip:34.6%
[libx264 @ 0218d480] mb B I16..4: 0.1% 0.3% 0.1% B16..8: 37.3% 2.6% 0.4% direct: 0.8% skip:58.4% L0:44.0% L1:51.7% BI: 4.3%
[libx264 @ 0218d480] 8x8 transform intra:70.8% inter:82.9%
[libx264 @ 0218d480] coded y,uvDC,uvAC intra: 58.7% 53.9% 12.8% inter: 20.2% 19.7% 0.4%
[libx264 @ 0218d480] i16 v,h,dc,p: 62% 16% 9% 13%
[libx264 @ 0218d480] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 27% 14% 30% 3% 5% 6% 4% 5% 4%
[libx264 @ 0218d480] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 34% 13% 11% 4% 10% 11% 7% 6% 3%
[libx264 @ 0218d480] i8c dc,h,v,p: 44% 19% 33% 4%
[libx264 @ 0218d480] Weighted P-Frames: Y:0.1% UV:0.0%
[libx264 @ 0218d480] ref P L0: 69.0% 16.7% 10.2% 4.0% 0.0%
[libx264 @ 0218d480] ref B L0: 86.1% 10.0% 3.9%
[libx264 @ 0218d480] ref B L1: 92.9% 7.1%
[libx264 @ 0218d480] kb/s:514.67
Moje dokładne polecenie nodejs z przypadkami testowymi, których użyłem (które zostały skomentowane):
, proc = new ffmpeg({
source: movie,
nolog: true,
timeout:15000
})
.addOptions(['-crf 22','-c:v libx264','-f mp4','-movflags','faststart+frag_keyframe'])
//.addOptions(['-threads 0', '-i_qfactor 0.71', '-qcomp 0.6', '-qmin 10', '-qmax 63', '-qdiff 4', '-trellis 0', '-vcodec libx264', '-s 640x360', '-b:v 1000k', '-b:a 56k','-ar 22050','-f mp4','-movflags','faststart+frag_keyframe'])
//.addOptions(['-r 30','-crf 30','-analyzeduration 0','-probesize 1000','-rc_lookahead 0','-fflags nobuffer','-g 75','-ss 0','-threads 0','-vcodec libx264','-qcomp 0.6','-qmin 10','-qmax 51','-qdiff 4','-b:v 400k','-maxrate 400k','-bufsize 800k','-acodec mp3','-ab 192k','-ar 44100','-tune zerolatency',metaDuration,tDuration,'-f mp4','-movflags','faststart+frag_keyframe'])
.writeToStream(res, function(retcode, error){
if (!error){
console.log('file has been converted succesfully',retcode .green);
}else{
console.log('file conversion error',error .red);
}
});
Mój odtwarzacz frontendowy to podstawowy odtwarzacz HTML5 z wideoJS na wierzchu (do obsługi tematycznej i kontroli).
<video id="player" class="video-js vjs-default-skin" controls preload="both" width="100%" height="100%"><source src="'+url+'" type="video/mp4"></video>