comparison libmpdemux/asf_mmst_streaming.c @ 6092:1529f01e8108

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