xref: /third_party/ffmpeg/libavformat/utils.c (revision cabdff1a)
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
41static AVMutex avformat_mutex = AV_MUTEX_INITIALIZER;
42
43/**
44 * @file
45 * various utility functions for use within FFmpeg
46 */
47
48int ff_lock_avformat(void)
49{
50    return ff_mutex_lock(&avformat_mutex) ? -1 : 0;
51}
52
53int 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. */
63static 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
102int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
103{
104#if FF_API_INIT_PACKET
105FF_DISABLE_DEPRECATION_WARNINGS
106    av_init_packet(pkt);
107    pkt->data = NULL;
108    pkt->size = 0;
109FF_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
118int 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
125int 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
134unsigned 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
144enum 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
155enum 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
204unsigned 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
212int 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
228enum 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
238int 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
258uint64_t ff_ntp_time(void)
259{
260    return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US;
261}
262
263uint64_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
285uint64_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
294int 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 {
338addchar:
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;
347fail:
348    *q = '\0';
349    return -1;
350}
351
352int 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
357void 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
420int 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
454char *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
475int 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
503void 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
557int 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
569int avformat_network_deinit(void)
570{
571#if CONFIG_NETWORK
572    ff_network_close();
573    ff_tls_deinit();
574#endif
575    return 0;
576}
577
578int 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
583int 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