libmodplug.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 /**
20 * @file
21 * ModPlug demuxer
22 * @todo better probing than extensions matching
23 */
24 
25 #include <libmodplug/modplug.h>
26 #include "libavutil/avstring.h"
27 #include "libavutil/eval.h"
28 #include "libavutil/opt.h"
29 #include "avformat.h"
30 #include "internal.h"
31 
32 typedef struct ModPlugContext {
33  const AVClass *class;
34  ModPlugFile *f;
35  uint8_t *buf; ///< input file content
36 
37  /* options */
45 
46  int max_size; ///< max file size to allocate
47 
48  /* optional video stream */
49  double ts_per_packet; ///< used to define the pts/dts using packet_count;
50  int packet_count; ///< total number of audio packets
51  int print_textinfo; ///< bool flag for printing speed, tempo, order, ...
52  int video_stream; ///< 1 if the user want a video stream, otherwise 0
53  int w; ///< video stream width in char (one char = 8x8px)
54  int h; ///< video stream height in char (one char = 8x8px)
55  int video_switch; ///< 1 if current packet is video, otherwise 0
56  int fsize; ///< constant frame size
57  int linesize; ///< line size in bytes
58  char *color_eval; ///< color eval user input expression
59  AVExpr *expr; ///< parsed color eval expression
61 
62 static const char *var_names[] = {
63  "x", "y",
64  "w", "h",
65  "t",
66  "speed", "tempo", "order", "pattern", "row",
67  NULL
68 };
69 
70 enum var_name {
76 };
77 
78 #define FF_MODPLUG_MAX_FILE_SIZE (100 * 1<<20) // 100M
79 #define FF_MODPLUG_DEF_FILE_SIZE ( 5 * 1<<20) // 5M
80 
81 #define OFFSET(x) offsetof(ModPlugContext, x)
82 #define D AV_OPT_FLAG_DECODING_PARAM
83 static const AVOption options[] = {
84  {"noise_reduction", "Enable noise reduction 0(off)-1(on)", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D},
85  {"reverb_depth", "Reverb level 0(quiet)-100(loud)", OFFSET(reverb_depth), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
86  {"reverb_delay", "Reverb delay in ms, usually 40-200ms", OFFSET(reverb_delay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D},
87  {"bass_amount", "XBass level 0(quiet)-100(loud)", OFFSET(bass_amount), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
88  {"bass_range", "XBass cutoff in Hz 10-100", OFFSET(bass_range), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
89  {"surround_depth", "Surround level 0(quiet)-100(heavy)", OFFSET(surround_depth), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
90  {"surround_delay", "Surround delay in ms, usually 5-40ms", OFFSET(surround_delay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D},
91  {"max_size", "Max file size supported (in bytes). Default is 5MB. Set to 0 for no limit (not recommended)",
93  {"video_stream_expr", "Color formula", OFFSET(color_eval), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D},
94  {"video_stream", "Make demuxer output a video stream", OFFSET(video_stream), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D},
95  {"video_stream_w", "Video stream width in char (one char = 8x8px)", OFFSET(w), AV_OPT_TYPE_INT, {.i64 = 30}, 20, 512, D},
96  {"video_stream_h", "Video stream height in char (one char = 8x8px)", OFFSET(h), AV_OPT_TYPE_INT, {.i64 = 30}, 20, 512, D},
97  {"video_stream_ptxt", "Print speed, tempo, order, ... in video stream", OFFSET(print_textinfo), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, D},
98  {NULL},
99 };
100 
101 #define SET_OPT_IF_REQUESTED(libopt, opt, flag) do { \
102  if (modplug->opt) { \
103  settings.libopt = modplug->opt; \
104  settings.mFlags |= flag; \
105  } \
106 } while (0)
107 
108 #define ADD_META_MULTIPLE_ENTRIES(entry_name, fname) do { \
109  if (n_## entry_name ##s) { \
110  unsigned i, n = 0; \
111  \
112  for (i = 0; i < n_## entry_name ##s; i++) { \
113  char item_name[64] = {0}; \
114  fname(f, i, item_name); \
115  if (!*item_name) \
116  continue; \
117  if (n) \
118  av_dict_set(&s->metadata, #entry_name, "\n", AV_DICT_APPEND); \
119  av_dict_set(&s->metadata, #entry_name, item_name, AV_DICT_APPEND); \
120  n++; \
121  } \
122  \
123  extra = av_asprintf(", %u/%u " #entry_name "%s", \
124  n, n_## entry_name ##s, n > 1 ? "s" : ""); \
125  if (!extra) \
126  return AVERROR(ENOMEM); \
127  av_dict_set(&s->metadata, "extra info", extra, AV_DICT_APPEND); \
128  av_free(extra); \
129  } \
130 } while (0)
131 
133 {
134  ModPlugContext *modplug = s->priv_data;
135  ModPlugFile *f = modplug->f;
136  char *extra;
137  const char *name = ModPlug_GetName(f);
138  const char *msg = ModPlug_GetMessage(f);
139 
140  unsigned n_instruments = ModPlug_NumInstruments(f);
141  unsigned n_samples = ModPlug_NumSamples(f);
142  unsigned n_patterns = ModPlug_NumPatterns(f);
143  unsigned n_channels = ModPlug_NumChannels(f);
144 
145  if (name && *name) av_dict_set(&s->metadata, "name", name, 0);
146  if (msg && *msg) av_dict_set(&s->metadata, "message", msg, 0);
147 
148  extra = av_asprintf("%u pattern%s, %u channel%s",
149  n_patterns, n_patterns > 1 ? "s" : "",
150  n_channels, n_channels > 1 ? "s" : "");
151  if (!extra)
152  return AVERROR(ENOMEM);
153  av_dict_set(&s->metadata, "extra info", extra, AV_DICT_DONT_STRDUP_VAL);
154 
155  ADD_META_MULTIPLE_ENTRIES(instrument, ModPlug_InstrumentName);
156  ADD_META_MULTIPLE_ENTRIES(sample, ModPlug_SampleName);
157 
158  return 0;
159 }
160 
161 #define AUDIO_PKT_SIZE 512
162 
164 {
165  AVStream *st;
166  AVIOContext *pb = s->pb;
167  ModPlug_Settings settings;
168  ModPlugContext *modplug = s->priv_data;
169  int sz = avio_size(pb);
170 
171  if (sz < 0) {
172  av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
173  sz = modplug->max_size;
174  } else if (modplug->max_size && sz > modplug->max_size) {
175  sz = modplug->max_size;
176  av_log(s, AV_LOG_WARNING, "Max file size reach%s, allocating %dB "
177  "but demuxing is likely to fail due to incomplete buffer\n",
178  sz == FF_MODPLUG_DEF_FILE_SIZE ? " (see -max_size)" : "", sz);
179  }
180 
181  if (modplug->color_eval) {
182  int r = av_expr_parse(&modplug->expr, modplug->color_eval, var_names,
183  NULL, NULL, NULL, NULL, 0, s);
184  if (r < 0)
185  return r;
186  }
187 
188  modplug->buf = av_malloc(modplug->max_size);
189  if (!modplug->buf)
190  return AVERROR(ENOMEM);
191  sz = avio_read(pb, modplug->buf, sz);
192 
193  ModPlug_GetSettings(&settings);
194  settings.mChannels = 2;
195  settings.mBits = 16;
196  settings.mFrequency = 44100;
197  settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; // best quality
198  settings.mLoopCount = 0; // prevents looping forever
199 
200  if (modplug->noise_reduction) settings.mFlags |= MODPLUG_ENABLE_NOISE_REDUCTION;
201  SET_OPT_IF_REQUESTED(mReverbDepth, reverb_depth, MODPLUG_ENABLE_REVERB);
202  SET_OPT_IF_REQUESTED(mReverbDelay, reverb_delay, MODPLUG_ENABLE_REVERB);
203  SET_OPT_IF_REQUESTED(mBassAmount, bass_amount, MODPLUG_ENABLE_MEGABASS);
204  SET_OPT_IF_REQUESTED(mBassRange, bass_range, MODPLUG_ENABLE_MEGABASS);
205  SET_OPT_IF_REQUESTED(mSurroundDepth, surround_depth, MODPLUG_ENABLE_SURROUND);
206  SET_OPT_IF_REQUESTED(mSurroundDelay, surround_delay, MODPLUG_ENABLE_SURROUND);
207 
208  if (modplug->reverb_depth) settings.mReverbDepth = modplug->reverb_depth;
209  if (modplug->reverb_delay) settings.mReverbDelay = modplug->reverb_delay;
210  if (modplug->bass_amount) settings.mBassAmount = modplug->bass_amount;
211  if (modplug->bass_range) settings.mBassRange = modplug->bass_range;
212  if (modplug->surround_depth) settings.mSurroundDepth = modplug->surround_depth;
213  if (modplug->surround_delay) settings.mSurroundDelay = modplug->surround_delay;
214 
215  ModPlug_SetSettings(&settings);
216 
217  modplug->f = ModPlug_Load(modplug->buf, sz);
218  if (!modplug->f)
219  return AVERROR_INVALIDDATA;
220 
221  st = avformat_new_stream(s, NULL);
222  if (!st)
223  return AVERROR(ENOMEM);
224  avpriv_set_pts_info(st, 64, 1, 1000);
225  st->duration = ModPlug_GetLength(modplug->f);
228  st->codec->channels = settings.mChannels;
229  st->codec->sample_rate = settings.mFrequency;
230 
231  // timebase = 1/1000, 2ch 16bits 44.1kHz-> 2*2*44100
232  modplug->ts_per_packet = 1000*AUDIO_PKT_SIZE / (4*44100.);
233 
234  if (modplug->video_stream) {
235  AVStream *vst = avformat_new_stream(s, NULL);
236  if (!vst)
237  return AVERROR(ENOMEM);
238  avpriv_set_pts_info(vst, 64, 1, 1000);
239  vst->duration = st->duration;
242  vst->codec->width = modplug->w << 3;
243  vst->codec->height = modplug->h << 3;
244  modplug->linesize = modplug->w * 3;
245  modplug->fsize = modplug->linesize * modplug->h;
246  }
247 
248  return modplug_load_metadata(s);
249 }
250 
251 static void write_text(uint8_t *dst, const char *s, int linesize, int x, int y)
252 {
253  int i;
254  dst += y*linesize + x*3;
255  for (i = 0; s[i]; i++, dst += 3) {
256  dst[0] = 0x0; // count - 1
257  dst[1] = s[i]; // char
258  dst[2] = 0x0f; // background / foreground
259  }
260 }
261 
262 #define PRINT_INFO(line, name, idvalue) do { \
263  snprintf(intbuf, sizeof(intbuf), "%.0f", var_values[idvalue]); \
264  write_text(pkt->data, name ":", modplug->linesize, 0+1, line+1); \
265  write_text(pkt->data, intbuf, modplug->linesize, 10+1, line+1); \
266 } while (0)
267 
269 {
270  ModPlugContext *modplug = s->priv_data;
271 
272  if (modplug->video_stream) {
273  modplug->video_switch ^= 1; // one video packet for one audio packet
274  if (modplug->video_switch) {
275  double var_values[VAR_VARS_NB];
276 
277  var_values[VAR_W ] = modplug->w;
278  var_values[VAR_H ] = modplug->h;
279  var_values[VAR_TIME ] = modplug->packet_count * modplug->ts_per_packet;
280  var_values[VAR_SPEED ] = ModPlug_GetCurrentSpeed (modplug->f);
281  var_values[VAR_TEMPO ] = ModPlug_GetCurrentTempo (modplug->f);
282  var_values[VAR_ORDER ] = ModPlug_GetCurrentOrder (modplug->f);
283  var_values[VAR_PATTERN] = ModPlug_GetCurrentPattern(modplug->f);
284  var_values[VAR_ROW ] = ModPlug_GetCurrentRow (modplug->f);
285 
286  if (av_new_packet(pkt, modplug->fsize) < 0)
287  return AVERROR(ENOMEM);
288  pkt->stream_index = 1;
289  memset(pkt->data, 0, modplug->fsize);
290 
291  if (modplug->print_textinfo) {
292  char intbuf[32];
293  PRINT_INFO(0, "speed", VAR_SPEED);
294  PRINT_INFO(1, "tempo", VAR_TEMPO);
295  PRINT_INFO(2, "order", VAR_ORDER);
296  PRINT_INFO(3, "pattern", VAR_PATTERN);
297  PRINT_INFO(4, "row", VAR_ROW);
298  PRINT_INFO(5, "ts", VAR_TIME);
299  }
300 
301  if (modplug->expr) {
302  int x, y;
303  for (y = 0; y < modplug->h; y++) {
304  for (x = 0; x < modplug->w; x++) {
305  double color;
306  var_values[VAR_X] = x;
307  var_values[VAR_Y] = y;
308  color = av_expr_eval(modplug->expr, var_values, NULL);
309  pkt->data[y*modplug->linesize + x*3 + 2] |= av_clip((int)color, 0, 0xf)<<4;
310  }
311  }
312  }
313  pkt->pts = pkt->dts = var_values[VAR_TIME];
314  pkt->flags |= AV_PKT_FLAG_KEY;
315  return 0;
316  }
317  }
318 
319  if (av_new_packet(pkt, AUDIO_PKT_SIZE) < 0)
320  return AVERROR(ENOMEM);
321 
322  if (modplug->video_stream)
323  pkt->pts = pkt->dts = modplug->packet_count++ * modplug->ts_per_packet;
324 
325  pkt->size = ModPlug_Read(modplug->f, pkt->data, AUDIO_PKT_SIZE);
326  if (pkt->size <= 0) {
327  av_free_packet(pkt);
328  return pkt->size == 0 ? AVERROR_EOF : AVERROR(EIO);
329  }
330  return 0;
331 }
332 
334 {
335  ModPlugContext *modplug = s->priv_data;
336  ModPlug_Unload(modplug->f);
337  av_freep(&modplug->buf);
338  return 0;
339 }
340 
341 static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
342 {
343  ModPlugContext *modplug = s->priv_data;
344  ModPlug_Seek(modplug->f, (int)ts);
345  if (modplug->video_stream)
346  modplug->packet_count = ts / modplug->ts_per_packet;
347  return 0;
348 }
349 
350 static const AVClass modplug_class = {
351  .class_name = "ModPlug demuxer",
352  .item_name = av_default_item_name,
353  .option = options,
354  .version = LIBAVUTIL_VERSION_INT,
355 };
356 
358  .name = "libmodplug",
359  .long_name = NULL_IF_CONFIG_SMALL("ModPlug demuxer"),
360  .priv_data_size = sizeof(ModPlugContext),
365  .extensions = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm"
366  ",itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz", // compressed mods
367  .priv_class = &modplug_class,
368 };
const char * name
Definition: avisynth_c.h:675
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define FF_MODPLUG_DEF_FILE_SIZE
Definition: libmodplug.c:79
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:261
void av_free_packet(AVPacket *pkt)
Free a packet.
Definition: avpacket.c:242
int h
video stream height in char (one char = 8x8px)
Definition: libmodplug.c:54
AVOption.
Definition: opt.h:251
int linesize
line size in bytes
Definition: libmodplug.c:57
int fsize
constant frame size
Definition: libmodplug.c:56
av_default_item_name
static int modplug_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: libmodplug.c:268
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags)
Definition: libcdio.c:153
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:640
#define sample
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
Format I/O context.
Definition: avformat.h:944
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:55
AVInputFormat ff_libmodplug_demuxer
Definition: libmodplug.c:357
uint8_t
AVOptions.
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:77
static const char * var_names[]
Definition: libmodplug.c:62
static AVPacket pkt
Definition: demuxing.c:56
int packet_count
total number of audio packets
Definition: libmodplug.c:50
Definition: eval.c:140
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
uint8_t * data
#define AVERROR_EOF
End of file.
Definition: error.h:55
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
struct ModPlugContext ModPlugContext
static const AVOption options[]
Definition: libmodplug.c:83
int video_stream
1 if the user want a video stream, otherwise 0
Definition: libmodplug.c:52
#define SET_OPT_IF_REQUESTED(libopt, opt, flag)
Definition: libmodplug.c:101
static int modplug_load_metadata(AVFormatContext *s)
Definition: libmodplug.c:132
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:478
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Discrete Time axis x
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:73
int print_textinfo
bool flag for printing speed, tempo, order, ...
Definition: libmodplug.c:51
AVDictionary * metadata
Definition: avformat.h:1092
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
const char * r
Definition: vf_curves.c:94
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
int surround_delay
Definition: libmodplug.c:44
int flags
A combination of AV_PKT_FLAG values.
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:112
static const AVClass modplug_class
Definition: libmodplug.c:350
uint8_t * buf
input file content
Definition: libmodplug.c:35
#define FF_MODPLUG_MAX_FILE_SIZE
Definition: libmodplug.c:78
AVExpr * expr
parsed color eval expression
Definition: libmodplug.c:59
var_name
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that&#39;s been allocated with av_malloc() and chilren.
Definition: dict.h:72
int width
picture width / height.
char * color_eval
color eval user input expression
Definition: libmodplug.c:58
#define D
Definition: libmodplug.c:82
static int modplug_read_header(AVFormatContext *s)
Definition: libmodplug.c:163
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:517
int video_switch
1 if current packet is video, otherwise 0
Definition: libmodplug.c:55
Stream structure.
Definition: avformat.h:643
NULL
Definition: eval.c:55
enum AVMediaType codec_type
int noise_reduction
Definition: libmodplug.c:38
enum AVCodecID codec_id
static void write_text(uint8_t *dst, const char *s, int linesize, int x, int y)
Definition: libmodplug.c:251
int sample_rate
samples per second
AVIOContext * pb
I/O context.
Definition: avformat.h:977
int max_size
max file size to allocate
Definition: libmodplug.c:46
static int read_packet(AVFormatContext *ctx, AVPacket *pkt)
Definition: libcdio.c:114
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:62
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
Describe the class of an AVClass context structure.
Definition: log.h:50
synthesis window for stochastic i
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
int w
video stream width in char (one char = 8x8px)
Definition: libmodplug.c:53
ModPlugFile * f
Definition: libmodplug.c:34
static int flags
Definition: cpu.c:23
#define PRINT_INFO(line, name, idvalue)
Definition: libmodplug.c:262
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition: avformat.h:696
Main libavformat public API header.
int surround_depth
Definition: libmodplug.c:43
function y
Definition: D.m:1
double ts_per_packet
used to define the pts/dts using packet_count;
Definition: libmodplug.c:49
#define AUDIO_PKT_SIZE
Definition: libmodplug.c:161
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:691
int channels
number of audio channels
else dst[i][x+y *dst_stride[i]]
Definition: vf_mcdeint.c:160
void * priv_data
Format private data.
Definition: avformat.h:964
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
static int modplug_read_close(AVFormatContext *s)
Definition: libmodplug.c:333
#define OFFSET(x)
Definition: libmodplug.c:81
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:461
#define ADD_META_MULTIPLE_ENTRIES(entry_name, fname)
Definition: libmodplug.c:108
This structure stores compressed data.
static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
Definition: libmodplug.c:341
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
simple arithmetic expression evaluator