Làm cách nào để ghép hai tệp MP4 bằng FFmpeg?


442

Tôi đang cố gắng ghép hai tập tin mp4 bằng ffmpeg. Tôi cần điều này là một quá trình tự động do đó tại sao tôi chọn ffmpeg. Tôi đang chuyển đổi hai tệp thành tệp .ts và sau đó ghép chúng lại và sau đó thử mã hóa tệp .ts được nối. Các tập tin được mã hóa h264 và aac và tôi hy vọng sẽ giữ được chất lượng như cũ hoặc gần với bản gốc nhất có thể.

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

Thật không may, tôi nhận được thông báo lỗi sau từ ffmpeg trong quá trình mã hóa:

[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

Điều này xảy ra khoảng một nửa trong quá trình mã hóa khiến tôi nghĩ rằng bạn không thể kết hợp hai tệp .ts lại với nhau và để nó hoạt động.

Câu trả lời:


785

FFmpeg có ba phương thức nối:

1. bộ lọc video concat

Sử dụng phương pháp này nếu đầu vào của bạn không có cùng tham số (chiều rộng, chiều cao, v.v.) hoặc không cùng định dạng / codec hoặc nếu bạn muốn thực hiện bất kỳ bộ lọc nào. (Bạn có thể mã hóa lại chỉ các đầu vào không khớp để chúng chia sẻ cùng một codec và các tham số khác, sau đó sử dụng bộ giải mã concat để tránh mã hóa lại các đầu vào khác).

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

Lưu ý rằng phương pháp này thực hiện mã hóa lại.

2. trình giải thích concat

Sử dụng phương pháp này khi bạn muốn tránh mã hóa lại và định dạng của bạn không hỗ trợ nối cấp độ tệp (hầu hết các tệp được sử dụng bởi người dùng chung không hỗ trợ nối cấp độ tệp).

$ 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

Đối với 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. giao thức concat

Sử dụng phương pháp này với các định dạng hỗ trợ nối cấp độ tệp (MPEG-1, MPEG-2 PS, DV). Đừng không sử dụng với MP4.

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

Phương pháp này không hoạt động đối với nhiều định dạng, bao gồm MP4, do bản chất của các định dạng này và việc ghép đơn giản được thực hiện bởi phương pháp này.


Nếu nghi ngờ về việc sử dụng phương pháp nào, hãy thử trình giải mã concat.

Cũng thấy


3
Ký tự thoát lệnh của Windows là ^; Tôi cũng gặp vấn đề với các dấu ngoặc kép nên nó trở thành: ffmpeg -i concat: input1 ^ | input2 -codec đầu ra bản sao
user423430

1
Câu trả lời hữu ích. Và nó thậm chí còn có ý nghĩa hơn với tôi khi tôi đọc biến thể này: superuser.com/a/607384/74576
Ryan

3
Trình giải mã concat hoạt động cho video, nhưng tôi đang mất âm thanh
Loïc

23
Đối với việc sử dụng oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv chấp nhận nhiều codec hơn mp4, nhưng bạn cũng có thể thử nó với mp4). Các -safe 0là dành cho phiên bản ffmpeg gần đây phàn nàn về tên file không an toàn , và -type fchỉ dành cho danh sách tập tin. Tôi đã thêm | sortđể sắp xếp các tập tin theo thứ tự abc; bởi vì findđọc chúng theo thứ tự như được lưu trên hệ thống tập tin. Hoạt động cũng cho các tập tin với khoảng trắng.
erik

1
Đối với tôi, trong Windows, dấu ngoặc kép hoạt động (thay vì dấu ngoặc đơn trong ví dụ của bạn) : ffmpeg -i "concat:input1|input2" -codec copy output. Không cần phải thoát khỏi nhân vật ống.
Shovalt

82

CHO PHIM MP4

Đối với các tệp .mp4 (mà tôi thu được từ DailyMotion.com: một tập phim truyền hình dài 50 phút, chỉ có thể tải xuống trong ba phần, như ba tệp video .mp4) sau đây là một giải pháp hiệu quả cho Windows 7KHÔNG liên quan đến việc mã hóa lại các tập tin.

Tôi đã đổi tên các tệp (như file1.mp4 , file2.mp4 , file3.mp4 ) sao cho các phần theo đúng thứ tự để xem tập phim truyền hình hoàn chỉnh.

