Tham gia tập tin mp4 trong linux


31

Tôi muốn tham gia hai tập tin mp4 để tạo một tập tin duy nhất. Các luồng video được mã hóa trong h264 và âm thanh trong aac. Tôi không thể mã hóa lại video sang định dạng khác vì lý do tính toán. Ngoài ra, tôi không thể sử dụng bất kỳ chương trình GUI nào, tất cả việc xử lý phải được thực hiện với các tiện ích dòng lệnh Linux. FFmpeg không thể làm điều này cho các tệp mpeg4 vì vậy thay vào đó tôi đã sử dụng MP4Box:

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

Thật không may, âm thanh bị lẫn lộn. Tôi nghĩ rằng vấn đề là âm thanh trong aac nên tôi đã chuyển mã nó thành mp3 và sử dụng lại MP4Box. Trong trường hợp này, âm thanh vẫn ổn trong nửa đầu newvideo.mp4(tương ứng với video1.mp4) nhưng sau đó chúng không có âm thanh và tôi cũng không thể điều hướng trong video.

Suy nghĩ tiếp theo của tôi là các luồng âm thanh và video có một số khác biệt nhỏ về độ dài mà chúng nên sửa. Vì vậy, đối với mỗi video đầu vào, tôi chia các luồng video và âm thanh và sau đó nối chúng với tùy chọn -shortest trong FFmpeg.

Vì vậy, cho video đầu tiên tôi chạy:

 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

Tương tự cho video thứ hai và sau đó sử dụng MP4Box như trước đây. Thật không may, điều này cũng không hoạt động. Thành công duy nhất tôi có là khi tôi tham gia các luồng video một cách riêng biệt (ví dụ: videostream1.mp4 và videostream2.mp4) và các luồng âm thanh (ví dụ: audiostream1.m4a và audiostream2.m4a) và sau đó tham gia video và âm thanh trong một tệp cuối cùng. Tuy nhiên, đồng bộ hóa bị mất trong nửa sau của video. Cụ thể, có độ trễ 1 giây của âm thanh và video. Bất kỳ đề xuất đều thực sự được chào đón.


