HLSのつなぎ方

HLS(HTTP Live Streaming)で分割されたAACファイルはそのままcatしても正しいファイルにはなりません。

ためしにffmpegでつないでみます。

```
% ls -l
total 368
-rw-r--r--  1 hiroki  wheel   60377 Feb  9 06:42 1120.aac
-rw-r--r--  1 hiroki  wheel   60174 Feb  9 06:43 1121.aac
-rw-r--r--  1 hiroki  wheel   60704 Feb  9 06:43 1122.aac
-rw-r--r--  1 hiroki  wheel      42 Feb  9 06:55 list
% cat list
file 1120.aac
file 1121.aac
file 1122.aac
% ffmpeg -f concat -safe 0 -i list -c copy output.aac
% ls -l output.aac 
-rw-r--r--  1 hiroki  wheel  180796 Feb  9 07:11 output.aac
```

中身はこんな感じです。

```
% hd 1120.aac | head
00000000  49 44 33 04 00 00 00 00  00 3f 50 52 49 56 00 00  |ID3......?PRIV..|
00000010  00 35 00 00 63 6f 6d 2e  61 70 70 6c 65 2e 73 74  |.5..com.apple.st|
00000020  72 65 61 6d 69 6e 67 2e  74 72 61 6e 73 70 6f 72  |reaming.transpor|
00000030  74 53 74 72 65 61 6d 54  69 6d 65 73 74 61 6d 70  |tStreamTimestamp|
00000040  00 00 00 00 01 bc 2e ba  1f 49 44 33 04 00 00 00  |.........ID3....|
00000050  00 00 46 50 52 49 56 00  00 00 3c 00 00 63 6f 6d  |..FPRIV...<..com|
00000060  2e 65 6c 65 6d 65 6e 74  61 6c 74 65 63 68 6e 6f  |.elementaltechno|
00000070  6c 6f 67 69 65 73 2e 74  69 6d 65 73 74 61 6d 70  |logies.timestamp|
00000080  2e 75 74 63 00 32 30 32  33 2d 30 32 2d 30 38 54  |.utc.2023-02-08T|
00000090  30 36 3a 34 32 3a 34 37  5a ff f1 58 80 26 a1 c8  |06:42:47Z..X.&..|
% hd output.aac | head
00000000  ff f1 58 80 26 a1 c8 21  1a 94 ed aa 1d 63 a2 58  |..X.&..!.....c.X|
00000010  90 42 44 08 88 00 34 8d  ea a0 71 68 a4 01 74 6a  |.BD...4...qh..tj|
00000020  aa 2d 38 00 04 7f d2 2b  1e e4 03 2e 47 64 d8 8b  |.-8....+....Gd..|
00000030  c6 d2 73 c7 ed aa 01 90  8f 27 84 2c 7f 0c b9 38  |..s......'.,...8|
00000040  cd e4 78 6f 63 6b 3a ae  d5 2a 2a 46 61 47 0d 55  |..xock:..**FaG.U|
00000050  d6 05 95 44 92 48 44 95  17 6a 84 9d 36 db 5c cd  |...D.HD..j..6.\.|
00000060  96 1f cd 8f 74 8f 65 67  aa bb 91 73 a4 c7 b0 a7  |....t.eg...s....|
00000070  41 38 89 de 84 bc 43 89  a8 4d ef f4 8f 0c b8 f6  |A8....C..M......|
00000080  3c 4f d3 e5 70 5f be ce  b3 79 c5 6d 70 73 67 d8  |<O..p_...y.mpsg.|
00000090  e7 40 7a cd 4e 1f 38 d6  7c 6a f2 27 07 c6 f2 b7  |.@z.N.8.|j.'....|
```

ID3タグx2(0x99バイト)が消されてますね。上記の三つのファイルサイズから0x99バイト引いて足した値が、output.aacのサイズに合致します。output.aacは切れ目なくちゃんと再生できました。

mrubyで処理してみました。

```ruby
url = "https://radio-stream.nhk.jp/hls/live/2023546/nhkradiruikfm/master48k.m3u8"

h = HttpRequest.new()
index = h.get(url)

ri = url.rindex("/")

base = url[0, ri]

ar = Array.new

index.body.each_line {|line|
  if line[0] != "#"
    l = line.chomp
    if !ar.include?(l)
      ar << l
    end
  end
}

file = File.new('sample.aac', 'w')
ar.each{|var|
  a = h.get(base + "/" + var)
  t1 = a.body[9,1].ord
  t2 = a.body[t1+10+9,1].ord
  off = t1 + 10 + t2 + 10
  len = a.body.size - off
  file.write(a.body[off, len])
}
file.close
```
256バイト以下のID3タグが2つ入っていることを前提にした手抜きコードです。良い子はまねしないでね。

当初ffmpegのソースを参考にしようかと思ったのですが、この手の調査は実際動かして確認するのが手っ取り早いです。

ライブ配信のm3u8は随時更新されてリストにAACファイルが追加されますが、聞き逃しサービスのm3u8は完全な一覧が返ってくるので、上記のスクリプトで完全なAACファイルを作ることができます。

聞き逃しのm3u8のURLはFirefoxのpluginのVideo DownloadHelperなどで確認できるようです。

FreeBSD/mipsなRT3883で上記のスクリプト実行するとけっこう負荷高いです。はて、

```
# vmstat -c 100
procs  memory       page                    disks     faults         cpu
r b w  avm   fre   flt  re  pi  po    fr   sr fl0 md0   in    sy    cs us sy id
0 0 0  50M   38M    43   0   4   0    45    2   0   0  116   203   322  2 14 85
0 0 0  50M   38M     1   0   0   0     0    3   0   0   40    59   134  0  0 100
0 0 0  50M   38M     0   0   0   0     0    2   0   0   46    59   139  1  0 99
0 0 0  50M   38M     0   0   0   0     0    3   0   0   36    59   113  1  0 99
0 0 0  50M   38M     0   0   0   0     0    3   0   0   40    59   130  0  0 100
0 0 0  50M   38M     0   0   0   0     0    2   0   0   35    59   121  0  0 100
1 0 0  56M   38M   139   0   0   0    18    3   0   0   50   206   135  5  1 94
1 0 0  56M   37M   151   0   0   0     0    3   0   4  299   423   529 68  3 29
1 0 0  57M   37M   124   0   1   0     6    4   1   1  376   321   639 73  9 18
1 0 0  57M   36M   142   0   0   0     0    3   0   1  423   445   846 62 10 27
1 0 0  58M   35M    94   0   0   0     0    3   0   1  346   325   614 74  5 21
0 0 0  50M   38M   111   0   0   0   707    3   0   1  282   288   592 38  7 55
0 0 0  50M   38M     0   0   0   0     0    3   0   0   36    59   116  0  0 100
0 0 0  50M   38M     0   0   0   0     0    2   0   0   38    59   129  0  1 99
0 0 0  50M   38M     0   0   0   0     0    3   0   0   37    59   112  1  0 99A
0 0 0  50M   38M     0   0   0   0     0    3   0   0   35    59   108  0  0 100
```

聞き逃しのAACファイルはフォーマットが違うみたいです。

aacファイルはADTS形式とM4A形式があるようです。