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