📄 mms.c
字号:
/* * return packet type */static int get_packet_header (mms_io_t *io, mms_t *this, mms_packet_header_t *header) { size_t len; int packet_type; header->packet_len = 0; header->packet_seq = 0; header->flags = 0; header->packet_id_type = 0; len = io_read(io, this->s, this->buf, 8); if (len != 8) goto error; if (LE_32(this->buf + 4) == 0xb00bface) { /* command packet */ header->flags = this->buf[3]; len = io_read(io, this->s, this->buf + 8, 4); if (len != 4) goto error; header->packet_len = LE_32(this->buf + 8) + 4; if (header->packet_len > BUF_SIZE - 12) { header->packet_len = 0; goto error; } lprintf("mms command\n"); packet_type = MMS_PACKET_COMMAND; } else { header->packet_seq = LE_32(this->buf); header->packet_id_type = this->buf[4]; header->flags = this->buf[5]; header->packet_len = (LE_16(this->buf + 6) - 8) & 0xffff; if (header->packet_id_type == ASF_HEADER_PACKET_ID_TYPE) { lprintf("asf header\n"); packet_type = MMS_PACKET_ASF_HEADER; } else { lprintf("asf packet\n"); packet_type = MMS_PACKET_ASF_PACKET; } } return packet_type; error: lprintf("read error, len=%d\n", len); perror("Could not read packet header"); return MMS_PACKET_ERR;}static int get_packet_command (mms_io_t *io, mms_t *this, uint32_t packet_len) { int command = 0; size_t len; /* always enter this loop */ lprintf("packet_len: %d bytes\n", packet_len); len = io_read(io, this->s, this->buf + 12, packet_len) ; if (len != packet_len) { return 0; } print_command (this->buf, len); /* check protocol type ("MMS ") */ if (LE_32(this->buf + 12) != 0x20534D4D) { lprintf("unknown protocol type: %c%c%c%c (0x%08X)\n", this->buf[12], this->buf[13], this->buf[14], this->buf[15], LE_32(this->buf + 12)); return 0; } command = LE_32 (this->buf + 36) & 0xFFFF; lprintf("command = 0x%2x\n", command); return command;}static int get_answer (mms_io_t *io, mms_t *this) { int command = 0; mms_packet_header_t header; switch (get_packet_header (io, this, &header)) { case MMS_PACKET_ERR: /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- " "libmms: failed to read mms packet header\n"); break; case MMS_PACKET_COMMAND: command = get_packet_command (io, this, header.packet_len); if (command == 0x1b) { if (!send_command (io, this, 0x1b, 0, 0, 0)) { /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- " "libmms: failed to send command\n"); return 0; } /* FIXME: limit recursion */ command = get_answer (io, this); } break; case MMS_PACKET_ASF_HEADER: /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- " "libmms: unexpected asf header packet\n"); break; case MMS_PACKET_ASF_PACKET: /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- ""libmms: unexpected asf packet\n"); break; } return command;}static int get_asf_header (mms_io_t *io, mms_t *this) { off_t len; int stop = 0; this->asf_header_read = 0; this->asf_header_len = 0; while (!stop) { mms_packet_header_t header; int command; switch (get_packet_header (io, this, &header)) { case MMS_PACKET_ERR: /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- " "libmms: failed to read mms packet header\n"); return 0; break; case MMS_PACKET_COMMAND: command = get_packet_command (io, this, header.packet_len); if (command == 0x1b) { if (!send_command (io, this, 0x1b, 0, 0, 0)) { /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- " "libmms: failed to send command\n"); return 0; } command = get_answer (io, this); } else { /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- " "libmms: unexpected command packet\n"); } break; case MMS_PACKET_ASF_HEADER: case MMS_PACKET_ASF_PACKET: if (header.packet_len + this->asf_header_len > ASF_HEADER_LEN) { lprintf( "***LOG:*** -- " "libmms: asf packet too large\n"); return 0; } len = io_read(io, this->s, this->asf_header + this->asf_header_len, header.packet_len); if (len != header.packet_len) { /* FIXME: de-xine-ification */ lprintf( "***LOG:*** -- " "libmms: get_asf_header failed\n"); return 0; } this->asf_header_len += header.packet_len; lprintf("header flags: %d\n", header.flags); if ((header.flags == 0X08) || (header.flags == 0X0C)) stop = 1; break; } } lprintf ("get header packet succ\n"); return 1;}static void interp_asf_header (mms_t *this) { int i; this->asf_packet_len = 0; this->num_stream_ids = 0; /* * parse header */ i = 30; while (i < this->asf_header_len) { int guid; uint64_t length; guid = get_guid(this->asf_header, i); i += 16; length = LE_64(this->asf_header + i); i += 8; switch (guid) { case GUID_ASF_FILE_PROPERTIES: this->asf_packet_len = LE_32(this->asf_header + i + 92 - 24); if (this->asf_packet_len > BUF_SIZE) { this->asf_packet_len = 0; lprintf( "***LOG:*** -- " "libmms: asf packet len too large\n"); break; } this->file_len = LE_64(this->asf_header + i + 40 - 24); lprintf ("file object, packet length = %d (%d)\n", this->asf_packet_len, LE_32(this->asf_header + i + 96 - 24)); break; case GUID_ASF_STREAM_PROPERTIES: { uint16_t flags; uint16_t stream_id; int type; int encrypted; guid = get_guid(this->asf_header, i); switch (guid) { case GUID_ASF_AUDIO_MEDIA: type = ASF_STREAM_TYPE_AUDIO; this->has_audio = 1; break; case GUID_ASF_VIDEO_MEDIA: case GUID_ASF_JFIF_MEDIA: case GUID_ASF_DEGRADABLE_JPEG_MEDIA: type = ASF_STREAM_TYPE_VIDEO; this->has_video = 1; break; case GUID_ASF_COMMAND_MEDIA: type = ASF_STREAM_TYPE_CONTROL; break; default: type = ASF_STREAM_TYPE_UNKNOWN; } flags = LE_16(this->asf_header + i + 48); stream_id = flags & 0x7F; encrypted = flags >> 15; lprintf ("stream object, stream id: %d, type: %d, encrypted: %d\n", stream_id, type, encrypted); if (this->num_stream_ids < ASF_MAX_NUM_STREAMS && stream_id < ASF_MAX_NUM_STREAMS) { this->stream_types[stream_id] = type; this->stream_ids[this->num_stream_ids] = stream_id; this->num_stream_ids++; } else { lprintf ("too many streams, skipping\n"); } } break; case GUID_ASF_STREAM_BITRATE_PROPERTIES: { uint16_t streams = LE_16(this->asf_header + i); uint16_t stream_id; int j; lprintf ("stream bitrate properties\n"); lprintf ("streams %d\n", streams); for(j = 0; j < streams; j++) { stream_id = LE_16(this->asf_header + i + 2 + j * 6); lprintf ("stream id %d\n", stream_id); this->bitrates[stream_id] = LE_32(this->asf_header + i + 4 + j * 6); this->bitrates_pos[stream_id] = i + 4 + j * 6; lprintf ("stream id %d, bitrate %d\n", stream_id, this->bitrates[stream_id]); } } break; default: lprintf ("unknown object\n"); break; } lprintf ("length : %lld\n", length); if (length > 24) { i += length - 24; } }}const static char *const mmst_proto_s[] = { "mms", "mmst", NULL };static int mmst_valid_proto (char *proto) { int i = 0; lprintf("mmst_valid_proto\n"); if (!proto) return 0; while(mmst_proto_s[i]) { if (!strcasecmp(proto, mmst_proto_s[i])) { return 1; } i++; } return 0;}/* FIXME: de-xine-ification *//* static void report_progress (void *data, int p) { xine_event_t event; xine_progress_data_t prg; prg.description = _("Connecting MMS server (over tcp)..."); prg.percent = p; event.type = XINE_EVENT_PROGRESS; event.data = &prg; event.data_length = sizeof (xine_progress_data_t); xine_event_send (stream, &event);} *//* * returns 1 on error */static int mms_tcp_connect(mms_io_t *io, mms_t *this) { int progress, res; if (!this->port) this->port = MMST_PORT; /* * try to connect */ lprintf("try to connect to %s on port %d \n", this->host, this->port); this->s = io_connect(io, this->host, this->port); if (this->s == -1) { /* FIXME: de-xine-ification */ lprintf ( "***LOG:*** -- " "failed to connect '%s'\n", this->host); return 1; } /* connection timeout 15s */ progress = 0; do { /*FIXME: de-xine-ification *//* report_progress(this->stream, progress); */ res = io_select(io, this->s, MMS_IO_WRITE_READY, 500); progress += 1; } while ((res == MMS_IO_STATUS_TIMEOUT) && (progress < 30)); if (res != MMS_IO_STATUS_READY) { return 1; } lprintf ("connected\n"); return 0;}static void mms_gen_guid(char guid[]) { static char digit[16] = "0123456789ABCDEF"; int i = 0; srand(time(NULL)); for (i = 0; i < 36; i++) { guid[i] = digit[(int) ((16.0*rand())/(RAND_MAX+1.0))]; } guid[8] = '-'; guid[13] = '-'; guid[18] = '-'; guid[23] = '-'; guid[36] = '\0';}/* * return 0 on error */int static mms_choose_best_streams(mms_io_t *io, mms_t *this) { int i; int video_stream = 0; int audio_stream = 0; int max_arate = 0; int min_vrate = 0; int min_bw_left = 0; int stream_id; int bandwitdh_left; int res; /* command 0x33 */ /* choose the best quality for the audio stream */ /* i've never seen more than one audio stream */ lprintf("num_stream_ids=%d\n", this->num_stream_ids); for (i = 0; i < this->num_stream_ids; i++) { stream_id = this->stream_ids[i]; switch (this->stream_types[stream_id]) { case ASF_STREAM_TYPE_AUDIO: if (this->bitrates[stream_id] > max_arate) { audio_stream = stream_id; max_arate = this->bitrates[stream_id]; } break; default: break; } } /* choose a video stream adapted to the user bandwidth */ bandwitdh_left = this->bandwidth - max_arate; if (bandwitdh_left < 0) { bandwitdh_left = 0; } lprintf("bandwitdh %d, left %d\n", this->bandwidth, bandwitdh_left); min_bw_left = bandwitdh_left; for (i = 0; i < this->num_stream_ids; i++) { stream_id = this->stream_ids[i]; switch (this->stream_types[stream_id]) { case ASF_STREAM_TYPE_VIDEO: if (((bandwitdh_left - this->bitrates[stream_id]) < min_bw_left) && (bandwitdh_left >= this->bitrates[stream_id])) { video_stream = stream_id; min_bw_left = bandwitdh_left - this->bitrates[stream_id]; } break; default: break; } } /* choose the lower bitrate of */ if (!video_stream && this->has_video) { for (i = 0; i < this->num_stream_ids; i++) { stream_id = this->stream_ids[i]; switch (this->stream_types[stream_id]) { case ASF_STREAM_TYPE_VIDEO: if ((this->bitrates[stream_id] < min_vrate) || (!min_vrate)) { video_stream = stream_id; min_vrate = this->bitrates[stream_id]; } break; default: break; } } } lprintf("selected streams: audio %d, video %d\n", audio_stream, video_stream); lprintf("disabling other streams\n"); memset (this->scmd_body, 0, 40); for (i = 1; i < this->num_stream_ids; i++) { this->scmd_body [ (i - 1) * 6 + 2 ] = 0xFF; this->scmd_body [ (i - 1) * 6 + 3 ] = 0xFF; this->scmd_body [ (i - 1) * 6 + 4 ] = this->stream_ids[i] ; this->scmd_body [ (i - 1) * 6 + 5 ] = this->stream_ids[i] >> 8; if ((this->stream_ids[i] == audio_stream) || (this->stream_ids[i] == video_stream)) { this->scmd_body [ (i - 1) * 6 + 6 ] = 0x00; this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00; } else { lprintf("disabling stream %d\n", this->stream_ids[i]); this->scmd_body [ (i - 1) * 6 + 6 ] = 0x02; this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00; /* forces the asf demuxer to not choose this stream */ if (this->bitrates_pos[this->stream_ids[i]]) { this->asf_header[this->bitrates_pos[this->stream_ids[i]]] = 0; this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 1] = 0; this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 2] = 0; this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 3] = 0; } } } if (!send_command (io, this, 0x33, this->num_stream_ids, 0xFFFF | this->stream_ids[0] << 16, this->num_stream_ids * 6 + 2)) { /* FIXME: de-xine-ification */ lprintf ( "***LOG:*** -- " "libmms: mms_choose_best_streams failed\n"); return 0; } if ((res = get_answer (io, this)) != 0x21) { /* FIXME: de-xine-ification */ lprintf ( "***LOG:*** -- " "libmms: unexpected response: %02x (0x21)\n", res); } return 1;}/* * TODO: error messages * network timing request *//* FIXME: got somewhat broken during xine_stream_t->(void*) conversion */mms_t *mms_connect (mms_io_t *io, void *data, const char *url, int bandwidth) {#ifdef USE_ICONV iconv_t url_conv;#else int url_conv = 0;#endif mms_t *this; int res;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -