FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/rtpdec_qt.c
Date: 2024-09-07 18:49:03
Exec Total Coverage
Lines: 0 148 0.0%
Functions: 0 3 0.0%
Branches: 0 71 0.0%

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