2009-02-15

YouTube動画をSLで - Yahoo Pipes 2

さて、前回のpipeをもうちょっと工夫してみましょう。

動画の品質を指定するには、
http://www.youtube.com/get_video?video_id={動画ID}&t={動画識別コード}&fmt={出力形式}
の、「fmt={出力形式}」の部分を変えるだけで実現できます。指定値は前々回に書いた通り、
  • fmt=18...MP4 H.264/AAC stereo
  • fmt=17...MP4 MPEG-4/AAC mono (モバイル)
  • fmt=22...MP4, H.264/AAC stereo (HD)

です。

ですから、「http://www.youtube.com/get_video?video_id={動画ID}&t={動画識別コード}」の部分までをPipeで作成・出力し、「&fmt={出力形式}」の部分をSL内でユーザに指定させて、LSLで
http://www.youtube.com/get_video?video_id={動画ID}&t={動画識別コード}&fmt={出力形式}
という処理形態にするのが自然かと思います。
特にhttp_responseイベントで取得できるデータ長さは2Kbyteという制限があるので、短いに越したことはありません。
(pipe側も複雑になると動かなくなることがあります)

そこを改良したpipeがこちら。

movie formatのInput Numberモジュールを削除し、最後のLoopモジュール内のString Builderモジュールから"fmt="、"text"の2項目を削除するだけです。

後は受け取ったLSL側のllParcelMediaCommandList()関数に指定するURLに"fmt=xx"を付加するようにします。

これでfmt=18とfmt=17の対応は終わりです。

前々回も書きましたが、どのYouTube動画でもこのfmt=18とfmt=17は有効です。
ただしYouTube動画で「高画質」が用意されていない場合、fmt=18がきちんと「MP4 H.264/AAC stereo」になるかどうかはチェックしてません。でも再生時にvideoとして認識されない、ということはありませんので安心してください。

- - - - - - - - - - - - - - - - - - - - - - - - - - -

ただし、fmt=22(HD)の場合は元動画がHDでないと有効になりません(SL内でMedia URLにセットしてもvideoとして認識されません)。その動画がHDかどうか、YouTube URLを指定する前に事前にどこかでチェックしないといけないのです。

この「HDかどうか」をYouTubeページを参照する前に確認する方法はないのでしょうか。

実はあります。
参考:「Youtube でHD動画に対応しているか確認する裏技見つけた

前回の「動画識別コード」を取得するために参照した部分、ここにその情報も含まれています。


この「fmt_map」の値の先頭が"22"であるならば、その動画はHD動画です。

ちなみに「高品質」がない動画の場合は

「高品質」がある場合(でHDがない場合)は

のようです。
(判定する必要はないですが)

"pipeで「HDかどうか」をLSLに返して、LSL側で出力形式を指定し再生用URLを組み立てる"
という処理形態にのっとってpipesとLSLを変更します。

そこで
という感じにしてみます。

pipe

右側のモジュールで「YouTube video URL (url)」とその下の「String Regex」についての説明はいままでと同じですので省きます。

右側3番目の「Item Builder」モジュールで、取得したYouTube IDを基に、itemを作成します。


左側のモジュールの一番上、「Fetch Page」もいままでと同様です。

左2番めの「Filter」モジュールで、取得してきたHTMLソースから"fmt_map=xxxx"と"t=xxx"の部分をitemとして取り出し(permit)ます。
上から3番目の「Filter」ですが、ごくたまに"dtst=xxxx"というitemが取得できることがあります。ほんとにたまーにで、毎回ではないようなので何かYouTube側で機能を盛り込み途中なのかもしれません。とりあえず今は必要ないので、運悪く取得できてしまった時のために"dtst=xxx"のitemは取り除き(block)ます。


次の「Rename」モジュール以降で、itemの体裁を整えます。
整えるために、新たにvideo.titleとvideo.descriptionという属性を、とりあえずitem.contentの値で追加します。
「Sub-element」モジュールで、video.titleとvideo.description属性のみを取り出します。取り出したのでそれぞれ、item.title、item.descriptionという属性になります。


