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