Audiovisuelle Inhalte verlieren die Synchronisation

343
Darkmoor

Ich habe eine .mp4Videodatei, die von einer unkomprimierten .aviKamera stammt emgu. Der Emgu videoWriterist so eingestellt, dass 30fpssogar das reale Video fpsmöglicherweise niedriger ist, z 29fps. Der Befehl, der zum Komprimieren verwendet wird, .avilautet:

Komprimierungsbefehl:

fmpeg -i uncompresedvideo.avi -v quiet -stats -nostdin -c:v libx264 -crf 1 -preset veryfast -maxrate 500k -bufsize 1835k vid.mp4 

Die Videokomprimierungsausgabe ist:

ffmpeg version N-82060-g0cfd6cc Copyright (c) 2000-2016 the FFmpeg developers built with gcc 5.4.0 (GCC) configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-libebur128 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-decklink --enable-zlib libavutil 55. 32.100 / 55. 32.100 libavcodec 57. 63.103 / 57. 63.103 libavformat 57. 52.100 / 57. 52.100 libavdevice 57. 0.102 / 57. 0.102 libavfilter 6. 64.100 / 6. 64.100 libswscale 4. 1.100 / 4. 1.100 libswresample 2. 2.100 / 2. 2.100 libpostproc 54. 0.100 / 54. 0.100 Input #0, avi, from 'C:\....\uncompresedvideo.avi': Metadata: encoder : Lavf56.36.100 Duration: 00:02:50.27, start: 0.000000, bitrate: 110597 kb/s Stream #0:0: Video: rawvideo (I420 / 0x30323449), yuv420p, 640x480, 110613 kb/s, 30 fps, 30 tbr, 30 tbn, 30 tbc [libx264 @ 0000000002636460] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 AVX2 LZCNT BMI2 [libx264 @ 0000000002636460] profile High, level 3.0 [libx264 @ 0000000002636460] 264 - core 148 r2721 72d53ab - H.264/MPEG-4 AVC codec - Copyleft 2003-2016 - http://www.videolan.org/x264.html - options: cabac=1 ref=1 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=2 psy=1 psy_rd=1.00:0.00 mixed_ref=0 me_range=16 chroma_me=1 trellis=0 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=6 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 weightb=1 open_gop=0 weightp=1 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=10 rc=crf mbtree=1 crf=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 vbv_maxrate=500 vbv_bufsize=1835 crf_max=0.0 nal_hrd=none filler=0 ip_ratio=1.40 aq=1:1.00 Output #0, mp4, to 'C:\....\vid.mp4': Metadata: encoder : Lavf57.52.100 Stream #0:0: Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p, 640x480, q=-1--1, 30 fps, 15360 tbn, 30 tbc Metadata: encoder : Lavc57.63.103 libx264 Side data: cpb: bitrate max/min/avg: 500000/0/0 buffer size: 1835000 vbv_delay: -1 Stream mapping: Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (libx264))  

Zusätzlich zu dieser Videoaufnahme habe ich eine .wavDatei, die von einem anderen Gerät stammt. Ich versuche diese mit dem folgenden Befehl mit dem Inhalt zu synchronisieren:

ffmpeg.exe -i vid.mp4 -r 30 -i audio.wav -ar 16000 -map 0:0 -map 1:0 -vcodec copy -acodec aac -shortest output.mp4 

Die Ausgabe des Synch-Befehls lautet:

ffmpeg version N-82060-g0cfd6cc Copyright (c) 2000-2016 the FFmpeg developers built with gcc 5.4.0 (GCC) configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-libebur128 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-decklink --enable-zlib libavutil 55. 32.100 / 55. 32.100 libavcodec 57. 63.103 / 57. 63.103 libavformat 57. 52.100 / 57. 52.100 libavdevice 57. 0.102 / 57. 0.102 libavfilter 6. 64.100 / 6. 64.100 libswscale 4. 1.100 / 4. 1.100 libswresample 2. 2.100 / 2. 2.100 libpostproc 54. 0.100 / 54. 0.100 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'audio.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf57.52.100 Duration: 00:02:50.27, start: 0.000000, bitrate: 507 kb/s Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 640x480, 504 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default) Metadata: handler_name : VideoHandler Guessed Channel Layout for Input Stream #1.0 : mono Input #1, wav, from 'audio.wav': Duration: 00:02:52.29, bitrate: 512 kb/s Stream #1:0: Audio: pcm_f32le ([3][0][0][0] / 0x0003), 16000 Hz, mono, flt, 512 kb/s Output #0, mp4, to 'output.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf57.52.100 Stream #0:0(und): Video: h264 (High) ([33][0][0][0] / 0x0021), yuv420p, 640x480, q=2-31, 504 kb/s, 30 fps, 30 tbr, 15360 tbn, 15360 tbc (default) Metadata: handler_name : VideoHandler Stream #0:1: Audio: aac (LC) ([64][0][0][0] / 0x0040), 16000 Hz, mono, fltp, 69 kb/s Metadata: encoder : Lavc57.63.103 aac Stream mapping: Stream #0:0 -> #0:0 (copy) Stream #1:0 -> #0:1 (pcm_f32le (native) -> aac (native)) Press [q] to stop, [?] for help frame= 5108 fps=1316 q=-1.0 Lsize= 11735kB time=00:02:52.28 bitrate= 558.0kbits/s speed=44.4x video:10486kB audio:1151kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.836344% [aac @ 00000000026977c0] Qavg: 65093.531 