次の「Regex」モジュール。item.titleとitem.descriptionには、"fmt_map=xxx"もしくは"t=xxx"が入っています。
item.titleの値が"fmt_map="で始まっていたら、item.titleには"fmt"を、"t="で始まっていたら"t"をセットします。
また、item.descriptionの値が"fmt_map="で始まっていたらその後ろの値を、"t="の場合もその後ろの相対をitem.descriptionにセットします。


右側下の「Union」モジュールで、先程作成したYouTube IDの入ったitemと、左モジュールで取得してきたfmtとtのitemを結合して出力します。

出力結果(CSV形式)はこうなります。


LSL側は…長いので別ページに用意しました。コピペし、適当なobjectに詰めてお使いください。

[2009-02-17追記]
HTTPリクエストからhttp_response待ちの間、正式に作成するならばタイマーを張って応答タイムアウトを取るのがベストかと思います。どこかでなんらかのエラーが発生した場合、このままだと永遠に(スクリプト・リセットをしない限り)処理が止まります。

ちなみに、http_responseのstatusについては「
Studying HTTP」の「HTTP Status Code」を参考にしています。

2009-02-11

YouTube動画をSLで - Yahoo Pipes

YouTubeをSLで再生するために必要なURL
http://www.youtube.com/get_video?video_id={動画ID}&t={動画識別コード}&fmt={出力形式}
は、どうやってつくるのでしょう。

ここではJvnさんの「【中級】youtube url変換Webサービス公開」で使われているPipeを自分用にコピー(Cloneを作成)してソースを覗きます。

(見やすいようにちょっと配置替えをしてあります)

それでは各モジュールの機能を説明していきましょう。

1.youtube url(url) ※一番上の真ん中

これはモジュール名が書き換わってしまっていますが、User Inputカテゴリの「URL Input」で、ユーザからURLを入力させるためのものです。といっても、キーボードからの入力ではなくて、URLのパラメータ(正しい言い方か、これ?w)としての入力です。
JvnさんのLSLを思い出してください。
strURL = "http://pipes.yahoo.com/pipes/pipe.run?_id=5a068edc3e7197ed30c21a4f90363fe2&_render=csv&format=18&url=" + strURL;
この最後の「url=xxxx」の部分に当たります。
Default欄には何も指定していないので、このPipeを実行する際には必ず指定すべきものです。

2.movie format (number) ※右はじ上

これも同様に名前が書き換わっていますが、User Inputカテゴリの「Number Input」で、ユーザから数値を入力させるためのものです。
JvnさんのLSLでいくと、「format=xx」の部分になります。

3.String Regex ※中央やや上

これはStringカテゴリにあるモジュールです。文字列を正規化表現を使って生成するものです。
(正規化表現についてはつっこまないでください! 超苦手です!)
何をやっているかというと、1で指定されたYouTubeURLの文字列からv=以降の動画IDを抜き出しています。
http://www.youtube.com/watch?v=ohvjtDevshU
こういうYouTube URLだと「ohvjtDevshU」の部分です。

4.Fetch Page ※左一番上

これはSouceカテゴリにあるモジュールです。指定されたURLのHTMLページ(ソース)を読み込みます。さらに「Cut content from...to」欄で、HTMLソース上の指定した部分だけをitemとして取り出します。
つまりHTMLソース上の「watch_fullscreen?」で始まり、次の「;」までです。

実はここにYouTubeをSLで再生させるためのt=パラメータ「動画識別コード(勝手に命名)」が書かれているのです。

[2009-02-12 追記]
実はもう一箇所あって、同じHTMLソース上の"var swfArgs = {"で始まり、次の"};"で終わる部分にもあります。(別の動画の識別コードなので上記とコードは異なっています)

ただし、こちらの場合だと、識別コードを取得したあと"t="と組み合わせるという手間が増えるので、上記のほうがいいかと思います。

5.Loop ※左上から2番目

Operatorカテゴリにあるモジュールです。item数分だけ指定した処理を行います。
この場合は1個しかitemがないので1回処理されるだけです。
処理の内容は、Loopモジュール中にある「String Regex」で、文字列を正規化表現を使って書き換えるものです。

