mmst.c 23.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * MMS protocol over TCP
 * Copyright (c) 2006,2007 Ryan Martell
 * Copyright (c) 2007 Bjrn Axelsson
 * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
23 24 25 26 27 28 29 30

/* References
 * MMS protocol specification:
 *  [1]http://msdn.microsoft.com/en-us/library/cc234711(PROT.10).aspx
 * ASF specification. Revision 01.20.03.
 *  [2]http://msdn.microsoft.com/en-us/library/bb643323.aspx
 */

31
#include "avformat.h"
32
#include "mms.h"
33
#include "internal.h"
34
#include "avio_internal.h"
35 36 37
#include "libavutil/intreadwrite.h"
#include "libavcodec/bytestream.h"
#include "network.h"
38
#include "url.h"
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

#define LOCAL_ADDRESS 0xc0a80081    // FIXME get and use correct local ip address.
#define LOCAL_PORT    1037          // as above.
/** Client to server packet types. */
typedef enum {
    CS_PKT_INITIAL                  = 0x01,
    CS_PKT_PROTOCOL_SELECT          = 0x02,
    CS_PKT_MEDIA_FILE_REQUEST       = 0x05,
    CS_PKT_START_FROM_PKT_ID        = 0x07,
    CS_PKT_STREAM_PAUSE             = 0x09,
    CS_PKT_STREAM_CLOSE             = 0x0d,
    CS_PKT_MEDIA_HEADER_REQUEST     = 0x15,
    CS_PKT_TIMING_DATA_REQUEST      = 0x18,
    CS_PKT_USER_PASSWORD            = 0x1a,
    CS_PKT_KEEPALIVE                = 0x1b,
    CS_PKT_STREAM_ID_REQUEST        = 0x33,
} MMSCSPacketType;

/** Server to client packet types. */
typedef enum {
    /** Control packets. */
    /*@{*/
    SC_PKT_CLIENT_ACCEPTED          = 0x01,
    SC_PKT_PROTOCOL_ACCEPTED        = 0x02,
    SC_PKT_PROTOCOL_FAILED          = 0x03,
    SC_PKT_MEDIA_PKT_FOLLOWS        = 0x05,
    SC_PKT_MEDIA_FILE_DETAILS       = 0x06,
    SC_PKT_HEADER_REQUEST_ACCEPTED  = 0x11,
    SC_PKT_TIMING_TEST_REPLY        = 0x15,
    SC_PKT_PASSWORD_REQUIRED        = 0x1a,
    SC_PKT_KEEPALIVE                = 0x1b,
    SC_PKT_STREAM_STOPPED           = 0x1e,
    SC_PKT_STREAM_CHANGING          = 0x20,
    SC_PKT_STREAM_ID_ACCEPTED       = 0x21,
    /*@}*/

    /** Pseudo packets. */
    /*@{*/
    SC_PKT_CANCEL                   = -1,
    SC_PKT_NO_DATA                  = -2,
    /*@}*/

    /** Data packets. */
    /*@{*/
    SC_PKT_ASF_HEADER               = 0x010000,// make it bigger than 0xFF in case of
    SC_PKT_ASF_MEDIA                = 0x010001,// receiving false data packets.
    /*@}*/
} MMSSCPacketType;

88 89 90 91 92 93 94 95 96 97 98
typedef struct {
    MMSContext  mms;
    int outgoing_packet_seq;             ///< Outgoing packet sequence number.
    char path[256];                      ///< Path of the resource being asked for.
    char host[128];                      ///< Host of the resources.
    int incoming_packet_seq;             ///< Incoming packet sequence number.
    int incoming_flags;                  ///< Incoming packet flags.
    int packet_id;                       ///< Identifier for packets in the current stream.
    unsigned int header_packet_id;       ///< default is 2.
} MMSTContext;

