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