Sau đó, tôi đã tạo một tệp bó đơn giản (concat.bat), với các nội dung sau:

:: 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

Cả hai tệp bóffmpeg.exe đều phải được đặt trong cùng một thư mục với các tệp .mp4 được nối. Sau đó chạy tệp bó. Nó thường sẽ mất ít hơn mười giây để chạy.
.

Phụ lục (2018/10/21) -

Nếu những gì bạn đang tìm kiếm là một phương pháp chỉ định tất cả các tệp mp4 trong thư mục hiện tại mà không cần thử lại nhiều, hãy thử điều này trong tệp bó Windows của bạn ( PHẢI bao gồm tùy chọn -safe 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

Điều này hoạt động trên Windows 7, trong một tệp bó. Đừng thử sử dụng nó trên dòng lệnh, vì nó chỉ hoạt động trong một tệp bó!


5
Các giải pháp đơn giản nhất cho đến nay.
1934286

Đây phải là câu trả lời tốt nhất và dễ nhất. Làm tốt lắm, anh bạn của tôi. Bạn đã cứu ngày của tôi.
DysaniazzZ

Đây là một giải pháp tốt nhưng nói về một tệp bó làm cho âm thanh này trở nên nguyên thủy (giống như nó được thực hiện theo lô) và phức tạp hơn nó (vì một tệp bó là hoàn toàn không cần thiết). Sẽ rõ ràng hơn nhiều nếu bạn chỉ hiển thị C:\blah>type mylist.txt<ENTER>(Vì vậy, họ thấy nội dung của tệp đó) Sau đó, ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> bạn cũng nên bao gồm một tham chiếu trac.ffmpeg.org/wiki/Concatenate (tham chiếu đó thậm chí sử dụng cùng tên tệp, mylist.txt)
barlop

Đây là một giải pháp rất tốt vì nó giúp bạn không phải gõ vào danh sách dài các tệp cho -itham số. Trên Linux tôi đã làm điều này: ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtthậm chí còn hay hơn mã hóa một tập lệnh bó. Dù sao, -c copythực hiện rất nhanh (mà tôi không biết) và đây là phép thuật thực sự của câu trả lời này.
Wurgspaß

1
Với các tệp mp4 của tôi, không có âm thanh nào trong tệp đầu ra sau khi chạy mã concat của bạn trên máy Mac, sử dụng ffmpeg v3.2.2.
kakyo

59

Đây là một cách nhanh chóng (mất ít hơn 1 phút) và cách dễ dàng để làm điều này mà không cần các tệp trung gian:

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

"Ls" chứa các tệp để tham gia "perl" tạo tệp ghép nối khi đang bay vào đường ống Phần "-i -" cho ffmpeg đọc từ đường ống

(lưu ý - các tệp của tôi không có khoảng trắng hoặc nội dung lạ trong đó - bạn sẽ cần thoát vỏ phù hợp nếu bạn muốn thực hiện ý tưởng này với các tệp "cứng").


2
Đã làm điều này trên OSX và nó hoạt động rất tốt! Giải pháp tuyệt vời, nhanh chóng lossless với ít yêu cầu.
GM Lucid

1
Với lối thoát thích hợp cho các tệp chứa khoảng trắng: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
Bạn cũng có thể chỉ cần làm ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4nếu các tập tin của bạn được đặt tên tốt và theo thứ tự. Làm việc tuyệt vời cho tôi trên OS X, chính xác những gì tôi muốn.
natebeaty

3
Trên Linux tôi đã sử dụng oneliner này: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv chấp nhận nhiều codec hơn mp4, nhưng bạn cũng có thể thử nó với mp4). Các -safe 0là dành cho phiên bản ffmpeg gần đây phàn nàn về tên file không an toàn , và -type fchỉ dành cho danh sách tập tin. Tôi đã thêm | sortđể sắp xếp các tập tin theo thứ tự abc; bởi vì findđọc chúng theo thứ tự như được lưu trên hệ thống tập tin. Hoạt động cũng cho các tập tin với khoảng trắng.
erik

12
Tôi đã phải thêm tham số này ffmpegđể làm cho nó hoạt động:-protocol_whitelist file,tcp,http,pipe
Bensge

44

cho các tệp MP4:

