]> git.sesse.net Git - ffmpeg/blob - libavformat/mmst.c
Use correct length modifier for size comparison in printf expression, fixes:
[ffmpeg] / libavformat / mmst.c
1 /*
2  * MMS protocol over TCP
3  * Copyright (c) 2006,2007 Ryan Martell
4  * Copyright (c) 2007 Björn Axelsson
5  * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 #include "avformat.h"
24 #include "internal.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavcodec/bytestream.h"
27 #include "network.h"
28 #include "asf.h"
29
30 #define LOCAL_ADDRESS 0xc0a80081    // FIXME get and use correct local ip address.
31 #define LOCAL_PORT    1037          // as above.
32 /** Client to server packet types. */
33 typedef enum {
34     CS_PKT_INITIAL                  = 0x01,
35     CS_PKT_PROTOCOL_SELECT          = 0x02,
36     CS_PKT_MEDIA_FILE_REQUEST       = 0x05,
37     CS_PKT_START_FROM_PKT_ID        = 0x07,
38     CS_PKT_STREAM_PAUSE             = 0x09,
39     CS_PKT_STREAM_CLOSE             = 0x0d,
40     CS_PKT_MEDIA_HEADER_REQUEST     = 0x15,
41     CS_PKT_TIMING_DATA_REQUEST      = 0x18,
42     CS_PKT_USER_PASSWORD            = 0x1a,
43     CS_PKT_KEEPALIVE                = 0x1b,
44     CS_PKT_STREAM_ID_REQUEST        = 0x33,
45 } MMSCSPacketType;
46
47 /** Server to client packet types. */
48 typedef enum {
49     /** Control packets. */
50     /*@{*/
51     SC_PKT_CLIENT_ACCEPTED          = 0x01,
52     SC_PKT_PROTOCOL_ACCEPTED        = 0x02,
53     SC_PKT_PROTOCOL_FAILED          = 0x03,
54     SC_PKT_MEDIA_PKT_FOLLOWS        = 0x05,
55     SC_PKT_MEDIA_FILE_DETAILS       = 0x06,
56     SC_PKT_HEADER_REQUEST_ACCEPTED  = 0x11,
57     SC_PKT_TIMING_TEST_REPLY        = 0x15,
58     SC_PKT_PASSWORD_REQUIRED        = 0x1a,
59     SC_PKT_KEEPALIVE                = 0x1b,
60     SC_PKT_STREAM_STOPPED           = 0x1e,
61     SC_PKT_STREAM_CHANGING          = 0x20,
62     SC_PKT_STREAM_ID_ACCEPTED       = 0x21,
63     /*@}*/
64
65     /** Pseudo packets. */
66     /*@{*/
67     SC_PKT_CANCEL                   = -1,
68     SC_PKT_NO_DATA                  = -2,
69     /*@}*/
70
71     /** Data packets. */
72     /*@{*/
73     SC_PKT_ASF_HEADER               = 0x010000,// make it bigger than 0xFF in case of
74     SC_PKT_ASF_MEDIA                = 0x010001,// receiving false data packets.
75     /*@}*/
76 } MMSSCPacketType;
77
78 typedef struct {
79     int id;
80 }MMSStream;
81
82 typedef struct {
83     int outgoing_packet_seq;             ///< Outgoing packet sequence number.
84     char path[256];                      ///< Path of the resource being asked for.
85     char host[128];                      ///< Host of the resources.
86
87     URLContext *mms_hd;                  ///< TCP connection handle
88     MMSStream streams[MAX_STREAMS];
89
90     /** Buffer for outgoing packets. */
91     /*@{*/
92     uint8_t *write_out_ptr;              ///< Pointer for writting the buffer.
93     uint8_t out_buffer[512];             ///< Buffer for outgoing packet.
94     /*@}*/
95
96     /** Buffer for incoming packets. */
97     /*@{*/
98     uint8_t in_buffer[8192];             ///< Buffer for incoming packets.
99     uint8_t *read_in_ptr;                ///< Pointer for reading from incoming buffer.
100     int remaining_in_len;                ///< Reading length from incoming buffer.
101     /*@}*/
102
103     int incoming_packet_seq;             ///< Incoming packet sequence number.
104     int incoming_flags;                  ///< Incoming packet flags.
105
106     int packet_id;                       ///< Identifier for packets in the current stream.
107     unsigned int header_packet_id;       ///< default is 2.
108
109     /** Internal handling of the ASF header */
110     /*@{*/
111     uint8_t *asf_header;                 ///< Stored ASF header.
112     int asf_header_size;                 ///< Size of stored ASF header.
113     int header_parsed;                   ///< The header has been received and parsed.
114     int asf_packet_len;
115     /*@}*/
116
117     int stream_num;                      ///< stream numbers.
118     int is_playing;
119 } MMSContext;
120
121 /** Create MMST command packet header */
122 static void start_command_packet(MMSContext *mms, MMSCSPacketType packet_type)
123 {
124     mms->write_out_ptr = mms->out_buffer;
125
126     bytestream_put_le32(&mms->write_out_ptr, 1); // start sequence
127     bytestream_put_le32(&mms->write_out_ptr, 0xb00bface);
128     bytestream_put_le32(&mms->write_out_ptr, 0); // Length starts from after the protocol type bytes
129     bytestream_put_le32(&mms->write_out_ptr, MKTAG('M','M','S',' '));
130     bytestream_put_le32(&mms->write_out_ptr, 0);
131     bytestream_put_le32(&mms->write_out_ptr, mms->outgoing_packet_seq++);
132     bytestream_put_le64(&mms->write_out_ptr, 0); // timestamp
133     bytestream_put_le32(&mms->write_out_ptr, 0);
134     bytestream_put_le16(&mms->write_out_ptr, packet_type);
135     bytestream_put_le16(&mms->write_out_ptr, 3); // direction to server
136 }
137
138 /** Add prefixes to MMST command packet. */
139 static void insert_command_prefixes(MMSContext *mms,
140         uint32_t prefix1, uint32_t prefix2)
141 {
142     bytestream_put_le32(&mms->write_out_ptr, prefix1); // first prefix
143     bytestream_put_le32(&mms->write_out_ptr, prefix2); // second prefix
144 }
145
146 /** Send a prepared MMST command packet. */
147 static int send_command_packet(MMSContext *mms)
148 {
149     int exact_length= mms->write_out_ptr - mms->out_buffer;
150     int first_length= exact_length - 16;
151     int len8= first_length/8;
152     int write_result;
153
154     // update packet length fields.
155     AV_WL32(mms->out_buffer + 8, first_length);
156     AV_WL32(mms->out_buffer + 16, len8);
157     AV_WL32(mms->out_buffer + 32, len8-2);
158
159     // write it out.
160     write_result= url_write(mms->mms_hd, mms->out_buffer, exact_length);
161     if(write_result != exact_length) {
162         dprintf(NULL, "url_write returned: %d != %d\n",
163                 write_result, exact_length);
164         return AVERROR_IO;
165     }
166
167     return 0;
168 }
169
170 static void mms_put_utf16(MMSContext *mms, uint8_t *src)
171 {
172     ByteIOContext bic;
173     int size = mms->write_out_ptr - mms->out_buffer;
174     int len;
175     init_put_byte(&bic, mms->write_out_ptr,
176             sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL);
177
178     len = ff_put_str16_nolen(&bic, src);
179     mms->write_out_ptr += len;
180 }
181
182 static int send_protocol_select(MMSContext *mms)
183 {
184     char data_string[256];
185
186     start_command_packet(mms, CS_PKT_PROTOCOL_SELECT);
187     insert_command_prefixes(mms, 0, 0xffffffff);
188     bytestream_put_le32(&mms->write_out_ptr, 0);          // maxFunnelBytes
189     bytestream_put_le32(&mms->write_out_ptr, 0x00989680); // maxbitRate
190     bytestream_put_le32(&mms->write_out_ptr, 2);          // funnelMode
191     snprintf(data_string, sizeof(data_string), "\\\\%d.%d.%d.%d\\%s\\%d",
192             (LOCAL_ADDRESS>>24)&0xff,
193             (LOCAL_ADDRESS>>16)&0xff,
194             (LOCAL_ADDRESS>>8)&0xff,
195             LOCAL_ADDRESS&0xff,
196             "TCP",                                        // or UDP
197             LOCAL_PORT);
198
199     mms_put_utf16(mms, data_string);
200     return send_command_packet(mms);
201 }
202
203 static int send_media_file_request(MMSContext *mms)
204 {
205     start_command_packet(mms, CS_PKT_MEDIA_FILE_REQUEST);
206     insert_command_prefixes(mms, 1, 0xffffffff);
207     bytestream_put_le32(&mms->write_out_ptr, 0);
208     bytestream_put_le32(&mms->write_out_ptr, 0);
209     mms_put_utf16(mms, mms->path + 1); // +1 for skip "/"
210
211     return send_command_packet(mms);
212 }
213
214 static void handle_packet_stream_changing_type(MMSContext *mms)
215 {
216     dprintf(NULL, "Stream changing!\n");
217
218     // 40 is the packet header size, 7 is the prefix size.
219     mms->header_packet_id= AV_RL32(mms->in_buffer + 40 + 7);
220     dprintf(NULL, "Changed header prefix to 0x%x", mms->header_packet_id);
221 }
222
223 static int send_keepalive_packet(MMSContext *mms)
224 {
225     // respond to a keepalive with a keepalive...
226     start_command_packet(mms, CS_PKT_KEEPALIVE);
227     insert_command_prefixes(mms, 1, 0x100FFFF);
228     return send_command_packet(mms);
229 }
230
231 /** Pad media packets smaller than max_packet_size and/or adjust read position
232   * after a seek. */
233 static void pad_media_packet(MMSContext *mms)
234 {
235     if(mms->remaining_in_len<mms->asf_packet_len) {
236         int padding_size = mms->asf_packet_len - mms->remaining_in_len;
237         memset(mms->in_buffer + mms->remaining_in_len, 0, padding_size);
238         mms->remaining_in_len += padding_size;
239     }
240 }
241
242 /** Read incoming MMST media, header or command packet. */
243 static MMSSCPacketType get_tcp_server_response(MMSContext *mms)
244 {
245     int read_result;
246     MMSSCPacketType packet_type= -1;
247
248     for(;;) {
249         if((read_result= url_read_complete(mms->mms_hd, mms->in_buffer, 8))==8) {
250             // handle command packet.
251             if(AV_RL32(mms->in_buffer + 4)==0xb00bface) {
252                 mms->incoming_flags= mms->in_buffer[3];
253                 read_result= url_read_complete(mms->mms_hd, mms->in_buffer+8, 4);
254                 if(read_result == 4) {
255                     int length_remaining= AV_RL32(mms->in_buffer+8) + 4;
256
257                     dprintf(NULL, "Length remaining is %d\n", length_remaining);
258                     // read the rest of the packet.
259                     if (length_remaining < 0
260                         || length_remaining > sizeof(mms->in_buffer) - 12) {
261                         dprintf(NULL, "Incoming message len %d exceeds buffer len %d\n",
262                             length_remaining, sizeof(mms->in_buffer) - 12);
263                         return -1;
264                     }
265                     read_result = url_read_complete(mms->mms_hd, mms->in_buffer + 12,
266                                                   length_remaining) ;
267                     if (read_result == length_remaining) {
268                         packet_type= AV_RL16(mms->in_buffer+36);
269                     } else {
270                         dprintf(NULL, "read for packet type failed%d!\n", read_result);
271                         return -1;
272                     }
273                 } else {
274                     dprintf(NULL, "read for length remaining failed%d!\n", read_result);
275                     return -1;
276                 }
277             } else {
278                 int length_remaining;
279                 int packet_id_type;
280                 int tmp;
281
282                 assert(mms->remaining_in_len==0);
283
284                 // note we cache the first 8 bytes,
285                 // then fill up the buffer with the others
286                 tmp                       = AV_RL16(mms->in_buffer + 6);
287                 length_remaining          = (tmp - 8) & 0xffff;
288                 mms->incoming_packet_seq  = AV_RL32(mms->in_buffer);
289                 packet_id_type            = mms->in_buffer[4];
290                 mms->incoming_flags       = mms->in_buffer[5];
291
292                 if (length_remaining < 0
293                         || length_remaining > sizeof(mms->in_buffer) - 8) {
294                     dprintf(NULL, "Incoming data len %d exceeds buffer len %d\n",
295                             length_remaining, sizeof(mms->in_buffer));
296                     return -1;
297                 }
298                 mms->remaining_in_len    = length_remaining;
299                 mms->read_in_ptr         = mms->in_buffer;
300                 read_result= url_read_complete(mms->mms_hd, mms->in_buffer, length_remaining);
301                 if(read_result != length_remaining) {
302                     dprintf(NULL, "read_bytes result: %d asking for %d\n",
303                             read_result, length_remaining);
304                     return -1;
305                 } else {
306                     // if we successfully read everything.
307                     if(packet_id_type == mms->header_packet_id) {
308                         packet_type = SC_PKT_ASF_HEADER;
309                         // Store the asf header
310                         if(!mms->header_parsed) {
311                             void *p = av_realloc(mms->asf_header,
312                                               mms->asf_header_size
313                                               + mms->remaining_in_len);
314                             if (!p) {
315                                 av_freep(&mms->asf_header);
316                                 return AVERROR(ENOMEM);
317                             }
318                             mms->asf_header = p;
319                             memcpy(mms->asf_header + mms->asf_header_size,
320                                                  mms->read_in_ptr,
321                                                  mms->remaining_in_len);
322                             mms->asf_header_size += mms->remaining_in_len;
323                         }
324                     } else if(packet_id_type == mms->packet_id) {
325                         packet_type = SC_PKT_ASF_MEDIA;
326                     } else {
327                         dprintf(NULL, "packet id type %d is old.", packet_id_type);
328                         continue;
329                     }
330                 }
331             }
332
333             // preprocess some packet type
334             if(packet_type == SC_PKT_KEEPALIVE) {
335                 send_keepalive_packet(mms);
336                 continue;
337             } else if(packet_type == SC_PKT_STREAM_CHANGING) {
338                 handle_packet_stream_changing_type(mms);
339             } else if(packet_type == SC_PKT_ASF_MEDIA) {
340                 pad_media_packet(mms);
341             }
342             return packet_type;
343         } else {
344             if(read_result<0) {
345                 dprintf(NULL, "Read error (or cancelled) returned %d!\n", read_result);
346                 packet_type = SC_PKT_CANCEL;
347             } else {
348                 dprintf(NULL, "Read result of zero?!\n");
349                 packet_type = SC_PKT_NO_DATA;
350             }
351             return packet_type;
352         }
353     }
354 }
355
356 static int mms_safe_send_recv(MMSContext *mms,
357                               int (*send_fun)(MMSContext *mms),
358                               const MMSSCPacketType expect_type)
359 {
360     MMSSCPacketType type;
361     if(send_fun) {
362         int ret = send_fun(mms);
363         if (ret < 0) {
364             dprintf(NULL, "Send Packet error before expecting recv packet %d\n", expect_type);
365             return ret;
366         }
367     }
368
369     if ((type = get_tcp_server_response(mms)) != expect_type) {
370         dprintf(NULL,"Unexpected packet type %d with type %d\n", type, expect_type);
371         return -1;
372     } else {
373         return 0;
374     }
375 }
376
377 static int send_media_header_request(MMSContext *mms)
378 {
379     start_command_packet(mms, CS_PKT_MEDIA_HEADER_REQUEST);
380     insert_command_prefixes(mms, 1, 0);
381     bytestream_put_le32(&mms->write_out_ptr, 0);
382     bytestream_put_le32(&mms->write_out_ptr, 0x00800000);
383     bytestream_put_le32(&mms->write_out_ptr, 0xffffffff);
384     bytestream_put_le32(&mms->write_out_ptr, 0);
385     bytestream_put_le32(&mms->write_out_ptr, 0);
386     bytestream_put_le32(&mms->write_out_ptr, 0);
387
388     // the media preroll value in milliseconds?
389     bytestream_put_le32(&mms->write_out_ptr, 0);
390     bytestream_put_le32(&mms->write_out_ptr, 0x40AC2000);
391     bytestream_put_le32(&mms->write_out_ptr, 2);
392     bytestream_put_le32(&mms->write_out_ptr, 0);
393
394     return send_command_packet(mms);
395 }
396
397 /** Send the initial handshake. */
398 static int send_startup_packet(MMSContext *mms)
399 {
400     char data_string[256];
401     // SubscriberName is defined in MS specification linked below.
402     // The guid value can be any valid value.
403     // http://download.microsoft.com/
404     // download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-WMSP%5D.pdf
405     snprintf(data_string, sizeof(data_string),
406             "NSPlayer/7.0.0.1956; {%s}; Host: %s",
407             "7E667F5D-A661-495E-A512-F55686DDA178", mms->host);
408
409     start_command_packet(mms, CS_PKT_INITIAL);
410     insert_command_prefixes(mms, 0, 0x0004000b);
411     bytestream_put_le32(&mms->write_out_ptr, 0x0003001c);
412     mms_put_utf16(mms, data_string);
413     return send_command_packet(mms);
414 }
415
416 static int asf_header_parser(MMSContext *mms)
417 {
418     uint8_t *p = mms->asf_header;
419     uint8_t *end;
420     int flags, stream_id, real_header_size;
421     mms->stream_num = 0;
422
423     if (mms->asf_header_size < sizeof(ff_asf_guid) * 2 + 22 ||
424         memcmp(p, ff_asf_header, sizeof(ff_asf_guid)))
425         return -1;
426
427     real_header_size = AV_RL64(p + sizeof(ff_asf_guid));
428     end = mms->asf_header + real_header_size;
429
430     p += sizeof(ff_asf_guid) + 14;
431     while(end - p >= sizeof(ff_asf_guid) + 8) {
432         uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid));
433         if (!chunksize || chunksize > end - p) {
434             dprintf(NULL, "chunksize is exceptional value:%d!\n", chunksize);
435             return -1;
436         }
437         if (!memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
438             /* read packet size */
439             if (end - p > sizeof(ff_asf_guid) * 2 + 68) {
440                 mms->asf_packet_len = AV_RL32(p + sizeof(ff_asf_guid) * 2 + 64);
441                 if (mms->asf_packet_len <= 0 || mms->asf_packet_len > sizeof(mms->in_buffer)) {
442                     dprintf(NULL,"Too large packet len:%d"
443                         " may overwrite in_buffer when padding", mms->asf_packet_len);
444                     return -1;
445                 }
446             }
447         } else if (!memcmp(p, ff_asf_stream_header, sizeof(ff_asf_guid))) {
448             flags     = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24);
449             stream_id = flags & 0x7F;
450             //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size,
451             //we can calcuate the packet size by stream_num.
452             //Please see function send_stream_selection_request().
453             if (mms->stream_num < MAX_STREAMS &&
454                     46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) {
455                 mms->streams[mms->stream_num].id = stream_id;
456                 mms->stream_num++;
457             } else {
458                 dprintf(NULL, "Too many streams.\n");
459                 return -1;
460             }
461         }
462         p += chunksize;
463     }
464
465     return 0;
466 }
467
468 /** Send MMST stream selection command based on the AVStream->discard values. */
469 static int send_stream_selection_request(MMSContext *mms)
470 {
471     int i;
472
473     //  send the streams we want back...
474     start_command_packet(mms, CS_PKT_STREAM_ID_REQUEST);
475     bytestream_put_le32(&mms->write_out_ptr, mms->stream_num);         // stream nums
476     for(i= 0; i<mms->stream_num; i++) {
477         bytestream_put_le16(&mms->write_out_ptr, 0xffff);              // flags
478         bytestream_put_le16(&mms->write_out_ptr, mms->streams[i].id);  // stream id
479         bytestream_put_le16(&mms->write_out_ptr, 0);                   // selection
480     }
481
482     bytestream_put_le16(&mms->write_out_ptr, 0);
483
484     return send_command_packet(mms);
485 }
486
487 static int read_data(MMSContext *mms, uint8_t *buf, const int buf_size)
488 {
489     int read_size;
490     read_size = FFMIN(buf_size, mms->remaining_in_len);
491     memcpy(buf, mms->read_in_ptr, read_size);
492     mms->remaining_in_len -= read_size;
493     mms->read_in_ptr      += read_size;
494     return read_size;
495 }
496
497 /** Read at most one media packet (or a whole header). */
498 static int read_mms_packet(MMSContext *mms, uint8_t *buf, int buf_size)
499 {
500     int result = 0, read_header_size = 0;
501     int size_to_copy;
502
503     do {
504         if(read_header_size < mms->asf_header_size && !mms->is_playing) {
505             /* Read from ASF header buffer */
506             size_to_copy= FFMIN(buf_size,
507                                 mms->asf_header_size - read_header_size);
508             memcpy(buf, mms->asf_header + read_header_size, size_to_copy);
509             read_header_size += size_to_copy;
510             result += size_to_copy;
511             dprintf(NULL, "Copied %d bytes from stored header. left: %d\n",
512                    size_to_copy, mms->asf_header_size - read_header_size);
513             if (mms->asf_header_size == read_header_size) {
514                 av_freep(&mms->asf_header);
515                 mms->is_playing = 1;
516             }
517         } else if(mms->remaining_in_len) {
518             /* Read remaining packet data to buffer.
519              * the result can not be zero because remaining_in_len is positive.*/
520             result = read_data(mms, buf, buf_size);
521         } else {
522             /* Read from network */
523             int err = mms_safe_send_recv(mms, NULL, SC_PKT_ASF_MEDIA);
524             if (err == 0) {
525                 if(mms->remaining_in_len>mms->asf_packet_len) {
526                     dprintf(NULL, "Incoming packet"
527                             "larger than the asf packet size stated (%d>%d)\n",
528                             mms->remaining_in_len, mms->asf_packet_len);
529                     result= AVERROR_IO;
530                 } else {
531                     // copy the data to the packet buffer.
532                     result = read_data(mms, buf, buf_size);
533                     if (result == 0) {
534                         dprintf(NULL, "read asf media paket size is zero!\n");
535                         break;
536                     }
537                 }
538             } else {
539                 dprintf(NULL, "read packet error!\n");
540                 break;
541             }
542         }
543     } while(!result); // only return one packet.
544     return result;
545 }
546
547 static int send_close_packet(MMSContext *mms)
548 {
549     start_command_packet(mms, CS_PKT_STREAM_CLOSE);
550     insert_command_prefixes(mms, 1, 1);
551
552     return send_command_packet(mms);
553 }
554
555 /** Close the MMSH/MMST connection */
556 static int mms_close(URLContext *h)
557 {
558     MMSContext *mms = (MMSContext *)h->priv_data;
559
560     if(mms->mms_hd) {
561         send_close_packet(mms);
562         url_close(mms->mms_hd);
563     }
564
565     /* free all separately allocated pointers in mms */
566     av_free(mms->asf_header);
567     av_freep(&h->priv_data);
568
569     return 0;
570 }
571
572 static int mms_open(URLContext *h, const char *uri, int flags)
573 {
574     MMSContext *mms;
575     int port, err;
576     char tcpname[256];
577
578     h->is_streamed = 1;
579     mms = h->priv_data = av_mallocz(sizeof(MMSContext));
580     if (!h->priv_data)
581         return AVERROR(ENOMEM);
582
583     // only for MMS over TCP, so set proto = NULL
584     av_url_split(NULL, 0, NULL, 0,
585             mms->host, sizeof(mms->host), &port, mms->path,
586             sizeof(mms->path), uri);
587
588     if(port<0)
589         port = 1755; // defaut mms protocol port
590
591     // establish tcp connection.
592     ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, mms->host, port, NULL);
593     err = url_open(&mms->mms_hd, tcpname, URL_RDWR);
594     if (err)
595         goto fail;
596
597     mms->packet_id        = 3;          // default, initial value.
598     mms->header_packet_id = 2;          // default, initial value.
599     err = mms_safe_send_recv(mms, send_startup_packet, SC_PKT_CLIENT_ACCEPTED);
600     if (err)
601         goto fail;
602     err = mms_safe_send_recv(mms, send_protocol_select, SC_PKT_PROTOCOL_ACCEPTED);
603     if (err)
604         goto fail;
605     err = mms_safe_send_recv(mms, send_media_file_request, SC_PKT_MEDIA_FILE_DETAILS);
606     if (err)
607         goto fail;
608     err = mms_safe_send_recv(mms, send_media_header_request, SC_PKT_HEADER_REQUEST_ACCEPTED);
609     if (err)
610         goto fail;
611     err = mms_safe_send_recv(mms, NULL, SC_PKT_ASF_HEADER);
612     if (err)
613         goto fail;
614     if((mms->incoming_flags != 0X08) && (mms->incoming_flags != 0X0C))
615         goto fail;
616     err = asf_header_parser(mms);
617     if (err) {
618         dprintf(NULL, "asf header parsed failed!\n");
619         goto fail;
620     }
621     mms->header_parsed = 1;
622
623     if (!mms->asf_packet_len || !mms->stream_num)
624         goto fail;
625
626     dprintf(NULL, "Leaving open (success)\n");
627     return 0;
628 fail:
629     mms_close(h);
630     dprintf(NULL, "Leaving open (failure: %d)\n", err);
631     return err;
632 }
633
634 static int send_media_packet_request(MMSContext *mms)
635 {
636     start_command_packet(mms, CS_PKT_START_FROM_PKT_ID);
637     insert_command_prefixes(mms, 1, 0x0001FFFF);
638     bytestream_put_le64(&mms->write_out_ptr, 0);          // seek timestamp
639     bytestream_put_le32(&mms->write_out_ptr, 0xffffffff); // unknown
640     bytestream_put_le32(&mms->write_out_ptr, 0xffffffff); // packet offset
641     bytestream_put_byte(&mms->write_out_ptr, 0xff);       // max stream time limit
642     bytestream_put_byte(&mms->write_out_ptr, 0xff);       // max stream time limit
643     bytestream_put_byte(&mms->write_out_ptr, 0xff);       // max stream time limit
644     bytestream_put_byte(&mms->write_out_ptr, 0x00);       // stream time limit flag
645
646     mms->packet_id++;                                     // new packet_id
647     bytestream_put_le32(&mms->write_out_ptr, mms->packet_id);
648     return send_command_packet(mms);
649 }
650
651
652 static void clear_stream_buffers(MMSContext *mms)
653 {
654     mms->remaining_in_len = 0;
655     mms->read_in_ptr      = mms->in_buffer;
656 }
657
658 /** Read ASF data through the protocol. */
659 static int mms_read(URLContext *h, uint8_t *buf, int size)
660 {
661     /* TODO: see tcp.c:tcp_read() about a possible timeout scheme */
662     MMSContext *mms = h->priv_data;
663     int result = 0;
664
665     /* Since we read the header at open(), this shouldn't be possible */
666     assert(mms->header_parsed);
667
668     if (!mms->is_playing) {
669         dprintf(NULL, "mms_read() before play().\n");
670         clear_stream_buffers(mms);
671         result = mms_safe_send_recv(mms, send_stream_selection_request, SC_PKT_STREAM_ID_ACCEPTED);
672         if (result)
673             return result;
674         // send media packet request
675         result = mms_safe_send_recv(mms, send_media_packet_request, SC_PKT_MEDIA_PKT_FOLLOWS);
676         if (result) {
677             return result;
678         }
679     }
680     return read_mms_packet(mms, buf, size);
681 }
682
683 URLProtocol mmst_protocol = {
684     "mmst",
685     mms_open,
686     mms_read,
687     NULL, // write
688     NULL, // seek
689     mms_close,
690 };