2010-11-06 (土)
*[ニコニコ動画] 動画をjpegで取得する
iPhoneとかが使ってるインターフェイスにアクセスしてみる.
iPhone/iPod touchアプリ “ニコニコ動画” をパケット解析する(2)
iPhoneとか持ってないので,この記事がとても参考になりました.
最初はデータ生成するからちょっと待て(?)といわれるので,数秒置いて同じリクエストを送るとデータが帰ってくるようです.
間違ってるかもしれませんが,chat_get=0で情報を取得したあと,chat_get=1とかにして動画データを取得できるようです.
取得したデータを見たら,動画情報,コメント,音声,jpeg,jpeg,音声,jpeg,jpeg,音声…という風に格納されていました.データの先頭にサイズが入っているのでパースするのは簡単そう.
音声部分は,生のPCMではないようなので,ニコモバの資料にある通りADPCMでしょうか.ADPCMと一言で言ってもフォーマットがいくつかあるので困りますが.
詳細な説明を書きたいところですが,なんかダメな気もするので我慢.
サンプル
必要なモジュールは適当に入れてください.
#!/usr/local/bin/ruby -Ke # -*- coding: ascii-8bit -*- require "rubygems" require 'httpclient' require 'kconv' account = { 'mail'=>'hoge@exsample.com', 'password'=>'*******' } vid = 'sm9' client = HTTPClient.new res = client.post('https://secure.nicovideo.jp/secure/login?site=nicoiphone', account) if res.content !~ /status="ok"/i || res.content !~ /<ticket>([^<]+)<\// print "TICKET ERROR\n" exit end ticket = $1 print "ticket: #{ticket}\n" res = client.get_content('http://i.nicovideo.jp/v2/login?ticket='+ticket).toutf8 if res !~ /status="ok"/ || res !~ /<session_id>([^<]+)<\// print "LOGIN ERROR\n" exit end sid = $1 print "sid: #{sid}\n"; res = client.get_content("http://fence.i.nicovideo.jp/v2/videostatus?video_id=#{vid}").toutf8 print "status: #{res}\n" res = client.get_content('http://fence.i.nicovideo.jp/v2/gate?video_id='+vid+'&sid='+sid,nil,{'User-Agent' => 'iPad'}).force_encoding('ascii-8bit') if res !~ /tid\x00.([^\x00]+)\x00.*psvr\x00.([^\x00]+)/m print "GATE ERROR\n" exit end tid = $1 psvr = $2 time = 0 begin res = client.get_content("http://fence.i.nicovideo.jp/v2/play?transmission_speed=0&sound_quality=16&frame_rate=8&chat_get=1&video_id=#{vid}&sid=#{sid}&network=wifi&thread_id=#{tid}&date_time=#{time}&play_server=#{psvr}&initial=1").force_encoding('ascii-8bit') p a = res.unpack('a4NnnN') if a[0] == "DNOP" && a[2] == 2 print "wait...\n" sleep 1 elsif a[0] != "DWNG" print "header: #{a[0]}\n" exit end end while a[0] == "DNOP" && a[2] == 2 pos = 0x14 + a[5] frame = 0 while pos+6<res.length do block_info = res[pos,6].unpack('nN') p pos p block_info if block_info[0] == 0xCB foo = File.open("#{vid}_#{sprintf("%04d_%02d",time,frame)}.adpcm",'wb') foo.write res[pos+6,block_info[1]] foo.close end if block_info[0] == 0xC8 foo = File.open("#{vid}_#{sprintf("%04d_%02d",time,frame)}.jpg",'wb') foo.write res[pos+6,block_info[1]] foo.close frame+=1 end pos+= 6 + block_info[1] end