📄 mmsh.c
字号:
/*********************************************************************** * mmsh.c: downloading via mmsh (Microsoft Media Service over HTTP) *********************************************************************** * Copyright (C) 2007 metro <me_t_ro@yahoo.com> * * This file is part of msdl, media stream downloader * * This file is based on mmsh implementation of mplayer, * and Windows Media Player transaction I saw through * packet monitoring program, wireshark (http://www.wireshark.org/) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * ***********************************************************************//* * Some code or data in this file is based on * MPlayer project * (MPlayer-1.0rc2/stream/stream/asf_streaming.c) */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include "msdl.h"#include "msdllib.h"#include "display.h"#include "network.h"#include "http.h"#include "asf.h"#include "mmsh.h"/* Windows Media Player stuff */const char mmsh_useragent[] = "User-Agent: NSPlayer/11.08.0005.0000";const char mmsh_xclientguid[] = "Pragma: xclientGuid={00000000-0000-0000-0000-000000000000}";const char mmsh_xacceptauth[] = "X-Accept-Authentication: Negotiate, NTLM, Digest, Basic";/* * definitions of type of ASF streaming */enum { ASF_Unknown_e, ASF_Seekable_e, ASF_Nonseekable_e, ASF_Authenticate_e,} ASF_streaming_types;/* * asf chunk magics */enum { ASF_STREAMING_CLEAR = 0x4324, /* $C */ ASF_STREAMING_DATA = 0x4424, /* $D */ ASF_STREAMING_END_TRANS = 0x4524, /* $E */ ASF_STREAMING_HEADER = 0x4824, /* $H */ ASF_STREAMING_IGNORE = 0x4d24, /* $M */ ASF_STREAMING_DATA2 = 0x44a4,};static struct mmsh_ctrl_t *new_mmsh_ctrl_t(void);static void free_mmsh_ctrl_t(struct mmsh_ctrl_t *ctrlt);static int mmsh_request_common(struct stream_t *stream, struct http_header_t *http_hdr);static struct http_header_t *mmsh_1st_request(struct stream_t *stream, struct http_header_t *http_hdr);static struct http_header_t *mmsh_media_request(struct stream_t *stream, struct http_header_t *http_hdr);static int mmsh_parse_response(struct mmsh_ctrl_t *mmsh_ctrl, struct http_header_t *http_hdr);static int asf_streaming(struct asf_stream_chunk_t *stream_chunk);static int mmsh_get_asf_header(struct stream_t *stream,uint8_t **asfheader, struct asf_stream_chunk_t *first_chunk);static int mmsh_get_media_packet(struct stream_t *stream, uint8_t *buffer, size_t max_size);/* * allocate/free mmsh_ctrl_t */static struct mmsh_ctrl_t *new_mmsh_ctrl_t(void){ struct mmsh_ctrl_t *ctrlt = (struct mmsh_ctrl_t *)xmalloc(sizeof(struct mmsh_ctrl_t)); ctrlt->hinfo = new_asf_headerinfo_t(); return ctrlt;}static void free_mmsh_ctrl_t(struct mmsh_ctrl_t *ctrlt){ if(!ctrlt) return; if(ctrlt->hinfo) free_asf_headerinfo_t(ctrlt->hinfo); free(ctrlt);}/* * set common part for mmsh request (for 1st and 2nd request) * return value: 1 ... success * -1 ... failure */static int mmsh_request_common(struct stream_t *stream, struct http_header_t *http_hdr){ struct stream_ctrl_t *stream_ctrl = stream->stream_ctrl; struct url_t *url = NULL; struct download_opts_t *dlopts = NULL; char str[BUFSIZE_1K]; /* Sanity Check */ if(stream_ctrl == NULL || http_hdr == NULL) { display(MSDL_ERR, "mmsh_request_common: argument invalid\n"); return -1; } url = stream->url; dlopts = stream->dlopts; if((url == NULL) || (dlopts == NULL)) { return -1; } http_set_field(http_hdr, "Accept: */*"); http_set_field(http_hdr, mmsh_useragent); http_add_basic_authentication(http_hdr, (url->username) ? url->username : stream->dlopts->username, (url->password) ? url->password : stream->dlopts->password); /* proxy check. use "http://" for proxy. */ if(dlopts->http_proxy) { char *new_url = xmalloc(7 + strlen(url->file) + 1); /* use "http://" because it is http proxy!! */ sprintf(new_url,"http://%s",url->file); http_set_uri(http_hdr,new_url); free(new_url); } else { http_set_uri(http_hdr,url->filepath); } snprintf(str,BUFSIZE_1K,"Host: %.220s",url->hostname); /* %.220s:%d,port*/ http_set_field(http_hdr,str); http_set_field(http_hdr,mmsh_xclientguid); return 1;}/* very first mmsh request */static struct http_header_t *mmsh_1st_request(struct stream_t *stream, struct http_header_t *http_hdr){ char str[BUFSIZE_1K]; if(mmsh_request_common(stream,http_hdr) < 0) { display(MSDL_ERR, "mmsh_request_common fialed\n"); return NULL; } snprintf(str,BUFSIZE_1K, "Pragma: no-cache,rate=1.000,stream-time=0,stream-offset=%u:%u,packet-num=%u,max-duration=%u", 0xffffffff,0xffffffff,0,0); /* for some reason this is required */ http_set_field(http_hdr,str); http_set_field(http_hdr,"Connection: Close"); http_request_get(http_hdr); return http_hdr;}/* * mmsh_request : make request to the server */static struct http_header_t *mmsh_media_request(struct stream_t *stream, struct http_header_t *http_hdr){ struct stream_ctrl_t *stream_ctrl = stream->stream_ctrl; struct mmsh_ctrl_t *mmsh_ctrl = stream_ctrl->mmsh_ctrl; char *ptr = NULL; int asf_streams_count = 0; char str[BUFSIZE_1K]; if(mmsh_request_common(stream,http_hdr) < 0) { display(MSDL_ERR, "mmsh_request_common fialed\n"); return NULL; } snprintf(str,BUFSIZE_1K, "Pragma: no-cache,rate=1.000,stream-time=%d,stream-offset=%u:%u,packet-num=%u,max-duration=%u", /*offset_lo,offset_hi,stream_ctrl->packet_count,0);*/ 0, /* start time in milliseconds */ 0xffffffff,0xffffffff,0xffffffff, 0); /* for some reason this is required */ http_set_field(http_hdr,str); /* MMSH part */ http_set_field(http_hdr,"Pragma: xPlayStrm=1"); http_set_field(http_hdr,"Pragma: version11-enabled=1"); ptr = str; ptr += sprintf(ptr,"Pragma: stream-switch-entry="); if(mmsh_ctrl->hinfo->streams->n_audio > 0) { int enable = 0; int stream_id = 0; int i = 0; /*printf("mmsh_ctrl->n_audio : %d\n",mmsh_ctrl->n_audio); */ for(i = 0; i < mmsh_ctrl->hinfo->streams->n_audio; i++) { stream_id = mmsh_ctrl->hinfo->streams->audio_streams[i]; /*printf("stream_id = %d %d\n",stream_id,mmsh_ctrl->audio_id); */ if(stream_id == mmsh_ctrl->hinfo->streams->audio_id) { enable = 0; /* enable stream */ } else { enable = 2; /* disable stream */ } asf_streams_count++; ptr += sprintf(ptr,"ffff:%d:%d ",stream_id,enable); } } if(mmsh_ctrl->hinfo->streams->n_video > 0) { int enable = 0; int stream_id = 0; int i = 0; for(i = 0; i < mmsh_ctrl->hinfo->streams->n_video; i++) { stream_id = mmsh_ctrl->hinfo->streams->video_streams[i]; if(stream_id == mmsh_ctrl->hinfo->streams->video_id) { enable = 0; /* enable stream */ } else { enable = 2; /* disable stream */ } asf_streams_count++; ptr += sprintf(ptr,"ffff:%d:%d ",stream_id,enable); } } http_set_field(http_hdr,str); snprintf(str,BUFSIZE_1K,"Pragma: stream-switch-count=%d",asf_streams_count); http_set_field(http_hdr,str); if(stream->dlopts->speed) { char *reason = NULL; int guessed_speed = 0; if(speed_valid_and_guess(stream->dlopts->speed,&guessed_speed,&reason)) { snprintf(str,BUFSIZE_1K - 1,"Pragma: Speed=%s",stream->dlopts->speed); } else { /* invlalid, use guessed value */ if(guessed_speed == 0) { guessed_speed = 1; /* default speed 1.000 */ } snprintf(str,BUFSIZE_1K - 1,"Pragma: Speed=%d.000",guessed_speed); display(MSDL_ERR, "option \"-s %s\" is invalid as mmsh speed request\n" ": %s\n" "send \"%s\" instead\n", stream->dlopts->speed,reason,str); } http_set_field(http_hdr,str); } http_set_field(http_hdr,"Connection: Close"); http_request_get(http_hdr); return http_hdr;}/* * asf_header_check : check if http_hdr->body is ASF object. * return value : 0 ... it was NOT asf object * 1 ... OK it was ASF object! */int asf_header_check(struct http_header_t *http_hdr){ struct asf_obj_header_t *asfobjh; if(!http_hdr) return 0; if(http_hdr->body == NULL || http_hdr->body_len < sizeof(struct asf_obj_header_t)) return 0; asfobjh = (struct asf_obj_header_t *)http_hdr->body; /* get GUID first 4 byte for check */ if(get32_le(asfobjh->guid) == 0x75b22630) return 1; return 0;}/* * returns content_type value. * this function is based on MPlayer /MPlayer/stream/asf_streaming.c */int mmsh_streaming_type(char *content_type,char *features, struct http_header_t *http_hdr){ if(content_type == NULL) return ASF_Unknown_e; if(!strcasecmp(content_type, "application/octet-stream") || !strcasecmp(content_type, "application/vnd.ms.wms-hdr.asfv1") || !strcasecmp(content_type, "application/x-mms-framed") || !strcasecmp(content_type, "video/x-ms-asf")) { if(strstr(features, "seekable") ) { display(MSDL_VER,"seekable ASF stream\n"); return ASF_Seekable_e; } else { display(MSDL_VER,"non-seekable ASF stream\n"); return ASF_Nonseekable_e; } } else { display(MSDL_VER,"content type: %s\n",content_type); return ASF_Unknown_e; }}/* * receive mmsh message from stream->sock. * use http_recv_header first. * return status code : success * -1 : failure */int mmsh_recv_header(struct stream_t *stream,struct http_header_t *http_hdr){ int ret = 0; ret = http_recv_header_get(stream,http_hdr); if(ret < 0) { display(MSDL_ERR,"MMSH header parse error by http header parse error\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -