วิธีการต่อไฟล์ MP4 สองไฟล์เข้าด้วยกันโดยใช้ FFmpeg


443

ฉันพยายามเชื่อมไฟล์ mp4 สองไฟล์เข้าด้วยกันโดยใช้ ffmpeg ฉันต้องการสิ่งนี้เพื่อเป็นกระบวนการอัตโนมัติดังนั้นทำไมฉันเลือก ffmpeg ฉันกำลังแปลงทั้งสองไฟล์เป็นไฟล์. ts จากนั้นทำการต่อไฟล์เข้าด้วยกันแล้วลองเข้ารหัสไฟล์. ts ที่ต่อกัน ไฟล์จะถูกเข้ารหัส h264 และ aac และฉันหวังว่าจะรักษาคุณภาพไว้เหมือนเดิมหรือใกล้เคียงกับของจริงที่สุด

ffmpeg -i part1.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part1.ts
ffmpeg -i part2.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part2.ts
cat part1.ts part2.ts > parts.ts
ffmpeg -y -i parts.ts -acodec copy -ar 44100 -ab 96k -coder ac -vbsf h264_mp4toannexb parts.mp4

น่าเสียดายที่ฉันได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้กลับมาจาก ffmpeg ระหว่างการเข้ารหัส:

[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[NULL @ 0x101d600]error, non monotone timestamps 13779431 >= 13779431kbits/s    
av_interleaved_write_frame(): Error while opening file

สิ่งนี้เกิดขึ้นประมาณครึ่งทางผ่านการเข้ารหัสซึ่งทำให้ฉันคิดว่าคุณไม่สามารถต่อไฟล์. ts สองไฟล์เข้าด้วยกันและทำงานได้

คำตอบ:


786

FFmpeg มีวิธีการต่อข้อมูลสามวิธี:

1. ตัวกรองวิดีโอ concat

ใช้วิธีนี้หากอินพุตของคุณไม่มีพารามิเตอร์เดียวกัน (ความกว้างความสูง ฯลฯ ) หรือไม่ใช่รูปแบบ / โคเดกเดียวกันหรือถ้าคุณต้องการทำการกรองใด ๆ (คุณสามารถเข้ารหัสอีกครั้งได้เพียงอินพุตที่ไม่ตรงกันดังนั้นจึงใช้ตัวแปลงสัญญาณและพารามิเตอร์อื่นร่วมกันจากนั้นใช้ concat demuxer เพื่อหลีกเลี่ยงการเข้ารหัสอินพุตอื่นอีกครั้ง)

ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv \
       -filter_complex "[0:v] [0:a] [1:v] [1:a] [2:v] [2:a] 
                        concat=n=3:v=1:a=1 [v] [a]" \
       -map "[v]" -map "[a]" output.mkv

โปรดทราบว่าวิธีนี้ทำการเข้ารหัสอีกครั้ง

2 demater concat

ใช้วิธีนี้เมื่อคุณต้องการหลีกเลี่ยงการเข้ารหัสซ้ำและรูปแบบของคุณไม่สนับสนุนการต่อข้อมูลระดับไฟล์ (ไฟล์ส่วนใหญ่ที่ผู้ใช้ทั่วไปใช้ไม่รองรับการต่อข้อมูลระดับไฟล์)

$ cat mylist.txt
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

$ ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

สำหรับ Windows :

(echo file 'first file.mp4' & echo file 'second file.mp4' )>list.txt
ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4

3. โปรโตคอล concat

ใช้วิธีนี้กับรูปแบบที่รองรับการต่อข้อมูลระดับไฟล์ (MPEG-1, MPEG-2 PS, DV) ไม่ได้ใช้กับ MP4

ffmpeg -i "concat:input1|input2" -codec copy output.mkv

วิธีนี้ใช้ไม่ได้กับหลาย ๆ รูปแบบรวมถึง MP4 เนื่องจากลักษณะของรูปแบบเหล่านี้และการต่อข้อมูลแบบง่าย ๆ โดยวิธีนี้


หากมีข้อสงสัยเกี่ยวกับวิธีการใช้งานลองใช้ตัวย่อ dematat

ยังดู


3
อักขระ escape พร้อมต์คำสั่ง Windows คือ ^; ฉันเจอปัญหาเกี่ยวกับเครื่องหมายคำพูดดังนั้นมันจึงกลายเป็น: ffmpeg -i concat: input1 ^ | input2 -codec ผลลัพธ์ของการคัดลอก
user423430

1
คำตอบที่เป็นประโยชน์ และมันก็สมเหตุสมผลมากขึ้นสำหรับฉันเมื่อฉันอ่านการเปลี่ยนแปลงนี้: superuser.com/a/607384/74576
Ryan

3
concat demuxer ทำงานสำหรับวิดีโอ แต่ฉันสูญเสียเสียง
Loïc

24
สำหรับผู้ใช้ oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv ยอมรับตัวแปลงสัญญาณมากกว่า mp4 แต่คุณสามารถลองกับ mp4 ได้) นี่-safe 0คือสำหรับรุ่น ffmpeg ล่าสุดที่บ่นเกี่ยวกับชื่อไฟล์ที่ไม่ปลอดภัยและ-type fเป็นไฟล์ที่มีรายชื่อเท่านั้น ฉันเพิ่ม| sortเพื่อจัดเรียงไฟล์ตามลำดับตัวอักษร; เพราะfindอ่านตามลำดับที่บันทึกไว้ในระบบไฟล์ ใช้งานได้กับไฟล์ที่มีช่องว่าง
erik

