Làm cách nào để mã hóa một chuỗi hình ảnh jpg thành video trong ffmpeg?


21

Tôi có một bộ jpg lớn mà tôi muốn chuyển đổi thành video một cách dễ dàng (hoặc, ít nhất, rất gần với lossless miễn là thời gian mã hóa không cao hơn nhiều so với khác).

Ngây thơ, tôi nghĩ rằng nên có một số codec có thể lưu trữ từng khung jpg riêng lẻ (không cần nén lại) và có thể đạt được một số nén tốt bằng cách thay thế một số khung bằng thông tin trên delta từ khung trước đó. Trong trường hợp của tôi, có nhiều chuỗi khung giống hệt nhau hoặc có sự khác biệt nhỏ giữa chúng.

Có một số codec và cài đặt phù hợp cho ffmpeg có thể đạt được điều này?




1
chuỗi-jpeg đã là một codec trong một thời gian dài. Máy ảnh kỹ thuật số không sử dụng h.264 luôn ghi MJPEG và thẻ ghi video được sử dụng để sử dụng nó, tôi nghĩ vậy.
Peter Cordes

Câu trả lời:


24

Chỉ cần mux các hình ảnh

Bạn chỉ có thể mux các hình ảnh JPG để tạo video:

ffmpeg -framerate 30 -i input%03d.jpg -codec copy output.mkv

Lưu ý rằng nếu bạn bỏ qua -frameratethì một mặc định -framerate 25sẽ được áp dụng cho đầu vào.

Tối ưu hóa lossless

Bạn có thể sử dụng jpegtranđể thực hiện tối ưu hóa lossless trên mỗi khung có thể giúp tiết kiệm kích thước tệp đáng kể:

mkdir outputdir
for f in *.jpg; do jpegtran -optimize -copy none -perfect -v "$f" > "outputdir/$f"; done

Bây giờ mux với ffmpegnhư hình trên.

Kiểm tra xem nó thực sự là lossless

Các muxer framehash thể được sử dụng để so sánh băm độc đáo của mỗi khung để đảm bảo rằng kết quả là thực sự lossless:

$ ffmpeg -i input%03d.jpg -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

$ ffmpeg -i output.mkv -map 0:v -f framehash -
stream_index, packet_dts, packet_pts, packet_duration, packet_size, hash
0,          0,          0,        1,   460800, 29bcc2db3726c7dfec1826c5740f603f
0,          1,          1,        1,   460800, b5fdc23d93cbd043dc2b9290dc8378f0
0,          2,          2,        1,   460800, ee0709942f24b458fd2380d134dcb59d
...

Trong các ví dụ trên, mỗi khung được liên kết cho đầu vào và đầu ra chia sẻ cùng một hàm băm đảm bảo rằng các khung giống hệt nhau và đầu ra không bị mất.

Cũng thấy


bạn có thể vui lòng làm rõ những gì hai framemd5lệnh được cho là đạt được ngoài việc chỉ liệt kê các giá trị băm không? Làm thế nào tôi có thể nén bổ sung khi các khung giống hệt nhau được xác định như vậy?
GJ.

1
Các giá trị băm chỉ được đưa vào để cho bạn thấy rằng các khung giống như các hình ảnh riêng lẻ, do đó đạt được yêu cầu của bạn về việc lưu trữ "từng khung hình jpg riêng lẻ (không cần nén lại)".
llogan

Đăng một câu trả lời của riêng tôi với một ý tưởng chưa được kiểm tra để loại bỏ các khung trùng lặp, để kết thúc với VFR MJPEG.mkv. VFR là cách duy nhất tôi có thể nghĩ đến để tận dụng sự dư thừa tạm thời với MJPEG. : P
Peter Cordes

SSIM có thể là một cách nhanh hơn để so sánh độ trung thực.
Gyan

11

Điều này sẽ xuất ra một video H.264 không mất dữ liệu trong đó các khung sẽ sử dụng thông tin từ các khung khác

ffmpeg -f image2 -r 30 -i %09d.jpg -vcodec libx264 -profile:v high444 -refs 16 -crf 0 -preset ultrafast a.mp4

