00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00036 #include "libavutil/base64.h"
00037 #include "libavutil/avstring.h"
00038 #include "libavcodec/get_bits.h"
00039 #include "avformat.h"
00040 #include "mpegts.h"
00041
00042 #include <unistd.h>
00043 #include "network.h"
00044 #include <assert.h>
00045
00046 #include "rtpdec.h"
00047 #include "rtpdec_formats.h"
00048
00049 struct PayloadContext {
00050
00051 uint8_t profile_idc;
00052 uint8_t profile_iop;
00053 uint8_t level_idc;
00054 int packetization_mode;
00055 #ifdef DEBUG
00056 int packet_types_received[32];
00057 #endif
00058 };
00059
00060 #ifdef DEBUG
00061 #define COUNT_NAL_TYPE(data, nal) data->packet_types_received[(nal) & 0x1f]++
00062 #else
00063 #define COUNT_NAL_TYPE(data, nal) do { } while (0)
00064 #endif
00065
00066 static const uint8_t start_sequence[] = { 0, 0, 0, 1 };
00067
00068 static int sdp_parse_fmtp_config_h264(AVStream *stream,
00069 PayloadContext *h264_data,
00070 char *attr, char *value)
00071 {
00072 AVCodecContext *codec = stream->codec;
00073 assert(codec->codec_id == CODEC_ID_H264);
00074 assert(h264_data != NULL);
00075
00076 if (!strcmp(attr, "packetization-mode")) {
00077 av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
00078 h264_data->packetization_mode = atoi(value);
00079
00080
00081
00082
00083
00084
00085
00086 if (h264_data->packetization_mode > 1)
00087 av_log(codec, AV_LOG_ERROR,
00088 "Interleaved RTP mode is not supported yet.\n");
00089 } else if (!strcmp(attr, "profile-level-id")) {
00090 if (strlen(value) == 6) {
00091 char buffer[3];
00092
00093 uint8_t profile_idc;
00094 uint8_t profile_iop;
00095 uint8_t level_idc;
00096
00097 buffer[0] = value[0];
00098 buffer[1] = value[1];
00099 buffer[2] = '\0';
00100 profile_idc = strtol(buffer, NULL, 16);
00101 buffer[0] = value[2];
00102 buffer[1] = value[3];
00103 profile_iop = strtol(buffer, NULL, 16);
00104 buffer[0] = value[4];
00105 buffer[1] = value[5];
00106 level_idc = strtol(buffer, NULL, 16);
00107
00108 av_log(codec, AV_LOG_DEBUG,
00109 "RTP Profile IDC: %x Profile IOP: %x Level: %x\n",
00110 profile_idc, profile_iop, level_idc);
00111 h264_data->profile_idc = profile_idc;
00112 h264_data->profile_iop = profile_iop;
00113 h264_data->level_idc = level_idc;
00114 }
00115 } else if (!strcmp(attr, "sprop-parameter-sets")) {
00116 codec->extradata_size = 0;
00117 av_freep(&codec->extradata);
00118
00119 while (*value) {
00120 char base64packet[1024];
00121 uint8_t decoded_packet[1024];
00122 int packet_size;
00123 char *dst = base64packet;
00124
00125 while (*value && *value != ','
00126 && (dst - base64packet) < sizeof(base64packet) - 1) {
00127 *dst++ = *value++;
00128 }
00129 *dst++ = '\0';
00130
00131 if (*value == ',')
00132 value++;
00133
00134 packet_size = av_base64_decode(decoded_packet, base64packet,
00135 sizeof(decoded_packet));
00136 if (packet_size > 0) {
00137 uint8_t *dest = av_malloc(packet_size + sizeof(start_sequence) +
00138 codec->extradata_size +
00139 FF_INPUT_BUFFER_PADDING_SIZE);
00140 if (!dest) {
00141 av_log(codec, AV_LOG_ERROR,
00142 "Unable to allocate memory for extradata!\n");
00143 return AVERROR(ENOMEM);
00144 }
00145 if (codec->extradata_size) {
00146 memcpy(dest, codec->extradata, codec->extradata_size);
00147 av_free(codec->extradata);
00148 }
00149
00150 memcpy(dest + codec->extradata_size, start_sequence,
00151 sizeof(start_sequence));
00152 memcpy(dest + codec->extradata_size + sizeof(start_sequence),
00153 decoded_packet, packet_size);
00154 memset(dest + codec->extradata_size + sizeof(start_sequence) +
00155 packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00156
00157 codec->extradata = dest;
00158 codec->extradata_size += sizeof(start_sequence) + packet_size;
00159 }
00160 }
00161 av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!\n",
00162 codec->extradata, codec->extradata_size);
00163 }
00164 return 0;
00165 }
00166
00167
00168 static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data,
00169 AVStream *st, AVPacket *pkt, uint32_t *timestamp,
00170 const uint8_t *buf, int len, int flags)
00171 {
00172 uint8_t nal;
00173 uint8_t type;
00174 int result = 0;
00175
00176 if (!len) {
00177 av_log(ctx, AV_LOG_ERROR, "Empty H264 RTP packet\n");
00178 return AVERROR_INVALIDDATA;
00179 }
00180 nal = buf[0];
00181 type = nal & 0x1f;
00182
00183 assert(data);
00184 assert(buf);
00185
00186
00187
00188 if (type >= 1 && type <= 23)
00189 type = 1;
00190 switch (type) {
00191 case 0:
00192 case 1:
00193 av_new_packet(pkt, len + sizeof(start_sequence));
00194 memcpy(pkt->data, start_sequence, sizeof(start_sequence));
00195 memcpy(pkt->data + sizeof(start_sequence), buf, len);
00196 COUNT_NAL_TYPE(data, nal);
00197 break;
00198
00199 case 24:
00200
00201 buf++;
00202 len--;
00203
00204 {
00205 int pass = 0;
00206 int total_length = 0;
00207 uint8_t *dst = NULL;
00208
00209 for (pass = 0; pass < 2; pass++) {
00210 const uint8_t *src = buf;
00211 int src_len = len;
00212
00213 while (src_len > 2) {
00214 uint16_t nal_size = AV_RB16(src);
00215
00216
00217 src += 2;
00218 src_len -= 2;
00219
00220 if (nal_size <= src_len) {
00221 if (pass == 0) {
00222
00223 total_length += sizeof(start_sequence) + nal_size;
00224 } else {
00225
00226 assert(dst);
00227 memcpy(dst, start_sequence, sizeof(start_sequence));
00228 dst += sizeof(start_sequence);
00229 memcpy(dst, src, nal_size);
00230 COUNT_NAL_TYPE(data, *src);
00231 dst += nal_size;
00232 }
00233 } else {
00234 av_log(ctx, AV_LOG_ERROR,
00235 "nal size exceeds length: %d %d\n", nal_size, src_len);
00236 }
00237
00238
00239 src += nal_size;
00240 src_len -= nal_size;
00241
00242 if (src_len < 0)
00243 av_log(ctx, AV_LOG_ERROR,
00244 "Consumed more bytes than we got! (%d)\n", src_len);
00245 }
00246
00247 if (pass == 0) {
00248
00249
00250 av_new_packet(pkt, total_length);
00251 dst = pkt->data;
00252 } else {
00253 assert(dst - pkt->data == total_length);
00254 }
00255 }
00256 }
00257 break;
00258
00259 case 25:
00260 case 26:
00261 case 27:
00262 case 29:
00263 av_log(ctx, AV_LOG_ERROR,
00264 "Unhandled type (%d) (See RFC for implementation details\n",
00265 type);
00266 result = AVERROR(ENOSYS);
00267 break;
00268
00269 case 28:
00270 buf++;
00271 len--;
00272 if (len > 1) {
00273
00274 uint8_t fu_indicator = nal;
00275 uint8_t fu_header = *buf;
00276 uint8_t start_bit = fu_header >> 7;
00277 uint8_t av_unused end_bit = (fu_header & 0x40) >> 6;
00278 uint8_t nal_type = fu_header & 0x1f;
00279 uint8_t reconstructed_nal;
00280
00281
00282
00283
00284 reconstructed_nal = fu_indicator & 0xe0;
00285 reconstructed_nal |= nal_type;
00286
00287
00288 buf++;
00289 len--;
00290
00291 if (start_bit)
00292 COUNT_NAL_TYPE(data, nal_type);
00293 if (start_bit) {
00294
00295 av_new_packet(pkt, sizeof(start_sequence) + sizeof(nal) + len);
00296 memcpy(pkt->data, start_sequence, sizeof(start_sequence));
00297 pkt->data[sizeof(start_sequence)] = reconstructed_nal;
00298 memcpy(pkt->data + sizeof(start_sequence) + sizeof(nal), buf, len);
00299 } else {
00300 av_new_packet(pkt, len);
00301 memcpy(pkt->data, buf, len);
00302 }
00303 } else {
00304 av_log(ctx, AV_LOG_ERROR, "Too short data for FU-A H264 RTP packet\n");
00305 result = AVERROR_INVALIDDATA;
00306 }
00307 break;
00308
00309 case 30:
00310 case 31:
00311 default:
00312 av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)\n", type);
00313 result = AVERROR_INVALIDDATA;
00314 break;
00315 }
00316
00317 pkt->stream_index = st->index;
00318
00319 return result;
00320 }
00321
00322 static PayloadContext *h264_new_context(void)
00323 {
00324 return av_mallocz(sizeof(PayloadContext) + FF_INPUT_BUFFER_PADDING_SIZE);
00325 }
00326
00327 static void h264_free_context(PayloadContext *data)
00328 {
00329 #ifdef DEBUG
00330 int ii;
00331
00332 for (ii = 0; ii < 32; ii++) {
00333 if (data->packet_types_received[ii])
00334 av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n",
00335 data->packet_types_received[ii], ii);
00336 }
00337 #endif
00338
00339 av_free(data);
00340 }
00341
00342 static int parse_h264_sdp_line(AVFormatContext *s, int st_index,
00343 PayloadContext *h264_data, const char *line)
00344 {
00345 AVStream *stream;
00346 AVCodecContext *codec;
00347 const char *p = line;
00348
00349 if (st_index < 0)
00350 return 0;
00351
00352 stream = s->streams[st_index];
00353 codec = stream->codec;
00354
00355 if (av_strstart(p, "framesize:", &p)) {
00356 char buf1[50];
00357 char *dst = buf1;
00358
00359
00360 while (*p && *p == ' ')
00361 p++;
00362 while (*p && *p != ' ')
00363 p++;
00364 while (*p && *p == ' ')
00365 p++;
00366 while (*p && *p != '-' && (dst - buf1) < sizeof(buf1) - 1)
00367 *dst++ = *p++;
00368 *dst = '\0';
00369
00370
00371
00372 codec->width = atoi(buf1);
00373 codec->height = atoi(p + 1);
00374 codec->pix_fmt = PIX_FMT_YUV420P;
00375 } else if (av_strstart(p, "fmtp:", &p)) {
00376 return ff_parse_fmtp(stream, h264_data, p, sdp_parse_fmtp_config_h264);
00377 } else if (av_strstart(p, "cliprect:", &p)) {
00378
00379 }
00380
00381 return 0;
00382 }
00383
00384 RTPDynamicProtocolHandler ff_h264_dynamic_handler = {
00385 .enc_name = "H264",
00386 .codec_type = AVMEDIA_TYPE_VIDEO,
00387 .codec_id = CODEC_ID_H264,
00388 .parse_sdp_a_line = parse_h264_sdp_line,
00389 .alloc = h264_new_context,
00390 .free = h264_free_context,
00391 .parse_packet = h264_handle_packet
00392 };