1
สำหรับผมใน Windows เครื่องหมายอัญประกาศทำงาน ffmpeg -i "concat:input1|input2" -codec copy output(แทนเดียวในตัวอย่างของคุณ): ไม่จำเป็นต้องหลบหนีไปป์ตัวละคร
Shovalt

84

สำหรับไฟล์ MP4

สำหรับไฟล์. mp4 (ที่ฉันได้รับจาก DailyMotion.com: ตอนทีวี 50 นาทีสามารถดาวน์โหลดได้เพียงสามส่วนเท่านั้นเป็นไฟล์วิดีโอ. mp4 ไฟล์สามไฟล์) ต่อไปนี้เป็นโซลูชันที่มีประสิทธิภาพสำหรับWindows 7และไม่เกี่ยวข้องกับการเข้ารหัสซ้ำ ไฟล์

ฉันเปลี่ยนชื่อไฟล์ (เช่นfile1.mp4 , file2.mp4 , file3.mp4 ) เพื่อให้ชิ้นส่วนอยู่ในลำดับที่ถูกต้องสำหรับการรับชมรายการทีวีที่สมบูรณ์

จากนั้นฉันสร้างไฟล์แบตช์อย่างง่าย(concat.bat) โดยมีเนื้อหาดังต่อไปนี้:

:: Create File List
echo file file1.mp4 >  mylist.txt 
echo file file2.mp4 >> mylist.txt
echo file file3.mp4 >> mylist.txt

:: Concatenate Files
ffmpeg -f concat -i mylist.txt -c copy output.mp4

ไฟล์ชุดและffmpeg.exe , ทั้งสองจะต้องใส่ในโฟลเดอร์เดียวกับไฟล์ .mp4ที่จะเข้าร่วม จากนั้นรันไฟล์แบตช์ โดยทั่วไปจะใช้เวลาน้อยกว่าสิบวินาทีในการทำงาน
.

ภาคผนวก (2018/10/21) -

หากสิ่งที่คุณกำลังมองหาเป็นวิธีการระบุไฟล์ mp4 ทั้งหมดในโฟลเดอร์ปัจจุบันโดยไม่ต้องพิมพ์ซ้ำจำนวนมากลองทำสิ่งนี้ในไฟล์แบตช์ Windows ของคุณแทน ( ต้องมีตัวเลือก - ปลอดภัย 0 ):

:: Create File List
for %%i in (*.mp4) do echo file '%%i'>> mylist.txt

:: Concatenate Files
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

สิ่งนี้ใช้ได้กับ Windows 7 ในแบตช์ไฟล์ อย่าลองใช้มันในบรรทัดคำสั่งเพราะมันใช้งานได้ในไฟล์แบตช์เท่านั้น!


5
ทางออกที่ง่ายที่สุด
1934286

นี่ควรเป็นคำตอบที่ดีที่สุดและง่ายที่สุด เยี่ยมมากเพื่อนของฉัน คุณบันทึกวันของฉัน
DysaniazzZ

นี่เป็นวิธีแก้ปัญหาที่ดี แต่การพูดถึงแบตช์ไฟล์ทำให้เสียงนี้เป็นแบบดั้งเดิม (เหมือนที่ทำในแบทช์) และมีความซับซ้อนมากกว่านั้น (เนื่องจากไฟล์แบตช์ไม่จำเป็นอย่างสมบูรณ์) มีความชัดเจนมากขึ้นถ้าคุณแสดงC:\blah>type mylist.txt<ENTER>(เพื่อให้พวกเขาเห็นเนื้อหาของไฟล์นั้น) จากนั้น ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> คุณควรรวมtrac.ffmpeg.org/wiki/Concatenateอ้างอิง ด้วย (การอ้างอิงนั้นใช้ชื่อไฟล์เดียวกัน mylist.txt)
barlop

นี่เป็นวิธีแก้ปัญหาที่ดีมากเพราะช่วยให้คุณไม่ต้องพิมพ์รายการไฟล์ที่มีความยาวสำหรับ-iพารามิเตอร์ บน Linux ฉันทำสิ่งนี้: ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtซึ่งเย็นกว่าการเขียนสคริปต์แบทช์ อย่างไรก็ตาม-c copyการดำเนินการอย่างรวดเร็ว (ซึ่งผมก็ไม่ทราบ) และนี่คือความมหัศจรรย์ที่แท้จริงของคำตอบนี้
Würgspaß

1
ด้วยไฟล์ mp4 ของฉันไม่มีเสียงเลยในไฟล์เอาต์พุตหลังจากรันโค้ด concat ของคุณบน Mac โดยใช้ ffmpeg v3.2.2
kakyo

60

ต่อไปนี้เป็นวิธีที่รวดเร็ว (ใช้เวลาน้อยกว่า 1 นาที) และไม่ต้องเสียเวลาทำโดยไม่ต้องใช้ไฟล์ระดับกลาง:

ls Movie_Part_1.mp4 Movie_Part_2.mp4 | \
perl -ne 'print "file $_"' | \
ffmpeg -f concat -i - -c copy Movie_Joined.mp4

