FFmpeg
url.c
Go to the documentation of this file.
1 /*
2  * URL utility functions
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 
23 #include "avformat.h"
24 #include "internal.h"
25 #include "config.h"
26 #include "url.h"
27 #if CONFIG_NETWORK
28 #include "network.h"
29 #endif
30 #include "libavutil/avassert.h"
31 #include "libavutil/avstring.h"
32 
33 /**
34  * @file
35  * URL utility functions.
36  */
37 
38 int ff_url_join(char *str, int size, const char *proto,
39  const char *authorization, const char *hostname,
40  int port, const char *fmt, ...)
41 {
42 #if CONFIG_NETWORK
43  struct addrinfo hints = { 0 }, *ai;
44 #endif
45 
46  str[0] = '\0';
47  if (proto)
48  av_strlcatf(str, size, "%s://", proto);
49  if (authorization && authorization[0])
50  av_strlcatf(str, size, "%s@", authorization);
51 #if CONFIG_NETWORK && defined(AF_INET6)
52  /* Determine if hostname is a numerical IPv6 address,
53  * properly escape it within [] in that case. */
54  hints.ai_flags = AI_NUMERICHOST;
55  if (!getaddrinfo(hostname, NULL, &hints, &ai)) {
56  if (ai->ai_family == AF_INET6) {
57  av_strlcat(str, "[", size);
58  av_strlcat(str, hostname, size);
59  av_strlcat(str, "]", size);
60  } else {
61  av_strlcat(str, hostname, size);
62  }
63  freeaddrinfo(ai);
64  } else
65 #endif
66  /* Not an IPv6 address, just output the plain string. */
67  av_strlcat(str, hostname, size);
68 
69  if (port >= 0)
70  av_strlcatf(str, size, ":%d", port);
71  if (fmt) {
72  va_list vl;
73  size_t len = strlen(str);
74 
75  va_start(vl, fmt);
76  vsnprintf(str + len, size > len ? size - len : 0, fmt, vl);
77  va_end(vl);
78  }
79  return strlen(str);
80 }
81 
82 static const char *find_delim(const char *delim, const char *cur, const char *end)
83 {
84  while (cur < end && !strchr(delim, *cur))
85  cur++;
86  return cur;
87 }
88 
89 int ff_url_decompose(URLComponents *uc, const char *url, const char *end)
90 {
91  const char *cur, *aend, *p;
92 
93  av_assert0(url);
94  if (!end)
95  end = url + strlen(url);
96  cur = uc->url = url;
97 
98  /* scheme */
99  uc->scheme = cur;
100  p = find_delim(":/", cur, end); /* lavf "schemes" can contain options */
101  if (*p == ':')
102  cur = p + 1;
103 
104  /* authority */
105  uc->authority = cur;
106  if (end - cur >= 2 && cur[0] == '/' && cur[1] == '/') {
107  cur += 2;
108  aend = find_delim("/?#", cur, end);
109 
110  /* userinfo */
111  uc->userinfo = cur;
112  p = find_delim("@", cur, aend);
113  if (*p == '@')
114  cur = p + 1;
115 
116  /* host */
117  uc->host = cur;
118  if (*cur == '[') { /* hello IPv6, thanks for using colons! */
119  p = find_delim("]", cur, aend);
120  if (*p != ']')
121  return AVERROR(EINVAL);
122  if (p + 1 < aend && p[1] != ':')
123  return AVERROR(EINVAL);
124  cur = p + 1;
125  } else {
126  cur = find_delim(":", cur, aend);
127  }
128 
129  /* port */
130  uc->port = cur;
131  cur = aend;
132  } else {
133  uc->userinfo = uc->host = uc->port = cur;
134  }
135 
136  /* path */
137  uc->path = cur;
138  cur = find_delim("?#", cur, end);
139 
140  /* query */
141  uc->query = cur;
142  if (*cur == '?')
143  cur = find_delim("#", cur, end);
144 
145  /* fragment */
146  uc->fragment = cur;
147 
148  uc->end = end;
149  return 0;
150 }
151 
152 static int append_path(char *root, char *out_end, char **rout,
153  const char *in, const char *in_end)
154 {
155  char *out = *rout;
156  const char *d, *next;
157 
158  if (in < in_end && *in == '/')
159  in++; /* already taken care of */
160  while (in < in_end) {
161  d = find_delim("/", in, in_end);
162  next = d + (d < in_end && *d == '/');
163  if (d - in == 1 && in[0] == '.') {
164  /* skip */
165  } else if (d - in == 2 && in[0] == '.' && in[1] == '.') {
166  av_assert1(out[-1] == '/');
167  if (out - root > 1)
168  while (out > root && (--out)[-1] != '/');
169  } else {
170  if (out_end - out < next - in)
171  return AVERROR(ENOMEM);
172  memmove(out, in, next - in);
173  out += next - in;
174  }
175  in = next;
176  }
177  *rout = out;
178  return 0;
179 }
180 
181 int ff_make_absolute_url(char *buf, int size, const char *base,
182  const char *rel)
183 {
184  URLComponents ub, uc;
185  char *out, *out_end, *path;
186  const char *keep, *base_path_end;
187  int use_base_path, simplify_path = 0, ret;
188 
189  /* This is tricky.
190  For HTTP, http://server/site/page + ../media/file
191  should resolve into http://server/media/file
192  but for filesystem access, dir/playlist + ../media/file
193  should resolve into dir/../media/file
194  because dir could be a symlink, and .. points to
195  the actual parent of the target directory.
196 
197  We'll consider that URLs with an actual scheme and authority,
198  i.e. starting with scheme://, need parent dir simplification,
199  while bare paths or pseudo-URLs starting with proto: without
200  the double slash do not.
201 
202  For real URLs, the processing is similar to the algorithm described
203  here:
204  https://tools.ietf.org/html/rfc3986#section-5
205  */
206 
207  if (!size)
208  return AVERROR(ENOMEM);
209  out = buf;
210  out_end = buf + size - 1;
211 
212  if (!base)
213  base = "";
214  if ((ret = ff_url_decompose(&ub, base, NULL) < 0) ||
215  (ret = ff_url_decompose(&uc, rel, NULL) < 0))
216  goto error;
217 
218  keep = ub.url;
219 #define KEEP(component, also) do { \
220  if (uc.url_component_end_##component == uc.url && \
221  ub.url_component_end_##component > keep) { \
222  keep = ub.url_component_end_##component; \
223  also \
224  } \
225  } while (0)
226  KEEP(scheme, );
227  KEEP(authority_full, simplify_path = 1;);
228  KEEP(path,);
229  KEEP(query,);
230  KEEP(fragment,);
231 #undef KEEP
232 #define COPY(start, end) do { \
233  size_t len = end - start; \
234  if (len > out_end - out) { \
235  ret = AVERROR(ENOMEM); \
236  goto error; \
237  } \
238  memmove(out, start, len); \
239  out += len; \
240  } while (0)
241  COPY(ub.url, keep);
242  COPY(uc.url, uc.path);
243 
244  use_base_path = URL_COMPONENT_HAVE(ub, path) && keep <= ub.path;
245  if (uc.path > uc.url)
246  use_base_path = 0;
247  if (URL_COMPONENT_HAVE(uc, path) && uc.path[0] == '/')
248  use_base_path = 0;
249  if (use_base_path) {
250  base_path_end = ub.url_component_end_path;
251  if (URL_COMPONENT_HAVE(uc, path))
252  while (base_path_end > ub.path && base_path_end[-1] != '/')
253  base_path_end--;
254  }
255  if (keep > ub.path)
256  simplify_path = 0;
257  if (URL_COMPONENT_HAVE(uc, scheme))
258  simplify_path = 0;
259  if (URL_COMPONENT_HAVE(uc, authority))
260  simplify_path = 1;
261  /* No path at all, leave it */
262  if (!use_base_path && !URL_COMPONENT_HAVE(uc, path))
263  simplify_path = 0;
264 
265  if (simplify_path) {
266  const char *root = "/";
267  COPY(root, root + 1);
268  path = out;
269  if (use_base_path) {
270  ret = append_path(path, out_end, &out, ub.path, base_path_end);
271  if (ret < 0)
272  goto error;
273  }
274  if (URL_COMPONENT_HAVE(uc, path)) {
275  ret = append_path(path, out_end, &out, uc.path, uc.url_component_end_path);
276  if (ret < 0)
277  goto error;
278  }
279  } else {
280  if (use_base_path)
281  COPY(ub.path, base_path_end);
282  COPY(uc.path, uc.url_component_end_path);
283  }
284 
285  COPY(uc.url_component_end_path, uc.end);
286 #undef COPY
287  *out = 0;
288  return 0;
289 
290 error:
291  snprintf(buf, size, "invalid:%s",
292  ret == AVERROR(ENOMEM) ? "truncated" :
293  ret == AVERROR(EINVAL) ? "syntax_error" : "");
294  return ret;
295 }
296 
298 {
299  AVIODirEntry *entry = av_mallocz(sizeof(AVIODirEntry));
300  if (entry) {
301  entry->type = AVIO_ENTRY_UNKNOWN;
302  entry->size = -1;
303  entry->modification_timestamp = -1;
304  entry->access_timestamp = -1;
305  entry->status_change_timestamp = -1;
306  entry->user_id = -1;
307  entry->group_id = -1;
308  entry->filemode = -1;
309  }
310  return entry;
311 }
#define NULL
Definition: coverity.c:32
int ff_url_decompose(URLComponents *uc, const char *url, const char *end)
Parse an URL to find the components.
Definition: url.c:89
#define URL_COMPONENT_HAVE(uc, component)
Definition: url.h:370
int64_t filemode
Unix file mode, -1 if unknown.
Definition: avio.h:100
const char * url
whole URL, for reference
Definition: url.h:348
Describes single entry of the directory.
Definition: avio.h:86
#define vsnprintf
Definition: snprintf.h:36
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
#define freeaddrinfo
Definition: network.h:218
static void error(const char *err)
static const char * find_delim(const char *delim, const char *cur, const char *end)
Definition: url.c:82
#define AI_NUMERICHOST
Definition: network.h:187
#define COPY(start, end)
uint8_t base
Definition: vp3data.h:202
const char * end
Definition: url.h:357
int64_t modification_timestamp
Time of last modification in microseconds since unix epoch, -1 if unknown.
Definition: avio.h:92
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:92
ptrdiff_t size
Definition: opengl_enc.c:100
simple assert() macros that are a bit more flexible than ISO C assert().
const char * userinfo
including final &#39;@&#39; if present
Definition: url.h:351
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:53
const char * authority
"//" if it is a real URL
Definition: url.h:350
const char * query
including initial &#39;?&#39; if present
Definition: url.h:355
int64_t access_timestamp
Time of last access in microseconds since unix epoch, -1 if unknown.
Definition: avio.h:94
int ff_make_absolute_url(char *buf, int size, const char *base, const char *rel)
Convert a relative url into an absolute url, given a base url.
Definition: url.c:181
int64_t size
File size in bytes, -1 if unknown.
Definition: avio.h:91
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition: url.c:38
int type
Type of the entry.
Definition: avio.h:88
const char * host
Definition: url.h:352
#define ub(width, name)
Definition: cbs_h2645.c:264
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31))))#define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac){}void ff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map){AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);return NULL;}return ac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;}int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){int use_generic=1;int len=in->nb_samples;int p;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
int64_t group_id
Group ID of owner, -1 if unknown.
Definition: avio.h:99
const char * port
including initial &#39;:&#39; if present
Definition: url.h:353
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
#define snprintf
Definition: snprintf.h:34
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes...
Definition: avstring.c:93
const char * path
Definition: url.h:354
static int append_path(char *root, char *out_end, char **rout, const char *in, const char *in_end)
Definition: url.c:152
const char * scheme
possibly including lavf-specific options
Definition: url.h:349
#define getaddrinfo
Definition: network.h:217
Main libavformat public API header.
int64_t status_change_timestamp
Time of last status change in microseconds since unix epoch, -1 if unknown.
Definition: avio.h:96
AVIODirEntry * ff_alloc_dir_entry(void)
Allocate directory entry with default values.
Definition: url.c:297
int len
int64_t user_id
User ID of owner, -1 if unknown.
Definition: avio.h:98
int ai_flags
Definition: network.h:138
FILE * out
Definition: movenc.c:54
unbuffered private I/O API
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
const char * fragment
including initial &#39;#&#39; if present
Definition: url.h:356
#define KEEP(component, also)