USB MPEGモジュール

かなり長いことうまく動かず下書きにしていたのだが、とりあえずキャプチャできるようになったので公開する。調べていた頃に気づいたことを書き綴ったので、文章としては成立してません。

今更だがNTSCをMPEGのUSBストリームにするモジュールを調べてみた。

ターゲットはConexantのCX23416にEZ-USB FX2をつけたものです。これはConexantのリファレンスデザインを元に設計されているものと思われます。

CX23416はエンコードだけの機能しかありませんが、CX23415というチップはエンコードとデコードの機能があるようです。

手元にはハードオフで消費税が5%の頃に315円で入手したモジュールが二種類あります。

Conexantはこのチップに関しては一切のコードをオープンソースにはしておらず、またデーターシートも原則非公開であったため、Windows環境のUSBのスヌープなどで仕様を把握していたようです。

<a data-flickr-embed="true"  href="https://www.flickr.com/photos/14000636@N03/10484785676/" title="IMGP2464"><img src="https://c1.staticflickr.com/8/7351/10484785676_b005c51241_z.jpg" width="640" height="480" alt="IMGP2464"></a>

![PVRUSB_HW.png](https://qiita-image-store.s3.amazonaws.com/0/104066/baa41c63-4a08-fe74-73fa-57247add829e.png)

CX23416はPCIのインターフェースと普通のIOでもアクセスできるようで、FX2からはIOでアクセスしていると思われる。

EEPROMはおそらく機能的には必要なくて、ドライバが設定値を保存しするためなどに使っているじゃないかと思われる。

CX23416にもI2Cのマスターの機能があるが、このモジュールでは使ってない。PCI接続の場合にビデオデコーダーなどの設定に使われているものと思われる。

CX25837はAudio IFが無いチップでI2SなADCが必要だが、リファレンスに使われているCX2584xはAudio IFが入っているようだ。

CS5340のMO,M1は両方とも0でSingle-Speed Modeのようだ。

ビデオデコーダーチップはPhilips SAA7111Aというものもあるが、このタイプのモジュールはConexantのものを使ったものが多いようだ。

PCIでもIOでもDMAがありそれでCPU側のメモリにデータを書き込んでいるものと考えられる。

MBOXという機能はPCIにもありPCIのアドレス空間にあるようなので通常のIOでも何らかの方法で、CX23416から引きとれるのではないだろうか。

Terratec Grabster AV 400という製品と同じ物ではないかと思われます。

CX23416はPCIのカードでも使われていたようです。またアナログ地上波のチューナ付きのモジュールも存在していたようです。アナログ地上波があったころには日本でもFreeBSDでPCIカードのサポートを試されていた人がいたようですが、すでにページが無くなっていました。。。

Conexantビデオプロダクトは元々はBrooktreeだったとおもいます。Brooktreeはコンピュータのフレームバッファのチップや、ビデオのエンコーダーチップなどを作っていました。アナログ地上波があった頃はキャプチャチップとしてBT848が最もメジャーで一世を風靡しました。CX23416はBT848などに比べるとちょっと違った感じなので、Brooktree由来ではないチームが作ったのかもしれません。CX25837の方はおそらくBrooktreeなチームが作ったような気がします。

Conexantも買収されて消滅しており、半導体ビジネスはほんとうに難しいと感じさせられます。

このモジュールにはLinux方面では[pvrusb2](http://www.isely.net/pvrusb2/pvrusb2.html)というドライバが存在します。

このドライバは当初はユーザーランドのプログラムでストリームを拾いだす[HACK](http://pvrusb2.dax.nu/)だったものを、v4lのドライバにしたようです。

firmwareをダウンロードして使うタイプのモジュールなのだが、firmwareはEZ-USB FX2用とCX23416用の二つ必要になる。これらはWindowsのドライバのp2usbwdm.sysの中に入っています。

![PVRUSB_SYS.png](https://qiita-image-store.s3.amazonaws.com/0/104066/3b8690c0-ae6c-f537-7ef6-682cde36949f.png)

p2usbwdm.sysはConexantが作っていて、ベンダーには同じものを提供しているようで、firmwareはいくつか入っているようです。おそらくinfファイルを元にどのfirmwareを使うか判断しているのではないだろうか。抜き出したfirmwareのProduct Stringなどの文字列はUTF-16で入っているのでstringsコマンドでは確認できない。

```
0000d90 002   @  ¥0  ¥0 004 003  ¥t 004 022 003   C  ¥0   o  ¥0   n  ¥0
0000da0   e  ¥0   x  ¥0   a  ¥0   n  ¥0   t  ¥0 036 003   P  ¥0   C  ¥0
0000db0   -  ¥0   M  ¥0   D  ¥0   V  ¥0   D  ¥0   /  ¥0   U  ¥0   2  ¥0
```

初期化はまずFX2の8Kバイトのfirmwareをダウンロードする。これは通常のEZ-USB FX2のダウンロード方法でおこなう事ができます。

ユーザーランドのpvrusb2の中にもlibusbベースのusbreplayコマンドで引数を-iとするとfx2-firmware.binというファイルをダウンロードできるが、以前見つけてあったMac OS Xサンプルコードでもダウンロードできるようにしてみた。

https://github.com/yamori813/Ezloader_OSX

```
Ezload -v 0x04b4 -p 0x8613 -n -F -r -f GV-MDVD.bin 
```

正しいファームウエアがダウンロードされると、スイッチのLEDが赤から緑に変わります、スイッチを押すとLEDが消えて電源が落ちます。もう一度押すと赤くなり、ダウンロードされてない状態すなわちFX2に戻ります。

FX2のfirmwareがダウンロードされて起動して、VID/PIDが変わる。変わった後のEndPointは以下の構成になっている。

|no|type|
|:--|:--|
|0x81|Bulk Input|
|0x84|Bulk Input|
|0x88|Bulk Input|
|0x01|Bulk Output|
|0x02|Bulk Output|
|0x86|Bulk Input|

0x81と0x01はコントロール用で、0x02はCXのfirmwareのダウンロード用で0x84がビデオストーリムで0x88がVBIのストリームのようだ。

VBIというのはNTSCの表示されない上部の走査線にビットパターンを乗せてデジタルデータを送信する仕組みでした。1998年くらいにその仕組みを作っていた会社にいたのですが、個人的にこのデコードの処理をFreeBSDのbktrに入れたことがあります。

このモジュールのチップの制御は以下の通りである。

* USB Bulkによるコントロール
 * コマンドによるコントール
 * I2Cによるコントロール
 * レジスタによるコントロール
 * MBOXによるエンコーダのコントロール

ビデオストーリムをそのままファイルに書き込めばmpegのファイルになるのではないかと思われる。

MBOXはメモリの0x44からあるのだが、long値なので二つ目は0x48かとおもったら、0x45だった。

FX2のファームウエアがダウンロードされたらCX23416のファームウエアをダウンロードする。こちらは256Kバイトになっているようだ。

firmwareはlinuxのリポジトリにもいくつか存在するが、FX2のfirmwareは最後の部分がaaでパディングされているので、それを元に探せる。CX23416のfirmwareはpvrusb2のページにもあるが、66 bb 55 aaのバイトの並びで探す事が出来るようだ。

抜き出したCXのfirmwareはバイトオーダー（エンディアン）が逆なので、ダウンロードする前にひっくり返す必要がある。

CXのfirmwareの仕様はCX23416 Firmware API Reference Manualというドキュメントに書かれているようだが、ネットで探しても出てこない。

CXのfirmwareは256Kと大きいので、ひょっとするととCX23416の中には一般的なCPUが入っているような気もします。

firmwareがダウンロードできたら、I2Cで接続されたvideoエンコーダーの初期化などをしてストリームをONにするとmpegのデータがUSBのバルクパイプから拾えるようになるようだ。

ユーザーランドのpvrusb2はusbsnoopで拾いだしたログでこれらの初期化をしている。ドライバの方はFX2のfirmwareのコマンドがpvrusb2-fx2-cmd.hでdefineされているが、コツコツ調べた模様。protocol-info.txtというファイルに仕様がある。

このモジュールのドライバの挙動をWindowsのUSBPcapで調べてみようとしたのだが、まったくデータが拾えない。何でなんだろう。。。

いろいろ試行錯誤の結果Macでキャプチャできるプログラムができました。

https://github.com/yamori813/mpeg-usb

rubyのスクリプトはWindowsのドライバからのfirmwareを抜き出すためのものです。

mpegcapt.cのビルドにはlibusb 1.0が必要です。

mpegcapt.cがlibusb1ベースのプログラムで、引数にcxのfirmwareと保存するファイル名を渡します。実行する前にFX2のfirmwareをダウンロードしておきます。このプログラムはctrl-cされるまでNTSC信号をmpegファイルに落とします。

キャプチャした画像はこんな感じです。VHSのテープが傷んでなければ結構綺麗に撮れます。

![スクリーンショット 2018-10-05 22.28.45.png](https://qiita-image-store.s3.amazonaws.com/0/104066/7a8e5d9d-8552-9b3e-0e1e-d4c839bca229.png)


映像がキャプチャーできるようになったのですが、オーディオが入りませんでした。いろいろ考えてみて試したところCX25837のPLL_CLK_OUT_ENをEnabled(1)にしたらいけました。

ちょっとわからないのがエンコーダーの設定がオーディオ設定(CX2341X_ENC_SET_AUDIO_PROPERTIES)が32Khzで正しく聞こえるのですが、CX25837のデフォルトは48KHzとデーターシートにあります。またなぜかVID_COUNTとAUD_COUNTがデフォルト値から微妙にずれています。あとこの表の意味が全く理解できません。

![スクリーンショット 2018-10-05 22.38.04.png](https://qiita-image-store.s3.amazonaws.com/0/104066/c4ad131c-4611-13db-7a74-f5c3b6373aad.png)

追記：当初10%くらい間延びしてたのを、いろいろ試して1%くらいまで追い込んであります。~~データーシートの記載をもとにロジックを入れました。~~複数のサンプリングレートでうまくいかなかったのでLinuxのドライバーにあった直値に代えました。

PCI(eじゃない)なデバイスは使える環境がほとんどなくなりつつありますが、USBは当面なくならないと思います。USBはほんとうにエコシステムだと思います。

デフォルトの入力はS Videoになっています。コンポジットでの接続の場合には-cオプションをつけます。

取り込んだファイルはQuickTime Playerで再生できます。

VHSやLDを取り込むときは下記のような接続になります。モニターする機能はないので、可能であればVHSやLDにモニターをつないでおくのが良いです。

![mpegcapt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/3ad9847a-4148-12dc-f965-3a89ace8cf8c.png)


NTSCは50年近くも現役だったので、VHSやLDでDVD化されてないものなど、手持ちのソースをデジタル化するのに良いのではないかと思います。

ハードオフでIOのチューナ付きのモジュールを買ってみたところ、CX23416は使われおらず、ソフトウエアエンコードするモジュールだった。主要チップはEMPIAのEM2820とEMP202とTIのTVP5150とチューナがPHILIPSのFQ1236/Fだった。USBのデバイスIDからCX23416なモジュールの前の製品と思われる。チューナ付きのCX23416なモジュールもあるようだ。Linux方面ではMP28xxというドライバーが存在する。

最近Amazonなどで販売されているNTSCキャプチャモジュールはソフトウエアエンコード用のもので、Conexantも無くなってしまい、ハードウエアエンコーダーはほとんどなくなっているのでかなり貴重な気がします。生のNTSCをそのまま送ろとかなりの転送レートになるので、圧縮してるものと思われます。そのため画質は劣化しますし、PCで一旦展開してまたmpegエンコードするので負荷高いんじゃないかな。このモジュールはWindows 10などで動かないようなので、狙い目ですよ。

コンパイルとか負荷の高い処理しながら動かすと飛んでしまうようなので、あまり負荷の高い処理は同時に動かさない方がよいです。

ハードオフでいろいろ物色してたら、このモジュールより前の製品で[BROADCOMのKfir-II](https://qiita.com/yamori813/items/dbbbe701f2634928665d)を使った製品があった。Kfir-IIはCX23416と同じくPCIと汎用IOのインターフェースがありEZ-USB FX2でUSB化されていた。

VHSビデオのキャプチャーサンプルアップしました。
https://youtu.be/zI6vjJJ9vzw

参考資料

https://linuxtv.org/downloads/v4l-dvb-apis/v4l-drivers/cx2341x.html