item.content(4で切り取ってきた文字列が入っている)の中身から、「t=」で始まり次の「&」で終わる部分までを取り出し、item.loop:strregexに格納します。

6.Loop ※左一番下

5と同様、Loopモジュールです。5と同様、ここでも1個しかitemがないので1回処理されるだけです。
処理の内容は、「String Builder」モジュールを使って、文字列を生成し、新規のitemとして出力します。

生成用の文字列は「String」の下にある各欄を上から順につなげたものになります。
  1. 欠けて見えませんが、"http://www.youtube.com/get_video?video_id="
  2. これも、結合線が隠れてしまっていますが、3のモジュールで作成した動画ID
  3. "&"
  4. 5のモジュールで作成したitem.loop:strregexの中身。要するに"t=xxxxxxxxxxxxxxxxx"の部分
  5. "&fmt="
  6. 2のモジュールで指定された数字。出力形式

と、これで、http://www.youtube.com/get_video?video_id={動画ID}&t={動画識別コード}&fmt={出力形式}
RSS形式で生成され出力されます。

さて次はこのpipeの出力結果をLSLで利用します。
llHTTPRequest()関数でこのpipeを実行します。
pipeの実行は
http://pipes.yahoo.com/pipes/pipe.run?_id={pipeのID}
の後に、必要なパラメータを指定していきます。このpipeの場合は
&url={YouTube URL}&format={出力形式}
です。指定の順番は気にしなくて大丈夫です。

結果はhttp_responseイベントのbodyに返ってきます。

ここで、pipeを普通に実行するとRSS形式のデータが返ってくることに注意してください。
単純に
http://pipes.yahoo.com/pipes/pipe.run?_id={pipeのID}&url={YouTubeURL}&format={出力形式}
としてやると、
bodyはrssのタグやらなにやらが大量に含まれます。

しかもきちんとRSSの仕様に準拠していないと、値は返ってきません。

このpipeでは単純にURLの1行文字列が必要なので、CSV形式で結果を返すようにpipeを実行します。
CSV形式の出力には実行URLに
&_render=csv
を追加します。

※ただしCSV出力にはSnumaさんのブログにあるとおり、日本語文字列に問題が発生します。CSVデータには文字コード指定(mime)がないからだと思われます。

あとは、返ってきたbodyの内容からURL部分だけを抜き出して、HTML特殊文字表記(こういう名称だっけ?)になっている"&"を"&"に置き換え、llParcelMediaCommandList()関数でURL等をセットするだけです。

2009-02-10

YouTube動画をSLで - まずは単体再生

なんかあっちでもこっちでも出てて旬な話題っぽいのでYahoo Pipesで作ってみることにします。

作ることに興味がなくて、SLで使うことにだけ興味のある人は
Jvnさんの「【中級】youtube url変換Webサービス公開」をどうぞ!
LSLにコピペするときにちょっと注意です。

一番最初のスクリプトのstate set、イベントhttp_responseの最後のところ、
integer idx = llSubStringIndex(strURL, "&");
while( idx > -1)
{
strURL = llDeleteSubString(strURL, idx+1, idx+4);
idx = llSubStringIndex(strURL, "&");
}
ここですが、このままコピペすると永久ループしてしまい、処理が終わりません。たぶんホームページ上での表示の問題でこんな表示になってしまっているのだと思います。
以下のように直さないといけません。
integer idx = llSubStringIndex(strURL, "&");
while( idx > -1)
{
strURL = llDeleteSubString(strURL, idx+1, idx+4);
idx = llSubStringIndex(strURL, "&");
}

あるいは while でまわすのではなく、Snumaさんの「[LSL] 複数の文字列を一気に置き換えたい」を参考に、
list listTemp = llParseStringKeepNulls(strURL, ["&"], []);
strURL = llDumpList2String(listTemp, "&");
に書き換えてもOKです。

- - - - - - - - - - - - - - - - - - - -
では、ここからは作りたい人のための情報です。

要するに、YouTube動画をSLで再生するには下記URL
http://www.youtube.com/get_video?video_id={動画ID}&t={動画識別コード}&fmt={出力形式}
を作成して、このリンクを土地のMedia URLにセットするだけです。

