RTSP: Move more SDP/FMTP stuff from rtsp.c to rtpdec_mpeg4.c
[libav.git] / libavformat / rtpdec_mpeg4.c
1 /**
2 * Common code for the RTP depacketization of MPEG-4 formats.
3 * Copyright (c) 2010 Fabrice Bellard
4 * Romain Degez
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * @file
25 * @brief MPEG4 / RTP Code
26 * @author Fabrice Bellard
27 * @author Romain Degez
28 */
29
30 #include "rtpdec_mpeg4.h"
31 #include "internal.h"
32 #include "libavutil/avstring.h"
33 #include <strings.h>
34
35 #include "rtsp.h" //XXX remove this dependency
36
37 /* return the length and optionally the data */
38 static int hex_to_data(uint8_t *data, const char *p)
39 {
40 int c, len, v;
41
42 len = 0;
43 v = 1;
44 for (;;) {
45 p += strspn(p, SPACE_CHARS);
46 if (*p == '\0')
47 break;
48 c = toupper((unsigned char) *p++);
49 if (c >= '0' && c <= '9')
50 c = c - '0';
51 else if (c >= 'A' && c <= 'F')
52 c = c - 'A' + 10;
53 else
54 break;
55 v = (v << 4) | c;
56 if (v & 0x100) {
57 if (data)
58 data[len] = v;
59 len++;
60 v = 1;
61 }
62 }
63 return len;
64 }
65
66 typedef struct {
67 const char *str;
68 uint16_t type;
69 uint32_t offset;
70 } AttrNameMap;
71
72 /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
73 #define ATTR_NAME_TYPE_INT 0
74 #define ATTR_NAME_TYPE_STR 1
75 static const AttrNameMap attr_names[]=
76 {
77 { "SizeLength", ATTR_NAME_TYPE_INT,
78 offsetof(RTPPayloadData, sizelength) },
79 { "IndexLength", ATTR_NAME_TYPE_INT,
80 offsetof(RTPPayloadData, indexlength) },
81 { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
82 offsetof(RTPPayloadData, indexdeltalength) },
83 { "profile-level-id", ATTR_NAME_TYPE_INT,
84 offsetof(RTPPayloadData, profile_level_id) },
85 { "StreamType", ATTR_NAME_TYPE_INT,
86 offsetof(RTPPayloadData, streamtype) },
87 { "mode", ATTR_NAME_TYPE_STR,
88 offsetof(RTPPayloadData, mode) },
89 { NULL, -1, -1 },
90 };
91
92 static int parse_fmtp_config(AVCodecContext * codec, char *value)
93 {
94 /* decode the hexa encoded parameter */
95 int len = hex_to_data(NULL, value);
96 if (codec->extradata)
97 av_free(codec->extradata);
98 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
99 if (!codec->extradata)
100 return AVERROR(ENOMEM);
101 codec->extradata_size = len;
102 hex_to_data(codec->extradata, value);
103 return 0;
104 }
105
106 static int parse_sdp_line(AVFormatContext *s, int st_index,
107 PayloadContext *data, const char *line)
108 {
109 const char *p;
110 char value[4096], attr[25];
111 int res = 0, i;
112 AVStream *st = s->streams[st_index];
113 RTSPStream *rtsp_st = st->priv_data;
114 AVCodecContext* codec = st->codec;
115 RTPPayloadData *rtp_payload_data = &rtsp_st->rtp_payload_data;
116
117 if (av_strstart(line, "fmtp:", &p)) {
118 // remove protocol identifier
119 while (*p && *p == ' ') p++; // strip spaces
120 while (*p && *p != ' ') p++; // eat protocol identifier
121 while (*p && *p == ' ') p++; // strip trailing spaces
122
123 while (ff_rtsp_next_attr_and_value(&p,
124 attr, sizeof(attr),
125 value, sizeof(value))) {
126 if (!strcmp(attr, "config")) {
127 res = parse_fmtp_config(codec, value);
128
129 if (res < 0)
130 return res;
131 }
132
133 if (codec->codec_id == CODEC_ID_AAC) {
134 /* Looking for a known attribute */
135 for (i = 0; attr_names[i].str; ++i) {
136 if (!strcasecmp(attr, attr_names[i].str)) {
137 if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
138 *(int *)((char *)rtp_payload_data +
139 attr_names[i].offset) = atoi(value);
140 } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
141 *(char **)((char *)rtp_payload_data +
142 attr_names[i].offset) = av_strdup(value);
143 }
144 }
145 }
146 }
147 }
148
149 return 0;
150
151 }
152
153 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
154 .enc_name = "MP4V-ES",
155 .codec_type = AVMEDIA_TYPE_VIDEO,
156 .codec_id = CODEC_ID_MPEG4,
157 .parse_sdp_a_line = parse_sdp_line,
158 .open = NULL,
159 .close = NULL,
160 .parse_packet = NULL
161 };
162
163 RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
164 .enc_name = "mpeg4-generic",
165 .codec_type = AVMEDIA_TYPE_AUDIO,
166 .codec_id = CODEC_ID_AAC,
167 .parse_sdp_a_line = parse_sdp_line,
168 .open = NULL,
169 .close = NULL,
170 .parse_packet = NULL
171 };