仙石浩明の日記

2007年10月15日

ビデオキャプチャ・カード GV-MVP/RX2W を使って Linux 2.6.22.10 でテレビ録画 hatena_b

Linux でテレビ録画を行なう方法は、 多くの Web ページで紹介されているが、 ビデオキャプチャ・カードによっては、 Linux カーネルのバージョンが変わると一筋縄にはいかなかったりするので、 現時点での Linux カーネル安定版の最新バージョン 2.6.22.10 で、 I-O DATA 製 ハードウェア MPEG-2 エンコーダ搭載TVキャプチャボード GV-MVP/RX2W (2006年7月5日生産終了) を使う方法をメモ (2.6.24.4 で使う方法)。

といっても多くの方々の努力により、 GV-MVP/RX2 は標準のカーネルのままで (多少の不具合はあるにせよ) テレビ視聴が可能になりつつあるので、 Linux 2.6.22.10 の時点で必要なパッチは、 以下の三ヵ所のみ (モノラル音声で構わなければ saa7115 に対するパッチのみ)。 なお、 IVTV プロジェクト で 最新ドライバが公開されているが、 少なくとも GV-MVP/RX2W を使う限りにおいては 既に Linux 2.6.22.10 カーネルに取り込まれているドライバだけで問題がないので、 標準のカーネルのドライバのみを使っている。

まず、SAA7115 Video Decoder ドライバ・モジュール saa7115.ko に対するパッチ:

diff -ru linux-2.6.22.10.org/drivers/media/video/saa7115.c linux-2.6.22.10/drivers/media/video/saa7115.c
--- linux-2.6.22.10.org/drivers/media/video/saa7115.c        2007-08-23 08:23:54.000000000 +0900
+++ linux-2.6.22.10/drivers/media/video/saa7115.c        2007-10-14 06:37:09.000000000 +0900
@@ -1543,7 +1543,8 @@
                 saa711x_writeregs(client, saa7113_init);
                 break;
         default:
-                state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
+                state->ucgc = 1;
+                state->cgcdiv = 0x04;
                 saa711x_writeregs(client, saa7115_init_auto_input);
         }
         saa711x_writeregs(client, saa7115_init_misc);

CGC (Clock Generation Circuit) の設定。 SAA7115 は 32.11MHz か 24.576MHz の水晶発振子を利用できて、 GV-MVP/RX2 では後者なのであるが、 このパッチをあてておかないと 32.11MHz の設定になってしまって、 録画したものを再生すると音声が早回しになってしまう。

次に、オーディオ・チップ・ドライバ・モジュール tvaudio.ko に対するパッチ:

diff -ru linux-2.6.22.10.org/drivers/media/video/tvaudio.c linux-2.6.22.10/drivers/media/video/tvaudio.c
--- linux-2.6.22.10.org/drivers/media/video/tvaudio.c        2007-08-23 08:23:54.000000000 +0900
+++ linux-2.6.22.10/drivers/media/video/tvaudio.c        2007-10-14 06:38:26.000000000 +0900
@@ -528,6 +528,31 @@
                 chip_write(chip,TDA985x_C6,c6);
 }
 
+static int gvmvprx_getmode(struct CHIPSTATE *chip) {
+        return VIDEO_SOUND_MONO;
+}
+
+extern int tda9887_tuner_init(struct i2c_client *c);
+static void gvmvprx_setmode(struct CHIPSTATE *chip, int mode) {
+        u8 data[3] = { 0x00, 0x00, 0x04 };
+
+        switch (mode) {
+                case VIDEO_SOUND_MONO:
+                case VIDEO_SOUND_LANG1:
+                        break;
+                case VIDEO_SOUND_STEREO:
+                        data[1] = 0x01;
+                        break;
+                case VIDEO_SOUND_LANG2:
+                        data[1] = 0x02;
+                        break;
+        }
+
+        if (i2c_master_send(&chip->c, data, sizeof(data)) != sizeof(data)) {
+                v4l_err(&chip->c, "%s: I/O error setting audmode\n", chip->c.name);
+        }
+}
+
 
 /* ---------------------------------------------------------------------- */
 /* audio chip descriptions - defines+functions for tda9873h               */