99
/** Create MMST command packet header */
100
static void start_command_packet(MMSTContext *mmst, MMSCSPacketType packet_type)
101
{
102
    MMSContext *mms    = &mmst->mms;
103 104 105 106 107 108 109
    mms->write_out_ptr = mms->out_buffer;

    bytestream_put_le32(&mms->write_out_ptr, 1); // start sequence
    bytestream_put_le32(&mms->write_out_ptr, 0xb00bface);
    bytestream_put_le32(&mms->write_out_ptr, 0); // Length starts from after the protocol type bytes
    bytestream_put_le32(&mms->write_out_ptr, MKTAG('M','M','S',' '));
    bytestream_put_le32(&mms->write_out_ptr, 0);
110
    bytestream_put_le32(&mms->write_out_ptr, mmst->outgoing_packet_seq++);
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    bytestream_put_le64(&mms->write_out_ptr, 0); // timestamp
    bytestream_put_le32(&mms->write_out_ptr, 0);
    bytestream_put_le16(&mms->write_out_ptr, packet_type);
    bytestream_put_le16(&mms->write_out_ptr, 3); // direction to server
}

/** Add prefixes to MMST command packet. */
static void insert_command_prefixes(MMSContext *mms,
        uint32_t prefix1, uint32_t prefix2)
{
    bytestream_put_le32(&mms->write_out_ptr, prefix1); // first prefix
    bytestream_put_le32(&mms->write_out_ptr, prefix2); // second prefix
}

/** Send a prepared MMST command packet. */
126
static int send_command_packet(MMSTContext *mmst)
127
{
128
    MMSContext *mms  = &mmst->mms;
129
    int len= mms->write_out_ptr - mms->out_buffer;
130
    int exact_length = FFALIGN(len, 8);
131 132 133 134 135 136 137 138
    int first_length= exact_length - 16;
    int len8= first_length/8;
    int write_result;

    // update packet length fields.
    AV_WL32(mms->out_buffer + 8, first_length);
    AV_WL32(mms->out_buffer + 16, len8);
    AV_WL32(mms->out_buffer + 32, len8-2);
139
    memset(mms->write_out_ptr, 0, exact_length - len);
140 141

    // write it out.
142
    write_result= ffurl_write(mms->mms_hd, mms->out_buffer, exact_length);
143
    if(write_result != exact_length) {
144 145 146 147 148
        av_log(NULL, AV_LOG_ERROR,
               "Failed to write data of length %d: %d (%s)\n",
               exact_length, write_result,
               write_result < 0 ? strerror(write_result) :
                   "The server closed the connection");
149
        return AVERROR(EIO);
150 151 152 153 154 155 156
    }

    return 0;
}

static void mms_put_utf16(MMSContext *mms, uint8_t *src)
{
157
    AVIOContext bic;
158 159
    int size = mms->write_out_ptr - mms->out_buffer;
    int len;
160
    ffio_init_context(&bic, mms->write_out_ptr,
161 162
            sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL);

163
    len = avio_put_str16le(&bic, src);
164 165 166
    mms->write_out_ptr += len;
}

167
static int send_time_test_data(MMSTContext *mmst)
168
{
169
    start_command_packet(mmst, CS_PKT_TIMING_DATA_REQUEST);
170
    insert_command_prefixes(&mmst->mms, 0x00f0f0f0, 0x0004000b);
171
    return send_command_packet(mmst);
172 173
}

174
static int send_protocol_select(MMSTContext *mmst)
175 176
{
    char data_string[256];
177
    MMSContext *mms = &mmst->mms;
178

179
    start_command_packet(mmst, CS_PKT_PROTOCOL_SELECT);
180 181 182 183 184 185 186 187 188 189 190 191 192
    insert_command_prefixes(mms, 0, 0xffffffff);
    bytestream_put_le32(&mms->write_out_ptr, 0);          // maxFunnelBytes
    bytestream_put_le32(&mms->write_out_ptr, 0x00989680); // maxbitRate
    bytestream_put_le32(&mms->write_out_ptr, 2);          // funnelMode
    snprintf(data_string, sizeof(data_string), "\\\\%d.%d.%d.%d\\%s\\%d",
            (LOCAL_ADDRESS>>24)&0xff,
            (LOCAL_ADDRESS>>16)&0xff,
            (LOCAL_ADDRESS>>8)&0xff,
            LOCAL_ADDRESS&0xff,
            "TCP",                                        // or UDP
            LOCAL_PORT);

    mms_put_utf16(mms, data_string);
193
    return send_command_packet(mmst);
194 195
}

