yading@11: /* yading@11: * RTP H264 Protocol (RFC3984) yading@11: * Copyright (c) 2006 Ryan Martell yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: /** yading@11: * @file yading@11: * @brief H.264 / RTP Code (RFC3984) yading@11: * @author Ryan Martell yading@11: * yading@11: * @note Notes: yading@11: * Notes: yading@11: * This currently supports packetization mode: yading@11: * Single Nal Unit Mode (0), or yading@11: * Non-Interleaved Mode (1). It currently does not support yading@11: * Interleaved Mode (2). (This requires implementing STAP-B, MTAP16, MTAP24, yading@11: * FU-B packet types) yading@11: */ yading@11: yading@11: #include "libavutil/base64.h" yading@11: #include "libavutil/avstring.h" yading@11: #include "libavcodec/get_bits.h" yading@11: #include "avformat.h" yading@11: yading@11: #include "network.h" yading@11: #include yading@11: yading@11: #include "rtpdec.h" yading@11: #include "rtpdec_formats.h" yading@11: yading@11: struct PayloadContext { yading@11: // sdp setup parameters yading@11: uint8_t profile_idc; yading@11: uint8_t profile_iop; yading@11: uint8_t level_idc; yading@11: int packetization_mode; yading@11: #ifdef DEBUG yading@11: int packet_types_received[32]; yading@11: #endif yading@11: }; yading@11: yading@11: #ifdef DEBUG yading@11: #define COUNT_NAL_TYPE(data, nal) data->packet_types_received[(nal) & 0x1f]++ yading@11: #else yading@11: #define COUNT_NAL_TYPE(data, nal) do { } while (0) yading@11: #endif yading@11: yading@11: static const uint8_t start_sequence[] = { 0, 0, 0, 1 }; yading@11: yading@11: static int sdp_parse_fmtp_config_h264(AVStream *stream, yading@11: PayloadContext *h264_data, yading@11: char *attr, char *value) yading@11: { yading@11: AVCodecContext *codec = stream->codec; yading@11: assert(codec->codec_id == AV_CODEC_ID_H264); yading@11: assert(h264_data != NULL); yading@11: yading@11: if (!strcmp(attr, "packetization-mode")) { yading@11: av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value)); yading@11: h264_data->packetization_mode = atoi(value); yading@11: /* yading@11: * Packetization Mode: yading@11: * 0 or not present: Single NAL mode (Only nals from 1-23 are allowed) yading@11: * 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed. yading@11: * 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A), yading@11: * and 29 (FU-B) are allowed. yading@11: */ yading@11: if (h264_data->packetization_mode > 1) yading@11: av_log(codec, AV_LOG_ERROR, yading@11: "Interleaved RTP mode is not supported yet.\n"); yading@11: } else if (!strcmp(attr, "profile-level-id")) { yading@11: if (strlen(value) == 6) { yading@11: char buffer[3]; yading@11: // 6 characters=3 bytes, in hex. yading@11: uint8_t profile_idc; yading@11: uint8_t profile_iop; yading@11: uint8_t level_idc; yading@11: yading@11: buffer[0] = value[0]; yading@11: buffer[1] = value[1]; yading@11: buffer[2] = '\0'; yading@11: profile_idc = strtol(buffer, NULL, 16); yading@11: buffer[0] = value[2]; yading@11: buffer[1] = value[3]; yading@11: profile_iop = strtol(buffer, NULL, 16); yading@11: buffer[0] = value[4]; yading@11: buffer[1] = value[5]; yading@11: level_idc = strtol(buffer, NULL, 16); yading@11: yading@11: av_log(codec, AV_LOG_DEBUG, yading@11: "RTP Profile IDC: %x Profile IOP: %x Level: %x\n", yading@11: profile_idc, profile_iop, level_idc); yading@11: h264_data->profile_idc = profile_idc; yading@11: h264_data->profile_iop = profile_iop; yading@11: h264_data->level_idc = level_idc; yading@11: } yading@11: } else if (!strcmp(attr, "sprop-parameter-sets")) { yading@11: codec->extradata_size = 0; yading@11: av_freep(&codec->extradata); yading@11: yading@11: while (*value) { yading@11: char base64packet[1024]; yading@11: uint8_t decoded_packet[1024]; yading@11: int packet_size; yading@11: char *dst = base64packet; yading@11: yading@11: while (*value && *value != ',' yading@11: && (dst - base64packet) < sizeof(base64packet) - 1) { yading@11: *dst++ = *value++; yading@11: } yading@11: *dst++ = '\0'; yading@11: yading@11: if (*value == ',') yading@11: value++; yading@11: yading@11: packet_size = av_base64_decode(decoded_packet, base64packet, yading@11: sizeof(decoded_packet)); yading@11: if (packet_size > 0) { yading@11: uint8_t *dest = av_malloc(packet_size + sizeof(start_sequence) + yading@11: codec->extradata_size + yading@11: FF_INPUT_BUFFER_PADDING_SIZE); yading@11: if (!dest) { yading@11: av_log(codec, AV_LOG_ERROR, yading@11: "Unable to allocate memory for extradata!\n"); yading@11: return AVERROR(ENOMEM); yading@11: } yading@11: if (codec->extradata_size) { yading@11: memcpy(dest, codec->extradata, codec->extradata_size); yading@11: av_free(codec->extradata); yading@11: } yading@11: yading@11: memcpy(dest + codec->extradata_size, start_sequence, yading@11: sizeof(start_sequence)); yading@11: memcpy(dest + codec->extradata_size + sizeof(start_sequence), yading@11: decoded_packet, packet_size); yading@11: memset(dest + codec->extradata_size + sizeof(start_sequence) + yading@11: packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); yading@11: yading@11: codec->extradata = dest; yading@11: codec->extradata_size += sizeof(start_sequence) + packet_size; yading@11: } yading@11: } yading@11: av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!\n", yading@11: codec->extradata, codec->extradata_size); yading@11: } yading@11: return 0; yading@11: } yading@11: yading@11: // return 0 on packet, no more left, 1 on packet, 1 on partial packet yading@11: static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, yading@11: AVStream *st, AVPacket *pkt, uint32_t *timestamp, yading@11: const uint8_t *buf, int len, uint16_t seq, yading@11: int flags) yading@11: { yading@11: uint8_t nal; yading@11: uint8_t type; yading@11: int result = 0; yading@11: yading@11: if (!len) { yading@11: av_log(ctx, AV_LOG_ERROR, "Empty H264 RTP packet\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: nal = buf[0]; yading@11: type = nal & 0x1f; yading@11: yading@11: assert(data); yading@11: assert(buf); yading@11: yading@11: /* Simplify the case (these are all the nal types used internally by yading@11: * the h264 codec). */ yading@11: if (type >= 1 && type <= 23) yading@11: type = 1; yading@11: switch (type) { yading@11: case 0: // undefined, but pass them through yading@11: case 1: yading@11: av_new_packet(pkt, len + sizeof(start_sequence)); yading@11: memcpy(pkt->data, start_sequence, sizeof(start_sequence)); yading@11: memcpy(pkt->data + sizeof(start_sequence), buf, len); yading@11: COUNT_NAL_TYPE(data, nal); yading@11: break; yading@11: yading@11: case 24: // STAP-A (one packet, multiple nals) yading@11: // consume the STAP-A NAL yading@11: buf++; yading@11: len--; yading@11: // first we are going to figure out the total size yading@11: { yading@11: int pass = 0; yading@11: int total_length = 0; yading@11: uint8_t *dst = NULL; yading@11: yading@11: for (pass = 0; pass < 2; pass++) { yading@11: const uint8_t *src = buf; yading@11: int src_len = len; yading@11: yading@11: while (src_len > 2) { yading@11: uint16_t nal_size = AV_RB16(src); yading@11: yading@11: // consume the length of the aggregate yading@11: src += 2; yading@11: src_len -= 2; yading@11: yading@11: if (nal_size <= src_len) { yading@11: if (pass == 0) { yading@11: // counting yading@11: total_length += sizeof(start_sequence) + nal_size; yading@11: } else { yading@11: // copying yading@11: assert(dst); yading@11: memcpy(dst, start_sequence, sizeof(start_sequence)); yading@11: dst += sizeof(start_sequence); yading@11: memcpy(dst, src, nal_size); yading@11: COUNT_NAL_TYPE(data, *src); yading@11: dst += nal_size; yading@11: } yading@11: } else { yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "nal size exceeds length: %d %d\n", nal_size, src_len); yading@11: } yading@11: yading@11: // eat what we handled yading@11: src += nal_size; yading@11: src_len -= nal_size; yading@11: yading@11: if (src_len < 0) yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "Consumed more bytes than we got! (%d)\n", src_len); yading@11: } yading@11: yading@11: if (pass == 0) { yading@11: /* now we know the total size of the packet (with the yading@11: * start sequences added) */ yading@11: av_new_packet(pkt, total_length); yading@11: dst = pkt->data; yading@11: } else { yading@11: assert(dst - pkt->data == total_length); yading@11: } yading@11: } yading@11: } yading@11: break; yading@11: yading@11: case 25: // STAP-B yading@11: case 26: // MTAP-16 yading@11: case 27: // MTAP-24 yading@11: case 29: // FU-B yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "Unhandled type (%d) (See RFC for implementation details\n", yading@11: type); yading@11: result = AVERROR(ENOSYS); yading@11: break; yading@11: yading@11: case 28: // FU-A (fragmented nal) yading@11: buf++; yading@11: len--; // skip the fu_indicator yading@11: if (len > 1) { yading@11: // these are the same as above, we just redo them here for clarity yading@11: uint8_t fu_indicator = nal; yading@11: uint8_t fu_header = *buf; yading@11: uint8_t start_bit = fu_header >> 7; yading@11: uint8_t av_unused end_bit = (fu_header & 0x40) >> 6; yading@11: uint8_t nal_type = fu_header & 0x1f; yading@11: uint8_t reconstructed_nal; yading@11: yading@11: // Reconstruct this packet's true nal; only the data follows. yading@11: /* The original nal forbidden bit and NRI are stored in this yading@11: * packet's nal. */ yading@11: reconstructed_nal = fu_indicator & 0xe0; yading@11: reconstructed_nal |= nal_type; yading@11: yading@11: // skip the fu_header yading@11: buf++; yading@11: len--; yading@11: yading@11: if (start_bit) yading@11: COUNT_NAL_TYPE(data, nal_type); yading@11: if (start_bit) { yading@11: /* copy in the start sequence, and the reconstructed nal */ yading@11: av_new_packet(pkt, sizeof(start_sequence) + sizeof(nal) + len); yading@11: memcpy(pkt->data, start_sequence, sizeof(start_sequence)); yading@11: pkt->data[sizeof(start_sequence)] = reconstructed_nal; yading@11: memcpy(pkt->data + sizeof(start_sequence) + sizeof(nal), buf, len); yading@11: } else { yading@11: av_new_packet(pkt, len); yading@11: memcpy(pkt->data, buf, len); yading@11: } yading@11: } else { yading@11: av_log(ctx, AV_LOG_ERROR, "Too short data for FU-A H264 RTP packet\n"); yading@11: result = AVERROR_INVALIDDATA; yading@11: } yading@11: break; yading@11: yading@11: case 30: // undefined yading@11: case 31: // undefined yading@11: default: yading@11: av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)\n", type); yading@11: result = AVERROR_INVALIDDATA; yading@11: break; yading@11: } yading@11: yading@11: pkt->stream_index = st->index; yading@11: yading@11: return result; yading@11: } yading@11: yading@11: static PayloadContext *h264_new_context(void) yading@11: { yading@11: return av_mallocz(sizeof(PayloadContext) + FF_INPUT_BUFFER_PADDING_SIZE); yading@11: } yading@11: yading@11: static void h264_free_context(PayloadContext *data) yading@11: { yading@11: #ifdef DEBUG yading@11: int ii; yading@11: yading@11: for (ii = 0; ii < 32; ii++) { yading@11: if (data->packet_types_received[ii]) yading@11: av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n", yading@11: data->packet_types_received[ii], ii); yading@11: } yading@11: #endif yading@11: yading@11: av_free(data); yading@11: } yading@11: yading@11: static int h264_init(AVFormatContext *s, int st_index, PayloadContext *data) yading@11: { yading@11: if (st_index < 0) yading@11: return 0; yading@11: s->streams[st_index]->need_parsing = AVSTREAM_PARSE_FULL; yading@11: return 0; yading@11: } yading@11: yading@11: static int parse_h264_sdp_line(AVFormatContext *s, int st_index, yading@11: PayloadContext *h264_data, const char *line) yading@11: { yading@11: AVStream *stream; yading@11: AVCodecContext *codec; yading@11: const char *p = line; yading@11: yading@11: if (st_index < 0) yading@11: return 0; yading@11: yading@11: stream = s->streams[st_index]; yading@11: codec = stream->codec; yading@11: yading@11: if (av_strstart(p, "framesize:", &p)) { yading@11: char buf1[50]; yading@11: char *dst = buf1; yading@11: yading@11: // remove the protocol identifier yading@11: while (*p && *p == ' ') yading@11: p++; // strip spaces. yading@11: while (*p && *p != ' ') yading@11: p++; // eat protocol identifier yading@11: while (*p && *p == ' ') yading@11: p++; // strip trailing spaces. yading@11: while (*p && *p != '-' && (dst - buf1) < sizeof(buf1) - 1) yading@11: *dst++ = *p++; yading@11: *dst = '\0'; yading@11: yading@11: // a='framesize:96 320-240' yading@11: // set our parameters yading@11: codec->width = atoi(buf1); yading@11: codec->height = atoi(p + 1); // skip the - yading@11: } else if (av_strstart(p, "fmtp:", &p)) { yading@11: return ff_parse_fmtp(stream, h264_data, p, sdp_parse_fmtp_config_h264); yading@11: } else if (av_strstart(p, "cliprect:", &p)) { yading@11: // could use this if we wanted. yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: RTPDynamicProtocolHandler ff_h264_dynamic_handler = { yading@11: .enc_name = "H264", yading@11: .codec_type = AVMEDIA_TYPE_VIDEO, yading@11: .codec_id = AV_CODEC_ID_H264, yading@11: .init = h264_init, yading@11: .parse_sdp_a_line = parse_h264_sdp_line, yading@11: .alloc = h264_new_context, yading@11: .free = h264_free_context, yading@11: .parse_packet = h264_handle_packet yading@11: };