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