Posts Tagged ‘m3u8’

Dienstag, 13. Dezember 2016

mitmproxy: Server-Antworten umschreiben (oder: M6 Geoblocker umgehen)

Heute durfte ich für einen Kollegen in den USA eine im Internet als Stream verfügbare M6 News-Sendung rippen.

Geoblocker

Damit ich an die m3u8-Datei des Streams herankam, musste ich aber zuerst die Geo-Sperre umgehen. Die Web-Site frägt nämlich beim Aufruf (gleich zweimal) ab, in welchem Land sich der Surfer befindet. Hierzu ruft der JavaScript-Code der Web-Site folgende zwei URLs auf:

Als Antwort erhält der Browser folgenden JSON-Code zurück (IP anonymisiert):

{"offset":"2","isp":"Andreas Fink","areas":[10],"country_code":"CH","asn":"AS6775","ip":"85.195.0.0"}

Diese Antwort bewegt den Player dazu, folgende Fehlermeldung anzuzeigen:

M6 6play Geoblock

mitmproxy installieren und konfigurieren

Der erste Task war somit klar: Ich musste mit dem quelloffenen Tool mitmproxy alle HTTP(S)-Requests meines iPads proxyifizieren und dann obige JSON-Antwort mit einer validen Antwort ersetzen, so wie sie über einen französischen ISP erfolgen würde.

mitmproxy hatte ich bereits auf meinem lokalen Linux-Server konfiguriert, weshalb ich auf dem iPad in den Netzwerkeinstellungen den Proxy nur noch erfassen musste: 10.0.X.Y:8888.

Auf dem Linux-Server startete ich mitmproxy folgendermassen:

# mitmproxy -p 8888

Als nächstes musste ich noch das mitmproxy-Zertifikat auf dem iPad installieren, damit HTTPS-Verbindungen entschlüsselt und umgeschrieben werden können. Hierzu reicht es, auf dem iPad die folgende URL aufzurufen …

mitm.it

… und den Anweisungen zu folgen (ACHTUNG: Sicherheitssensitive Personen löschen das Zertifikat nach der Verwendung wieder vom iPad. Es findet sich unter Settings > General > Profiles).

Inline-Script zum Umschreiben von Antworten

Damit ich vom Proxy-Server empfangene Antworten der M6-Server umschreiben konnte, musste ich nun noch ein mitmproxy Inline-Script einbauen, welches Aufrufe auf die oben genannten URLs abfängt und nach meinem Gusto umschreibt.

Hierzu legte ich unter /tmp/m6-geoip.py folgendes Python-Script ab:

import json

def response(context, flow):
	f = open('/tmp/mitm.log','a+')
	url = flow.request.get_url()
	f.write('URL "' + url  + '"' + "\n")

	if url.endswith('geoInfo') or url.endswith('geoInfos'):
		f.write('    matched' + "\n")
		data = json.loads(flow.response.content)
		# {"offset":"2","isp":"Andreas Fink","areas":[10],"country_code":"CH","asn":"AS6775","ip":"85.195.0.0"}
		# {"offset":"2","isp":"QSC AG","areas":[1,2,3,10,11],"country_code":"FR","asn":"AS20676","ip":"92.222.83.58"} via http://www.franceproxy.net
		#data["country_code"] = "FR"
		#jsonOut = json.dumps(data)
		jsonOut = '{"offset":"2","isp":"QSC AG","areas":[1,2,3,10,11],"country_code":"FR","asn":"AS20676","ip":"92.222.83.58"}'
		flow.response.content = jsonOut
		f.write("    " + jsonOut + "\n")
	f.close()

Tipp 1: Da selten Leute vom Himmel gefallen sind, welche ein Script auf Anhieb richtig hingekriegt haben, hilft es zum Debugging, statt mitmproxy mitmdump zu verwenden:

# mitmdump -e -p 8888 -s "/tmp/m6-geoip.py"

