2 * MMS protocol common definitions.
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>
7 * This file is part of FFmpeg.
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.
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.
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
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/mem.h"
28 #define MMS_MAX_STREAMS 256 /**< arbitrary sanity check value */
30 int ff_mms_read_header(MMSContext
*mms
, uint8_t *buf
, const int size
)
34 int remaining_size
= mms
->asf_header_size
- mms
->asf_header_read_size
;
35 size_to_copy
= FFMIN(size
, remaining_size
);
36 pos
= mms
->asf_header
+ mms
->asf_header_read_size
;
37 memcpy(buf
, pos
, size_to_copy
);
38 if (mms
->asf_header_read_size
== mms
->asf_header_size
) {
39 av_freep(&mms
->asf_header
); // which contains asf header
41 mms
->asf_header_read_size
+= size_to_copy
;
45 int ff_mms_read_data(MMSContext
*mms
, uint8_t *buf
, const int size
)
48 read_size
= FFMIN(size
, mms
->remaining_in_len
);
49 memcpy(buf
, mms
->read_in_ptr
, read_size
);
50 mms
->remaining_in_len
-= read_size
;
51 mms
->read_in_ptr
+= read_size
;
55 int ff_mms_asf_header_parser(MMSContext
*mms
)
57 uint8_t *p
= mms
->asf_header
;
62 if (mms
->asf_header_size
< sizeof(ff_asf_guid
) * 2 + 22 ||
63 memcmp(p
, ff_asf_header
, sizeof(ff_asf_guid
))) {
64 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
65 "Corrupt stream (invalid ASF header, size=%d)\n",
66 mms
->asf_header_size
);
67 return AVERROR_INVALIDDATA
;
70 end
= mms
->asf_header
+ mms
->asf_header_size
;
72 p
+= sizeof(ff_asf_guid
) + 14;
73 while(end
- p
>= sizeof(ff_asf_guid
) + 8) {
75 if (!memcmp(p
, ff_asf_data_header
, sizeof(ff_asf_guid
))) {
76 chunksize
= 50; // see Reference [2] section 5.1
78 chunksize
= AV_RL64(p
+ sizeof(ff_asf_guid
));
80 if (!chunksize
|| chunksize
> end
- p
) {
81 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
82 "Corrupt stream (header chunksize %"PRId64
" is invalid)\n",
84 return AVERROR_INVALIDDATA
;
86 if (!memcmp(p
, ff_asf_file_header
, sizeof(ff_asf_guid
))) {
87 /* read packet size */
88 if (end
- p
> sizeof(ff_asf_guid
) * 2 + 68) {
89 mms
->asf_packet_len
= AV_RL32(p
+ sizeof(ff_asf_guid
) * 2 + 64);
90 if (mms
->asf_packet_len
<= 0 || mms
->asf_packet_len
> sizeof(mms
->in_buffer
)) {
91 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
92 "Corrupt stream (too large pkt_len %d)\n",
94 return AVERROR_INVALIDDATA
;
97 } else if (!memcmp(p
, ff_asf_stream_header
, sizeof(ff_asf_guid
))) {
98 if (end
- p
>= (sizeof(ff_asf_guid
) * 3 + 26)) {
99 flags
= AV_RL16(p
+ sizeof(ff_asf_guid
)*3 + 24);
100 stream_id
= flags
& 0x7F;
101 //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size,
102 //we can calculate the packet size by stream_num.
103 //Please see function send_stream_selection_request().
104 if (mms
->stream_num
< MMS_MAX_STREAMS
&&
105 46 + mms
->stream_num
* 6 < sizeof(mms
->out_buffer
)) {
106 mms
->streams
= av_fast_realloc(mms
->streams
,
107 &mms
->nb_streams_allocated
,
108 (mms
->stream_num
+ 1) * sizeof(MMSStream
));
110 return AVERROR(ENOMEM
);
111 mms
->streams
[mms
->stream_num
].id
= stream_id
;
114 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
115 "Corrupt stream (too many A/V streams)\n");
116 return AVERROR_INVALIDDATA
;
119 } else if (!memcmp(p
, ff_asf_ext_stream_header
, sizeof(ff_asf_guid
))) {
121 int stream_count
= AV_RL16(p
+ 84), ext_len_count
= AV_RL16(p
+ 86);
122 uint64_t skip_bytes
= 88;
123 while (stream_count
--) {
124 if (end
- p
< skip_bytes
+ 4) {
125 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
126 "Corrupt stream (next stream name length is not in the buffer)\n");
127 return AVERROR_INVALIDDATA
;
129 skip_bytes
+= 4 + AV_RL16(p
+ skip_bytes
+ 2);
131 while (ext_len_count
--) {
132 if (end
- p
< skip_bytes
+ 22) {
133 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
134 "Corrupt stream (next extension system info length is not in the buffer)\n");
135 return AVERROR_INVALIDDATA
;
137 skip_bytes
+= 22 + AV_RL32(p
+ skip_bytes
+ 18);
139 if (end
- p
< skip_bytes
) {
140 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
141 "Corrupt stream (the last extension system info length is invalid)\n");
142 return AVERROR_INVALIDDATA
;
144 if (chunksize
- skip_bytes
> 24)
145 chunksize
= skip_bytes
;
147 } else if (!memcmp(p
, ff_asf_head1_guid
, sizeof(ff_asf_guid
))) {
148 chunksize
= 46; // see references [2] section 3.4. This should be set 46.
149 if (chunksize
> end
- p
) {
150 av_log(mms
->mms_hd
, AV_LOG_ERROR
,
151 "Corrupt stream (header chunksize %"PRId64
" is invalid)\n",
153 return AVERROR_INVALIDDATA
;