mediautil.h (11080B)
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.h 22 * @brief helpers shared by the video thumbnail and audio preview plugins 23 * @author Christian Grothoff 24 * 25 * The four media plugins (thumbnailffmpeg, thumbnailgst, previewopus and 26 * previewgst) all have to do the same three boring things before they can 27 * get to work: parse the plugin option string, make sure the input even 28 * looks like media, and keep an eye on the clock. This file is compiled 29 * into each of them (plugins are modules and must not depend on each 30 * other, so this is deliberately a source-level, not a library-level, 31 * dependency). 32 */ 33 #ifndef MEDIAUTIL_H 34 #define MEDIAUTIL_H 35 36 #include "extractor.h" 37 38 /** 39 * Maximum number of bytes we are willing to emit for a thumbnail. 40 */ 41 #define EXTRACTOR_MEDIA_MAX_THUMBNAIL (100 * 1024) 42 43 /** 44 * Maximum number of bytes we are willing to emit for an audio preview. 45 */ 46 #define EXTRACTOR_MEDIA_MAX_PREVIEW (64 * 1024) 47 48 /** 49 * Largest image we are willing to scale down, in pixels. Guards against 50 * absurd dimensions in a hostile file header. 51 */ 52 #define EXTRACTOR_MEDIA_MAX_PIXELS (64 * 1024 * 1024) 53 54 /** 55 * Largest width or height we accept for the source video. 56 */ 57 #define EXTRACTOR_MEDIA_MAX_DIMENSION 16384 58 59 60 /** 61 * Options a media plugin understands, as given in the plugin 62 * configuration string, i.e. "thumbnailffmpeg(size=256,format=png)". 63 */ 64 struct EXTRACTOR_MediaOptions 65 { 66 /** 67 * Edge length of the box the thumbnail must fit into, in pixels. 68 */ 69 unsigned int size; 70 71 /** 72 * Emit PNG instead of JPEG (option "format=png"). 73 */ 74 int png; 75 76 /** 77 * How many seconds into the media we would like to sample. 78 */ 79 unsigned int offset; 80 81 /** 82 * Length of the audio preview in seconds. 83 */ 84 unsigned int length; 85 86 /** 87 * Target bitrate of the Opus encoder, in bits per second. 88 */ 89 unsigned int bitrate; 90 91 /** 92 * Wall clock budget for the entire extraction, in milliseconds. 93 */ 94 unsigned int deadline; 95 96 /** 97 * Language of the subtitle track to dump as SRT (option "srt:LANG"), 98 * empty string if no subtitle dump was requested. 99 */ 100 char srt_lang[16]; 101 102 /** 103 * Number of tiles in the thumbnail gallery (option "gallery:N"), 104 * 0 for a plain single thumbnail. 105 */ 106 unsigned int gallery; 107 }; 108 109 110 /** 111 * Largest number of tiles in a gallery. 112 */ 113 #define EXTRACTOR_MEDIA_MAX_GALLERY 100 114 115 /** 116 * Largest gallery sheet in pixels. Far below #EXTRACTOR_MEDIA_MAX_PIXELS: 117 * the sheet is encoded in one uninterruptible call, and a larger one 118 * cannot be squeezed into #EXTRACTOR_MEDIA_MAX_GALLERY_BYTES anyway. 119 * Tiles are scaled down to fit. 120 */ 121 #define EXTRACTOR_MEDIA_MAX_GALLERY_PIXELS (4 * 1024 * 1024) 122 123 /** 124 * Maximum number of bytes we are willing to emit for a gallery. 125 */ 126 #define EXTRACTOR_MEDIA_MAX_GALLERY_BYTES (4 * 1024 * 1024) 127 128 /** 129 * Maximum number of bytes we are willing to emit for an SRT dump. 130 */ 131 #define EXTRACTOR_MEDIA_MAX_SRT (8 * 1024 * 1024) 132 133 134 /** 135 * Check whether the language tag @a have of a stream matches the 136 * language @a want requested by the user. Both may be ISO 639-1 137 * ("de"), ISO 639-2/B ("ger") or ISO 639-2/T ("deu"), optionally with 138 * a region ("de-AT", "de_AT"); comparison ignores case. 139 * 140 * @param want requested language 141 * @param have language tag of the stream, may be NULL 142 * @return 1 if they denote the same language, 0 if not 143 */ 144 int 145 EXTRACTOR_media_lang_matches_ (const char *want, 146 const char *have); 147 148 149 /** 150 * Check whether a frame shows basically nothing: at least 99% of its 151 * pixels fall into a narrow color range in every channel (e.g. almost 152 * all black, almost all white, a uniform color, a fade). 153 * 154 * @param rgb packed RGB24 pixels 155 * @param width width in pixels 156 * @param height height in pixels 157 * @param stride bytes per row 158 * @return 1 if the frame is (nearly) flat, 0 if it has content 159 */ 160 int 161 EXTRACTOR_media_frame_is_flat_ (const uint8_t *rgb, 162 unsigned int width, 163 unsigned int height, 164 size_t stride); 165 166 167 /** 168 * Choose a grid for @a n tiles of @a tile_w x @a tile_h pixels such 169 * that the entire sheet is as close to 16:9 as possible (ties are 170 * broken towards fewer empty cells). 171 * 172 * @param n number of tiles, at least 1 173 * @param tile_w width of one tile 174 * @param tile_h height of one tile 175 * @param[out] cols number of columns 176 * @param[out] rows number of rows 177 */ 178 void 179 EXTRACTOR_media_gallery_layout_ (unsigned int n, 180 unsigned int tile_w, 181 unsigned int tile_h, 182 unsigned int *cols, 183 unsigned int *rows); 184 185 186 /** 187 * Time stamp in the gallery for tile @a i of @a n: the midpoints of 188 * @a n equal slices of @a duration_ms. 189 * 190 * @param i tile index, in [0,n) 191 * @param n number of tiles 192 * @param duration_ms length of the media 193 * @return position of tile @a i in milliseconds 194 */ 195 uint64_t 196 EXTRACTOR_media_gallery_time_ (unsigned int i, 197 unsigned int n, 198 uint64_t duration_ms); 199 200 201 /** 202 * An SRT file under construction. 203 */ 204 struct EXTRACTOR_MediaSrt 205 { 206 /** 207 * The text so far. 208 */ 209 char *buf; 210 211 /** 212 * Number of bytes in @e buf. 213 */ 214 size_t len; 215 216 /** 217 * Allocated size of @e buf. 218 */ 219 size_t cap; 220 221 /** 222 * Number of cues written so far. 223 */ 224 unsigned int count; 225 226 /** 227 * 1 if we hit #EXTRACTOR_MEDIA_MAX_SRT or ran out of memory. 228 */ 229 int full; 230 }; 231 232 233 /** 234 * Append one cue to @a srt. @a text may contain ASS dialogue lines 235 * ("0,0,Default,,0,0,0,,Hello\\Nworld", as FFmpeg produces them) or 236 * plain text; ASS override tags are removed, "\\N" becomes a line 237 * break, invalid UTF-8 is replaced by '?', and empty lines inside the 238 * cue are dropped. Cues without text are ignored. 239 * 240 * @param srt file to append to 241 * @param start_ms start of the cue in milliseconds 242 * @param end_ms end of the cue in milliseconds 243 * @param text text of the cue 244 * @param text_len number of bytes in @a text 245 * @param is_ass 1 if @a text is an ASS dialogue event (fields before 246 * the text are skipped), 0 if it is plain text 247 */ 248 void 249 EXTRACTOR_media_srt_add_ (struct EXTRACTOR_MediaSrt *srt, 250 uint64_t start_ms, 251 uint64_t end_ms, 252 const char *text, 253 size_t text_len, 254 int is_ass); 255 256 257 /** 258 * Emit @a srt as #EXTRACTOR_METATYPE_SUBTITLE_TEXT (if non-empty). 259 * 260 * @param srt file to emit 261 * @param ec extraction context 262 * @param plugin_name short name of the plugin 263 * @return return value of `proc` (0 if nothing was emitted) 264 */ 265 int 266 EXTRACTOR_media_srt_emit_ (const struct EXTRACTOR_MediaSrt *srt, 267 struct EXTRACTOR_ExtractContext *ec, 268 const char *plugin_name); 269 270 271 /** 272 * Release @a srt. 273 * 274 * @param srt file to release 275 */ 276 void 277 EXTRACTOR_media_srt_clear_ (struct EXTRACTOR_MediaSrt *srt); 278 279 280 /** 281 * A wall clock deadline. 282 */ 283 struct EXTRACTOR_MediaDeadline 284 { 285 /** 286 * When we must be done, in milliseconds since some arbitrary epoch. 287 */ 288 uint64_t expiration; 289 }; 290 291 292 /** 293 * Initialize @a opt with the defaults, then apply the comma-separated 294 * "key=value" assignments from @a config. Unknown keys and malformed 295 * values are ignored; the resulting values are always in range. 296 * 297 * @param config configuration string of the plugin, may be NULL 298 * @param[out] opt set to the resulting options 299 */ 300 void 301 EXTRACTOR_media_options_parse_ (const char *config, 302 struct EXTRACTOR_MediaOptions *opt); 303 304 305 /** 306 * Check whether the input of @a ec looks like media we should touch, 307 * using libmagic on the first few kilobytes. Always leaves the 308 * extraction context rewound to the beginning of the file. 309 * 310 * Handing arbitrary bytes to a media framework is expensive and grows 311 * the attack surface for no gain, so both plugin families gate on this. 312 * 313 * @param ec extraction context to inspect 314 * @param want_audio also accept "audio/*" (in addition to "video/*") 315 * @return 1 if the input should be processed, 0 if not 316 */ 317 int 318 EXTRACTOR_media_is_media_ (struct EXTRACTOR_ExtractContext *ec, 319 int want_audio); 320 321 322 /** 323 * Start the clock. 324 * 325 * @param[out] dl deadline to initialize 326 * @param ms budget in milliseconds from now 327 */ 328 void 329 EXTRACTOR_media_deadline_start_ (struct EXTRACTOR_MediaDeadline *dl, 330 unsigned int ms); 331 332 333 /** 334 * Check whether the budget is used up. 335 * 336 * @param dl deadline to check 337 * @return 1 if we are out of time 338 */ 339 int 340 EXTRACTOR_media_deadline_expired_ (const struct EXTRACTOR_MediaDeadline *dl); 341 342 343 /** 344 * Time left before @a dl expires. 345 * 346 * @param dl deadline to check 347 * @return remaining milliseconds, 0 if expired 348 */ 349 uint64_t 350 EXTRACTOR_media_deadline_remaining_ (const struct EXTRACTOR_MediaDeadline *dl); 351 352 353 /** 354 * Compute the size of a thumbnail with the aspect ratio of a 355 * @a width x @a height image that fits into a @a box x @a box square. 356 * Never scales up. 357 * 358 * @param width width of the source image 359 * @param height height of the source image 360 * @param box edge length of the target square 361 * @param[out] rwidth width of the thumbnail 362 * @param[out] rheight height of the thumbnail 363 * @return 1 on success, 0 if the source dimensions are unusable 364 */ 365 int 366 EXTRACTOR_media_thumbnail_size_ (unsigned int width, 367 unsigned int height, 368 unsigned int box, 369 unsigned int *rwidth, 370 unsigned int *rheight); 371 372 373 /** 374 * Apply a linear fade-in and fade-out to 16-bit signed mono PCM. 375 * Without this, a preview cut out of the middle of a track starts and 376 * ends with an audible click. 377 * 378 * @param[in,out] samples PCM data to modify 379 * @param num_samples number of samples in @a samples 380 * @param fade_samples length of each ramp in samples 381 */ 382 void 383 EXTRACTOR_media_fade_s16_ (int16_t *samples, 384 size_t num_samples, 385 size_t fade_samples); 386 387 #endif 388 389 /* end of mediautil.h */