]> git.sesse.net Git - ffmpeg/blob - libavformat/rtpdec_qt.c
AVFrame: deprecate all now unused fields
[ffmpeg] / libavformat / rtpdec_qt.c
1 /*
2  * RTP/Quicktime support.
3  * Copyright (c) 2009 Ronald S. Bultje
4  *
5  * This file is part of Libav.
6  *
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.
11  *
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.
16  *
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
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
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)
46 {
47     AVIOContext pb;
48     GetBitContext gb;
49     int packing_scheme, has_payload_desc, has_packet_info, alen,
50         has_marker_bit = flags & RTP_FLAG_MARKER;
51
52     if (qt->remaining) {
53         int num = qt->pkt.size / qt->bytes_per_frame;
54
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;
59         memcpy(pkt->data,
60                &qt->pkt.data[(num - qt->remaining) * qt->bytes_per_frame],
61                qt->bytes_per_frame);
62         if (--qt->remaining == 0) {
63             av_freep(&qt->pkt.data);
64             qt->pkt.size = 0;
65         }
66         return qt->remaining > 0;
67     }
68
69     /**
70      * The RTP payload is described in:
71      * http://developer.apple.com/quicktime/icefloe/dispatch026.html
72      */
73     init_get_bits(&gb, buf, len << 3);
74     ffio_init_context(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
75
76     if (len < 4)
77         return AVERROR_INVALIDDATA;
78
79     skip_bits(&gb, 4); // version
80     if ((packing_scheme = get_bits(&gb, 2)) == 0)
81         return AVERROR_INVALIDDATA;
82     if (get_bits1(&gb))
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
87
88     if (has_payload_desc) {
89         int data_len, pos, is_start, is_finish;
90         uint32_t tag;
91
92         pos = get_bits_count(&gb) >> 3;
93         if (pos + 12 > len)
94             return AVERROR_INVALIDDATA;
95
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;
103         }
104         skip_bits(&gb, 12); // reserved
105         data_len = get_bits(&gb, 16);
106
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));
115
116         if (pos + data_len > len)
117             return AVERROR_INVALIDDATA;
118         /* TLVs */
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;
124
125 #define MKTAG16(a,b) MKTAG(a,b,0,0)
126             switch (tag) {
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));
132                 if (!mc)
133                     return AVERROR(ENOMEM);
134                 mc->fc = s;
135                 st->priv_data = msc = av_mallocz(sizeof(MOVStreamContext));
136                 if (!msc) {
137                     av_free(mc);
138                     st->priv_data = priv_data;
139                     return AVERROR(ENOMEM);
140                 }
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;
146                 av_free(msc);
147                 av_free(mc);
148                 st->priv_data = priv_data;
149                 s->nb_streams = nb_streams;
150                 break;
151             }
152             default:
153                 avio_skip(&pb, tlv_len);
154                 break;
155             }
156         }
157
158         /* 32-bit alignment */
159         avio_skip(&pb, ((avio_tell(&pb) + 3) & ~3) - avio_tell(&pb));
160     } else
161         avio_seek(&pb, 4, SEEK_SET);
162
163     if (has_packet_info) {
164         av_log_missing_feature(s, "RTP-X-QT with packet specific info", 1);
165         return AVERROR_PATCHWELCOME;
166     }
167
168     alen = len - avio_tell(&pb);
169     if (alen <= 0)
170         return AVERROR_INVALIDDATA;
171
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);
177         } else {
178             av_freep(&qt->pkt.data);
179             av_init_packet(&qt->pkt);
180             qt->pkt.data = av_malloc(alen + FF_INPUT_BUFFER_PADDING_SIZE);
181             qt->pkt.size = 0;
182             qt->timestamp = *timestamp;
183         }
184         if (!qt->pkt.data)
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);
190             if (ret < 0)
191                 return ret;
192
193             qt->pkt.size = 0;
194             qt->pkt.data = NULL;
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);
198             return 0;
199         }
200         return AVERROR(EAGAIN);
201
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);
215             if (!qt->pkt.data) {
216                 av_free_packet(pkt);
217                 return AVERROR(ENOMEM);
218             }
219             qt->pkt.size = qt->remaining * qt->bytes_per_frame;
220             memcpy(qt->pkt.data,
221                    buf + avio_tell(&pb) + qt->bytes_per_frame,
222                    qt->remaining * qt->bytes_per_frame);
223             qt->pkt.flags = pkt->flags;
224             return 1;
225         }
226         return 0;
227
228     default:  /* unimplemented */
229         av_log_missing_feature(NULL, "RTP-X-QT with packing scheme 2", 1);
230         return AVERROR_PATCHWELCOME;
231     }
232 }
233
234 static PayloadContext *qt_rtp_new(void)
235 {
236     return av_mallocz(sizeof(PayloadContext));
237 }
238
239 static void qt_rtp_free(PayloadContext *qt)
240 {
241     av_freep(&qt->pkt.data);
242     av_free(qt);
243 }
244
245 #define RTP_QT_HANDLER(m, n, s, t) \
246 RTPDynamicProtocolHandler ff_ ## m ## _rtp_ ## n ## _handler = { \
247     .enc_name         = s, \
248     .codec_type       = t, \
249     .codec_id         = AV_CODEC_ID_NONE, \
250     .alloc            = qt_rtp_new,    \
251     .free             = qt_rtp_free,   \
252     .parse_packet     = qt_rtp_parse_packet, \
253 }
254
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);