mms: remove dependency on MAX_STREAM API
[ffmpeg.git] / libavformat / mms.c
1 /*
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>
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 #include "mms.h"
24 #include "asf.h"
25 #include "libavutil/intreadwrite.h"
26
27 #if FF_API_MAX_STREAMS
28 #define MMS_MAX_STREAMS MAX_STREAMS
29 #else
30 #define MMS_MAX_STREAMS 256    /**< arbitrary sanity check value */
31 #endif
32
33 int ff_mms_read_header(MMSContext *mms, uint8_t *buf, const int size)
34 {
35     char *pos;
36     int size_to_copy;
37     int remaining_size = mms->asf_header_size - mms->asf_header_read_size;
38     size_to_copy = FFMIN(size, remaining_size);
39     pos = mms->asf_header + mms->asf_header_read_size;
40     memcpy(buf, pos, size_to_copy);
41     if (mms->asf_header_read_size == mms->asf_header_size) {
42         av_freep(&mms->asf_header); // which contains asf header
43     }
44     mms->asf_header_read_size += size_to_copy;
45     return size_to_copy;
46 }
47
48 int ff_mms_read_data(MMSContext *mms, uint8_t *buf, const int size)
49 {
50     int read_size;
51     read_size = FFMIN(size, mms->remaining_in_len);
52     memcpy(buf, mms->read_in_ptr, read_size);
53     mms->remaining_in_len -= read_size;
54     mms->read_in_ptr      += read_size;
55     return read_size;
56 }
57
58 int ff_mms_asf_header_parser(MMSContext *mms)
59 {
60     uint8_t *p = mms->asf_header;
61     uint8_t *end;
62     int flags, stream_id;
63     mms->stream_num = 0;
64
65     if (mms->asf_header_size < sizeof(ff_asf_guid) * 2 + 22 ||
66         memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) {
67         av_log(NULL, AV_LOG_ERROR,
68                "Corrupt stream (invalid ASF header, size=%d)\n",
69                mms->asf_header_size);
70         return AVERROR_INVALIDDATA;
71     }
72
73     end = mms->asf_header + mms->asf_header_size;
74
75     p += sizeof(ff_asf_guid) + 14;
76     while(end - p >= sizeof(ff_asf_guid) + 8) {
77         uint64_t chunksize;
78         if (!memcmp(p, ff_asf_data_header, sizeof(ff_asf_guid))) {
79             chunksize = 50; // see Reference [2] section 5.1
80         } else {
81             chunksize = AV_RL64(p + sizeof(ff_asf_guid));
82         }
83         if (!chunksize || chunksize > end - p) {
84             av_log(NULL, AV_LOG_ERROR,
85                    "Corrupt stream (header chunksize %"PRId64" is invalid)\n",
86                    chunksize);
87             return AVERROR_INVALIDDATA;
88         }
89         if (!memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
90             /* read packet size */
91             if (end - p > sizeof(ff_asf_guid) * 2 + 68) {
92                 mms->asf_packet_len = AV_RL32(p + sizeof(ff_asf_guid) * 2 + 64);
93                 if (mms->asf_packet_len <= 0 || mms->asf_packet_len > sizeof(mms->in_buffer)) {
94                     av_log(NULL, AV_LOG_ERROR,
95                            "Corrupt stream (too large pkt_len %d)\n",
96                            mms->asf_packet_len);
97                     return AVERROR_INVALIDDATA;
98                 }
99             }
100         } else if (!memcmp(p, ff_asf_stream_header, sizeof(ff_asf_guid))) {
101             flags     = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24);
102             stream_id = flags & 0x7F;
103             //The second condition is for checking CS_PKT_STREAM_ID_REQUEST packet size,
104             //we can calcuate the packet size by stream_num.
105             //Please see function send_stream_selection_request().
106             if (mms->stream_num < MMS_MAX_STREAMS &&
107                     46 + mms->stream_num * 6 < sizeof(mms->out_buffer)) {
108                 mms->streams = av_fast_realloc(mms->streams,
109                                    &mms->nb_streams_allocated,
110                                    (mms->stream_num + 1) * sizeof(MMSStream));
111                 mms->streams[mms->stream_num].id = stream_id;
112                 mms->stream_num++;
113             } else {
114                 av_log(NULL, AV_LOG_ERROR,
115                        "Corrupt stream (too many A/V streams)\n");
116                 return AVERROR_INVALIDDATA;
117             }
118         } else if (!memcmp(p, ff_asf_head1_guid, sizeof(ff_asf_guid))) {
119             chunksize = 46; // see references [2] section 3.4. This should be set 46.
120         }
121         p += chunksize;
122     }
123
124     return 0;
125 }