Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * Microsoft RTP/ASF support.
3
 * Copyright (c) 2008 Ronald S. Bultje
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
 
22
/**
23
 * @file
24
 * @brief Microsoft RTP/ASF support
25
 * @author Ronald S. Bultje 
26
 */
27
 
28
#include "libavutil/base64.h"
29
#include "libavutil/avstring.h"
30
#include "libavutil/intreadwrite.h"
31
#include "rtp.h"
32
#include "rtpdec_formats.h"
33
#include "rtsp.h"
34
#include "asf.h"
35
#include "avio_internal.h"
36
#include "internal.h"
37
 
38
/**
39
 * From MSDN 2.2.1.4, we learn that ASF data packets over RTP should not
40
 * contain any padding. Unfortunately, the header min/max_pktsize are not
41
 * updated (thus making min_pktsize invalid). Here, we "fix" these faulty
42
 * min_pktsize values in the ASF file header.
43
 * @return 0 on success, <0 on failure (currently -1).
44
 */
45
static int rtp_asf_fix_header(uint8_t *buf, int len)
46
{
47
    uint8_t *p = buf, *end = buf + len;
48
 
49
    if (len < sizeof(ff_asf_guid) * 2 + 22 ||
50
        memcmp(p, ff_asf_header, sizeof(ff_asf_guid))) {
51
        return -1;
52
    }
53
    p += sizeof(ff_asf_guid) + 14;
54
    do {
55
        uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid));
56
        if (memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
57
            if (chunksize > end - p)
58
                return -1;
59
            p += chunksize;
60
            continue;
61
        }
62
 
63
        /* skip most of the file header, to min_pktsize */
64
        p += 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2;
65
        if (p + 8 <= end && AV_RL32(p) == AV_RL32(p + 4)) {
66
            /* and set that to zero */
67
            AV_WL32(p, 0);
68
            return 0;
69
        }
70
        break;
71
    } while (end - p >= sizeof(ff_asf_guid) + 8);
72
 
73
    return -1;
74
}
75
 
76
/**
77
 * The following code is basically a buffered AVIOContext,
78
 * with the added benefit of returning -EAGAIN (instead of 0)
79
 * on packet boundaries, such that the ASF demuxer can return
80
 * safely and resume business at the next packet.
81
 */
82
static int packetizer_read(void *opaque, uint8_t *buf, int buf_size)
83
{
84
    return AVERROR(EAGAIN);
85
}
86
 
87
static void init_packetizer(AVIOContext *pb, uint8_t *buf, int len)
88
{
89
    ffio_init_context(pb, buf, len, 0, NULL, packetizer_read, NULL, NULL);
90
 
91
    /* this "fills" the buffer with its current content */
92
    pb->pos     = len;
93
    pb->buf_end = buf + len;
94
}
95
 
96
int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p)
97
{
98
    int ret = 0;
99
    if (av_strstart(p, "pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,", &p)) {
100
        AVIOContext pb;
101
        RTSPState *rt = s->priv_data;
102
        AVDictionary *opts = NULL;
103
        int len = strlen(p) * 6 / 8;
104
        char *buf = av_mallocz(len);
105
        av_base64_decode(buf, p, len);
106
 
107
        if (rtp_asf_fix_header(buf, len) < 0)
108
            av_log(s, AV_LOG_ERROR,
109
                   "Failed to fix invalid RTSP-MS/ASF min_pktsize\n");
110
        init_packetizer(&pb, buf, len);
111
        if (rt->asf_ctx) {
112
            avformat_close_input(&rt->asf_ctx);
113
        }
114
        if (!(rt->asf_ctx = avformat_alloc_context()))
115
            return AVERROR(ENOMEM);
116
        rt->asf_ctx->pb      = &pb;
117
        av_dict_set(&opts, "no_resync_search", "1", 0);
118
        ret = avformat_open_input(&rt->asf_ctx, "", &ff_asf_demuxer, &opts);
119
        av_dict_free(&opts);
120
        if (ret < 0)
121
            return ret;
122
        av_dict_copy(&s->metadata, rt->asf_ctx->metadata, 0);
123
        rt->asf_pb_pos = avio_tell(&pb);
124
        av_free(buf);
125
        rt->asf_ctx->pb = NULL;
126
    }
127
    return ret;
128
}
129
 
130
static int asfrtp_parse_sdp_line(AVFormatContext *s, int stream_index,
131
                                 PayloadContext *asf, const char *line)
132
{
133
    if (stream_index < 0)
134
        return 0;
135
    if (av_strstart(line, "stream:", &line)) {
136
        RTSPState *rt = s->priv_data;
137
 
138
        s->streams[stream_index]->id = strtol(line, NULL, 10);
139
 
140
        if (rt->asf_ctx) {
141
            int i;
142
 
143
            for (i = 0; i < rt->asf_ctx->nb_streams; i++) {
144
                if (s->streams[stream_index]->id == rt->asf_ctx->streams[i]->id) {
145
                    *s->streams[stream_index]->codec =
146
                        *rt->asf_ctx->streams[i]->codec;
147
                    rt->asf_ctx->streams[i]->codec->extradata_size = 0;
148
                    rt->asf_ctx->streams[i]->codec->extradata = NULL;
149
                    avpriv_set_pts_info(s->streams[stream_index], 32, 1, 1000);
150
                }
151
           }
152
        }
153
    }
154
 
155
    return 0;
156
}
157
 
158
struct PayloadContext {
159
    AVIOContext *pktbuf, pb;
160
    uint8_t *buf;
161
};
162
 