"ls" มีไฟล์ที่จะเข้าร่วม "perl" จะสร้างไฟล์การต่อข้อมูลลงในท่อในส่วน "-i -" บอกให้ ffmpeg อ่านจากไปป์

(หมายเหตุ - ไฟล์ของฉันไม่มีช่องว่างหรือสิ่งแปลก ๆ ในนั้นคุณจะต้องหลบหนีด้วยเปลือกหอยที่เหมาะสมหากคุณต้องการทำแนวคิดนี้ด้วยไฟล์ "ยาก"


2
ทำสิ่งนี้บน OSX และใช้งานได้ดี! โซลูชันที่ยอดเยี่ยมและไม่สูญเสียความรวดเร็วด้วยความต้องการเพียงเล็กน้อย
GM Lucid

1
ด้วยการหลบหนีที่เหมาะสมสำหรับไฟล์ที่มีช่องว่าง:ls Movie_Part_1.mp4 Movie_Part_2.mp4 | perl -ne '$_ =~ s/\n$//; print "file '"'"'$_'"'"'\n"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4
Thomas Bachem

4
คุณสามารถทำได้ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4ถ้าไฟล์ของคุณมีชื่อดีและเป็นระเบียบ ทำงานได้ดีสำหรับฉันใน OS X สิ่งที่ฉันต้องการ
natebeaty

3
บน Linux ฉันใช้ oneliner นี้: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv ยอมรับตัวแปลงสัญญาณมากกว่า mp4 แต่คุณสามารถลองกับ mp4 ได้) นี่-safe 0คือสำหรับรุ่น ffmpeg ล่าสุดที่บ่นเกี่ยวกับชื่อไฟล์ที่ไม่ปลอดภัยและ-type fเป็นไฟล์ที่มีรายชื่อเท่านั้น ฉันเพิ่ม| sortเพื่อจัดเรียงไฟล์ตามลำดับตัวอักษร; เพราะfindอ่านตามลำดับที่บันทึกไว้ในระบบไฟล์ ใช้งานได้กับไฟล์ที่มีช่องว่าง
erik

13
ฉันต้องเพิ่มพารามิเตอร์นี้ffmpegเพื่อให้มันทำงานได้:-protocol_whitelist file,tcp,http,pipe
Bensge

44

สำหรับไฟล์ MP4:

หากพวกเขาไม่เหมือนกัน (ไฟล์ตัวแปลงสัญญาณเดียวกัน 100% ความละเอียดเดียวกันประเภทเดียวกัน) ไฟล์ MP4 แล้วคุณต้อง trans-code พวกเขาลงในกระแสกลางในตอนแรก:

ffmpeg -i myfile1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp1.ts
ffmpeg -i myfile2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp2.ts
// now join
ffmpeg -i "concat:temp1.ts|temp2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

บันทึก! : เอาต์พุตจะเหมือนไฟล์แรก (ไม่ใช่ไฟล์ที่สอง)


2
ดังที่แสดงในคำตอบของฉันด้านล่างการแปลงไฟล์ไม่จำเป็น FFmpeg สามารถต่อเชื่อมไฟล์ mp4 หลายไฟล์ให้เป็นไฟล์ mp4 ไฟล์เดียว - โดยไม่มีขั้นตอนกลางและไม่มีการเข้ารหัสใหม่ กรณีเดียวที่จำเป็นต้องมีการเข้ารหัสซ้ำอีกครั้งคือถ้าไฟล์ต้นฉบับไม่ใช่ไฟล์ mp4 แต่ความตั้งใจคือการสร้างไฟล์ mp4 เป็นไฟล์เอาต์พุต
Ed999

@T Todua: ฉันสนใจที่จะเรียนรู้ว่าอะไรคือความแตกต่างระหว่างไฟล์ mp4 สองไฟล์ของคุณอย่างแม่นยำ พวกเขาใช้อัตราตัวอย่างที่แตกต่างกัน (เช่น 44,100 Hz และ 48,000 Hz) หรือไม่ หรือพวกเขากำลังใช้อัตราบิตที่แตกต่างกัน (เช่น 128 kbps และ 64 kbps)? ในกรณีเช่นนี้ฉันไม่เข้าใจว่าคำสั่ง -c copy (คำสั่ง stream-copy) จะแก้ไขไฟล์ต้นฉบับเพื่อให้เข้ากันได้อย่างไร
Ed999

4
@ T.Todua สวัสดีคำสั่งใช้งานได้ดีเมื่อวิดีโอไม่มีแทร็กเสียง อย่างไรก็ตามเมื่อ myfile1.mp4 ไม่มีเสียงและ myfile2.mp4 อยู่กับเสียงผลลัพธ์ output.mp4 จะไม่มีเสียง output.mp4 ที่คาดหวังควรมีเสียง ฉันจะแก้มันได้อย่างไร
AnswerZhao

2
@ T.Todua er .... มันแย่เกินไป file1 | file2 สร้างวิดีโอต่าง ๆ ด้วย file2 | file1 คำสั่งซื้อเป็นสิ่งสำคัญ
AnswerZhao

