libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

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 */