Giải thích về các lựa chọn:

  • -f image2 - bảo ffmpeg chọn một nhóm hình ảnh
  • -r 30 - yêu cầu ffmpeg mã hóa ở 30 khung hình (hoặc hình ảnh) mỗi giây (thay đổi khung hình này thành tốc độ khung hình mong muốn của bạn)
  • -i %09d.jpg- yêu cầu ffmpeg sử dụng các hình ảnh 000000000.jpg đến 999999999.jpg làm đầu vào. Thay đổi 9trong %09d.jpgbao nhiêu zero tên của chuỗi hình ảnh của bạn có. Nếu tên tệp của bạn là, ví dụ, img0001.jpg, thì tên này sẽ được biểu thị dưới dạng img% 04d.jpg
  • -vcodec libx264 - yêu cầu ffmpeg xuất ra tệp tương thích H.264
  • -profile:v high444 - yêu cầu libx264 sử dụng cấu hình Dự đoán tổn thất cao 4: 4: 4, cho phép mã hóa lossless
  • -refs 16 - nói với libx264 để có 16 hình ảnh được lưu trữ trong bộ đệm, để chúng có thể được tham chiếu bởi các hình ảnh khác trong video
  • -crf 0 - nói với libx264 để thực hiện mã hóa lossless
  • -preset ultrafast - yêu cầu libx264 ưu tiên tốc độ mã hóa so với kích thước tệp đầu ra
  • a.mp4- bảo ffmpeg lưu đầu ra trong tệp MP4 có tên a.mp4. Thay đổi tên này thành tên tệp và định dạng mà bạn muốn sử dụng

3
Một vài lưu ý: -f image2là không cần thiết ở đây. Các demuxer tập tin hình ảnh nên sử dụng -frameratethay vì -r. libx264 sẽ tự động chọn cái thích hợp -profilecho lossless, và -presetsẽ xử lý -refs.
llogan

-refs 5tại MOST, trừ khi bạn biết nội dung của mình có các hình ảnh giống hệt nhau được phân tách bằng một số hình ảnh khác, điều đó có thể khiến x264 mất tham chiếu trước khi nó bị trùng lặp. Cao hơn so với ultrafastviệc tạo ra sự khác biệt nhỏ trong chế độ lossless, ngoại trừ mức tăng ~ 10% của CABAC so với CAVLC (với chi phí cpu cao ở mức bitrate cần thiết cho lossless). Nghiêm túc mà nói, trên một số 720x480p60 live-action (đầu ra deinterlace), superfastlà 28GB, slowerlà 27GB. Nếu thời gian mã hóa không thành vấn đề, nhưng thời gian giải mã thì không, hãy đảm bảo bạn tránh CABAC. Thậm chí có thể -tune fastdecode. Số lượng ref vừa phải không nên làm tổn thương.
Peter Cordes

Và nếu bạn có CPU để ghi, bạn thậm chí có thể thử -preset placebothêm một vài phần trăm.
DrYak

Ngoài ra để hoàn thiện h265 cũng có chế độ lossless riêng. -vcodec libx265 -x265-params lossless=1là lựa chọn tương đương. . ... Chế độ không mất mát
DrYak

5

Bạn có thể tạo ra một avihình ảnh động như một loạt các pnghình ảnh ( png lossless nên jpeg => pngchuyển đổi không nên làm suy giảm hình ảnh của bạn):

nếu hình ảnh của bạn được đặt tên img_0001.jpg

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec png video.avi

trong đó "25" là tốc độ khung hình bạn muốn trong video kết quả. -start_numberkhông cần thiết nếu là 1, nhưng sẽ hữu ích nếu số video đầu tiên của bạn không phải là 1.

Nếu bạn muốn mã hóa mjpegvới dòng lệnh chất lượng cao nhất là:

ffmpeg -r 25 -start_number 1 -f image2 -i "img_%04d.jpg" -vcodec mjpeg -qscale 1 video.avi

Và cái hay của việc này là bạn có thể chuyển đổi video thành một loạt hình ảnh:

ffmpeg -i video.avi "img_series_%04d.png"
ffmpeg -i video.avi "img_series_%04d.jpg"

v.v ...


