2013/01/25(Fri)C#からDirectShowを使って動画のビットマップのポインタを得てDirect3Dでムービーテクスチャにもできる動画再生ライブラリを作ったのでNYSLで公開しました。

はてブ数 2013/01/25 23:36 プログラミング::C# つーさ

本日(じゃないけど)のアウトプット。
動画プレーヤーつくりました。

今更DirectShowのSampleGrabberを使えるようになってみたり。
再生するというよりは、ビットマップのポインタを得てぐりぐり加工する向けですな。

    /// 
    /// DirectShowのSampleGrabberGraph を使ってメディアファイルを再生するサンプル。
    /// SampleGrabberを使うメリットは、ビデオもオーディオもデコード後のデータのポインタが得られることで、
    /// Marshal.Copyなどでbyte[]にコピーするなり、unsafeコンテキストを使うなりで手軽に加工することができる。
    /// ゲームアプリなどではDynamicTextureに転送することで簡単にムービーテクスチャを作ることもできる。
    /// VMR9を使った方がパフォーマンスが出るが、Device LostがOSのバージョンごとに挙動が違ったりで対応しきれない。
    /// カスタムレンダラを作るのが最良の方法なのだろうけれど、C#のみでカスタムレンダラを作るのは至難の業。
    /// Enter:開く, Space:再生/一時停止, Escape:停止 ←/→:5秒シーク
    /// 

例によってソースをNYSLで公開してます。
https://github.com/ttsuki/ttsuki-csmix/tree/master/WindowsUtil/DirectShow/

例によって、このコードをあなたのプログラムにコピペすると、
特にアセンブリを追加することなくEXE単体で動画再生ができます。
DirectShow.net とか使ってない。

C#の動画再生あれこれと言えば……。

たとえば、Managed DirectXには AudioVideoPlayback というクラスがあって、
実はManaged Direct3Dのテクスチャに転送する機能もついていることにはいるんですが、
強制的に、画面のFPSが動画のFPSに合わせられてしまったりするので、
(ただ再生するならそれでいいですが、ゲーム中のテクスチャとして使うには)非常に扱いが難しいです。

VMR9を使うと動画のフレームを描画したテクスチャを直接受け取ることができなくもないんですが、
これまた動画のレンダリング中(テクスチャを投入してから、次のフレーム時刻になって、テクスチャ描画されて戻ってくるまで)は、
描画スレッド側でDirect3DのAPIが呼べないため、60FPSを維持しながら動画再生するのはなかなか至難の業っぽく。
動画に1FPSの区間があったりすると、ゲームアプリ側も巻き込まれて1FPSになるんですよね、はい。

また、VMR9はDevice Lostしたとき、Pinを切ってDirect3DをResetしてPinをつなぐとWinXPでは動いていたんですが、
Win8にしたらそのコードではCOMExceptionが出るようなので、結局Graphをいったん破棄してとか。
当時はDirectShowに対する知識も浅かったので(未だに浅いですが)使い方間違ってたかもなぁ……。

という感じで一周してきて、結局頼れるのはSampleGrabberですね!

Media Foundation API とか使うとmp4とかも開けるようになるみたいで、そっちも使えてみたいなぁ。
APIのネーミングとかをさらっと見た感じでは、
DirectShowで言うグラフのようにトポロジを構成してデータを流すっぽいんですが。

2012/11/03(Sat)C#から手軽にUPnPでルータに穴開けるクラスライブラリ作ったった

はてブ数 2012/11/03 1:05 プログラミング::C# つーさ

https://github.com/ttsuki/ttsuki/blob/master/Net/UPnPWanService.cs

Windows標準のupnp.dllを使う方法で。

COM使うけど、TypeLib参照せず、自前でCOM定義してるので、InteropなDLL不要。
この UPnPWanService.cs ファイル1つコンパイルすれば、UPnPがしゃべれるんだぜ!

ゲームの通信対戦とか、P2Pアプリケーションとか作れるね!
これ使って、UDPポート穴開けてKademliaかなんかDHTとP2Pルーティング実装して、
でかいblobの転送に関しても、UPnP使ってFTPのパッシブモードみたいに穴開けたら
オレオレBitTorrentのようなものができそう。
そのネットワーク使って色々楽しいことできるんじゃないかとか妄想してる。

ソフト作っても使ってくれる人がいないと意味ないから、
ちゃんと需要あるソフト作って、ちゃんと宣伝しないとねー。

2012/09/22(Sat)GitHub はじめました。

はてブ数 2012/09/22 23:53 プログラミング::C# つーさ

たこねこかわゆし。登録したのは8ヶ月前ですが。
https://github.com/ttsuki/ttsuki
C#でWindowsのP/Invokeなライブラリ集になりそうです。
今できることはリンク先のREADME.mdをみてください。

これからはブログ記事に貼り付けるソースコードなんかもこっちにアップしてけばいいよね。
ということで、手始めに、数年前に作ったwinmm.dllをラップするクラス群をPushしてみる。今更!

2012/08/27(Mon)Wake On Lan In C#

はてブ数 2012/08/27 23:59 プログラミング::C# つーさ

ある日のTwitterにて。

