1 /*****************************************************************************
2 * utils.c / utils.cpp
3 *****************************************************************************
4 * Copyright (C) 2012-2015 L-SMASH Works project
5 *
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
20
21 /* This file is available under an ISC license. */
22
23 #include "cpp_compat.h"
24
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <inttypes.h>
29 #include <math.h>
30
31 #include "utils.h"
32
lw_malloc_zero(size_t size)33 void *lw_malloc_zero( size_t size )
34 {
35 void *p = malloc( size );
36 if( !p )
37 return NULL;
38 memset( p, 0, size );
39 return p;
40 }
41
lw_free(void * pointer)42 void lw_free( void *pointer )
43 {
44 free( pointer );
45 }
46
lw_freep(void * pointer)47 void lw_freep( void *pointer )
48 {
49 if( !pointer )
50 return;
51 void **p = (void **)pointer;
52 free( *p );
53 *p = NULL;
54 }
55
lw_memdup(void * src,size_t size)56 void *lw_memdup
57 (
58 void *src,
59 size_t size
60 )
61 {
62 if( size == 0 )
63 return NULL;
64 void *dst = malloc( size );
65 if( !dst )
66 return NULL;
67 memcpy( dst, src, size );
68 return dst;
69 }
70
lw_log_write_message(lw_log_handler_t * lhp,lw_log_level level,char * message,const char * format,va_list args)71 static void lw_log_write_message
72 (
73 lw_log_handler_t *lhp,
74 lw_log_level level,
75 char *message,
76 const char *format,
77 va_list args
78 )
79 {
80 char *prefix;
81 switch( level )
82 {
83 case LW_LOG_FATAL:
84 prefix = "Fatal";
85 break;
86 case LW_LOG_ERROR:
87 prefix = "Error";
88 break;
89 case LW_LOG_WARNING:
90 prefix = "Warning";
91 break;
92 case LW_LOG_INFO:
93 prefix = "Info";
94 break;
95 default:
96 prefix = "Unknown";
97 break;
98 }
99 char temp[512];
100 vsprintf( temp, format, args );
101 if( lhp->name )
102 sprintf( message, "%s [%s]: %s", lhp->name, prefix, temp );
103 else
104 sprintf( message, "[%s]: %s", prefix, temp );
105 }
106
lw_log_show(lw_log_handler_t * lhp,lw_log_level level,const char * format,...)107 void lw_log_show
108 (
109 lw_log_handler_t *lhp,
110 lw_log_level level,
111 const char *format,
112 ...
113 )
114 {
115 if( !lhp || !lhp->priv || !lhp->show_log || level < lhp->level )
116 return;
117 va_list args;
118 va_start( args, format );
119 char message[1024];
120 lw_log_write_message( lhp, level, message, format, args );
121 va_end( args );
122 lhp->show_log( lhp, level, message );
123 }
124
lw_check_file_extension(const char * file_name,const char * extension)125 int lw_check_file_extension
126 (
127 const char *file_name,
128 const char *extension
129 )
130 {
131 int extension_length = strlen( extension );
132 int file_name_length = strlen( file_name );
133 if( file_name_length - extension_length <= 1 )
134 return -1;
135 const char *ext = &file_name[file_name_length - extension_length];
136 return ext[-1] != '.' || memcmp( extension, ext, extension_length ) ? -1 : 0;
137 }
138
lw_round(double x)139 static inline double lw_round
140 (
141 double x
142 )
143 {
144 return x > 0 ? floor( x + 0.5 ) : ceil( x - 0.5 );
145 }
146
sigexp10(double value,double * exponent)147 static inline double sigexp10
148 (
149 double value,
150 double *exponent
151 )
152 {
153 /* This function separates significand and exp10 from double floating point. */
154 *exponent = 1;
155 while( value < 1 )
156 {
157 value *= 10;
158 *exponent /= 10;
159 }
160 while( value >= 10 )
161 {
162 value /= 10;
163 *exponent *= 10;
164 }
165 return value;
166 }
167
lw_try_rational_framerate(double framerate,int64_t * framerate_num,int64_t * framerate_den,uint64_t timebase)168 int lw_try_rational_framerate
169 (
170 double framerate,
171 int64_t *framerate_num,
172 int64_t *framerate_den,
173 uint64_t timebase
174 )
175 {
176 #define DOUBLE_EPSILON 5e-5
177 if( framerate == 0 )
178 return 0;
179 uint64_t fps_den[3] = { 0 };
180 uint64_t fps_num[3] = { 0 };
181 double error[3] = { DOUBLE_EPSILON, DOUBLE_EPSILON, DOUBLE_EPSILON };
182 double exponent;
183 double fps_sig = sigexp10( framerate, &exponent );
184 uint64_t base[3] = { timebase, 1001, 1 };
185 for( int i = 0; i < 3; i++ )
186 {
187 if( i && base[i] == base[0] )
188 continue;
189 if( i == 2 && (error[0] < DOUBLE_EPSILON || error[1] < DOUBLE_EPSILON) )
190 break;
191 for( int j = 1; ; j++ )
192 {
193 fps_den[i] = j * base[i];
194 fps_num[i] = (uint64_t)(lw_round( fps_den[i] * fps_sig ) * exponent);
195 if( fps_num[i] > INT32_MAX )
196 {
197 error[i] = DOUBLE_EPSILON;
198 break;
199 }
200 error[i] = fabs( ((double)fps_num[i] / fps_den[i]) / exponent - fps_sig );
201 if( error[i] < DOUBLE_EPSILON )
202 break;
203 }
204 }
205 double min_error = DOUBLE_EPSILON;
206 for( int i = 0; i < 3; i++ )
207 if( min_error > error[i] )
208 {
209 min_error = error[i];
210 reduce_fraction( &fps_num[i], &fps_den[i] );
211 *framerate_num = (int64_t)fps_num[i];
212 *framerate_den = (int64_t)fps_den[i];
213 }
214 return (min_error < DOUBLE_EPSILON);
215 #undef DOUBLE_EPSILON
216 }
217
lw_tokenize_string(char * str,char separator,char ** bufs)218 const char **lw_tokenize_string
219 (
220 char * str, /* null-terminated string: separator charactors will be replaced with '\0'. */
221 char separator, /* separator */
222 char **bufs /* If NULL, allocate memory block internally, which can be deallocated by lw_freep(). */
223 )
224 {
225 if( !str )
226 return NULL;
227 char **tokens = bufs ? bufs : (char **)malloc( 2 * sizeof(char *) );
228 if( !tokens )
229 return NULL;
230 size_t i = 1;
231 tokens[0] = str;
232 tokens[1] = NULL; /* null-terminated */
233 for( char *p = str; *p != '\0'; p++ )
234 if( *p == separator )
235 {
236 *p = '\0';
237 if( *(p + 1) != '\0' )
238 {
239 if( !bufs )
240 {
241 char **tmp = (char **)realloc( tokens, (i + 2) * sizeof(char *) );
242 if( !tmp )
243 break;
244 tokens = tmp;
245 }
246 tokens[ i] = p + 1;
247 tokens[++i] = NULL; /* null-terminated */
248 }
249 }
250 return (const char **)tokens;
251 }
252