Ich möchte erwähnen, dass sowohl Audio als auch Video einen gemeinsamen Anfang haben. Während der audiovisuelle Inhalt zu Beginn eine gute Synchronisation aufweist, geht die Synchronisation am Ende der Aufzeichnung verloren. Könnten Sie bitte einen Vorschlag machen, was passiert?

Ihre Hilfe wird sehr geschätzt, danke.

1
@slhck Ja, ich habe ein Refactoring gemacht und mehr Details zur aktuellen Situation gemacht. Daher dachte ich, es wäre besser, wenn man vom Betteln aus eine andere Perspektive einnimmt. Wenn man es hüpft, wird es anderen helfen, mehr zu verstehen. Ich hoffe es ist kein großes Problem. Darkmoor vor 7 Jahren 0
@slhck Ich glaube, ich habe den Grund meines Problems. Das komprimierte Video hat während der gesamten Aufnahme keine konstanten "fps". Darf ich fragen, ob es möglich ist, ein Video mit nicht konstanten fps mit "ffmpeg" in konstante eins umzuwandeln? Darkmoor vor 7 Jahren 0
Wenn Sie den Parameter `-r` im Komprimierungsbefehl mit einem fps unter dem tatsächlichen Wert verwenden, wird ein konstantes Bildfrequenz-Bild (.mp4) bereitgestellt? Darkmoor vor 7 Jahren 0
Ich bin mir nicht sicher, ich bin in letzter Zeit nicht auf variable Video-Frameraten gestoßen. Hast du eine Probe? Haben Sie die `force-crf`-Option ausprobiert? slhck vor 7 Jahren 0
@slhck Entschuldigung für die Verzögerung. Ich habe getestet, das Video mit der Option "force-crf" zu komprimieren, funktionierte jedoch nicht. Darf ich fragen, ob es eine mögliche Option für das Audio ".wav" gibt, die nicht immer eine konstante Sample-Rate hat? Darkmoor vor 7 Jahren 0
@slhck danke für die Antwort. Ich möchte noch einen letzten Versuch machen, also lassen Sie mich bitte folgendes fragen. Wie in der Frage beschrieben, unterscheiden sich die tatsächlichen "fps" des Streams von den gespeicherten über "opencv". Ist es möglich, die "fps" während der Komprimierung oder danach zu ändern? Ist das auch für die `.wav`-Datei möglich? Danke noch einmal! Darkmoor vor 7 Jahren 0
Ich habe unten eine ausführlichere Antwort geschrieben. Wenn Sie einige Beispiele sehen, hilft dies bei der Fehlerbehebung, aber so wie ich Ihr Problem jetzt verstehe, scheint es unmöglich, es zu beheben. slhck vor 7 Jahren 0

1 Antwort auf die Frage

1
slhck

Ich denke, das Problem ist, dass Ihr Eingangsvideo aufgrund der Kodierung bereits falsche Zeitstempel hat. Ich verstehe, dass das ursprüngliche Webcam-Video Frames mit variabler Länge (dh ein Video mit variabler Framerate) ausgegeben hat, aber eine unkomprimierte AVI-Datei kann nur Frames mit konstanter Länge speichern .

Beim Lesen dieser AVI-Datei (oder einer darauf folgenden komprimierten MP4-Datei) geht ffmpeg davon aus, dass es sich um ein Video mit konstanter Bildrate handelt. Dies führt dazu, dass sich mit der Zeit eine Asynchronität "aufbaut", da die Zeitstempel in Ihrem AVI / MP4 konstante Offsets aufweisen. ffmpeg kann dies nicht für Sie beheben, da die Eingabezeitstempel bereits falsch sind. In anderen Worten, ich gehe davon aus, dass videoWriterSie ein Video mit konstanter Bildrate aus einer variablen Bildrate erstellt haben und falsche Zeitstempel erstellen. Ohne zu wissen, wann oder wie sich die Framerate geändert hat, können Sie die Zeitstempel nicht festlegen.

Die einzige Option wäre, den Videostream von der Webcam mit einem Container neu zu generieren, der eine variable Bildrate unterstützt (z. B. MKV oder MP4 / MOV). Bei einer späteren Konvertierung könnte der Inhalt dann mit einem Audiostrom synchronisiert werden. Da dieser Webcam-Feed jedoch wahrscheinlich live ist, gibt es keine Möglichkeit, zurück zu kehren. Ich glaube auch nicht, dass OpenCV auch eine videoWritervariable Framerate ausgeben kann (aber ich bin kein Experte dafür).


Hinweis: Es ist einfacher, dieses Problem zu beheben, wenn das Originalvideo mit einer falschen konstanten Bildrate codiert wurde . Sie könnten dann ffmpeg zwingen, eine andere Bildfrequenz für das Eingangsvideo anzunehmen, die ursprünglichen Zeitstempel effektiv zu entfernen und neue zu erzeugen, wobei eine konstante Bildrate angenommen wird. Wenn Ihre Videokonvertierung beispielsweise ein 30-fps-Video erstellt hat, der ursprüngliche Eingang jedoch 29 fps war, gehen Sie folgendermaßen vor:

ffmpeg -r 29 -i <input> …