Bei Python-Problemen mit dem Inline-Script wird der Stack Trace und die Fehlermeldung direkt auf der Kommandozeile ausgegeben.

Tipp 2: Die Ausgabe aller URLs in eine Log-Datei resultiert in Performance-Einbussen, kann für das Debugging aber sehr nützlich sein.

Anschliessend startete ich den mitmproxy neu:

# mitmproxy -p 8888 -s "/tmp/m6-geoip.py"

JSON-Quelle

Doch von wo hatte ich den JSON-String?

Nach etwas Googeln fand ich folgenden Proxy-Service:

www.franceproxy.net

Gibt man dort eine der obigen URLs ein, erhält man als Antwort den JSON-Code, welchen ich dann auch für die Umgehung des Geoblockers verwendete.

Kostenloser Tipp an die Web-Entwickler von M6: Die Geo-Location eines Aufrufs prüft man nicht im JavaScript auf dem Client, sondern auf dem Server.

Der erneute Versuch im Web-Browser

Ich lud die Web-Seite auf dem iPad erneut — erhielt zwar eine Fehlermeldung, dass trotzdem irgendetwas schief gelaufen war, doch im mitmproxy-Log fand sich die sehnlichst gesuchte URL zur m3u8-Datei:

lb.cdn.m6web.fr

Daraus — und mit Informationen der aktuellsten Sendung, welche sich auch für Schweizer streamen lässt — leitete ich die tatsächliche URL zur Master-Playlist ab:

e112.cdn.m6web.fr

Von dieser Datei war es dann nur noch ein Katzensprung zur m3u8-Datei mit dem Stream mit der höchsten Bit-Rate:

e112.cdn.m6web.fr

Und so lud ich den Stream dann mit ffmpeg herunter:

$ ffmpeg -protocol_whitelist file,http,https,tcp,tls -i "http://e112.cdn.m6web.fr/usp/mb_sd3/2/8/1/Le-1945_c11636016_19-45-du-dimanche-11/Le-1945_c11636016_19-45-du-dimanche-11_unpnp.ism/Le-1945_c11636016_19-45-du-dimanche-11_unpnp-audio_fra=93468-video_eng=1501000.m3u8" video.mp4

Tags: , , , , , , , , ,
Labels: IT

Keine Kommentare | neuen Kommentar verfassen

Montag, 5. September 2016

SRF 3 Musiks „Best of Festivalsommer 2016“ herunterladen

SRF hat am 28. August die eineinhalbstündige Reportage „Best of Festivalsommer 2016“ ausgestrahlt. Wer von der Sendung ein Backup auf dem heimischen Computer anlegen möchte, gehe folgendermassen vor:

Mit dem Firefox mit aktivierten Network-Monitor (Tools > Web-Developer > Network) die folgende Seite ansurfen:

In der Liste vom Browser geladenenen Dateien die Datei mit master.m3u8 im Titel suchen. Hat man diese gefunden, klickt man mit der rechten Maustasten auf den Eintrag und wählt „Copy URL“.

In Terminal.app lädt man die Datei nun herunter und benennt sie um:

$ wget -O "master.m3u8" "http://srfvodhd-vh.akamaihd.net/i/vod/srf3musik/2016/08/srf3musik_20160828_200256_v_webcast_h264_,q40,q10,q20,q30,q50,q60,.mp4.csmil/master.m3u8?hdnts=exp%3D1473097915~acl%3D%2Fi%2Fvod%2F*~hmac%3D082b882b8cc09344ec0e52120adc1dd0b0d0ee0b668899c1d93cac56094f1aab"

Anschliessend startet man ffmpeg (bei mir v3.1.2):

$ ffmpeg -protocol_whitelist file,http,https,tcp,tls -i master.m3u8 -strict -2 video.mp4

Hinweis

Der Parameter -i schluckt übrigens anstandslos auch URLs:

$ ffmpeg -protocol_whitelist file,http,https,tcp,tls -i "http://cdn-vod-ios.br.de/i/b7/2016-07/24/0f8a34f451c211e68a90984be10adece_,0,A,B,E,C,X,.mp4.csmil/master.m3u8?__b__=200" -strict -2 video.mp4