196
static int send_media_file_request(MMSTContext *mmst)
197
{
198 199
    MMSContext *mms = &mmst->mms;
    start_command_packet(mmst, CS_PKT_MEDIA_FILE_REQUEST);
200 201 202
    insert_command_prefixes(mms, 1, 0xffffffff);
    bytestream_put_le32(&mms->write_out_ptr, 0);
    bytestream_put_le32(&mms->write_out_ptr, 0);
203
    mms_put_utf16(mms, mmst->path + 1); // +1 for skip "/"
204

205
    return send_command_packet(mmst);
206 207
}

208
static void handle_packet_stream_changing_type(MMSTContext *mmst)
209
{
210
    MMSContext *mms = &mmst->mms;
211
    av_dlog(NULL, "Stream changing!\n");
212 213

    // 40 is the packet header size, 7 is the prefix size.
214
    mmst->header_packet_id= AV_RL32(mms->in_buffer + 40 + 7);
215
    av_dlog(NULL, "Changed header prefix to 0x%x", mmst->header_packet_id);
216 217
}

218
static int send_keepalive_packet(MMSTContext *mmst)
219 220
{
    // respond to a keepalive with a keepalive...
221 222 223
    start_command_packet(mmst, CS_PKT_KEEPALIVE);
    insert_command_prefixes(&mmst->mms, 1, 0x100FFFF);
    return send_command_packet(mmst);
224 225 226 227 228 229 230 231 232 233 234 235 236 237
}

/** Pad media packets smaller than max_packet_size and/or adjust read position
  * after a seek. */
static void pad_media_packet(MMSContext *mms)
{
    if(mms->remaining_in_len<mms->asf_packet_len) {
        int padding_size = mms->asf_packet_len - mms->remaining_in_len;
        memset(mms->in_buffer + mms->remaining_in_len, 0, padding_size);
        mms->remaining_in_len += padding_size;
    }
}

