recfsusb2nで初期のストリームを捨ててみる

先日、USB地デジチューナーのKTV-FSUSB2を購入しました。
Ubuntu 11.04で、recfsusb2nを使って録画サーバを構築できています。
先人に感謝です。


録画サーバとしては正常に動いてはいるものの、気になる点がありました。
録画したTSが、ffmpegmencoderなどのツールで受け付けられないんです。


ffmpegだとこんな感じ。

$ ffmpeg -i /tmp/err.ts 
...略...
[NULL @ 0x9a4e420]Format detected only with low score of 25, misdetection possible!
[mp1 @ 0x9a4f720]Header missing
    Last message repeated 1 times
[mpeg @ 0x9a4e420]pes_ext F0 is invalid
[mp1 @ 0x9a4f720]Header missing
    Last message repeated 200 times
[ac3 @ 0x9a53cc0]frame sync error
[mpeg @ 0x9a4e420]Could not find codec parameters (Audio: mp1, 0 channels, s16)
[mpeg @ 0x9a4e420]Could not find codec parameters (Video: 0x0000)
[mpeg @ 0x9a4e420]Could not find codec parameters (Audio: ac3, 0 channels, s16)
[mpeg @ 0x9a4e420]Could not find codec parameters (Video: 0x0000)
    Last message repeated 1 times
[NULL @ 0x9ab9670]start time is not set in av_estimate_timings_from_pts
/tmp/err.ts: could not find codec parameters

mencoderだとこんな感じ。

$ mencoder /tmp/err.ts -o dummy.ts
MEncoder UNKNOWN-4.5.2 (C) 2000-2011 MPlayer Team
success: format: 0  data: 0x0 - 0x1347f6c
TS file format detected.
VIDEO MPEG2(pid=337) AUDIO MPA(pid=338) NO SUBS (yet)!  PROGRAM N. 0
TS_PARSE: COULDN'T SYNC
MPEG: FATAL: EOF while searching for sequence header.
Video: Cannot read properties.

Exiting...

気になったので調べてみました。

TSパケットの解析

TSはTSパケットと呼ばれる188バイトのパケットの集合体でできています。
その中身を見てみました。

00000000 1 1 1 036C
00000001 1 0 1 1500
00000002 1 0 0 1D3A
00000003 1 0 0 0148
00000004 1 0 0 1164
00000005 1 0 0 0154
00000006 1 1 1 1167
00000007 1 0 0 11C4
00000008 1 0 1 1B99
00000009 1 1 1 1078
00000010 1 1 1 1354
00000011 1 0 0 1400
00000012 1 0 0 0109
00000013 1 1 1 13B6
00000014 1 0 0 08BB
00000015 1 1 0 1E41

先頭の数字が受信したパケットの番号、その次の3つの数字がそれぞれトランスポートエラーインジケータ、ペイロードスタートインジケータ、トランスポート優先度、最後の記号がPIDを表しています。


ことごとく、トランスポートエラーインジケータが立っています。PIDもめちゃめちゃです。
どうやらこのチューナー、録画を開始してから受信が落ち着くまで、しばらく時間がかかるっぽいです。


うちの環境では先頭から6000パケットあたりで安定し始め、だいたい7000-10000パケットあたりで完全に安定します。
10000パケット目からみてみると、こんなかんじ

00010000 0 0 0 0100
00010001 0 0 0 0100
00010002 0 0 0 0100
00010003 0 0 0 0583
00010004 0 0 0 0100
00010005 0 0 0 0100
00010006 0 0 0 0100
00010007 0 0 0 0100
00010008 0 0 0 0100
00010009 0 0 0 0164
00010010 0 0 0 0100
00010011 0 0 0 0100
00010012 0 0 0 0100
00010013 0 0 0 0100
00010014 0 0 0 0100
00010015 0 0 0 0140

きれいですね。

録画するときに、先頭のパケットを捨てる

どうやら、先頭のパケットを削れば良さそうです。


録画してから削っても良いんですが、巨大なTSは録画した後の編集が非常にめんどくさいです。
できれば、録画時に削ってしまいたい、、、


最初に考えたのは、recfsusb2nでTSを標準出力に吐き出して、それをごにょごにょする方法。
実際にやってみたんだけども、CPU負荷がすごいです。Atomが悲鳴をあげてる;;
ごにょごにょするツールがRubyだ、てのもあるかもしれません。Cだと話は変わるかも。


次に考えたのが、recfsusb2nに手を入れちゃう方法。


recfsusb2nはTSパケットを意識してないっぽかったので、最初の2回分の受信を捨てることにした。
時間にしておそらく1秒くらいじゃないかな。ということで、うまくいったっぽい。

正常なTSになったっぽい

ffmpeg

$ ffmpeg -i test.ts 
...略...
Input #0, mpegts, from 'test.ts':
  Duration: 00:00:09.15, start: 82202.683756, bitrate: 16324 kb/s
  Program xxxxx
    Metadata:
      name            : xxxxx
      provider_name   : 
    Stream #0.0[0x111]: Video: mpeg2video, yuv420p, 1440x1080 [PAR 4:3 DAR 16:9], 24000 kb/s, 30.34 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Stream #0.1[0x112]: Audio: aac, 48000 Hz, stereo, s16, 226 kb/s
    Stream #0.2[0x114]: Data: 0x0006
    Stream #0.3[0x810]: Data: 0x000d
    Stream #0.4[0x811]: Data: 0x000d
    Stream #0.5[0x81a]: Data: 0x000d
    Stream #0.6[0x81f]: Data: 0x000d
    Stream #0.7[0x816]: Data: 0x000d
    Stream #0.8[0x81b]: Data: 0x000d
  Program xxxxx
    Metadata:
      name            : xxxxx
      provider_name   : 
    Stream #0.0[0x111]: Video: mpeg2video, yuv420p, 1440x1080 [PAR 4:3 DAR 16:9], 24000 kb/s, 30.34 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Stream #0.1[0x112]: Audio: aac, 48000 Hz, stereo, s16, 226 kb/s
    Stream #0.2[0x114]: Data: 0x0006
    Stream #0.3[0x810]: Data: 0x000d
    Stream #0.4[0x811]: Data: 0x000d
    Stream #0.5[0x81a]: Data: 0x000d
    Stream #0.6[0x81f]: Data: 0x000d
    Stream #0.7[0x816]: Data: 0x000d
    Stream #0.8[0x81b]: Data: 0x000d
  Program xxxxx
    Metadata:
      name            : xxxxx
      provider_name   : 
    Stream #0.10[0x151]: Video: h264, yuv420p, 320x180, 8.83 fps, 14.99 tbr, 90k tbn, 14.99 tbc
    Stream #0.9[0x152]: Audio: aac, 48000 Hz, stereo, s16, 46 kb/s
    Stream #0.11[0x154]: Data: 0x0006
At least one output file must be specified

パッチ

recfsusb2n 0.9.2 に対するパッチです。無保証。


fsusb2n.cpp

@@ -183,10 +183,17 @@
 	usbDev->startStream();
 
 	// Main loop
+	int stream_counter = 0;
 	while (!caughtSignal && (args.forever || time(NULL) <= time_start + args.recsec)) {
 		usleep(750000);
 		const void *buf = NULL;
 		int rlen = usbDev->getStream(&buf);
+
+		stream_counter++;
+		if (stream_counter < 2) {
+			continue;
+		}
+
 		if (0 == rlen) continue;
 #ifdef B25
 			// B25を経由して受け取る