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