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