/** Read incoming MMST media, header or command packet. */
238
static MMSSCPacketType get_tcp_server_response(MMSTContext *mmst)
239 240 241
{
    int read_result;
    MMSSCPacketType packet_type= -1;
242
    MMSContext *mms = &mmst->mms;
243
    for(;;) {
244
        read_result = ffurl_read_complete(mms->mms_hd, mms->in_buffer, 8);
245 246 247 248 249 250 251 252 253 254 255 256 257 258
        if (read_result != 8) {
            if(read_result < 0) {
                av_log(NULL, AV_LOG_ERROR,
                       "Error reading packet header: %d (%s)\n",
                       read_result, strerror(read_result));
                packet_type = SC_PKT_CANCEL;
            } else {
                av_log(NULL, AV_LOG_ERROR,
                       "The server closed the connection\n");
                packet_type = SC_PKT_NO_DATA;
            }
            return packet_type;
        }

259 260
        // handle command packet.
        if(AV_RL32(mms->in_buffer + 4)==0xb00bface) {
261 262
            int length_remaining, hr;

263
            mmst->incoming_flags= mms->in_buffer[3];
264
            read_result= ffurl_read_complete(mms->mms_hd, mms->in_buffer+8, 4);
265 266 267 268 269 270
            if(read_result != 4) {
                av_log(NULL, AV_LOG_ERROR,
                       "Reading command packet length failed: %d (%s)\n",
                       read_result,
                       read_result < 0 ? strerror(read_result) :
                           "The server closed the connection");
271
                return read_result < 0 ? read_result : AVERROR(EIO);
272
            }
273

274
            length_remaining= AV_RL32(mms->in_buffer+8) + 4;
275
            av_dlog(NULL, "Length remaining is %d\n", length_remaining);
276 277 278 279 280 281 282 283
            // read the rest of the packet.
            if (length_remaining < 0
                || length_remaining > sizeof(mms->in_buffer) - 12) {
                av_log(NULL, AV_LOG_ERROR,
                       "Incoming packet length %d exceeds bufsize %zu\n",
                       length_remaining, sizeof(mms->in_buffer) - 12);
                return AVERROR_INVALIDDATA;
            }
284
            read_result = ffurl_read_complete(mms->mms_hd, mms->in_buffer + 12,
285 286 287 288 289 290 291
                                            length_remaining) ;
            if (read_result != length_remaining) {
                av_log(NULL, AV_LOG_ERROR,
                       "Reading pkt data (length=%d) failed: %d (%s)\n",
                       length_remaining, read_result,
                       read_result < 0 ? strerror(read_result) :
                           "The server closed the connection");
292
                return read_result < 0 ? read_result : AVERROR(EIO);
293 294
            }
            packet_type= AV_RL16(mms->in_buffer+36);
295
            if (read_result >= 44 && (hr = AV_RL32(mms->in_buffer + 40))) {
296
                av_log(NULL, AV_LOG_ERROR,
297
                       "Server sent a message with packet type 0x%x and error status code 0x%08x\n", packet_type, hr);
298
                return AVERROR(EINVAL);
299 300 301 302 303 304 305 306 307 308
            }
        } else {
            int length_remaining;
            int packet_id_type;
            int tmp;

            // note we cache the first 8 bytes,
            // then fill up the buffer with the others
            tmp                       = AV_RL16(mms->in_buffer + 6);
            length_remaining          = (tmp - 8) & 0xffff;
309
            mmst->incoming_packet_seq = AV_RL32(mms->in_buffer);
310
            packet_id_type            = mms->in_buffer[4];
311
            mmst->incoming_flags      = mms->in_buffer[5];
312 313 314 315 316 317 318 319 320 321

            if (length_remaining < 0
                || length_remaining > sizeof(mms->in_buffer) - 8) {
                av_log(NULL, AV_LOG_ERROR,
                       "Data length %d is invalid or too large (max=%zu)\n",
                       length_remaining, sizeof(mms->in_buffer));
                return AVERROR_INVALIDDATA;
            }
            mms->remaining_in_len    = length_remaining;
            mms->read_in_ptr         = mms->in_buffer;
322
            read_result= ffurl_read_complete(mms->mms_hd, mms->in_buffer, length_remaining);
323 324 325 326 327 328
            if(read_result != length_remaining) {
                av_log(NULL, AV_LOG_ERROR,
                       "Failed to read packet data of size %d: %d (%s)\n",
                       length_remaining, read_result,
                       read_result < 0 ? strerror(read_result) :
                           "The server closed the connection");
329
                return read_result < 0 ? read_result : AVERROR(EIO);
330 331
            }

332
            // if we successfully read everything.
333
            if(packet_id_type == mmst->header_packet_id) {
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
                packet_type = SC_PKT_ASF_HEADER;
                // Store the asf header
                if(!mms->header_parsed) {
                    void *p = av_realloc(mms->asf_header,
                                  mms->asf_header_size + mms->remaining_in_len);
                    if (!p) {
                        av_freep(&mms->asf_header);
                        return AVERROR(ENOMEM);
                    }
                    mms->asf_header = p;
                    memcpy(mms->asf_header + mms->asf_header_size,
                           mms->read_in_ptr, mms->remaining_in_len);
                    mms->asf_header_size += mms->remaining_in_len;
                }
                // 0x04 means asf header is sent in multiple packets.
349
                if (mmst->incoming_flags == 0x04)
350
                    continue;
351
            } else if(packet_id_type == mmst->packet_id) {
352 353
                packet_type = SC_PKT_ASF_MEDIA;
            } else {
354
                av_dlog(NULL, "packet id type %d is old.", packet_id_type);
355 356
                continue;
            }
357 358 359 360
        }

        // preprocess some packet type
        if(packet_type == SC_PKT_KEEPALIVE) {
361
            send_keepalive_packet(mmst);
362 363
            continue;
        } else if(packet_type == SC_PKT_STREAM_CHANGING) {
364
            handle_packet_stream_changing_type(mmst);
365 366 367 368
        } else if(packet_type == SC_PKT_ASF_MEDIA) {
            pad_media_packet(mms);
        }
        return packet_type;
369 370 371
    }
}