163
/**
164
 * @return 0 when a packet was written into /p pkt, and no more data is left;
165
 *         1 when a packet was written into /p pkt, and more packets might be left;
166
 *        <0 when not enough data was provided to return a full packet, or on error.
167
 */
168
static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf,
169
                               AVStream *st, AVPacket *pkt,
170
                               uint32_t *timestamp,
171
                               const uint8_t *buf, int len, uint16_t seq,
172
                               int flags)
173
{
174
    AVIOContext *pb = &asf->pb;
175
    int res, mflags, len_off;
176
    RTSPState *rt = s->priv_data;
177
 
178
    if (!rt->asf_ctx)
179
        return -1;
180
 
181
    if (len > 0) {
182
        int off, out_len = 0;
183
 
184
        if (len < 4)
185
            return -1;
186
 
187
        av_freep(&asf->buf);
188
 
189
        ffio_init_context(pb, buf, len, 0, NULL, NULL, NULL, NULL);
190
 
191
        while (avio_tell(pb) + 4 < len) {
192
            int start_off = avio_tell(pb);
193
 
194
            mflags = avio_r8(pb);
195
            if (mflags & 0x80)
196
                flags |= RTP_FLAG_KEY;
197
            len_off = avio_rb24(pb);
198
            if (mflags & 0x20)   /**< relative timestamp */
199
                avio_skip(pb, 4);
200
            if (mflags & 0x10)   /**< has duration */
201
                avio_skip(pb, 4);
202
            if (mflags & 0x8)    /**< has location ID */
203
                avio_skip(pb, 4);
204
            off = avio_tell(pb);
205
 
206
            if (!(mflags & 0x40)) {
207
                /**
208
                 * If 0x40 is not set, the len_off field specifies an offset
209
                 * of this packet's payload data in the complete (reassembled)
210
                 * ASF packet. This is used to spread one ASF packet over
211
                 * multiple RTP packets.
212
                 */
213
                if (asf->pktbuf && len_off != avio_tell(asf->pktbuf)) {
214
                    uint8_t *p;
215
                    avio_close_dyn_buf(asf->pktbuf, &p);
216
                    asf->pktbuf = NULL;
217
                    av_free(p);
218
                }
219
                if (!len_off && !asf->pktbuf &&
220
                    (res = avio_open_dyn_buf(&asf->pktbuf)) < 0)
221
                    return res;
222
                if (!asf->pktbuf)
223
                    return AVERROR(EIO);
224
 
225
                avio_write(asf->pktbuf, buf + off, len - off);
226
                avio_skip(pb, len - off);
227
                if (!(flags & RTP_FLAG_MARKER))
228
                    return -1;
229
                out_len     = avio_close_dyn_buf(asf->pktbuf, &asf->buf);
230
                asf->pktbuf = NULL;
231
            } else {
232
                /**
233
                 * If 0x40 is set, the len_off field specifies the length of
234
                 * the next ASF packet that can be read from this payload
235
                 * data alone. This is commonly the same as the payload size,
236
                 * but could be less in case of packet splitting (i.e.
237
                 * multiple ASF packets in one RTP packet).
238
                 */
239
 
240
                int cur_len = start_off + len_off - off;
241
                int prev_len = out_len;
242
                out_len += cur_len;
243
                if (FFMIN(cur_len, len - off) < 0)
244
                    return -1;
245
                if ((res = av_reallocp(&asf->buf, out_len)) < 0)
246
                    return res;
247
                memcpy(asf->buf + prev_len, buf + off,
248
                       FFMIN(cur_len, len - off));
249
                avio_skip(pb, cur_len);
250
            }
251
        }
252
 
253
        init_packetizer(pb, asf->buf, out_len);
254
        pb->pos += rt->asf_pb_pos;
255
        pb->eof_reached = 0;
256
        rt->asf_ctx->pb = pb;
257
    }
258
 
259
    for (;;) {
260
        int i;
261
 
262
        res = ff_read_packet(rt->asf_ctx, pkt);
263
        rt->asf_pb_pos = avio_tell(pb);
264
        if (res != 0)
265
            break;
266
        for (i = 0; i < s->nb_streams; i++) {
267
            if (s->streams[i]->id == rt->asf_ctx->streams[pkt->stream_index]->id) {
268
                pkt->stream_index = i;
269
                return 1; // FIXME: return 0 if last packet
270
            }
271
        }
272
        av_free_packet(pkt);
273
    }
274
 
275
    return res == 1 ? -1 : res;
276
}
277
 
278
static PayloadContext *asfrtp_new_context(void)
279
{
280
    return av_mallocz(sizeof(PayloadContext));
281
}
282
 
283
static void asfrtp_free_context(PayloadContext *asf)
284
{
285
    if (asf->pktbuf) {
286
        uint8_t *p = NULL;
287
        avio_close_dyn_buf(asf->pktbuf, &p);
288
        asf->pktbuf = NULL;
289
        av_free(p);
290
    }
291
    av_freep(&asf->buf);
292
    av_free(asf);
293
}
294
 
295
#define RTP_ASF_HANDLER(n, s, t) \
296
RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \
297
    .enc_name         = s, \
298
    .codec_type       = t, \
299
    .codec_id         = AV_CODEC_ID_NONE, \
300
    .parse_sdp_a_line = asfrtp_parse_sdp_line, \
301
    .alloc            = asfrtp_new_context, \
302
    .free             = asfrtp_free_context, \
303
    .parse_packet     = asfrtp_parse_packet,   \
304
}
305
 
306
RTP_ASF_HANDLER(asf_pfv, "x-asf-pf",  AVMEDIA_TYPE_VIDEO);
307
RTP_ASF_HANDLER(asf_pfa, "x-asf-pf",  AVMEDIA_TYPE_AUDIO);