気まぐれにdevenvしておよそ10分後にできたものがこれだっ

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace WoL
{
  class Program
  {
    static void Main(string[] args)
    {
      // args[0] = "DE-AD-BE-EF-11-FE"
      new Action<string>(a=>new UdpClient(0).Send(Array.ConvertAll(("FF-FF-FF-FF-FF-FF-"+string.Join("-",new string[]{a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a})).Split('-'), s=>byte.Parse(s, NumberStyles.AllowHexSpecifier)),102,new IPEndPoint(0xFFFFFFFF, 9)))(args[0]);
    }
  }
}

設定など要らんっ

自分のマシンに対して使って動くことは確認した。
ほんとは140文字以内にしてツイートしたかった。

追記

解説した。

それを踏まえて上のコードを分解。

続きを読む

2012/08/26(Sun)JavaScriptの無名function内にバインドされる変数のスコープがC#と違う

はてブ数 2012/08/26 17:38 プログラミング::JavaScript つーさ

ボタンをスクリプトでたくさん作って、それぞれの clickイベントの function を作るときに、
そのfunctionの外側で宣言された変数がどうbindしたらいいのか。

<div id="test"></div>

<script>
for (var i = 0; i < 10; i++) {
  var input = document.createElement('input');
  var j = i;
  input.type = 'button';
  input.value = input.id = 'button_' + i;
  input.addEventListener('click', function() { alert(j); });
  document.getElementById('test').appendChild(input);
}
</script>

やりたいことはわかってもらえると思う?
でも、どのボタンを押しても表示されるのは9。これじゃあだめ。

というか、一瞬自分の書いたスクリプトに馬鹿にされてる気がしてきた。9的な意味で。

どーやるんだろう。

続きを読む

2012/08/22(Wed)C言語でJSONパーサーをかく?

はてブ数 2012/08/23 1:13 プログラミング::チラ裏 つーさ

ついったで、C言語によるJSONパーサーの話題をチラ見した。

  • C++だとpicojsonが便利いけど、C言語でJSON扱えるライブラリってそんなにないのか? 動的なメモリアロケーションがどうとか言うが、事前にchar[65536]確保して渡してそん中でごにょごにょするデザインにすりゃええんでろ? とか思って島 (20分前)
  • JSONパーサーは、パーサー書く練習のいい題材かもしれんのう。実際C#で書いた自前JSONパーサーが、もっとも多用してるライブラリやも。 (16分前)
  • struct json E_TYPE TYPE; size_t LENGTH; union { float NUMBER; char STRING[1]; ... } みたいなサイズ不定の構造体をchar[]の中に詰め込みながら先頭アドレスをメモってくのが好き。 (9分前)

静的に型付けされてる言語でJSONをどう扱うかっていうのが結構難しいよね。

とりあえずぱっと思いつくのはこういうモデル?

/* json parser */

#include <stdio.h>

typedef enum {
  E_JSON_TYPE_NULL,
  E_JSON_TYPE_BOOLEAN,
  E_JSON_TYPE_NUMBER,
  E_JSON_TYPE_STRING,
  E_JSON_TYPE_ARRAY,
  E_JSON_TYPE_OBJECT,
} e_json_type_t;

typedef struct t_json {
  e_json_type_t type;
  size_t length;
  union {
    char as_boolean;
    long long as_number;
    wchar_t as_string[1];
    size_t as_array;
    size_t as_object;
  };
} json_t;

inline int as_int(const json_t *o)
{
  assert(o->type == E_JSON_TYPE_NUMBER);
  return (int)o->as_number;
}

as_arrayとかas_objectのときは、そこに書いてあるsize_t分、後続のjson_tが格納されてると見なす、みたいな?

配列やオブジェクトのパースの時には事前に長さがわからないので、ランダムアクセスさせるデータ構造は作れないような気がする。
でも、上に書いたような線形リストっぽい実装しちゃうと、後からのトラバースでいちいち中見ないといけなくて面倒だよね。
obj[3][2] は、 obj->child->next->next->next->child->next->next って展開されるからアクセスも遅そうだし。

んー。メモリプールを二つに分けて、数値と文字列と真偽値みたいな葉をひたすらため込むプールとそこへのポインタをため込むプールにわける?
ポインタをため込むプールの方は1要素のサイズが固定できて添え字によるランダムアクセスしやすくなる。

案外奥が深いよね。

CでまともにTwitter Clientとか作ろうと思ったらめんどそう。

2012/08/04(Sat)漢字の読みを得るには C#版 - Marshalで遊ぼう

はてブ数 2012/08/04 4:58 プログラミング::C# つーさ

やってることは、かつてHSP3向けに作ったスクリと一緒。
C#ならどれだけ楽かと思って、COM Interopしてみたくなった。
やってみたら実はTypeLibがなくて全然楽じゃなかった。

"冬過ぎて春来るらし朝日さす春日の山に霞たなびく" から、
"ふゆすぎてはるらいるらしあさひさすかすがのやまにかすみたなびく" が得られる。
お、Win8では「かすがのやまに」になってる。が、「はるらいるらし」になってる。
うーん、相変わらずビミョーね。

続きを読む