• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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