Nếu chúng không hoàn toàn giống nhau (100% cùng một codec, cùng độ phân giải, cùng loại) các tệp MP4, thì trước tiên bạn phải chuyển mã chúng thành các luồng trung gian:

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

GHI CHÚ! : Đầu ra sẽ giống như tệp đầu tiên (chứ không phải tệp thứ hai)


2
Như minh họa trong câu trả lời của tôi, bên dưới, việc chuyển mã các tập tin là không cần thiết. FFmpeg có thể ghép nhiều tệp mp4 thành một tệp mp4 - không cần bất kỳ bước trung gian nào và không có bất kỳ mã hóa lại nào. Trường hợp duy nhất trong đó bất kỳ mã hóa lại nào sẽ cần thiết là nếu các tệp gốc không phải là tệp mp4 nhưng ý định là tạo một tệp mp4 làm tệp đầu ra.
Ed999

@T. Todua: Tôi muốn tìm hiểu chính xác sự khác biệt giữa hai tệp nguồn mp4 của bạn là gì. Có phải họ đang sử dụng các tốc độ mẫu khác nhau (ví dụ 44.100 Hz và 48.000 Hz)? Hay họ đang sử dụng các tốc độ bit khác nhau (ví dụ: 128 kbps và 64 kbps)? Trong cả hai trường hợp như vậy, tôi hoàn toàn không hiểu cách sao chép lệnh -c (một lệnh sao chép luồng) sẽ sửa đổi các tệp nguồn để làm cho chúng tương thích.
Ed999

4
@ T.Todua Xin chào, lệnh hoạt động tốt khi video không có rãnh âm thanh. Tuy nhiên, khi myfile1.mp4 không có âm thanh và myfile2.mp4 có âm thanh, kết quả output.mp4 không có âm thanh. Đầu ra dự kiến.mp4 nên chứa âm thanh. Làm thế nào tôi có thể giải quyết nó?
Trả lời vào

2
@ T.Todua er .... Thật tệ quá. File1 | file2 tạo video khác với file2 | file1. thứ tự là quan trọng.
Trả lờiZiao

1
Tôi đã thử lệnh của bạn trên concat 2 tập tin mp4. Nó hoạt động. Tuy nhiên, âm thanh của tập tin thứ hai trở nên chói tai như giọng nói của Ah-oh-Ee trong phần ghép mới được tạo ra. Bạn có một sửa chữa cho điều này?
superlinux

35

Tôi đã cố gắng ghép ba .mp3tệp âm thanh thành một .m4atệp và lệnh ffmpeg này hoạt động.

Lệnh đầu vào:

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

Ý nghĩa của: "-filter_complex concat = n = 3: v = 0: a = 1" :

concat có nghĩa là sử dụng chức năng concatenate (nối) phương tiện truyền thông.
n có nghĩa là xác nhận tổng số tập tin đầu vào.
v có nghĩa là có video ? sử dụng 0 = không có video, 1 = chứa video.
một phương tiện có âm thanh ? sử dụng 0 = không có âm thanh, 1 = chứa âm thanh.
-f có nghĩa là bắt buộc đặt định dạng tệp (để xem tất cả các định dạng được hỗ trợ, sử dụng ffmpeg -formats)
-vn có nghĩa là tắt video (và cũng -ansẽ tắt âm thanh nếu không muốn)
-y có nghĩa là ghi đè lên các tệp đầu ra (nếu tệp đầu ra đã tồn tại).

Để biết thêm thông tin: sử dụng ffmpeg -h full in tất cả các tùy chọn (bao gồm tất cả các tùy chọn định dạng và codec cụ thể, rất dài)


1
fi sử dụng cái này -f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"nó sẽ concat nhưng khi một số video có âm thanh và một số không có âm thanh thì nó không hoạt động làm sao tôi có thể sắp xếp cái này. Cảm ơn -
Ahmad

1
Những công việc này. Cảm ơn đã giải thích chi tiết trong câu trả lời của bạn. Nó rất hữu ích.
Joe T. Boka

31

Tôi đã kết thúc bằng cách sử dụng mpg làm định dạng trung gian và nó đã hoạt động (LƯU Ý đây là một ví dụ nguy hiểm, -qscale 0 sẽ mã hóa lại video ...)

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
Theo nhận xét này, -sameqđã được gỡ bỏ. Sử dụng -qscale 0thay thế.
Xavier Hồ

