1/*
2 * RTP/Quicktime support.
3 * Copyright (c) 2009 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 Quicktime-style RTP support
25 * @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
26 */
27
28#include "avformat.h"
29#include "internal.h"
30#include "avio_internal.h"
31#include "rtp.h"
32#include "rtpdec.h"
33#include "isom.h"
34#include "libavcodec/get_bits.h"
35
36struct PayloadContext {
37    AVPacket *pkt;
38    int bytes_per_frame, remaining;
39    uint32_t timestamp;
40};
41
42static av_cold int qt_rtp_init(AVFormatContext *ctx, int st_index,
43                               PayloadContext *qt)
44{
45    qt->pkt = av_packet_alloc();
46    if (!qt->pkt)
47        return AVERROR(ENOMEM);
48
49    return 0;
50}
51
52static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt,
53                               AVStream *st, AVPacket *pkt,
54                               uint32_t *timestamp, const uint8_t *buf,
55                               int len, uint16_t seq, int flags)
56{
57    FFIOContext pb0;
58    AVIOContext *const pb = &pb0.pub;
59    GetBitContext gb;
60    int packing_scheme, has_payload_desc, has_packet_info, alen,
61        has_marker_bit = flags & RTP_FLAG_MARKER,
62        keyframe, ret;
63
64    if (qt->remaining) {
65        int num = qt->pkt->size / qt->bytes_per_frame;
66
67        if ((ret = av_new_packet(pkt, qt->bytes_per_frame)) < 0)
68            return ret;
69        pkt->stream_index = st->index;
70        pkt->flags        = qt->pkt->flags;
71        memcpy(pkt->data,
72               &qt->pkt->data[(num - qt->remaining) * qt->bytes_per_frame],
73               qt->bytes_per_frame);
74        if (--qt->remaining == 0) {
75            av_freep(&qt->pkt->data);
76            qt->pkt->size = 0;
77        }
78        return qt->remaining > 0;
79    }
80
81    /**
82     * The RTP payload is described in:
83     * http://developer.apple.com/quicktime/icefloe/dispatch026.html
84     */
85    ret = init_get_bits(&gb, buf, len << 3);
86    if (ret < 0)
87        return ret;
88    ffio_init_context(&pb0, (uint8_t*)buf, len, 0, NULL, NULL, NULL, NULL);
89
90    if (len < 4)
91        return AVERROR_INVALIDDATA;
92
93    skip_bits(&gb, 4); // version
94    if ((packing_scheme = get_bits(&gb, 2)) == 0)
95        return AVERROR_INVALIDDATA;
96    keyframe            = get_bits1(&gb);
97    has_payload_desc    = get_bits1(&gb);
98    has_packet_info     = get_bits1(&gb);
99    skip_bits(&gb, 23); // reserved:7, cache payload info:1, payload ID:15
100
101    if (has_payload_desc) {
102        int data_len, pos, is_start, is_finish;
103        uint32_t tag;
104
105        pos = get_bits_count(&gb) >> 3;
106        if (pos + 12 > len)
107            return AVERROR_INVALIDDATA;
108
109        skip_bits(&gb, 2); // has non-I-frames:1, is sparse:1
110        is_start  = get_bits1(&gb);
111        is_finish = get_bits1(&gb);
112        if (!is_start || !is_finish) {
113            avpriv_request_sample(s, "RTP-X-QT with payload description "
114                                  "split over several packets");
115            return AVERROR_PATCHWELCOME;
116        }
117        skip_bits(&gb, 12); // reserved
118        data_len = get_bits(&gb, 16);
119
120        avio_seek(pb, pos + 4, SEEK_SET);
121        tag = avio_rl32(pb);
122        if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
123                 tag != MKTAG('v','i','d','e')) ||
124            (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
125                 tag != MKTAG('s','o','u','n')))
126            return AVERROR_INVALIDDATA;
127        avpriv_set_pts_info(st, 32, 1, avio_rb32(pb));
128
129        if (pos + data_len > len)
130            return AVERROR_INVALIDDATA;
131        /* TLVs */
132        while (avio_tell(pb) + 4 < pos + data_len) {
133            int tlv_len = avio_rb16(pb);
134            tag = avio_rl16(pb);
135            if (avio_tell(pb) + tlv_len > pos + data_len)
136                return AVERROR_INVALIDDATA;
137
138#define MKTAG16(a,b) MKTAG(a,b,0,0)
139            switch (tag) {
140            case MKTAG16('s','d'): {
141                MOVStreamContext *msc;
142                void *priv_data = st->priv_data;
143                int nb_streams = s->nb_streams;
144                MOVContext *mc = av_mallocz(sizeof(*mc));
145                if (!mc)
146                    return AVERROR(ENOMEM);
147                mc->fc = s;
148                st->priv_data = msc = av_mallocz(sizeof(MOVStreamContext));
149                if (!msc) {
150                    av_free(mc);
151                    st->priv_data = priv_data;
152                    return AVERROR(ENOMEM);
153                }
154                /* ff_mov_read_stsd_entries updates stream s->nb_streams-1,
155                 * so set it temporarily to indicate which stream to update. */
156                s->nb_streams = st->index + 1;
157                ff_mov_read_stsd_entries(mc, pb, 1);
158                qt->bytes_per_frame = msc->bytes_per_frame;
159                av_free(msc);
160                av_free(mc);
161                st->priv_data = priv_data;
162                s->nb_streams = nb_streams;
163                break;
164            }
165            default:
166                avio_skip(pb, tlv_len);
167                break;
168            }
169        }
170
171        /* 32-bit alignment */
172        avio_skip(pb, ((avio_tell(pb) + 3) & ~3) - avio_tell(pb));
173    } else
174        avio_seek(pb, 4, SEEK_SET);
175
176    if (has_packet_info) {
177        avpriv_request_sample(s, "RTP-X-QT with packet-specific info");
178        return AVERROR_PATCHWELCOME;
179    }
180
181    alen = len - avio_tell(pb);
182    if (alen <= 0)
183        return AVERROR_INVALIDDATA;
184
185    switch (packing_scheme) {
186    case 3: /* one data packet spread over 1 or multiple RTP packets */
187        if (qt->pkt->size > 0 && qt->timestamp == *timestamp) {
188            int err;
189            if ((err = av_reallocp(&qt->pkt->data, qt->pkt->size + alen +
190                                   AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
191                qt->pkt->size = 0;
192                return err;
193            }
194        } else {
195            av_freep(&qt->pkt->data);
196            av_packet_unref(qt->pkt);
197            qt->pkt->data = av_realloc(NULL, alen + AV_INPUT_BUFFER_PADDING_SIZE);
198            if (!qt->pkt->data)
199                return AVERROR(ENOMEM);
200            qt->pkt->size = 0;
201            qt->timestamp = *timestamp;
202        }
203        memcpy(qt->pkt->data + qt->pkt->size, buf + avio_tell(pb), alen);
204        qt->pkt->size += alen;
205        if (has_marker_bit) {
206            int ret = av_packet_from_data(pkt, qt->pkt->data, qt->pkt->size);
207            if (ret < 0)
208                return ret;
209
210            qt->pkt->size = 0;
211            qt->pkt->data = NULL;
212            pkt->flags        = keyframe ? AV_PKT_FLAG_KEY : 0;
213            pkt->stream_index = st->index;
214            memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
215            return 0;
216        }
217        return AVERROR(EAGAIN);
218
219    case 1: /* constant packet size, multiple packets per RTP packet */
220        if (qt->bytes_per_frame == 0 ||
221            alen % qt->bytes_per_frame != 0)
222            return AVERROR_INVALIDDATA; /* wrongly padded */
223        qt->remaining = (alen / qt->bytes_per_frame) - 1;
224        if ((ret = av_new_packet(pkt, qt->bytes_per_frame)) < 0)
225            return ret;
226        memcpy(pkt->data, buf + avio_tell(pb), qt->bytes_per_frame);
227        pkt->flags = keyframe ? AV_PKT_FLAG_KEY : 0;
228        pkt->stream_index = st->index;
229        if (qt->remaining > 0) {
230            av_freep(&qt->pkt->data);
231            qt->pkt->data = av_realloc(NULL, qt->remaining * qt->bytes_per_frame);
232            if (!qt->pkt->data) {
233                av_packet_unref(pkt);
234                return AVERROR(ENOMEM);
235            }
236            qt->pkt->size = qt->remaining * qt->bytes_per_frame;
237            memcpy(qt->pkt->data,
238                   buf + avio_tell(pb) + qt->bytes_per_frame,
239                   qt->remaining * qt->bytes_per_frame);
240            qt->pkt->flags = pkt->flags;
241            return 1;
242        }
243        return 0;
244
245    default:  /* unimplemented */
246        avpriv_request_sample(NULL, "RTP-X-QT with packing scheme 2");
247        return AVERROR_PATCHWELCOME;
248    }
249}
250
251static void qt_rtp_close(PayloadContext *qt)
252{
253    av_freep(&qt->pkt->data);
254    av_packet_free(&qt->pkt);
255}
256
257#define RTP_QT_HANDLER(m, n, s, t) \
258const RTPDynamicProtocolHandler ff_ ## m ## _rtp_ ## n ## _handler = { \
259    .enc_name         = s, \
260    .codec_type       = t, \
261    .codec_id         = AV_CODEC_ID_NONE, \
262    .priv_data_size   = sizeof(PayloadContext), \
263    .init             = qt_rtp_init,    \
264    .close            = qt_rtp_close,   \
265    .parse_packet     = qt_rtp_parse_packet, \
266}
267
268RTP_QT_HANDLER(qt,        vid, "X-QT",        AVMEDIA_TYPE_VIDEO);
269RTP_QT_HANDLER(qt,        aud, "X-QT",        AVMEDIA_TYPE_AUDIO);
270RTP_QT_HANDLER(quicktime, vid, "X-QUICKTIME", AVMEDIA_TYPE_VIDEO);
271RTP_QT_HANDLER(quicktime, aud, "X-QUICKTIME", AVMEDIA_TYPE_AUDIO);
272