Tags: , , , , , , , , ,
Labels: IT

1 Kommentar | neuen Kommentar verfassen

Sonntag, 14. Februar 2016

New York Times-Videos herunterladen

Heute wollte ich mir ein informatives Video der New York Times herunterladen, in welchem die Entdeckung von Gravitationswellen erläutert wird: Gravitational Waves Detected, Confirming Einstein’s Theory

Leider wird das Video gestreamt und kann nicht wie früher als komplettes MP4 heruntergeladen werden.

Mit Safaris Develop > Show Page Resources Menu war es mir dann aber rasch möglich, im Ordner „Other“ den Aufruf einer m3u8-Videoplaylist zu beobachten:

NYTimes m3u8

Bewaffnet mit dieser URL und der Unterstützung des geliebten ffmpeg konnte ich dann das Video streamen und im MP4-Format ablegen:

$ ffmpeg -i "http://vp.nyt.com/video/2016/02/13/38248_1_out-there-g-waves_wg_hls/master.m3u8" -strict -2 video.mp4
ffmpeg version 2.8.3 Copyright (c) 2000-2015 the FFmpeg developers
  built with Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
  configuration: --prefix=/opt/local --enable-swscale --enable-avfilter --enable-avresample --enable-libmp3lame --enable-libvorbis --enable-libopus --enable-libtheora --enable-libschroedinger --enable-libopenjpeg --enable-libmodplug --enable-libvpx --enable-libsoxr --enable-libspeex --enable-libass --enable-libbluray --enable-lzma --enable-gnutls --enable-fontconfig --enable-libfreetype --enable-libfribidi --disable-indev=jack --disable-outdev=xv --mandir=/opt/local/share/man --enable-shared --enable-pthreads --cc=/usr/bin/clang --enable-vda --enable-videotoolbox --arch=x86_64 --enable-yasm --enable-gpl --enable-postproc --enable-libx264 --enable-libxvid
  libavutil      54. 31.100 / 54. 31.100
  libavcodec     56. 60.100 / 56. 60.100
  libavformat    56. 40.101 / 56. 40.101
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 40.101 /  5. 40.101
  libavresample   2.  1.  0 /  2.  1.  0
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  2.101 /  1.  2.101
  libpostproc    53.  3.100 / 53.  3.100
[http @ 0x7fa8b1710060] No trailing CRLF found in HTTP header.
[http @ 0x7fa8b1710ba0] No trailing CRLF found in HTTP header.
[http @ 0x7fa8b153de80] No trailing CRLF found in HTTP header.
[http @ 0x7fa8b1536cc0] No trailing CRLF found in HTTP header.
[http @ 0x7fa8b2809660] No trailing CRLF found in HTTP header.
[http @ 0x7fa8b290fa60] No trailing CRLF found in HTTP header.
Input #0, hls,applehttp, from 'http://vp.nyt.com/video/2016/02/13/38248_1_out-there-g-waves_wg_hls/master.m3u8':
  Duration: 00:04:37.00, start: 10.000000, bitrate: 0 kb/s
  Program 0 
    Metadata:
      variant_bitrate : 3900747
    Stream #0:0: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p(tv, bt709/bt709/unknown), 1920x1080 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Metadata:
      variant_bitrate : 3900747
    Stream #0:1: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 51 kb/s
    Metadata:
      variant_bitrate : 3900747
  Program 1 
    Metadata:
      variant_bitrate : 426834
    Stream #0:2: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p, 426x240 [SAR 1:1 DAR 71:40], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Metadata:
      variant_bitrate : 426834
    Stream #0:3: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 51 kb/s
    Metadata:
      variant_bitrate : 426834
  Program 2 
    Metadata:
      variant_bitrate : 1039878
    Stream #0:4: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p, 640x360 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Metadata:
      variant_bitrate : 1039878
    Stream #0:5: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 51 kb/s
    Metadata:
      variant_bitrate : 1039878
  Program 3 
    Metadata:
      variant_bitrate : 1652921
    Stream #0:6: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p(tv, smpte170m/smpte170m/unknown), 854x480 [SAR 1:1 DAR 427:240], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Metadata:
      variant_bitrate : 1652921
    Stream #0:7: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 51 kb/s
    Metadata:
      variant_bitrate : 1652921
  Program 4 
    Metadata:
      variant_bitrate : 2674660
    Stream #0:8: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p(tv, bt709/bt709/unknown), 1280x720 [SAR 1:1 DAR 16:9], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
    Metadata:
      variant_bitrate : 2674660
    Stream #0:9: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 51 kb/s
    Metadata:
      variant_bitrate : 2674660
  Program 5 
    Metadata:
      variant_bitrate : 97776
    Stream #0:10: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 51 kb/s
    Metadata:
      variant_bitrate : 97776
[libx264 @ 0x7fa8b402d000] using SAR=1/1
[libx264 @ 0x7fa8b402d000] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264 @ 0x7fa8b402d000] profile High, level 4.0
[libx264 @ 0x7fa8b402d000] 264 - core 142 - H.264/MPEG-4 AVC codec - Copyleft 2003-2014 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'video.mp4':
  Metadata:
    encoder         : Lavf56.40.101
    Stream #0:0: Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], q=-1--1, 29.97 fps, 30k tbn, 29.97 tbc
    Metadata:
      variant_bitrate : 3900747
      encoder         : Lavc56.60.100 libx264
    Stream #0:1: Audio: aac ([64][0][0][0] / 0x0040), 44100 Hz, stereo, fltp, 128 kb/s
    Metadata:
      variant_bitrate : 3900747
      encoder         : Lavc56.60.100 aac
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
[http @ 0x7fa8b2b04620] No trailing CRLF found in HTTP header.rate=   0.2kbits/s dup=1 drop=0    
[hls,applehttp @ 0x7fa8b3000000] No longer receiving playlist 1
[hls,applehttp @ 0x7fa8b3000000] No longer receiving playlist 2
[hls,applehttp @ 0x7fa8b3000000] No longer receiving playlist 3
[hls,applehttp @ 0x7fa8b3000000] No longer receiving playlist 4
[hls,applehttp @ 0x7fa8b3000000] No longer receiving playlist 5
[http @ 0x7fa8b153dea0] No trailing CRLF found in HTTP header.trate= 129.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b1710a60] No trailing CRLF found in HTTP header.trate= 934.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a06800] No trailing CRLF found in HTTP header.trate=1266.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b290f640] No trailing CRLF found in HTTP header.trate=1687.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b1602500] No trailing CRLF found in HTTP header.trate=1430.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b1408e60] No trailing CRLF found in HTTP header.trate=1839.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b2949ac0] No trailing CRLF found in HTTP header.trate=2542.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b17134c0] No trailing CRLF found in HTTP header.trate=2730.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a03260] No trailing CRLF found in HTTP header.trate=2688.2kbits/s dup=1 drop=0    
[http @ 0x7fa8b1718b20] No trailing CRLF found in HTTP header.trate=2669.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b153a500] No trailing CRLF found in HTTP header.trate=2726.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b1533700] No trailing CRLF found in HTTP header.trate=3060.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b2948ac0] No trailing CRLF found in HTTP header.trate=3412.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b17143a0] No trailing CRLF found in HTTP header.trate=3669.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b1403ae0] No trailing CRLF found in HTTP header.trate=3883.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b03b00] No trailing CRLF found in HTTP header.trate=4061.9kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a022a0] No trailing CRLF found in HTTP header.trate=4163.1kbits/s dup=1 drop=0    
[http @ 0x7fa8b152e620] No trailing CRLF found in HTTP header.trate=4201.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b062c0] No trailing CRLF found in HTTP header.trate=4589.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b1401ee0] No trailing CRLF found in HTTP header.trate=4955.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b294dde0] No trailing CRLF found in HTTP header.trate=5290.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b290fa60] No trailing CRLF found in HTTP header.trate=5383.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b1534d80] No trailing CRLF found in HTTP header.trate=5476.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a03960] No trailing CRLF found in HTTP header.trate=5499.9kbits/s dup=1 drop=0    
[http @ 0x7fa8b1535ce0] No trailing CRLF found in HTTP header.trate=5433.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b074e0] No trailing CRLF found in HTTP header.trate=5348.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b294cda0] No trailing CRLF found in HTTP header.trate=5295.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b1713180] No trailing CRLF found in HTTP header.trate=5206.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b1403900] No trailing CRLF found in HTTP header.trate=5077.6kbits/s dup=1 drop=0    
[http @ 0x7fa8b1712340] No trailing CRLF found in HTTP header.trate=4959.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b1605f40] No trailing CRLF found in HTTP header.trate=4834.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b1536700] No trailing CRLF found in HTTP header.trate=4884.1kbits/s dup=1 drop=0    
[http @ 0x7fa8b1534300] No trailing CRLF found in HTTP header.trate=4905.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b1534320] No trailing CRLF found in HTTP header.trate=4854.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b294fb40] No trailing CRLF found in HTTP header.trate=4758.6kbits/s dup=1 drop=0    
[http @ 0x7fa8b1401a00] No trailing CRLF found in HTTP header.trate=4719.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b16048e0] No trailing CRLF found in HTTP header.trate=4656.1kbits/s dup=1 drop=0    
[http @ 0x7fa8b2803680] No trailing CRLF found in HTTP header.trate=4603.5kbits/s dup=1 drop=0    
[http @ 0x7fa8b1606b40] No trailing CRLF found in HTTP header.trate=4587.9kbits/s dup=1 drop=0    
[http @ 0x7fa8b1402a00] No trailing CRLF found in HTTP header.trate=4594.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a03c60] No trailing CRLF found in HTTP header.trate=4618.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b1403a20] No trailing CRLF found in HTTP header.trate=4624.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b294c9e0] No trailing CRLF found in HTTP header.trate=4669.2kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a03da0] No trailing CRLF found in HTTP header.trate=4708.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b1404820] No trailing CRLF found in HTTP header.trate=4697.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b1604620] No trailing CRLF found in HTTP header.trate=4695.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b153a0c0] No trailing CRLF found in HTTP header.trate=4719.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a032e0] No trailing CRLF found in HTTP header.trate=4712.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b28056a0] No trailing CRLF found in HTTP header.trate=4757.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b2805680] No trailing CRLF found in HTTP header.trate=4802.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a027a0] No trailing CRLF found in HTTP header.trate=4848.1kbits/s dup=1 drop=0    
[http @ 0x7fa8b28066c0] No trailing CRLF found in HTTP header.trate=4901.2kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a03680] No trailing CRLF found in HTTP header.trate=4898.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b294b8c0] No trailing CRLF found in HTTP header.trate=4900.6kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b0afe0] No trailing CRLF found in HTTP header.trate=4900.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b1602440] No trailing CRLF found in HTTP header.trate=4900.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a062e0] No trailing CRLF found in HTTP header.trate=4935.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b1717840] No trailing CRLF found in HTTP header.trate=4923.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b280c880] No trailing CRLF found in HTTP header.trate=4914.9kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a02340] No trailing CRLF found in HTTP header.trate=4849.2kbits/s dup=1 drop=0    
[http @ 0x7fa8b1602b00] No trailing CRLF found in HTTP header.trate=4797.2kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b10f20] No trailing CRLF found in HTTP header.trate=4750.1kbits/s dup=1 drop=0    
[http @ 0x7fa8b2808620] No trailing CRLF found in HTTP header.trate=4713.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b1404980] No trailing CRLF found in HTTP header.trate=4892.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b14044a0] No trailing CRLF found in HTTP header.trate=5097.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a04ea0] No trailing CRLF found in HTTP header.trate=5236.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b1536d40] No trailing CRLF found in HTTP header.trate=5251.2kbits/s dup=1 drop=0    
[http @ 0x7fa8b294ade0] No trailing CRLF found in HTTP header.trate=5216.1kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a01d80] No trailing CRLF found in HTTP header.trate=5159.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b15371e0] No trailing CRLF found in HTTP header.trate=5116.1kbits/s dup=1 drop=0    
[http @ 0x7fa8b2953fc0] No trailing CRLF found in HTTP header.trate=5068.9kbits/s dup=1 drop=0    
[http @ 0x7fa8b2954100] No trailing CRLF found in HTTP header.trate=5021.2kbits/s dup=1 drop=0    
[http @ 0x7fa8b2804b60] No trailing CRLF found in HTTP header.trate=4988.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b2948fc0] No trailing CRLF found in HTTP header.trate=4956.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b2805bc0] No trailing CRLF found in HTTP header.trate=4937.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b1567be0] No trailing CRLF found in HTTP header.trate=4907.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b16030e0] No trailing CRLF found in HTTP header.trate=4892.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b2950600] No trailing CRLF found in HTTP header.trate=4893.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b0e9c0] No trailing CRLF found in HTTP header.trate=4882.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b1405380] No trailing CRLF found in HTTP header.trate=4892.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b1712340] No trailing CRLF found in HTTP header.trate=4891.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a03180] No trailing CRLF found in HTTP header.trate=4888.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b171d040] No trailing CRLF found in HTTP header.trate=4883.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b1717520] No trailing CRLF found in HTTP header.trate=4867.7kbits/s dup=1 drop=0    
[http @ 0x7fa8b153de80] No trailing CRLF found in HTTP header.trate=4864.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b1402a40] No trailing CRLF found in HTTP header.trate=4849.4kbits/s dup=1 drop=0    
[http @ 0x7fa8b14026a0] No trailing CRLF found in HTTP header.trate=4878.3kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b09980] No trailing CRLF found in HTTP header.trate=4861.0kbits/s dup=1 drop=0    
[http @ 0x7fa8b1710980] No trailing CRLF found in HTTP header.trate=4841.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b2a024c0] No trailing CRLF found in HTTP header.trate=4829.8kbits/s dup=1 drop=0    
[http @ 0x7fa8b2b0d080] No trailing CRLF found in HTTP header.trate=4812.2kbits/s dup=1 drop=0    
frame= 8280 fps= 19 q=-1.0 Lsize=  161479kB time=00:04:36.20 bitrate=4789.2kbits/s dup=3 drop=0    
video:156761kB audio:4396kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.199356%
[libx264 @ 0x7fa8b402d000] frame I:124   Avg QP:19.52  size: 97053
[libx264 @ 0x7fa8b402d000] frame P:4102  Avg QP:22.58  size: 27562
[libx264 @ 0x7fa8b402d000] frame B:4054  Avg QP:24.78  size:  8739
[libx264 @ 0x7fa8b402d000] consecutive B-frames: 26.8% 20.0% 10.9% 42.3%
[libx264 @ 0x7fa8b402d000] mb I  I16..4: 14.0% 61.1% 24.9%
[libx264 @ 0x7fa8b402d000] mb P  I16..4:  2.8%  5.4%  1.2%  P16..4: 40.5%  9.3%  4.3%  0.0%  0.0%    skip:36.4%
[libx264 @ 0x7fa8b402d000] mb B  I16..4:  0.1%  0.2%  0.2%  B16..8: 41.5%  2.5%  0.4%  direct: 1.2%  skip:54.0%  L0:49.9% L1:48.4% BI: 1.8%
[libx264 @ 0x7fa8b402d000] 8x8 transform intra:57.5% inter:60.3%
[libx264 @ 0x7fa8b402d000] coded y,uvDC,uvAC intra: 47.1% 38.5% 6.2% inter: 12.1% 9.3% 0.2%
[libx264 @ 0x7fa8b402d000] i16 v,h,dc,p: 26% 31% 13% 30%
[libx264 @ 0x7fa8b402d000] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 23% 18% 33%  4%  5%  4%  5%  3%  5%
[libx264 @ 0x7fa8b402d000] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 18% 18% 25%  8%  8%  6%  8%  5%  6%
[libx264 @ 0x7fa8b402d000] i8c dc,h,v,p: 63% 21% 11%  4%
[libx264 @ 0x7fa8b402d000] Weighted P-Frames: Y:16.9% UV:11.9%
[libx264 @ 0x7fa8b402d000] ref P L0: 63.1% 15.1% 16.2%  5.3%  0.3%
[libx264 @ 0x7fa8b402d000] ref B L0: 86.4% 12.3%  1.4%
[libx264 @ 0x7fa8b402d000] ref B L1: 95.8%  4.2%
[libx264 @ 0x7fa8b402d000] kb/s:4648.19