1
ฉันลองคำสั่งของคุณในไฟล์ concat 2 mp4 มันได้ผล. อย่างไรก็ตามเสียงของไฟล์ที่สองจะเปลี่ยนแปลงเร็วเหมือนเสียง Ah-oh-Ee ในการต่อข้อมูลใหม่ที่สร้างขึ้น คุณมีวิธีแก้ไขไหม
superlinux

35

ฉันพยายามเชื่อม.mp3ไฟล์เสียงสามไฟล์ให้เป็นไฟล์เดียว.m4aและคำสั่ง ffmpeg นี้ทำงาน

คำสั่งอินพุต:

ffmpeg -i input1.mp3 -i input2.mp3 -i input3.mp3 \
       -filter_complex "concat=n=3:v=0:a=1" -f MOV -vn -y input.m4a

ความหมายของ: -filter_complex "concat = n = 3: v = 0: a = 1" :

concatหมายถึงใช้ฟังก์ชั่นเชื่อมต่อสื่อ (เข้าร่วม)
nหมายถึงยืนยันจำนวนไฟล์อินพุตทั้งหมด
vหมายถึงวิดีโอหรือไม่ ใช้ 0 = ไม่มีวิดีโอ, 1 = มีวิดีโอ หมายถึงมีเสียง ? ใช้ 0 = ไม่มีเสียง 1 = มีเสียง -fหมายถึงรูปแบบไฟล์บังคับ (เพื่อดูรูปแบบที่รองรับการใช้งานทั้งหมด) -vnหมายถึงปิดใช้งานวิดีโอ (และจะปิดใช้งานเสียงหากไม่ต้องการ) -yหมายถึงเขียนทับไฟล์เอาต์พุต (หากไฟล์เอาต์พุตมีอยู่แล้ว)

ffmpeg -formats
-an

สำหรับข้อมูลเพิ่มเติม: ใช้ffmpeg -h full พิมพ์ตัวเลือกทั้งหมด (รวมถึงรูปแบบทั้งหมดและตัวเลือกเฉพาะตัวแปลงสัญญาณที่ยาวมาก)


1
fi ใช้สิ่งนี้-f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"มันจะต่อกัน แต่เมื่อบางวิดีโอมีเสียงและบางอย่างไม่มีเสียงมันไม่ทำงานฉันจะสังคายนาสิ่งนี้ได้อย่างไร ขอบคุณ -
อาห์หมัด

1
วิธีนี้ใช้ได้ผล ขอบคุณสำหรับคำอธิบายโดยละเอียดในคำตอบของคุณ มันมีประโยชน์มาก
Joe T. Boka

31

ฉันลงเอยด้วยการใช้ mpg เป็นรูปแบบกลางและใช้งานได้ (โปรดทราบว่านี่เป็นตัวอย่างที่เป็นอันตราย -qscale 0 จะเข้ารหัสวิดีโออีกครั้ง ... )

ffmpeg -i 1.mp4 -qscale 0 1.mpg
ffmpeg -i 2.mp4 -qscale 0 2.mpg
cat 1.mpg 2.mpg | ffmpeg -f mpeg -i - -qscale 0 -vcodec mpeg4 output.mp4

8
ในฐานะที่เป็นความคิดเห็นนี้-sameqถูกลบออก ใช้-qscale 0แทน
Xavier Ho

6
-sameqไม่ได้หมายถึง "คุณภาพเดียวกัน"และถูกลบออกจาก ffmpeg ตามที่ระบุไว้โดย @XavierHo
llogan

3
ดูเหมือนว่าน่าละอายที่จะต้องแปลงรหัสวิดีโอผ่านรูปแบบสื่อกลางเพื่อเชื่อมไฟล์สองไฟล์เข้าด้วยกัน คุณจะได้รับการสูญเสียรุ่น ดีกว่าที่จะไม่ไปลึกกว่ารูปแบบคอนเทนเนอร์และใช้concatคำสั่งใน ffmpeg ตามที่ @rogerdpack ทำด้านบน
Randall Cook

8
นี่เป็นคำตอบที่ยอมรับได้ทำไม นี่เป็นวิธีที่แย่มาก
ชื่อที่แสดง

4
@SargeBorsch เพราะมันใช้งานได้ ฉันได้ลองทุกอย่างในหน้า - มันไม่ทำงาน

14

เอกสารรายละเอียดเกี่ยวกับวิธีการต่างๆของการเรียงต่อกันใน ffmpeg สามารถพบได้ที่นี่

คุณสามารถใช้'ตัวกรอง Concat'สำหรับการต่อข้อมูลแบบย่อ

มันทำการเข้ารหัสอีกครั้ง ตัวเลือกนี้จะดีที่สุดเมื่ออินพุตมีรูปแบบวิดีโอ / เสียงที่แตกต่างกัน

สำหรับการต่อไฟล์ 2 ไฟล์:

ffmpeg -i input1.mp4 -i input2.webm \
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]" \
-map "[v]" -map "[a]" output.mp4

สำหรับการต่อไฟล์ 3 ไฟล์:

ffmpeg -i input1.mp4 -i input2.webm -i input3.mp4 \
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] [2:v:0] [2:a:0] concat=n=3:v=1:a=1 [v] [a]" \
-map "[v]" -map "[a]" output.mp4

สามารถใช้งานได้กับไฟล์อินพุตเดียวกันหลายประเภท