372 373
static int mms_safe_send_recv(MMSTContext *mmst,
                              int (*send_fun)(MMSTContext *mmst),
374 375 376 377
                              const MMSSCPacketType expect_type)
{
    MMSSCPacketType type;
    if(send_fun) {
378
        int ret = send_fun(mmst);
379
        if (ret < 0) {
380
            av_dlog(NULL, "Send Packet error before expecting recv packet %d\n", expect_type);
381 382 383 384
            return ret;
        }
    }

385
    if ((type = get_tcp_server_response(mmst)) != expect_type) {
386 387 388 389
        av_log(NULL, AV_LOG_ERROR,
               "Corrupt stream (unexpected packet type 0x%x, expected 0x%x)\n",
               type, expect_type);
        return AVERROR_INVALIDDATA;
390 391 392 393 394
    } else {
        return 0;
    }
}

395
static int send_media_header_request(MMSTContext *mmst)
396
{
397 398
    MMSContext *mms = &mmst->mms;
    start_command_packet(mmst, CS_PKT_MEDIA_HEADER_REQUEST);
399 400 401 402 403 404 405 406 407 408 409 410 411 412
    insert_command_prefixes(mms, 1, 0);
    bytestream_put_le32(&mms->write_out_ptr, 0);
    bytestream_put_le32(&mms->write_out_ptr, 0x00800000);
    bytestream_put_le32(&mms->write_out_ptr, 0xffffffff);
    bytestream_put_le32(&mms->write_out_ptr, 0);
    bytestream_put_le32(&mms->write_out_ptr, 0);
    bytestream_put_le32(&mms->write_out_ptr, 0);

    // the media preroll value in milliseconds?
    bytestream_put_le32(&mms->write_out_ptr, 0);
    bytestream_put_le32(&mms->write_out_ptr, 0x40AC2000);
    bytestream_put_le32(&mms->write_out_ptr, 2);
    bytestream_put_le32(&mms->write_out_ptr, 0);

413
    return send_command_packet(mmst);
414 415 416
}

/** Send the initial handshake. */
417
static int send_startup_packet(MMSTContext *mmst)
418 419
{
    char data_string[256];
420
    MMSContext *mms = &mmst->mms;
421 422 423 424 425 426
    // SubscriberName is defined in MS specification linked below.
    // The guid value can be any valid value.
    // http://download.microsoft.com/
    // download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-WMSP%5D.pdf
    snprintf(data_string, sizeof(data_string),
            "NSPlayer/7.0.0.1956; {%s}; Host: %s",
427
            "7E667F5D-A661-495E-A512-F55686DDA178", mmst->host);
428

429
    start_command_packet(mmst, CS_PKT_INITIAL);
430 431 432
    insert_command_prefixes(mms, 0, 0x0004000b);
    bytestream_put_le32(&mms->write_out_ptr, 0x0003001c);
    mms_put_utf16(mms, data_string);
433
    return send_command_packet(mmst);
434 435 436
}

/** Send MMST stream selection command based on the AVStream->discard values. */
437
static int send_stream_selection_request(MMSTContext *mmst)
438 439
{
    int i;
440
    MMSContext *mms = &mmst->mms;
441
    //  send the streams we want back...
442
    start_command_packet(mmst, CS_PKT_STREAM_ID_REQUEST);
443 444 445 446 447 448
    bytestream_put_le32(&mms->write_out_ptr, mms->stream_num);         // stream nums
    for(i= 0; i<mms->stream_num; i++) {
        bytestream_put_le16(&mms->write_out_ptr, 0xffff);              // flags
        bytestream_put_le16(&mms->write_out_ptr, mms->streams[i].id);  // stream id
        bytestream_put_le16(&mms->write_out_ptr, 0);                   // selection
    }
449
    return send_command_packet(mmst);
450 451
}

