1/* 2 * RTP H264 Protocol (RFC3984) 3 * Copyright (c) 2006 Ryan Martell 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/rtp_h264.c 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/bitstream.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 "rtp_h264.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 void 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(NULL, AV_LOG_DEBUG, "H.264/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(stream, AV_LOG_ERROR, 91 "H.264/RTP 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(NULL, AV_LOG_DEBUG, 109 "H.264/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 uint32_t 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) { 137 uint8_t *dest= av_malloc(packet_size+sizeof(start_sequence)+codec->extradata_size); 138 if(dest) 139 { 140 if(codec->extradata_size) 141 { 142 // av_realloc? 143 memcpy(dest, codec->extradata, codec->extradata_size); 144 av_free(codec->extradata); 145 } 146 147 memcpy(dest+codec->extradata_size, start_sequence, sizeof(start_sequence)); 148 memcpy(dest+codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); 149 150 codec->extradata= dest; 151 codec->extradata_size+= sizeof(start_sequence)+packet_size; 152 } else { 153 av_log(NULL, AV_LOG_ERROR, "H.264/RTP Unable to allocate memory for extradata!"); 154 } 155 } 156 } 157 av_log(NULL, AV_LOG_DEBUG, "H.264/RTP Extradata set to %p (size: %d)!", codec->extradata, codec->extradata_size); 158 } 159} 160 161// return 0 on packet, no more left, 1 on packet, 1 on partial packet... 162static int h264_handle_packet(AVFormatContext *ctx, 163 PayloadContext *data, 164 AVStream *st, 165 AVPacket * pkt, 166 uint32_t * timestamp, 167 const uint8_t * buf, 168 int len, int flags) 169{ 170 uint8_t nal = buf[0]; 171 uint8_t type = (nal & 0x1f); 172 int result= 0; 173 uint8_t start_sequence[]= {0, 0, 1}; 174 175#ifdef DEBUG 176 assert(data); 177 assert(data->cookie == MAGIC_COOKIE); 178#endif 179 assert(buf); 180 181 if (type >= 1 && type <= 23) 182 type = 1; // simplify the case. (these are all the nal types used internally by the h264 codec) 183 switch (type) { 184 case 0: // undefined; 185 result= -1; 186 break; 187 188 case 1: 189 av_new_packet(pkt, len+sizeof(start_sequence)); 190 memcpy(pkt->data, start_sequence, sizeof(start_sequence)); 191 memcpy(pkt->data+sizeof(start_sequence), buf, len); 192#ifdef DEBUG 193 data->packet_types_received[nal & 0x1f]++; 194#endif 195 break; 196 197 case 24: // STAP-A (one packet, multiple nals) 198 // consume the STAP-A NAL 199 buf++; 200 len--; 201 // first we are going to figure out the total size.... 202 { 203 int pass= 0; 204 int total_length= 0; 205 uint8_t *dst= NULL; 206 207 for(pass= 0; pass<2; pass++) { 208 const uint8_t *src= buf; 209 int src_len= len; 210 211 do { 212 uint16_t nal_size = AV_RB16(src); // this going to be a problem if unaligned (can it be?) 213 214 // consume the length of the aggregate... 215 src += 2; 216 src_len -= 2; 217 218 if (nal_size <= src_len) { 219 if(pass==0) { 220 // counting... 221 total_length+= sizeof(start_sequence)+nal_size; 222 } else { 223 // copying 224 assert(dst); 225 memcpy(dst, start_sequence, sizeof(start_sequence)); 226 dst+= sizeof(start_sequence); 227 memcpy(dst, src, nal_size); 228#ifdef DEBUG 229 data->packet_types_received[*src & 0x1f]++; 230#endif 231 dst+= nal_size; 232 } 233 } else { 234 av_log(NULL, AV_LOG_ERROR, 235 "nal size exceeds length: %d %d\n", nal_size, src_len); 236 } 237 238 // eat what we handled... 239 src += nal_size; 240 src_len -= nal_size; 241 242 if (src_len < 0) 243 av_log(NULL, AV_LOG_ERROR, 244 "Consumed more bytes than we got! (%d)\n", src_len); 245 } while (src_len > 2); // because there could be rtp padding.. 246 247 if(pass==0) { 248 // now we know the total size of the packet (with the start sequences added) 249 av_new_packet(pkt, total_length); 250 dst= pkt->data; 251 } else { 252 assert(dst-pkt->data==total_length); 253 } 254 } 255 } 256 break; 257 258 case 25: // STAP-B 259 case 26: // MTAP-16 260 case 27: // MTAP-24 261 case 29: // FU-B 262 av_log(NULL, AV_LOG_ERROR, 263 "Unhandled type (%d) (See RFC for implementation details\n", 264 type); 265 result= -1; 266 break; 267 268 case 28: // FU-A (fragmented nal) 269 buf++; 270 len--; // skip the fu_indicator 271 { 272 // these are the same as above, we just redo them here for clarity... 273 uint8_t fu_indicator = nal; 274 uint8_t fu_header = *buf; // read the fu_header. 275 uint8_t start_bit = fu_header >> 7; 276// uint8_t end_bit = (fu_header & 0x40) >> 6; 277 uint8_t nal_type = (fu_header & 0x1f); 278 uint8_t reconstructed_nal; 279 280 // reconstruct this packet's true nal; only the data follows.. 281 reconstructed_nal = fu_indicator & (0xe0); // the original nal forbidden bit and NRI are stored in this packet's nal; 282 reconstructed_nal |= nal_type; 283 284 // skip the fu_header... 285 buf++; 286 len--; 287 288#ifdef DEBUG 289 if (start_bit) 290 data->packet_types_received[nal_type]++; 291#endif 292 if(start_bit) { 293 // copy in the start sequence, and the reconstructed nal.... 294 av_new_packet(pkt, sizeof(start_sequence)+sizeof(nal)+len); 295 memcpy(pkt->data, start_sequence, sizeof(start_sequence)); 296 pkt->data[sizeof(start_sequence)]= reconstructed_nal; 297 memcpy(pkt->data+sizeof(start_sequence)+sizeof(nal), buf, len); 298 } else { 299 av_new_packet(pkt, len); 300 memcpy(pkt->data, buf, len); 301 } 302 } 303 break; 304 305 case 30: // undefined 306 case 31: // undefined 307 default: 308 av_log(NULL, AV_LOG_ERROR, "Undefined type (%d)", type); 309 result= -1; 310 break; 311 } 312 313 return result; 314} 315 316/* ---------------- public code */ 317static PayloadContext *h264_new_extradata(void) 318{ 319 PayloadContext *data = 320 av_mallocz(sizeof(PayloadContext) + 321 FF_INPUT_BUFFER_PADDING_SIZE); 322 323 if (data) { 324 data->cookie = MAGIC_COOKIE; 325 } 326 327 return data; 328} 329 330static void h264_free_extradata(PayloadContext *data) 331{ 332#ifdef DEBUG 333 int ii; 334 335 for (ii = 0; ii < 32; ii++) { 336 if (data->packet_types_received[ii]) 337 av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n", 338 data->packet_types_received[ii], ii); 339 } 340#endif 341 342 assert(data); 343 assert(data->cookie == MAGIC_COOKIE); 344 345 // avoid stale pointers (assert) 346 data->cookie = DEAD_COOKIE; 347 348 // and clear out this... 349 av_free(data); 350} 351 352static int parse_h264_sdp_line(AVFormatContext *s, int st_index, 353 PayloadContext *h264_data, const char *line) 354{ 355 AVStream *stream = s->streams[st_index]; 356 AVCodecContext *codec = stream->codec; 357 const char *p = line; 358 359 assert(h264_data->cookie == MAGIC_COOKIE); 360 361 if (av_strstart(p, "framesize:", &p)) { 362 char buf1[50]; 363 char *dst = buf1; 364 365 // remove the protocol identifier.. 366 while (*p && *p == ' ') p++; // strip spaces. 367 while (*p && *p != ' ') p++; // eat protocol identifier 368 while (*p && *p == ' ') p++; // strip trailing spaces. 369 while (*p && *p != '-' && (buf1 - dst) < sizeof(buf1) - 1) { 370 *dst++ = *p++; 371 } 372 *dst = '\0'; 373 374 // a='framesize:96 320-240' 375 // set our parameters.. 376 codec->width = atoi(buf1); 377 codec->height = atoi(p + 1); // skip the - 378 codec->pix_fmt = PIX_FMT_YUV420P; 379 } else if (av_strstart(p, "fmtp:", &p)) { 380 char attr[256]; 381 char value[4096]; 382 383 // remove the protocol identifier.. 384 while (*p && *p == ' ') p++; // strip spaces. 385 while (*p && *p != ' ') p++; // eat protocol identifier 386 while (*p && *p == ' ') p++; // strip trailing spaces. 387 388 /* loop on each attribute */ 389 while (rtsp_next_attr_and_value 390 (&p, attr, sizeof(attr), value, sizeof(value))) { 391 /* grab the codec extra_data from the config parameter of the fmtp line */ 392 sdp_parse_fmtp_config_h264(stream, h264_data, attr, value); 393 } 394 } else if (av_strstart(p, "cliprect:", &p)) { 395 // could use this if we wanted. 396 } 397 398 av_set_pts_info(stream, 33, 1, 90000); // 33 should be right, because the pts is 64 bit? (done elsewhere; this is a one time thing) 399 400 return 0; // keep processing it the normal way... 401} 402 403/** 404This is the structure for expanding on the dynamic rtp protocols (makes everything static. yay!) 405*/ 406RTPDynamicProtocolHandler ff_h264_dynamic_handler = { 407 "H264", 408 CODEC_TYPE_VIDEO, 409 CODEC_ID_H264, 410 parse_h264_sdp_line, 411 h264_new_extradata, 412 h264_free_extradata, 413 h264_handle_packet 414}; 415