卒業論文 2004 年度(平成 16 年度) JPEG2000 を用いた最適動画像

卒業論文
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