OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * RTP Vorbis Protocol (RFC5215) |
| 3 * Copyright (c) 2009 Colin McQuillan |
| 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 libavformat/rtpdec_vorbis.c |
| 24 * @brief Vorbis / RTP Code (RFC 5215) |
| 25 * @author Colin McQuillan <m.niloc@gmail.com> |
| 26 */ |
| 27 |
| 28 #include "libavutil/base64.h" |
| 29 #include "libavutil/avstring.h" |
| 30 #include "libavcodec/bytestream.h" |
| 31 |
| 32 #include <assert.h> |
| 33 |
| 34 #include "rtpdec.h" |
| 35 #include "rtpdec_vorbis.h" |
| 36 |
| 37 /** |
| 38 * RTP/Vorbis specific private data. |
| 39 */ |
| 40 struct PayloadContext { |
| 41 unsigned ident; ///< 24-bit stream configuration identifier |
| 42 }; |
| 43 |
| 44 /** |
| 45 * Length encoding described in RFC5215 section 3.1.1. |
| 46 */ |
| 47 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end) |
| 48 { |
| 49 int n = 0; |
| 50 for (; *buf < buf_end; ++*buf) { |
| 51 n <<= 7; |
| 52 n += **buf & 0x7f; |
| 53 if (!(**buf & 0x80)) { |
| 54 ++*buf; |
| 55 return n; |
| 56 } |
| 57 } |
| 58 return 0; |
| 59 } |
| 60 |
| 61 /** |
| 62 * Out-of-band headers, described in RFC 5251 section 3.2.1 |
| 63 */ |
| 64 static unsigned int |
| 65 parse_packed_headers(const uint8_t * packed_headers, |
| 66 const uint8_t * packed_headers_end, |
| 67 AVCodecContext * codec, PayloadContext * vorbis_data) |
| 68 { |
| 69 unsigned num_packed, num_headers, length, length1, length2; |
| 70 uint8_t *ptr; |
| 71 |
| 72 num_packed = bytestream_get_be32(&packed_headers); |
| 73 vorbis_data->ident = bytestream_get_be24(&packed_headers); |
| 74 length = bytestream_get_be16(&packed_headers); |
| 75 num_headers = get_base128(&packed_headers, packed_headers_end); |
| 76 length1 = get_base128(&packed_headers, packed_headers_end); |
| 77 length2 = get_base128(&packed_headers, packed_headers_end); |
| 78 |
| 79 if (num_packed != 1 || num_headers > 3) { |
| 80 av_log(codec, AV_LOG_ERROR, |
| 81 "Unimplemented number of headers: %d packed headers, %d headers\n
", |
| 82 num_packed, num_headers); |
| 83 return AVERROR_PATCHWELCOME; |
| 84 } |
| 85 |
| 86 if (packed_headers_end - packed_headers != length || |
| 87 length1 > length || length2 > length - length1) { |
| 88 av_log(codec, AV_LOG_ERROR, |
| 89 "Bad packed header lengths (%d,%d,%d,%d)\n", length1, |
| 90 length2, packed_headers_end - packed_headers, length); |
| 91 return AVERROR_INVALIDDATA; |
| 92 } |
| 93 |
| 94 ptr = codec->extradata = av_mallocz(length + length / 255 + 64); |
| 95 if (!ptr) { |
| 96 av_log(codec, AV_LOG_ERROR, "Out of memory"); |
| 97 return AVERROR_NOMEM; |
| 98 } |
| 99 *ptr++ = 2; |
| 100 ptr += av_xiphlacing(ptr, length1); |
| 101 ptr += av_xiphlacing(ptr, length2); |
| 102 memcpy(ptr, packed_headers, length); |
| 103 ptr += length; |
| 104 codec->extradata_size = ptr - codec->extradata; |
| 105 |
| 106 return 0; |
| 107 } |
| 108 |
| 109 int |
| 110 ff_vorbis_parse_fmtp_config(AVCodecContext * codec, |
| 111 void *vorbis_data, char *attr, char *value) |
| 112 { |
| 113 int result = 0; |
| 114 assert(codec->codec_id == CODEC_ID_VORBIS); |
| 115 assert(vorbis_data); |
| 116 |
| 117 // The configuration value is a base64 encoded packed header |
| 118 if (!strcmp(attr, "configuration")) { |
| 119 uint8_t *decoded_packet = NULL; |
| 120 int packet_size; |
| 121 size_t decoded_alloc = strlen(value) / 4 * 3 + 4; |
| 122 |
| 123 if (decoded_alloc <= INT_MAX) { |
| 124 decoded_packet = av_malloc(decoded_alloc); |
| 125 if (decoded_packet) { |
| 126 packet_size = |
| 127 av_base64_decode(decoded_packet, value, decoded_alloc); |
| 128 |
| 129 result = parse_packed_headers |
| 130 (decoded_packet, decoded_packet + packet_size, codec, |
| 131 vorbis_data); |
| 132 } else { |
| 133 av_log(codec, AV_LOG_ERROR, |
| 134 "Out of memory while decoding SDP configuration.\n"); |
| 135 result = AVERROR_NOMEM; |
| 136 } |
| 137 } else { |
| 138 av_log(codec, AV_LOG_ERROR, "Packet too large\n"); |
| 139 result = AVERROR_INVALIDDATA; |
| 140 } |
| 141 av_free(decoded_packet); |
| 142 } |
| 143 return result; |
| 144 } |
| 145 |
| 146 static PayloadContext *vorbis_new_context(void) |
| 147 { |
| 148 return av_mallocz(sizeof(PayloadContext)); |
| 149 } |
| 150 |
| 151 static void vorbis_free_context(PayloadContext * data) |
| 152 { |
| 153 av_free(data); |
| 154 } |
| 155 |
| 156 /** |
| 157 * Handle payload as described in RFC 5215 section 2.2 |
| 158 */ |
| 159 static int |
| 160 vorbis_handle_packet(AVFormatContext * ctx, |
| 161 PayloadContext * data, |
| 162 AVStream * st, |
| 163 AVPacket * pkt, |
| 164 uint32_t * timestamp, |
| 165 const uint8_t * buf, int len, int flags) |
| 166 { |
| 167 int ident, fragmented, vdt, num_pkts, pkt_len; |
| 168 |
| 169 if (len < 6) { |
| 170 av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len); |
| 171 return AVERROR_INVALIDDATA; |
| 172 } |
| 173 |
| 174 ident = AV_RB24(buf); |
| 175 fragmented = buf[3] >> 6; |
| 176 vdt = (buf[3] >> 4) & 3; |
| 177 num_pkts = buf[3] & 7; |
| 178 pkt_len = AV_RB16(buf + 4); |
| 179 |
| 180 if (pkt_len > len - 6) { |
| 181 av_log(ctx, AV_LOG_ERROR, |
| 182 "Invalid packet length %d in %d byte packet\n", pkt_len, |
| 183 len); |
| 184 return AVERROR_INVALIDDATA; |
| 185 } |
| 186 |
| 187 if (ident != data->ident) { |
| 188 av_log(ctx, AV_LOG_ERROR, |
| 189 "Unimplemented Vorbis SDP configuration change detected\n"); |
| 190 return AVERROR_PATCHWELCOME; |
| 191 } |
| 192 |
| 193 if (fragmented != 0 || vdt != 0 || num_pkts != 1) { |
| 194 av_log(ctx, AV_LOG_ERROR, |
| 195 "Unimplemented RTP Vorbis packet settings (%d,%d,%d)\n", |
| 196 fragmented, vdt, num_pkts); |
| 197 return AVERROR_PATCHWELCOME; |
| 198 } |
| 199 |
| 200 if (av_new_packet(pkt, pkt_len)) { |
| 201 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); |
| 202 return AVERROR_NOMEM; |
| 203 } |
| 204 |
| 205 memcpy(pkt->data, buf + 6, pkt_len); |
| 206 pkt->stream_index = st->index; |
| 207 return 0; |
| 208 } |
| 209 |
| 210 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = { |
| 211 .enc_name = "vorbis", |
| 212 .codec_type = CODEC_TYPE_AUDIO, |
| 213 .codec_id = CODEC_ID_VORBIS, |
| 214 .parse_sdp_a_line = NULL, |
| 215 .open = vorbis_new_context, |
| 216 .close = vorbis_free_context, |
| 217 .parse_packet = vorbis_handle_packet |
| 218 }; |
OLD | NEW |