6092
|
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 }
|