有办法通过代码生成生成视频帧的内容吗?
例如:
我想制作一个程序,它以一些string变量作为输入,然后给出一个相同文本的输出视频,但现在对文本本身有特殊的影响。
在看到Facebook在他们的网站上做的一些项目后,我想到了这个想法。他们有一个与用户相关的图片、评论、朋友、事件、喜欢等等的数据库。所有这些信息,他们做的视频,例如朋友节,视频是完全相关的用户,想发布它。
这些东西是怎么工作的?
有什么软件我可以用吗?有人能给我一个开始的地方吗?
发布于 2017-02-09 19:03:31
我想要做一个程序,以一些字符串变量作为输入,然后提供一个输出视频相同的文本,但现在具有特殊效果的文本本身。
您可以使用画布呈现文本,并使用新的媒体记录器API记录结果。
当然,这种效果可以通过多种方式产生,文本内容本身可以针对数据库使用,也可以与机器学习相结合来构造/获取与文本相关的数据。不过,这是一个很广的范围,比这里适用的范围更广。
无论如何,视频本身的生成如下所示。这是一个简单的例子,你可以输入一些文本,它会得到动画和录制为视频。当您单击“停止”时,实际的视频将显示出来(您可以允许用户下载)。您可以扩展与其他效果,故事板的功能,以便您可以记录场景,并开发它来制作一个完整的电影。
请注意,所有的动画发生在画布上的实时。典型的视频以每秒30帧的速度记录,而不是每秒60帧,这是画布的典型帧速率。这也是在平滑方面要考虑的问题。但是,您可以通过瞄准30个FPS来利用这一点来给您的代码更多的时间来处理。API应该通过不给出一个帧速率作为参数来支持步骤记录,但是到目前为止,我还没有能够完成这个工作。
目前对API的支持是有限制的,因为并不是所有的浏览器都支持它。
示例
// un-refined code for demo use only
// set up globals, get key elements
var div = document.querySelector("div");
var btn = document.querySelector("button");
var txt = document.querySelector("input");
var c = document.querySelector("canvas");
// make 2d context without alpha channel
var ctx = c.getContext("2d", {alpha: false});
var isRecording = false;
// stream vars
var rec, stream, tref;
// if clicked, lets go
btn.onclick = setup;
function setup() {
// toggle button text/status for demo
if (isRecording) {
this.disabled = true;
this.innerHTML = "Making video...";
stop();
return
}
else {
isRecording = true;
this.innerHTML = "Click to stop & show video";
}
// Setup canvas for text rendering
var ct1 = document.createElement("canvas");
var ct2 = document.createElement("canvas");
var ctxText1 = ct1.getContext("2d");
var ctxText2 = ct2.getContext("2d");
var w, h;
w = ct1.width = ct2.width = c.width;
h = ct1.height = ct2.height = c.height;
setupCtx(ctxText1, "#333", "#FF9F05");
setupCtx(ctxText2, "#FF9F05", "#000");
function setupCtx(ctxText, bg, fg) {
ctxText.textAlign = "center";
ctxText.textBaseline = "middle";
ctxText.font = "92px sans-serif";
ctxText.fillStyle = bg;
ctxText.fillRect(0, 0, w, h);
ctxText.fillStyle = fg;
ctxText.translate(w/2, h/2);
ctxText.rotate(-0.5);
ctxText.fillText(txt.value.toUpperCase(), 0, 0);
}
// populate grid (see Square object below which handles the tiles)
var cols = 18,rows = 11,
cellWidth = (c.width / cols)|0,
cellHeight = (c.height / rows)|0,
grid = [],
len = cols * rows, y = 0, x,
index, hasActive = true;
for (; y < rows; y++) {
for (x = 0; x < cols; x++) {
grid.push(new Square(ctx, x * cellWidth, y * cellHeight, cellWidth, cellHeight, ct1, ct2, 0.01));
}
}
x = 0;
// start recording canvas to video
record();
//animation loop (refactor at will)
function loop() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.globalAlpha = 1;
ctx.clearRect(0, 0, w, h);
// trigger cells
for (y = 0; y < rows; y++) {
var gx = (x | 0) - y;
if (gx >= 0 && gx < cols) {
index = y * cols + gx;
grid[index].trigger();
}
}
x += 0.25;
// update all
for (var i = 0; i < grid.length; i++) grid[i].update();
tref = requestAnimationFrame(loop);
}
// setup media recorder to record canvas @ 30 FPS (note: canvas = 60 FPS by def.)
function record() {
stream = c.captureStream(30);
rec = new MediaRecorder(stream);
rec.addEventListener('dataavailable', done);
rec.start();
requestAnimationFrame(loop);
}
}
// stop recorder and trigger dataavailable event
function stop() {
rec.stop();
cancelAnimationFrame(tref); // stop loop as well
}
// finish up, show new shiny video instead of canvas
function done(e) {
var blob = new Blob([e.data], {"type": "video/webm"});
var video = document.createElement("video");
document.body.removeChild(c);
document.body.appendChild(video);
// play, Don
video.autoplay = video.loop = video.controls = true;
video.src = URL.createObjectURL(blob);
video.onplay = function() {
div.innerHTML = "Playing resulting video below:";
};
}
// stolen from a previous example I made (CC3.0-attr btw as always)
// this is included for the sole purpose of some animation.
function Square(ctx, x, y, w, h, image, image2, speed) {
this.ctx = ctx;
this.x = x;
this.y = y;
this.height = h;
this.width = w;
this.image = image;
this.image2 = image2;
this.first = true;
this.alpha = 0; // current alpha for this instance
this.speed = speed; // increment for alpha per frame
this.triggered = false; // is running
this.done = false; // has finished
}
Square.prototype = {
trigger: function () { // start this rectangle
this.triggered = true
},
update: function () {
if (this.triggered && !this.done) { // only if active
this.alpha += this.speed; // update alpha
if (this.alpha <= 0 || this.alpha >= 1)
this.speed = -this.speed;
}
var t = Math.sin(Math.PI * this.alpha);
if (t <= 0) this.first = !this.first;
this.ctx.fillStyle = this.color; // render this instance
this.ctx.globalAlpha = Math.max(0, Math.min(1, t));
var cx = this.x + this.width * 0.5, // center position
cy = this.y + this.width * 0.5;
this.ctx.setTransform(t*0.5+0.5, 0, 0, t*0.5+0.5, cx, cy); // scale and translate
this.ctx.rotate(-Math.PI * (1 - t)); // rotate, 90° <- alpha
this.ctx.translate(-cx, -cy); // translate back
this.ctx.drawImage(this.first ? this.image : this.image2, this.x, this.y, this.width, this.height, this.x, this.y, this.width, this.height);
}
};body {background: #555;color:#ddd;font:16px sans-serif}<div>
<label>Enter text to animate: <input value="U R AWESOME"></label>
<button>Click to start animation + recording</button>
</div>
<canvas width=640 height=400></canvas>
https://stackoverflow.com/questions/42079205
复制相似问题