mediautil.c (7219B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2026 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file plugins/mediautil.c 22 * @brief helpers shared by the video thumbnail and audio preview plugins 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "mediautil.h" 27 #include <magic.h> 28 29 /** 30 * How many bytes we give libmagic to make up its mind. 31 */ 32 #define SNIFF_SIZE (16 * 1024) 33 34 35 void 36 EXTRACTOR_media_options_parse_ (const char *config, 37 struct EXTRACTOR_MediaOptions *opt) 38 { 39 const char *pos; 40 41 opt->size = 128; 42 opt->png = 0; 43 opt->offset = 30; 44 opt->length = 15; 45 opt->bitrate = 24000; 46 opt->deadline = 10000; 47 if (NULL == config) 48 return; 49 pos = config; 50 while ('\0' != *pos) 51 { 52 unsigned long long v; 53 char *endp; 54 55 if (0 == strncmp (pos, 56 "format=", 57 strlen ("format="))) 58 { 59 pos += strlen ("format="); 60 opt->png = (0 == strncmp (pos, 61 "png", 62 strlen ("png"))); 63 } 64 else if (0 == strncmp (pos, 65 "size=", 66 strlen ("size="))) 67 { 68 pos += strlen ("size="); 69 v = strtoull (pos, &endp, 10); 70 if ( (endp != pos) && 71 (v >= 8) && 72 (v <= 1024) ) 73 opt->size = (unsigned int) v; 74 } 75 else if (0 == strncmp (pos, 76 "offset=", 77 strlen ("offset="))) 78 { 79 pos += strlen ("offset="); 80 v = strtoull (pos, &endp, 10); 81 if ( (endp != pos) && 82 (v <= 24 * 60 * 60) ) 83 opt->offset = (unsigned int) v; 84 } 85 else if (0 == strncmp (pos, 86 "length=", 87 strlen ("length="))) 88 { 89 pos += strlen ("length="); 90 v = strtoull (pos, &endp, 10); 91 if ( (endp != pos) && 92 (v >= 1) && 93 (v <= 60) ) 94 opt->length = (unsigned int) v; 95 } 96 else if (0 == strncmp (pos, 97 "bitrate=", 98 strlen ("bitrate="))) 99 { 100 pos += strlen ("bitrate="); 101 v = strtoull (pos, &endp, 10); 102 if ( (endp != pos) && 103 (v >= 6000) && 104 (v <= 128000) ) 105 opt->bitrate = (unsigned int) v; 106 } 107 else if (0 == strncmp (pos, 108 "deadline=", 109 strlen ("deadline="))) 110 { 111 pos += strlen ("deadline="); 112 v = strtoull (pos, &endp, 10); 113 if ( (endp != pos) && 114 (v >= 100) && 115 (v <= 120000) ) 116 opt->deadline = (unsigned int) v; 117 } 118 /* advance to the next assignment */ 119 pos = strchr (pos, ','); 120 if (NULL == pos) 121 break; 122 pos++; 123 } 124 } 125 126 127 int 128 EXTRACTOR_media_is_media_ (struct EXTRACTOR_ExtractContext *ec, 129 int want_audio) 130 { 131 magic_t magic; 132 void *data; 133 ssize_t iret; 134 const char *mime; 135 int ret; 136 137 if (-1 == (iret = ec->read (ec->cls, 138 &data, 139 SNIFF_SIZE))) 140 return 0; 141 ret = 0; 142 if (NULL == (magic = magic_open (MAGIC_MIME_TYPE))) 143 return 0; 144 if (0 == magic_load (magic, NULL)) 145 { 146 mime = magic_buffer (magic, 147 data, 148 iret); 149 if (NULL != mime) 150 { 151 if (0 == strncmp (mime, 152 "video/", 153 strlen ("video/"))) 154 ret = 1; 155 if ( (0 != want_audio) && 156 (0 == strncmp (mime, 157 "audio/", 158 strlen ("audio/"))) ) 159 ret = 1; 160 /* Ogg and Matroska files carrying video are frequently reported as 161 "application/ogg" or "video/x-matroska"; the former would be lost 162 here, so let it through and let the demuxer decide. */ 163 if (0 == strcmp (mime, 164 "application/ogg")) 165 ret = 1; 166 } 167 } 168 magic_close (magic); 169 if (0 != ec->seek (ec->cls, 170 0, 171 SEEK_SET)) 172 return 0; 173 return ret; 174 } 175 176 177 /** 178 * Current time in milliseconds since an arbitrary epoch. 179 * 180 * @return the time 181 */ 182 static uint64_t 183 now_ms (void) 184 { 185 struct timespec ts; 186 187 if (0 != clock_gettime (CLOCK_MONOTONIC, 188 &ts)) 189 return 0; 190 return ((uint64_t) ts.tv_sec) * 1000ULL 191 + ((uint64_t) ts.tv_nsec) / 1000000ULL; 192 } 193 194 195 void 196 EXTRACTOR_media_deadline_start_ (struct EXTRACTOR_MediaDeadline *dl, 197 unsigned int ms) 198 { 199 dl->expiration = now_ms () + ms; 200 } 201 202 203 int 204 EXTRACTOR_media_deadline_expired_ (const struct EXTRACTOR_MediaDeadline *dl) 205 { 206 return now_ms () >= dl->expiration; 207 } 208 209 210 uint64_t 211 EXTRACTOR_media_deadline_remaining_ (const struct EXTRACTOR_MediaDeadline *dl) 212 { 213 uint64_t now = now_ms (); 214 215 if (now >= dl->expiration) 216 return 0; 217 return dl->expiration - now; 218 } 219 220 221 int 222 EXTRACTOR_media_thumbnail_size_ (unsigned int width, 223 unsigned int height, 224 unsigned int box, 225 unsigned int *rwidth, 226 unsigned int *rheight) 227 { 228 uint64_t w = width; 229 uint64_t h = height; 230 231 if ( (0 == width) || 232 (0 == height) || 233 (width > EXTRACTOR_MEDIA_MAX_DIMENSION) || 234 (height > EXTRACTOR_MEDIA_MAX_DIMENSION) || 235 (((uint64_t) width) * height > EXTRACTOR_MEDIA_MAX_PIXELS) ) 236 return 0; 237 if (h > box) 238 { 239 w = w * box / h; 240 h = box; 241 } 242 if (w > box) 243 { 244 h = h * box / w; 245 w = box; 246 } 247 if ( (0 == w) || 248 (0 == h) ) 249 return 0; 250 /* many encoders dislike odd dimensions, and we lose nothing by rounding */ 251 w &= ~1ULL; 252 h &= ~1ULL; 253 if ( (0 == w) || 254 (0 == h) ) 255 return 0; 256 *rwidth = (unsigned int) w; 257 *rheight = (unsigned int) h; 258 return 1; 259 } 260 261 262 void 263 EXTRACTOR_media_fade_s16_ (int16_t *samples, 264 size_t num_samples, 265 size_t fade_samples) 266 { 267 size_t i; 268 269 if (0 == fade_samples) 270 return; 271 if (fade_samples * 2 > num_samples) 272 fade_samples = num_samples / 2; 273 for (i = 0; i < fade_samples; i++) 274 { 275 samples[i] = (int16_t) (((int32_t) samples[i]) * (int32_t) i 276 / (int32_t) fade_samples); 277 samples[num_samples - 1 - i] = 278 (int16_t) (((int32_t) samples[num_samples - 1 - i]) * (int32_t) i 279 / (int32_t) fade_samples); 280 } 281 } 282 283 284 /* end of mediautil.c */