"FFmpeg không thể làm điều này cho các tệp mpeg4 vì vậy thay vào đó tôi đã sử dụng MP4Box", ý bạn là tệp MP4? cả hai luồng âm thanh-video có sử dụng cùng một tham số mã hóa (chiều rộng, chiều cao, SPS, PPS, tốc độ khung hình, lấy mẫu, số lượng kênh không?

sử dụng ffprobe Tôi thấy rằng các luồng âm thanh có thuộc tính giống hệt nhau. Các luồng video có cùng kích thước nhưng tỷ lệ khác nhau. Đối với video đầu tiên Video: h264, 720x592, 277 kb / s, PAR 18944: 12915 DAR 512: 287, 24.97 fps, 45k tbr, 90k tbn, 90k tbc trong khi cho Video thứ hai: h264, 720x592, 226 kb / s, PAR PAR: 330 DAR 39:22, 24,91 khung hình / giây, 45k tbr, 90k tbn, 90k tbc. Bạn có tin rằng đây là nguồn gốc của vấn đề của tôi?

MP4 hỗ trợ nối video / âm thanh với các đặc điểm khác nhau bằng cách sử dụng bản nhạc khác nhau cho video khác nhau, nhưng trình phát không thông minh.
rajneesh


Câu hỏi của bạn đã được trả lời trong ffmpeg FAQ: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Câu trả lời:


31

Cách tốt nhất để làm điều này hiện nay là với bộ giải mã concat . Đầu tiên, tạo một tệp gọi là inputs.txtđịnh dạng như vậy:

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

Sau đó, chỉ cần chạy lệnh ffmpeg này:

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

Xem thêm phần ghép trong ffmpegFAQ .


Tôi giữ những điều sau đây vì lợi ích của bất kỳ ai sử dụng các phiên bản cũ hơn của ffmpeg.

Các phiên bản mới nhất của ffmpeg có thể làm điều này: trước tiên bạn sẽ phải chuyển các tệp vào luồng truyền tải mpeg (khá nhẹ bộ xử lý, vì nó chỉ thay đổi định dạng vùng chứa):

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

Nếu điều đó gây ra lỗi về h264, bạn có thể cần phải sử dụng:

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

Bạn sẽ phải làm điều này một cách riêng biệt với mỗi tệp đầu vào. Để ghép các tệp lại với nhau, sử dụng:

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

Nếu điều đó gây ra lỗi về aac, bạn có thể cần phải sử dụng

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

Nếu hệ thống của bạn hỗ trợ các đường ống có tên, bạn có thể làm điều này mà không cần tạo các tệp trung gian.

mkfifo temp0 temp1

Bạn sẽ phải làm như sau trong ba thiết bị đầu cuối ảo riêng biệt:

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

Nếu output.mp4 đã tồn tại, ffmpeg thứ ba sẽ hỏi bạn có muốn ghi đè lên nó không, nhưng nó sẽ thực hiện điều này sau khi nó đã truy cập vào các FIFO và điều này sẽ khiến ffmpegs đầu tiên đóng lại. Vì vậy, hãy chắc chắn rằng bạn chọn một tên không sử dụng cho tệp đầu ra của bạn.

Điều này có thể không hoạt động nếu các tệp đầu vào của bạn khác nhau - Tôi tin rằng sự khác biệt về tốc độ bit là OK, nhưng kích thước khung hình, tốc độ khung hình v.v ... phải khớp với nhau.


nhiều người bạn đời, làm việc như một bùa mê
Jose Armando

2
@DaveJarvis Không phải vậy; đó là một thông điệp được lan truyền một cách có chủ ý và độc hại bởi nhóm libav, một nhóm các nhà phát triển tách ra từ dự án ffmpeg để phát triển avconv (và thay đổi tên vì họ không thể bảo mật bản quyền cho tên ffmpeg). Xem Ai có thể cho tôi biết sự khác biệt và mối quan hệ giữa ffmpeg, libav và avconv? để biết thêm một chút thông tin
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.là một thông điệp tôi thấy bây giờ khi chạyffmpeg
Lord Loh.

@LordLoh. Xem liên kết trong bình luận trước của tôi.
evilsoup

1
Câu trả lời đó không trả lời - làm thế nào để ghép mp4 vớiavconv
Lord Loh.

7

Đối với mp4, giải pháp làm việc duy nhất tôi tìm thấy là với MP4Box từ gói 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

hoặc lệnh là

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

với mencoder và avconv tôi không thể làm cho nó hoạt động :-(


2

Cảm ơn kịch bản dvo. Đó là một điểm khởi đầu tuyệt vời cho tôi. Tôi không gặp vấn đề gì với việc sử dụng các ống có tên nên tôi đã điều chỉnh kịch bản để sử dụng chúng thay thế. Thêm vào đó tôi đã sửa nó để làm việc với tên tệp có khoảng trắng trong đó. Đầu ra cho các ống được đặt tên không "đi" cho đến khi bạn bắt đầu đọc từ chúng, do đó cần phải làm nền cho các tác vụ làm lại ban đầu với một & trước lệnh gọi cuối cùng đến avconv. Ngoài ra, đừng quên sử dụng bản sao -c hoặc cuối cùng bạn sẽ mã hóa lại toàn bộ.

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

Vì một số lý do, điều này mang lại cho tôi lỗi "concat: first.m4v.fifo | second.m4v.fifo: Không có tệp hoặc thư mục như vậy" .. ngay cả với dấu ngoặc kép (-i concat: "$ IN" hoặc -i "concat: $ IN "). MP4Box đề xuất trong câu trả lời khác dưới đây tuy nhiên hoạt động rất tốt!
vorburger

2

Trên máy Mac (macOS 10.13 High Sierra) tôi đã sử dụng thành công như sau:

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

Sắp xếp lại như trên tương tự nếu cần thiết (lưu ý rằng ./ đã bị xóa - đường dẫn đã khiến ffmpeg ném lỗi tên tệp không an toàn).

Sau đó, tôi đã phải loại bỏ codec và bitrate được chỉ định cho ffmpeg mặc định của MacPort để thích nó:

ffmpeg -f concat -i mylist.txt  output.m4a

Chào mừng bạn đến với Super User!, Vui lòng đọc lại câu hỏi một cách cẩn thận. Câu trả lời của bạn không trả lời câu hỏi ban đầu về linux. Nếu bạn tin rằng nó sẽ hoạt động trên linux, vui lòng thêm rằng để người đọc trong tương lai hiểu rõ hơn, ngoài điều đó một lần nữa chào mừng bạn đến với superuser và thankyou cho đầu vào của bạn. Vui lòng dành vài phút và đọc: - superuser.com/help. Trả lời: superuser.com/help/how-to-answer .
mic84

2

Đây là một lớp lót làm cho nó dễ dàng hơn nhiều. Nó thực hiện mọi thứ cần thiết để cuối cùng cung cấp cho bạn một tệp video kết quả. Chúc mừng!

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

1

Cảm ơn evilsoup; đây là một đoạn script nhỏ để tự động hóa quá trình, sử dụng gần đây hơn avconv.
BTW, đường ống có tên không hoạt động đối với tôi (đầu ra cho chúng bị kẹt).

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

0

Đã tận hưởng thành công lớn với

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

bạn có thể cần phải sắp xếp lại mylist.txt một chút

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

phiên bản ffmpeg 2.2.3

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.