このページの本文へ

HTML5+JavaScriptでビデオエフェクターに挑戦! (6/6)

2010年05月12日 11時00分更新

文●古籏一浩

  • この記事をはてなブックマークに追加
本文印刷

動画をファイルに保存する

 ここまでで、ほぼリアルタイムで動画にエフェクトをかける処理を作り、プラグイン化によってエフェクト処理の分離もできました。

 しかし残念なのが、せっかく面白いエフェクトができても、エフェクトを適用した後の動画をファイルに保存できないことです。H264などのエンコード処理をこなすライブラリーがないことが理由ですが、ここでは暫定的な解決策として、1フレームずつPNG画像として保存する方法を試してみます。ただし、ファイルの保存処理はブラウザーに依存する部分があるので、ここで紹介する方法もすべてのブラウザーで確実に動作する保証はありません。

 今回作成したビデオエフェクターは、動画をCanvasに転送してエフェクトをかけているので、エフェクト処理の後にCanvasの内容を保存する処理を動画のフレーム数だけ繰り返せば、シーケンシャルな画像データになります。あとは保存されたPNGファイルを動画編集ソフトなどに読み込めば、ブラウザーで作成した動画を一般的な動画形式(QuickTimeやwmv、FLV)に変換できます。

 Canvasの画像データを保存するにはCanvasのtoDataURL()メソッドを使います。詳しくは以下の記事を参照してください。

HTML5のCanvasで作る、Flash不要のお絵かきツール
http://cms.uzmz.ascii.jp/elem/000/000/513/513377/


 動画の場合、複数の画像を連続して保存する必要があります。window.open()か、もしくはHTMLのインラインフレーム(iframe)を使う方法がありますが、window.open()はうまいくいかないことがあったので、今回はインラインフレームで保存します。

 動画の時間を変更してCanvasに転送/エフェクト処理したら、インラインフレームを使って保存すればできあがりです……と言いたいところですが、実際には最初のフレームしか保存されなかったり、順番に画像が保存されなかったりと、なかなか期待通りに動作しません。また、Firefoxのように動画データを途中で読みに行くブラウザーではうまくいきません。

 そこでやや強引ですが、タイマーのsetTimeout()を使って4秒間隔でフレームごとに画像を保存する処理を実行します。これで今回のエフェクト程度であれば、おおよそ問題なく保存できるはずです。

 実際のスクリプトはサンプル06です。サンプル06では1秒1フレームで保存していますが、より細かいフレームで保存したい場合は、以下の行の1/1を保存したいフレームレート(1/30など)に変更してください。


time = time + 1/1;  // フレームレート


6-1.png

ファイルに書き出しボタンをクリックするとPNG形式で保存できる

6-2.png

Safari 4の場合は連番ファイルとして保存される。ダウンロードウィンドウにある書類アイコンをダブルクリックすると……

6-3.png

保存されたPNG画像が表示される。Firefoxで保存した場合、拡張子などを変更しないとPNG画像として認識されない

サンプル06[HTML]


<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>キャンバス映像をファイルに出力</title>
        <link rel="stylesheet" href="css/main.css" type="text/css" media="all">
        <script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
        <script type="text/javascript" src="js/view.js"></script>
    </head>
    <body>
    <h1>キャンバス映像をファイルに出力</h1>
    <video id="myVideo" controls autobuffer>
        <source src="movie.mov" width="384" height="216">
        <source src="movie.ogv" width="384" height="216">
    </video>
    <canvas id="myCanvas" width="384" height="216"></canvas>
    <div id="control">
        エフェクトを適用した映像をフレームごと(連番)にファイルに出力します。<br>
        <br>
        <button onclick="saveData(0)">ファイルに書き出し</button>
    </div>
    <div id="mySave"></div>
</body>
</html>


サンプル06[JavaScritp:view.js]


var fx = [];    // 実行するプラグインのコード
var maxFx = 0;  // プラグインの最大数
var time = 0;
window.addEventListener("load", function(){
    // エフェクトプラグインデータを読み込む
    $.get('fxlist.js', function(text){
        var list = eval(text);  // プラグインリストを取得
        for(var i=0; i<list.length; i++){
            $.getScript(list[i]); // エフェクト処理のスクリプトを読み込む
        }
    });
    setInterval("effect()", 1000/30); // 30フレーム
}, true);
// エフェクト処理
function effect(){
    var video = document.getElementById("myVideo");
    var can = document.getElementById("myCanvas");
    var con = can.getContext("2d");
    con.drawImage(video, 0, 0);
    var pxdata = con.getImageData(0, 0, can.width, can.height);
    var p = pxdata.data;
    for(var i1969=0; i1969<maxFx; i1969++){
        eval(fx[i1969]);    // エフェクトを実行する
    }
    con.putImageData(pxdata, 0, 0);
}
// 保存処理
function saveData(time){
    var video = document.getElementById("myVideo");
    video.currentTime = time;
    effect();
    var can = document.getElementById("myCanvas");
    var d = can.toDataURL("image/png");
    d = d.replace("image/png", "image/octet-stream");
    document.getElementById("mySave").innerHTML = '<iframe width="2" height="2" src="'+d+'"></iframe>';
    time = time + 1/1;  // フレームレート
    if (time <= document.getElementById("myVideo").duration){
        setTimeout("saveData("+time+")", 4000);
    }
}


 今回の記事は、ブラウザー+HTML5+JavaScriptでAdobe After Effectsのようなアプリケーションが作れないかの試行錯誤が元になっています。かなり強引な手法で保存機能まで作っていますが、もっとよい保存方法があるかもしれません。また、プラグインの機構部分(仕組み)をもっとよいものに設計しなおせば、本当にブラウザー+HTML5+JavaScriptでAfter Effectsが実現できるかもしれません。

 JavaScriptを使ったエフェクトプラグインがたくさん登場すれば、ブラウザー上での映像表現はもっと面白くなるでしょう。

 それでは、また次回。

前へ 1 2 3 4 5 6 次へ

この連載の記事

一覧へ

この記事の編集者は以下の記事をオススメしています