FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mmst.c
Go to the documentation of this file.
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 "mms.h"
33 #include "internal.h"
34 #include "avio_internal.h"
35 #include "libavutil/intreadwrite.h"
36 #include "libavcodec/bytestream.h"
37 #include "network.h"
38 #include "url.h"
39 
40 #define LOCAL_ADDRESS 0xc0a80081 // FIXME get and use correct local ip address.
41 #define LOCAL_PORT 1037 // as above.
42 /** Client to server packet types. */
43 typedef enum {
56 
57 /** Server to client packet types. */
58 typedef enum {
59  /** Control packets. */
60  /*@{*/
73  /*@}*/
74 
75  /** Pseudo packets. */
76  /*@{*/
79  /*@}*/
80 
81  /** Data packets. */
82  /*@{*/
83  SC_PKT_ASF_HEADER = 0x010000,// make it bigger than 0xFF in case of
84  SC_PKT_ASF_MEDIA = 0x010001,// receiving false data packets.
85  /*@}*/
87 
88 typedef struct {
90  int outgoing_packet_seq; ///< Outgoing packet sequence number.
91  char path[256]; ///< Path of the resource being asked for.
92  char host[128]; ///< Host of the resources.
93  int incoming_packet_seq; ///< Incoming packet sequence number.
94  int incoming_flags; ///< Incoming packet flags.
95  int packet_id; ///< Identifier for packets in the current stream.
96  unsigned int header_packet_id; ///< default is 2.
97 } MMSTContext;
98 
99 /** Create MMST command packet header */
100 static void start_command_packet(MMSTContext *mmst, MMSCSPacketType packet_type)
101 {
102  MMSContext *mms = &mmst->mms;
103  mms->write_out_ptr = mms->out_buffer;
104 
105  bytestream_put_le32(&mms->write_out_ptr, 1); // start sequence
106  bytestream_put_le32(&mms->write_out_ptr, 0xb00bface);
107  bytestream_put_le32(&mms->write_out_ptr, 0); // Length starts from after the protocol type bytes
108  bytestream_put_le32(&mms->write_out_ptr, MKTAG('M','M','S',' '));
109  bytestream_put_le32(&mms->write_out_ptr, 0);
110  bytestream_put_le32(&mms->write_out_ptr, mmst->outgoing_packet_seq++);
111  bytestream_put_le64(&mms->write_out_ptr, 0); // timestamp
112  bytestream_put_le32(&mms->write_out_ptr, 0);
113  bytestream_put_le16(&mms->write_out_ptr, packet_type);
114  bytestream_put_le16(&mms->write_out_ptr, 3); // direction to server
115 }
116 
117 /** Add prefixes to MMST command packet. */
119  uint32_t prefix1, uint32_t prefix2)
120 {
121  bytestream_put_le32(&mms->write_out_ptr, prefix1); // first prefix
122  bytestream_put_le32(&mms->write_out_ptr, prefix2); // second prefix
123 }
124 
125 /** Send a prepared MMST command packet. */
127 {
128  MMSContext *mms = &mmst->mms;
129  int len= mms->write_out_ptr - mms->out_buffer;
130  int exact_length = FFALIGN(len, 8);
131  int first_length= exact_length - 16;
132  int len8= first_length/8;
133  int write_result;
134 
135  // update packet length fields.
136  AV_WL32(mms->out_buffer + 8, first_length);
137  AV_WL32(mms->out_buffer + 16, len8);
138  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  av_log(NULL, AV_LOG_ERROR,
145  "Failed to write data of length %d: %d (%s)\n",
146  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  return 0;
153 }
154 
155 static int mms_put_utf16(MMSContext *mms, const uint8_t *src)
156 {
157  AVIOContext bic;
158  int size = mms->write_out_ptr - mms->out_buffer;
159  int len;
160  ffio_init_context(&bic, mms->write_out_ptr,
161  sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL);
162 
163  len = avio_put_str16le(&bic, src);
164  if (len < 0)
165  return len;
166  mms->write_out_ptr += len;
167  return 0;
168 }
169 
171 {
173  insert_command_prefixes(&mmst->mms, 0x00f0f0f0, 0x0004000b);
174  return send_command_packet(mmst);
175 }
176 
178 {
179  int ret;
180  char data_string[256];
181  MMSContext *mms = &mmst->mms;
182 
184  insert_command_prefixes(mms, 0, 0xffffffff);
185  bytestream_put_le32(&mms->write_out_ptr, 0); // maxFunnelBytes
186  bytestream_put_le32(&mms->write_out_ptr, 0x00989680); // maxbitRate
187  bytestream_put_le32(&mms->write_out_ptr, 2); // funnelMode
188  snprintf(data_string, sizeof(data_string), "\\\\%d.%d.%d.%d\\%s\\%d",
189  (LOCAL_ADDRESS>>24)&0xff,
190  (LOCAL_ADDRESS>>16)&0xff,
191  (LOCAL_ADDRESS>>8)&0xff,
192  LOCAL_ADDRESS&0xff,
193  "TCP", // or UDP
194  LOCAL_PORT);
195 
196  if ((ret = mms_put_utf16(mms, data_string)) < 0)
197  return ret;
198  return send_command_packet(mmst);
199 }
200 
202 {
203  int ret;
204  MMSContext *mms = &mmst->mms;
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  if ((ret = mms_put_utf16(mms, mmst->path + 1)) < 0) // +1 for skip "/"
210  return ret;
211 
212  return send_command_packet(mmst);
213 }
214 
216 {
217  MMSContext *mms = &mmst->mms;
218  av_dlog(NULL, "Stream changing!\n");
219 
220  // 40 is the packet header size, 7 is the prefix size.
221  mmst->header_packet_id= AV_RL32(mms->in_buffer + 40 + 7);
222  av_dlog(NULL, "Changed header prefix to 0x%x", mmst->header_packet_id);
223 }
224 
226 {
227  // respond to a keepalive with a keepalive...
229  insert_command_prefixes(&mmst->mms, 1, 0x100FFFF);
230  return send_command_packet(mmst);
231 }
232 
233 /** Pad media packets smaller than max_packet_size and/or adjust read position
234  * after a seek. */
235 static void pad_media_packet(MMSContext *mms)
236 {
237  if(mms->remaining_in_len<mms->asf_packet_len) {
238  int padding_size = mms->asf_packet_len - mms->remaining_in_len;
239  memset(mms->in_buffer + mms->remaining_in_len, 0, padding_size);
240  mms->remaining_in_len += padding_size;
241  }
242 }
243 
244 /** Read incoming MMST media, header or command packet. */
246 {
247  int read_result;
248  MMSSCPacketType packet_type= -1;
249  MMSContext *mms = &mmst->mms;
250  for(;;) {
251  read_result = ffurl_read_complete(mms->mms_hd, mms->in_buffer, 8);
252  if (read_result != 8) {
253  if(read_result < 0) {
254  av_log(NULL, AV_LOG_ERROR,
255  "Error reading packet header: %d (%s)\n",
256  read_result, strerror(AVUNERROR(read_result)));
257  packet_type = SC_PKT_CANCEL;
258  } else {
259  av_log(NULL, AV_LOG_ERROR,
260  "The server closed the connection\n");
261  packet_type = SC_PKT_NO_DATA;
262  }
263  return packet_type;
264  }
265 
266  // handle command packet.
267  if(AV_RL32(mms->in_buffer + 4)==0xb00bface) {
268  int length_remaining, hr;
269 
270  mmst->incoming_flags= mms->in_buffer[3];
271  read_result= ffurl_read_complete(mms->mms_hd, mms->in_buffer+8, 4);
272  if(read_result != 4) {
273  av_log(NULL, AV_LOG_ERROR,
274  "Reading command packet length failed: %d (%s)\n",
275  read_result,
276  read_result < 0 ? strerror(AVUNERROR(read_result)) :
277  "The server closed the connection");
278  return read_result < 0 ? read_result : AVERROR(EIO);
279  }
280 
281  length_remaining= AV_RL32(mms->in_buffer+8) + 4;
282  av_dlog(NULL, "Length remaining is %d\n", length_remaining);
283  // read the rest of the packet.
284  if (length_remaining < 0
285  || length_remaining > sizeof(mms->in_buffer) - 12) {
286  av_log(NULL, AV_LOG_ERROR,
287  "Incoming packet length %d exceeds bufsize %"SIZE_SPECIFIER"\n",
288  length_remaining, sizeof(mms->in_buffer) - 12);
289  return AVERROR_INVALIDDATA;
290  }
291  read_result = ffurl_read_complete(mms->mms_hd, mms->in_buffer + 12,
292  length_remaining) ;
293  if (read_result != length_remaining) {
294  av_log(NULL, AV_LOG_ERROR,
295  "Reading pkt data (length=%d) failed: %d (%s)\n",
296  length_remaining, read_result,
297  read_result < 0 ? strerror(AVUNERROR(read_result)) :
298  "The server closed the connection");
299  return read_result < 0 ? read_result : AVERROR(EIO);
300  }
301  packet_type= AV_RL16(mms->in_buffer+36);
302  if (read_result >= 44 && (hr = AV_RL32(mms->in_buffer + 40))) {
303  av_log(NULL, AV_LOG_ERROR,
304  "Server sent a message with packet type 0x%x and error status code 0x%08x\n", packet_type, hr);
305  return AVERROR(EINVAL);
306  }
307  } else {
308  int length_remaining;
309  int packet_id_type;
310  int tmp;
311 
312  // note we cache the first 8 bytes,
313  // then fill up the buffer with the others
314  tmp = AV_RL16(mms->in_buffer + 6);
315  length_remaining = (tmp - 8) & 0xffff;
316  mmst->incoming_packet_seq = AV_RL32(mms->in_buffer);
317  packet_id_type = mms->in_buffer[4];
318  mmst->incoming_flags = mms->in_buffer[5];
319 
320  if (length_remaining < 0
321  || length_remaining > sizeof(mms->in_buffer) - 8) {
322  av_log(NULL, AV_LOG_ERROR,
323  "Data length %d is invalid or too large (max=%"SIZE_SPECIFIER")\n",
324  length_remaining, sizeof(mms->in_buffer));
325  return AVERROR_INVALIDDATA;
326  }
327  mms->remaining_in_len = length_remaining;
328  mms->read_in_ptr = mms->in_buffer;
329  read_result= ffurl_read_complete(mms->mms_hd, mms->in_buffer, length_remaining);
330  if(read_result != length_remaining) {
331  av_log(NULL, AV_LOG_ERROR,
332  "Failed to read packet data of size %d: %d (%s)\n",
333  length_remaining, read_result,
334  read_result < 0 ? strerror(AVUNERROR(read_result)) :
335  "The server closed the connection");
336  return read_result < 0 ? read_result : AVERROR(EIO);
337  }
338 
339  // if we successfully read everything.
340  if(packet_id_type == mmst->header_packet_id) {
341  int err;
342  packet_type = SC_PKT_ASF_HEADER;
343  // Store the asf header
344  if(!mms->header_parsed) {
345  if ((err = av_reallocp(&mms->asf_header,
346  mms->asf_header_size +
347  mms->remaining_in_len)) < 0) {
348  mms->asf_header_size = 0;
349  return err;
350  }
351  memcpy(mms->asf_header + mms->asf_header_size,
352  mms->read_in_ptr, mms->remaining_in_len);
353  mms->asf_header_size += mms->remaining_in_len;
354  }
355  // 0x04 means asf header is sent in multiple packets.
356  if (mmst->incoming_flags == 0x04)
357  continue;
358  } else if(packet_id_type == mmst->packet_id) {
359  packet_type = SC_PKT_ASF_MEDIA;
360  } else {
361  av_dlog(NULL, "packet id type %d is old.", packet_id_type);
362  continue;
363  }
364  }
365 
366  // preprocess some packet type
367  if(packet_type == SC_PKT_KEEPALIVE) {
368  send_keepalive_packet(mmst);
369  continue;
370  } else if(packet_type == SC_PKT_STREAM_CHANGING) {
372  } else if(packet_type == SC_PKT_ASF_MEDIA) {
373  pad_media_packet(mms);
374  }
375  return packet_type;
376  }
377 }
378 
380  int (*send_fun)(MMSTContext *mmst),
381  const MMSSCPacketType expect_type)
382 {
384  if(send_fun) {
385  int ret = send_fun(mmst);
386  if (ret < 0) {
387  av_dlog(NULL, "Send Packet error before expecting recv packet %d\n", expect_type);
388  return ret;
389  }
390  }
391 
392  if ((type = get_tcp_server_response(mmst)) != expect_type) {
393  av_log(NULL, AV_LOG_ERROR,
394  "Corrupt stream (unexpected packet type 0x%x, expected 0x%x)\n",
395  type, expect_type);
396  return AVERROR_INVALIDDATA;
397  } else {
398  return 0;
399  }
400 }
401 
403 {
404  MMSContext *mms = &mmst->mms;
406  insert_command_prefixes(mms, 1, 0);
407  bytestream_put_le32(&mms->write_out_ptr, 0);
408  bytestream_put_le32(&mms->write_out_ptr, 0x00800000);
409  bytestream_put_le32(&mms->write_out_ptr, 0xffffffff);
410  bytestream_put_le32(&mms->write_out_ptr, 0);
411  bytestream_put_le32(&mms->write_out_ptr, 0);
412  bytestream_put_le32(&mms->write_out_ptr, 0);
413 
414  // the media preroll value in milliseconds?
415  bytestream_put_le32(&mms->write_out_ptr, 0);
416  bytestream_put_le32(&mms->write_out_ptr, 0x40AC2000);
417  bytestream_put_le32(&mms->write_out_ptr, 2);
418  bytestream_put_le32(&mms->write_out_ptr, 0);
419 
420  return send_command_packet(mmst);
421 }
422 
423 /** Send the initial handshake. */
425 {
426  char data_string[256];
427  int ret;
428  MMSContext *mms = &mmst->mms;
429  // SubscriberName is defined in MS specification linked below.
430  // The guid value can be any valid value.
431  // http://download.microsoft.com/
432  // download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-WMSP%5D.pdf
433  snprintf(data_string, sizeof(data_string),
434  "NSPlayer/7.0.0.1956; {%s}; Host: %s",
435  "7E667F5D-A661-495E-A512-F55686DDA178", mmst->host);
436 
438  insert_command_prefixes(mms, 0, 0x0004000b);
439  bytestream_put_le32(&mms->write_out_ptr, 0x0003001c);
440  if ((ret = mms_put_utf16(mms, data_string)) < 0)
441  return ret;
442  return send_command_packet(mmst);
443 }
444 
445 /** Send MMST stream selection command based on the AVStream->discard values. */
447 {
448  int i;
449  MMSContext *mms = &mmst->mms;
450  // send the streams we want back...
452  bytestream_put_le32(&mms->write_out_ptr, mms->stream_num); // stream nums
453  for(i= 0; i<mms->stream_num; i++) {
454  bytestream_put_le16(&mms->write_out_ptr, 0xffff); // flags
455  bytestream_put_le16(&mms->write_out_ptr, mms->streams[i].id); // stream id
456  bytestream_put_le16(&mms->write_out_ptr, 0); // selection
457  }
458  return send_command_packet(mmst);
459 }
460 
462 {
464  insert_command_prefixes(&mmst->mms, 1, 1);
465 
466  return send_command_packet(mmst);
467 }
468 
469 /** Close the MMSH/MMST connection */
470 static int mms_close(URLContext *h)
471 {
472  MMSTContext *mmst = (MMSTContext *)h->priv_data;
473  MMSContext *mms = &mmst->mms;
474  if(mms->mms_hd) {
475  send_close_packet(mmst);
476  ffurl_close(mms->mms_hd);
477  }
478 
479  /* free all separately allocated pointers in mms */
480  av_free(mms->streams);
481  av_free(mms->asf_header);
482 
483  return 0;
484 }
485 
487 {
488  MMSContext *mms = &mmst->mms;
490  insert_command_prefixes(mms, 1, 0x0001FFFF);
491  bytestream_put_le64(&mms->write_out_ptr, 0); // seek timestamp
492  bytestream_put_le32(&mms->write_out_ptr, 0xffffffff); // unknown
493  bytestream_put_le32(&mms->write_out_ptr, 0xffffffff); // packet offset
494  bytestream_put_byte(&mms->write_out_ptr, 0xff); // max stream time limit
495  bytestream_put_byte(&mms->write_out_ptr, 0xff); // max stream time limit
496  bytestream_put_byte(&mms->write_out_ptr, 0xff); // max stream time limit
497  bytestream_put_byte(&mms->write_out_ptr, 0x00); // stream time limit flag
498 
499  mmst->packet_id++; // new packet_id
500  bytestream_put_le32(&mms->write_out_ptr, mmst->packet_id);
501  return send_command_packet(mmst);
502 }
503 
504 
506 {
507  mms->remaining_in_len = 0;
508  mms->read_in_ptr = mms->in_buffer;
509 }
510 
511 static int mms_open(URLContext *h, const char *uri, int flags)
512 {
513  MMSTContext *mmst = h->priv_data;
514  MMSContext *mms;
515  int port, err;
516  char tcpname[256];
517 
518  h->is_streamed = 1;
519  mms = &mmst->mms;
520 
521  // only for MMS over TCP, so set proto = NULL
522  av_url_split(NULL, 0, NULL, 0,
523  mmst->host, sizeof(mmst->host), &port, mmst->path,
524  sizeof(mmst->path), uri);
525 
526  if(port<0)
527  port = 1755; // defaut mms protocol port
528 
529  // establish tcp connection.
530  ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, mmst->host, port, NULL);
531  err = ffurl_open(&mms->mms_hd, tcpname, AVIO_FLAG_READ_WRITE,
532  &h->interrupt_callback, NULL);
533  if (err)
534  goto fail;
535 
536  mmst->packet_id = 3; // default, initial value.
537  mmst->header_packet_id = 2; // default, initial value.
539  if (err)
540  goto fail;
542  if (err)
543  goto fail;
545  if (err)
546  goto fail;
548  if (err)
549  goto fail;
551  if (err)
552  goto fail;
553  err = mms_safe_send_recv(mmst, NULL, SC_PKT_ASF_HEADER);
554  if (err)
555  goto fail;
556  if((mmst->incoming_flags != 0X08) && (mmst->incoming_flags != 0X0C)) {
557  av_log(NULL, AV_LOG_ERROR,
558  "The server does not support MMST (try MMSH or RTSP)\n");
559  err = AVERROR(EINVAL);
560  goto fail;
561  }
562  err = ff_mms_asf_header_parser(mms);
563  if (err) {
564  av_dlog(NULL, "asf header parsed failed!\n");
565  goto fail;
566  }
567  mms->header_parsed = 1;
568 
569  if (!mms->asf_packet_len || !mms->stream_num)
570  goto fail;
571 
574  if (err)
575  goto fail;
576  // send media packet request
578  if (err) {
579  goto fail;
580  }
581  av_dlog(NULL, "Leaving open (success)\n");
582  return 0;
583 fail:
584  mms_close(h);
585  av_dlog(NULL, "Leaving open (failure: %d)\n", err);
586  return err;
587 }
588 
589 /** Read ASF data through the protocol. */
590 static int mms_read(URLContext *h, uint8_t *buf, int size)
591 {
592  /* TODO: see tcp.c:tcp_read() about a possible timeout scheme */
593  MMSTContext *mmst = h->priv_data;
594  MMSContext *mms = &mmst->mms;
595  int result = 0;
596 
597  do {
598  if(mms->asf_header_read_size < mms->asf_header_size) {
599  /* Read from ASF header buffer */
600  result = ff_mms_read_header(mms, buf, size);
601  } else if(mms->remaining_in_len) {
602  /* Read remaining packet data to buffer.
603  * the result can not be zero because remaining_in_len is positive.*/
604  result = ff_mms_read_data(mms, buf, size);
605  } else {
606  /* Read from network */
607  int err = mms_safe_send_recv(mmst, NULL, SC_PKT_ASF_MEDIA);
608  if (err == 0) {
609  if(mms->remaining_in_len>mms->asf_packet_len) {
610  av_log(NULL, AV_LOG_ERROR,
611  "Incoming pktlen %d is larger than ASF pktsize %d\n",
612  mms->remaining_in_len, mms->asf_packet_len);
613  result= AVERROR(EIO);
614  } else {
615  // copy the data to the packet buffer.
616  result = ff_mms_read_data(mms, buf, size);
617  if (result == 0) {
618  av_dlog(NULL, "Read ASF media packet size is zero!\n");
619  break;
620  }
621  }
622  } else {
623  av_dlog(NULL, "read packet error!\n");
624  break;
625  }
626  }
627  } while(!result); // only return one packet.
628  return result;
629 }
630 
632  .name = "mmst",
633  .url_open = mms_open,
634  .url_read = mms_read,
635  .url_close = mms_close,
636  .priv_data_size = sizeof(MMSTContext),
638 };