2015-07-19 15 views
9

Tôi có một bộ hoạt ảnh mà tôi có thể tạo trong Canvas (fabric.js) hoặc WebGL (three.js). Tôi cần phải ghi lại chúng tự động, phía máy chủ, thông qua một kịch bản và đầu ra một tập tin video.Cách tốt nhất để ghi lại máy chủ hoạt ảnh HTML Canvas/WebGL thành video?

Những hình ảnh động bao gồm:

  1. Hình
  2. Video (với âm thanh)
  3. hình ảnh động khác/hiệu ứng

Tôi đã nghiên cứu rất nhiều trong vài tháng vừa qua về vấn đề này .

Kết quả
1. PhantomJS tài + FFMPEG
hình ảnh động Run HTML Canvas trên trình duyệt không đầu (PhantomJS) và kỷ lục với FFMPEG. Ở đây vấn đề là PhantomJS không hỗ trợ WebGL và phần tử Video.http://phantomjs.org/supported-web-standards.html

2. Sử dụng Websockets để gửi dữ liệu trở lại máy chủ sử dụng DataURL
Một lần nữa, chúng tôi sẽ cần phải chạy các hình ảnh động trên trình duyệt (mà chúng ta không thể bởi vì chúng ta phải làm tất cả mọi thứ trên máy chủ) .

3. Use node-canvas
Đây là thư viện của TJ Holowaychuk cho phép hiển thị HTML Canvas trên Node.js. Nhưng nó có những hạn chế riêng của nó cộng với tôi đã không thực sự khám phá lĩnh vực này nhiều. (Nếu ai đó có thể chiếu sáng nhiều hơn trên thư viện này)

Nếu có ai đã làm trước hoặc có thể hướng dẫn tôi ở đâu đó hữu ích.
Tất cả những gì chúng ta cần làm là sử dụng một số dữ liệu để tạo hoạt ảnh và ghi lại nó thành video, mọi thứ ở phía máy chủ.

+0

'node-canvas' có vẻ như trong ngữ cảnh 2d. Tôi đã tìm thấy gói 'node-webgl' nhưng không thành công để cài đặt các phụ thuộc của nó. Tuy nhiên như một bình luận tôi phải viết: nếu bạn muốn ghi lại một ngữ cảnh webgl (và sử dụng nó như một công cụ dựng hình) để xuất video cho chính mình, 1-by-1, bạn có thể làm điều đó phía máy chủ với 'xhr' trên một máy chủ cục bộ. Nhưng nếu bạn muốn xuất video cho mỗi người dùng được kết nối trên internet, chỉ cần xem xét rằng nó yêu cầu serverSSS của bạn có một cặp CPU-GPU cho mỗi khách truy cập. Tôi đã kiểm tra google cho 'dựng hình 3D phía máy chủ': hiện tại không có gì nghiêm trọng với công nghệ năm 2015. – Atrahasis

+0

Ngoài ra: những gì bạn mô tả là cách để sử dụng webgl như một công cụ dựng hình cho chính mình, đó là lý do tại sao tôi đã viết về nó ở trên. Nếu bạn chỉ tìm cách để thực hiện điều đó trên trang web, câu hỏi của bạn là bản sao của http://stackoverflow.com/questions/64291/api-for-server-side-3d-rendering. Nhưng tất cả các câu trả lời ở đó, không có gì mang lại ^^ – Atrahasis

+0

@Atrahasis Nếu chúng ta chỉ muốn ghi lại Canvas và KHÔNG webGL. Nút-canvas có thể được sử dụng cho nó không? Nó có hỗ trợ video và hoạt ảnh không? – Abhinav

Trả lời

1

Tôi không nghĩ rằng khung hình hỗ trợ ngữ cảnh webgl, do đó bạn sẽ sử dụng thư viện được xây dựng quanh bản vẽ 2 chiều và chắc chắn sẽ không hỗ trợ bất kỳ codec video nào.

Nếu bạn có thể nhận được hình ảnh động của bạn để làm việc sử dụng nút-canvas, bạn có thể lấy khung hoạt hình tại một phù hợp tỷ lệ cho nội dung của bạn, một cái gì đó như thế này:

Tiết lộ: Tôi đã thành công đã sử dụng FFmpeg để mã hóa một chuỗi hình ảnh được tạo bên ngoài, nhưng chưa thử phương thức setInterval() bên dưới. Ngoài các hình ảnh động trên đầu nó, tôi không biết làm thế nào xuất khẩu một vải để PNG tập tin tại 30 FPS sẽ thực hiện.

// assuming "canvas" is asynchronously drawn on some interval 

function saveCanvas(canvas, destFile) { 
    return new Promise((resolve, reject) => { 
    const ext  = path.extname(destFile), 
      encoder = '.png' === ext ? 'pngStream' 
            : 'jpegStream'; 
    let writable = fs.createWriteStream(destFile), 
     readable = canvas[encoder](); 

    writable 
     .on('finish', resolve) 
     .on('error', err => { 
     let msg = `cannot write "${destFile}": ${err.message}`; 
     reject(new Error(msg)); 
     }); 
    readable 
     .on('end', () => writable.end()) 
     .on('error', err => { 
     let msg = `cannot encode "${destFile}": ${err.message}`; 
     reject(new Error(msg)); 
     }); 
    readable.pipe(writable); 
    }); 
} 

const FPS = 30; 

let frame = 0, 
    tasks = [], 
    interval = setInterval(() => tasks.push(
    saveCanvas(canvas, `frame_${frame++}.png`)), 1000/FPS); 

// when animation is done, stop timer 
// and wait for images to be written 
clearInterval(interval); 

Promise.all(tasks).then(encodeVideo); 

function encodeVideo() { 
    // too much code to show here, but basically run FFmpeg 
    // externally with "-i" option containing "frame_%d.png" 
    // and "-r" = FPS. If you want to encode to VP9 + WEBM, 
    // definitely see: http://wiki.webmproject.org/ffmpeg/vp9-encoding-guide 
} 

Và sau đó sử dụng FFmpeg để mã hóa chuỗi hình ảnh thành video.
Đối với mã phía sau encodeVideo(), bạn có thể xem this example.

Sửa: Có thể có một vấn đề với canvas.pngStream() viết khung không chính xác khi vòng lặp hình ảnh động liên tục dựa trên rằng một canvas - có thể là một bản sao của bức tranh cần phải được tạo mỗi khung? Điều đó chắc chắn sẽ tạo ra áp lực bộ nhớ đáng kể.

2

Bạn có thể sử dụng điện tử để hiển thị các trang WebGL có tùy chọn BrowserWindow "hiển thị" được đặt thành false và/hoặc sử dụng xvfb-run để chạy không đầu.

Các vấn đề liên quan