Gabung file mp4 di linux

31

Saya ingin menggabungkan dua file mp4 untuk membuat satu. Aliran video dikodekan dalam h264 dan audio dalam aac. Saya tidak dapat menyandikan ulang video ke format lain karena alasan komputasi. Juga, saya tidak dapat menggunakan program GUI, semua pemrosesan harus dilakukan dengan utilitas baris perintah Linux. FFmpeg tidak dapat melakukan ini untuk file mpeg4 jadi saya menggunakan MP4Box:

MP4Box -add video1.mp4 -cat video2.mp4 newvideo.mp4

Sayangnya audio menjadi kacau. Saya pikir masalahnya adalah audio di aac jadi saya menyalinnya di mp3 dan menggunakan lagi MP4Box. Dalam hal ini audio baik-baik saja untuk bagian pertama newvideo.mp4(sesuai dengan video1.mp4) tetapi kemudian tidak ada audio dan saya tidak dapat menavigasi dalam video juga.

Pikiran saya berikutnya adalah bahwa stream audio dan video memiliki beberapa perbedaan kecil yang harus saya perbaiki. Jadi untuk setiap input video saya memisahkan stream video dan audio dan kemudian bergabung dengan mereka dengan opsi -shortest di FFmpeg.

Jadi untuk video pertama saya berlari:

 avconv -y -i video1.mp4 -c copy -map 0:0 videostream1.mp4
 avconv -y -i video1.mp4 -c copy -map 0:1 audiostream1.m4a
 avconv -y -i videostream1.mp4 -i audiostream1.m4a  -c copy -shortest  video1_aligned.mp4

Begitu pula untuk video kedua dan kemudian menggunakan MP4Box seperti sebelumnya. Sayangnya ini juga tidak berhasil. Satu-satunya keberhasilan yang saya miliki adalah ketika saya bergabung dengan stream video secara terpisah (yaitu videostream1.mp4 dan videostream2.mp4) dan stream audio (yaitu audiostream1.m4a dan audiostream2.m4a) dan kemudian bergabung dengan video dan audio dalam file terakhir. Namun, sinkronisasi hilang untuk paruh kedua video. Konkretnya, ada penundaan audio dan video 1 detik. Setiap saran sangat diterima.

