00001 /* 00002 * This file is part of FFmpeg. 00003 * 00004 * FFmpeg is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * FFmpeg is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with FFmpeg; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00017 */ 00018 00025 #include <libmodplug/modplug.h> 00026 #include "libavutil/avstring.h" 00027 #include "libavutil/eval.h" 00028 #include "libavutil/opt.h" 00029 #include "avformat.h" 00030 #include "internal.h" 00031 00032 typedef struct ModPlugContext { 00033 const AVClass *class; 00034 ModPlugFile *f; 00035 uint8_t *buf; 00036 00037 /* options */ 00038 int noise_reduction; 00039 int reverb_depth; 00040 int reverb_delay; 00041 int bass_amount; 00042 int bass_range; 00043 int surround_depth; 00044 int surround_delay; 00045 00046 int max_size; 00047 00048 /* optional video stream */ 00049 double ts_per_packet; 00050 int packet_count; 00051 int print_textinfo; 00052 int video_stream; 00053 int w; 00054 int h; 00055 int video_switch; 00056 int fsize; 00057 int linesize; 00058 char *color_eval; 00059 AVExpr *expr; 00060 } ModPlugContext; 00061 00062 static const char *var_names[] = { 00063 "x", "y", 00064 "w", "h", 00065 "t", 00066 "speed", "tempo", "order", "pattern", "row", 00067 NULL 00068 }; 00069 00070 enum var_name { 00071 VAR_X, VAR_Y, 00072 VAR_W, VAR_H, 00073 VAR_TIME, 00074 VAR_SPEED, VAR_TEMPO, VAR_ORDER, VAR_PATTERN, VAR_ROW, 00075 VAR_VARS_NB 00076 }; 00077 00078 #define FF_MODPLUG_MAX_FILE_SIZE (100 * 1<<20) // 100M 00079 #define FF_MODPLUG_DEF_FILE_SIZE ( 5 * 1<<20) // 5M 00080 00081 #define OFFSET(x) offsetof(ModPlugContext, x) 00082 #define D AV_OPT_FLAG_DECODING_PARAM 00083 static const AVOption options[] = { 00084 {"noise_reduction", "Enable noise reduction 0(off)-1(on)", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, D}, 00085 {"reverb_depth", "Reverb level 0(quiet)-100(loud)", OFFSET(reverb_depth), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, 00086 {"reverb_delay", "Reverb delay in ms, usually 40-200ms", OFFSET(reverb_delay), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, D}, 00087 {"bass_amount", "XBass level 0(quiet)-100(loud)", OFFSET(bass_amount), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, 00088 {"bass_range", "XBass cutoff in Hz 10-100", OFFSET(bass_range), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, 00089 {"surround_depth", "Surround level 0(quiet)-100(heavy)", OFFSET(surround_depth), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, 00090 {"surround_delay", "Surround delay in ms, usually 5-40ms", OFFSET(surround_delay), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, D}, 00091 {"max_size", "Max file size supported (in bytes). Default is 5MB. Set to 0 for no limit (not recommended)", 00092 OFFSET(max_size), AV_OPT_TYPE_INT, {.dbl = FF_MODPLUG_DEF_FILE_SIZE}, 0, FF_MODPLUG_MAX_FILE_SIZE, D}, 00093 {"video_stream_expr", "Color formula", OFFSET(color_eval), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D}, 00094 {"video_stream", "Make demuxer output a video stream", OFFSET(video_stream), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, D}, 00095 {"video_stream_w", "Video stream width in char (one char = 8x8px)", OFFSET(w), AV_OPT_TYPE_INT, {.dbl = 30}, 20, 512, D}, 00096 {"video_stream_h", "Video stream height in char (one char = 8x8px)", OFFSET(h), AV_OPT_TYPE_INT, {.dbl = 30}, 20, 512, D}, 00097 {"video_stream_ptxt", "Print speed, tempo, order, ... in video stream", OFFSET(print_textinfo), AV_OPT_TYPE_INT, {.dbl = 1}, 0, 1, D}, 00098 {NULL}, 00099 }; 00100 00101 #define SET_OPT_IF_REQUESTED(libopt, opt, flag) do { \ 00102 if (modplug->opt) { \ 00103 settings.libopt = modplug->opt; \ 00104 settings.mFlags |= flag; \ 00105 } \ 00106 } while (0) 00107 00108 #define ADD_META_MULTIPLE_ENTRIES(entry_name, fname) do { \ 00109 if (n_## entry_name ##s) { \ 00110 unsigned i, n = 0; \ 00111 \ 00112 for (i = 0; i < n_## entry_name ##s; i++) { \ 00113 char item_name[64] = {0}; \ 00114 fname(f, i, item_name); \ 00115 if (!*item_name) \ 00116 continue; \ 00117 if (n) \ 00118 av_dict_set(&s->metadata, #entry_name, "\n", AV_DICT_APPEND); \ 00119 av_dict_set(&s->metadata, #entry_name, item_name, AV_DICT_APPEND); \ 00120 n++; \ 00121 } \ 00122 \ 00123 extra = av_asprintf(", %u/%u " #entry_name "%s", \ 00124 n, n_## entry_name ##s, n > 1 ? "s" : ""); \ 00125 if (!extra) \ 00126 return AVERROR(ENOMEM); \ 00127 av_dict_set(&s->metadata, "extra info", extra, AV_DICT_APPEND); \ 00128 av_free(extra); \ 00129 } \ 00130 } while (0) 00131 00132 static int modplug_load_metadata(AVFormatContext *s) 00133 { 00134 ModPlugContext *modplug = s->priv_data; 00135 ModPlugFile *f = modplug->f; 00136 char *extra; 00137 const char *name = ModPlug_GetName(f); 00138 const char *msg = ModPlug_GetMessage(f); 00139 00140 unsigned n_instruments = ModPlug_NumInstruments(f); 00141 unsigned n_samples = ModPlug_NumSamples(f); 00142 unsigned n_patterns = ModPlug_NumPatterns(f); 00143 unsigned n_channels = ModPlug_NumChannels(f); 00144 00145 if (name && *name) av_dict_set(&s->metadata, "name", name, 0); 00146 if (msg && *msg) av_dict_set(&s->metadata, "message", msg, 0); 00147 00148 extra = av_asprintf("%u pattern%s, %u channel%s", 00149 n_patterns, n_patterns > 1 ? "s" : "", 00150 n_channels, n_channels > 1 ? "s" : ""); 00151 if (!extra) 00152 return AVERROR(ENOMEM); 00153 av_dict_set(&s->metadata, "extra info", extra, AV_DICT_DONT_STRDUP_VAL); 00154 00155 ADD_META_MULTIPLE_ENTRIES(instrument, ModPlug_InstrumentName); 00156 ADD_META_MULTIPLE_ENTRIES(sample, ModPlug_SampleName); 00157 00158 return 0; 00159 } 00160 00161 #define AUDIO_PKT_SIZE 512 00162 00163 static int modplug_read_header(AVFormatContext *s, AVFormatParameters *ap) 00164 { 00165 AVStream *st; 00166 AVIOContext *pb = s->pb; 00167 ModPlug_Settings settings; 00168 ModPlugContext *modplug = s->priv_data; 00169 int sz = avio_size(pb); 00170 00171 if (sz < 0) { 00172 av_log(s, AV_LOG_WARNING, "Could not determine file size\n"); 00173 sz = modplug->max_size; 00174 } else if (modplug->max_size && sz > modplug->max_size) { 00175 sz = modplug->max_size; 00176 av_log(s, AV_LOG_WARNING, "Max file size reach%s, allocating %dB " 00177 "but demuxing is likely to fail due to incomplete buffer\n", 00178 sz == FF_MODPLUG_DEF_FILE_SIZE ? " (see -max_size)" : "", sz); 00179 } 00180 00181 if (modplug->color_eval) { 00182 int r = av_expr_parse(&modplug->expr, modplug->color_eval, var_names, 00183 NULL, NULL, NULL, NULL, 0, s); 00184 if (r < 0) 00185 return r; 00186 } 00187 00188 modplug->buf = av_malloc(modplug->max_size); 00189 if (!modplug->buf) 00190 return AVERROR(ENOMEM); 00191 sz = avio_read(pb, modplug->buf, sz); 00192 00193 ModPlug_GetSettings(&settings); 00194 settings.mChannels = 2; 00195 settings.mBits = 16; 00196 settings.mFrequency = 44100; 00197 settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; // best quality 00198 settings.mLoopCount = 0; // prevents looping forever 00199 00200 if (modplug->noise_reduction) settings.mFlags |= MODPLUG_ENABLE_NOISE_REDUCTION; 00201 SET_OPT_IF_REQUESTED(mReverbDepth, reverb_depth, MODPLUG_ENABLE_REVERB); 00202 SET_OPT_IF_REQUESTED(mReverbDelay, reverb_delay, MODPLUG_ENABLE_REVERB); 00203 SET_OPT_IF_REQUESTED(mBassAmount, bass_amount, MODPLUG_ENABLE_MEGABASS); 00204 SET_OPT_IF_REQUESTED(mBassRange, bass_range, MODPLUG_ENABLE_MEGABASS); 00205 SET_OPT_IF_REQUESTED(mSurroundDepth, surround_depth, MODPLUG_ENABLE_SURROUND); 00206 SET_OPT_IF_REQUESTED(mSurroundDelay, surround_delay, MODPLUG_ENABLE_SURROUND); 00207 00208 if (modplug->reverb_depth) settings.mReverbDepth = modplug->reverb_depth; 00209 if (modplug->reverb_delay) settings.mReverbDelay = modplug->reverb_delay; 00210 if (modplug->bass_amount) settings.mBassAmount = modplug->bass_amount; 00211 if (modplug->bass_range) settings.mBassRange = modplug->bass_range; 00212 if (modplug->surround_depth) settings.mSurroundDepth = modplug->surround_depth; 00213 if (modplug->surround_delay) settings.mSurroundDelay = modplug->surround_delay; 00214 00215 ModPlug_SetSettings(&settings); 00216 00217 modplug->f = ModPlug_Load(modplug->buf, sz); 00218 if (!modplug->f) 00219 return AVERROR_INVALIDDATA; 00220 00221 st = avformat_new_stream(s, NULL); 00222 if (!st) 00223 return AVERROR(ENOMEM); 00224 avpriv_set_pts_info(st, 64, 1, 1000); 00225 st->duration = ModPlug_GetLength(modplug->f); 00226 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00227 st->codec->codec_id = CODEC_ID_PCM_S16LE; 00228 st->codec->channels = settings.mChannels; 00229 st->codec->sample_rate = settings.mFrequency; 00230 00231 // timebase = 1/1000, 2ch 16bits 44.1kHz-> 2*2*44100 00232 modplug->ts_per_packet = 1000*AUDIO_PKT_SIZE / (4*44100.); 00233 00234 if (modplug->video_stream) { 00235 AVStream *vst = avformat_new_stream(s, NULL); 00236 if (!vst) 00237 return AVERROR(ENOMEM); 00238 avpriv_set_pts_info(vst, 64, 1, 1000); 00239 vst->duration = st->duration; 00240 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00241 vst->codec->codec_id = CODEC_ID_XBIN; 00242 vst->codec->width = modplug->w << 3; 00243 vst->codec->height = modplug->h << 3; 00244 modplug->linesize = modplug->w * 3; 00245 modplug->fsize = modplug->linesize * modplug->h; 00246 } 00247 00248 return modplug_load_metadata(s); 00249 } 00250 00251 static void write_text(uint8_t *dst, const char *s, int linesize, int x, int y) 00252 { 00253 int i; 00254 dst += y*linesize + x*3; 00255 for (i = 0; s[i]; i++, dst += 3) { 00256 dst[0] = 0x0; // count - 1 00257 dst[1] = s[i]; // char 00258 dst[2] = 0x0f; // background / foreground 00259 } 00260 } 00261 00262 #define PRINT_INFO(line, name, idvalue) do { \ 00263 snprintf(intbuf, sizeof(intbuf), "%.0f", var_values[idvalue]); \ 00264 write_text(pkt->data, name ":", modplug->linesize, 0+1, line+1); \ 00265 write_text(pkt->data, intbuf, modplug->linesize, 10+1, line+1); \ 00266 } while (0) 00267 00268 static int modplug_read_packet(AVFormatContext *s, AVPacket *pkt) 00269 { 00270 ModPlugContext *modplug = s->priv_data; 00271 00272 if (modplug->video_stream) { 00273 modplug->video_switch ^= 1; // one video packet for one audio packet 00274 if (modplug->video_switch) { 00275 double var_values[VAR_VARS_NB]; 00276 00277 var_values[VAR_W ] = modplug->w; 00278 var_values[VAR_H ] = modplug->h; 00279 var_values[VAR_TIME ] = modplug->packet_count * modplug->ts_per_packet; 00280 var_values[VAR_SPEED ] = ModPlug_GetCurrentSpeed (modplug->f); 00281 var_values[VAR_TEMPO ] = ModPlug_GetCurrentTempo (modplug->f); 00282 var_values[VAR_ORDER ] = ModPlug_GetCurrentOrder (modplug->f); 00283 var_values[VAR_PATTERN] = ModPlug_GetCurrentPattern(modplug->f); 00284 var_values[VAR_ROW ] = ModPlug_GetCurrentRow (modplug->f); 00285 00286 if (av_new_packet(pkt, modplug->fsize) < 0) 00287 return AVERROR(ENOMEM); 00288 pkt->stream_index = 1; 00289 memset(pkt->data, 0, modplug->fsize); 00290 00291 if (modplug->print_textinfo) { 00292 char intbuf[32]; 00293 PRINT_INFO(0, "speed", VAR_SPEED); 00294 PRINT_INFO(1, "tempo", VAR_TEMPO); 00295 PRINT_INFO(2, "order", VAR_ORDER); 00296 PRINT_INFO(3, "pattern", VAR_PATTERN); 00297 PRINT_INFO(4, "row", VAR_ROW); 00298 PRINT_INFO(5, "ts", VAR_TIME); 00299 } 00300 00301 if (modplug->expr) { 00302 int x, y; 00303 for (y = 0; y < modplug->h; y++) { 00304 for (x = 0; x < modplug->w; x++) { 00305 double color; 00306 var_values[VAR_X] = x; 00307 var_values[VAR_Y] = y; 00308 color = av_expr_eval(modplug->expr, var_values, NULL); 00309 pkt->data[y*modplug->linesize + x*3 + 2] |= av_clip((int)color, 0, 0xf)<<4; 00310 } 00311 } 00312 } 00313 pkt->pts = pkt->dts = var_values[VAR_TIME]; 00314 pkt->flags |= AV_PKT_FLAG_KEY; 00315 return 0; 00316 } 00317 } 00318 00319 if (av_new_packet(pkt, AUDIO_PKT_SIZE) < 0) 00320 return AVERROR(ENOMEM); 00321 00322 if (modplug->video_stream) 00323 pkt->pts = pkt->dts = modplug->packet_count++ * modplug->ts_per_packet; 00324 00325 pkt->size = ModPlug_Read(modplug->f, pkt->data, AUDIO_PKT_SIZE); 00326 if (pkt->size <= 0) { 00327 av_free_packet(pkt); 00328 return pkt->size == 0 ? AVERROR_EOF : AVERROR(EIO); 00329 } 00330 return 0; 00331 } 00332 00333 static int modplug_read_close(AVFormatContext *s) 00334 { 00335 ModPlugContext *modplug = s->priv_data; 00336 ModPlug_Unload(modplug->f); 00337 av_freep(&modplug->buf); 00338 return 0; 00339 } 00340 00341 static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags) 00342 { 00343 ModPlugContext *modplug = s->priv_data; 00344 ModPlug_Seek(modplug->f, (int)ts); 00345 if (modplug->video_stream) 00346 modplug->packet_count = ts / modplug->ts_per_packet; 00347 return 0; 00348 } 00349 00350 static const AVClass modplug_class = { 00351 .class_name = "ModPlug demuxer", 00352 .item_name = av_default_item_name, 00353 .option = options, 00354 .version = LIBAVUTIL_VERSION_INT, 00355 }; 00356 00357 AVInputFormat ff_libmodplug_demuxer = { 00358 .name = "libmodplug", 00359 .long_name = NULL_IF_CONFIG_SMALL("ModPlug demuxer"), 00360 .priv_data_size = sizeof(ModPlugContext), 00361 .read_header = modplug_read_header, 00362 .read_packet = modplug_read_packet, 00363 .read_close = modplug_read_close, 00364 .read_seek = modplug_read_seek, 00365 .extensions = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm" 00366 ",itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz", // compressed mods 00367 .priv_class = &modplug_class, 00368 };