1/* 2 * RTP H264 Protocol (RFC3984) 3 * Copyright (c) 2006 Ryan Martell 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; 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 H.264 / RTP Code (RFC3984) 25 * @author Ryan Martell <rdm4@martellventures.com> 26 * 27 * @note Notes: 28 * Notes: 29 * This currently supports packetization mode: 30 * Single Nal Unit Mode (0), or 31 * Non-Interleaved Mode (1). It currently does not support 32 * Interleaved Mode (2). (This requires implementing STAP-B, MTAP16, MTAP24, FU-B packet types) 33 * 34 * @note TODO: 35 * 1) RTCP sender reports for udp streams are required.. 36 * 37 */ 38 39#include "libavutil/base64.h" 40#include "libavutil/avstring.h" 41#include "libavcodec/get_bits.h" 42#include "avformat.h" 43#include "mpegts.h" 44 45#include <unistd.h> 46#include "network.h" 47#include <assert.h> 48 49#include "rtpdec.h" 50#include "rtpdec_formats.h" 51 52/** 53 RTP/H264 specific private data. 54*/ 55struct PayloadContext { 56 unsigned long cookie; ///< sanity check, to make sure we get the pointer we're expecting. 57 58 //sdp setup parameters 59 uint8_t profile_idc; ///< from the sdp setup parameters. 60 uint8_t profile_iop; ///< from the sdp setup parameters. 61 uint8_t level_idc; ///< from the sdp setup parameters. 62 int packetization_mode; ///< from the sdp setup parameters. 63#ifdef DEBUG 64 int packet_types_received[32]; 65#endif 66}; 67 68#define MAGIC_COOKIE (0xdeadbeef) ///< Cookie for the extradata; to verify we are what we think we are, and that we haven't been freed. 69#define DEAD_COOKIE (0xdeaddead) ///< Cookie for the extradata; once it is freed. 70 71/* ---------------- private code */ 72static int sdp_parse_fmtp_config_h264(AVStream * stream, 73 PayloadContext * h264_data, 74 char *attr, char *value) 75{ 76 AVCodecContext *codec = stream->codec; 77 assert(codec->codec_id == CODEC_ID_H264); 78 assert(h264_data != NULL); 79 80 if (!strcmp(attr, "packetization-mode")) { 81 av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value)); 82 h264_data->packetization_mode = atoi(value); 83 /* 84 Packetization Mode: 85 0 or not present: Single NAL mode (Only nals from 1-23 are allowed) 86 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed. 87 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A), and 29 (FU-B) are allowed. 88 */ 89 if (h264_data->packetization_mode > 1) 90 av_log(codec, AV_LOG_ERROR, 91 "Interleaved RTP mode is not supported yet."); 92 } else if (!strcmp(attr, "profile-level-id")) { 93 if (strlen(value) == 6) { 94 char buffer[3]; 95 // 6 characters=3 bytes, in hex. 96 uint8_t profile_idc; 97 uint8_t profile_iop; 98 uint8_t level_idc; 99 100 buffer[0] = value[0]; buffer[1] = value[1]; buffer[2] = '\0'; 101 profile_idc = strtol(buffer, NULL, 16); 102 buffer[0] = value[2]; buffer[1] = value[3]; 103 profile_iop = strtol(buffer, NULL, 16); 104 buffer[0] = value[4]; buffer[1] = value[5]; 105 level_idc = strtol(buffer, NULL, 16); 106 107 // set the parameters... 108 av_log(codec, AV_LOG_DEBUG, 109 "RTP Profile IDC: %x Profile IOP: %x Level: %x\n", 110 profile_idc, profile_iop, level_idc); 111 h264_data->profile_idc = profile_idc; 112 h264_data->profile_iop = profile_iop; 113 h264_data->level_idc = level_idc; 114 } 115 } else if (!strcmp(attr, "sprop-parameter-sets")) { 116 uint8_t start_sequence[]= { 0, 0, 1 }; 117 codec->extradata_size= 0; 118 codec->extradata= NULL; 119 120 while (*value) { 121 char base64packet[1024]; 122 uint8_t decoded_packet[1024]; 123 int packet_size; 124 char *dst = base64packet; 125 126 while (*value && *value != ',' 127 && (dst - base64packet) < sizeof(base64packet) - 1) { 128 *dst++ = *value++; 129 } 130 *dst++ = '\0'; 131 132 if (*value == ',') 133 value++; 134 135 packet_size= av_base64_decode(decoded_packet, base64packet, sizeof(decoded_packet)); 136 if (packet_size > 0) { 137 uint8_t *dest = av_malloc(packet_size + sizeof(start_sequence) + 138 codec->extradata_size + 139 FF_INPUT_BUFFER_PADDING_SIZE); 140 if(dest) 141 { 142 if(codec->extradata_size) 143 { 144 // av_realloc? 145 memcpy(dest, codec->extradata, codec->extradata_size); 146 av_free(codec->extradata); 147 } 148 149 memcpy(dest+codec->extradata_size, start_sequence, sizeof(start_sequence)); 150 memcpy(dest+codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); 151 memset(dest+codec->extradata_size+sizeof(start_sequence)+ 152 packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); 153 154 codec->extradata= dest; 155 codec->extradata_size+= sizeof(start_sequence)+packet_size; 156 } else { 157 av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!"); 158 return AVERROR(ENOMEM); 159 } 160 } 161 } 162 av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!", codec->extradata, codec->extradata_size); 163 } 164 return 0; 165} 166 167// return 0 on packet, no more left, 1 on packet, 1 on partial packet... 168static int h264_handle_packet(AVFormatContext *ctx, 169 PayloadContext *data, 170 AVStream *st, 171 AVPacket * pkt, 172 uint32_t * timestamp, 173 const uint8_t * buf, 174 int len, int flags) 175{ 176 uint8_t nal = buf[0]; 177 uint8_t type = (nal & 0x1f); 178 int result= 0; 179 uint8_t start_sequence[]= {0, 0, 1}; 180 181#ifdef DEBUG 182 assert(data); 183 assert(data->cookie == MAGIC_COOKIE); 184#endif 185 assert(buf); 186 187 if (type >= 1 && type <= 23) 188 type = 1; // simplify the case. (these are all the nal types used internally by the h264 codec) 189 switch (type) { 190 case 0: // undefined, but pass them through 191 case 1: 192 av_new_packet(pkt, len+sizeof(start_sequence)); 193 memcpy(pkt->data, start_sequence, sizeof(start_sequence)); 194 memcpy(pkt->data+sizeof(start_sequence), buf, len); 195#ifdef DEBUG 196 data->packet_types_received[nal & 0x1f]++; 197#endif 198 break; 199 200 case 24: // STAP-A (one packet, multiple nals) 201 // consume the STAP-A NAL 202 buf++; 203 len--; 204 // first we are going to figure out the total size.... 205 { 206 int pass= 0; 207 int total_length= 0; 208 uint8_t *dst= NULL; 209 210 for(pass= 0; pass<2; pass++) { 211 const uint8_t *src= buf; 212 int src_len= len; 213 214 do { 215 uint16_t nal_size = AV_RB16(src); // this going to be a problem if unaligned (can it be?) 216 217 // consume the length of the aggregate... 218 src += 2; 219 src_len -= 2; 220 221 if (nal_size <= src_len) { 222 if(pass==0) { 223 // counting... 224 total_length+= sizeof(start_sequence)+nal_size; 225 } else { 226 // copying 227 assert(dst); 228 memcpy(dst, start_sequence, sizeof(start_sequence)); 229 dst+= sizeof(start_sequence); 230 memcpy(dst, src, nal_size); 231#ifdef DEBUG 232 data->packet_types_received[*src & 0x1f]++; 233#endif 234 dst+= nal_size; 235 } 236 } else { 237 av_log(ctx, AV_LOG_ERROR, 238 "nal size exceeds length: %d %d\n", nal_size, src_len); 239 } 240 241 // eat what we handled... 242 src += nal_size; 243 src_len -= nal_size; 244 245 if (src_len < 0) 246 av_log(ctx, AV_LOG_ERROR, 247 "Consumed more bytes than we got! (%d)\n", src_len); 248 } while (src_len > 2); // because there could be rtp padding.. 249 250 if(pass==0) { 251 // now we know the total size of the packet (with the start sequences added) 252 av_new_packet(pkt, total_length); 253 dst= pkt->data; 254 } else { 255 assert(dst-pkt->data==total_length); 256 } 257 } 258 } 259 break; 260 261 case 25: // STAP-B 262 case 26: // MTAP-16 263 case 27: // MTAP-24 264 case 29: // FU-B 265 av_log(ctx, AV_LOG_ERROR, 266 "Unhandled type (%d) (See RFC for implementation details\n", 267 type); 268 result= -1; 269 break; 270 271 case 28: // FU-A (fragmented nal) 272 buf++; 273 len--; // skip the fu_indicator 274 { 275 // these are the same as above, we just redo them here for clarity... 276 uint8_t fu_indicator = nal; 277 uint8_t fu_header = *buf; // read the fu_header. 278 uint8_t start_bit = fu_header >> 7; 279// uint8_t end_bit = (fu_header & 0x40) >> 6; 280 uint8_t nal_type = (fu_header & 0x1f); 281 uint8_t reconstructed_nal; 282 283 // reconstruct this packet's true nal; only the data follows.. 284 reconstructed_nal = fu_indicator & (0xe0); // the original nal forbidden bit and NRI are stored in this packet's nal; 285 reconstructed_nal |= nal_type; 286 287 // skip the fu_header... 288 buf++; 289 len--; 290 291#ifdef DEBUG 292 if (start_bit) 293 data->packet_types_received[nal_type]++; 294#endif 295 if(start_bit) { 296 // copy in the start sequence, and the reconstructed nal.... 297 av_new_packet(pkt, sizeof(start_sequence)+sizeof(nal)+len); 298 memcpy(pkt->data, start_sequence, sizeof(start_sequence)); 299 pkt->data[sizeof(start_sequence)]= reconstructed_nal; 300 memcpy(pkt->data+sizeof(start_sequence)+sizeof(nal), buf, len); 301 } else { 302 av_new_packet(pkt, len); 303 memcpy(pkt->data, buf, len); 304 } 305 } 306 break; 307 308 case 30: // undefined 309 case 31: // undefined 310 default: 311 av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)", type); 312 result= -1; 313 break; 314 } 315 316 pkt->stream_index = st->index; 317 318 return result; 319} 320 321/* ---------------- public code */ 322static PayloadContext *h264_new_context(void) 323{ 324 PayloadContext *data = 325 av_mallocz(sizeof(PayloadContext) + 326 FF_INPUT_BUFFER_PADDING_SIZE); 327 328 if (data) { 329 data->cookie = MAGIC_COOKIE; 330 } 331 332 return data; 333} 334 335static void h264_free_context(PayloadContext *data) 336{ 337#ifdef DEBUG 338 int ii; 339 340 for (ii = 0; ii < 32; ii++) { 341 if (data->packet_types_received[ii]) 342 av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n", 343 data->packet_types_received[ii], ii); 344 } 345#endif 346 347 assert(data); 348 assert(data->cookie == MAGIC_COOKIE); 349 350 // avoid stale pointers (assert) 351 data->cookie = DEAD_COOKIE; 352 353 // and clear out this... 354 av_free(data); 355} 356 357static int parse_h264_sdp_line(AVFormatContext *s, int st_index, 358 PayloadContext *h264_data, const char *line) 359{ 360 AVStream *stream = s->streams[st_index]; 361 AVCodecContext *codec = stream->codec; 362 const char *p = line; 363 364 assert(h264_data->cookie == MAGIC_COOKIE); 365 366 if (av_strstart(p, "framesize:", &p)) { 367 char buf1[50]; 368 char *dst = buf1; 369 370 // remove the protocol identifier.. 371 while (*p && *p == ' ') p++; // strip spaces. 372 while (*p && *p != ' ') p++; // eat protocol identifier 373 while (*p && *p == ' ') p++; // strip trailing spaces. 374 while (*p && *p != '-' && (dst - buf1) < sizeof(buf1) - 1) { 375 *dst++ = *p++; 376 } 377 *dst = '\0'; 378 379 // a='framesize:96 320-240' 380 // set our parameters.. 381 codec->width = atoi(buf1); 382 codec->height = atoi(p + 1); // skip the - 383 codec->pix_fmt = PIX_FMT_YUV420P; 384 } else if (av_strstart(p, "fmtp:", &p)) { 385 return ff_parse_fmtp(stream, h264_data, p, sdp_parse_fmtp_config_h264); 386 } else if (av_strstart(p, "cliprect:", &p)) { 387 // could use this if we wanted. 388 } 389 390 return 0; // keep processing it the normal way... 391} 392 393/** 394This is the structure for expanding on the dynamic rtp protocols (makes everything static. yay!) 395*/ 396RTPDynamicProtocolHandler ff_h264_dynamic_handler = { 397 .enc_name = "H264", 398 .codec_type = AVMEDIA_TYPE_VIDEO, 399 .codec_id = CODEC_ID_H264, 400 .parse_sdp_a_line = parse_h264_sdp_line, 401 .alloc = h264_new_context, 402 .free = h264_free_context, 403 .parse_packet = h264_handle_packet 404}; 405