mmst.c 23.1 KB
Newer Older
1 2 3
/*
 * MMS protocol over TCP
 * Copyright (c) 2006,2007 Ryan Martell
Luca Barbato's avatar
Luca Barbato committed
4
 * Copyright (c) 2007 Björn Axelsson
5 6
 * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
 *
7
 * This file is part of Libav.
8
 *
9
 * Libav is free software; you can redistribute it and/or
10 11 12 13
 * 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.
 *
14
 * Libav is distributed in the hope that it will be useful,
15 16 17 18 19
 * 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
20
 * License along with Libav; if not, write to the Free Software
21 22
 * 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
        av_log(NULL, AV_LOG_ERROR,
               "Failed to write data of length %d: %d (%s)\n",
               exact_length, write_result,
147
               write_result < 0 ? strerror(AVUNERROR(write_result)) :
148
                   "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;
Luca Barbato's avatar
Luca Barbato committed
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);
Luca Barbato's avatar
Luca Barbato committed
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
        if (read_result != 8) {
            if(read_result < 0) {
                av_log(NULL, AV_LOG_ERROR,
                       "Error reading packet header: %d (%s)\n",
249
                       read_result, strerror(AVUNERROR(read_result)));
250 251 252 253 254 255 256 257 258
                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;
        }

Ronald S. Bultje's avatar
Ronald S. Bultje committed
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);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
265 266 267 268
            if(read_result != 4) {
                av_log(NULL, AV_LOG_ERROR,
                       "Reading command packet length failed: %d (%s)\n",
                       read_result,
269
                       read_result < 0 ? strerror(AVUNERROR(read_result)) :
Ronald S. Bultje's avatar
Ronald S. Bultje committed
270
                           "The server closed the connection");
271
                return read_result < 0 ? read_result : AVERROR(EIO);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
272
            }
273

274
            length_remaining= AV_RL32(mms->in_buffer+8) + 4;
Luca Barbato's avatar
Luca Barbato committed
275
            av_dlog(NULL, "Length remaining is %d\n", length_remaining);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
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,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
285 286 287 288 289
                                            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,
290
                       read_result < 0 ? strerror(AVUNERROR(read_result)) :
Ronald S. Bultje's avatar
Ronald S. Bultje committed
291
                           "The server closed the connection");
292
                return read_result < 0 ? read_result : AVERROR(EIO);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
293 294
            }
            packet_type= AV_RL16(mms->in_buffer+36);
295
            if (read_result >= 44 && (hr = AV_RL32(mms->in_buffer + 40))) {
Ronald S. Bultje's avatar
Ronald S. Bultje committed
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);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
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);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
310
            packet_id_type            = mms->in_buffer[4];
311
            mmst->incoming_flags      = mms->in_buffer[5];
Ronald S. Bultje's avatar
Ronald S. Bultje committed
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);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
323 324 325 326
            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,
327
                       read_result < 0 ? strerror(AVUNERROR(read_result)) :
Ronald S. Bultje's avatar
Ronald S. Bultje committed
328
                           "The server closed the connection");
329
                return read_result < 0 ? read_result : AVERROR(EIO);
330 331
            }

Ronald S. Bultje's avatar
Ronald S. Bultje committed
332
            // if we successfully read everything.
333
            if(packet_id_type == mmst->header_packet_id) {
334
                int err;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
335 336 337
                packet_type = SC_PKT_ASF_HEADER;
                // Store the asf header
                if(!mms->header_parsed) {
338 339
                    if ((err = av_reallocp(&mms->asf_header,
                                           mms->asf_header_size +
340 341
                                           mms->remaining_in_len)) < 0) {
                        mms->asf_header_size = 0;
342
                        return err;
343
                    }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
344 345 346 347 348
                    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)
Ronald S. Bultje's avatar
Ronald S. Bultje committed
350
                    continue;
351
            } else if(packet_id_type == mmst->packet_id) {
Ronald S. Bultje's avatar
Ronald S. Bultje committed
352 353
                packet_type = SC_PKT_ASF_MEDIA;
            } else {
Luca Barbato's avatar
Luca Barbato committed
354
                av_dlog(NULL, "packet id type %d is old.", packet_id_type);
355 356
                continue;
            }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
357 358 359 360
        }

        // preprocess some packet type
        if(packet_type == SC_PKT_KEEPALIVE) {
361
            send_keepalive_packet(mmst);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
362 363
            continue;
        } else if(packet_type == SC_PKT_STREAM_CHANGING) {
364
            handle_packet_stream_changing_type(mmst);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
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) {
Luca Barbato's avatar
Luca Barbato committed
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
    av_free(mms->asf_header);

    return 0;
}

477
static int send_media_packet_request(MMSTContext *mmst)
478
{
479 480
    MMSContext *mms = &mmst->mms;
    start_command_packet(mmst, CS_PKT_START_FROM_PKT_ID);
481 482 483 484 485 486 487 488 489
    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

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


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

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

    h->is_streamed = 1;
510
    mms = &mmst->mms;
511 512

    // only for MMS over TCP, so set proto = NULL
Måns Rullgård's avatar
Måns Rullgård committed
513
    av_url_split(NULL, 0, NULL, 0,
514 515
            mmst->host, sizeof(mmst->host), &port, mmst->path,
            sizeof(mmst->path), uri);
516 517 518 519 520

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

    // establish tcp connection.
521
    ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, mmst->host, port, NULL);
522
    err = ffurl_open(&mms->mms_hd, tcpname, AVIO_FLAG_READ_WRITE,
523
                     &h->interrupt_callback, NULL);
524 525 526
    if (err)
        goto fail;

527 528 529
    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);
530 531
    if (err)
        goto fail;
532
    err = mms_safe_send_recv(mmst, send_time_test_data, SC_PKT_TIMING_TEST_REPLY);
533 534
    if (err)
        goto fail;
535
    err = mms_safe_send_recv(mmst, send_protocol_select, SC_PKT_PROTOCOL_ACCEPTED);
536 537
    if (err)
        goto fail;
538
    err = mms_safe_send_recv(mmst, send_media_file_request, SC_PKT_MEDIA_FILE_DETAILS);
539 540
    if (err)
        goto fail;
541
    err = mms_safe_send_recv(mmst, send_media_header_request, SC_PKT_HEADER_REQUEST_ACCEPTED);
542 543
    if (err)
        goto fail;
544
    err = mms_safe_send_recv(mmst, NULL, SC_PKT_ASF_HEADER);
545 546
    if (err)
        goto fail;
547 548 549
    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");
550
        err = AVERROR(EINVAL);
551
        goto fail;
552
    }
553
    err = ff_mms_asf_header_parser(mms);
554
    if (err) {
Luca Barbato's avatar
Luca Barbato committed
555
        av_dlog(NULL, "asf header parsed failed!\n");
556 557 558 559 560 561 562
        goto fail;
    }
    mms->header_parsed = 1;

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

Zhentan Feng's avatar
Zhentan Feng committed
563
    clear_stream_buffers(mms);
564
    err = mms_safe_send_recv(mmst, send_stream_selection_request, SC_PKT_STREAM_ID_ACCEPTED);
Zhentan Feng's avatar
Zhentan Feng committed
565 566 567
    if (err)
        goto fail;
    // send media packet request
568
    err = mms_safe_send_recv(mmst, send_media_packet_request, SC_PKT_MEDIA_PKT_FOLLOWS);
Zhentan Feng's avatar
Zhentan Feng committed
569 570 571
    if (err) {
        goto fail;
    }
Luca Barbato's avatar
Luca Barbato committed
572
    av_dlog(NULL, "Leaving open (success)\n");
573 574 575
    return 0;
fail:
    mms_close(h);
Luca Barbato's avatar
Luca Barbato committed
576
    av_dlog(NULL, "Leaving open (failure: %d)\n", err);
577 578 579 580 581 582 583
    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 */
