annotate ffmpeg/libavformat/rtpdec_qt.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * RTP/Quicktime support.
yading@11 3 * Copyright (c) 2009 Ronald S. Bultje
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 /**
yading@11 23 * @file
yading@11 24 * @brief Quicktime-style RTP support
yading@11 25 * @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
yading@11 26 */
yading@11 27
yading@11 28 #include "avformat.h"
yading@11 29 #include "internal.h"
yading@11 30 #include "avio_internal.h"
yading@11 31 #include "rtp.h"
yading@11 32 #include "rtpdec.h"
yading@11 33 #include "isom.h"
yading@11 34 #include "libavcodec/get_bits.h"
yading@11 35
yading@11 36 struct PayloadContext {
yading@11 37 AVPacket pkt;
yading@11 38 int bytes_per_frame, remaining;
yading@11 39 uint32_t timestamp;
yading@11 40 };
yading@11 41
yading@11 42 static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt,
yading@11 43 AVStream *st, AVPacket *pkt,
yading@11 44 uint32_t *timestamp, const uint8_t *buf,
yading@11 45 int len, uint16_t seq, int flags)
yading@11 46 {
yading@11 47 AVIOContext pb;
yading@11 48 GetBitContext gb;
yading@11 49 int packing_scheme, has_payload_desc, has_packet_info, alen,
yading@11 50 has_marker_bit = flags & RTP_FLAG_MARKER;
yading@11 51
yading@11 52 if (qt->remaining) {
yading@11 53 int num = qt->pkt.size / qt->bytes_per_frame;
yading@11 54
yading@11 55 if (av_new_packet(pkt, qt->bytes_per_frame))
yading@11 56 return AVERROR(ENOMEM);
yading@11 57 pkt->stream_index = st->index;
yading@11 58 pkt->flags = qt->pkt.flags;
yading@11 59 memcpy(pkt->data,
yading@11 60 &qt->pkt.data[(num - qt->remaining) * qt->bytes_per_frame],
yading@11 61 qt->bytes_per_frame);
yading@11 62 if (--qt->remaining == 0) {
yading@11 63 av_freep(&qt->pkt.data);
yading@11 64 qt->pkt.size = 0;
yading@11 65 }
yading@11 66 return qt->remaining > 0;
yading@11 67 }
yading@11 68
yading@11 69 /**
yading@11 70 * The RTP payload is described in:
yading@11 71 * http://developer.apple.com/quicktime/icefloe/dispatch026.html
yading@11 72 */
yading@11 73 init_get_bits(&gb, buf, len << 3);
yading@11 74 ffio_init_context(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
yading@11 75
yading@11 76 if (len < 4)
yading@11 77 return AVERROR_INVALIDDATA;
yading@11 78
yading@11 79 skip_bits(&gb, 4); // version
yading@11 80 if ((packing_scheme = get_bits(&gb, 2)) == 0)
yading@11 81 return AVERROR_INVALIDDATA;
yading@11 82 if (get_bits1(&gb))
yading@11 83 flags |= RTP_FLAG_KEY;
yading@11 84 has_payload_desc = get_bits1(&gb);
yading@11 85 has_packet_info = get_bits1(&gb);
yading@11 86 skip_bits(&gb, 23); // reserved:7, cache payload info:1, payload ID:15
yading@11 87
yading@11 88 if (has_payload_desc) {
yading@11 89 int data_len, pos, is_start, is_finish;
yading@11 90 uint32_t tag;
yading@11 91
yading@11 92 pos = get_bits_count(&gb) >> 3;
yading@11 93 if (pos + 12 > len)
yading@11 94 return AVERROR_INVALIDDATA;
yading@11 95
yading@11 96 skip_bits(&gb, 2); // has non-I frames:1, is sparse:1
yading@11 97 is_start = get_bits1(&gb);
yading@11 98 is_finish = get_bits1(&gb);
yading@11 99 if (!is_start || !is_finish) {
yading@11 100 avpriv_request_sample(s, "RTP-X-QT with payload description "
yading@11 101 "split over several packets");
yading@11 102 return AVERROR_PATCHWELCOME;
yading@11 103 }
yading@11 104 skip_bits(&gb, 12); // reserved
yading@11 105 data_len = get_bits(&gb, 16);
yading@11 106
yading@11 107 avio_seek(&pb, pos + 4, SEEK_SET);
yading@11 108 tag = avio_rl32(&pb);
yading@11 109 if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
yading@11 110 tag != MKTAG('v','i','d','e')) ||
yading@11 111 (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
yading@11 112 tag != MKTAG('s','o','u','n')))
yading@11 113 return AVERROR_INVALIDDATA;
yading@11 114 avpriv_set_pts_info(st, 32, 1, avio_rb32(&pb));
yading@11 115
yading@11 116 if (pos + data_len > len)
yading@11 117 return AVERROR_INVALIDDATA;
yading@11 118 /* TLVs */
yading@11 119 while (avio_tell(&pb) + 4 < pos + data_len) {
yading@11 120 int tlv_len = avio_rb16(&pb);
yading@11 121 tag = avio_rl16(&pb);
yading@11 122 if (avio_tell(&pb) + tlv_len > pos + data_len)
yading@11 123 return AVERROR_INVALIDDATA;
yading@11 124
yading@11 125 #define MKTAG16(a,b) MKTAG(a,b,0,0)
yading@11 126 switch (tag) {
yading@11 127 case MKTAG16('s','d'): {
yading@11 128 MOVStreamContext *msc;
yading@11 129 void *priv_data = st->priv_data;
yading@11 130 int nb_streams = s->nb_streams;
yading@11 131 MOVContext *mc = av_mallocz(sizeof(*mc));
yading@11 132 if (!mc)
yading@11 133 return AVERROR(ENOMEM);
yading@11 134 mc->fc = s;
yading@11 135 st->priv_data = msc = av_mallocz(sizeof(MOVStreamContext));
yading@11 136 if (!msc) {
yading@11 137 av_free(mc);
yading@11 138 st->priv_data = priv_data;
yading@11 139 return AVERROR(ENOMEM);
yading@11 140 }
yading@11 141 /* ff_mov_read_stsd_entries updates stream s->nb_streams-1,
yading@11 142 * so set it temporarily to indicate which stream to update. */
yading@11 143 s->nb_streams = st->index + 1;
yading@11 144 ff_mov_read_stsd_entries(mc, &pb, 1);
yading@11 145 qt->bytes_per_frame = msc->bytes_per_frame;
yading@11 146 av_free(msc);
yading@11 147 av_free(mc);
yading@11 148 st->priv_data = priv_data;
yading@11 149 s->nb_streams = nb_streams;
yading@11 150 break;
yading@11 151 }
yading@11 152 default:
yading@11 153 avio_skip(&pb, tlv_len);
yading@11 154 break;
yading@11 155 }
yading@11 156 }
yading@11 157
yading@11 158 /* 32-bit alignment */
yading@11 159 avio_skip(&pb, ((avio_tell(&pb) + 3) & ~3) - avio_tell(&pb));
yading@11 160 } else
yading@11 161 avio_seek(&pb, 4, SEEK_SET);
yading@11 162
yading@11 163 if (has_packet_info) {
yading@11 164 avpriv_request_sample(s, "RTP-X-QT with packet-specific info");
yading@11 165 return AVERROR_PATCHWELCOME;
yading@11 166 }
yading@11 167
yading@11 168 alen = len - avio_tell(&pb);
yading@11 169 if (alen <= 0)
yading@11 170 return AVERROR_INVALIDDATA;
yading@11 171
yading@11 172 switch (packing_scheme) {
yading@11 173 case 3: /* one data packet spread over 1 or multiple RTP packets */
yading@11 174 if (qt->pkt.size > 0 && qt->timestamp == *timestamp) {
yading@11 175 qt->pkt.data = av_realloc(qt->pkt.data, qt->pkt.size + alen +
yading@11 176 FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 177 } else {
yading@11 178 av_freep(&qt->pkt.data);
yading@11 179 av_init_packet(&qt->pkt);
yading@11 180 qt->pkt.data = av_malloc(alen + FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 181 qt->pkt.size = 0;
yading@11 182 qt->timestamp = *timestamp;
yading@11 183 }
yading@11 184 if (!qt->pkt.data)
yading@11 185 return AVERROR(ENOMEM);
yading@11 186 memcpy(qt->pkt.data + qt->pkt.size, buf + avio_tell(&pb), alen);
yading@11 187 qt->pkt.size += alen;
yading@11 188 if (has_marker_bit) {
yading@11 189 int ret = av_packet_from_data(pkt, qt->pkt.data, qt->pkt.size);
yading@11 190 if (ret < 0)
yading@11 191 return ret;
yading@11 192
yading@11 193 qt->pkt.size = 0;
yading@11 194 qt->pkt.data = NULL;
yading@11 195 pkt->flags = flags & RTP_FLAG_KEY ? AV_PKT_FLAG_KEY : 0;
yading@11 196 pkt->stream_index = st->index;
yading@11 197 memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 198 return 0;
yading@11 199 }
yading@11 200 return AVERROR(EAGAIN);
yading@11 201
yading@11 202 case 1: /* constant packet size, multiple packets per RTP packet */
yading@11 203 if (qt->bytes_per_frame == 0 ||
yading@11 204 alen % qt->bytes_per_frame != 0)
yading@11 205 return AVERROR_INVALIDDATA; /* wrongly padded */
yading@11 206 qt->remaining = (alen / qt->bytes_per_frame) - 1;
yading@11 207 if (av_new_packet(pkt, qt->bytes_per_frame))
yading@11 208 return AVERROR(ENOMEM);
yading@11 209 memcpy(pkt->data, buf + avio_tell(&pb), qt->bytes_per_frame);
yading@11 210 pkt->flags = flags & RTP_FLAG_KEY ? AV_PKT_FLAG_KEY : 0;
yading@11 211 pkt->stream_index = st->index;
yading@11 212 if (qt->remaining > 0) {
yading@11 213 av_freep(&qt->pkt.data);
yading@11 214 qt->pkt.data = av_malloc(qt->remaining * qt->bytes_per_frame);
yading@11 215 if (!qt->pkt.data) {
yading@11 216 av_free_packet(pkt);
yading@11 217 return AVERROR(ENOMEM);
yading@11 218 }
yading@11 219 qt->pkt.size = qt->remaining * qt->bytes_per_frame;
yading@11 220 memcpy(qt->pkt.data,
yading@11 221 buf + avio_tell(&pb) + qt->bytes_per_frame,
yading@11 222 qt->remaining * qt->bytes_per_frame);
yading@11 223 qt->pkt.flags = pkt->flags;
yading@11 224 return 1;
yading@11 225 }
yading@11 226 return 0;
yading@11 227
yading@11 228 default: /* unimplemented */
yading@11 229 avpriv_request_sample(NULL, "RTP-X-QT with packing scheme 2");
yading@11 230 return AVERROR_PATCHWELCOME;
yading@11 231 }
yading@11 232 }
yading@11 233
yading@11 234 static PayloadContext *qt_rtp_new(void)
yading@11 235 {
yading@11 236 return av_mallocz(sizeof(PayloadContext));
yading@11 237 }
yading@11 238
yading@11 239 static void qt_rtp_free(PayloadContext *qt)
yading@11 240 {
yading@11 241 av_freep(&qt->pkt.data);
yading@11 242 av_free(qt);
yading@11 243 }
yading@11 244
yading@11 245 #define RTP_QT_HANDLER(m, n, s, t) \
yading@11 246 RTPDynamicProtocolHandler ff_ ## m ## _rtp_ ## n ## _handler = { \
yading@11 247 .enc_name = s, \
yading@11 248 .codec_type = t, \
yading@11 249 .codec_id = AV_CODEC_ID_NONE, \
yading@11 250 .alloc = qt_rtp_new, \
yading@11 251 .free = qt_rtp_free, \
yading@11 252 .parse_packet = qt_rtp_parse_packet, \
yading@11 253 }
yading@11 254
yading@11 255 RTP_QT_HANDLER(qt, vid, "X-QT", AVMEDIA_TYPE_VIDEO);
yading@11 256 RTP_QT_HANDLER(qt, aud, "X-QT", AVMEDIA_TYPE_AUDIO);
yading@11 257 RTP_QT_HANDLER(quicktime, vid, "X-QUICKTIME", AVMEDIA_TYPE_VIDEO);
yading@11 258 RTP_QT_HANDLER(quicktime, aud, "X-QUICKTIME", AVMEDIA_TYPE_AUDIO);