6
-sameqkhông có nghĩa là "cùng chất lượng" và đã bị xóa khỏi ffmpeg như được đề cập bởi @XavierHo.
llogan

3
Có vẻ xấu hổ khi phải chuyển mã video thông qua định dạng trung gian chỉ để ghép hai tệp. Bạn sẽ bị mất thế hệ. Tốt hơn là không đi sâu hơn định dạng chứa và sử dụng concatlệnh trong ffmpeg, như @rogerdpack đã làm ở trên.
Randall Cook

8
Làm thế nào đây là một câu trả lời được chấp nhận? Đây là phương pháp rất xấu.
Tên hiển thị

4
@SargeBorsch Vì nó hoạt động. Tôi đã thử mọi thứ khác trên trang-- Không ai trong số họ làm việc.

14

Tài liệu chi tiết về các cách ghép khác nhau trong ffmpeg có thể được tìm thấy ở đây .

Bạn có thể sử dụng 'Bộ lọc concat' để nối nhanh.

Nó thực hiện mã hóa lại. Tùy chọn này là tốt nhất khi đầu vào có các định dạng video / âm thanh khác nhau.

Để ghép 2 tệp:

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

Để ghép 3 tập tin:

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

Điều này hoạt động cho cùng một loại cũng như nhiều loại tập tin đầu vào.


bạn có thể chỉ định thêm chi tiết về các tùy chọn bạn có trong ví dụ này không?
Nhà phát triển

@ Nhà phát triển: Để giải thích về các tùy chọn -> Bộ lọc concat wiki
SJ00

4
Khi ghép 3 tệp bạn nên sử dụng concat = n = 3: v = 1: a = 1 không n = 2
Cynapsis

1
Tôi không nhận được kết nối không mất dữ liệu ouput.mp4bitrate video của tôi thấp hơn đáng kể so với bitrate video video đầu vào
jasan

Cảm ơn Cynapsis đã chỉ ra và georgiecasey đã cập nhật lệnh
SJ00

10

Tôi thấy toán tử đường ống không hoạt động với tôi khi sử dụng tùy chọn 3 để ghép một số MP4 trên máy Mac trong câu trả lời được chấp nhận.

Một lớp lót sau hoạt động trên máy Mac (High Sierra) để ghép các mp4, không cần tạo tệp trung gian.

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


2
Câu trả lời đơn giản này là người duy nhất thực sự làm việc cho tôi. Các trang trên các trang tài liệu ở đây và các nơi khác, trong khi một lớp lót đơn giản này là tất cả những gì được yêu cầu - và thực sự hoạt động. Cảm ơn bạn.
blujay

10

Dưới đây là 2 giải pháp bash thuần túy chỉ sử dụng ffmpegvà không sử dụng

  • một tập tin trung gian
  • perl, python hay javascript

Giải pháp một lớp lót sử dụng 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

Hàm có 0 hoặc 2+ đối số

#######################################
# 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
}

Lưu ý: đã thử một số giải pháp trong chủ đề này và không có gì làm tôi hài lòng


9

dựa trên phản hồi của rogerdpack và Ed999, tôi đã tạo phiên bản .sh của mình

#!/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

nó tham gia tất cả các *.mp4tập tin trong thư mục hiện tại vàojoined-out.mp4

thử nghiệm trên mac.

kích thước tập tin là tổng số chính xác của 60 tập tin thử nghiệm của tôi. Không nên mất mát. Đúng thứ tôi cần


9

cái này hiệu quả với tôi (trên windows)

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

một ví dụ...

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

Con trăn

Sử dụng một số mã python để làm điều đó với nhiều mp4 có trong một thư mục (cài đặt python từ python.org, sao chép và dán và lưu mã này vào một tệp có tên mp4.py và chạy nó từ cmd được mở trong thư mục với python mp4.py và tất cả các mp4 trong thư mục sẽ được nối)

import glob
import os

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

Phiên bản 2 với Python

Lấy từ bài đăng của tôi trên blog của tôi , đây là cách tôi làm điều đó trong 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
Giao thức concat không nên được sử dụng với MP4 và sẽ không hoạt động như được đề cập trong câu trả lời được chấp nhận .
llogan

