libmodplug: simplify and fix read_packet() callback.
[ffmpeg.git] / libavformat / libmodplug.c
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 ModPlug options (noise reduction, reverb, bass boost, ...)
23 * @todo metadata
24 */
25
26 #include <libmodplug/modplug.h>
27 #include "avformat.h"
28
29 typedef struct ModPlugContext {
30     ModPlugFile *f;
31     uint8_t buf[5 * 1<<20]; ///< input file content, 5M max
32 } ModPlugContext;
33
34 static int modplug_read_header(AVFormatContext *s, AVFormatParameters *ap)
35 {
36     AVStream *st;
37     AVIOContext *pb = s->pb;
38     ModPlug_Settings settings;
39     ModPlugContext *modplug = s->priv_data;
40
41     int sz = avio_read(pb, modplug->buf, sizeof(modplug->buf));
42
43     ModPlug_GetSettings(&settings);
44     settings.mChannels       = 2;
45     settings.mBits           = 16;
46     settings.mFrequency      = 44100;
47     settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; // best quality
48     settings.mLoopCount      = 0; // prevents looping forever
49     ModPlug_SetSettings(&settings);
50
51     modplug->f = ModPlug_Load(modplug->buf, sz);
52     if (!modplug->f)
53         return AVERROR_INVALIDDATA;
54
55     st = av_new_stream(s, 0);
56     if (!st)
57         return AVERROR(ENOMEM);
58     av_set_pts_info(st, 64, 1, 1000);
59     st->duration = ModPlug_GetLength(modplug->f);
60     st->codec->codec_type  = AVMEDIA_TYPE_AUDIO;
61     st->codec->codec_id    = CODEC_ID_PCM_S16LE;
62     st->codec->channels    = settings.mChannels;
63     st->codec->sample_rate = settings.mFrequency;
64     return 0;
65 }
66
67 static int modplug_read_packet(AVFormatContext *s, AVPacket *pkt)
68 {
69     ModPlugContext *modplug = s->priv_data;
70
71     if (av_new_packet(pkt, 512) < 0)
72         return AVERROR(ENOMEM);
73
74     pkt->size = ModPlug_Read(modplug->f, pkt->data, 512);
75     if (pkt->size <= 0) {
76         av_free_packet(pkt);
77         return AVERROR(EIO);
78     }
79     return 0;
80 }
81
82 static int modplug_read_close(AVFormatContext *s)
83 {
84     ModPlugContext *modplug = s->priv_data;
85     ModPlug_Unload(modplug->f);
86     return 0;
87 }
88
89 static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
90 {
91     const ModPlugContext *modplug = s->priv_data;
92     ModPlug_Seek(modplug->f, (int)ts);
93     return 0;
94 }
95
96 AVInputFormat ff_libmodplug_demuxer = {
97     .name           = "libmodplug",
98     .long_name      = NULL_IF_CONFIG_SMALL("ModPlug demuxer"),
99     .priv_data_size = sizeof(ModPlugContext),
100     .read_header    = modplug_read_header,
101     .read_packet    = modplug_read_packet,
102     .read_close     = modplug_read_close,
103     .read_seek      = modplug_read_seek,
104     .extensions     = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm"
105                       ",itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz", // compressed mods
106 };