2 * RTP/Quicktime support.
3 * Copyright (c) 2009 Ronald S. Bultje
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * @brief Quicktime-style RTP support
25 * @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
30 #include "avio_internal.h"
34 #include "libavcodec/get_bits.h"
36 struct PayloadContext
{
38 int bytes_per_frame
, remaining
;
42 static int qt_rtp_parse_packet(AVFormatContext
*s
, PayloadContext
*qt
,
43 AVStream
*st
, AVPacket
*pkt
,
44 uint32_t *timestamp
, const uint8_t *buf
,
45 int len
, uint16_t seq
, int flags
)
49 int packing_scheme
, has_payload_desc
, has_packet_info
, alen
,
50 has_marker_bit
= flags
& RTP_FLAG_MARKER
;
53 int num
= qt
->pkt
.size
/ qt
->bytes_per_frame
;
55 if (av_new_packet(pkt
, qt
->bytes_per_frame
))
56 return AVERROR(ENOMEM
);
57 pkt
->stream_index
= st
->index
;
58 pkt
->flags
= qt
->pkt
.flags
;
60 &qt
->pkt
.data
[(num
- qt
->remaining
) * qt
->bytes_per_frame
],
62 if (--qt
->remaining
== 0) {
63 av_freep(&qt
->pkt
.data
);
66 return qt
->remaining
> 0;
70 * The RTP payload is described in:
71 * http://developer.apple.com/quicktime/icefloe/dispatch026.html
73 init_get_bits(&gb
, buf
, len
<< 3);
74 ffio_init_context(&pb
, buf
, len
, 0, NULL
, NULL
, NULL
, NULL
);
77 return AVERROR_INVALIDDATA
;
79 skip_bits(&gb
, 4); // version
80 if ((packing_scheme
= get_bits(&gb
, 2)) == 0)
81 return AVERROR_INVALIDDATA
;
83 flags
|= RTP_FLAG_KEY
;
84 has_payload_desc
= get_bits1(&gb
);
85 has_packet_info
= get_bits1(&gb
);
86 skip_bits(&gb
, 23); // reserved:7, cache payload info:1, payload ID:15
88 if (has_payload_desc
) {
89 int data_len
, pos
, is_start
, is_finish
;
92 pos
= get_bits_count(&gb
) >> 3;
94 return AVERROR_INVALIDDATA
;
96 skip_bits(&gb
, 2); // has non-I frames:1, is sparse:1
97 is_start
= get_bits1(&gb
);
98 is_finish
= get_bits1(&gb
);
99 if (!is_start
|| !is_finish
) {
100 av_log_missing_feature(s
, "RTP-X-QT with payload description "
101 "split over several packets", 1);
102 return AVERROR_PATCHWELCOME
;
104 skip_bits(&gb
, 12); // reserved
105 data_len
= get_bits(&gb
, 16);
107 avio_seek(&pb
, pos
+ 4, SEEK_SET
);
108 tag
= avio_rl32(&pb
);
109 if ((st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
&&
110 tag
!= MKTAG('v','i','d','e')) ||
111 (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
&&
112 tag
!= MKTAG('s','o','u','n')))
113 return AVERROR_INVALIDDATA
;
114 avpriv_set_pts_info(st
, 32, 1, avio_rb32(&pb
));
116 if (pos
+ data_len
> len
)
117 return AVERROR_INVALIDDATA
;
119 while (avio_tell(&pb
) + 4 < pos
+ data_len
) {
120 int tlv_len
= avio_rb16(&pb
);
121 tag
= avio_rl16(&pb
);
122 if (avio_tell(&pb
) + tlv_len
> pos
+ data_len
)
123 return AVERROR_INVALIDDATA
;
125 #define MKTAG16(a,b) MKTAG(a,b,0,0)
127 case MKTAG16('s','d'): {
128 MOVStreamContext
*msc
;
129 void *priv_data
= st
->priv_data
;
130 int nb_streams
= s
->nb_streams
;
131 MOVContext
*mc
= av_mallocz(sizeof(*mc
));
133 return AVERROR(ENOMEM
);
135 st
->priv_data
= msc
= av_mallocz(sizeof(MOVStreamContext
));
138 st
->priv_data
= priv_data
;
139 return AVERROR(ENOMEM
);
141 /* ff_mov_read_stsd_entries updates stream s->nb_streams-1,
142 * so set it temporarily to indicate which stream to update. */
143 s
->nb_streams
= st
->index
+ 1;
144 ff_mov_read_stsd_entries(mc
, &pb
, 1);
145 qt
->bytes_per_frame
= msc
->bytes_per_frame
;
148 st
->priv_data
= priv_data
;
149 s
->nb_streams
= nb_streams
;
153 avio_skip(&pb
, tlv_len
);
158 /* 32-bit alignment */
159 avio_skip(&pb
, ((avio_tell(&pb
) + 3) & ~3) - avio_tell(&pb
));
161 avio_seek(&pb
, 4, SEEK_SET
);
163 if (has_packet_info
) {
164 av_log_missing_feature(s
, "RTP-X-QT with packet specific info", 1);
165 return AVERROR_PATCHWELCOME
;
168 alen
= len
- avio_tell(&pb
);
170 return AVERROR_INVALIDDATA
;
172 switch (packing_scheme
) {
173 case 3: /* one data packet spread over 1 or multiple RTP packets */
174 if (qt
->pkt
.size
> 0 && qt
->timestamp
== *timestamp
) {
175 qt
->pkt
.data
= av_realloc(qt
->pkt
.data
, qt
->pkt
.size
+ alen
+
176 FF_INPUT_BUFFER_PADDING_SIZE
);
178 av_freep(&qt
->pkt
.data
);
179 av_init_packet(&qt
->pkt
);
180 qt
->pkt
.data
= av_malloc(alen
+ FF_INPUT_BUFFER_PADDING_SIZE
);
182 qt
->timestamp
= *timestamp
;
185 return AVERROR(ENOMEM
);
186 memcpy(qt
->pkt
.data
+ qt
->pkt
.size
, buf
+ avio_tell(&pb
), alen
);
187 qt
->pkt
.size
+= alen
;
188 if (has_marker_bit
) {
189 int ret
= av_packet_from_data(pkt
, qt
->pkt
.data
, qt
->pkt
.size
);
195 pkt
->flags
= flags
& RTP_FLAG_KEY
? AV_PKT_FLAG_KEY
: 0;
196 pkt
->stream_index
= st
->index
;
197 memset(pkt
->data
+ pkt
->size
, 0, FF_INPUT_BUFFER_PADDING_SIZE
);
200 return AVERROR(EAGAIN
);
202 case 1: /* constant packet size, multiple packets per RTP packet */
203 if (qt
->bytes_per_frame
== 0 ||
204 alen
% qt
->bytes_per_frame
!= 0)
205 return AVERROR_INVALIDDATA
; /* wrongly padded */
206 qt
->remaining
= (alen
/ qt
->bytes_per_frame
) - 1;
207 if (av_new_packet(pkt
, qt
->bytes_per_frame
))
208 return AVERROR(ENOMEM
);
209 memcpy(pkt
->data
, buf
+ avio_tell(&pb
), qt
->bytes_per_frame
);
210 pkt
->flags
= flags
& RTP_FLAG_KEY
? AV_PKT_FLAG_KEY
: 0;
211 pkt
->stream_index
= st
->index
;
212 if (qt
->remaining
> 0) {
213 av_freep(&qt
->pkt
.data
);
214 qt
->pkt
.data
= av_malloc(qt
->remaining
* qt
->bytes_per_frame
);
217 return AVERROR(ENOMEM
);
219 qt
->pkt
.size
= qt
->remaining
* qt
->bytes_per_frame
;
221 buf
+ avio_tell(&pb
) + qt
->bytes_per_frame
,
222 qt
->remaining
* qt
->bytes_per_frame
);
223 qt
->pkt
.flags
= pkt
->flags
;
228 default: /* unimplemented */
229 av_log_missing_feature(NULL
, "RTP-X-QT with packing scheme 2", 1);
230 return AVERROR_PATCHWELCOME
;
234 static PayloadContext
*qt_rtp_new(void)
236 return av_mallocz(sizeof(PayloadContext
));
239 static void qt_rtp_free(PayloadContext
*qt
)
241 av_freep(&qt
->pkt
.data
);
245 #define RTP_QT_HANDLER(m, n, s, t) \
246 RTPDynamicProtocolHandler ff_ ## m ## _rtp_ ## n ## _handler = { \
249 .codec_id = AV_CODEC_ID_NONE, \
250 .alloc = qt_rtp_new, \
251 .free = qt_rtp_free, \
252 .parse_packet = qt_rtp_parse_packet, \
255 RTP_QT_HANDLER(qt
, vid
, "X-QT", AVMEDIA_TYPE_VIDEO
);
256 RTP_QT_HANDLER(qt
, aud
, "X-QT", AVMEDIA_TYPE_AUDIO
);
257 RTP_QT_HANDLER(quicktime
, vid
, "X-QUICKTIME", AVMEDIA_TYPE_VIDEO
);
258 RTP_QT_HANDLER(quicktime
, aud
, "X-QUICKTIME", AVMEDIA_TYPE_AUDIO
);