• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 struct PayloadContext {
37     AVPacket *pkt;
38     int bytes_per_frame, remaining;
39     uint32_t timestamp;
40 };
41 
qt_rtp_init(AVFormatContext * ctx,int st_index,PayloadContext * qt)42 static 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 
qt_rtp_parse_packet(AVFormatContext * s,PayloadContext * qt,AVStream * st,AVPacket * pkt,uint32_t * timestamp,const uint8_t * buf,int len,uint16_t seq,int flags)52 static 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 
qt_rtp_close(PayloadContext * qt)251 static 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) \
258 const 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 
268 RTP_QT_HANDLER(qt,        vid, "X-QT",        AVMEDIA_TYPE_VIDEO);
269 RTP_QT_HANDLER(qt,        aud, "X-QT",        AVMEDIA_TYPE_AUDIO);
270 RTP_QT_HANDLER(quicktime, vid, "X-QUICKTIME", AVMEDIA_TYPE_VIDEO);
271 RTP_QT_HANDLER(quicktime, aud, "X-QUICKTIME", AVMEDIA_TYPE_AUDIO);
272