This content originally appeared on Modern Web Development with Chrome and was authored by Paul Kinlan
<p>You should be able to create and edit videos using just the web in the browser.
It should be possible to provide a user-interface akin to Screenflow that lets
you create an output video that combines multiple videos, images, and audio into
one video that can be uploaded to services like YouTube.</p>
<p>This post is really just a statement of intent. I am going to start the long
process of working out what is and isn't available on the platform and seeing
how far we can get today.</p>
<p>During some of the thoughts on this project, I had a Carl Sagan moment - so
instead of inventing the universe to create an apple pie, I need to at least
create all the tools needed to build a video editor, especially if I want to
record the process of doing it. The fact that this post exists is because I know
I have some of the pieces in place and ready to go.</p>
<p>I don't think I am going to create one massively monolithic 'video editor', that
can be a business for someone else, but I do plan on trying to work out all the
pieces that are needed so that I can make it easy to create great videos on the
web and hopefully show a lot of people what is possible on the web.</p>
<p>Below is my rough one-page project plan:</p>
<p><strong>Use cases that I have:</strong></p>
<ul>
<li>I normally have to record all the device demos for Google I/O and Chrome
DevSummit and add in the overlays etc. Everyone on the team should be able to
do this.</li>
<li>The team often record screencasts and I would like to enable them to do it
quickly from a simple website and be able to the clean up the final output.</li>
<li>I need to build some products to keep sharp. ;)</li>
</ul>
<p><strong>Input:</strong></p>
<ul>
<li>[p0] Record audio from a microphone</li>
<li>[p0] Record video from a web camera [done - see below]</li>
<li>[p0] Embed external videos hosted on the web</li>
<li>[p0] Record the desktop</li>
<li>[p1] Record a remote stream</li>
<li>[p1] Record a <canvas> element</li>
<li>[p0] Load a file from the local device</li>
<li>[p1] Share a file from the local device (android share intent)</li>
</ul>
<p><strong>Manipulation:</strong></p>
<ul>
<li>[p1] Add watermarks</li>
<li>[p1] Add in filter effects to the image</li>
<li>[p0] Add in custom images as layers</li>
<li>[p0] Queue videos and overlay</li>
<li>[p0] Overlay separate tracks of audio and video</li>
<li>[p1] Overlay text at specific times</li>
<li>[p0] Crop video to size</li>
<li>[p0] Enable positioning and resizing of the video</li>
<li>[p0] Trim video / audio</li>
<li>[p0] Splice video / audio</li>
</ul>
<p><strong>Output:</strong></p>
<ul>
<li>[p0] Video file in webm format</li>
<li>[p1] VTT information</li>
<li>[p1] Video file in xyz format</li>
</ul>
<p><a href="https://glitch.com/edit/#!/camera-recorder?path=script.js:1:0">Code for this
video</a>
<a href="https://camera-recorder.glitch.me/">Demo</a></p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">init</span> <span style="color:#f92672">=</span> () => {
<span style="color:#66d9ef">let</span> <span style="color:#a6e22e">blobs</span>;
<span style="color:#66d9ef">let</span> <span style="color:#a6e22e">rec</span>;
<span style="color:#66d9ef">let</span> <span style="color:#a6e22e">stream</span>;
<span style="color:#a6e22e">captureBtn</span>.<span style="color:#a6e22e">onclick</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">async</span> () => {
<span style="color:#a6e22e">stream</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">await</span> <span style="color:#a6e22e">navigator</span>.<span style="color:#a6e22e">mediaDevices</span>.<span style="color:#a6e22e">getUserMedia</span>({<span style="color:#a6e22e">video</span><span style="color:#f92672">:</span> { <span style="color:#a6e22e">width</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">1280</span>,
<span style="color:#a6e22e">height</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">720</span> }, <span style="color:#a6e22e">audio</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>});
<span style="color:#a6e22e">videoElement</span>.<span style="color:#a6e22e">srcObject</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">stream</span>;
<span style="color:#66d9ef">let</span> <span style="color:#a6e22e">opts</span> <span style="color:#f92672">=</span> {<span style="color:#a6e22e">mimeType</span><span style="color:#f92672">:</span> <span style="color:#e6db74">'video/webm; codecs=vp9,opus'</span>};
<span style="color:#a6e22e">blobs</span> <span style="color:#f92672">=</span> [];
<span style="color:#a6e22e">download</span>.<span style="color:#a6e22e">style</span>.<span style="color:#a6e22e">display</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">'none'</span>
<span style="color:#a6e22e">rec</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">MediaRecorder</span>(<span style="color:#a6e22e">stream</span>, <span style="color:#a6e22e">opts</span>);
<span style="color:#a6e22e">rec</span>.<span style="color:#a6e22e">ondataavailable</span> <span style="color:#f92672">=</span> (<span style="color:#a6e22e">e</span>) => <span style="color:#a6e22e">blobs</span>.<span style="color:#a6e22e">push</span>(<span style="color:#a6e22e">e</span>.<span style="color:#a6e22e">data</span>);
<span style="color:#a6e22e">rec</span>.<span style="color:#a6e22e">onstop</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">async</span> () => {
<span style="color:#66d9ef">let</span> <span style="color:#a6e22e">blob</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Blob</span>(<span style="color:#a6e22e">blobs</span>, {<span style="color:#a6e22e">type</span><span style="color:#f92672">:</span> <span style="color:#e6db74">'video/webm'</span>});
<span style="color:#66d9ef">let</span> <span style="color:#a6e22e">url</span> <span style="color:#f92672">=</span> window.<span style="color:#a6e22e">URL</span>.<span style="color:#a6e22e">createObjectURL</span>(<span style="color:#a6e22e">blob</span>);
<span style="color:#a6e22e">download</span>.<span style="color:#a6e22e">href</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">url</span>;
<span style="color:#a6e22e">download</span>.<span style="color:#a6e22e">download</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">'test.webm'</span>;
<span style="color:#a6e22e">download</span>.<span style="color:#a6e22e">style</span>.<span style="color:#a6e22e">display</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">'block'</span>;
};
<span style="color:#a6e22e">startBtn</span>.<span style="color:#a6e22e">disabled</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
<span style="color:#a6e22e">captureBtn</span>.<span style="color:#a6e22e">disabled</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
};
<span style="color:#a6e22e">startBtn</span>.<span style="color:#a6e22e">onclick</span> <span style="color:#f92672">=</span> () => {
<span style="color:#a6e22e">startBtn</span>.<span style="color:#a6e22e">disabled</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
<span style="color:#a6e22e">stopBtn</span>.<span style="color:#a6e22e">disabled</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
<span style="color:#a6e22e">rec</span>.<span style="color:#a6e22e">start</span>();
};
<span style="color:#a6e22e">stopBtn</span>.<span style="color:#a6e22e">onclick</span> <span style="color:#f92672">=</span> () => {
<span style="color:#a6e22e">captureBtn</span>.<span style="color:#a6e22e">disabled</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>;
<span style="color:#a6e22e">startBtn</span>.<span style="color:#a6e22e">disabled</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
<span style="color:#a6e22e">stopBtn</span>.<span style="color:#a6e22e">disabled</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
<span style="color:#a6e22e">rec</span>.<span style="color:#a6e22e">stop</span>();
<span style="color:#a6e22e">stream</span>.<span style="color:#a6e22e">getTracks</span>().<span style="color:#a6e22e">forEach</span>(<span style="color:#a6e22e">s</span>=><span style="color:#a6e22e">s</span>.<span style="color:#a6e22e">stop</span>())
<span style="color:#a6e22e">videoElement</span>.<span style="color:#a6e22e">srcObject</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span>
<span style="color:#a6e22e">stream</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span>;
};
};
window.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">'load'</span>, <span style="color:#a6e22e">init</span>);
</code></pre></div>
This content originally appeared on Modern Web Development with Chrome and was authored by Paul Kinlan