Coverage Report

Created: 2026-04-01 07:42

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