• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/rtpdec_h264.c

Go to the documentation of this file.
00001 /*
00002  * RTP H264 Protocol (RFC3984)
00003  * Copyright (c) 2006 Ryan Martell
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00039 #include "libavutil/base64.h"
00040 #include "libavutil/avstring.h"
00041 #include "libavcodec/get_bits.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 "rtpdec_h264.h"
00051 
00055 struct PayloadContext {
00056     unsigned long cookie;       
00057 
00058     //sdp setup parameters
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)       ///< Cookie for the extradata; to verify we are what we think we are, and that we haven't been freed.
00069 #define DEAD_COOKIE (0xdeaddead)        ///< Cookie for the extradata; once it is freed.
00070 
00071 /* ---------------- private code */
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(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
00082         h264_data->packetization_mode = atoi(value);
00083         /*
00084            Packetization Mode:
00085            0 or not present: Single NAL mode (Only nals from 1-23 are allowed)
00086            1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed.
00087            2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A), and 29 (FU-B) are allowed.
00088          */
00089         if (h264_data->packetization_mode > 1)
00090             av_log(codec, AV_LOG_ERROR,
00091                    "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             // 6 characters=3 bytes, in hex.
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             // set the parameters...
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         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) +
00138                                          codec->extradata_size +
00139                                          FF_INPUT_BUFFER_PADDING_SIZE);
00140                 if(dest)
00141                 {
00142                     if(codec->extradata_size)
00143                     {
00144                         // av_realloc?
00145                         memcpy(dest, codec->extradata, codec->extradata_size);
00146                         av_free(codec->extradata);
00147                     }
00148 
00149                     memcpy(dest+codec->extradata_size, start_sequence, sizeof(start_sequence));
00150                     memcpy(dest+codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size);
00151                     memset(dest+codec->extradata_size+sizeof(start_sequence)+
00152                            packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00153 
00154                     codec->extradata= dest;
00155                     codec->extradata_size+= sizeof(start_sequence)+packet_size;
00156                 } else {
00157                     av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!");
00158                 }
00159             }
00160         }
00161         av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!", codec->extradata, codec->extradata_size);
00162     }
00163 }
00164 
00165 // return 0 on packet, no more left, 1 on packet, 1 on partial packet...
00166 static int h264_handle_packet(AVFormatContext *ctx,
00167                               PayloadContext *data,
00168                               AVStream *st,
00169                               AVPacket * pkt,
00170                               uint32_t * timestamp,
00171                               const uint8_t * buf,
00172                               int len, int flags)
00173 {
00174     uint8_t nal = buf[0];
00175     uint8_t type = (nal & 0x1f);
00176     int result= 0;
00177     uint8_t start_sequence[]= {0, 0, 1};
00178 
00179 #ifdef DEBUG
00180     assert(data);
00181     assert(data->cookie == MAGIC_COOKIE);
00182 #endif
00183     assert(buf);
00184 
00185     if (type >= 1 && type <= 23)
00186         type = 1;              // simplify the case. (these are all the nal types used internally by the h264 codec)
00187     switch (type) {
00188     case 0:                    // undefined;
00189         result= -1;
00190         break;
00191 
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 #ifdef DEBUG
00197         data->packet_types_received[nal & 0x1f]++;
00198 #endif
00199         break;
00200 
00201     case 24:                   // STAP-A (one packet, multiple nals)
00202         // consume the STAP-A NAL
00203         buf++;
00204         len--;
00205         // first we are going to figure out the total size....
00206         {
00207             int pass= 0;
00208             int total_length= 0;
00209             uint8_t *dst= NULL;
00210 
00211             for(pass= 0; pass<2; pass++) {
00212                 const uint8_t *src= buf;
00213                 int src_len= len;
00214 
00215                 do {
00216                     uint16_t nal_size = AV_RB16(src); // this going to be a problem if unaligned (can it be?)
00217 
00218                     // consume the length of the aggregate...
00219                     src += 2;
00220                     src_len -= 2;
00221 
00222                     if (nal_size <= src_len) {
00223                         if(pass==0) {
00224                             // counting...
00225                             total_length+= sizeof(start_sequence)+nal_size;
00226                         } else {
00227                             // copying
00228                             assert(dst);
00229                             memcpy(dst, start_sequence, sizeof(start_sequence));
00230                             dst+= sizeof(start_sequence);
00231                             memcpy(dst, src, nal_size);
00232 #ifdef DEBUG
00233                             data->packet_types_received[*src & 0x1f]++;
00234 #endif
00235                             dst+= nal_size;
00236                         }
00237                     } else {
00238                         av_log(ctx, AV_LOG_ERROR,
00239                                "nal size exceeds length: %d %d\n", nal_size, src_len);
00240                     }
00241 
00242                     // eat what we handled...
00243                     src += nal_size;
00244                     src_len -= nal_size;
00245 
00246                     if (src_len < 0)
00247                         av_log(ctx, AV_LOG_ERROR,
00248                                "Consumed more bytes than we got! (%d)\n", src_len);
00249                 } while (src_len > 2);      // because there could be rtp padding..
00250 
00251                 if(pass==0) {
00252                     // now we know the total size of the packet (with the start sequences added)
00253                     av_new_packet(pkt, total_length);
00254                     dst= pkt->data;
00255                 } else {
00256                     assert(dst-pkt->data==total_length);
00257                 }
00258             }
00259         }
00260         break;
00261 
00262     case 25:                   // STAP-B
00263     case 26:                   // MTAP-16
00264     case 27:                   // MTAP-24
00265     case 29:                   // FU-B
00266         av_log(ctx, AV_LOG_ERROR,
00267                "Unhandled type (%d) (See RFC for implementation details\n",
00268                type);
00269         result= -1;
00270         break;
00271 
00272     case 28:                   // FU-A (fragmented nal)
00273         buf++;
00274         len--;                  // skip the fu_indicator
00275         {
00276             // these are the same as above, we just redo them here for clarity...
00277             uint8_t fu_indicator = nal;
00278             uint8_t fu_header = *buf;   // read the fu_header.
00279             uint8_t start_bit = fu_header >> 7;
00280 //            uint8_t end_bit = (fu_header & 0x40) >> 6;
00281             uint8_t nal_type = (fu_header & 0x1f);
00282             uint8_t reconstructed_nal;
00283 
00284             // reconstruct this packet's true nal; only the data follows..
00285             reconstructed_nal = fu_indicator & (0xe0);  // the original nal forbidden bit and NRI are stored in this packet's nal;
00286             reconstructed_nal |= nal_type;
00287 
00288             // skip the fu_header...
00289             buf++;
00290             len--;
00291 
00292 #ifdef DEBUG
00293             if (start_bit)
00294                 data->packet_types_received[nal_type]++;
00295 #endif
00296             if(start_bit) {
00297                 // copy in the start sequence, and the reconstructed nal....
00298                 av_new_packet(pkt, sizeof(start_sequence)+sizeof(nal)+len);
00299                 memcpy(pkt->data, start_sequence, sizeof(start_sequence));
00300                 pkt->data[sizeof(start_sequence)]= reconstructed_nal;
00301                 memcpy(pkt->data+sizeof(start_sequence)+sizeof(nal), buf, len);
00302             } else {
00303                 av_new_packet(pkt, len);
00304                 memcpy(pkt->data, buf, len);
00305             }
00306         }
00307         break;
00308 
00309     case 30:                   // undefined
00310     case 31:                   // undefined
00311     default:
00312         av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)", type);
00313         result= -1;
00314         break;
00315     }
00316 
00317     pkt->stream_index = st->index;
00318 
00319     return result;
00320 }
00321 
00322 /* ---------------- public code */
00323 static PayloadContext *h264_new_context(void)
00324 {
00325     PayloadContext *data =
00326         av_mallocz(sizeof(PayloadContext) +
00327                    FF_INPUT_BUFFER_PADDING_SIZE);
00328 
00329     if (data) {
00330         data->cookie = MAGIC_COOKIE;
00331     }
00332 
00333     return data;
00334 }
00335 
00336 static void h264_free_context(PayloadContext *data)
00337 {
00338 #ifdef DEBUG
00339     int ii;
00340 
00341     for (ii = 0; ii < 32; ii++) {
00342         if (data->packet_types_received[ii])
00343             av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n",
00344                    data->packet_types_received[ii], ii);
00345     }
00346 #endif
00347 
00348     assert(data);
00349     assert(data->cookie == MAGIC_COOKIE);
00350 
00351     // avoid stale pointers (assert)
00352     data->cookie = DEAD_COOKIE;
00353 
00354     // and clear out this...
00355     av_free(data);
00356 }
00357 
00358 static int parse_h264_sdp_line(AVFormatContext *s, int st_index,
00359                                PayloadContext *h264_data, const char *line)
00360 {
00361     AVStream *stream = s->streams[st_index];
00362     AVCodecContext *codec = stream->codec;
00363     const char *p = line;
00364 
00365     assert(h264_data->cookie == MAGIC_COOKIE);
00366 
00367     if (av_strstart(p, "framesize:", &p)) {
00368         char buf1[50];
00369         char *dst = buf1;
00370 
00371         // remove the protocol identifier..
00372         while (*p && *p == ' ') p++; // strip spaces.
00373         while (*p && *p != ' ') p++; // eat protocol identifier
00374         while (*p && *p == ' ') p++; // strip trailing spaces.
00375         while (*p && *p != '-' && (dst - buf1) < sizeof(buf1) - 1) {
00376             *dst++ = *p++;
00377         }
00378         *dst = '\0';
00379 
00380         // a='framesize:96 320-240'
00381         // set our parameters..
00382         codec->width = atoi(buf1);
00383         codec->height = atoi(p + 1); // skip the -
00384         codec->pix_fmt = PIX_FMT_YUV420P;
00385     } else if (av_strstart(p, "fmtp:", &p)) {
00386         char attr[256];
00387         char value[4096];
00388 
00389         // remove the protocol identifier..
00390         while (*p && *p == ' ') p++; // strip spaces.
00391         while (*p && *p != ' ') p++; // eat protocol identifier
00392         while (*p && *p == ' ') p++; // strip trailing spaces.
00393 
00394         /* loop on each attribute */
00395         while (ff_rtsp_next_attr_and_value
00396                (&p, attr, sizeof(attr), value, sizeof(value))) {
00397             /* grab the codec extra_data from the config parameter of the fmtp line */
00398             sdp_parse_fmtp_config_h264(stream, h264_data, attr, value);
00399         }
00400     } else if (av_strstart(p, "cliprect:", &p)) {
00401         // could use this if we wanted.
00402     }
00403 
00404     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)
00405 
00406     return 0;                   // keep processing it the normal way...
00407 }
00408 
00412 RTPDynamicProtocolHandler ff_h264_dynamic_handler = {
00413     .enc_name         = "H264",
00414     .codec_type       = AVMEDIA_TYPE_VIDEO,
00415     .codec_id         = CODEC_ID_H264,
00416     .parse_sdp_a_line = parse_h264_sdp_line,
00417     .open             = h264_new_context,
00418     .close            = h264_free_context,
00419     .parse_packet     = h264_handle_packet
00420 };

Generated on Fri Sep 16 2011 17:17:50 for FFmpeg by  doxygen 1.7.1