คุณสามารถระบุรายละเอียดเพิ่มเติมเกี่ยวกับตัวเลือกที่คุณมีในตัวอย่างนี้ได้หรือไม่?
นักพัฒนา

@Developer: สำหรับคำอธิบายของตัวเลือก -> wiki Concat filter
SJ00

4
เมื่อทำการเชื่อมต่อ 3 ไฟล์คุณควรใช้ concat = n = 3: v = 1: a = 1 ไม่ใช่ n = 2
Cynapsis

1
ฉันไม่ได้รับการต่อเชื่อมแบบไม่สูญเสียouput.mp4บิตเรตวิดีโอของฉันต่ำกว่าวิดีโอบิตเรตวิดีโออินพุตอย่างมาก
มิถุนายน

ขอบคุณ Cynapsis สำหรับการชี้ให้เห็นและ georgiecasey สำหรับการปรับปรุงคำสั่ง
SJ00

10

ฉันพบว่าตัวดำเนินการไปป์ไม่ทำงานสำหรับฉันเมื่อใช้ตัวเลือก 3 เพื่อเชื่อมต่อ MP4 หลายตัวบน Mac ในคำตอบที่ยอมรับ

สายการบินเดียวต่อไปนี้ทำงานบน Mac (High Sierra) เพื่อต่อเชื่อม mp4 ได้โดยไม่ต้องสร้างไฟล์ตัวกลาง

ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4


2
คำตอบง่ายๆนี้เป็นคำตอบเดียวที่ได้ผลสำหรับฉัน หน้าเอกสารของหน้าเอกสารที่นี่และที่อื่น ๆ ในขณะที่หนึ่งซับง่าย ๆ นี้เป็นสิ่งที่จำเป็น - และใช้งานได้จริง ขอบคุณ.
blujay

10

ที่นี่ 2 วิธีทุบตีบริสุทธิ์โดยใช้เท่านั้นffmpegและไม่ได้ใช้

  • ไฟล์ตัวกลาง
  • perl, python และ javascript

วิธีการแก้ปัญหาหนึ่งซับโดยใช้ ls

ls video1.mp4 video2.mp4 | while read line; do echo file \'$line\'; done | ffmpeg -protocol_whitelist file,pipe -f concat -i - -c copy output.mp4

ฟังก์ชันที่รับอาร์กิวเมนต์ 0 หรือ 2+

