xref: /third_party/ffmpeg/libavformat/sdp.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * copyright (c) 2007 Luca Abeni
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include "config_components.h"
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include <string.h>
24cabdff1aSopenharmony_ci#include "libavutil/avstring.h"
25cabdff1aSopenharmony_ci#include "libavutil/base64.h"
26cabdff1aSopenharmony_ci#include "libavutil/dict.h"
27cabdff1aSopenharmony_ci#include "libavutil/parseutils.h"
28cabdff1aSopenharmony_ci#include "libavutil/opt.h"
29cabdff1aSopenharmony_ci#include "libavcodec/xiph.h"
30cabdff1aSopenharmony_ci#include "libavcodec/mpeg4audio.h"
31cabdff1aSopenharmony_ci#include "avformat.h"
32cabdff1aSopenharmony_ci#include "internal.h"
33cabdff1aSopenharmony_ci#include "avc.h"
34cabdff1aSopenharmony_ci#include "hevc.h"
35cabdff1aSopenharmony_ci#include "rtp.h"
36cabdff1aSopenharmony_ci#if CONFIG_NETWORK
37cabdff1aSopenharmony_ci#include "network.h"
38cabdff1aSopenharmony_ci#endif
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci#if CONFIG_RTP_MUXER
41cabdff1aSopenharmony_ci#define MAX_EXTRADATA_SIZE ((INT_MAX - 10) / 2)
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_cistruct sdp_session_level {
44cabdff1aSopenharmony_ci    int sdp_version;      /**< protocol version (currently 0) */
45cabdff1aSopenharmony_ci    int id;               /**< session ID */
46cabdff1aSopenharmony_ci    int version;          /**< session version */
47cabdff1aSopenharmony_ci    int start_time;       /**< session start time (NTP time, in seconds),
48cabdff1aSopenharmony_ci                               or 0 in case of permanent session */
49cabdff1aSopenharmony_ci    int end_time;         /**< session end time (NTP time, in seconds),
50cabdff1aSopenharmony_ci                               or 0 if the session is not bounded */
51cabdff1aSopenharmony_ci    int ttl;              /**< TTL, in case of multicast stream */
52cabdff1aSopenharmony_ci    const char *user;     /**< username of the session's creator */
53cabdff1aSopenharmony_ci    const char *src_addr; /**< IP address of the machine from which the session was created */
54cabdff1aSopenharmony_ci    const char *src_type; /**< address type of src_addr */
55cabdff1aSopenharmony_ci    const char *dst_addr; /**< destination IP address (can be multicast) */
56cabdff1aSopenharmony_ci    const char *dst_type; /**< destination IP address type */
57cabdff1aSopenharmony_ci    const char *name;     /**< session name (can be an empty string) */
58cabdff1aSopenharmony_ci};
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_cistatic void sdp_write_address(char *buff, int size, const char *dest_addr,
61cabdff1aSopenharmony_ci                              const char *dest_type, int ttl)
62cabdff1aSopenharmony_ci{
63cabdff1aSopenharmony_ci    if (dest_addr) {
64cabdff1aSopenharmony_ci        if (!dest_type)
65cabdff1aSopenharmony_ci            dest_type = "IP4";
66cabdff1aSopenharmony_ci        if (ttl > 0 && !strcmp(dest_type, "IP4")) {
67cabdff1aSopenharmony_ci            /* The TTL should only be specified for IPv4 multicast addresses,
68cabdff1aSopenharmony_ci             * not for IPv6. */
69cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "c=IN %s %s/%d\r\n", dest_type, dest_addr, ttl);
70cabdff1aSopenharmony_ci        } else {
71cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "c=IN %s %s\r\n", dest_type, dest_addr);
72cabdff1aSopenharmony_ci        }
73cabdff1aSopenharmony_ci    }
74cabdff1aSopenharmony_ci}
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_cistatic void sdp_write_header(char *buff, int size, struct sdp_session_level *s)
77cabdff1aSopenharmony_ci{
78cabdff1aSopenharmony_ci    av_strlcatf(buff, size, "v=%d\r\n"
79cabdff1aSopenharmony_ci                            "o=- %d %d IN %s %s\r\n"
80cabdff1aSopenharmony_ci                            "s=%s\r\n",
81cabdff1aSopenharmony_ci                            s->sdp_version,
82cabdff1aSopenharmony_ci                            s->id, s->version, s->src_type, s->src_addr,
83cabdff1aSopenharmony_ci                            s->name);
84cabdff1aSopenharmony_ci    sdp_write_address(buff, size, s->dst_addr, s->dst_type, s->ttl);
85cabdff1aSopenharmony_ci    av_strlcatf(buff, size, "t=%d %d\r\n"
86cabdff1aSopenharmony_ci                            "a=tool:libavformat " AV_STRINGIFY(LIBAVFORMAT_VERSION) "\r\n",
87cabdff1aSopenharmony_ci                            s->start_time, s->end_time);
88cabdff1aSopenharmony_ci}
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci#if CONFIG_NETWORK
91cabdff1aSopenharmony_cistatic int resolve_destination(char *dest_addr, int size, char *type,
92cabdff1aSopenharmony_ci                               int type_size)
93cabdff1aSopenharmony_ci{
94cabdff1aSopenharmony_ci    struct addrinfo hints = { 0 }, *ai;
95cabdff1aSopenharmony_ci    int is_multicast;
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ci    av_strlcpy(type, "IP4", type_size);
98cabdff1aSopenharmony_ci    if (!dest_addr[0])
99cabdff1aSopenharmony_ci        return 0;
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci    /* Resolve the destination, since it must be written
102cabdff1aSopenharmony_ci     * as a numeric IP address in the SDP. */
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_ci    if (getaddrinfo(dest_addr, NULL, &hints, &ai))
105cabdff1aSopenharmony_ci        return 0;
106cabdff1aSopenharmony_ci    getnameinfo(ai->ai_addr, ai->ai_addrlen, dest_addr, size,
107cabdff1aSopenharmony_ci                NULL, 0, NI_NUMERICHOST);
108cabdff1aSopenharmony_ci#ifdef AF_INET6
109cabdff1aSopenharmony_ci    if (ai->ai_family == AF_INET6)
110cabdff1aSopenharmony_ci        av_strlcpy(type, "IP6", type_size);
111cabdff1aSopenharmony_ci#endif
112cabdff1aSopenharmony_ci    is_multicast = ff_is_multicast_address(ai->ai_addr);
113cabdff1aSopenharmony_ci    freeaddrinfo(ai);
114cabdff1aSopenharmony_ci    return is_multicast;
115cabdff1aSopenharmony_ci}
116cabdff1aSopenharmony_ci#else
117cabdff1aSopenharmony_cistatic int resolve_destination(char *dest_addr, int size, char *type,
118cabdff1aSopenharmony_ci                               int type_size)
119cabdff1aSopenharmony_ci{
120cabdff1aSopenharmony_ci    return 0;
121cabdff1aSopenharmony_ci}
122cabdff1aSopenharmony_ci#endif
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_cistatic int sdp_get_address(char *dest_addr, int size, int *ttl, const char *url)
125cabdff1aSopenharmony_ci{
126cabdff1aSopenharmony_ci    int port;
127cabdff1aSopenharmony_ci    const char *p;
128cabdff1aSopenharmony_ci    char proto[32];
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_ci    av_url_split(proto, sizeof(proto), NULL, 0, dest_addr, size, &port, NULL, 0, url);
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    *ttl = 0;
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_ci    if (strcmp(proto, "rtp") && strcmp(proto, "srtp")) {
135cabdff1aSopenharmony_ci        /* The url isn't for the actual rtp sessions,
136cabdff1aSopenharmony_ci         * don't parse out anything else than the destination.
137cabdff1aSopenharmony_ci         */
138cabdff1aSopenharmony_ci        return 0;
139cabdff1aSopenharmony_ci    }
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_ci    p = strchr(url, '?');
142cabdff1aSopenharmony_ci    if (p) {
143cabdff1aSopenharmony_ci        char buff[64];
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci        if (av_find_info_tag(buff, sizeof(buff), "ttl", p)) {
146cabdff1aSopenharmony_ci            *ttl = strtol(buff, NULL, 10);
147cabdff1aSopenharmony_ci        } else {
148cabdff1aSopenharmony_ci            *ttl = 5;
149cabdff1aSopenharmony_ci        }
150cabdff1aSopenharmony_ci    }
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_ci    return port;
153cabdff1aSopenharmony_ci}
154cabdff1aSopenharmony_ci
155cabdff1aSopenharmony_ci#define MAX_PSET_SIZE 1024
156cabdff1aSopenharmony_cistatic int extradata2psets(AVFormatContext *s, const AVCodecParameters *par,
157cabdff1aSopenharmony_ci                           char **out)
158cabdff1aSopenharmony_ci{
159cabdff1aSopenharmony_ci    char *psets, *p;
160cabdff1aSopenharmony_ci    const uint8_t *r;
161cabdff1aSopenharmony_ci    static const char pset_string[] = "; sprop-parameter-sets=";
162cabdff1aSopenharmony_ci    static const char profile_string[] = "; profile-level-id=";
163cabdff1aSopenharmony_ci    uint8_t *extradata = par->extradata;
164cabdff1aSopenharmony_ci    int extradata_size = par->extradata_size;
165cabdff1aSopenharmony_ci    uint8_t *tmpbuf = NULL;
166cabdff1aSopenharmony_ci    const uint8_t *sps = NULL, *sps_end;
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    *out = NULL;
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_ci    if (par->extradata_size > MAX_EXTRADATA_SIZE) {
171cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Too much extradata!\n");
172cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
173cabdff1aSopenharmony_ci    }
174cabdff1aSopenharmony_ci    if (par->extradata[0] == 1) {
175cabdff1aSopenharmony_ci        int ret = ff_avc_write_annexb_extradata(par->extradata, &extradata,
176cabdff1aSopenharmony_ci                                                &extradata_size);
177cabdff1aSopenharmony_ci        if (ret < 0)
178cabdff1aSopenharmony_ci            return ret;
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci        tmpbuf = extradata;
181cabdff1aSopenharmony_ci    }
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci    psets = av_mallocz(MAX_PSET_SIZE);
184cabdff1aSopenharmony_ci    if (!psets) {
185cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Cannot allocate memory for the parameter sets.\n");
186cabdff1aSopenharmony_ci        av_free(tmpbuf);
187cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
188cabdff1aSopenharmony_ci    }
189cabdff1aSopenharmony_ci    memcpy(psets, pset_string, strlen(pset_string));
190cabdff1aSopenharmony_ci    p = psets + strlen(pset_string);
191cabdff1aSopenharmony_ci    r = ff_avc_find_startcode(extradata, extradata + extradata_size);
192cabdff1aSopenharmony_ci    while (r < extradata + extradata_size) {
193cabdff1aSopenharmony_ci        const uint8_t *r1;
194cabdff1aSopenharmony_ci        uint8_t nal_type;
195cabdff1aSopenharmony_ci
196cabdff1aSopenharmony_ci        while (!*(r++));
197cabdff1aSopenharmony_ci        nal_type = *r & 0x1f;
198cabdff1aSopenharmony_ci        r1 = ff_avc_find_startcode(r, extradata + extradata_size);
199cabdff1aSopenharmony_ci        if (nal_type != 7 && nal_type != 8) { /* Only output SPS and PPS */
200cabdff1aSopenharmony_ci            r = r1;
201cabdff1aSopenharmony_ci            continue;
202cabdff1aSopenharmony_ci        }
203cabdff1aSopenharmony_ci        if (p != (psets + strlen(pset_string))) {
204cabdff1aSopenharmony_ci            *p = ',';
205cabdff1aSopenharmony_ci            p++;
206cabdff1aSopenharmony_ci        }
207cabdff1aSopenharmony_ci        if (!sps) {
208cabdff1aSopenharmony_ci            sps = r;
209cabdff1aSopenharmony_ci            sps_end = r1;
210cabdff1aSopenharmony_ci        }
211cabdff1aSopenharmony_ci        if (!av_base64_encode(p, MAX_PSET_SIZE - (p - psets), r, r1 - r)) {
212cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "Cannot Base64-encode %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"!\n",
213cabdff1aSopenharmony_ci                   MAX_PSET_SIZE - (p - psets), r1 - r);
214cabdff1aSopenharmony_ci            av_free(psets);
215cabdff1aSopenharmony_ci            av_free(tmpbuf);
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
218cabdff1aSopenharmony_ci        }
219cabdff1aSopenharmony_ci        p += strlen(p);
220cabdff1aSopenharmony_ci        r = r1;
221cabdff1aSopenharmony_ci    }
222cabdff1aSopenharmony_ci    if (sps && sps_end - sps >= 4 && p - psets <= MAX_PSET_SIZE - strlen(profile_string) - 7) {
223cabdff1aSopenharmony_ci        memcpy(p, profile_string, strlen(profile_string));
224cabdff1aSopenharmony_ci        p += strlen(p);
225cabdff1aSopenharmony_ci        ff_data_to_hex(p, sps + 1, 3, 0);
226cabdff1aSopenharmony_ci    }
227cabdff1aSopenharmony_ci    av_free(tmpbuf);
228cabdff1aSopenharmony_ci
229cabdff1aSopenharmony_ci    *out = psets;
230cabdff1aSopenharmony_ci    return 0;
231cabdff1aSopenharmony_ci}
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_cistatic int extradata2psets_hevc(const AVCodecParameters *par, char **out)
234cabdff1aSopenharmony_ci{
235cabdff1aSopenharmony_ci    char *psets;
236cabdff1aSopenharmony_ci    uint8_t *extradata = par->extradata;
237cabdff1aSopenharmony_ci    int extradata_size = par->extradata_size;
238cabdff1aSopenharmony_ci    uint8_t *tmpbuf = NULL;
239cabdff1aSopenharmony_ci    int ps_pos[3] = { 0 };
240cabdff1aSopenharmony_ci    static const char * const ps_names[3] = { "vps", "sps", "pps" };
241cabdff1aSopenharmony_ci    int num_arrays, num_nalus;
242cabdff1aSopenharmony_ci    int pos, i, j, ret = 0;
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci    *out = NULL;
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_ci    // Convert to hvcc format. Since we need to group multiple NALUs of
247cabdff1aSopenharmony_ci    // the same type, and we might need to convert from one format to the
248cabdff1aSopenharmony_ci    // other anyway, we get away with a little less work by using the hvcc
249cabdff1aSopenharmony_ci    // format.
250cabdff1aSopenharmony_ci    if (par->extradata[0] != 1) {
251cabdff1aSopenharmony_ci        AVIOContext *pb;
252cabdff1aSopenharmony_ci
253cabdff1aSopenharmony_ci        ret = avio_open_dyn_buf(&pb);
254cabdff1aSopenharmony_ci        if (ret < 0)
255cabdff1aSopenharmony_ci            return ret;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci        ret = ff_isom_write_hvcc(pb, par->extradata, par->extradata_size, 0);
258cabdff1aSopenharmony_ci        if (ret < 0) {
259cabdff1aSopenharmony_ci            avio_close_dyn_buf(pb, &tmpbuf);
260cabdff1aSopenharmony_ci            goto err;
261cabdff1aSopenharmony_ci        }
262cabdff1aSopenharmony_ci        extradata_size = avio_close_dyn_buf(pb, &extradata);
263cabdff1aSopenharmony_ci        tmpbuf = extradata;
264cabdff1aSopenharmony_ci    }
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci    if (extradata_size < 23)
267cabdff1aSopenharmony_ci        goto err;
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci    num_arrays = extradata[22];
270cabdff1aSopenharmony_ci    pos = 23;
271cabdff1aSopenharmony_ci    for (i = 0; i < num_arrays; i++) {
272cabdff1aSopenharmony_ci        int num_nalus, nalu_type;
273cabdff1aSopenharmony_ci        if (pos + 3 > extradata_size)
274cabdff1aSopenharmony_ci            goto err;
275cabdff1aSopenharmony_ci        nalu_type = extradata[pos] & 0x3f;
276cabdff1aSopenharmony_ci        // Not including libavcodec/hevc.h to avoid confusion between
277cabdff1aSopenharmony_ci        // NAL_* with the same name for both H.264 and HEVC.
278cabdff1aSopenharmony_ci        if (nalu_type == 32) // VPS
279cabdff1aSopenharmony_ci            ps_pos[0] = pos;
280cabdff1aSopenharmony_ci        else if (nalu_type == 33) // SPS
281cabdff1aSopenharmony_ci            ps_pos[1] = pos;
282cabdff1aSopenharmony_ci        else if (nalu_type == 34) // PPS
283cabdff1aSopenharmony_ci            ps_pos[2] = pos;
284cabdff1aSopenharmony_ci        num_nalus = AV_RB16(&extradata[pos + 1]);
285cabdff1aSopenharmony_ci        pos += 3;
286cabdff1aSopenharmony_ci        for (j = 0; j < num_nalus; j++) {
287cabdff1aSopenharmony_ci            int len;
288cabdff1aSopenharmony_ci            if (pos + 2 > extradata_size)
289cabdff1aSopenharmony_ci                goto err;
290cabdff1aSopenharmony_ci            len = AV_RB16(&extradata[pos]);
291cabdff1aSopenharmony_ci            pos += 2;
292cabdff1aSopenharmony_ci            if (pos + len > extradata_size)
293cabdff1aSopenharmony_ci                goto err;
294cabdff1aSopenharmony_ci            pos += len;
295cabdff1aSopenharmony_ci        }
296cabdff1aSopenharmony_ci    }
297cabdff1aSopenharmony_ci    if (!ps_pos[0] || !ps_pos[1] || !ps_pos[2])
298cabdff1aSopenharmony_ci        goto err;
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci    psets = av_mallocz(MAX_PSET_SIZE);
301cabdff1aSopenharmony_ci    if (!psets) {
302cabdff1aSopenharmony_ci        ret = AVERROR(ENOMEM);
303cabdff1aSopenharmony_ci        goto err;
304cabdff1aSopenharmony_ci    }
305cabdff1aSopenharmony_ci
306cabdff1aSopenharmony_ci    psets[0] = '\0';
307cabdff1aSopenharmony_ci
308cabdff1aSopenharmony_ci    for (i = 0; i < 3; i++) {
309cabdff1aSopenharmony_ci        pos = ps_pos[i];
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_ci        if (i > 0)
312cabdff1aSopenharmony_ci            av_strlcat(psets, "; ", MAX_PSET_SIZE);
313cabdff1aSopenharmony_ci        av_strlcatf(psets, MAX_PSET_SIZE, "sprop-%s=", ps_names[i]);
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci        // Skipping boundary checks in the input here; we've already traversed
316cabdff1aSopenharmony_ci        // the whole hvcc structure above without issues
317cabdff1aSopenharmony_ci        num_nalus = AV_RB16(&extradata[pos + 1]);
318cabdff1aSopenharmony_ci        pos += 3;
319cabdff1aSopenharmony_ci        for (j = 0; j < num_nalus; j++) {
320cabdff1aSopenharmony_ci            int len = AV_RB16(&extradata[pos]);
321cabdff1aSopenharmony_ci            int strpos;
322cabdff1aSopenharmony_ci            pos += 2;
323cabdff1aSopenharmony_ci            if (j > 0)
324cabdff1aSopenharmony_ci                av_strlcat(psets, ",", MAX_PSET_SIZE);
325cabdff1aSopenharmony_ci            strpos = strlen(psets);
326cabdff1aSopenharmony_ci            if (!av_base64_encode(psets + strpos, MAX_PSET_SIZE - strpos,
327cabdff1aSopenharmony_ci                                  &extradata[pos], len)) {
328cabdff1aSopenharmony_ci                av_free(psets);
329cabdff1aSopenharmony_ci                goto err;
330cabdff1aSopenharmony_ci            }
331cabdff1aSopenharmony_ci            pos += len;
332cabdff1aSopenharmony_ci        }
333cabdff1aSopenharmony_ci    }
334cabdff1aSopenharmony_ci    av_free(tmpbuf);
335cabdff1aSopenharmony_ci
336cabdff1aSopenharmony_ci    *out = psets;
337cabdff1aSopenharmony_ci    return 0;
338cabdff1aSopenharmony_cierr:
339cabdff1aSopenharmony_ci    if (ret >= 0)
340cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
341cabdff1aSopenharmony_ci    av_free(tmpbuf);
342cabdff1aSopenharmony_ci    return ret;
343cabdff1aSopenharmony_ci}
344cabdff1aSopenharmony_ci
345cabdff1aSopenharmony_cistatic int extradata2config(AVFormatContext *s, const AVCodecParameters *par,
346cabdff1aSopenharmony_ci                            char **out)
347cabdff1aSopenharmony_ci{
348cabdff1aSopenharmony_ci    char *config;
349cabdff1aSopenharmony_ci
350cabdff1aSopenharmony_ci    *out = NULL;
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci    if (par->extradata_size > MAX_EXTRADATA_SIZE) {
353cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Too much extradata!\n");
354cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
355cabdff1aSopenharmony_ci    }
356cabdff1aSopenharmony_ci    config = av_malloc(10 + par->extradata_size * 2);
357cabdff1aSopenharmony_ci    if (!config) {
358cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n");
359cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
360cabdff1aSopenharmony_ci    }
361cabdff1aSopenharmony_ci    memcpy(config, "; config=", 9);
362cabdff1aSopenharmony_ci    ff_data_to_hex(config + 9, par->extradata, par->extradata_size, 0);
363cabdff1aSopenharmony_ci
364cabdff1aSopenharmony_ci    *out = config;
365cabdff1aSopenharmony_ci    return 0;
366cabdff1aSopenharmony_ci}
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_cistatic int xiph_extradata2config(AVFormatContext *s, const AVCodecParameters *par,
369cabdff1aSopenharmony_ci                                 char **out)
370cabdff1aSopenharmony_ci{
371cabdff1aSopenharmony_ci    uint8_t *config;
372cabdff1aSopenharmony_ci    char *encoded_config;
373cabdff1aSopenharmony_ci    const uint8_t *header_start[3];
374cabdff1aSopenharmony_ci    int headers_len, header_len[3], config_len;
375cabdff1aSopenharmony_ci    int first_header_size, ret;
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci    *out = NULL;
378cabdff1aSopenharmony_ci
379cabdff1aSopenharmony_ci    switch (par->codec_id) {
380cabdff1aSopenharmony_ci    case AV_CODEC_ID_THEORA:
381cabdff1aSopenharmony_ci        first_header_size = 42;
382cabdff1aSopenharmony_ci        break;
383cabdff1aSopenharmony_ci    case AV_CODEC_ID_VORBIS:
384cabdff1aSopenharmony_ci        first_header_size = 30;
385cabdff1aSopenharmony_ci        break;
386cabdff1aSopenharmony_ci    default:
387cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Unsupported Xiph codec ID\n");
388cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
389cabdff1aSopenharmony_ci    }
390cabdff1aSopenharmony_ci
391cabdff1aSopenharmony_ci    ret = avpriv_split_xiph_headers(par->extradata, par->extradata_size,
392cabdff1aSopenharmony_ci                                    first_header_size, header_start,
393cabdff1aSopenharmony_ci                                    header_len);
394cabdff1aSopenharmony_ci    if (ret < 0) {
395cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Extradata corrupt.\n");
396cabdff1aSopenharmony_ci        return ret;
397cabdff1aSopenharmony_ci    }
398cabdff1aSopenharmony_ci
399cabdff1aSopenharmony_ci    headers_len = header_len[0] + header_len[2];
400cabdff1aSopenharmony_ci    config_len = 4 +          // count
401cabdff1aSopenharmony_ci                 3 +          // ident
402cabdff1aSopenharmony_ci                 2 +          // packet size
403cabdff1aSopenharmony_ci                 1 +          // header count
404cabdff1aSopenharmony_ci                 2 +          // header size
405cabdff1aSopenharmony_ci                 headers_len; // and the rest
406cabdff1aSopenharmony_ci
407cabdff1aSopenharmony_ci    config = av_malloc(config_len);
408cabdff1aSopenharmony_ci    if (!config)
409cabdff1aSopenharmony_ci        goto xiph_fail;
410cabdff1aSopenharmony_ci
411cabdff1aSopenharmony_ci    encoded_config = av_malloc(AV_BASE64_SIZE(config_len));
412cabdff1aSopenharmony_ci    if (!encoded_config) {
413cabdff1aSopenharmony_ci        av_free(config);
414cabdff1aSopenharmony_ci        goto xiph_fail;
415cabdff1aSopenharmony_ci    }
416cabdff1aSopenharmony_ci
417cabdff1aSopenharmony_ci    config[0] = config[1] = config[2] = 0;
418cabdff1aSopenharmony_ci    config[3] = 1;
419cabdff1aSopenharmony_ci    config[4] = (RTP_XIPH_IDENT >> 16) & 0xff;
420cabdff1aSopenharmony_ci    config[5] = (RTP_XIPH_IDENT >>  8) & 0xff;
421cabdff1aSopenharmony_ci    config[6] = (RTP_XIPH_IDENT      ) & 0xff;
422cabdff1aSopenharmony_ci    config[7] = (headers_len >> 8) & 0xff;
423cabdff1aSopenharmony_ci    config[8] = headers_len & 0xff;
424cabdff1aSopenharmony_ci    config[9] = 2;
425cabdff1aSopenharmony_ci    config[10] = header_len[0];
426cabdff1aSopenharmony_ci    config[11] = 0; // size of comment header; nonexistent
427cabdff1aSopenharmony_ci    memcpy(config + 12, header_start[0], header_len[0]);
428cabdff1aSopenharmony_ci    memcpy(config + 12 + header_len[0], header_start[2], header_len[2]);
429cabdff1aSopenharmony_ci
430cabdff1aSopenharmony_ci    av_base64_encode(encoded_config, AV_BASE64_SIZE(config_len),
431cabdff1aSopenharmony_ci                     config, config_len);
432cabdff1aSopenharmony_ci    av_free(config);
433cabdff1aSopenharmony_ci
434cabdff1aSopenharmony_ci    *out = encoded_config;
435cabdff1aSopenharmony_ci    return 0;
436cabdff1aSopenharmony_ci
437cabdff1aSopenharmony_cixiph_fail:
438cabdff1aSopenharmony_ci    av_log(s, AV_LOG_ERROR,
439cabdff1aSopenharmony_ci           "Not enough memory for configuration string\n");
440cabdff1aSopenharmony_ci    return AVERROR(ENOMEM);
441cabdff1aSopenharmony_ci}
442cabdff1aSopenharmony_ci
443cabdff1aSopenharmony_cistatic int latm_context2profilelevel(const AVCodecParameters *par)
444cabdff1aSopenharmony_ci{
445cabdff1aSopenharmony_ci    /* MP4A-LATM
446cabdff1aSopenharmony_ci     * The RTP payload format specification is described in RFC 3016
447cabdff1aSopenharmony_ci     * The encoding specifications are provided in ISO/IEC 14496-3 */
448cabdff1aSopenharmony_ci
449cabdff1aSopenharmony_ci    int profile_level = 0x2B;
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ci    /* TODO: AAC Profile only supports AAC LC Object Type.
452cabdff1aSopenharmony_ci     * Different Object Types should implement different Profile Levels */
453cabdff1aSopenharmony_ci
454cabdff1aSopenharmony_ci    if (par->sample_rate <= 24000) {
455cabdff1aSopenharmony_ci        if (par->ch_layout.nb_channels <= 2)
456cabdff1aSopenharmony_ci            profile_level = 0x28; // AAC Profile, Level 1
457cabdff1aSopenharmony_ci    } else if (par->sample_rate <= 48000) {
458cabdff1aSopenharmony_ci        if (par->ch_layout.nb_channels <= 2) {
459cabdff1aSopenharmony_ci            profile_level = 0x29; // AAC Profile, Level 2
460cabdff1aSopenharmony_ci        } else if (par->ch_layout.nb_channels <= 5) {
461cabdff1aSopenharmony_ci            profile_level = 0x2A; // AAC Profile, Level 4
462cabdff1aSopenharmony_ci        }
463cabdff1aSopenharmony_ci    } else if (par->sample_rate <= 96000) {
464cabdff1aSopenharmony_ci        if (par->ch_layout.nb_channels <= 5) {
465cabdff1aSopenharmony_ci            profile_level = 0x2B; // AAC Profile, Level 5
466cabdff1aSopenharmony_ci        }
467cabdff1aSopenharmony_ci    }
468cabdff1aSopenharmony_ci
469cabdff1aSopenharmony_ci    return profile_level;
470cabdff1aSopenharmony_ci}
471cabdff1aSopenharmony_ci
472cabdff1aSopenharmony_cistatic int latm_context2config(AVFormatContext *s, const AVCodecParameters *par,
473cabdff1aSopenharmony_ci                               char **out)
474cabdff1aSopenharmony_ci{
475cabdff1aSopenharmony_ci    /* MP4A-LATM
476cabdff1aSopenharmony_ci     * The RTP payload format specification is described in RFC 3016
477cabdff1aSopenharmony_ci     * The encoding specifications are provided in ISO/IEC 14496-3 */
478cabdff1aSopenharmony_ci
479cabdff1aSopenharmony_ci    uint8_t config_byte[6];
480cabdff1aSopenharmony_ci    int rate_index;
481cabdff1aSopenharmony_ci    char *config;
482cabdff1aSopenharmony_ci
483cabdff1aSopenharmony_ci    *out = NULL;
484cabdff1aSopenharmony_ci
485cabdff1aSopenharmony_ci    for (rate_index = 0; rate_index < 16; rate_index++)
486cabdff1aSopenharmony_ci        if (ff_mpeg4audio_sample_rates[rate_index] == par->sample_rate)
487cabdff1aSopenharmony_ci            break;
488cabdff1aSopenharmony_ci    if (rate_index == 16) {
489cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n");
490cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
491cabdff1aSopenharmony_ci    }
492cabdff1aSopenharmony_ci
493cabdff1aSopenharmony_ci    config_byte[0] = 0x40;
494cabdff1aSopenharmony_ci    config_byte[1] = 0;
495cabdff1aSopenharmony_ci    config_byte[2] = 0x20 | rate_index;
496cabdff1aSopenharmony_ci    config_byte[3] = par->ch_layout.nb_channels << 4;
497cabdff1aSopenharmony_ci    config_byte[4] = 0x3f;
498cabdff1aSopenharmony_ci    config_byte[5] = 0xc0;
499cabdff1aSopenharmony_ci
500cabdff1aSopenharmony_ci    config = av_malloc(6*2+1);
501cabdff1aSopenharmony_ci    if (!config) {
502cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n");
503cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
504cabdff1aSopenharmony_ci    }
505cabdff1aSopenharmony_ci    ff_data_to_hex(config, config_byte, 6, 1);
506cabdff1aSopenharmony_ci
507cabdff1aSopenharmony_ci    *out = config;
508cabdff1aSopenharmony_ci    return 0;
509cabdff1aSopenharmony_ci}
510cabdff1aSopenharmony_ci
511cabdff1aSopenharmony_cistatic int sdp_write_media_attributes(char *buff, int size, const AVStream *st,
512cabdff1aSopenharmony_ci                                      int payload_type, AVFormatContext *fmt)
513cabdff1aSopenharmony_ci{
514cabdff1aSopenharmony_ci    char *config = NULL;
515cabdff1aSopenharmony_ci    const AVCodecParameters *p = st->codecpar;
516cabdff1aSopenharmony_ci    int ret = 0;
517cabdff1aSopenharmony_ci
518cabdff1aSopenharmony_ci    switch (p->codec_id) {
519cabdff1aSopenharmony_ci    case AV_CODEC_ID_DIRAC:
520cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d VC2/90000\r\n", payload_type);
521cabdff1aSopenharmony_ci        break;
522cabdff1aSopenharmony_ci    case AV_CODEC_ID_H264: {
523cabdff1aSopenharmony_ci        int mode = 1;
524cabdff1aSopenharmony_ci        if (fmt && fmt->oformat && fmt->oformat->priv_class &&
525cabdff1aSopenharmony_ci            av_opt_flag_is_set(fmt->priv_data, "rtpflags", "h264_mode0"))
526cabdff1aSopenharmony_ci            mode = 0;
527cabdff1aSopenharmony_ci        if (p->extradata_size) {
528cabdff1aSopenharmony_ci            ret = extradata2psets(fmt, p, &config);
529cabdff1aSopenharmony_ci            if (ret < 0)
530cabdff1aSopenharmony_ci                return ret;
531cabdff1aSopenharmony_ci        }
532cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d H264/90000\r\n"
533cabdff1aSopenharmony_ci                                "a=fmtp:%d packetization-mode=%d%s\r\n",
534cabdff1aSopenharmony_ci                                 payload_type,
535cabdff1aSopenharmony_ci                                 payload_type, mode, config ? config : "");
536cabdff1aSopenharmony_ci        break;
537cabdff1aSopenharmony_ci    }
538cabdff1aSopenharmony_ci    case AV_CODEC_ID_H261:
539cabdff1aSopenharmony_ci    {
540cabdff1aSopenharmony_ci        const char *pic_fmt = NULL;
541cabdff1aSopenharmony_ci        /* only QCIF and CIF are specified as supported in RFC 4587 */
542cabdff1aSopenharmony_ci        if (p->width == 176 && p->height == 144)
543cabdff1aSopenharmony_ci            pic_fmt = "QCIF=1";
544cabdff1aSopenharmony_ci        else if (p->width == 352 && p->height == 288)
545cabdff1aSopenharmony_ci            pic_fmt = "CIF=1";
546cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
547cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d H261/90000\r\n", payload_type);
548cabdff1aSopenharmony_ci        if (pic_fmt)
549cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=fmtp:%d %s\r\n", payload_type, pic_fmt);
550cabdff1aSopenharmony_ci        break;
551cabdff1aSopenharmony_ci    }
552cabdff1aSopenharmony_ci    case AV_CODEC_ID_H263:
553cabdff1aSopenharmony_ci    case AV_CODEC_ID_H263P:
554cabdff1aSopenharmony_ci        /* a=framesize is required by 3GPP TS 26.234 (PSS). It
555cabdff1aSopenharmony_ci         * actually specifies the maximum video size, but we only know
556cabdff1aSopenharmony_ci         * the current size. This is required for playback on Android
557cabdff1aSopenharmony_ci         * stagefright and on Samsung bada. */
558cabdff1aSopenharmony_ci        if (!fmt || !fmt->oformat->priv_class ||
559cabdff1aSopenharmony_ci            !av_opt_flag_is_set(fmt->priv_data, "rtpflags", "rfc2190") ||
560cabdff1aSopenharmony_ci            p->codec_id == AV_CODEC_ID_H263P)
561cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d H263-2000/90000\r\n"
562cabdff1aSopenharmony_ci                                "a=framesize:%d %d-%d\r\n",
563cabdff1aSopenharmony_ci                                payload_type,
564cabdff1aSopenharmony_ci                                payload_type, p->width, p->height);
565cabdff1aSopenharmony_ci        break;
566cabdff1aSopenharmony_ci    case AV_CODEC_ID_HEVC:
567cabdff1aSopenharmony_ci        if (p->extradata_size) {
568cabdff1aSopenharmony_ci            ret = extradata2psets_hevc(p, &config);
569cabdff1aSopenharmony_ci            if (ret < 0)
570cabdff1aSopenharmony_ci                return ret;
571cabdff1aSopenharmony_ci        }
572cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d H265/90000\r\n", payload_type);
573cabdff1aSopenharmony_ci        if (config)
574cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=fmtp:%d %s\r\n",
575cabdff1aSopenharmony_ci                                     payload_type, config);
576cabdff1aSopenharmony_ci        break;
577cabdff1aSopenharmony_ci    case AV_CODEC_ID_MPEG4:
578cabdff1aSopenharmony_ci        if (p->extradata_size) {
579cabdff1aSopenharmony_ci            ret = extradata2config(fmt, p, &config);
580cabdff1aSopenharmony_ci            if (ret < 0)
581cabdff1aSopenharmony_ci                return ret;
582cabdff1aSopenharmony_ci        }
583cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d MP4V-ES/90000\r\n"
584cabdff1aSopenharmony_ci                                "a=fmtp:%d profile-level-id=1%s\r\n",
585cabdff1aSopenharmony_ci                                 payload_type,
586cabdff1aSopenharmony_ci                                 payload_type, config ? config : "");
587cabdff1aSopenharmony_ci        break;
588cabdff1aSopenharmony_ci    case AV_CODEC_ID_AAC:
589cabdff1aSopenharmony_ci        if (fmt && fmt->oformat && fmt->oformat->priv_class &&
590cabdff1aSopenharmony_ci            av_opt_flag_is_set(fmt->priv_data, "rtpflags", "latm")) {
591cabdff1aSopenharmony_ci            ret = latm_context2config(fmt, p, &config);
592cabdff1aSopenharmony_ci            if (ret < 0)
593cabdff1aSopenharmony_ci                return ret;
594cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d MP4A-LATM/%d/%d\r\n"
595cabdff1aSopenharmony_ci                                    "a=fmtp:%d profile-level-id=%d;cpresent=0;config=%s\r\n",
596cabdff1aSopenharmony_ci                                     payload_type, p->sample_rate, p->ch_layout.nb_channels,
597cabdff1aSopenharmony_ci                                     payload_type, latm_context2profilelevel(p), config);
598cabdff1aSopenharmony_ci        } else {
599cabdff1aSopenharmony_ci            if (p->extradata_size) {
600cabdff1aSopenharmony_ci                ret = extradata2config(fmt, p, &config);
601cabdff1aSopenharmony_ci                if (ret < 0)
602cabdff1aSopenharmony_ci                    return ret;
603cabdff1aSopenharmony_ci            } else {
604cabdff1aSopenharmony_ci                /* FIXME: maybe we can forge config information based on the
605cabdff1aSopenharmony_ci                 *        codec parameters...
606cabdff1aSopenharmony_ci                 */
607cabdff1aSopenharmony_ci                av_log(fmt, AV_LOG_ERROR, "AAC with no global headers is currently not supported.\n");
608cabdff1aSopenharmony_ci                return AVERROR(ENOSYS);
609cabdff1aSopenharmony_ci            }
610cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n"
611cabdff1aSopenharmony_ci                                    "a=fmtp:%d profile-level-id=1;"
612cabdff1aSopenharmony_ci                                    "mode=AAC-hbr;sizelength=13;indexlength=3;"
613cabdff1aSopenharmony_ci                                    "indexdeltalength=3%s\r\n",
614cabdff1aSopenharmony_ci                                     payload_type, p->sample_rate, p->ch_layout.nb_channels,
615cabdff1aSopenharmony_ci                                     payload_type, config);
616cabdff1aSopenharmony_ci        }
617cabdff1aSopenharmony_ci        break;
618cabdff1aSopenharmony_ci    case AV_CODEC_ID_PCM_S16BE:
619cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
620cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d L16/%d/%d\r\n",
621cabdff1aSopenharmony_ci                                     payload_type,
622cabdff1aSopenharmony_ci                                     p->sample_rate, p->ch_layout.nb_channels);
623cabdff1aSopenharmony_ci        break;
624cabdff1aSopenharmony_ci    case AV_CODEC_ID_PCM_S24BE:
625cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
626cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d L24/%d/%d\r\n",
627cabdff1aSopenharmony_ci                                     payload_type,
628cabdff1aSopenharmony_ci                                     p->sample_rate, p->ch_layout.nb_channels);
629cabdff1aSopenharmony_ci        break;
630cabdff1aSopenharmony_ci    case AV_CODEC_ID_PCM_MULAW:
631cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
632cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d PCMU/%d/%d\r\n",
633cabdff1aSopenharmony_ci                                     payload_type,
634cabdff1aSopenharmony_ci                                     p->sample_rate, p->ch_layout.nb_channels);
635cabdff1aSopenharmony_ci        break;
636cabdff1aSopenharmony_ci    case AV_CODEC_ID_PCM_ALAW:
637cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
638cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d PCMA/%d/%d\r\n",
639cabdff1aSopenharmony_ci                                     payload_type,
640cabdff1aSopenharmony_ci                                     p->sample_rate, p->ch_layout.nb_channels);
641cabdff1aSopenharmony_ci        break;
642cabdff1aSopenharmony_ci    case AV_CODEC_ID_AMR_NB:
643cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d AMR/%d/%d\r\n"
644cabdff1aSopenharmony_ci                                "a=fmtp:%d octet-align=1\r\n",
645cabdff1aSopenharmony_ci                                 payload_type, p->sample_rate, p->ch_layout.nb_channels,
646cabdff1aSopenharmony_ci                                 payload_type);
647cabdff1aSopenharmony_ci        break;
648cabdff1aSopenharmony_ci    case AV_CODEC_ID_AMR_WB:
649cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d AMR-WB/%d/%d\r\n"
650cabdff1aSopenharmony_ci                                "a=fmtp:%d octet-align=1\r\n",
651cabdff1aSopenharmony_ci                                 payload_type, p->sample_rate, p->ch_layout.nb_channels,
652cabdff1aSopenharmony_ci                                 payload_type);
653cabdff1aSopenharmony_ci        break;
654cabdff1aSopenharmony_ci    case AV_CODEC_ID_VORBIS:
655cabdff1aSopenharmony_ci        if (p->extradata_size)
656cabdff1aSopenharmony_ci            ret = xiph_extradata2config(fmt, p, &config);
657cabdff1aSopenharmony_ci        else {
658cabdff1aSopenharmony_ci            av_log(fmt, AV_LOG_ERROR, "Vorbis configuration info missing\n");
659cabdff1aSopenharmony_ci            ret = AVERROR_INVALIDDATA;
660cabdff1aSopenharmony_ci        }
661cabdff1aSopenharmony_ci        if (ret < 0)
662cabdff1aSopenharmony_ci            return ret;
663cabdff1aSopenharmony_ci
664cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d vorbis/%d/%d\r\n"
665cabdff1aSopenharmony_ci                                "a=fmtp:%d configuration=%s\r\n",
666cabdff1aSopenharmony_ci                                payload_type, p->sample_rate, p->ch_layout.nb_channels,
667cabdff1aSopenharmony_ci                                payload_type, config);
668cabdff1aSopenharmony_ci        break;
669cabdff1aSopenharmony_ci    case AV_CODEC_ID_THEORA: {
670cabdff1aSopenharmony_ci        const char *pix_fmt;
671cabdff1aSopenharmony_ci        switch (p->format) {
672cabdff1aSopenharmony_ci        case AV_PIX_FMT_YUV420P:
673cabdff1aSopenharmony_ci            pix_fmt = "YCbCr-4:2:0";
674cabdff1aSopenharmony_ci            break;
675cabdff1aSopenharmony_ci        case AV_PIX_FMT_YUV422P:
676cabdff1aSopenharmony_ci            pix_fmt = "YCbCr-4:2:2";
677cabdff1aSopenharmony_ci            break;
678cabdff1aSopenharmony_ci        case AV_PIX_FMT_YUV444P:
679cabdff1aSopenharmony_ci            pix_fmt = "YCbCr-4:4:4";
680cabdff1aSopenharmony_ci            break;
681cabdff1aSopenharmony_ci        default:
682cabdff1aSopenharmony_ci            av_log(fmt, AV_LOG_ERROR, "Unsupported pixel format.\n");
683cabdff1aSopenharmony_ci            return AVERROR(ENOSYS);
684cabdff1aSopenharmony_ci        }
685cabdff1aSopenharmony_ci
686cabdff1aSopenharmony_ci        if (p->extradata_size)
687cabdff1aSopenharmony_ci            ret = xiph_extradata2config(fmt, p, &config);
688cabdff1aSopenharmony_ci        else {
689cabdff1aSopenharmony_ci            av_log(fmt, AV_LOG_ERROR, "Theora configuration info missing\n");
690cabdff1aSopenharmony_ci            ret = AVERROR_INVALIDDATA;
691cabdff1aSopenharmony_ci        }
692cabdff1aSopenharmony_ci        if (ret < 0)
693cabdff1aSopenharmony_ci            return ret;
694cabdff1aSopenharmony_ci
695cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n"
696cabdff1aSopenharmony_ci                                "a=fmtp:%d delivery-method=inline; "
697cabdff1aSopenharmony_ci                                "width=%d; height=%d; sampling=%s; "
698cabdff1aSopenharmony_ci                                "configuration=%s\r\n",
699cabdff1aSopenharmony_ci                                payload_type, payload_type,
700cabdff1aSopenharmony_ci                                p->width, p->height, pix_fmt, config);
701cabdff1aSopenharmony_ci        break;
702cabdff1aSopenharmony_ci    }
703cabdff1aSopenharmony_ci    case AV_CODEC_ID_BITPACKED:
704cabdff1aSopenharmony_ci    case AV_CODEC_ID_RAWVIDEO: {
705cabdff1aSopenharmony_ci        const char *pix_fmt;
706cabdff1aSopenharmony_ci        int bit_depth = 8;
707cabdff1aSopenharmony_ci
708cabdff1aSopenharmony_ci        switch (p->format) {
709cabdff1aSopenharmony_ci        case AV_PIX_FMT_UYVY422:
710cabdff1aSopenharmony_ci            pix_fmt = "YCbCr-4:2:2";
711cabdff1aSopenharmony_ci            break;
712cabdff1aSopenharmony_ci        case AV_PIX_FMT_YUV422P10:
713cabdff1aSopenharmony_ci            pix_fmt = "YCbCr-4:2:2";
714cabdff1aSopenharmony_ci            bit_depth = 10;
715cabdff1aSopenharmony_ci            break;
716cabdff1aSopenharmony_ci        case AV_PIX_FMT_YUV420P:
717cabdff1aSopenharmony_ci            pix_fmt = "YCbCr-4:2:0";
718cabdff1aSopenharmony_ci            break;
719cabdff1aSopenharmony_ci        case AV_PIX_FMT_RGB24:
720cabdff1aSopenharmony_ci            pix_fmt = "RGB";
721cabdff1aSopenharmony_ci            break;
722cabdff1aSopenharmony_ci        case AV_PIX_FMT_BGR24:
723cabdff1aSopenharmony_ci            pix_fmt = "BGR";
724cabdff1aSopenharmony_ci            break;
725cabdff1aSopenharmony_ci        default:
726cabdff1aSopenharmony_ci            av_log(fmt, AV_LOG_ERROR, "Unsupported pixel format.\n");
727cabdff1aSopenharmony_ci            return AVERROR(ENOSYS);
728cabdff1aSopenharmony_ci        }
729cabdff1aSopenharmony_ci
730cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d raw/90000\r\n"
731cabdff1aSopenharmony_ci                                "a=fmtp:%d sampling=%s; "
732cabdff1aSopenharmony_ci                                "width=%d; height=%d; "
733cabdff1aSopenharmony_ci                                "depth=%d",
734cabdff1aSopenharmony_ci                                payload_type, payload_type,
735cabdff1aSopenharmony_ci                                pix_fmt, p->width, p->height, bit_depth);
736cabdff1aSopenharmony_ci        if (p->field_order != AV_FIELD_PROGRESSIVE)
737cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "; interlace");
738cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "\r\n");
739cabdff1aSopenharmony_ci        break;
740cabdff1aSopenharmony_ci    }
741cabdff1aSopenharmony_ci
742cabdff1aSopenharmony_ci    case AV_CODEC_ID_VP8:
743cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d VP8/90000\r\n",
744cabdff1aSopenharmony_ci                                 payload_type);
745cabdff1aSopenharmony_ci        break;
746cabdff1aSopenharmony_ci    case AV_CODEC_ID_VP9:
747cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d VP9/90000\r\n",
748cabdff1aSopenharmony_ci                                 payload_type);
749cabdff1aSopenharmony_ci        break;
750cabdff1aSopenharmony_ci    case AV_CODEC_ID_MJPEG:
751cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
752cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d JPEG/90000\r\n",
753cabdff1aSopenharmony_ci                                     payload_type);
754cabdff1aSopenharmony_ci        break;
755cabdff1aSopenharmony_ci    case AV_CODEC_ID_ADPCM_G722:
756cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
757cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d G722/%d/%d\r\n",
758cabdff1aSopenharmony_ci                                     payload_type,
759cabdff1aSopenharmony_ci                                     8000, p->ch_layout.nb_channels);
760cabdff1aSopenharmony_ci        break;
761cabdff1aSopenharmony_ci    case AV_CODEC_ID_ADPCM_G726: {
762cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
763cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d AAL2-G726-%d/%d\r\n",
764cabdff1aSopenharmony_ci                                     payload_type,
765cabdff1aSopenharmony_ci                                     p->bits_per_coded_sample*8,
766cabdff1aSopenharmony_ci                                     p->sample_rate);
767cabdff1aSopenharmony_ci        break;
768cabdff1aSopenharmony_ci    }
769cabdff1aSopenharmony_ci    case AV_CODEC_ID_ADPCM_G726LE: {
770cabdff1aSopenharmony_ci        if (payload_type >= RTP_PT_PRIVATE)
771cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=rtpmap:%d G726-%d/%d\r\n",
772cabdff1aSopenharmony_ci                                     payload_type,
773cabdff1aSopenharmony_ci                                     p->bits_per_coded_sample*8,
774cabdff1aSopenharmony_ci                                     p->sample_rate);
775cabdff1aSopenharmony_ci        break;
776cabdff1aSopenharmony_ci    }
777cabdff1aSopenharmony_ci    case AV_CODEC_ID_ILBC:
778cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d iLBC/%d\r\n"
779cabdff1aSopenharmony_ci                                "a=fmtp:%d mode=%d\r\n",
780cabdff1aSopenharmony_ci                                 payload_type, p->sample_rate,
781cabdff1aSopenharmony_ci                                 payload_type, p->block_align == 38 ? 20 : 30);
782cabdff1aSopenharmony_ci        break;
783cabdff1aSopenharmony_ci    case AV_CODEC_ID_SPEEX:
784cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d speex/%d\r\n",
785cabdff1aSopenharmony_ci                                 payload_type, p->sample_rate);
786cabdff1aSopenharmony_ci        break;
787cabdff1aSopenharmony_ci    case AV_CODEC_ID_OPUS:
788cabdff1aSopenharmony_ci        /* The opus RTP draft says that all opus streams MUST be declared
789cabdff1aSopenharmony_ci           as stereo, to avoid negotiation failures. The actual number of
790cabdff1aSopenharmony_ci           channels can change on a packet-by-packet basis. The number of
791cabdff1aSopenharmony_ci           channels a receiver prefers to receive or a sender plans to send
792cabdff1aSopenharmony_ci           can be declared via fmtp parameters (both default to mono), but
793cabdff1aSopenharmony_ci           receivers MUST be able to receive and process stereo packets. */
794cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "a=rtpmap:%d opus/48000/2\r\n",
795cabdff1aSopenharmony_ci                                 payload_type);
796cabdff1aSopenharmony_ci        if (p->ch_layout.nb_channels == 2) {
797cabdff1aSopenharmony_ci            av_strlcatf(buff, size, "a=fmtp:%d sprop-stereo=1\r\n",
798cabdff1aSopenharmony_ci                                     payload_type);
799cabdff1aSopenharmony_ci        }
800cabdff1aSopenharmony_ci        break;
801cabdff1aSopenharmony_ci    default:
802cabdff1aSopenharmony_ci        /* Nothing special to do here... */
803cabdff1aSopenharmony_ci        break;
804cabdff1aSopenharmony_ci    }
805cabdff1aSopenharmony_ci
806cabdff1aSopenharmony_ci    av_free(config);
807cabdff1aSopenharmony_ci
808cabdff1aSopenharmony_ci    return 0;
809cabdff1aSopenharmony_ci}
810cabdff1aSopenharmony_ci
811cabdff1aSopenharmony_ciint ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx,
812cabdff1aSopenharmony_ci                       const char *dest_addr, const char *dest_type,
813cabdff1aSopenharmony_ci                       int port, int ttl, AVFormatContext *fmt)
814cabdff1aSopenharmony_ci{
815cabdff1aSopenharmony_ci    const AVCodecParameters *p = st->codecpar;
816cabdff1aSopenharmony_ci    const char *type;
817cabdff1aSopenharmony_ci    int payload_type;
818cabdff1aSopenharmony_ci
819cabdff1aSopenharmony_ci    payload_type = ff_rtp_get_payload_type(fmt, st->codecpar, idx);
820cabdff1aSopenharmony_ci
821cabdff1aSopenharmony_ci    switch (p->codec_type) {
822cabdff1aSopenharmony_ci        case AVMEDIA_TYPE_VIDEO   : type = "video"      ; break;
823cabdff1aSopenharmony_ci        case AVMEDIA_TYPE_AUDIO   : type = "audio"      ; break;
824cabdff1aSopenharmony_ci        case AVMEDIA_TYPE_SUBTITLE: type = "text"       ; break;
825cabdff1aSopenharmony_ci        default                 : type = "application"; break;
826cabdff1aSopenharmony_ci    }
827cabdff1aSopenharmony_ci
828cabdff1aSopenharmony_ci    av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type);
829cabdff1aSopenharmony_ci    sdp_write_address(buff, size, dest_addr, dest_type, ttl);
830cabdff1aSopenharmony_ci    if (p->bit_rate) {
831cabdff1aSopenharmony_ci        av_strlcatf(buff, size, "b=AS:%"PRId64"\r\n", p->bit_rate / 1000);
832cabdff1aSopenharmony_ci    }
833cabdff1aSopenharmony_ci
834cabdff1aSopenharmony_ci    return sdp_write_media_attributes(buff, size, st, payload_type, fmt);
835cabdff1aSopenharmony_ci}
836cabdff1aSopenharmony_ci
837cabdff1aSopenharmony_ciint av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size)
838cabdff1aSopenharmony_ci{
839cabdff1aSopenharmony_ci    AVDictionaryEntry *title = av_dict_get(ac[0]->metadata, "title", NULL, 0);
840cabdff1aSopenharmony_ci    struct sdp_session_level s = { 0 };
841cabdff1aSopenharmony_ci    int i, j, port, ttl, is_multicast, index = 0;
842cabdff1aSopenharmony_ci    char dst[32], dst_type[5];
843cabdff1aSopenharmony_ci
844cabdff1aSopenharmony_ci    memset(buf, 0, size);
845cabdff1aSopenharmony_ci    s.user = "-";
846cabdff1aSopenharmony_ci    s.src_addr = "127.0.0.1";    /* FIXME: Properly set this */
847cabdff1aSopenharmony_ci    s.src_type = "IP4";
848cabdff1aSopenharmony_ci    s.name = title ? title->value : "No Name";
849cabdff1aSopenharmony_ci
850cabdff1aSopenharmony_ci    port = 0;
851cabdff1aSopenharmony_ci    ttl = 0;
852cabdff1aSopenharmony_ci    if (n_files == 1) {
853cabdff1aSopenharmony_ci        port = sdp_get_address(dst, sizeof(dst), &ttl, ac[0]->url ? ac[0]->url : "");
854cabdff1aSopenharmony_ci        is_multicast = resolve_destination(dst, sizeof(dst), dst_type,
855cabdff1aSopenharmony_ci                                           sizeof(dst_type));
856cabdff1aSopenharmony_ci        if (!is_multicast)
857cabdff1aSopenharmony_ci            ttl = 0;
858cabdff1aSopenharmony_ci        if (dst[0]) {
859cabdff1aSopenharmony_ci            s.dst_addr = dst;
860cabdff1aSopenharmony_ci            s.dst_type = dst_type;
861cabdff1aSopenharmony_ci            s.ttl = ttl;
862cabdff1aSopenharmony_ci            if (!strcmp(dst_type, "IP6")) {
863cabdff1aSopenharmony_ci                s.src_addr = "::1";
864cabdff1aSopenharmony_ci                s.src_type = "IP6";
865cabdff1aSopenharmony_ci            }
866cabdff1aSopenharmony_ci        }
867cabdff1aSopenharmony_ci    }
868cabdff1aSopenharmony_ci    sdp_write_header(buf, size, &s);
869cabdff1aSopenharmony_ci
870cabdff1aSopenharmony_ci    dst[0] = 0;
871cabdff1aSopenharmony_ci    for (i = 0; i < n_files; i++) {
872cabdff1aSopenharmony_ci        if (n_files != 1) {
873cabdff1aSopenharmony_ci            port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->url ? ac[i]->url : "");
874cabdff1aSopenharmony_ci            is_multicast = resolve_destination(dst, sizeof(dst), dst_type,
875cabdff1aSopenharmony_ci                                               sizeof(dst_type));
876cabdff1aSopenharmony_ci            if (!is_multicast)
877cabdff1aSopenharmony_ci                ttl = 0;
878cabdff1aSopenharmony_ci        }
879cabdff1aSopenharmony_ci        for (j = 0; j < ac[i]->nb_streams; j++) {
880cabdff1aSopenharmony_ci            int ret = ff_sdp_write_media(buf, size, ac[i]->streams[j], index++,
881cabdff1aSopenharmony_ci                                         dst[0] ? dst : NULL, dst_type,
882cabdff1aSopenharmony_ci                                         (port > 0) ? port + j * 2 : 0,
883cabdff1aSopenharmony_ci                                         ttl, ac[i]);
884cabdff1aSopenharmony_ci            if (ret < 0)
885cabdff1aSopenharmony_ci                return ret;
886cabdff1aSopenharmony_ci
887cabdff1aSopenharmony_ci            if (port <= 0) {
888cabdff1aSopenharmony_ci                av_strlcatf(buf, size,
889cabdff1aSopenharmony_ci                                   "a=control:streamid=%d\r\n", i + j);
890cabdff1aSopenharmony_ci            }
891cabdff1aSopenharmony_ci            if (ac[i]->pb && ac[i]->pb->av_class) {
892cabdff1aSopenharmony_ci                uint8_t *crypto_suite = NULL, *crypto_params = NULL;
893cabdff1aSopenharmony_ci                av_opt_get(ac[i]->pb, "srtp_out_suite",  AV_OPT_SEARCH_CHILDREN,
894cabdff1aSopenharmony_ci                           &crypto_suite);
895cabdff1aSopenharmony_ci                av_opt_get(ac[i]->pb, "srtp_out_params", AV_OPT_SEARCH_CHILDREN,
896cabdff1aSopenharmony_ci                           &crypto_params);
897cabdff1aSopenharmony_ci                if (crypto_suite && crypto_suite[0])
898cabdff1aSopenharmony_ci                    av_strlcatf(buf, size,
899cabdff1aSopenharmony_ci                                "a=crypto:1 %s inline:%s\r\n",
900cabdff1aSopenharmony_ci                                crypto_suite, crypto_params);
901cabdff1aSopenharmony_ci                av_free(crypto_suite);
902cabdff1aSopenharmony_ci                av_free(crypto_params);
903cabdff1aSopenharmony_ci            }
904cabdff1aSopenharmony_ci        }
905cabdff1aSopenharmony_ci    }
906cabdff1aSopenharmony_ci
907cabdff1aSopenharmony_ci    return 0;
908cabdff1aSopenharmony_ci}
909cabdff1aSopenharmony_ci#else
910cabdff1aSopenharmony_ciint av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size)
911cabdff1aSopenharmony_ci{
912cabdff1aSopenharmony_ci    return AVERROR(ENOSYS);
913cabdff1aSopenharmony_ci}
914cabdff1aSopenharmony_ci
915cabdff1aSopenharmony_ciint ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx,
916cabdff1aSopenharmony_ci                       const char *dest_addr, const char *dest_type,
917cabdff1aSopenharmony_ci                       int port, int ttl, AVFormatContext *fmt)
918cabdff1aSopenharmony_ci{
919cabdff1aSopenharmony_ci    return AVERROR(ENOSYS);
920cabdff1aSopenharmony_ci}
921cabdff1aSopenharmony_ci#endif
922