卒業論文 2004 年度(平成 16 年度) JPEG2000 を用いた最適動画像配信システムの設計と実装 慶應義塾大学 氏名 環境情報学部 石神 靖弘 指導教員 慶應義塾大学 環境情報学部 村井純 徳田英幸 中村修 楠本博之 南政樹 Abstract(Japanese) 2 Abstract(English) 3 目次 第1章 序論:動画像配信と使用帯域の制御 1.1 背景:ネットワークの広帯域化と動画像配信の一般化 1.2 問題意識:フレーム内圧縮と DV 1.3 研究の目的:より柔軟な輻輳制御を行うシステムの構築 1.3 論文の構成 第 2 章 本研究における要素技術 2.1 IP ネットワーク上における映像・音声転送 2.1.1 ストリーミング 2.1.2 RTP 2.1.3 RTCP 2.2 JPEG2000 2.3 DirectX 第3章 既存技術:DVTS 3.1 DVTS の概要 3.2 フォーマットの特徴 3.3 パケットフォーマット 3.4 DVTS の帯域削減手法 3.4 DVTS の問題点 第 4 章 より柔軟な帯域制御手法の提案 4.1 圧縮率変更による使用帯域の削減 4.2 フレーム間引きとの併用 第 5 章 設計 5.1 設計要件 5.2 設計概要 5.3 IMediaSample インターフェイス 5.4 送信部 5.4.1 送信部設計概要 5.4.2 Network Send フィルタの設計 5.4.2.1 基底クラス 4 5.4.2.2 IP ネットワークへの送信 5.5 受信部 5.5.1 受信部設計概要 5.5.2 Network Recv フィルタの設計 5.5.2.1 基底クラス 5.5.2.2 IP ネットワークからのデータ受信 5.6 制御部 第 6 章 実装 6.1 実装環境 6.2 フィルタ間のデータの受け渡し 6.3 送信部分フィルタ 6.3.1 CNetworkSend クラス 6.3.2 UDP Socket の作成 6.3.3 マーカ・マーカセグメントの解析 6.3.4 IP パケット送信 6.4 受信部分 Filter 第 7 章 評価 7.1 評価概要 7.2 本システムの実現した機能 7.3 送出データ量の計測 7.4 より柔軟な輻輳制御の実現 7.4.1 実験: 帯域幅の不足 7.4.2 実験: 遅延時間 7.5 まとめ 第 8 章 結論 8.1 まとめ 8.2 今後の課題 8.3 展望と応用 5 第1章 1.1 序論:動画像配信と使用帯域の制御 背景:ネットワークの広帯域化と動画像配信の一般化 ネ ッ ト ワ ー ク は 広 帯 域 化 し た 。 バ ッ ク ボ ー ン ネ ッ ト ワ ー ク に お い て は Gigabit Ethernet(IEEE802.11ab)や 10Gigabit Ethernet(IEEE802.11ae)が用いられるようなった。 また、家庭においては ADSL(Asymmetric Digital Subscriber Line)や FTTH(Fiber To The Home)が普及し、一般のユーザも高速な通信環境を享受できるようになった。 それに伴い、インターネットを介した動画像配信が一般的なものとなりつつある。例え ば、映画などのコンテンツの商用配信や教育目的での映像の配信が行われるようになった。 また、個人でも手軽に動画像配信が行えるようになり、MSN Messenger では、USB 接続 のカメラを接続するだけで、動画像によるコミュニケーションを楽しむことができる。 1.2 問題意識:フレーム内圧縮と DV 動画像の符号化方式には、フレーム間圧縮とフレーム内圧縮とがある。前者はフレーム とフレームの差分をとり、その差分を圧縮することによって、画像のデータ量を削減する。 しかし、フレーム間の差分を圧縮するため、パケットロスなどのエラーに極めて弱いとい う本質的な欠点がある。後者はフレームを逐一静止画のように圧縮する。フレーム間圧縮 に比べて、画像のサイズが大きくなってしまうが、エラーに強いという利点がある。 フレーム内圧縮の代表的な映像フォーマットとして、DV フォーマットがある。しかし、 DV フォーマットでは圧縮率の変更ができない。したがって、使用帯域の削減や輻輳制御を 行うためには、フレームを間引く必要がある。だが、フレームを間引くと、動きがかくか くとした不自然な映像になってしまうという問題点がある。 1.2 研究の目的:より柔軟な輻輳制御を行うシステムの構築 本研究では、フレーム内圧縮のフォーマットである JPEG2000 を用いる。すでに JPEG2000 フォーマットでの配信は行われているが、専用の機器を必要とし、いずれも高 価である。また、JPEG2000 の本来の規格に正確に準拠していないことが多い。 本研究の目的は、JPEG2000 フォーマットを用いた、安価かつ手軽で、より柔軟な輻輳 制御を意識した動画像配信を行うシステムを構築することである。したがって、フレーム 間引きと複数の圧縮率の変更に対応することが不可欠である。 1.3 論文の構成 本論文は 8 章から構成されている。第 2 章では、本研究の要素技術である IP ネットワー ク、JPEG2000 符号化、DirectX について概説する。第 3 章では、本研究の関連研究を取 6 り上げ、既存技術である DVTS との比較を行い、既存技術の問題点を明確化する。第 4 章 では、より柔軟な輻輳制御手法についての提案を述べる。第 5 章では本研究において実装 したアプリケーションの設計を説明する。第 6 章では、本研究の実装について述べる。第 7 章では、評価を行い、既存技術の問題点を克服することができたか否かを判断する。第 8 章では、本研究を総括し、今後の展望について述べる。 7 第2章 本研究における要素技術 本研究を構成する技術として、本章では IP ネットワーク上における音声・映像転送、 JPEG2000、DirectX についての概要を述べる。 2.1 IP ネットワーク上における音声・映像転送 2.1.1 ストリーミング IP ネットワーク上における音声・映像転送の方法として、ダウンロード方式とストリー ミング方式がある。ダウンロード方式は、映像・音声データをいったん全て受信し、ハー ドディスクに保存してから再生する方式である。一方、ストリーミング方式は映像・音声デ ータを受信しながら、再生を行う方式である。一般に、すでに蓄積されたコンテンツの配 信ではダウンとロード方式が、リアルタイムコンテンツの配信ではストリーミング方式が 採用される。 2.1.2 RTP ストリーミング方式での転送においては、伝送プロトコルとして主に UDP (User Datagram Protocol)が用いられる。UDP は TCP(Transmission Control Protocol)のよ うに、輻輳制御機能やフロー制御機能を有しない。また、パケットの到着順序にも関知せ ず、パケットの再送も行わない。従って、ネットワーク上でのパケットロスや輻輳に対し ては、アプリケーション側で対応する必要がある。 RTP(Real-Time Transport Protocol)は、UDP を用いたリアルタイムコンテンツの配信時 に通常用いられるプロトコルである。個々のパケットにシーケンス番号やタイムスタンプ を付加することにより、パケットの到達順序の検査やパケットロスの検知といったパケッ トの識別に利用される。なお、RTP そのものはパケットの到達順序を保障するプロトコル ではなく、あくまでパケットの識別を補助するものである。 2.1.3 RTCP RTCP(Real-Time Transport Control Protocol)は RTP セッションを管理するためのプロ トコルである。RTP により受信側が得たパケットの到達順序やパケットロスの有無、受信 品質、参加者の識別などといった情報をセッションの参加者間で交換する。これらの情報 をもとに、送信側は映像の圧縮率やフレームレートの制御を行い、送信するデータ量の増 減を調整する。 なお、RTCP は、RTP と同様に、データの配送やパケットの到達を保障するのではなく、 RTP によって得た情報を通知するプロトコルである。 8 2.2 JPEG2000 -概要 JPEG2000(Joint Photographic Experts Group 2000)は、JPEG(Joint Photographic Experts Group)の 30%の圧縮率向上を目標として仕様が策定されたフォーマットである。 JPEG にはない JPEG2000 の特徴として、以下の点が挙げられる。 階層符号化 高い圧縮効率 ブロックノイズやモスキートノイズが発生しない 高いエラー耐性 ROI(Region Of Interest) プログレッシブ表示に対応 また、JPEG2000 は周波数変換に離散 Cosine 変換(DCT: Discrete Cosine Transform)で はなく、離散 Wavelet 変換(DWT: Discrete Wavelet Transform)を用いている。エントロピ ー 符 号 も Huffman 符 号 で は な く 、 係 数 ビ ッ ト モ デ リ ン グ と 算 術 符 号 を 合 わ せ た EBCOT(Embedded Block Coding with Optimized Truncation)を用いている。 -JPEG 画像との比較 下の図は上から非圧縮の画像、JPEG 画像、JPEG2000 画像である。JPEG 画像と JPEG2000 画像はほぼ同じデータ量に合わせてある。JPEG 画像と JPEG2000 画像とを比 較すると、JPEG 画像のほうはブロックノイズが目立ち、画質が大きく劣化している。これ に対して、JPEG2000 画像は現画像のシャープさが失われているものの、原形を留めてい る。 9 図 Mandrill(Bitmap: 196,662 Byte,256×256) 図 Mandrill(JPEG: 2,082 Byte,256×256) 図 Mandrill(JPEG2000: 1,964 Byte,256×256) 10 -エンコードとデコードのプロセス 以下にエンコードとデコードの大まかな流れを示す。なお、JPEG2000 はデコーダの規 格であるため、エンコードのプロセスに関しては一例となる。 図 エンコードの流れ ・DC レベルシフト 入力された信号が符号なし整数であった場合に、符号付き整数に変換する。具体的に は、信号値からダイナミックレンジの半分を減算する。 ・Wavelet 変換 信号値に対して、Wavelet 変換を実行する。 ・量子化 Implicit と Explicit という2つの量子化方式からどちらか選択し、量子化を行う。こ こでの量子化は任意である。 ・EBCOT(Embedded Block Coding with Optimized Truncation) ビットモデリングした係数を算術符号化する。 ・ビット切捨て 与えられたビットレート以上のデータを切り捨てる 11 図 デコードの流れ ・Packet 解析 Packet のデータ部分を抽出する。 ・逆 EBCOT 算術符号化されたデータを復号化し、係数ビットデモデリングを行う。 ・逆量子化 量子化の逆の操作を行う。量子化に落とされた精度を元の精度へと戻す。 ・Wavelet 逆変換 復号化された係数に対して、Wavelet 逆変換を実行し、画像信号値を得る。 ・DC レベル逆シフト 出力される信号値を符号なし整数に変換する。具体的には、信号値にダイナミックレ ンジの半分を加算する。 ― コードストリームの構造 JPEG2000 のコードストリームは、Packet として符号化されたデータが格納されたタイ ルパートとヘッダから構成される。ヘッダにはメインヘッダとタイルパートヘッダがある。 ヘッダはマーカとマーカセグメントから成っている。 マーカは2Byte 長の値であり、コードストリーム内のデータのデリミタやコードストリ ームの特徴を示すものである。マーカセグメントは、1つのマーカとそれに付随するマー カセグメントパラメータをひとくくりにしたものである。下の表に、マーカとマーカセグ メントのリストを示す。 12 表 マーカセグメントのリスト Name Code Main header Tile-part header Start of codestream SOC 0xFF4F required not allowed Start of tile-part SOT 0xFF90 not allowed required Start of data SOD 0xFF93 not allowed last marker End of codestream EOC 0xFFD9 not allowed not allowed SIZ 0xFF51 required not allowed Coding style default COD 0xFF52 required optional Coding style component COC 0xFF53 optional optional Region of interest RGN 0xFF5E optional optional Quantization default QCD 0xFF5C required optional Quantization component QCC 0xFF5D optional optional Progression order default POD 0xFF5F optional optional Tile-part lengths, main header TLM 0xFF55 optional not allowed Packet length, main header PLM 0xFF57 optional not allowed Packet length, tile-part header PLT 0xFF58 not allowed optional Packed packet headers, main header PPM 0xFF60 optional not allowed Packed packet headers, tile-part header PPT 0xFF61 not allowed optional Start of packet SOP 0xFF91 not allowed End of packet header EPH 0xFF92 not allowed CME 0xFF64 optional Delimiting marker segments Fixed information marker segments Image and time size Functional marker segments Pointer marker segments In bit stream marker segments optional, in bit stream optional, in bit stream Informational marker segments Comment and extension 13 optional マーカとマーカセグメントには以下の 6 タイプが存在する。 Delimiting Fixed Information Functional Pointer In bit stream Informational このうち、Delimiting と Fixed Information マーカ/マーカセグメントについては、出現位 置と順番が厳密に決められている。以下にコードストリームの構造を示す。 14 図 コードストリームの構造 15 DirestShow 2.3 DirectShow は、Windows アプリケーションで高品位な映像・音声の再生やキャプチ ャといったマルチメディアストリームを扱う API 群である。以下に、DirectShow を構成す る基本要素について説明する。 ― フィルタ DirectShow のフィルタとは、マルチメディアストリームの処理を個々のステップに分割 した、線形フィルタである。アプリケーションが、グラフ上で、エンコーダやデコーダ、 レンダラといったフィルタを組み合わせることで、多様な処理を行うことができる。 ― ピン フィルタは、少なくとも1つのピンをもつ。DirectShow フィルタのピンは、フィルタ間 でメディアデータの受け渡しを行う部分である。ピンには方向があり、入力と出力の2つ がある。フィルタ同士を接続する際には、入力ピンと出力ピンの間にコネクションを張り、 ピンがサポートしているメディアタイプを互いに照合する。 ― フィルタの分類 フィルタには、以下の3つがある。 ソースフィルタ トランスフォームフィルタ レンダリングフィルタ ソースフィルタは未処理のメディアデータを出力するフィルタである。ソースフィルタ には、DV カメラなどの映像ソースや AVI ファイルなどのファイルソースがある。トランス フォームフィルタは、入力ピンから受け取ったメディアデータを、圧縮伸張などの変換処 理を行ってから、出力ピンへ渡すフィルタである。トランスフォームフィルタには、エン コード/デコードフィルタや、映像や音声をスプリットするフィルタなどがある。レンダリ ングフィルタは、出力デバイスへ完全に処理したメディアデータを書き込むフィルタであ る。レンダリングフィルタには、映像データを画面上にレンダリングするフィルタや音声 データを再生するフィルタなどがある。 ― フィルタグラフ フィルタグラフはピンによって相互に接続されたフィルタの集合である。フィルタグラ フを組み立てる手段として、アプリケーションが手動でフィルタ間のピンとピンとをつな ぐ方法や、グラフビルダなどによって自動的にフィルタグラフを構築する方法がある。 16 図 フィルタグラフ 17 第3章 既存技術:DVTS 本章では、既存技術である DVTS(Digital Video Transport System)について、概要を述 べ、考察する。 3.1 DVTS の概要 DVTS は、IEEE1394 を通じて民生用 DV カメラから取得した、DV 圧縮された映像デー タと非圧縮の音声に対して、IP データグラム化を行い、転送するシステムである。 DVTS の主な機能としては、以下の点が挙げられる。 IPV4/IPV6 に対応 RTP による通信 Multicast による複数地点への転送 フレーム間引きによる帯域制御 3.2 DV フォーマットの特徴 DVTS では、映像フォーマットとして、DV フォーマットを採用している。 DV フォーマットの特徴を表に示す。 表 DV フォーマットの特徴 圧縮方式 フレーム内圧縮 解像度 720×480 フレームレート 29.97 fps 使用帯域 約 30Mbps 圧縮率 一定 DV フォーマットは基本的に JPEG の技術を踏襲している。JPEG 同様、周波数変換には DCT(Discreet Cosine Transform)を、エントロピー符号化には、Huffman 符号を用いて いる。 18 3.3 パケットフォーマット DVTS で使われている DV/RTP パケットフォーマットを図に示す。 図 DV/RTP パケットフォーマット DV フォーマットでは、映像や音声といったデータは 80Byte 長の DIF Block というブロ ックで区切られている。したがって、DV のデータ量は 80Byte 単位で変化する。DV/RTP パケットは DIF Block を複数持つことができ、その数は任意に選択できる。 3.4 DVTS の帯域削減手法 DVTS では、フレームを間引く、すなわち IP データグラム化する映像フレーム数を減ら すことで、使用帯域の調整を実現している。 図 DVTS のフレーム間引き フレーム内圧縮である DV データは、フレーム全てが、MPEG の I Picture に相当するキ ーフレームであるため、フレームを間引いても、映像の再生に何等支障はない。 19 下の図はフレーム間引き率と使用帯域の関係を示したものである。 図 フレーム間引き率と使用帯域 フレーム間引きを行っていないときは 30Mbps 強の帯域を占有しているが、フレームを間 引くごとに使用帯域が減少している。なお、音声の間引きは行っていないため、音声パケ ットが占有する帯域は常に一定である。 3.4 DVTS の問題点 前述したように、DVTS は、フレーム間引きを実施することで、使用帯域の削減を行う。 しかしながら、フレームを間引くと、物体の動きがかくかくとした不自然な映像になって しまう。また、DV フォーマットの圧縮率は一定であるため、常に約 30Mbps の帯域を占有 する。それゆえ、映像品質を落とすことなく、使用帯域の調整を行うことでは不可能であ る。 20 第 4 章 より柔軟な帯域制御手法の提案 4.1 圧縮率変更による使用帯域の削減 4.2 フレーム間引きとの併用 21 第 5章 設計 本章では、設計について述べる。 5.1 設計要件 本研究における設計要件として、以下の事項がある。 RTP による通信 DirectShow フィルタ化 フレーム間引きに対応 複数の圧縮率に対応 DV データのデコード JPEG2000 データのエンコード/デコード 5.2 設計概要 本システムは送信部と受信部から構成され、ともに DirectShow のフィルタとなっている。 DV カメラと計算機間の通信には IEEE1394 を用いて DV データを取得する。計算機間の JPEG2000 データの受け渡しには、IP を利用し、データの送受信を行う。フィルタ間のデ ータの受け渡しは、IMediaSample インターフェイスのインスタンスを用いる。 5.3 IMediaSample インターフェイス フィルタ間のデータの受け渡しは、IMediaSample インターフェイスのインスタンスを 通じて行う。IMediaSample インターフェイスは COM オブジェクトであり、フィルタ間の 共有メモリバッファとして使われる。したがって、データのサイズ、データが入ったバッ フ ァ へ のポ イ ン タな ど は全 て カプ セ ル化 さ れ 、外 部 から 隠 蔽さ れ てい る 。 次に 、 IMediaSample インターフェイスの定義を示す。 22 23 5.4 送信部 5.4.1 送信部設計概要 送信部は以下の機能要素から構成される。 IEEE1394 を通じて、DV カメラから DV データの取得 DV データのデコード JPEG2000 データにエンコード IP ネットワークに対してデータを送信 圧縮率やフレームレートの変更に対応 上記の機能要素を、DirectShow フィルタとして構成した場合、送信側のフィルタは以下の 4つになる。 ― Microsoft DV Camera and VCR Microsoft DV Camera and VCR フィルタは、DV カメラを表わす Plug and Play Device フィルタである。DV Vid Out ピンから、DV データを送出する。このフィルタは DirectShow 付属のフィルタである。 ― DV Video Decoder DV Video Decoder フィルタは DV データをデコードする Transform フィルタである。 入力ピンから受信した DV データをデコードし、非圧縮の映像データを出力ピンへ送出 する。このフィルタは DirectShow 付属のフィルタである。 ― LEAD MJ2K Encoder LEAD MJ2K Encoder フィルタは、非圧縮の映像データを JPEG2000 データへとエン コードするフィルタである。このフィルタは Lead Technologies 社が販売しているもので ある。 ― Network Send Network Send は JPEG2000 データを分割し、RTP ヘッダを付加して、UDP パケッ トとして送出するフィルタである。本研究で設計実装する。 24 図 送信側フィルタグラフ 5.4.2 Network Send フィルタの設計 5.4.2.1 基底クラス Network Send フィルタは、基底クラスとして、CBaseRenderer クラスを継承する。 CBaseRenderer クラスはレンダリングフィルタを作成する際に用いられる基底クラスであ る。 5.4.2.2 IP ネットワークへの送信 IMediaSample インターフェイスのオブジェクトによって渡されたデータを IP ネットワ ークへ送信する。そのとき、次の 2 点を考慮に入れ、データを分割する。 ― JPEG2000 コードストリームの構造 第 2 章で述べたとおり、JPEG2000 コードストリームはヘッダとタイルパートから構成 される。送信用バッファにデータを格納する時には、このコードストリームの特徴を勘案 する。したがって、ヘッダ部分とデータが入ったタイルパート部分を別パケットで送信す る。 ― RTP ヘッダ RTP ヘッダをバッファの先頭に付加し、IP ネットワーク上へパケットを送出する。図に RTP ヘッダフォーマットを示す。 25 図 RTP ヘッダ シーケンス番号(Sequence Number)は IP パケットごとに1ずつインクリメントする。タ イムスタンプ(Timestamp)は 90KHz を単位とする。今回は DV カメラから画像を取得して いるため、3003 ずつ増加させる。 次に、ペイロードフォーマットを示す。このペイロードフォーマットは、現在 internet draft として公開され、議論されているものである。 図 RTP ペイロードフォーマット tp(type): 2bits 0: プログレッシブ 1: インターレース 奇数フィールド 2: インターレース 偶数フィールド 3: インターレース 奇数フィールドと偶数フィールドの両方 MHF (Main Header Flag) : 2 bits 走査型の識別 ペイロード中のメインヘッダの有無 0: ペイロード中にメインヘッダがない 1: メインヘッダがフラグメント化されている 2: フラグメント化されたメインヘッダの最後 3: ペイロード中にメインヘッダが全て含まれている mh_id (Main Header Identification) : 3 bits 26 メインヘッダをロスした場合に、メインヘッダの復元が可能かどうか メインヘッダの値が変わるごとに1ずつインクリメントする T (Tile field invalidation flag) : 1 bit タイルナンバーの有効性 0: タイルナンバーが有効 複数のタイルパートが1つのペイロードに格納されている ペイロード中にメインヘッダしかない など JPEG2000 におけるペイロードの重要度 0: メインヘッダやタイルパートヘッダといった最も重要度が高いもの 1-255: その他(番号が大きくなるほど、重要度が低くなる) タイルナンバー T=0 のとき、タイルナンバーを示す T=1 のとき、受信側はこのフィールドを無視する R (Reserved) : 8 bits 予約された領域 tile number : 16 bits 1: タイルナンバーが向こう priority : 8 bits ペイロード中に1つのタイルパートしか存在しない 常に 0 fragment offset : 24 bits JPEG2000 コードストリームの先頭からのオフセットバイト数 5.5 受信部 5.5.1 受信部設計概要 受信部は以下の機能要素から構成される。 IP ネットワークからのデータ受信 エラー処理 JPEG2000 データをデコード デバイスにレンダリング 上記の機能要素を、DirectShow フィルタとして構成した場合、受信側のフィルタは以下の 3つになる ― Network Recv 27 Network Recv フィルタは、送信側から IP ネットワークを通して送られてきた UDP パ ケットを JPEG2000 データとして再構築するフィルタである。また、後述するが、伝送 時のエラー、例えばパケットロスなどに対処する。本研究で、設計実装する。 ― LEAD ML2K Decoder LEAD ML2K Decoder フィルタは、JPEG2000 データを非圧縮の映像データへデコード するフィルタである。LEAD ML2K Encoder 同様、LEAD Technologies 社が販売してい るフィルタである。 ― Video Renderer Video Renderer フィルタは、非圧縮の映像データをモニタへレンダリングするフィルタ である。このフィルタは DirectShow 付属のフィルタである。 図 受信側フィルタグラフ 5.5.2 Network Recv フィルタの設計 5.5.2.1 基底クラス Nerwork Recv フィルタは、基底クラスとして CSource クラスと CSourceStream クラス を継承する。CSource クラスと CSourceStream クラスはソースフィルタを作成する際に 用いられる基底クラスである。 5.5.2.2 ネットワークからのデータ受信 受信バッファにデータを受信する。受信バッファのデータを出力ピンの出力バッファに 書き込む前に、次に挙げる項目をチェックする。 ― パケットの識別 受け取ったパケットのシーケンス番号をもとに、パケットの到着順序やパケットロスの 有無を調べる。仮に正しい順序でパケットが到達していないことが判明した場合、そパケ ットロスとしてカウントする。 ― ペイロードの識別 送信側は JPEG2000 コードストリームのヘッダとタイルパートを別々のパケットで送信 28 している。到達優先度が最も高いヘッダが欠落してしまった場合、通常のパケットロスと は異なった対応をとる必要がある。というのは、ヘッダとりわけメインヘッダが欠落して しまった場合、当該フレームのデコードは不可能だからである。 メインヘッダが欠落してしまった場合の対応策として、前に受信したメインヘッダが再 利用可能かどうかを調べて、再利用可能であれば、そのヘッダを欠落したメインヘッダの 代替として用いるということが挙げられる。しかしながら、映像フレームに、タイルパー トが1つしかなく、かつタイルパートヘッダが欠落してしまった場合、ヘッダの補完がで きないため、フレームを破棄しなければならない。 5.6 制御部分 29 第 6 章 実装 本章では、前章で述べた設計に基づいて実装した送信部分・受信部分・制御部分のフィ ルタについて述べる。6.1節で実装の概要について述べ、6.2節以降で、実際に実装 したフィルタについての詳らかな説明を行う。 6.1 実装環境 本研究では送信部分・受信部分・制御部分を全て DirectShow フィルタとして実装する。 また、本研究で用いる JPEG2000 のエンコーダとデコーダは Video for Windows もしくは DirectShow 上のみ利用できるものである。したがって、フィルタの実装環境には Windows OS を選択した。表に実装に用いた環境を示す。 表 ソフトウェア環境 OS Windows XP SP1 開発環境 Visual Studio .NET2003 DirectX DirectX 9.0c 言語 Visual C++ .NET2003 JPEG2000 のエンコーダ・デコーダ 表 エンコーダ LEAD Technologies デコーダ LEAD Technologies 表 ハードウェア環境。 CPU Pentium4 3.0GHz メモリ 1024 MBytes ハードディスク 120GBytes NIC 100Base-TX 6.2 フィルタ間のデータの受け渡し フィルタ間でのデータの受け渡しは、IMediaSample インターフェイスのオブジェクト を使って行う。下の表に、受け渡しの際に用いるメソッドを示す。 30 メソッド 説明 GetPointer バッファのポインタを取得する GetSize バッファのサイズを取得する GetActualDataLength バッファ内の有効データサイズを取得する SetActualDataLength バッファ内の有効データサイズを設定する 図 データの受け渡しの際に用いるメソッド 実際のデータの書き込みは次のようになる。 //pMediaSample: IMediaSample インターフェイスのインスタンス //バッファのポインタを格納するポインタ変数 BYTE* pData; //バッファのポインタを取得 pMediaSample->GetPointer( &pData ); //バッファへデータをコピー CopyMemory( pData, コピー元, コピーするサイズ ); //実データサイズを格納 pMediaSample->SetActualDataLength( 実データサイズ ); 図 データの書き込み 31 実際のデータの読み込みは次のようになる。 // pMediaSample: IMediaSample インターフェイスのインスタンス //バッファのポインタを格納するポインタ変数 BYTE* pData; //実データサイズを格納する変数 LONG lDataSize; //バッファのポインタを取得 pMediaSample->GetPointer( &pData ); //バッファ内の実データサイズを取得 lDataSize = pMediaSample->GetActualDataLength( ); //バッファからデータをコピー CopyMemory( コピー先, pData, lDataSize ); 図 データの読み込み 6.2 送信部分フィルタ 本節では送信部分のフィルタである network send フィルタの詳細について述べる。 network send フィルタは、CBaseRenderer クラスを継承した CNetworkSend クラスとし て実装される。CNetworkSend クラスの機能は次の通りである。 UDP Socket の作成 マーカ・マーカセグメント解析 IP パケット送信 6.2.1 CNetworkSend クラス 下に CNetworkSend クラスの定義を示す。 32 class CNetworkSend : public CBaseRenderer { private: WSADATA wsaData; SOCKET sock; SOCKADDR_IN addrTo; RTP_HEADER rtp_header; RTP_PAYLOAD_HEADER_JP2 rtp_payload; char szSendBuf[1500]; private: CNetworkSend ( IUnknown* pUnk, HRESULT* phr ); ~CNetworkSend ( ); public: static CUnknown* WINAPI CreateInstance( IUnknown* pUnk, HRESULT* phr ); HRESULT CheckMediaType( const CMediaType* pmt); HRESULT DoRenderSample( IMediaSample* pMediaSample); int SeekMarker(LPBYTE pBuf); }; 図 CNetworkSend クラス CNetworkSend クラスはレンダラの基底クラスである CBaseRenderer クラスを継承し ている。CBaseRenderer クラスは下の図の 2 つの関数を純粋仮想メソッドとしてもってい る。したがって、CBaseRenderer クラスを継承したクラスは最低限この2つの関数をオー バーロードしなければならない。なお、”PURE” は純粋仮想メソッドを表わす “=0” のマ クロである。 33 virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; virtual HRESULT CheckMediaType(const CMediaType *) PURE; 図 CBaseRenderer クラスの純粋仮想メソッド 6.2.2 UDP Socket の作成 CNetworkSend クラスのコンストラクタで、UDP Socket を作成する。いったんメモリ 上に生成された CNetworkSend フィルタがメモリから開放されるのは、アプリケーション 終了時と、Release メソッドの呼び出しにより参照カウントが 0 になった時のみである。し たがって、コンストラクタで作成された UDP ソケットは終了時まで保持される。 作成した Socket はデストラクタで閉じる。 6.2.3 マーカ・マーカセグメントの解析 ヘッダとタイルパートを分割して送信するために、マーカ・マーカセグメントの解析を行 う。解析対象とするマーカは次の通りである。 SOC SOT タイルパートヘッダの先頭 SOD JPEG2000 コードストリームの先頭 タイルパートヘッダの終端 EOC コードストリームの終端 次にマーカ・マーカセグメント解析のフローチャートを示す。コードストリーム中にタイ ルパートは複数存在してもよいから、EOC マーカに到達するまで、コードストリーム中の タイルパートの検出を行う。マーカセグメントが検出され次第、次節で述べるが、IP パケ ット送信を行う。 34 LEAD Technologies 社のエンコーダが出力する JPEG2000 データは、タイルパートが1 つしかない。したがって、実際には繰り返し処理を行うことなく、フレーム終端へ到着す る。 この部分はまだ未実装です。 6.2.4 IP パケット送信 マーカセグメントが検出されるごとに、IP パケット送信を行う。以下にメインヘッダ、 タイルパートヘッダ、ビットストリームごとの RTP ペイロードヘッダの値と処理を記す。 ― メインヘッダ MHF = 3 priority = 0 メインヘッダのサイズは MTU 以下であるため、そのまま sendto 関数を呼び出し、パケ ットを送信する。 35 ― タイルパートヘッダ MHF = 0 priority = 0 タイルパートヘッダのサイズも MTU 以下であるため、そのまま sendto 関数を呼び出し、 パケットを送信する。 ― ビットストリーム MHF = 0 priority = 1 以上 ビットストリームのサイズは、通常、MTU よりも大きい。したがって、ビットストリー ム部分は分割して送信する。 6.3 受信部分 Filter 本節では受信部分のフィルタである network recv フィルタの詳細について述べる。 network recv フィルタは、CSource クラスを継承した CNetworkRecv クラスによって実装 される。しかし、データの受信や受け渡しといった主要な処理は network recv フィルタの 出力ピンが行う。出力ピンは CSourceStream クラスを継承した CNetworkRecvPin クラス によって実装される。 図 network recv フィルタの構成 36 以下に CNetworkRecv クラスと CNetworkRecvPin クラスの構成を示す。 class CNetworkRecv : public CSource { private: CNetworkRecv( IUnknown *pUnk, HRESULT *phr ); public: static CUnknown * WINAPI CreateInstance( IUnknown *pUnk, HRESULT *phr ); }; 図 CNetworkRecv クラス CNetworkRecv クラスはの主要な役割は、そのコンストラクタの中で、CNetworkRecvPin のオブジェクトを生成することである。IP パケット受信といった具体的なデータの扱いは、 CNetworkRecvPin が担う。 37 class CNetworkRecvPin : public CSourceStream { private: SOCKET sock; SOCKADDR_IN addrMe; char szRecvBuf[1500]; BOOL bRecvisFirst; WORD wBeforeSequenceNum; WORD wSequenceNum; DWORD dwTimestamp; DWORD dwBeforeTimestamp; DWORD dwPacketLoss; LONG lTotalByteNoRTP; LONG lTotalByte; CCritSec m_cSharedState; protected: HRESULT GetMediaType(CMediaType *pMediaType); HRESULT CheckMediaType(const CMediaType *pMediaType); HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest); HRESULT FillBuffer(IMediaSample *pSample); public: CNetworkRecvPin (HRESULT *phr, CSource *pFilter); ~ CNetworkRecvPin ( ); }; 図 CNetworkRecvPin クラス 6.3.1 IP パケット受信 38 第 7 章 評価 7.1 評価概要 7.2 本システムの実現した機能 7.3 送出データ量の計測 7.4 より柔軟な輻輳制御の実現 7.4.1 実験: 帯域幅の不足 7.4.2 実験: 遅延時間 7.5 まとめ 39 第 8 章 結論 8.1 まとめ 8.2 今後の課題 40 付録 RenBase.h 内で定義されている CBaseRenderer クラス // Main renderer class that handles synchronisation and state changes class CBaseRenderer : public CBaseFilter { protected: friend class CRendererInputPin; friend void CALLBACK EndOfStreamTimer( UINT uID, // Timer identifier UINT uMsg, // Not currently used DWORD_PTR dwUser, // User information DWORD_PTR dw1, // Windows reserved DWORD_PTR dw2); // Is also reserved CRendererPosPassThru *m_pPosition; // Media seeking pass by object CAMEvent m_RenderEvent; // Used to signal timer events CAMEvent m_ThreadSignal; // Signalled to release worker thread CAMEvent m_evComplete; // Signalled when state complete BOOL m_bAbort; // Stop us from rendering more data BOOL m_bStreaming; // Are we currently streaming DWORD_PTR m_dwAdvise; // Timer advise cookie IMediaSample *m_pMediaSample; // Current image media sample BOOL m_bEOS; // Any more samples in the stream BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE CRendererInputPin *m_pInputPin; // Our renderer input pin object CCritSec m_InterfaceLock; // Critical section for interfaces CCritSec m_RendererLock; // Controls access to internals IQualityControl * m_pQSink; // QualityControl sink BOOL m_bRepaintStatus; // // Can we signal an EC_REPAINT Avoid some deadlocks by tracking filter during stop volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive // And actually processing the sample REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE 41 UINT m_EndOfStreamTimer; CCritSec m_ObjectCreationLock; // Used to signal end of stream // This lock protects the creation and // of m_pPosition and m_pInputPin. It // ensures that two threads cannot create // either object simultaneously. public: CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer TCHAR *pName, // Debug ONLY description LPUNKNOWN pUnk, // Aggregated owner object HRESULT *phr); // General OLE return code ~CBaseRenderer(); // Overriden to say what interfaces we support and where virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv); STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); virtual HRESULT SourceThreadCanWait(BOOL bCanWait); #ifdef DEBUG // Debug only dump of the renderer state void DisplayRendererState(); #endif virtual HRESULT WaitForRenderTime(); virtual HRESULT CompleteStateChange(FILTER_STATE OldState); // Return internal information about this filter BOOL IsEndOfStream() { return m_bEOS; }; BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; BOOL IsStreaming() { return m_bStreaming; }; void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; 42 // Permit access to the transition state void Ready() { m_evComplete.Set(); }; void NotReady() { m_evComplete.Reset(); }; BOOL CheckReady() { return m_evComplete.Check(); }; virtual int GetPinCount(); virtual CBasePin *GetPin(int n); FILTER_STATE GetRealState(); void SendRepaint(); void SendNotifyWindow(IPin *pPin,HWND hwnd); BOOL OnDisplayChange(); void SetRepaintStatus(BOOL bRepaint); // Override the filter and pin interface functions STDMETHODIMP Stop(); STDMETHODIMP Pause(); STDMETHODIMP Run(REFERENCE_TIME StartTime); STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State); STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); // These are available for a quality management implementation virtual void OnRenderStart(IMediaSample *pMediaSample); virtual void OnRenderEnd(IMediaSample *pMediaSample); virtual HRESULT OnStartStreaming() { return NOERROR; }; virtual HRESULT OnStopStreaming() { return NOERROR; }; virtual void OnWaitStart() { }; virtual void OnWaitEnd() { }; virtual void PrepareRender() { }; #ifdef PERF REFERENCE_TIME m_trRenderStart; // Just before we started drawing // Set in OnRenderStart, Used in OnRenderEnd int m_idBaseStamp; // MSR_id for frame time stamp int m_idBaseRenderTime; // MSR_id for true wait time int m_idBaseAccuracy; // MSR_id for time frame is late (int) #endif 43 // Quality management implementation for scheduling rendering virtual BOOL ScheduleSample(IMediaSample *pMediaSample); virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime); virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, REFERENCE_TIME *ptrStart, REFERENCE_TIME *ptrEnd); // Lots of end of stream complexities void TimerCallback(); void ResetEndOfStreamTimer(); HRESULT NotifyEndOfStream(); virtual HRESULT SendEndOfStream(); virtual HRESULT ResetEndOfStream(); virtual HRESULT EndOfStream(); // Rendering is based around the clock void SignalTimerFired(); virtual HRESULT CancelNotification(); virtual HRESULT ClearPendingSample(); // Called when the filter changes state virtual HRESULT Active(); virtual HRESULT Inactive(); virtual HRESULT StartStreaming(); virtual HRESULT StopStreaming(); virtual HRESULT BeginFlush(); virtual HRESULT EndFlush(); // Deal with connections and type changes virtual HRESULT BreakConnect(); virtual HRESULT SetMediaType(const CMediaType *pmt); virtual HRESULT CompleteConnect(IPin *pReceivePin); 44 // These look after the handling of data samples virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); virtual HRESULT Receive(IMediaSample *pMediaSample); virtual BOOL HaveCurrentSample(); virtual IMediaSample *GetCurrentSample(); virtual HRESULT Render(IMediaSample *pMediaSample); // Derived classes MUST override these virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; virtual HRESULT CheckMediaType(const CMediaType *) PURE; // Helper void WaitForReceiveToComplete(); }; 45 ImediaSample インターフェイスの定義 IMediaSample : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE GetPointer( /* [out] */ BYTE **ppBuffer) = 0; virtual long STDMETHODCALLTYPE GetSize( void) = 0; virtual HRESULT STDMETHODCALLTYPE GetTime( /* [out] */ REFERENCE_TIME *pTimeStart, /* [out] */ REFERENCE_TIME *pTimeEnd) = 0; virtual HRESULT STDMETHODCALLTYPE SetTime( /* [in] */ REFERENCE_TIME *pTimeStart, /* [in] */ REFERENCE_TIME *pTimeEnd) = 0; virtual HRESULT STDMETHODCALLTYPE IsSyncPoint( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetSyncPoint( BOOL bIsSyncPoint) = 0; virtual HRESULT STDMETHODCALLTYPE IsPreroll( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetPreroll( BOOL bIsPreroll) = 0; virtual long STDMETHODCALLTYPE GetActualDataLength( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetActualDataLength( long __MIDL_0010) = 0; virtual HRESULT STDMETHODCALLTYPE GetMediaType( AM_MEDIA_TYPE **ppMediaType) = 0; virtual HRESULT STDMETHODCALLTYPE SetMediaType( AM_MEDIA_TYPE *pMediaType) = 0; virtual HRESULT STDMETHODCALLTYPE IsDiscontinuity( void) = 0; virtual HRESULT STDMETHODCALLTYPE SetDiscontinuity( BOOL bDiscontinuity) = 0; virtual HRESULT STDMETHODCALLTYPE GetMediaTime( /* [out] */ LONGLONG *pTimeStart, /* [out] */ LONGLONG *pTimeEnd) = 0; virtual HRESULT STDMETHODCALLTYPE SetMediaTime( /* [in] */ LONGLONG *pTimeStart, /* [in] */ LONGLONG *pTimeEnd) = 0; 46 }; CSource クラス class CSource : public CBaseFilter { 47 public: CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid); #ifdef UNICODE CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr); CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid); #endif ~CSource(); int GetPinCount(void); CBasePin *GetPin(int n); // -- Utilities -// provide our critical section CCritSec* pStateLock(void) { return &m_cStateLock; } HRESULT AddPin(CSourceStream *); HRESULT RemovePin(CSourceStream *); STDMETHODIMP FindPin( LPCWSTR Id, IPin ** ppPin ); int FindPinNumber(IPin *iPin); protected: // The number of pins on this filter. Updated by CSourceStream int m_iPins; // constructors & destructors. CSourceStream **m_paStreams; CCritSec m_cStateLock; // the pins on this filter. // Lock this to serialize function accesses to the filter state }; CSourceStream クラス class CSourceStream : public CAMThread, public CBaseOutputPin { 48 public: CSourceStream(TCHAR *pObjectName, HRESULT *phr, CSource *pms, LPCWSTR pName); #ifdef UNICODE CSourceStream(CHAR *pObjectName, HRESULT *phr, CSource *pms, LPCWSTR pName); #endif virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. protected: CSource *m_pFilter; // The parent of this stream // * // * Data Source // * // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are // * called from within the ThreadProc. They are used in the creation of // * the media samples this pin will provide // * // Override this to provide the worker thread a means // of processing a buffer virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; // Called as the thread is created/destroyed - use to perform // jobs such as start/stop streaming mode // If OnThreadCreate returns an error the thread will exit. virtual HRESULT OnThreadCreate(void) {return NOERROR;}; virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; 49 virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; // * // * Worker Thread // * HRESULT Active(void); // Starts up the worker thread HRESULT Inactive(void); // Exits the worker thread. public: // thread commands enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; HRESULT Init(void) { return CallWorker(CMD_INIT); } HRESULT Exit(void) { return CallWorker(CMD_EXIT); } HRESULT Run(void) { return CallWorker(CMD_RUN); } HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } HRESULT Stop(void) { return CallWorker(CMD_STOP); } protected: Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } // override these if you want to add thread commands virtual DWORD ThreadProc(void); // the thread function virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running // * // * AM_MEDIA_TYPE support // * // If you support more than one media type then override these 2 functions 50 virtual HRESULT CheckMediaType(const CMediaType *pMediaType); virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); List pos. 0-n // If you support only one type then override this fn. // This will only be called by the default implementations // of CheckMediaType and GetMediaType(int, CMediaType*) // You must override this fn. or the above 2! virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;} STDMETHODIMP QueryId( LPWSTR * Id ); }; 51 // 謝辞 本研究を進めるにあたり、御指導を頂きました、慶應義塾大学環境情報学部教授の 村井純博士、徳田英幸博士、同学部助教授の楠本博之博士、中村修博士、同大学環境 情報学部専任講師の南政樹氏に感謝致します。 絶えずご指導とご助言を頂きました慶應義塾大学院政策・メディア研究科助手の杉浦一徳 博士に感謝致します。 52
© Copyright 2024 Paperzz