452
static int send_close_packet(MMSTContext *mmst)
453
{
454 455
    start_command_packet(mmst, CS_PKT_STREAM_CLOSE);
    insert_command_prefixes(&mmst->mms, 1, 1);
456

457
    return send_command_packet(mmst);
458 459 460 461 462
}

/** Close the MMSH/MMST connection */
static int mms_close(URLContext *h)
{
463 464
    MMSTContext *mmst = (MMSTContext *)h->priv_data;
    MMSContext *mms   = &mmst->mms;
465
    if(mms->mms_hd) {
466
        send_close_packet(mmst);
467
        ffurl_close(mms->mms_hd);
468 469 470
    }

    /* free all separately allocated pointers in mms */
471
    av_free(mms->streams);
472 473 474 475 476 477
    av_free(mms->asf_header);
    av_freep(&h->priv_data);

    return 0;
}

478
static int send_media_packet_request(MMSTContext *mmst)
479
{
480 481
    MMSContext *mms = &mmst->mms;
    start_command_packet(mmst, CS_PKT_START_FROM_PKT_ID);
482 483 484 485 486 487 488 489 490
    insert_command_prefixes(mms, 1, 0x0001FFFF);
    bytestream_put_le64(&mms->write_out_ptr, 0);          // seek timestamp
    bytestream_put_le32(&mms->write_out_ptr, 0xffffffff); // unknown
    bytestream_put_le32(&mms->write_out_ptr, 0xffffffff); // packet offset
    bytestream_put_byte(&mms->write_out_ptr, 0xff);       // max stream time limit
    bytestream_put_byte(&mms->write_out_ptr, 0xff);       // max stream time limit
    bytestream_put_byte(&mms->write_out_ptr, 0xff);       // max stream time limit
    bytestream_put_byte(&mms->write_out_ptr, 0x00);       // stream time limit flag

491 492 493
    mmst->packet_id++;                                     // new packet_id
    bytestream_put_le32(&mms->write_out_ptr, mmst->packet_id);
    return send_command_packet(mmst);
494 495 496 497 498 499 500 501 502
}


static void clear_stream_buffers(MMSContext *mms)
{
    mms->remaining_in_len = 0;
    mms->read_in_ptr      = mms->in_buffer;
}

503 504
static int mms_open(URLContext *h, const char *uri, int flags)
{
505
    MMSTContext *mmst;
506 507 508 509 510
    MMSContext *mms;
    int port, err;
    char tcpname[256];

    h->is_streamed = 1;
511
    mmst = h->priv_data = av_mallocz(sizeof(MMSTContext));
512 513
    if (!h->priv_data)
        return AVERROR(ENOMEM);
514
    mms = &mmst->mms;
515 516

    // only for MMS over TCP, so set proto = NULL
517
    av_url_split(NULL, 0, NULL, 0,
518 519
            mmst->host, sizeof(mmst->host), &port, mmst->path,
            sizeof(mmst->path), uri);
520 521 522 523 524

    if(port<0)
        port = 1755; // defaut mms protocol port

    // establish tcp connection.
525
    ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, mmst->host, port, NULL);
526
    err = ffurl_open(&mms->mms_hd, tcpname, AVIO_FLAG_READ_WRITE);
527 528 529
    if (err)
        goto fail;

530 531 532
    mmst->packet_id        = 3;          // default, initial value.
    mmst->header_packet_id = 2;          // default, initial value.
    err = mms_safe_send_recv(mmst, send_startup_packet, SC_PKT_CLIENT_ACCEPTED);
533 534
    if (err)
        goto fail;
535
    err = mms_safe_send_recv(mmst, send_time_test_data, SC_PKT_TIMING_TEST_REPLY);
