FFmpeg  4.0
libopenmpt.c
Go to the documentation of this file.
1 /*
2  * Tracked MOD demuxer (libopenmpt)
3  * Copyright (c) 2016 Josh de Kock
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <libopenmpt/libopenmpt.h>
23 #include <libopenmpt/libopenmpt_stream_callbacks_file.h>
24 #include <libopenmpt/libopenmpt_version.h>
25 /* Shims to support libopenmpt < 0.3.0 (as documented by libopenmpt) */
26 #if !defined(OPENMPT_API_VERSION_MAKE)
27 #define OPENMPT_API_VERSION_MAKE(major, minor, patch) (((major)<<24)|((minor)<<16)|((patch)<<0))
28 #endif
29 #if !defined(OPENMPT_API_VERSION_AT_LEAST)
30 #define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch)))
31 #endif
32 
33 #include "libavutil/avstring.h"
34 #include "libavutil/opt.h"
35 #include "avformat.h"
36 #include "internal.h"
37 
38 typedef struct OpenMPTContext {
39  const AVClass *class;
40  openmpt_module *module;
41 
42  int channels;
43  double duration;
44  /* options */
46  int64_t layout;
47  int subsong;
49 
50 #define OFFSET(x) offsetof(OpenMPTContext, x)
51 #define A AV_OPT_FLAG_AUDIO_PARAM
52 #define D AV_OPT_FLAG_DECODING_PARAM
53 static const AVOption options[] = {
54  { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, { .i64 = 48000 }, 1000, INT_MAX, A | D },
55  { "layout", "set channel layout", OFFSET(layout), AV_OPT_TYPE_CHANNEL_LAYOUT, { .i64 = AV_CH_LAYOUT_STEREO }, 0, INT64_MAX, A | D },
56  { "subsong", "set subsong", OFFSET(subsong), AV_OPT_TYPE_INT, { .i64 = -2 }, -2, INT_MAX, A | D, "subsong"},
57  { "all", "all", 0, AV_OPT_TYPE_CONST, { .i64 = -1}, 0, 0, A | D, "subsong" },
58  { "auto", "auto", 0, AV_OPT_TYPE_CONST, { .i64 = -2}, 0, 0, A | D, "subsong" },
59  { NULL }
60 };
61 
62 static void openmpt_logfunc(const char *message, void *userdata)
63 {
64  int level = AV_LOG_INFO;
65  if (strstr(message, "ERROR") != NULL) {
66  level = AV_LOG_ERROR;
67  }
68  av_log(userdata, level, "%s\n", message);
69 }
70 
71 #define add_meta(s, name, meta) \
72 do { \
73  const char *value = meta; \
74  if (value && value[0]) \
75  av_dict_set(&s->metadata, name, value, 0); \
76  openmpt_free_string(value); \
77 } while(0)
78 
80 {
81  AVStream *st;
82  OpenMPTContext *openmpt = s->priv_data;
83  int64_t size;
84  char *buf;
85 #if OPENMPT_API_VERSION_AT_LEAST(0,3,0)
86  int error;
87 #endif
88  int ret;
89 
90  size = avio_size(s->pb);
91  if (size <= 0)
92  return AVERROR_INVALIDDATA;
93  buf = av_malloc(size);
94  if (!buf)
95  return AVERROR(ENOMEM);
96  size = avio_read(s->pb, buf, size);
97  if (size < 0) {
98  av_log(s, AV_LOG_ERROR, "Reading input buffer failed.\n");
99  av_freep(&buf);
100  return size;
101  }
102 
103 #if OPENMPT_API_VERSION_AT_LEAST(0,3,0)
104  error = OPENMPT_ERROR_OK;
105  openmpt->module = openmpt_module_create_from_memory2(buf, size, openmpt_logfunc, s, NULL, NULL, &error, NULL, NULL);
106  av_freep(&buf);
107  if (!openmpt->module) {
108  if (error == OPENMPT_ERROR_OUT_OF_MEMORY)
109  return AVERROR(ENOMEM);
110  else if (error >= OPENMPT_ERROR_GENERAL)
111  return AVERROR_INVALIDDATA;
112  else
113  return AVERROR_UNKNOWN;
114  }
115 #else
116  openmpt->module = openmpt_module_create_from_memory(buf, size, openmpt_logfunc, s, NULL);
117  av_freep(&buf);
118  if (!openmpt->module)
119  return AVERROR_INVALIDDATA;
120 #endif
121 
123 
124  if (openmpt->subsong >= openmpt_module_get_num_subsongs(openmpt->module)) {
125  openmpt_module_destroy(openmpt->module);
126  av_log(s, AV_LOG_ERROR, "Invalid subsong index: %d\n", openmpt->subsong);
127  return AVERROR(EINVAL);
128  }
129 
130  if (openmpt->subsong != -2) {
131  if (openmpt->subsong >= 0) {
132  av_dict_set_int(&s->metadata, "track", openmpt->subsong + 1, 0);
133  }
134  ret = openmpt_module_select_subsong(openmpt->module, openmpt->subsong);
135  if (!ret){
136  openmpt_module_destroy(openmpt->module);
137  av_log(s, AV_LOG_ERROR, "Could not select requested subsong: %d", openmpt->subsong);
138  return AVERROR(EINVAL);
139  }
140  }
141 
142  openmpt->duration = openmpt_module_get_duration_seconds(openmpt->module);
143 
144  add_meta(s, "artist", openmpt_module_get_metadata(openmpt->module, "artist"));
145  add_meta(s, "title", openmpt_module_get_metadata(openmpt->module, "title"));
146  add_meta(s, "encoder", openmpt_module_get_metadata(openmpt->module, "tracker"));
147  add_meta(s, "comment", openmpt_module_get_metadata(openmpt->module, "message"));
148  add_meta(s, "date", openmpt_module_get_metadata(openmpt->module, "date"));
149 
150  st = avformat_new_stream(s, NULL);
151  if (!st) {
152  openmpt_module_destroy(openmpt->module);
153  openmpt->module = NULL;
154  return AVERROR(ENOMEM);
155  }
156  avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE);
157  st->duration = llrint(openmpt->duration*AV_TIME_BASE);
158 
161  st->codecpar->channels = openmpt->channels;
162  st->codecpar->sample_rate = openmpt->sample_rate;
163 
164  return 0;
165 }
166 
167 #define AUDIO_PKT_SIZE 2048
168 
170 {
171  OpenMPTContext *openmpt = s->priv_data;
172  int n_samples = AUDIO_PKT_SIZE / (openmpt->channels ? openmpt->channels*4 : 4);
173  int ret;
174 
175  if ((ret = av_new_packet(pkt, AUDIO_PKT_SIZE)) < 0)
176  return ret;
177 
178  switch (openmpt->channels) {
179  case 1:
180  ret = openmpt_module_read_float_mono(openmpt->module, openmpt->sample_rate,
181  n_samples, (float *)pkt->data);
182  break;
183  case 2:
184  ret = openmpt_module_read_interleaved_float_stereo(openmpt->module, openmpt->sample_rate,
185  n_samples, (float *)pkt->data);
186  break;
187  case 4:
188  ret = openmpt_module_read_interleaved_float_quad(openmpt->module, openmpt->sample_rate,
189  n_samples, (float *)pkt->data);
190  break;
191  default:
192  av_log(s, AV_LOG_ERROR, "Unsupported number of channels: %d", openmpt->channels);
193  return AVERROR(EINVAL);
194  }
195 
196  if (ret < 1) {
197  pkt->size = 0;
198  return AVERROR_EOF;
199  }
200 
201  pkt->size = ret * (openmpt->channels * 4);
202 
203  return 0;
204 }
205 
207 {
208  OpenMPTContext *openmpt = s->priv_data;
209  openmpt_module_destroy(openmpt->module);
210  openmpt->module = NULL;
211  return 0;
212 }
213 
214 static int read_seek_openmpt(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
215 {
216  OpenMPTContext *openmpt = s->priv_data;
217  openmpt_module_set_position_seconds(openmpt->module, (double)ts/AV_TIME_BASE);
218  return 0;
219 }
220 
222 {
223  const char *ext;
224  if (p->filename) {
225  ext = strrchr(p->filename, '.');
226  if (ext && strlen(ext + 1) > 0) {
227  ext++; /* skip '.' */
228  if (openmpt_is_extension_supported(ext) == 1)
230  }
231  }
232  return 0;
233 }
234 
236 {
237 #if OPENMPT_API_VERSION_AT_LEAST(0,3,0)
238  int probe_result;
239  if (p->buf && p->buf_size > 0) {
240  probe_result = openmpt_probe_file_header_without_filesize(
241  OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT,
242  p->buf, p->buf_size,
244  if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS) {
245  /* As probing here relies on code external to FFmpeg, do not return
246  * AVPROBE_SCORE_MAX in order to reduce the impact in the rare
247  * cases of false positives.
248  */
249  return AVPROBE_SCORE_MIME + 1;
250  } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA) {
251  if (probe_openmpt_extension(p) > 0) {
252  return AVPROBE_SCORE_RETRY;
253  } else {
254  if (p->buf_size >= openmpt_probe_file_header_get_recommended_size()) {
255  /* We have already received the recommended amount of data
256  * and still cannot decide. Return a rather low score.
257  */
258  return AVPROBE_SCORE_RETRY / 2;
259  } else {
260  /* The file extension is unknown and we have very few data
261  * bytes available. libopenmpt cannot decide anything here,
262  * and returning any score > 0 would result in successfull
263  * probing of random data.
264  */
265  return 0;
266  }
267  }
268  } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE) {
269  return 0;
270  }
271  }
272 #endif
273  /* for older libopenmpt, fall back to file extension probing */
274  return probe_openmpt_extension(p);
275 }
276 
277 static const AVClass class_openmpt = {
278  .class_name = "libopenmpt",
279  .item_name = av_default_item_name,
280  .option = options,
281  .version = LIBAVUTIL_VERSION_INT,
282 };
283 
285  .name = "libopenmpt",
286  .long_name = NULL_IF_CONFIG_SMALL("Tracker formats (libopenmpt)"),
287  .priv_data_size = sizeof(OpenMPTContext),
293  .priv_class = &class_openmpt,
295  .extensions = "669,amf,ams,dbm,digi,dmf,dsm,dtm,far,gdm,ice,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,st26,stk,stm,stp,ult,umx,wow,xm,xpk",
296 #else
297  .extensions = "669,amf,ams,dbm,digi,dmf,dsm,far,gdm,ice,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,st26,stk,stm,ult,umx,wow,xm,xpk",
298 #endif
299 };
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:768
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:336
int size
AVOption.
Definition: opt.h:246
static int probe_openmpt_extension(AVProbeData *p)
Definition: libopenmpt.c:221
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
const char * filename
Definition: avformat.h:449
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.
Definition: utils.c:4811
static int read_packet_openmpt(AVFormatContext *s, AVPacket *pkt)
Definition: libopenmpt.c:169
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags)
Definition: libcdio.c:153
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3884
int size
Definition: avcodec.h:1431
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
static int read_header_openmpt(AVFormatContext *s)
Definition: libopenmpt.c:79
static AVPacket pkt
#define AV_CH_LAYOUT_STEREO
double duration
Definition: libopenmpt.c:43
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
Return the number of channels in the channel layout.
Format I/O context.
Definition: avformat.h:1342
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:72
#define av_malloc(s)
AVOptions.
#define AVPROBE_SCORE_MIME
score for file mime type
Definition: avformat.h:459
static int read_close_openmpt(AVFormatContext *s)
Definition: libopenmpt.c:206
#define AV_NE(be, le)
Definition: common.h:50
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4441
uint8_t * data
Definition: avcodec.h:1430
#define AUDIO_PKT_SIZE
Definition: libopenmpt.c:167
static int flags
Definition: log.c:55
#define AVERROR_EOF
End of file.
Definition: error.h:55
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
static const AVClass class_openmpt
Definition: libopenmpt.c:277
#define A
Definition: libopenmpt.c:51
#define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch)
Definition: libopenmpt.c:30
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:648
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:86
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1580
#define AVERROR(e)
Definition: error.h:43
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3880
int64_t layout
Definition: libopenmpt.c:46
static const AVOption options[]
Definition: libopenmpt.c:53
#define OFFSET(x)
Definition: libopenmpt.c:50
int buf_size
Size of buf except extra allocated bytes.
Definition: avformat.h:451
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:450
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
static int read_probe(AVProbeData *pd)
Definition: jvdec.c:55
#define AVPROBE_SCORE_RETRY
Definition: avformat.h:455
static void error(const char *err)
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:530
Stream structure.
Definition: avformat.h:873
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
#define D
Definition: libopenmpt.c:52
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
AVIOContext * pb
I/O context.
Definition: avformat.h:1384
static int read_probe_openmpt(AVProbeData *p)
Definition: libopenmpt.c:235
AVInputFormat ff_libopenmpt_demuxer
Definition: libopenmpt.c:284
void * buf
Definition: avisynth_c.h:690
#define llrint(x)
Definition: libm.h:394
Describe the class of an AVClass context structure.
Definition: log.h:67
#define AVPROBE_SCORE_EXTENSION
score for file extension
Definition: avformat.h:458
This structure contains the data a format has to probe a file.
Definition: avformat.h:448
uint8_t level
Definition: svq3.c:207
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition: avformat.h:922
#define add_meta(s, name, meta)
Definition: libopenmpt.c:71
int sample_rate
Audio only.
Definition: avcodec.h:3994
Main libavformat public API header.
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set that converts the value to a string and stores it...
Definition: dict.c:147
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
void * priv_data
Format private data.
Definition: avformat.h:1370
int channels
Audio only.
Definition: avcodec.h:3990
#define av_freep(p)
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:647
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1020
static int read_seek_openmpt(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
Definition: libopenmpt.c:214
This structure stores compressed data.
Definition: avcodec.h:1407
openmpt_module * module
Definition: libopenmpt.c:40
static void openmpt_logfunc(const char *message, void *userdata)
Definition: libopenmpt.c:62