@LordNeckbeard Tôi tự hỏi nếu bạn biết câu trả lời cho câu hỏi ffmpeg này về việc ghép 2 video MP4 trong khi chỉ định tốc độ bit đầu ra? video.stackexchange.com/q/24569/5657 Cảm ơn.
Ryan

@LordNeckbeard Tôi đoán là câu trả lời của bạn sẽ là câu trả lời hay nhất, nếu bạn sẵn sàng! Tôi không đặc biệt hài lòng với chính mình.
Ryan

Không chỉ (như Lord Neckbeard chỉ ra) là cần thiết để chuyển đổi tệp .mp4 sang định dạng .TS trung gian để ghép nối thành công, nhưng, thậm chí tệ hơn, câu trả lời này thậm chí không bắt đầu giải quyết nhu cầu đầu vào các tệp video có bitrate phù hợp, tốc độ khung hình, tốc độ mẫu, cơ sở thời gian và thời lượng. Nếu không có tất cả 5 yếu tố chung đó, các tệp không thể được nối (nghĩa là đã tham gia bằng cách sử dụng bản sao luồng ), nhưng phải được mã hóa lại thay thế.
Ed999

7

Đối với .mp4các tệp, tôi thấy nó hoạt động tốt hơn và nhanh hơn để sử dụng công cụ dòng lệnh opensource : mp4box. Sau đó, bạn có thể sử dụng nó theo cách này:

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

Tải xuống tại đây cho hầu hết các nền tảng: https://gpac.wp.imt.fr/mp4box/


2
Mặc dù điều này có thể hữu ích cho ai đó, nhưng yêu cầu là: " Tôi đang cố gắng ghép hai tệp mp4 bằng ffmpeg. Tôi cần điều này là một quy trình tự động ". Vui lòng đọc toàn bộ câu hỏi và thử và đưa ra câu trả lời đúng.
thvs86

5
Câu trả lời này là hoàn toàn trên điểm. Đây là một công cụ FOSS thực hiện cùng một công việc. Nó có thể được sử dụng trong một kịch bản giống như FFmpeg. Nó hoàn thành công việc đơn giản hơn bất kỳ câu trả lời FFmpeg nào. Hãy nhìn xem chúng phức tạp như thế nào! Một trong số họ sử dụng Node.js để gọi FFmpeg! Chứng điên cuồng. Hãy dừng lại với wonkism và thử và làm cho StackOverflow trở nên hữu ích một lần nữa. Trang web này là một cái bóng của bản thân trước đây của nó nhờ các won như bạn. Bên cạnh đó, câu hỏi này là một ví dụ về "Vấn đề XY", mà một wonk như bạn nên làm quen.
blujay

Nó không quan trọng rằng mp4box là một công cụ FOSS. Câu hỏi yêu cầu trả lời bằng ffmpeg, không phải mp4box.
jramos775

@ thvs86 Tôi là một ví dụ về điều đó. Tôi sử dụng ffmpeg vì nó là một con dao thụy sĩ thực sự cho phương tiện truyền thông. Tôi cũng tìm kiếm sự giúp đỡ với các trường hợp sử dụng cụ thể của mình, vì cấu trúc của các cuộc tranh luận có thể khá phức tạp (điều này được thể hiện bằng các câu trả lời khác nhau ở đây). Đây là lần đầu tiên tôi nghe về mp4box và tôi sẽ không tìm thấy nó nếu không có câu trả lời này. Vì vậy, +1 từ tôi và xin vui lòng, hãy suy nghĩ nhiều hơn về những người tìm kiếm câu trả lời hơn là về các điểm Internet vô nghĩa và các quy tắc cứng nhắc.
Pavel

4

Đây là một kịch bản tôi đã thực hiện để ghép một số mp4 của GoPro thành một mp4 720p. Hy vọng nó sẽ giúp.

#!/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}

Đây không phải là nối. Mã này không nối các đầu vào, nó mã hóa lại chúng. Điều này nhận bất kỳ tệp video tùy ý và thay đổi chúng thành bitrate âm thanh và video phổ biến (bất kể tốc độ bit gốc hoặc khung hình gốc của tệp nguồn). O / p muốn tham gia hai tệp bằng cách sử dụng sao chép luồng, không mã hóa lại chúng, vì vậy điều này không giải quyết được câu hỏi được hỏi.
Ed999

4

Từ tài liệu ở đây: https://trac.ffmpeg.org/wiki/Concatenate