@@ -1307,17 +1332,17 @@
                 .checkmode  = generic_checkmode,
         },
         {
-                .name       = "tda9850",
+                .name       = "tda9850 (GV-MVP/RX)",
                 .id         = I2C_DRIVERID_TDA9850,
                 .insmodopt  = &tda9850,
                 .addr_lo    = I2C_ADDR_TDA985x_L >> 1,
                 .addr_hi    = I2C_ADDR_TDA985x_H >> 1,
                 .registers  = 11,
 
-                .getmode    = tda985x_getmode,
-                .setmode    = tda985x_setmode,
+                .getmode    = gvmvprx_getmode,
+                .setmode    = gvmvprx_setmode,
 
-                .init       = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
+                .init       = { 3, { 0x00, 0x01, 0x04 } }
         },
         {
                 .name       = "tda9855",

ステレオ/モノラル/音声多重(二ヶ国語放送) 音声モードの変更。 GV-MVP/RX2W は他のチューナと異なり、 設定変更の際 3 バイトのデータを送信する必要があるらしい。

tda9887 を deemphasis->off (このチップは deemphasis すると音声を強制でモノラルにしてしまう。 tda9887.c の NTSC-M-J の項では deemphasis を default で OFF にすべきなのではないでしょうか。 素人考えかな。)
ivtv-0.2.0-rc3j-paken.051002-bilingul.patch をベースに MPX 操作 (レジスタ0に3バイト書き込むほう) すればうちのカードでは音声多重に対応できるようです。 レジスタ 0 に 1 バイト書き込むほうのMPX操作では うちのカードでは動作しませんでした。 カードのリビジョンとかの関係かもしれません。
ぱ研「LinuxでITVC16-STVLP」 の kazz 氏コメント (2007-03-10) から引用

DeEmphasis (DEM) モードを設定すると常にモノラル音声になってしまう。 kazz 氏が言及しているように default で DEM を off にしておけば 済むような気がするし、 そもそもなぜ DEM がデフォルトで ON になっているのか疑問だったので、 以下のようなパッチを tuner チップ・ドライバ・モジュール tuner.ko の tda9887.c にあてて、 NTSC-M-JP の場合は DeEmphasis を off にしてみた。

diff -ru linux-2.6.22.10.org/drivers/media/video/tda9887.c linux-2.6.22.10/drivers/media/video/tda9887.c
--- linux-2.6.22.10.org/drivers/media/video/tda9887.c        2007-08-23 08:23:54.000000000 +0900
+++ linux-2.6.22.10/drivers/media/video/tda9887.c        2007-10-14 11:59:50.000000000 +0900
@@ -214,8 +214,7 @@
                 .name  = "NTSC-M-JP",
                 .b     = ( cNegativeFmTV  |
                            cQSS           ),
-                .c     = ( cDeemphasisON  |
-                           cDeemphasis50  |
+                .c     = ( cDeemphasisOFF |
                            cTopDefault),
                 .e     = ( cGating_36     |
                            cAudioIF_4_5   |

「cDeemphasisON | cDeemphasis50」の部分を「cDeemphasisOFF」に変更しただけの 安易なパッチ (^^;) であるが、 とりあえずこれでステレオ/音声多重での録画が可能になっている。

以上のように tvaudio と tuner (tda9887.c) の両ドライバ・モジュールに パッチをあてることにより、 ステレオ/音声多重で録画できる。 もちろん v4l2-ctl コマンドで音声モードを変更することもできるが、 録画は常に「ステレオ/音声多重」で行なっておいて、 再生時に音声モードを切替えたほうが便利。

私は録画 perl スクリプトを自作して使っているが、 この perl スクリプトで使用している Video::ivtv & Video::Frequencies モジュールには若干問題がある。 すなわち setFrequency する際にチューナ形式を指定し忘れているので、 正しく TV チャンネルの変更が行なえない。 私は以下のような修正パッチをあてて使用している。

diff -u Video-ivtv-0.13/ivtv.xs.org Video-ivtv-0.13/ivtv.xs
--- Video-ivtv-0.13/ivtv.xs.org        2004-06-14 06:07:40.000000000 +0900
+++ Video-ivtv-0.13/ivtv.xs        2007-10-08 10:03:57.000000000 +0900
@@ -132,6 +132,7 @@
                 }
   CODE:
     vf.tuner = tuner;
+    vf.type = V4L2_OUTPUT_TYPE_ANALOG;
     if (ioctl(fd, VIDIOC_G_FREQUENCY, &vf) < 0)
     {
       RETVAL = -1;
@@ -158,6 +159,7 @@
     }
   CODE:
     vf.tuner = tuner;
+    vf.type = V4L2_OUTPUT_TYPE_ANALOG;
     vf.frequency = freq;
     if (ioctl(fd, VIDIOC_S_FREQUENCY, &vf) < 0)
     {

この録画スクリプトは 予約録画 (-t オプション) もサポートしている他、 tv -P 1234 などと実行すると、 TV サーバとして利用することもできる。 つまり LAN 内の任意のマシンで、 VLC media player を使って http://senri:1234/?c=1 などとチャンネル指定付で tv サーバへ接続し、 TV を視聴できる。

(ビデオキャプチャ・カード GV-MVP/RX2W を使って Linux 2.6.24.4 でテレビ録画)

Filed under: ハードウェアの認識と制御 — hiroaki_sengoku @ 07:14

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment