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

libavformat/rtpdec_mpeg4.c

Go to the documentation of this file.
00001 
00030 #include "rtpdec_formats.h"
00031 #include "internal.h"
00032 #include "libavutil/avstring.h"
00033 #include "libavcodec/get_bits.h"
00034 #include <strings.h>
00035 
00037 struct PayloadContext
00038 {
00039     int sizelength;
00040     int indexlength;
00041     int indexdeltalength;
00042     int profile_level_id;
00043     int streamtype;
00044     int objecttype;
00045     char *mode;
00046 
00048     struct AUHeaders {
00049         int size;
00050         int index;
00051         int cts_flag;
00052         int cts;
00053         int dts_flag;
00054         int dts;
00055         int rap_flag;
00056         int streamstate;
00057     } *au_headers;
00058     int au_headers_allocated;
00059     int nb_au_headers;
00060     int au_headers_length_bytes;
00061     int cur_au_index;
00062 };
00063 
00064 typedef struct {
00065     const char *str;
00066     uint16_t    type;
00067     uint32_t    offset;
00068 } AttrNameMap;
00069 
00070 /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
00071 #define ATTR_NAME_TYPE_INT 0
00072 #define ATTR_NAME_TYPE_STR 1
00073 static const AttrNameMap attr_names[]=
00074 {
00075     { "SizeLength",       ATTR_NAME_TYPE_INT,
00076       offsetof(PayloadContext, sizelength) },
00077     { "IndexLength",      ATTR_NAME_TYPE_INT,
00078       offsetof(PayloadContext, indexlength) },
00079     { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
00080       offsetof(PayloadContext, indexdeltalength) },
00081     { "profile-level-id", ATTR_NAME_TYPE_INT,
00082       offsetof(PayloadContext, profile_level_id) },
00083     { "StreamType",       ATTR_NAME_TYPE_INT,
00084       offsetof(PayloadContext, streamtype) },
00085     { "mode",             ATTR_NAME_TYPE_STR,
00086       offsetof(PayloadContext, mode) },
00087     { NULL, -1, -1 },
00088 };
00089 
00090 static PayloadContext *new_context(void)
00091 {
00092     return av_mallocz(sizeof(PayloadContext));
00093 }
00094 
00095 static void free_context(PayloadContext * data)
00096 {
00097     int i;
00098     for (i = 0; i < data->nb_au_headers; i++) {
00099          /* according to rtp_parse_mp4_au, we treat multiple
00100           * au headers as one, so nb_au_headers is always 1.
00101           * loop anyway in case this changes.
00102           * (note: changes done carelessly might lead to a double free)
00103           */
00104        av_free(&data->au_headers[i]);
00105     }
00106     av_free(data->mode);
00107     av_free(data);
00108 }
00109 
00110 static int parse_fmtp_config(AVCodecContext * codec, char *value)
00111 {
00112     /* decode the hexa encoded parameter */
00113     int len = ff_hex_to_data(NULL, value);
00114     av_free(codec->extradata);
00115     codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
00116     if (!codec->extradata)
00117         return AVERROR(ENOMEM);
00118     codec->extradata_size = len;
00119     ff_hex_to_data(codec->extradata, value);
00120     return 0;
00121 }
00122 
00123 static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf)
00124 {
00125     int au_headers_length, au_header_size, i;
00126     GetBitContext getbitcontext;
00127 
00128     /* decode the first 2 bytes where the AUHeader sections are stored
00129        length in bits */
00130     au_headers_length = AV_RB16(buf);
00131 
00132     if (au_headers_length > RTP_MAX_PACKET_LENGTH)
00133       return -1;
00134 
00135     data->au_headers_length_bytes = (au_headers_length + 7) / 8;
00136 
00137     /* skip AU headers length section (2 bytes) */
00138     buf += 2;
00139 
00140     init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
00141 
00142     /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */
00143     au_header_size = data->sizelength + data->indexlength;
00144     if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
00145         return -1;
00146 
00147     data->nb_au_headers = au_headers_length / au_header_size;
00148     if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
00149         av_free(data->au_headers);
00150         data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
00151         data->au_headers_allocated = data->nb_au_headers;
00152     }
00153 
00154     /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving)
00155        In my test, the FAAD decoder does not behave correctly when sending each AU one by one
00156        but does when sending the whole as one big packet...  */
00157     data->au_headers[0].size = 0;
00158     data->au_headers[0].index = 0;
00159     for (i = 0; i < data->nb_au_headers; ++i) {
00160         data->au_headers[0].size += get_bits_long(&getbitcontext, data->sizelength);
00161         data->au_headers[0].index = get_bits_long(&getbitcontext, data->indexlength);
00162     }
00163 
00164     data->nb_au_headers = 1;
00165 
00166     return 0;
00167 }
00168 
00169 
00170 /* Follows RFC 3640 */
00171 static int aac_parse_packet(AVFormatContext *ctx,
00172                             PayloadContext *data,
00173                             AVStream *st,
00174                             AVPacket *pkt,
00175                             uint32_t *timestamp,
00176                             const uint8_t *buf, int len, int flags)
00177 {
00178     if (rtp_parse_mp4_au(data, buf))
00179         return -1;
00180 
00181     buf += data->au_headers_length_bytes + 2;
00182     len -= data->au_headers_length_bytes + 2;
00183 
00184     /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define
00185                     one au_header */
00186     av_new_packet(pkt, data->au_headers[0].size);
00187     memcpy(pkt->data, buf, data->au_headers[0].size);
00188 
00189     pkt->stream_index = st->index;
00190     return 0;
00191 }
00192 
00193 static int parse_fmtp(AVStream *stream, PayloadContext *data,
00194                       char *attr, char *value)
00195 {
00196     AVCodecContext *codec = stream->codec;
00197     int res, i;
00198 
00199     if (!strcmp(attr, "config")) {
00200         res = parse_fmtp_config(codec, value);
00201 
00202         if (res < 0)
00203             return res;
00204     }
00205 
00206     if (codec->codec_id == CODEC_ID_AAC) {
00207         /* Looking for a known attribute */
00208         for (i = 0; attr_names[i].str; ++i) {
00209             if (!strcasecmp(attr, attr_names[i].str)) {
00210                 if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
00211                     *(int *)((char *)data+
00212                         attr_names[i].offset) = atoi(value);
00213                 } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
00214                     *(char **)((char *)data+
00215                         attr_names[i].offset) = av_strdup(value);
00216             }
00217         }
00218     }
00219     return 0;
00220 }
00221 
00222 static int parse_sdp_line(AVFormatContext *s, int st_index,
00223                           PayloadContext *data, const char *line)
00224 {
00225     const char *p;
00226 
00227     if (av_strstart(line, "fmtp:", &p))
00228         return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
00229 
00230     return 0;
00231 }
00232 
00233 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
00234     .enc_name           = "MP4V-ES",
00235     .codec_type         = AVMEDIA_TYPE_VIDEO,
00236     .codec_id           = CODEC_ID_MPEG4,
00237     .parse_sdp_a_line   = parse_sdp_line,
00238     .alloc              = NULL,
00239     .free               = NULL,
00240     .parse_packet       = NULL
00241 };
00242 
00243 RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
00244     .enc_name           = "mpeg4-generic",
00245     .codec_type         = AVMEDIA_TYPE_AUDIO,
00246     .codec_id           = CODEC_ID_AAC,
00247     .parse_sdp_a_line   = parse_sdp_line,
00248     .alloc              = new_context,
00249     .free               = free_context,
00250     .parse_packet       = aac_parse_packet
00251 };

Generated on Wed Apr 11 2012 07:31:36 for FFmpeg by  doxygen 1.7.1