t={}は最近付け加わったので、今後も変わらないかどうかは保証の限りではありません。
YouTubeがこのやり方を公式発表しているわけでもないようですし。

●動画ID
これはYouTubeの各動画ページのURI
http://www.youtube.com/watch?v=71MM68d8Viw
のv=以降の部分です。

●出力形式
フラッシュ形式だとか、モバイル用品質だとか、高品質だとかHDだとかです。
これは「YoutubeのHD動画正式対応で、改めて動画形式をまとめてみる」で表形式にまとめられています。
Jvnさんのものでは、標準が17(モバイル)、高品質が18、もっと上(HD?)はhttpではなく、rtsp(リアルタイム・ストリーミング)です。
ですが17のモバイルだとかなり品質が落ちてしまうので、SL内では
  • 標準...18(MP4 H.264/AAC stereo)
  • 低画質...17(MP4 MPEG-4/AAC mono)
  • HD...22(MP4, H.264/AAC stereo)
というのがいいかと思います。

fmt=18とfmt=22は試した感じでは、確かにfmt=22の方がきれいです。
ただし! 「SL内で再生する」という目的からするとビットレート2Mbps超は非常に辛く、ほぼ趣味の世界といったところではないでしょうかw

動画によっては「HDないよ!」とか「(YouTube上では)高品質で見るがないよ!」と思われるかもしれませんが、どの動画でもfmt=18とfmt=17は有効です。fmt=22だけはHDでアップロードされていないと使うことができません。

参考までにSL内で各フォーマットを試してみた結果を。
動画はLINZOOさんの作成された「GION LIVE FINAL」です。
fmt=17


fmt=18


fmt=22


●動画識別コード
名称は勝手に付けましたw これも動画個別にあります。詳細は後ほど。

2009-02-06

釣り