Điều này không thực sự đáp ứng nhu cầu của người hỏi. Anh ta đang tìm kiếm một cách mà khung hình có thể được cập nhật một cách dễ dàng chỉ khi hình ảnh thay đổi. Điều này có nghĩa là cùng một hình ảnh có thể được sử dụng nhiều lần. Ngoài ra, bản chất jpeg không mất mát vì tôi tin rằng nó sử dụng nén jpeg ngay cả ở chất lượng tối đa.
AJ Henderson

Trên thực tế tôi đoán anh ấy đã sẵn sàng để có một số nén, mặc dù tôi không chắc nó sẽ diễn ra như thế nào trên các chuỗi dài của cùng một khung. Tôi vẫn nghĩ rằng một định dạng trình bày tốc độ khung hình thay đổi là những gì cần thiết mặc dù tôi không chắc chắn nếu ffmpeg hỗ trợ bất kỳ.
AJ Henderson

CorePNG cũng có thể tạo khung P. Thông thường jpeg không phải là nén không mất dữ liệu và tôi nghi ngờ mjpeg có thể tạo khung P. Tôi đồng ý Tôi không trả lời câu hỏi khi được hỏi, nhưng tôi đưa ra giải pháp để có một video không mất dữ liệu với ffmpeg.
Olivier S

4

Để mở rộng câu trả lời của LordNeckbeard, vâng, chỉ cần chuyển dữ liệu JPEG vào luồng video MJPEG. Đó sẽ là đại diện nhỏ nhất của chuỗi hình ảnh đầu ra chính xác, mặc dù MJPEG là một codec không hiệu quả khủng khiếp theo tiêu chuẩn ngày nay. (không có dự phòng thời gian, và thậm chí không có bất kỳ dự đoán nội bộ.

Bạn có thể tạo video MJPEG biến đổi tốc độ để tận dụng các hình ảnh trùng lặp trong đầu vào của mình.

ffmpeg -framerate 30 -i input%03d.jpg -vf mpdecimate -codec copy output.mkv  # doesn't work.

Hrm, điều này sẽ không hoạt động, vì mpdecimate sẽ không hoạt động trên dữ liệu nén và chúng tôi không thể để ffmpeg giải mã và sau đó jpeg lại dữ liệu hình ảnh mà không mất và chi phí CPU.

Có lẽ nếu bạn thay thế các tệp nguồn jpg trùng lặp bằng các tệp trống bằng số thứ tự đó, hoặc một cái gì đó?

Vì câu hỏi này thậm chí không phải là gần đây, tôi sẽ không dành thời gian để tìm ra cách thực hiện trừ khi có ai đó trả lời để hỏi làm thế nào. Nhưng vì MJPEG có thể đi vào bộ chứa mkv, tôi chắc chắn có thể có một tệp không sao chép dữ liệu jpeg cho các khung lặp lại, nhưng thay vào đó chỉ không có khung đầu ra để giải mã cho đến khi chuỗi trùng lặp là kết thúc.

Đây là một ý tưởng:

ffmpeg -framerate blah -input blah -vf mpdecimate -f mkvtimestamp_v2 mpdecimate.timestamps

Sau đó xóa (hoặc di chuyển sang một bên) tất cả các jpeg cho các khung mà mpdecimate muốn bỏ (có thể nó có một số tùy chọn ghi nhật ký? Hoặc -vf showinfo, và phân tích, và di chuyển hoặc liên kết cứng chỉ các khung hiển thị ở đầu ra của nó, bỏ lại phía sau các JPEG bị rơi?). chuyển đến MJPEG.mkv, sau đó làm gì đó với mkvmerge để thay thế dấu thời gian của khung bằng dấu thời gian từ đó mpdecimate.timestamps.

Nếu bạn là xcoding, thay vì chỉ chuyển dữ liệu jpeg sang MJPEG, việc này sẽ dễ dàng hơn, vì bạn chỉ cần sử dụng lệnh đầu tiên của tôi với mpdecimate và bất kỳ codec nào khác copy, và nó sẽ chỉ hoạt động (tm).

Tôi đã không thử bất cứ điều gì trong số này, vì đây là một câu hỏi cũ. Ngoài ra, lý do tôi chưa điền vào các khoảng trống về cách thực sự lọc thư mục jpeg của bạn dựa trên đầu ra mpdecimate hoặc cách thực sự sử dụng luồng dấu thời gian.

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.