584 585
    MMSTContext *mmst = h->priv_data;
    MMSContext *mms   = &mmst->mms;
586
    int result = 0;
587

588 589 590
    do {
        if(mms->asf_header_read_size < mms->asf_header_size) {
            /* Read from ASF header buffer */
591
            result = ff_mms_read_header(mms, buf, size);
592 593 594
        } else if(mms->remaining_in_len) {
            /* Read remaining packet data to buffer.
             * the result can not be zero because remaining_in_len is positive.*/
595
            result = ff_mms_read_data(mms, buf, size);
596 597
        } else {
            /* Read from network */
598
            int err = mms_safe_send_recv(mmst, NULL, SC_PKT_ASF_MEDIA);
599 600 601 602 603
            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);
604
                    result= AVERROR(EIO);
605 606
                } else {
                    // copy the data to the packet buffer.
607
                    result = ff_mms_read_data(mms, buf, size);
608
                    if (result == 0) {
Diego Biurrun's avatar
Diego Biurrun committed
609
                        av_dlog(NULL, "Read ASF media packet size is zero!\n");
610 611 612 613
                        break;
                    }
                }
            } else {
Luca Barbato's avatar
Luca Barbato committed
614
                av_dlog(NULL, "read packet error!\n");
615 616 617 618 619
                break;
            }
        }
    } while(!result); // only return one packet.
    return result;
620 621
}

622
URLProtocol ff_mmst_protocol = {
623 624 625 626
    .name           = "mmst",
    .url_open       = mms_open,
    .url_read       = mms_read,
    .url_close      = mms_close,
627
    .priv_data_size = sizeof(MMSTContext),
628
    .flags          = URL_PROTOCOL_FLAG_NETWORK,
629
};