いつも行く釣り堀「Cheep Cheep Landing (http://slurl.com/secondlife/Livingtree/68/42/23)」。
昨晩は、しばらくして「やっぱ撮影しよう!」と思いついたり、その後(飛行船を直して何か一仕事終えた気分になったので撮影を終了した)戻ってrolling restartに巻き込まれたりしてあんまり釣りできなかったんだけど。
なぜか「 NR Camp Owner's Best Catch 2.0 owned by Robin Sojourner gave you 'fishy balloon hat ~'」というメッセージが来て、賞品がもらえました。
だいぶ前から、釣り堀sim単位のBest Catch (smallクラス、Mediumクラス、総合)褒章があったんですが、いつのまにかsimオーナーからのBest Catch褒章システムが追加されたみたいですね。


あ、私が利用している釣りはNeo-Realms Fishing Gameです。

やっぱり7Seas Fishing GameのOpenSeas対策なのかな。7SeasのQuest…じゃなくてなんだっけ、あ、Blue Print/Salvageだ、それとは違ってBest Catchを狙うだけ!
(もっとも、欲しいものかどうかにもよりますがw)

ちなみに貰えた賞品は名前(fishy balloon hat)の通り…

風船でできた魚帽子、です。

これは同じLivingtree sim内にある子供用品専門店「Kick the Can - Kid's Stuff (http://slurl.com/secondlife/Livingtree/145/131/24)」で販売されているものです。



あ、ちなみにここ、7Seasの釣りもできて、すでに7SeasのOpenSeas賞品もあるようです。


実は7Seasもベンダーごと(だって自分のベンダーからなら20%引きで買えるから)持ってますが、めったにやりません。なぜなら7Seasの場合、Castするのにファンクションキーを押すしかないから。

いつも私は釣りをしているように見えますが、実は釣りをしつつ、スクリプトを書いたり、動画のチェックをしていたり、Web閲覧してたり、単に釣りだけだったりしているのです。
Neo-Realmsの場合、ファンクションキーでも動作するのですが、釣りダイアログが出るのでマウス・クリックでCastができます。
これは結構スクリプトを書いたりしているときは重要で、一々Castする度にメイン画面をアクティブにしてファンクションキーを押すのは面倒なんです。変なとこでファンクション押すと思いもかけない動作するし。

釣りしてるときに釣りだけでずっと過ごす…って退屈で耐えられないんです…。時間もったいないし。
(ならなんで釣りなんかしてるんだ!)

Numbakulla (The Pot Healer Adventure)動画 - 閑話休題

悩んでもしかたがないのでまだ撮影してない部分を撮影してきました。
といっても今日はduzzyのDJがあったので、その後ちょっとだけですが。

で…

これはーーーーーーー!

なんか飛行船が建物に埋まってました!
rolling restartとかでバグったのだろうかw

この後、一度乗船してしばらくしたら元通りきちんと動いていたようです。
よかった。

2009-02-05

KoiNUP PlacesにOctobervilleを登録

タイトル通りです…w
Numbakullaは手詰まり状態なので今日は何もしてません。

SnumaさんがGIONかな?動画を登録してたのを見つけて「それならせっかくPlacesPixelTrixあるし私も登録しちゃおうー」って感じで数日前、YouTube動画をslurl付きで登録しました。PixelTrixで検索すると他の方のフォトやなんか(works)と同様に動画もスライドショーで見ることができます。

今見たら古い方には「nice video」とコメントがついてました。

これは……
「古い方のが面白い」という意味なんだろうか。それとも「新しい方は見てない」という意味なんだろうか…。と、マイナス思考してみる。

でもこれどうなんでしょうね。Octobervilleって10月しかやってないからさ、この動画を見てPixelTrixに行ったりして「Octobervilleどこ?!」ってならないのかな。一応「10月のイベントだよ」とは書いておいたけど。

実は2007年のOctobervilleをYouTubeに上げた際、「Octobervilleで(SL内)検索したけど、ないよ?どこなの?」と問い合わせ(YouTubeメッセージ)があったんですよね。「10月のイベントだから終わってるよ。来年もやると思うから、来年に期待しよう!」と返信したら、「忙しくてSLイン率低いんだよね。残念」とか。
そんなこともあって、2008年の10月直前にこの人宛に「今年もOctoberville始まるよー」とメッセージを送っといたんですが…あの人どうしたかなぁ。

他の動画はKoinUPには登録してません。場所に関係のある動画ないしね。「YouTube動画だからYouTube探せばいいじゃん」…と今の所は思ってます。slurl付きで登録しなきゃいいんだけど。

あ、もちろんNumbakullaは出来上がったらKoiNUpのPlaces行きにしますよ。
「出来上がったら」、ですけどw

2009-02-04

Numbakulla (The Pot Healer Adventure)動画 - イントロ

イントロ…なのかな、まぁいいか。

昨日の撮影分で編集してみました。サンプル6。

あーでもない、こーでもない。あれも撮りなおし、これも撮りなおし。あそこは何で埋めよう…なんてやっているうちに、すっかり疲れ切って曲を聴くのすら飽きてしまいましたw
この4,5日だけでも100回以上はこの曲聴いてるんだよ…。

やっぱり完成は半年後ぐらいかなw

とりあえずイントロから前半1/4くらいのところまでと最後は固まったかなぁ(撮影し直しはあるけど)。
そんなわけで今までのイントロ部分の変遷を(誰も見ねーよ?)。

●サンプル・その1
まだWindLightも導入されていない2007年11月頃の撮影。
夕日から日没までを撮影するために、Numbakullaシム内がその時間帯になるまで待機。その後日没まで15分にわたってカメラ固定で撮影。それを5分に収めるために「2倍速」再生で編集。これをメインに間に適当に他のシーンをはさむ…。てな感じで作成。
マウス操作のカメラコントロールではだいぶ無理があると痛感。その後WindLight機能ベータが始まり、Day Cycle EditorなるものでSL内で時間を早送りできる機能が導入されることを知り、以降作成停止。
WindLight正式導入以後も、3Dマウス対応なる機能がさらに導入予定と知り、作成停止継続。



●サンプル・その2
そろそろ作りたいよね…と思い立ち、まずはスクリーンショットでsim内各所を撮影。その他に思いつくまま動画も何カットか撮影。これを編集。
これが3、4日前。



●サンプル・その4 (その3は出力すらせず)
イントロのスクリーンショット切り替え部分、1枚1枚をもう少しじっくり見させるために枚数を減らす。ついでに、「滅びてしまった哀れさ(?)」を感じさせるシーンのみに減らす。その後フェードのタイミングを調整。
「でもタイトルロールどこに入れよう…文字かぶったら見えない…とりあえず余ったところに白画面でいれとけ!」なのがこれ。
これが一昨日。



●サンプル・その6 (その5も出力すらせず)
さらにイントロのシーン。ここは「Numbakullaの聖なる木」に焦点を絞り(ゲーム自体がそうだし)、さらに枚数を減らす。WindLightの「Environinment Editor」(日本語メニューだとなんだ?)でごちゃごちゃ変更しつつ静止画の撮りなおしと追加及び動画を撮影し、編集。
タイトルロールは「やっぱ木ときたら種だよね」で、種(ネタバレになってしまうので撮影は神経を使います…)。まだ文字がかぶると見えないけど。
これが今日。



こんな感じで一歩一歩進んでいます。
これを毎日10回や20回見直して、変更したり追加したりの構想を練るわけです。

※動画には音楽がはいってませんが、まだ許可を取ってないので抜きました。
(だって英文かかないとだし! 完成できるかどうかもわからないしw)
同様の理由でシナリオ上の曲名は灰色で塗りつぶしています。

2009-02-03

Numbakulla (The Pot Healer Adventure)動画 - 大気

動画を始めた時にいずれ作りたいと思っていた「Numbakulla (The pot healer adventure)(仮)」に、そろそろ取り掛かろうかと…。
(ここの訳もいい加減なおさないと…)
これはとてもお気に入りの場所なので、本当に大事に作りたいところです。

もう曲は決めてあって(許可はまだ)サンプルも済んでるんだけど、当時はWindLightもなくて(夕暮れから月の出まで5分くらいでまわしたかった)、3Dマウスもなくて(月をフォーカスしたかったがプリムではないのでカメラコントロールが無理だった)、懸案になってました。
その後環境が揃っても、イベント以外の動画作成に自信がもてず、ずっと「待ち」の状態でした。が、これも「Octoberville 2008」で経験したので、ついに再始動です。

音楽が決まっていて試験撮影も済んでいるとは言え、まだまだ全体をどうするかまったく決まりません。
なのでやっぱり「Octoberville 2008」と同様、まずは各地のスクリーンショット撮影。

これがおとつい。

撮影したスクリーンショットはFlickr(セットになってますが93枚と大量なのでスライドショーで見る場合には覚悟のほどを)とKoinUpに。
KoinUpって一度に25枚しかアップできなくて、さらにPlacesは15枚までしか見れないのね…。他の人の分が見えなくなっちゃいますね。後で撮影しなおしたりしてFlickrともども整理しなおそう。93枚のスライドショーも減らさないとw

このスクリーンショットと何本かの撮影動画で、色々入れ替えたりタイミングを変えたりでサンプルその3までを作成。
これが昨日。

今日はこのサンプル3で撮影し直したい部分と追加撮影をしてきました。
撮影し直しは主に光線の具合調整とか色具合調整とか、WindLight機能の部分。

いや、でもね…こんな機能がなかったらこんなことで悩まずに済むのに…と思わないでもない、すごい機能です。っていうか使いこなせない! 思っていた状態になかなかならんのですわね。
でも大事に作りたいから四苦八苦しながらも撮影してきましたよ…。

全体を動画として繋げたら、やっぱり違う設定のがよいかな、とか出るんだろうなぁ…。
ま、そんときはまた撮影しなおせばいいか。

で、今日の成果はこちら。左が普通の「Sunset」、右が色々いじった「夕焼け」。…ちょっと強すぎたかなw


普通の「Sunset」と、太陽の位置・光量を調整したもの。


いじってて思ったんですが、雲の量、難しいですね。
静止画ならLockかけて時間かけられるけど、動画だと常に動いているから好みの量になるまで待たなきゃならないし。待ってる間に人が画面に!とか…。

まだまだ撮影は難行しそうです。

半年後ぐらいには出来上がるといいなぁ…w