#######################################
# Merge mp4 files into one output mp4 file
# usage:
#   mergemp4 #merges all mp4 in current directory
#   mergemp4 video1.mp4 video2.mp4
#   mergemp4 video1.mp4 video2.mp4 [ video3.mp4 ...] output.mp4 
#######################################
function mergemp4() {
  if [ $# = 1 ]; then return; fi

  outputfile="output.mp4"

  #if no arguments we take all mp4 in current directory as array
  if [ $# = 0 ]; then inputfiles=($(ls -1v *.mp4)); fi
  if [ $# = 2 ]; then inputfiles=($1 $2); fi  
  if [ $# -ge 3 ]; then
    outputfile=${@: -1} # Get the last argument
    inputfiles=(${@:1:$# - 1}) # Get all arguments besides last one as array
  fi

  # -y: automatically overwrite output file if exists
  # -loglevel quiet: disable ffmpeg logs
  ffmpeg -y \
  -loglevel quiet \
  -f concat \
  -safe 0 \
  -i <(for f in $inputfiles; do echo "file '$PWD/$f'"; done) \
  -c copy $outputfile

  if test -f "$outputfile"; then echo "$outputfile created"; fi
}

หมายเหตุ: ได้ลองวิธีแก้ปัญหาบางอย่างในกระทู้นี้และไม่มีใครพอใจฉัน


9

จากคำตอบของ rogerdpack และ Ed999 ฉันได้สร้างรุ่น. sh

#!/bin/bash

[ -e list.txt ] && rm list.txt
for f in *.mp4
do
   echo "file $f" >> list.txt
done

ffmpeg -f concat -i list.txt -c copy joined-out.mp4 && rm list.txt

มันเข้าร่วม*.mp4ไฟล์ทั้งหมดในโฟลเดอร์ปัจจุบันเข้าjoined-out.mp4

ทดสอบบน mac

ขนาดไฟล์ที่ได้คือผลรวมที่แน่นอนของไฟล์ที่ผ่านการทดสอบ 60 ไฟล์ของฉัน ไม่ควรขาดทุน สิ่งที่ฉันต้องการ


9

สิ่งนี้ใช้ได้สำหรับฉัน (บน windows)

ffmpeg -i "concat:input1|input2" -codec copy output

ตัวอย่าง...

ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4

หลาม

การใช้โค้ดไพ ธ อนเพื่อทำกับ mp4 มากเท่าที่มีในโฟลเดอร์ (ติดตั้งไพ ธ อนจาก python.org คัดลอกและวางและบันทึกรหัสนี้ลงในไฟล์ชื่อ mp4.py และเรียกใช้จาก cmd ที่เปิดในโฟลเดอร์ที่มีไพ ธ อน mp4.py และ mp4 ทั้งหมดในโฟลเดอร์จะถูกต่อกัน)

import glob
import os

stringa = ""
for f in glob.glob("*.mp4"):
    stringa += f + "|"
os.system("ffmpeg -i \"concat:" + stringa + "\" -codec copy output.mp4")

เวอร์ชัน 2 พร้อม Python

นำมาจากการโพสต์บนบล็อกของฉันนี่คือวิธีที่ฉันทำในหลาม:

import os
import glob

def concatenate():
    stringa = "ffmpeg -i \"concat:"
    elenco_video = glob.glob("*.mp4")
    elenco_file_temp = []
    for f in elenco_video:
        file = "temp" + str(elenco_video.index(f) + 1) + ".ts"
        os.system("ffmpeg -i " + f + " -c copy -bsf:v h264_mp4toannexb -f mpegts " + file)
        elenco_file_temp.append(file)
    print(elenco_file_temp)
    for f in elenco_file_temp:
        stringa += f
        if elenco_file_temp.index(f) != len(elenco_file_temp)-1:
            stringa += "|"
        else:
            stringa += "\" -c copy  -bsf:a aac_adtstoasc output.mp4"
    print(stringa)
    os.system(stringa)

concatenate()

1
โปรโตคอล concat ไม่ควรใช้กับ MP4 และจะไม่ทำงานตามที่กล่าวไว้ในคำตอบที่ได้รับการยอมรับ
llogan

@ LordNeckbeard ฉันสงสัยว่าคุณรู้คำตอบสำหรับคำถาม ffmpeg นี้หรือไม่เกี่ยวกับการเชื่อมต่อวิดีโอ 2 MP4 ในขณะที่ระบุบิตเรตเอาต์พุต video.stackexchange.com/q/24569/5657ขอบคุณ
Ryan

@ LordNeckbeard ฉันเดาได้ว่าคำตอบของคุณจะดีที่สุดถ้าคุณพร้อมที่จะทำ! ฉันไม่พอใจกับตัวเองเป็นพิเศษ
Ryan

ไม่เพียง (ตามที่ Lord Neckbeard ชี้ให้เห็น) จำเป็นต้องแปลงไฟล์. mp4 เป็นฟอร์แมต. TS ระดับกลางเพื่อให้การต่อข้อมูลสำเร็จ แต่อาจแย่กว่านั้นคำตอบนี้ไม่ได้เริ่มตอบสนองความต้องการอินพุต ไฟล์วิดีโอที่มีอัตราบิตที่ตรงกันอัตราเฟรมอัตราตัวอย่างระยะเวลาและระยะเวลา หากไม่มีปัจจัยทั้งหมด 5 ประการที่เหมือนกันไฟล์จะไม่สามารถต่อกันได้ (เช่นเข้าร่วมโดยใช้การคัดลอกสตรีม ) แต่ต้องเข้ารหัสใหม่แทน
Ed999

7

สำหรับ.mp4ไฟล์ที่ผมพบว่ามันทำงานได้ดีขึ้นและเร็วขึ้นเพื่อใช้เครื่องมือบรรทัดคำสั่ง opensource mp4boxนี้: จากนั้นคุณสามารถใช้วิธีนี้:

mp4box.exe -add video1.mp4 -cat video2.mp4 destvideo.mp4

ดาวน์โหลดได้ที่นี่สำหรับแพลตฟอร์มส่วนใหญ่: https://gpac.wp.imt.fr/mp4box/


2
แม้ว่าสิ่งนี้อาจมีประโยชน์สำหรับบางคนความต้องการคือ: " ฉันพยายามเชื่อมไฟล์ mp4 สองไฟล์โดยใช้ ffmpeg ฉันต้องการสิ่งนี้เพื่อให้เป็นกระบวนการอัตโนมัติ " โปรดอ่านคำถามทั้งหมดแล้วลองตอบคำถามที่ตรงประเด็น
thvs86

5
คำตอบนี้ตรงประเด็นทั้งหมด มันเป็นเครื่องมือ FOSS ที่ทำงานเหมือนกัน มันสามารถใช้ในสคริปต์เช่นเดียวกับ FFmpeg มันทำให้งานทำได้ง่ายกว่าคำตอบ FFmpeg ใด ๆ ดูสิว่ามันซับซ้อนแค่ไหน! หนึ่งในนั้นใช้ Node.js เพื่อเรียก FFmpeg! ความบ้า โปรดหยุดด้วยการชนะใจและลองทำ StackOverflow ให้เป็นประโยชน์อีกครั้ง เว็บไซต์นี้เป็นเพียงเงาของตัวเองในอดีตขอบคุณสำหรับความต้องการของคุณ นอกจากนี้คำถามนี้เป็นตัวอย่างของ "ปัญหา XY" ซึ่งคุณควรทำความคุ้นเคย
blujay

ไม่สำคัญว่า mp4box เป็นเครื่องมือ FOSS คำถามถามหาคำตอบโดยใช้ ffmpeg ไม่ใช่ mp4box
jramos775

@ thvs86 ฉันเป็นหนึ่งในตัวอย่างที่ ฉันใช้ ffmpeg เพราะมันเป็นมีดสวิสแท้สำหรับสื่อ ฉันยังค้นหาความช่วยเหลือเกี่ยวกับกรณีการใช้งานเฉพาะของฉันเนื่องจากโครงสร้างของการโต้เถียงนั้นค่อนข้างซับซ้อน (ซึ่งแสดงโดยคำตอบที่หลากหลายที่นี่) นี่เป็นครั้งแรกที่ฉันได้ยินเกี่ยวกับ mp4box และฉันจะไม่พบมันหากมันไม่ใช่คำตอบนี้ ดังนั้น +1 จากฉันและโปรดได้โปรดคิดเกี่ยวกับคนที่ค้นหาคำตอบมากกว่าเกี่ยวกับคะแนนอินเทอร์เน็ตที่ไม่มีความหมายและกฎที่เข้มงวด
Pavel

4

นี่คือสคริปต์ที่ฉันทำเพื่อเชื่อมต่อ GoPro mp4 หลายตัวเข้ากับ 720p mp4 หวังว่ามันจะช่วย

#!/bin/sh
cmd="( "
for i; do
    cmd="${cmd}ffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; "
done
cmd="${cmd} ) | ffmpeg -i - -vb 10000000 -ab 256000 -s 1280x720 -y out-`date +%F-%H%M.%S`.mp4"
echo "${cmd}"
eval ${cmd}

นี่ไม่ใช่การต่อข้อมูล รหัสนี้ไม่ได้เชื่อมต่อกับอินพุต แต่จะเข้ารหัสอีกครั้ง การดำเนินการนี้จะใช้ไฟล์วิดีโอใด ๆ และเปลี่ยนเป็นบิตเรตเสียงและวิดีโอทั่วไป (ไม่ว่าบิตเรตดั้งเดิมหรือขนาดเฟรมดั้งเดิมของไฟล์ต้นฉบับ) o / p ต้องการเข้าร่วมสองไฟล์โดยใช้การคัดลอกสตรีมไม่เข้ารหัสไฟล์เหล่านี้อีกครั้งดังนั้นจึงไม่ได้ตอบคำถามที่ถาม
Ed999

4

จากเอกสารที่นี่: https://trac.ffmpeg.org/wiki/Concatenate

หากคุณมีไฟล์ MP4, เหล่านี้อาจจะlosslesslyตัดแบ่งโดยแปลงแรกที่พวกเขาไปเป็น MPEG-2 กระแสการขนส่ง ด้วยวิดีโอ H.264 และเสียง AAC คุณสามารถใช้สิ่งต่อไปนี้:

ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

วิธีนี้ใช้ได้กับทุกแพลตฟอร์ม

ฉันต้องการความสามารถในการห่อหุ้มสิ่งนี้ในสคริปต์ข้ามแพลตฟอร์มดังนั้นฉันจึงใช้fluent-ffmpegและคิดวิธีแก้ปัญหาต่อไปนี้ขึ้นมา:

const unlink = path =>
  new Promise((resolve, reject) =>
    fs.unlink(path, err => (err ? reject(err) : resolve()))
  )

const createIntermediate = file =>
  new Promise((resolve, reject) => {
    const out = `${Math.random()
      .toString(13)
      .slice(2)}.ts`

    ffmpeg(file)
      .outputOptions('-c', 'copy', '-bsf:v', 'h264_mp4toannexb', '-f', 'mpegts')
      .output(out)
      .on('end', () => resolve(out))
      .on('error', reject)
      .run()
  })

const concat = async (files, output) => {
  const names = await Promise.all(files.map(createIntermediate))
  const namesString = names.join('|')

  await new Promise((resolve, reject) =>
    ffmpeg(`concat:${namesString}`)
      .outputOptions('-c', 'copy', '-bsf:a', 'aac_adtstoasc')
      .output(output)
      .on('end', resolve)
      .on('error', reject)
      .run()
  )

  names.map(unlink)
}

concat(['file1.mp4', 'file2.mp4', 'file3.mp4'], 'output.mp4').then(() =>
  console.log('done!')
)

1
ffmpeg \
  -i input_1.mp4 \
  -i input_2.mp4 \
  -filter_complex '[0:v]pad=iw*2:ih[int];[int][1:v]overlay=W/2:0[vid]' \
  -map [vid] \
  -c:v libx264 \
  -crf 23 \
  -preset veryfast \
  output.mp4

1
ไม่เพียงแค่โพสต์คำตอบคุณสามารถเพิ่มคำอธิบายเล็กน้อยซึ่งเข้าใจวิธีแก้ปัญหาที่ดีกว่าสำหรับ OP และผู้อ่านในอนาคตเช่นกัน
Balagurunathan Marimuthu

1
สิ่งนี้สร้างวิดีโอเงียบใหม่โดยมีอินพุตทั้งสองเล่นพร้อมกันติดกัน ฉันคาดว่าการต่อข้อมูลจะสร้างวิดีโอที่ input_1.mp4 เล่นแล้ว input_2.mp4
Alexx Roche

3
นี่เป็นคำตอบที่ผิดทั้งหมด นี่ไม่ได้เป็นการต่อวิดีโอ แต่มันเล่นกับมันแบบคู่ขนานอย่าง @AlexxRoche
Kalob Taulien

1

รวมไฟล์ mp4 ทั้งหมดจากไดเรกทอรีปัจจุบัน

ฉันเป็นคนชอบที่จะไม่สร้างไฟล์ภายนอกที่ฉันจะต้องลบหลังจากนั้นดังนั้นวิธีการแก้ปัญหาของฉันคือการติดตามซึ่งรวมถึงรายการหมายเลขไฟล์ (เช่นfile_1_name, file_2_name, file_10_name, file_20_name, file_100_name, ... )

#!/bin/bash
filesList=""
for file in $(ls -1v *.mp4);do #lists even numbered file
    filesList="${filesList}${file}|"
done
filesList=${filesList%?} # removes trailing pipe
ffmpeg -i "concat:$filesList" -c copy $(date +%Y%m%d_%H%M%S)_merged.mp4

ฉันคัดลอกรหัสนี้ไปยัง Notepad และไม่มีอะไรเกิดขึ้น
7vujy0f0hy

1
@ 7vujy0f0hy งานนี้บนลินุกซ์ที่มีเปลือกทุบตีบางทีมันอาจจะสามารถทำงานร่วมกับ Cygwin
Pipo

1

หลังจากพยายามหลายครั้งด้านล่างสคริปต์ใช้งานได้สำหรับฉันบน windows 10 powershell

    $files=Get-ChildItem -path e:\ -Filter *.mp4


    $files| ForEach-Object  {"file '$($_.FullName)'"}| Out-File -FilePath e:\temp.txt -Encoding ASCII


    if (-not (test-path "e:\ffmpeg\bin\ffmpeg.exe")) {throw "e:\ffmpeg\bin\ffmpeg.exe needed"}

    E:\ffmpeg\bin\ffmpeg.exe -safe 0 -f concat -i "e:\temp.txt" -c copy -bsf:v hevc_mp4toannexb -an e:\joined.mp4

    # Conversion Cleanup
    Remove-Item e:\temp.txt

ที่นี่สองบรรทัดแรกสร้างไฟล์ข้อความ temp.txt ซึ่งมีเนื้อหาดังต่อไปนี้

file 'e:\first.mp4'
file 'e:\second.mp4'

บรรทัดที่ 3, 4 ตรวจสอบว่า ffmpeg มีอยู่ที่ path และสร้าง "join.mp4"

ความแตกต่างที่สำคัญจากคำตอบอื่น ๆ มีดังนี้

usage  of -bsf:v hevc_mp4toannexb -an

สำหรับไฟล์ mp4 ของฉันทำงานได้คุณอาจต้องใช้ทางเลือกอื่นเช่นด้านล่างขึ้นอยู่กับการเข้ารหัสวิดีโอของคุณ

h264_mp4toannexb

ตัวกรองบิตสตรีมที่เป็นไปได้ทั้งหมดสามารถดูได้ที่https://ffmpeg.org/ffmpeg-bitstream-filters.html


ฉันเป็น MP4 มาจากกล้องวงจรปิด หากไม่มีคำสั่งนั้นการสนทนาจะไม่สามารถสร้างไฟล์เอาต์พุตได้ฉันใช้ ffmpeg ล่าสุดจากเว็บไซต์ของมัน
ราหุล maindargi

0

นี่คือวิธีการของฉันสำหรับการเข้าร่วมไดเรกทอรีที่เต็มไปด้วยไฟล์ MP4 โดยใช้การแทนที่คำสั่งและตัวกรองวิดีโอ concat (จะเข้ารหัสอีกครั้ง) - คิดว่าคนอื่นจะได้รับประโยชน์จากซับในนี้โดยเฉพาะถ้าคุณมีไฟล์จำนวนมาก เข้าร่วม 17 ไฟล์ในหนึ่งเดียวก้ม:)

ffmpeg $(for f in *.mp4 ; do echo -n "-i $f "; done) -filter_complex \
"$(i=0 ; for f in *.mp4 ; do echo -n "[$i:v] [$i:a] " ; i=$((i+1)) ; done \
&& echo "concat=n=$i:v=1:a=1 [v] [a]")" -map "[v]" -map "[a]" output.mp4

หมายเหตุคำสั่งนี้จะรวมไฟล์ของคุณตามลำดับที่ชื่อ (เช่นคำสั่งเดียวกับที่แสดงถ้าคุณเรียกใช้ls *.mp4) - ในกรณีของฉันพวกเขาแต่ละคนมีหมายเลขแทร็กดังนั้นจึงใช้งานได้ดี


0

โปรโตคอล concat อธิบายไว้ที่นี่; https://trac.ffmpeg.org/wiki/Concatenate#protocol

เมื่อใช้งานไปป์ที่มีชื่อเพื่อหลีกเลี่ยงไฟล์ระดับกลาง

เร็วมาก (อ่าน: ทันที) ไม่มีเฟรมหลุดและทำงานได้ดี

อย่าลืมลบไฟล์ไปป์ที่มีชื่อและอย่าลืมตรวจสอบว่าวิดีโอนั้นเป็น H264 และ AAC ซึ่งคุณสามารถทำได้ด้วยเพียงแค่ffmpeg -i filename.mp4(ตรวจสอบ h264 และ aac กล่าวถึง)


-1

คำตอบที่ยอมรับในรูปแบบของสคริปต์ PowerShell ที่ใช้ซ้ำได้

Param(
[string]$WildcardFilePath,
[string]$OutFilePath
)
try
{
    $tempFile = [System.IO.Path]::GetTempFileName()
    Get-ChildItem -path $wildcardFilePath | foreach  { "file '$_'" } | Out-File -FilePath $tempFile -Encoding ascii
    ffmpeg.exe -safe 0 -f concat -i $tempFile -c copy $outFilePath
}
finally
{
    Remove-Item $tempFile
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.