📄 mmsh.c
字号:
lprintf("seekable stream\n"); this->stream_type = MMSH_SEEKABLE; } else { if (strstr(features, "broadcast")) { lprintf("live stream\n"); this->stream_type = MMSH_LIVE; } } } } } if (len == -1) { done = 1; } else { len = 0; } } else { len ++; } } if (this->stream_type == MMSH_UNKNOWN) { lprintf ("mmsh: unknown stream type\n"); this->stream_type = MMSH_SEEKABLE; /* FIXME ? */ } return 1;}static int get_chunk_header (mms_io_t *io, mmsh_t *this) { uint8_t chunk_header[CHUNK_HEADER_LENGTH]; uint8_t ext_header[EXT_HEADER_LENGTH]; int read_len; int ext_header_len; lprintf ("get_chunk_header\n"); /* read chunk header */ read_len = io_read(io, this->s, chunk_header, CHUNK_HEADER_LENGTH); if (read_len != CHUNK_HEADER_LENGTH) { lprintf ("chunk header read failed, %d != %d\n", len, CHUNK_HEADER_LENGTH); return 0; } this->chunk_type = LE_16 (&chunk_header[0]); this->chunk_length = LE_16 (&chunk_header[2]); switch (this->chunk_type) { case CHUNK_TYPE_DATA: ext_header_len = 8; break; case CHUNK_TYPE_END: ext_header_len = 4; break; case CHUNK_TYPE_ASF_HEADER: ext_header_len = 8; break; case CHUNK_TYPE_RESET: ext_header_len = 4; break; default: ext_header_len = 0; } /* read extended header */ if (ext_header_len > 0) { read_len = io_read (io, this->s, ext_header, ext_header_len); if (read_len != ext_header_len) { lprintf ("extended header read failed. %d != %d\n", read_len, ext_header_len); return 0; } } /* display debug infos */#ifdef DEBUG switch (this->chunk_type) { case CHUNK_TYPE_DATA: this->chunk_seq_number = LE_32 (&ext_header[0]); lprintf ("chunk type: CHUNK_TYPE_DATA\n"); lprintf ("chunk length: %d\n", this->chunk_length); lprintf ("chunk seq: %d\n", this->chunk_seq_number); lprintf ("unknown: %d\n", ext_header[4]); lprintf ("mmsh seq: %d\n", ext_header[5]); lprintf ("len2: %d\n", LE_16(&ext_header[6])); break; case CHUNK_TYPE_END: this->chunk_seq_number = LE_32 (&ext_header[0]); lprintf ("chunk type: CHUNK_TYPE_END\n"); lprintf ("continue: %d\n", this->chunk_seq_number); break; case CHUNK_TYPE_ASF_HEADER: lprintf ("chunk type: CHUNK_TYPE_ASF_HEADER\n"); lprintf ("chunk length: %d\n", this->chunk_length); lprintf ("unknown: %2X %2X %2X %2X %2X %2X\n", ext_header[0], ext_header[1], ext_header[2], ext_header[3], ext_header[4], ext_header[5]); lprintf ("len2: %d\n", LE_16(&ext_header[6])); break; case CHUNK_TYPE_RESET: lprintf ("chunk type: CHUNK_TYPE_RESET\n"); lprintf ("chunk seq: %d\n", this->chunk_seq_number); lprintf ("unknown: %2X %2X %2X %2X\n", ext_header[0], ext_header[1], ext_header[2], ext_header[3]); break; default: lprintf ("unknown chunk: %4X\n", this->chunk_type); }#endif this->chunk_length -= ext_header_len; return 1;}static int get_header (mms_io_t *io, mmsh_t *this) { int len = 0; lprintf("get_header\n"); this->asf_header_len = 0; this->asf_header_read = 0; /* read chunk */ while (1) { if (get_chunk_header(io, this)) { if (this->chunk_type == CHUNK_TYPE_ASF_HEADER) { if ((this->asf_header_len + this->chunk_length) > ASF_HEADER_SIZE) { lprintf ("mmsh: the asf header exceed %d bytes\n", ASF_HEADER_SIZE); return 0; } else { len = io_read(io, this->s, this->asf_header + this->asf_header_len, this->chunk_length); this->asf_header_len += len; if (len != this->chunk_length) { return 0; } } } else { break; } } else { lprintf("get_chunk_header failed\n"); return 0; } } if (this->chunk_type == CHUNK_TYPE_DATA) { /* read the first data chunk */ len = io_read (io, this->s, this->buf, this->chunk_length); if (len != this->chunk_length) { return 0; } else { return 1; } } else { /* unexpected packet type */ return 0; }}static void interp_header (mms_io_t *io, mmsh_t *this) { int i; lprintf ("interp_header, header_len=%d\n", this->asf_header_len); this->packet_length = 0; /* * parse asf header */ i = 30; while ((i + 24) < 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; if ((i + length) >= this->asf_header_len) return; switch (guid) { case GUID_ASF_FILE_PROPERTIES: this->packet_length = LE_32(this->asf_header + i + 92 - 24); if (this->packet_length > CHUNK_SIZE) { this->packet_length = 0; break; } this->file_length = LE_64(this->asf_header + i + 40 - 24); lprintf ("file object, packet length = %d (%d)\n", this->packet_length, 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); this->stream_types[stream_id] = type; this->stream_ids[this->num_stream_ids] = stream_id; this->num_stream_ids++; } 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 ("mmsh: 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 mmsh_proto_s[] = { "mms", "mmsh", NULL };static int mmsh_valid_proto (char *proto) { int i = 0; lprintf("mmsh_valid_proto\n"); if (!proto) return 0; while(mmsh_proto_s[i]) { if (!strcasecmp(proto, mmsh_proto_s[i])) { return 1; } i++; } return 0;}/* * returns 1 on error */static int mmsh_tcp_connect(mms_io_t *io, mmsh_t *this) { int progress, res; if (!this->connect_port) this->connect_port = MMSH_PORT; /* * try to connect */ lprintf("try to connect to %s on port %d \n", this->connect_host, this->connect_port); this->s = io_connect (io, this->connect_host, this->connect_port); if (this->s == -1) { lprintf ("mmsh: failed to connect '%s'\n", this->connect_host); return 1; } /* connection timeout 15s */ progress = 0; do {// 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 int mmsh_connect_int (mms_io_t *io, mmsh_t *this, int bandwidth) { int i; int video_stream = -1; int audio_stream = -1; int max_arate = -1; int min_vrate = -1; int min_bw_left = 0; int stream_id; int bandwitdh_left; char stream_selection[10 * ASF_MAX_NUM_STREAMS]; /* 10 chars per stream */ int offset; /* * let the negotiations begin... */ this->num_stream_ids = 0; /* first request */ lprintf("first http request\n"); snprintf (this->str, SCRATCH_SIZE, mmsh_FirstRequest, this->uri, this->http_host, this->http_port, 1); if (!send_command (io, this, this->str)) goto fail; if (!get_answer (io, this)) goto fail; get_header(io, this); interp_header(io, this); close(this->s);// report_progress (stream, 20); /* choose the best quality for the audio stream */ /* i've never seen more than one audio stream */ 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 ((audio_stream == -1) || (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 = bandwidth - max_arate; if (bandwitdh_left < 0) { bandwitdh_left = 0; } lprintf("bandwitdh %d, left %d\n", 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 stream with the lower bitrate */ if ((video_stream == -1) && 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 ((video_stream == -1) || (this->bitrates[stream_id] < min_vrate) || (!min_vrate)) { video_stream = stream_id; min_vrate = this->bitrates[stream_id]; } break; default: break; } } } lprintf("audio stream %d, video stream %d\n", audio_stream, video_stream); /* second request */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -