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