Nếu bạn có tập tin MP4, những có thể được losslessly nối bằng chuyển mã đầu tiên họ đến con suối MPEG-2 vận chuyển. Với video H.264 và âm thanh AAC, có thể sử dụng các mục sau:

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

Cách tiếp cận này hoạt động trên tất cả các nền tảng.

Tôi cần khả năng gói gọn điều này trong một kịch bản đa nền tảng, vì vậy tôi đã sử dụng fluent-ffmpegvà đưa ra giải pháp sau:

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
Không chỉ đăng một câu trả lời, bạn có thể thêm một chút giải thích để hiểu giải pháp tốt hơn cho OP và cả những độc giả tương lai.
Balagurunathan Marimuthu

1
Điều này tạo ra một video im lặng mới với cả hai đầu vào phát cùng lúc cạnh nhau. Tôi dự kiến ​​kết nối sẽ tạo ra một video trong đó input_1.mp4 đã phát và sau đó input_2.mp4
Roche

3
Đây là câu trả lời sai hoàn toàn. Điều này không kết hợp các video, nó chỉ phát âm thầm bên cạnh nhau, như @AlexxRoche đã đề cập.
Kalob Taulien

1

Hợp nhất tất cả các tệp mp4 từ thư mục hiện tại

Tôi cá nhân như không tạo tệp bên ngoài mà tôi phải xóa sau đó, vì vậy giải pháp của tôi là theo sau bao gồm danh sách đánh số tệp (như 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

Tôi đã sao chép mã này vào Notepad và không có gì xảy ra.
7vujy0f0hy

1
@ 7vujy0f0tại sao điều này hoạt động trên linux với shell bash có lẽ nó có thể hoạt động với cygwin
Pipo

1

Sau nhiều lần thử, kịch bản dưới đây đã hoạt động với tôi trên 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

Ở đây hai dòng đầu tiên tạo một tệp văn bản temp.txt có nội dung sau

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

Các dòng thứ 3, 4 kiểm tra xem ffmpeg có sẵn tại đường dẫn hay không và tạo "gia nhập.mp4"

Sự khác biệt chính từ các câu trả lời khác như dưới đây

usage  of -bsf:v hevc_mp4toannexb -an

đối với tệp mp4 của tôi ở trên đã hoạt động, bạn có thể cần phải sử dụng các lựa chọn thay thế khác như bên dưới tùy thuộc vào mã hóa video của bạn.

h264_mp4toannexb

Tất cả các bộ lọc Bitstream có thể có thể được tìm thấy tại https://ffmpeg.org/ffmpeg-bitstream-filters.html


Của tôi là MP4 đến từ một camera quan sát. Không có lệnh đó, cuộc hội thoại không thể tạo tệp đầu ra. Tôi đang sử dụng ffmpeg mới nhất từ ​​trang web của mình.
rahul maindargi

0

Đây là phương pháp của tôi để tham gia một thư mục chứa đầy các tệp MP4 bằng cách sử dụng thay thế lệnh và bộ lọc video concat (điều này sẽ mã hóa lại) - hình dung người khác sẽ nhận được một số sử dụng từ lớp lót này, đặc biệt là nếu bạn có nhiều tệp (tôi chỉ đã tham gia 17 tập tin trong một cú trượt ngã):

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

Lưu ý lệnh này tham gia các tệp của bạn theo thứ tự chúng được đặt tên (nghĩa là thứ tự giống như chúng được trình bày nếu bạn chạy ls *.mp4) - trong trường hợp của tôi, mỗi tệp đều có số theo dõi, vì vậy nó hoạt động rất tốt.


0

Giao thức concat được mô tả ở đây; https://trac.ffmpeg.org/wiki/Concatenate#protatio

Khi thực hiện sử dụng đường ống có tên để tránh các tập tin trung gian

Rất nhanh (đọc: tức thời), không có khung hình bị rơi và hoạt động tốt.

Nhớ xóa các tập tin đường ống được đặt tên và nhớ kiểm tra xem video có phải là H264 và AAC mà bạn có thể làm chỉ với ffmpeg -i filename.mp4(kiểm tra h264 và aac đề cập)


-1

Câu trả lời được chấp nhận dưới dạng tập lệnh PowerShell có thể sử dụng lại

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
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.