536 537
    if (err)
        goto fail;
538
    err = mms_safe_send_recv(mmst, send_protocol_select, SC_PKT_PROTOCOL_ACCEPTED);
539 540
    if (err)
        goto fail;
541
    err = mms_safe_send_recv(mmst, send_media_file_request, SC_PKT_MEDIA_FILE_DETAILS);
542 543
    if (err)
        goto fail;
544
    err = mms_safe_send_recv(mmst, send_media_header_request, SC_PKT_HEADER_REQUEST_ACCEPTED);
545 546
    if (err)
        goto fail;
547
    err = mms_safe_send_recv(mmst, NULL, SC_PKT_ASF_HEADER);
548 549
    if (err)
        goto fail;
550 551 552
    if((mmst->incoming_flags != 0X08) && (mmst->incoming_flags != 0X0C)) {
        av_log(NULL, AV_LOG_ERROR,
               "The server does not support MMST (try MMSH or RTSP)\n");
553
        err = AVERROR(EINVAL);
554
        goto fail;
555
    }
556
    err = ff_mms_asf_header_parser(mms);
557
    if (err) {
558
        av_dlog(NULL, "asf header parsed failed!\n");
559 560 561 562 563 564 565
        goto fail;
    }
    mms->header_parsed = 1;

    if (!mms->asf_packet_len || !mms->stream_num)
        goto fail;

566
    clear_stream_buffers(mms);
567
    err = mms_safe_send_recv(mmst, send_stream_selection_request, SC_PKT_STREAM_ID_ACCEPTED);
568 569 570
    if (err)
        goto fail;
    // send media packet request
571
    err = mms_safe_send_recv(mmst, send_media_packet_request, SC_PKT_MEDIA_PKT_FOLLOWS);
572 573 574
    if (err) {
        goto fail;
    }
575
    av_dlog(NULL, "Leaving open (success)\n");
576 577 578
    return 0;
fail:
    mms_close(h);
579
    av_dlog(NULL, "Leaving open (failure: %d)\n", err);
580 581 582 583 584 585 586
    return err;
}

/** Read ASF data through the protocol. */
static int mms_read(URLContext *h, uint8_t *buf, int size)
{
    /* TODO: see tcp.c:tcp_read() about a possible timeout scheme */
587 588
    MMSTContext *mmst = h->priv_data;
    MMSContext *mms   = &mmst->mms;
589
    int result = 0;
590

591 592 593
    do {
        if(mms->asf_header_read_size < mms->asf_header_size) {
            /* Read from ASF header buffer */
594
            result = ff_mms_read_header(mms, buf, size);
595 596 597
        } else if(mms->remaining_in_len) {
            /* Read remaining packet data to buffer.
             * the result can not be zero because remaining_in_len is positive.*/
598
            result = ff_mms_read_data(mms, buf, size);
599 600
        } else {
            /* Read from network */
601
            int err = mms_safe_send_recv(mmst, NULL, SC_PKT_ASF_MEDIA);
602 603 604 605 606
            if (err == 0) {
                if(mms->remaining_in_len>mms->asf_packet_len) {
                    av_log(NULL, AV_LOG_ERROR,
                           "Incoming pktlen %d is larger than ASF pktsize %d\n",
                           mms->remaining_in_len, mms->asf_packet_len);
607
                    result= AVERROR(EIO);
608 609
                } else {
                    // copy the data to the packet buffer.
610
                    result = ff_mms_read_data(mms, buf, size);
611
                    if (result == 0) {
612
                        av_dlog(NULL, "read asf media paket size is zero!\n");
613 614 615 616
                        break;
                    }
                }
            } else {
617
                av_dlog(NULL, "read packet error!\n");
618 619 620 621 622
                break;
            }
        }
    } while(!result); // only return one packet.
    return result;
623 624
}

625
URLProtocol ff_mmst_protocol = {
626 627 628 629
    .name      = "mmst",
    .url_open  = mms_open,
    .url_read  = mms_read,
    .url_close = mms_close,
630
};