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 36struct PayloadContext { 37 AVPacket *pkt; 38 int bytes_per_frame, remaining; 39 uint32_t timestamp; 40}; 41 42static 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 52static 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 251static 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) \ 258const 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 268RTP_QT_HANDLER(qt, vid, "X-QT", AVMEDIA_TYPE_VIDEO); 269RTP_QT_HANDLER(qt, aud, "X-QT", AVMEDIA_TYPE_AUDIO); 270RTP_QT_HANDLER(quicktime, vid, "X-QUICKTIME", AVMEDIA_TYPE_VIDEO); 271RTP_QT_HANDLER(quicktime, aud, "X-QUICKTIME", AVMEDIA_TYPE_AUDIO); 272