comparison stream/asf_mmst_streaming.c @ 19271:64d82a45a05d

introduce new 'stream' directory for all stream layer related components and split them from libmpdemux
author ben
date Mon, 31 Jul 2006 17:39:17 +0000
parents libmpdemux/asf_mmst_streaming.c@41aeb5e0cb4b
children ab8d6b6deb63
comparison
equal deleted inserted replaced
19270:7d39b911f0bd 19271:64d82a45a05d
1 // mmst implementation taken from the xine-mms plugin made by majormms (http://geocities.com/majormms/)
2 //
3 // ported to mplayer by Abhijeet Phatak <abhijeetphatak@yahoo.com>
4 // date : 16 April 2002
5 //
6 // information about the mms protocol can be find at http://get.to/sdp
7 //
8
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <inttypes.h>
16
17 #include "config.h"
18
19 #include "mp_msg.h"
20 #include "help_mp.h"
21
22 #ifndef HAVE_WINSOCK2
23 #define closesocket close
24 #else
25 #include <winsock2.h>
26 #endif
27
28 #ifndef USE_SETLOCALE
29 #undef USE_ICONV
30 #endif
31
32 #ifdef USE_ICONV
33 #include <iconv.h>
34 #ifdef USE_LANGINFO
35 #include <langinfo.h>
36 #endif
37 #endif
38
39 #include "url.h"
40 #include "asf.h"
41
42 #include "stream.h"
43
44 #include "network.h"
45
46 #define BUF_SIZE 102400
47 #define HDR_BUF_SIZE 8192
48 #define MAX_STREAMS 20
49
50 typedef struct
51 {
52 uint8_t buf[BUF_SIZE];
53 int num_bytes;
54
55 } command_t;
56
57 static int seq_num;
58 static int num_stream_ids;
59 static int stream_ids[MAX_STREAMS];
60
61 static int get_data (int s, char *buf, size_t count);
62
63 static void put_32 (command_t *cmd, uint32_t value)
64 {
65 cmd->buf[cmd->num_bytes ] = value % 256;
66 value = value >> 8;
67 cmd->buf[cmd->num_bytes+1] = value % 256 ;
68 value = value >> 8;
69 cmd->buf[cmd->num_bytes+2] = value % 256 ;
70 value = value >> 8;
71 cmd->buf[cmd->num_bytes+3] = value % 256 ;
72
73 cmd->num_bytes += 4;
74 }
75
76 static uint32_t get_32 (unsigned char *cmd, int offset)
77 {
78 uint32_t ret;
79
80 ret = cmd[offset] ;
81 ret |= cmd[offset+1]<<8 ;
82 ret |= cmd[offset+2]<<16 ;
83 ret |= cmd[offset+3]<<24 ;
84
85 return ret;
86 }
87
88 static void send_command (int s, int command, uint32_t switches,
89 uint32_t extra, int length,
90 char *data)
91 {
92 command_t cmd;
93 int len8;
94
95 len8 = (length + 7) / 8;
96
97 cmd.num_bytes = 0;
98
99 put_32 (&cmd, 0x00000001); /* start sequence */
100 put_32 (&cmd, 0xB00BFACE); /* #-)) */
101 put_32 (&cmd, len8*8 + 32);
102 put_32 (&cmd, 0x20534d4d); /* protocol type "MMS " */
103 put_32 (&cmd, len8 + 4);
104 put_32 (&cmd, seq_num);
105 seq_num++;
106 put_32 (&cmd, 0x0); /* unknown */
107 put_32 (&cmd, 0x0);
108 put_32 (&cmd, len8+2);
109 put_32 (&cmd, 0x00030000 | command); /* dir | command */
110 put_32 (&cmd, switches);
111 put_32 (&cmd, extra);
112
113 memcpy (&cmd.buf[48], data, length);
114 if (length & 7)
115 memset(&cmd.buf[48 + length], 0, 8 - (length & 7));
116
117 if (send (s, cmd.buf, len8*8+48, 0) != (len8*8+48)) {
118 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_WriteError);
119 }
120 }
121
122 #ifdef USE_ICONV
123 static iconv_t url_conv;
124 #endif
125
126 static void string_utf16(char *dest, char *src, int len) {
127 int i;
128 #ifdef USE_ICONV
129 size_t len1, len2;
130 char *ip, *op;
131
132 if (url_conv != (iconv_t)(-1))
133 {
134 memset(dest, 0, 1000);
135 len1 = len; len2 = 1000;
136 ip = src; op = dest;
137
138 iconv(url_conv, &ip, &len1, &op, &len2);
139 }
140 else
141 {
142 #endif
143 if (len > 499) len = 499;
144 for (i=0; i<len; i++) {
145 dest[i*2] = src[i];
146 dest[i*2+1] = 0;
147 }
148 /* trailing zeroes */
149 dest[i*2] = 0;
150 dest[i*2+1] = 0;
151 #ifdef USE_ICONV
152 }
153 #endif
154 }
155
156 static void get_answer (int s)
157 {
158 char data[BUF_SIZE];
159 int command = 0x1b;
160
161 while (command == 0x1b) {
162 int len;
163
164 len = recv (s, data, BUF_SIZE, 0) ;
165 if (!len) {
166 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_EOFAlert);
167 return;
168 }
169
170 command = get_32 (data, 36) & 0xFFFF;
171
172 if (command == 0x1b)
173 send_command (s, 0x1b, 0, 0, 0, data);
174 }
175 }
176
177 static int get_data (int s, char *buf, size_t count)
178 {
179 ssize_t len;
180 size_t total = 0;
181
182 while (total < count) {
183
184 len = recv (s, &buf[total], count-total, 0);
185
186 if (len<=0) {
187 perror ("read error:");
188 return 0;
189 }
190
191 total += len;
192
193 if (len != 0) {
194 // mp_msg(MSGT_NETWORK,MSGL_INFO,"[%d/%d]", total, count);
195 fflush (stdout);
196 }
197
198 }
199
200 return 1;
201
202 }
203
204 static int get_header (int s, uint8_t *header, streaming_ctrl_t *streaming_ctrl)
205 {
206 unsigned char pre_header[8];
207 int header_len;
208
209 header_len = 0;
210
211 while (1) {
212 if (!get_data (s, pre_header, 8)) {
213 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_PreHeaderReadFailed);
214 return 0;
215 }
216 if (pre_header[4] == 0x02) {
217
218 int packet_len;
219
220 packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
221
222 // mp_msg(MSGT_NETWORK,MSGL_INFO,"asf header packet detected, len=%d\n", packet_len);
223
224 if (packet_len < 0 || packet_len > HDR_BUF_SIZE - header_len) {
225 mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_MMST_InvalidHeaderSize);
226 return 0;
227 }
228
229 if (!get_data (s, &header[header_len], packet_len)) {
230 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_HeaderDataReadFailed);
231 return 0;
232 }
233
234 header_len += packet_len;
235
236 if ( (header[header_len-1] == 1) && (header[header_len-2]==1)) {
237
238
239 if( streaming_bufferize( streaming_ctrl, header, header_len )<0 ) {
240 return -1;
241 }
242
243 // mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet finished\n");
244
245 return (header_len);
246
247 }
248
249 } else {
250
251 int32_t packet_len;
252 int command;
253 char data[BUF_SIZE];
254
255 if (!get_data (s, (char*)&packet_len, 4)) {
256 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_packet_lenReadFailed);
257 return 0;
258 }
259
260 packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4;
261
262 // mp_msg(MSGT_NETWORK,MSGL_INFO,"command packet detected, len=%d\n", packet_len);
263
264 if (packet_len < 0 || packet_len > BUF_SIZE) {
265 mp_msg(MSGT_NETWORK, MSGL_FATAL,
266 MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize);
267 return 0;
268 }
269
270 if (!get_data (s, data, packet_len)) {
271 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_CmdDataReadFailed);
272 return 0;
273 }
274
275 command = get_32 (data, 24) & 0xFFFF;
276
277 // mp_msg(MSGT_NETWORK,MSGL_INFO,"command: %02x\n", command);
278
279 if (command == 0x1b)
280 send_command (s, 0x1b, 0, 0, 0, data);
281
282 }
283
284 // mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet succ\n");
285 }
286 }
287
288 static int interp_header (uint8_t *header, int header_len)
289 {
290 int i;
291 int packet_length=-1;
292
293 /*
294 * parse header
295 */
296
297 i = 30;
298 while (i<header_len) {
299
300 uint64_t guid_1, guid_2, length;
301
302 guid_2 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8)
303 | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
304 | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
305 | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
306 i += 8;
307
308 guid_1 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8)
309 | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
310 | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
311 | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
312 i += 8;
313
314 // mp_msg(MSGT_NETWORK,MSGL_INFO,"guid found: %016llx%016llx\n", guid_1, guid_2);
315
316 length = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8)
317 | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
318 | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
319 | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
320
321 i += 8;
322
323 if ( (guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22630ULL) ) {
324 mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_HeaderObject);
325 } else if ((guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22636ULL)) {
326 mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_DataObject);
327 } else if ((guid_1 == 0x6553200cc000e48eULL) && (guid_2 == 0x11cfa9478cabdca1ULL)) {
328
329 packet_length = get_32(header, i+92-24);
330
331 mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_FileObjectPacketLen,
332 packet_length, get_32(header, i+96-24));
333
334
335 } else if ((guid_1 == 0x6553200cc000e68eULL) && (guid_2 == 0x11cfa9b7b7dc0791ULL)) {
336
337 int stream_id = header[i+48] | header[i+49] << 8;
338
339 mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_StreamObjectStreamID, stream_id);
340
341 if (num_stream_ids < MAX_STREAMS) {
342 stream_ids[num_stream_ids] = stream_id;
343 num_stream_ids++;
344 } else {
345 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_2ManyStreamID);
346 }
347
348 } else {
349 #if 0
350 int b = i;
351 printf ("unknown object (guid: %016llx, %016llx, len: %lld)\n", guid_1, guid_2, length);
352 for (; b < length; b++)
353 {
354 if (isascii(header[b]) || isalpha(header[b]))
355 printf("%c ", header[b]);
356 else
357 printf("%x ", header[b]);
358 }
359 printf("\n");
360 #else
361 mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_MMST_UnknownObject);
362 #endif
363 }
364
365 // mp_msg(MSGT_NETWORK,MSGL_INFO,"length : %lld\n", length);
366
367 i += length-24;
368
369 }
370
371 return packet_length;
372
373 }
374
375
376 static int get_media_packet (int s, int padding, streaming_ctrl_t *stream_ctrl) {
377 unsigned char pre_header[8];
378 char data[BUF_SIZE];
379
380 if (!get_data (s, pre_header, 8)) {
381 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_PreHeaderReadFailed);
382 return 0;
383 }
384
385 // for (i=0; i<8; i++)
386 // mp_msg(MSGT_NETWORK,MSGL_INFO,"pre_header[%d] = %02x (%d)\n",
387 // i, pre_header[i], pre_header[i]);
388
389 if (pre_header[4] == 0x04) {
390
391 int packet_len;
392
393 packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
394
395 // mp_msg(MSGT_NETWORK,MSGL_INFO,"asf media packet detected, len=%d\n", packet_len);
396
397 if (packet_len < 0 || packet_len > BUF_SIZE) {
398 mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize);
399 return 0;
400 }
401
402 if (!get_data (s, data, packet_len)) {
403 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MediaDataReadFailed);
404 return 0;
405 }
406
407 streaming_bufferize(stream_ctrl, data, padding);
408
409 } else {
410
411 int32_t packet_len;
412 int command;
413
414 if (!get_data (s, (char*)&packet_len, 4)) {
415 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_packet_lenReadFailed);
416 return 0;
417 }
418
419 packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4;
420
421 if (packet_len < 0 || packet_len > BUF_SIZE) {
422 mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize);
423 return 0;
424 }
425
426 if (!get_data (s, data, packet_len)) {
427 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_CmdDataReadFailed);
428 return 0;
429 }
430
431 if ( (pre_header[7] != 0xb0) || (pre_header[6] != 0x0b)
432 || (pre_header[5] != 0xfa) || (pre_header[4] != 0xce) ) {
433
434 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MissingSignature);
435 return -1;
436 }
437
438 command = get_32 (data, 24) & 0xFFFF;
439
440 // mp_msg(MSGT_NETWORK,MSGL_INFO,"\ncommand packet detected, len=%d cmd=0x%X\n", packet_len, command);
441
442 if (command == 0x1b)
443 send_command (s, 0x1b, 0, 0, 0, data);
444 else if (command == 0x1e) {
445 mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_PatentedTechnologyJoke);
446 return 0;
447 }
448 else if (command == 0x21 ) {
449 // Looks like it's new in WMS9
450 // Unknown command, but ignoring it seems to work.
451 return 0;
452 }
453 else if (command != 0x05) {
454 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_UnknownCmd,command);
455 return -1;
456 }
457 }
458
459 // mp_msg(MSGT_NETWORK,MSGL_INFO,"get media packet succ\n");
460
461 return 1;
462 }
463
464
465 static int packet_length1;
466
467 static int asf_mmst_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl )
468 {
469 int len;
470
471 while( stream_ctrl->buffer_size==0 ) {
472 // buffer is empty - fill it!
473 int ret = get_media_packet( fd, packet_length1, stream_ctrl);
474 if( ret<0 ) {
475 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_GetMediaPacketErr,strerror(errno));
476 return -1;
477 } else if (ret==0) //EOF?
478 return ret;
479 }
480
481 len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos;
482 if(len>size) len=size;
483 memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len );
484 stream_ctrl->buffer_pos += len;
485 if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) {
486 free( stream_ctrl->buffer );
487 stream_ctrl->buffer = NULL;
488 stream_ctrl->buffer_size = 0;
489 stream_ctrl->buffer_pos = 0;
490 }
491 return len;
492
493 }
494
495 static int asf_mmst_streaming_seek( int fd, off_t pos, streaming_ctrl_t *streaming_ctrl )
496 {
497 return -1;
498 // Shut up gcc warning
499 fd++;
500 pos++;
501 streaming_ctrl=NULL;
502 }
503
504 int asf_mmst_streaming_start(stream_t *stream)
505 {
506 char str[1024];
507 char data[BUF_SIZE];
508 uint8_t asf_header[HDR_BUF_SIZE];
509 int asf_header_len;
510 int len, i, packet_length;
511 char *path, *unescpath;
512 URL_t *url1 = stream->streaming_ctrl->url;
513 int s = stream->fd;
514
515 if( s>0 ) {
516 closesocket( stream->fd );
517 stream->fd = -1;
518 }
519
520 /* parse url */
521 path = strchr(url1->file,'/') + 1;
522
523 /* mmst filename are not url_escaped by MS MediaPlayer and are expected as
524 * "plain text" by the server, so need to decode it here
525 */
526 unescpath=malloc(strlen(path)+1);
527 if (!unescpath) {
528 mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed);
529 return -1;
530 }
531 url_unescape_string(unescpath,path);
532 path=unescpath;
533
534
535 if( url1->port==0 ) {
536 url1->port=1755;
537 }
538 s = connect2Server( url1->hostname, url1->port, 1);
539 if( s<0 ) {
540 free(path);
541 return s;
542 }
543 mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_Connected);
544
545 seq_num=0;
546
547 /*
548 * Send the initial connect info including player version no. Client GUID (random) and the host address being connected to.
549 * This command is sent at the very start of protocol initiation. It sends local information to the serve
550 * cmd 1 0x01
551 * */
552
553 /* prepare for the url encoding conversion */
554 #ifdef USE_ICONV
555 #ifdef USE_LANGINFO
556 url_conv = iconv_open("UTF-16LE",nl_langinfo(CODESET));
557 #else
558 url_conv = iconv_open("UTF-16LE", NULL);
559 #endif
560 #endif
561
562 snprintf (str, 1023, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s", url1->hostname);
563 string_utf16 (data, str, strlen(str));
564 // send_command(s, commandno ....)
565 send_command (s, 1, 0, 0x0004000b, strlen(str)*2+2, data);
566
567 len = recv (s, data, BUF_SIZE, 0) ;
568
569 /*This sends details of the local machine IP address to a Funnel system at the server.
570 * Also, the TCP or UDP transport selection is sent.
571 *
572 * here 192.168.0.1 is local ip address TCP/UDP states the tronsport we r using
573 * and 1037 is the local TCP or UDP socket number
574 * cmd 2 0x02
575 * */
576
577 string_utf16 (&data[8], "\002\000\\\\192.168.0.1\\TCP\\1037", 24);
578 memset (data, 0, 8);
579 send_command (s, 2, 0, 0, 24*2+10, data);
580
581 len = recv (s, data, BUF_SIZE, 0) ;
582
583 /* This command sends file path (at server) and file name request to the server.
584 * 0x5 */
585
586 string_utf16 (&data[8], path, strlen(path));
587 memset (data, 0, 8);
588 send_command (s, 5, 0, 0, strlen(path)*2+10, data);
589 free(path);
590
591 get_answer (s);
592
593 /* The ASF header chunk request. Includes ?session' variable for pre header value.
594 * After this command is sent,
595 * the server replies with 0x11 command and then the header chunk with header data follows.
596 * 0x15 */
597
598 memset (data, 0, 40);
599 data[32] = 2;
600
601 send_command (s, 0x15, 1, 0, 40, data);
602
603 num_stream_ids = 0;
604 /* get_headers(s, asf_header); */
605
606 asf_header_len = get_header (s, asf_header, stream->streaming_ctrl);
607 // mp_msg(MSGT_NETWORK,MSGL_INFO,"---------------------------------- asf_header %d\n",asf_header);
608 if (asf_header_len==0) return -1; //error reading header
609 packet_length = interp_header (asf_header, asf_header_len);
610
611
612 /*
613 * This command is the media stream MBR selector. Switches are always 6 bytes in length.
614 * After all switch elements, data ends with bytes [00 00] 00 20 ac 40 [02].
615 * Where:
616 * [00 00] shows 0x61 0x00 (on the first 33 sent) or 0xff 0xff for ASF files, and with no ending data for WMV files.
617 * It is not yet understood what all this means.
618 * And the last [02] byte is probably the header ?session' value.
619 *
620 * 0x33 */
621
622 memset (data, 0, 40);
623
624 for (i=1; i<num_stream_ids; i++) {
625 data [ (i-1) * 6 + 2 ] = 0xFF;
626 data [ (i-1) * 6 + 3 ] = 0xFF;
627 data [ (i-1) * 6 + 4 ] = stream_ids[i];
628 data [ (i-1) * 6 + 5 ] = 0x00;
629 }
630
631 send_command (s, 0x33, num_stream_ids, 0xFFFF | stream_ids[0] << 16, (num_stream_ids-1)*6+2 , data);
632
633 get_answer (s);
634
635 /* Start sending file from packet xx.
636 * This command is also used for resume downloads or requesting a lost packet.
637 * Also used for seeking by sending a play point value which seeks to the media time point.
638 * Includes ?session' value in pre header and the maximum media stream time.
639 * 0x07 */
640
641 memset (data, 0, 40);
642
643 for (i=8; i<16; i++)
644 data[i] = 0xFF;
645
646 data[20] = 0x04;
647
648 send_command (s, 0x07, 1, 0xFFFF | stream_ids[0] << 16, 24, data);
649
650 stream->fd = s;
651 stream->streaming_ctrl->streaming_read = asf_mmst_streaming_read;
652 stream->streaming_ctrl->streaming_seek = asf_mmst_streaming_seek;
653 stream->streaming_ctrl->buffering = 1;
654 stream->streaming_ctrl->status = streaming_playing_e;
655
656 packet_length1 = packet_length;
657 mp_msg(MSGT_NETWORK,MSGL_INFO,"mmst packet_length = %d\n", packet_length);
658
659 #ifdef USE_ICONV
660 if (url_conv != (iconv_t)(-1))
661 iconv_close(url_conv);
662 #endif
663
664 return 0;
665 }