Tags: , , , ,
Labels: Uncategorized

1 Kommentar | neuen Kommentar verfassen

Mittwoch, 5. März 2014

SRF Video-Streams im m3u8-Format lokal abspeichern

Auf meinem Synology NAS lagern hunderte Video-Clips und Sendungen, welche ich mir bei Gelegenheit mit AirVideo (iOS-Client mit OS X-Server) über meinen Mac mini über unseren Apple TV auf dem Panasonic-Plasma anschaue.

Die lokale Sicherung von Video-Clips klappt für YouTube und Vimeo vorzüglich (youtube-dl, welches ich im Zusammenspiel mit Remember the Milk kürzlich mit einem bash-Script automatisiert habe, welches den RSS-Feed der To Do-Liste nach YouTube- und Vimeo-URLs absucht und diese in einen _TOWATCH-Ordner auf dem NAS abspeichert), doch bei Streams von Fernsehsendern hat man seine liebe Mühe – manchmal nützen nicht einmal Jaksta, um den Stream über das Mitlesen des TCP/IP-Verkehrs mitzuschreiben, oder spezifisch für einen Sender geschriebene Tools wie Arte+7 videos are one click away ….

Das Schweizer Fernsehen ist so ein Sonderfall: Wenn ich es richtig verstehe, setzt der Sender eine Adobe-Lösung ein, um Streams entweder über einen Flash-Player an Mac- oder Windows-Clients oder als m3u8-Stream an Smartphones und Tablets auszuliefern.

