1 /*
2 * various utility functions for use within FFmpeg
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 #include <stdint.h>
23
24 #include "config.h"
25
26 #include "libavutil/avstring.h"
27 #include "libavutil/bprint.h"
28 #include "libavutil/internal.h"
29 #include "libavutil/thread.h"
30 #include "libavutil/time.h"
31
32 #include "libavcodec/internal.h"
33
34 #include "avformat.h"
35 #include "avio_internal.h"
36 #include "internal.h"
37 #if CONFIG_NETWORK
38 #include "network.h"
39 #endif
40
41 static AVMutex avformat_mutex = AV_MUTEX_INITIALIZER;
42
43 /**
44 * @file
45 * various utility functions for use within FFmpeg
46 */
47
ff_lock_avformat(void)48 int ff_lock_avformat(void)
49 {
50 return ff_mutex_lock(&avformat_mutex) ? -1 : 0;
51 }
52
ff_unlock_avformat(void)53 int ff_unlock_avformat(void)
54 {
55 return ff_mutex_unlock(&avformat_mutex) ? -1 : 0;
56 }
57
58 /* an arbitrarily chosen "sane" max packet size -- 50M */
59 #define SANE_CHUNK_SIZE (50000000)
60
61 /* Read the data in sane-sized chunks and append to pkt.
62 * Return the number of bytes read or an error. */
append_packet_chunked(AVIOContext * s,AVPacket * pkt,int size)63 static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size)
64 {
65 int orig_size = pkt->size;
66 int ret;
67
68 do {
69 int prev_size = pkt->size;
70 int read_size;
71
72 /* When the caller requests a lot of data, limit it to the amount
73 * left in file or SANE_CHUNK_SIZE when it is not known. */
74 read_size = size;
75 if (read_size > SANE_CHUNK_SIZE/10) {
76 read_size = ffio_limit(s, read_size);
77 // If filesize/maxsize is unknown, limit to SANE_CHUNK_SIZE
78 if (ffiocontext(s)->maxsize < 0)
79 read_size = FFMIN(read_size, SANE_CHUNK_SIZE);
80 }
81
82 ret = av_grow_packet(pkt, read_size);
83 if (ret < 0)
84 break;
85
86 ret = avio_read(s, pkt->data + prev_size, read_size);
87 if (ret != read_size) {
88 av_shrink_packet(pkt, prev_size + FFMAX(ret, 0));
89 break;
90 }
91
92 size -= read_size;
93 } while (size > 0);
94 if (size > 0)
95 pkt->flags |= AV_PKT_FLAG_CORRUPT;
96
97 if (!pkt->size)
98 av_packet_unref(pkt);
99 return pkt->size > orig_size ? pkt->size - orig_size : ret;
100 }
101
av_get_packet(AVIOContext * s,AVPacket * pkt,int size)102 int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
103 {
104 #if FF_API_INIT_PACKET
105 FF_DISABLE_DEPRECATION_WARNINGS
106 av_init_packet(pkt);
107 pkt->data = NULL;
108 pkt->size = 0;
109 FF_ENABLE_DEPRECATION_WARNINGS
110 #else
111 av_packet_unref(pkt);
112 #endif
113 pkt->pos = avio_tell(s);
114
115 return append_packet_chunked(s, pkt, size);
116 }
117
av_append_packet(AVIOContext * s,AVPacket * pkt,int size)118 int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
119 {
120 if (!pkt->size)
121 return av_get_packet(s, pkt, size);
122 return append_packet_chunked(s, pkt, size);
123 }
124
av_filename_number_test(const char * filename)125 int av_filename_number_test(const char *filename)
126 {
127 char buf[1024];
128 return filename &&
129 (av_get_frame_filename(buf, sizeof(buf), filename, 1) >= 0);
130 }
131
132 /**********************************************************/
133
ff_codec_get_tag(const AVCodecTag * tags,enum AVCodecID id)134 unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum AVCodecID id)
135 {
136 while (tags->id != AV_CODEC_ID_NONE) {
137 if (tags->id == id)
138 return tags->tag;
139 tags++;
140 }
141 return 0;
142 }
143
ff_codec_get_id(const AVCodecTag * tags,unsigned int tag)144 enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag)
145 {
146 for (int i = 0; tags[i].id != AV_CODEC_ID_NONE; i++)
147 if (tag == tags[i].tag)
148 return tags[i].id;
149 for (int i = 0; tags[i].id != AV_CODEC_ID_NONE; i++)
150 if (ff_toupper4(tag) == ff_toupper4(tags[i].tag))
151 return tags[i].id;
152 return AV_CODEC_ID_NONE;
153 }
154
ff_get_pcm_codec_id(int bps,int flt,int be,int sflags)155 enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags)
156 {
157 if (bps <= 0 || bps > 64)
158 return AV_CODEC_ID_NONE;
159
160 if (flt) {
161 switch (bps) {
162 case 32:
163 return be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE;
164 case 64:
165 return be ? AV_CODEC_ID_PCM_F64BE : AV_CODEC_ID_PCM_F64LE;
166 default:
167 return AV_CODEC_ID_NONE;
168 }
169 } else {
170 bps += 7;
171 bps >>= 3;
172 if (sflags & (1 << (bps - 1))) {
173 switch (bps) {
174 case 1:
175 return AV_CODEC_ID_PCM_S8;
176 case 2:
177 return be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE;
178 case 3:
179 return be ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
180 case 4:
181 return be ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE;
182 case 8:
183 return be ? AV_CODEC_ID_PCM_S64BE : AV_CODEC_ID_PCM_S64LE;
184 default:
185 return AV_CODEC_ID_NONE;
186 }
187 } else {
188 switch (bps) {
189 case 1:
190 return AV_CODEC_ID_PCM_U8;
191 case 2:
192 return be ? AV_CODEC_ID_PCM_U16BE : AV_CODEC_ID_PCM_U16LE;
193 case 3:
194 return be ? AV_CODEC_ID_PCM_U24BE : AV_CODEC_ID_PCM_U24LE;
195 case 4:
196 return be ? AV_CODEC_ID_PCM_U32BE : AV_CODEC_ID_PCM_U32LE;
197 default:
198 return AV_CODEC_ID_NONE;
199 }
200 }
201 }
202 }
203
av_codec_get_tag(const AVCodecTag * const * tags,enum AVCodecID id)204 unsigned int av_codec_get_tag(const AVCodecTag *const *tags, enum AVCodecID id)
205 {
206 unsigned int tag;
207 if (!av_codec_get_tag2(tags, id, &tag))
208 return 0;
209 return tag;
210 }
211
av_codec_get_tag2(const AVCodecTag * const * tags,enum AVCodecID id,unsigned int * tag)212 int av_codec_get_tag2(const AVCodecTag * const *tags, enum AVCodecID id,
213 unsigned int *tag)
214 {
215 for (int i = 0; tags && tags[i]; i++) {
216 const AVCodecTag *codec_tags = tags[i];
217 while (codec_tags->id != AV_CODEC_ID_NONE) {
218 if (codec_tags->id == id) {
219 *tag = codec_tags->tag;
220 return 1;
221 }
222 codec_tags++;
223 }
224 }
225 return 0;
226 }
227
av_codec_get_id(const AVCodecTag * const * tags,unsigned int tag)228 enum AVCodecID av_codec_get_id(const AVCodecTag *const *tags, unsigned int tag)
229 {
230 for (int i = 0; tags && tags[i]; i++) {
231 enum AVCodecID id = ff_codec_get_id(tags[i], tag);
232 if (id != AV_CODEC_ID_NONE)
233 return id;
234 }
235 return AV_CODEC_ID_NONE;
236 }
237
ff_alloc_extradata(AVCodecParameters * par,int size)238 int ff_alloc_extradata(AVCodecParameters *par, int size)
239 {
240 av_freep(&par->extradata);
241 par->extradata_size = 0;
242
243 if (size < 0 || size >= INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
244 return AVERROR(EINVAL);
245
246 par->extradata = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
247 if (!par->extradata)
248 return AVERROR(ENOMEM);
249
250 memset(par->extradata + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
251 par->extradata_size = size;
252
253 return 0;
254 }
255
256 /*******************************************************/
257
ff_ntp_time(void)258 uint64_t ff_ntp_time(void)
259 {
260 return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US;
261 }
262
ff_get_formatted_ntp_time(uint64_t ntp_time_us)263 uint64_t ff_get_formatted_ntp_time(uint64_t ntp_time_us)
264 {
265 uint64_t ntp_ts, frac_part, sec;
266 uint32_t usec;
267
268 //current ntp time in seconds and micro seconds
269 sec = ntp_time_us / 1000000;
270 usec = ntp_time_us % 1000000;
271
272 //encoding in ntp timestamp format
273 frac_part = usec * 0xFFFFFFFFULL;
274 frac_part /= 1000000;
275
276 if (sec > 0xFFFFFFFFULL)
277 av_log(NULL, AV_LOG_WARNING, "NTP time format roll over detected\n");
278
279 ntp_ts = sec << 32;
280 ntp_ts |= frac_part;
281
282 return ntp_ts;
283 }
284
ff_parse_ntp_time(uint64_t ntp_ts)285 uint64_t ff_parse_ntp_time(uint64_t ntp_ts)
286 {
287 uint64_t sec = ntp_ts >> 32;
288 uint64_t frac_part = ntp_ts & 0xFFFFFFFFULL;
289 uint64_t usec = (frac_part * 1000000) / 0xFFFFFFFFULL;
290
291 return (sec * 1000000) + usec;
292 }
293
av_get_frame_filename2(char * buf,int buf_size,const char * path,int number,int flags)294 int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number, int flags)
295 {
296 const char *p;
297 char *q, buf1[20], c;
298 int nd, len, percentd_found;
299
300 q = buf;
301 p = path;
302 percentd_found = 0;
303 for (;;) {
304 c = *p++;
305 if (c == '\0')
306 break;
307 if (c == '%') {
308 do {
309 nd = 0;
310 while (av_isdigit(*p)) {
311 if (nd >= INT_MAX / 10 - 255)
312 goto fail;
313 nd = nd * 10 + *p++ - '0';
314 }
315 c = *p++;
316 } while (av_isdigit(c));
317
318 switch (c) {
319 case '%':
320 goto addchar;
321 case 'd':
322 if (!(flags & AV_FRAME_FILENAME_FLAGS_MULTIPLE) && percentd_found)
323 goto fail;
324 percentd_found = 1;
325 if (number < 0)
326 nd += 1;
327 snprintf(buf1, sizeof(buf1), "%0*d", nd, number);
328 len = strlen(buf1);
329 if ((q - buf + len) > buf_size - 1)
330 goto fail;
331 memcpy(q, buf1, len);
332 q += len;
333 break;
334 default:
335 goto fail;
336 }
337 } else {
338 addchar:
339 if ((q - buf) < buf_size - 1)
340 *q++ = c;
341 }
342 }
343 if (!percentd_found)
344 goto fail;
345 *q = '\0';
346 return 0;
347 fail:
348 *q = '\0';
349 return -1;
350 }
351
av_get_frame_filename(char * buf,int buf_size,const char * path,int number)352 int av_get_frame_filename(char *buf, int buf_size, const char *path, int number)
353 {
354 return av_get_frame_filename2(buf, buf_size, path, number, 0);
355 }
356
av_url_split(char * proto,int proto_size,char * authorization,int authorization_size,char * hostname,int hostname_size,int * port_ptr,char * path,int path_size,const char * url)357 void av_url_split(char *proto, int proto_size,
358 char *authorization, int authorization_size,
359 char *hostname, int hostname_size,
360 int *port_ptr, char *path, int path_size, const char *url)
361 {
362 const char *p, *ls, *at, *at2, *col, *brk;
363
364 if (port_ptr)
365 *port_ptr = -1;
366 if (proto_size > 0)
367 proto[0] = 0;
368 if (authorization_size > 0)
369 authorization[0] = 0;
370 if (hostname_size > 0)
371 hostname[0] = 0;
372 if (path_size > 0)
373 path[0] = 0;
374
375 /* parse protocol */
376 if ((p = strchr(url, ':'))) {
377 av_strlcpy(proto, url, FFMIN(proto_size, p + 1 - url));
378 p++; /* skip ':' */
379 if (*p == '/')
380 p++;
381 if (*p == '/')
382 p++;
383 } else {
384 /* no protocol means plain filename */
385 av_strlcpy(path, url, path_size);
386 return;
387 }
388
389 /* separate path from hostname */
390 ls = p + strcspn(p, "/?#");
391 av_strlcpy(path, ls, path_size);
392
393 /* the rest is hostname, use that to parse auth/port */
394 if (ls != p) {
395 /* authorization (user[:pass]@hostname) */
396 at2 = p;
397 while ((at = strchr(p, '@')) && at < ls) {
398 av_strlcpy(authorization, at2,
399 FFMIN(authorization_size, at + 1 - at2));
400 p = at + 1; /* skip '@' */
401 }
402
403 if (*p == '[' && (brk = strchr(p, ']')) && brk < ls) {
404 /* [host]:port */
405 av_strlcpy(hostname, p + 1,
406 FFMIN(hostname_size, brk - p));
407 if (brk[1] == ':' && port_ptr)
408 *port_ptr = atoi(brk + 2);
409 } else if ((col = strchr(p, ':')) && col < ls) {
410 av_strlcpy(hostname, p,
411 FFMIN(col + 1 - p, hostname_size));
412 if (port_ptr)
413 *port_ptr = atoi(col + 1);
414 } else
415 av_strlcpy(hostname, p,
416 FFMIN(ls + 1 - p, hostname_size));
417 }
418 }
419
ff_mkdir_p(const char * path)420 int ff_mkdir_p(const char *path)
421 {
422 int ret = 0;
423 char *temp = av_strdup(path);
424 char *pos = temp;
425 char tmp_ch = '\0';
426
427 if (!path || !temp) {
428 return -1;
429 }
430
431 if (!av_strncasecmp(temp, "/", 1) || !av_strncasecmp(temp, "\\", 1)) {
432 pos++;
433 } else if (!av_strncasecmp(temp, "./", 2) || !av_strncasecmp(temp, ".\\", 2)) {
434 pos += 2;
435 }
436
437 for ( ; *pos != '\0'; ++pos) {
438 if (*pos == '/' || *pos == '\\') {
439 tmp_ch = *pos;
440 *pos = '\0';
441 ret = mkdir(temp, 0755);
442 *pos = tmp_ch;
443 }
444 }
445
446 if ((*(pos - 1) != '/') && (*(pos - 1) != '\\')) {
447 ret = mkdir(temp, 0755);
448 }
449
450 av_free(temp);
451 return ret;
452 }
453
ff_data_to_hex(char * buff,const uint8_t * src,int s,int lowercase)454 char *ff_data_to_hex(char *buff, const uint8_t *src, int s, int lowercase)
455 {
456 static const char hex_table_uc[16] = { '0', '1', '2', '3',
457 '4', '5', '6', '7',
458 '8', '9', 'A', 'B',
459 'C', 'D', 'E', 'F' };
460 static const char hex_table_lc[16] = { '0', '1', '2', '3',
461 '4', '5', '6', '7',
462 '8', '9', 'a', 'b',
463 'c', 'd', 'e', 'f' };
464 const char *hex_table = lowercase ? hex_table_lc : hex_table_uc;
465
466 for (int i = 0; i < s; i++) {
467 buff[i * 2] = hex_table[src[i] >> 4];
468 buff[i * 2 + 1] = hex_table[src[i] & 0xF];
469 }
470 buff[2 * s] = '\0';
471
472 return buff;
473 }
474
ff_hex_to_data(uint8_t * data,const char * p)475 int ff_hex_to_data(uint8_t *data, const char *p)
476 {
477 int c, len, v;
478
479 len = 0;
480 v = 1;
481 for (;;) {
482 p += strspn(p, SPACE_CHARS);
483 if (*p == '\0')
484 break;
485 c = av_toupper((unsigned char) *p++);
486 if (c >= '0' && c <= '9')
487 c = c - '0';
488 else if (c >= 'A' && c <= 'F')
489 c = c - 'A' + 10;
490 else
491 break;
492 v = (v << 4) | c;
493 if (v & 0x100) {
494 if (data)
495 data[len] = v;
496 len++;
497 v = 1;
498 }
499 }
500 return len;
501 }
502
ff_parse_key_value(const char * str,ff_parse_key_val_cb callback_get_buf,void * context)503 void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf,
504 void *context)
505 {
506 const char *ptr = str;
507
508 /* Parse key=value pairs. */
509 for (;;) {
510 const char *key;
511 char *dest = NULL, *dest_end;
512 int key_len, dest_len = 0;
513
514 /* Skip whitespace and potential commas. */
515 while (*ptr && (av_isspace(*ptr) || *ptr == ','))
516 ptr++;
517 if (!*ptr)
518 break;
519
520 key = ptr;
521
522 if (!(ptr = strchr(key, '=')))
523 break;
524 ptr++;
525 key_len = ptr - key;
526
527 callback_get_buf(context, key, key_len, &dest, &dest_len);
528 dest_end = dest ? dest + dest_len - 1 : NULL;
529
530 if (*ptr == '\"') {
531 ptr++;
532 while (*ptr && *ptr != '\"') {
533 if (*ptr == '\\') {
534 if (!ptr[1])
535 break;
536 if (dest && dest < dest_end)
537 *dest++ = ptr[1];
538 ptr += 2;
539 } else {
540 if (dest && dest < dest_end)
541 *dest++ = *ptr;
542 ptr++;
543 }
544 }
545 if (*ptr == '\"')
546 ptr++;
547 } else {
548 for (; *ptr && !(av_isspace(*ptr) || *ptr == ','); ptr++)
549 if (dest && dest < dest_end)
550 *dest++ = *ptr;
551 }
552 if (dest)
553 *dest = 0;
554 }
555 }
556
avformat_network_init(void)557 int avformat_network_init(void)
558 {
559 #if CONFIG_NETWORK
560 int ret;
561 if ((ret = ff_network_init()) < 0)
562 return ret;
563 if ((ret = ff_tls_init()) < 0)
564 return ret;
565 #endif
566 return 0;
567 }
568
avformat_network_deinit(void)569 int avformat_network_deinit(void)
570 {
571 #if CONFIG_NETWORK
572 ff_network_close();
573 ff_tls_deinit();
574 #endif
575 return 0;
576 }
577
ff_is_http_proto(const char * filename)578 int ff_is_http_proto(const char *filename) {
579 const char *proto = avio_find_protocol_name(filename);
580 return proto ? (!av_strcasecmp(proto, "http") || !av_strcasecmp(proto, "https")) : 0;
581 }
582
ff_bprint_to_codecpar_extradata(AVCodecParameters * par,struct AVBPrint * buf)583 int ff_bprint_to_codecpar_extradata(AVCodecParameters *par, struct AVBPrint *buf)
584 {
585 int ret;
586 char *str;
587
588 ret = av_bprint_finalize(buf, &str);
589 if (ret < 0)
590 return ret;
591 if (!av_bprint_is_complete(buf)) {
592 av_free(str);
593 return AVERROR(ENOMEM);
594 }
595
596 par->extradata = str;
597 /* Note: the string is NUL terminated (so extradata can be read as a
598 * string), but the ending character is not accounted in the size (in
599 * binary formats you are likely not supposed to mux that character). When
600 * extradata is copied, it is also padded with AV_INPUT_BUFFER_PADDING_SIZE
601 * zeros. */
602 par->extradata_size = buf->len;
603 return 0;
604 }
605