Jose Armando
sumber
"FFmpeg tidak dapat melakukan ini untuk file mpeg4 jadi alih-alih saya menggunakan MP4Box" maksud Anda file MP4? apakah kedua aliran audio-video menggunakan parameter penyandian yang sama (lebar, tinggi, SPS, PPS, framerate, samplingrate, jumlah saluran?
menggunakan ffprobe saya melihat bahwa stream audio memiliki atribut yang identik. Streaming video memiliki dimensi yang sama tetapi dengan laju yang berbeda. Untuk Video video pertama: h264, 720x592, 277 kb / s, PAR 18944: 12915 DAR 512: 287, 24,97 fps, 45k tbr, 90k tbn, 90k tbc sementara untuk Video kedua: h264, 720x592, 226 kb / s, PAR 481: 330 DAR 39:22, 24,91 fps, 45k tbr, 90k tbn, 90k tbc. Apakah Anda percaya bahwa ini adalah sumber masalah saya?
MP4 mendukung penggabungan video / audio dengan karakteristik berbeda menggunakan trek berbeda untuk video berbeda, tetapi pemain tidak sepintar itu.
rajneesh
Pertanyaan Anda sudah dijawab di FAQ ffmpeg: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Jawaban:

31

Cara terbaik untuk melakukan ini saat ini adalah dengan demuxer concat . Pertama, buat file bernama inputs.txtdiformat seperti ini:

file '/path/to/input1.mp4'
file '/path/to/input2.mp4'
file '/path/to/input3.mp4'

Kemudian, jalankan perintah ffmpeg ini:

ffmpeg -f concat -i inputs.txt -c copy output.mp4

Lihat juga gabungan dalam ffmpegFAQ .


Saya menyimpan yang berikut di sini untuk kepentingan siapa pun yang menggunakan ffmpeg versi lama.

Versi terbaru dari ffmpeg dapat melakukan ini: Anda harus melakukan remux file ke aliran transport mpeg terlebih dahulu (cukup prosesor-cahaya, karena hanya mengubah format wadah):

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Jika itu memunculkan kesalahan tentang h264, Anda mungkin perlu menggunakan:

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Anda harus melakukan ini secara terpisah dengan setiap file input. Untuk menyatukan file bersama, gunakan:

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy output.mp4

Jika itu memunculkan kesalahan tentang aac, Anda mungkin perlu menggunakan

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy -absf aac_adtstoasc output.mp4

Jika sistem Anda mendukung pipa bernama, Anda dapat melakukan ini tanpa membuat file perantara.

mkfifo temp0 temp1

Anda harus melakukan hal berikut dalam tiga terminal virtual terpisah:

ffmpeg -i input0.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp0
ffmpeg -i input1.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp1
ffmpeg -f mpegts -i "concat:temp0|temp1" -c copy -absf aac_adtstoasc output.mp4

Jika output.mp4 sudah ada, ffmpeg ketiga akan menanyakan apakah Anda ingin menimpanya, tetapi akan melakukan ini setelah mengakses FIFO , dan ini akan membuat yang pertama menutup ffmpeg. Jadi pastikan Anda memilih nama yang tidak digunakan untuk file output Anda.

Ini mungkin tidak berfungsi jika file input Anda berbeda - saya percaya bahwa perbedaan dalam bit rate OK, tetapi ukuran frame, frame rate dll harus cocok.

Evilsoup
sumber
banyak teman, bekerja seperti pesona
Jose Armando
2
@ DaveJarvis Tidak begitu; itu adalah pesan yang sengaja dan jahat disebarkan oleh tim libav, yang merupakan sekelompok pengembang yang berpisah dari proyek ffmpeg untuk mengembangkan avconv (dan mengubah nama karena mereka tidak dapat mengamankan hak cipta atas nama ffmpeg). Lihat Siapa yang dapat memberi tahu saya perbedaan dan hubungan antara ffmpeg, libav, dan avconv? untuk informasi lebih lanjut.
evilsoup
2
*** THIS PROGRAM IS DEPRECATED *** This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.adalah pesan yang saya lihat sekarang sedang berjalanffmpeg
Lord Loh.
@ LordLoh. Lihat tautan di komentar saya sebelumnya.
evilsoup
1
Jawaban itu tidak menjawab - bagaimana menggabungkan mp4 denganavconv
Lord Loh.
7

Untuk mp4 satu-satunya solusi yang saya temukan adalah dengan MP4Box dari paket gpac

#!/bin/bash
filesList=""
for file in $(ls *.mp4|sort -n);do
    filesList="$filesList -cat $file"
done
MP4Box $filesList -new merged_files_$(date +%Y%m%d_%H%M%S).mp4

atau perintah

MP4Box -cat file1.mp4 -cat file2.mp4 -new mergedFile.mp4

dengan mencoder dan avconv saya tidak bisa membuatnya bekerja :-(

Philippe Gachoud
sumber
2

Terima kasih untuk skrip dvo. Itu adalah titik awal yang bagus bagi saya. Saya tidak punya masalah dengan menggunakan pipa bernama jadi saya mengadaptasi skrip untuk menggunakannya. Plus saya memperbaikinya untuk bekerja dengan nama file dengan spasi di dalamnya. Output ke pipa bernama tidak "pergi" sampai Anda mulai membaca dari mereka, maka kebutuhan untuk latar belakang tugas remux awal dengan & sebelum panggilan terakhir ke avconv. Plus, jangan lupa untuk menggunakan -c copy, atau Anda akhirnya menyandikan ulang seluruh lot.

#!/bin/bash
for FILE in "$@"; do
   TAG=$(echo "$FILE" | sed -e s/[^A-Za-z0-9.]/_/g)
   mkfifo $TAG.mp4concatpipe
   avconv -loglevel "quiet" -i "$FILE"  -f mpegts -c copy -bsf h264_mp4toannexb -y $TAG.mp4concatpipe &
   IN=$IN\|$TAG.fifo
done

IN=${IN#\|}
avconv -i concat:$IN -c copy out.mp4
rm *.mp4concatpipe
Menandai
sumber
Untuk beberapa alasan ini memberi saya kesalahan "concat: first.m4v.fifo | second.m4v.fifo: Tidak ada file atau direktori" seperti itu .. bahkan dengan tanda kutip (-i concat: "$ IN" atau -i "concat: $ IN "). MP4Box disarankan dalam jawaban lain di bawah ini namun berfungsi dengan baik!
vorburger
2

Di Mac (macOS 10.13 High Sierra) saya menggunakan yang berikut ini dengan sukses:

for f in *.m4a; do echo "file '$f'" >> mylist.txt; done

Susun ulang seperti di atas dengan cara yang sama jika perlu (perhatikan bahwa ./ telah dihapus - path menyebabkan ffmpeg untuk melemparkan kesalahan nama file yang tidak aman).

Kemudian saya harus menghapus codec dan bitrate yang ditentukan untuk ffmpeg MacPorts default untuk menyukainya:

ffmpeg -f concat -i mylist.txt  output.m4a
Robert Cole
sumber
Selamat datang di Pengguna Super !, Silakan baca pertanyaan lagi dengan seksama. Jawaban Anda tidak menjawab pertanyaan awal tentang linux. Jika Anda yakin itu akan berfungsi di linux, harap tambahkan bahwa pembaca yang akan datang memiliki pemahaman yang jelas, selain itu, selamat datang lagi untuk pengguna super dan terima kasih atas masukan Anda. Silakan luangkan waktu beberapa menit dan baca: - superuser.com/help. Jawab: superuser.com/help/how-to-answer .
mic84
2

Berikut ini adalah satu-liner yang membuatnya lebih mudah. Itu melakukan semua yang perlu dilakukan untuk akhirnya memberi Anda satu file video yang dihasilkan. Tepuk tangan!

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts
Anonim
sumber
1

Terima kasih evilsoup; di sini ada sedikit skrip untuk mengotomatiskan proses, menggunakan yang lebih baru avconv.
BTW, pipa bernama tidak bekerja untuk saya (output ke mereka macet).

   #!/bin/bash

    for FILE in $@; do
      avconv -i $FILE -map 0 -f mpegts -bsf h264_mp4toannexb -c:v copy -y $FILE.tmp
      IN=$IN\|$FILE.tmp
    done

    IN=${IN#\|}
    avconv -i concat:"$IN" out.mp4

    for FILE in $@; do
      rm $FILE.tmp
    done
dvo
sumber
0

Telah menikmati kesuksesan besar bersama

for f in ./*.m4a; do echo "file '$f'" >> mylist.txt; done

Anda mungkin perlu memesan ulang mylist.txt sedikit

ffmpeg -f concat -i mylist.txt -c:a libfdk_aac -b:a 128k output.m4a

ffmpeg versi 2.2.3

Benjamin
sumber