Damit man an die URL für den m3u8-Stream kommt, muss man unter Mac OS X unter Firefox den User Agent temporär so anpassen, dass dem SRF-Server ein iPad vorgegaukelt wird. Ich verwende dazu die Extension User Agent Switcher 0.7.3, wobei ich anmerken muss, dass ich einfach die nächstbeste Erweiterung installiert habe, die mir vor die Flinte kam.

Ein möglicher User Agent, um ein iPad vorzutäuschen, lautet beispielsweise:

Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53

Quelle: User Agent Strings of iOS – Webapps Online

Hat man die URL zum m3u8-Stream im HTML-Quellcode ausfindig gemacht, lädt man die m3u8-Datei herunter und zeigt anschliessend ffmpeg (bei mir über MacPorts installiert) auf die Datei, um den Stream abzugreifen:

$ wget -O master.m3u8 "http://srfvodhd-vh.akamaihd.net/i/vod/dok/2014/01/dok_20140122_225809_v_webcast_h264_,q10,q20,q30,q40,.mp4.csmil/master.m3u8"
$ ffmpeg -i master.m3u8 -strict -2 video.mp4

Je nach Downloadgeschwindigkeit sollte man nach einigen Minuten eine MP4-Datei im aktuellen Verzeichnis liegen haben, welche sich dann problemlos auf den Apple TV streamen lässt.

Tags: , , , , , , , ,
Labels: IT

1 Kommentar | neuen Kommentar verfassen