pen2 の日記

Twitterには長くて書けないことを書きます^^

MPlayer でHTTP 302エラーを限界までハンドリングする

MPlayer という非常に便利なストリーミング再生ソフトがあります。Windows では WMP とかあるのでいいのですが、Linux 環境では この MPlayer や VideoLAN(VLC) などが選択肢となります。

MPlayer でストリーミングを再生しようとしたとき、再生先のリソースが HTTP 302 や 303 で移動している事はよくあります。それはいいんですが、「ストリーミング情報が記録されたメタファイルの中のURLにアクセスすると HTTP 302」というすごい運用をしている放送局があったりします*1。この場合、MPlayer で再生しようとすると無条件でエラーになってしまいます。

こんな感じです。

Connecting to server SERVER_NAME[SERVER_IP]: SERVER_PORT...
Server returned 302:Found
Failed to parse header.
Failed, exiting.

それでは困るので、少なくとも移動先をハンドリングできるように、Location ヘッダを読み込んで標準出力に書き出すように改造してみます。

diff -c mplayer-checkout-2009-12-12/stream/asf_streaming.c mplayer-moved_ver/stream/asf_streaming.c
*** mplayer-checkout-2009-12-12/stream/asf_streaming.c  2009-12-12 14:15:03.000000000 +0900
--- mplayer-moved_ver/stream/asf_streaming.c    2009-12-13 14:32:54.000000000 +0900
***************
*** 622,627 ****
--- 622,628 ----
  
  static int asf_http_parse_response(asf_http_streaming_ctrl_t *asf_http_ctrl, HTTP_header_t *http_hdr ) {
        char *content_type, *pragma;
+       char *next_url; // added by @pen2
        char features[64] = "\0";
        size_t len;
        if( http_response_parse(http_hdr)<0 ) {
***************
*** 631,636 ****
--- 632,643 ----
        switch( http_hdr->status_code ) {
                case 200:
                        break;
+               case 302: // Moved, added by @pen2
+                       next_url = http_get_field( http_hdr, "Location" );
+                       if (next_url != NULL) {
+                               printf("Moved: Using this url instead %s\n",next_url);
+                       }
+                       return -1;
                case 401: // Authentication required
                        return ASF_Authenticate_e;
                default:

これによって、

Connecting to server SERVER_NAME[SERVER_IP]: SERVER_PORT...
Moved: Using this url instead http://{RESOURCE_URI}
Failed to parse header.
Failed, exiting.

と言う形で移転先が返ってくるので、これをハンドリングして再度読み込めば上手くいきます。

本当は MPlayer 内で再帰的に読み込みを行えればベストなんですが、リソースURLを読み込む部分は "stream/asf_streaming.c" であり、ストリーム再生部分のかなり深い部分で、ここで再度メタファイルを読み込み治すようにするには、この辺の部分のコードを全面的に書き直す必要があるので、断念しました。

*1:ちなみに、WindowsMedia形式のネットラジオなどの場合、メタファイルは wma などの形式になっていて、ここに本来のリソースを指定できます。なので、本来のリソースの位置が変更になったら、ここを書き換えればいいはずですが… なんででしょうね?