Browse code

lavf: add support for libgme

Reviewed-by: Stefano Sabatini <stefasab@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

wm4 authored on 2013/06/28 17:36:00
Showing 7 changed files
... ...
@@ -68,6 +68,7 @@ version <next>:
68 68
 - WavPack encoding through libwavpack
69 69
 - rotate filter
70 70
 - spp filter ported from libmpcodecs
71
+- libgme support
71 72
 
72 73
 
73 74
 version 1.2:
... ...
@@ -202,6 +202,7 @@ External library support:
202 202
   --enable-libfdk-aac      enable AAC encoding via libfdk-aac [no]
203 203
   --enable-libflite        enable flite (voice synthesis) support via libflite [no]
204 204
   --enable-libfreetype     enable libfreetype [no]
205
+  --enable-libgme          enable Game Music Emu via libgme [no]
205 206
   --enable-libgsm          enable GSM de/encoding via libgsm [no]
206 207
   --enable-libiec61883     enable iec61883 via libiec61883 [no]
207 208
   --enable-libilbc         enable iLBC de/encoding via libilbc [no]
... ...
@@ -1167,6 +1168,7 @@ EXTERNAL_LIBRARY_LIST="
1167 1167
     libfdk_aac
1168 1168
     libflite
1169 1169
     libfreetype
1170
+    libgme
1170 1171
     libgsm
1171 1172
     libiec61883
1172 1173
     libilbc
... ...
@@ -1974,6 +1976,7 @@ libfaac_encoder_deps="libfaac"
1974 1974
 libfaac_encoder_select="audio_frame_queue"
1975 1975
 libfdk_aac_encoder_deps="libfdk_aac"
1976 1976
 libfdk_aac_encoder_select="audio_frame_queue"
1977
+libgme_demuxer_deps="libgme"
1977 1978
 libgsm_decoder_deps="libgsm"
1978 1979
 libgsm_encoder_deps="libgsm"
1979 1980
 libgsm_ms_decoder_deps="libgsm"
... ...
@@ -4131,6 +4134,7 @@ enabled libfdk_aac        && require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen
4131 4131
 flite_libs="-lflite_cmu_time_awb -lflite_cmu_us_awb -lflite_cmu_us_kal -lflite_cmu_us_kal16 -lflite_cmu_us_rms -lflite_cmu_us_slt -lflite_usenglish -lflite_cmulex -lflite"
4132 4132
 enabled libflite          && require2 libflite "flite/flite.h" flite_init $flite_libs
4133 4133
 enabled libfreetype       && require_pkg_config freetype2 "ft2build.h freetype/freetype.h" FT_Init_FreeType
4134
+enabled libgme            && require  libgme gme/gme.h gme_new_emu -lgme
4134 4135
 enabled libgsm            && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do
4135 4136
                                    check_lib "${gsm_hdr}" gsm_create -lgsm && break;
4136 4137
                                done || die "ERROR: libgsm not found"; }
... ...
@@ -103,6 +103,19 @@ probed and 0 otherwise.
103 103
 
104 104
 @end table
105 105
 
106
+@section libgme
107
+
108
+The Game Music Emu library is a collection of video game music file emulators.
109
+
110
+See @url{http://code.google.com/p/game-music-emu/} for more information.
111
+
112
+Some files have multiple tracks. The demuxer will pick the first track by
113
+default. The @option{track_index} option can be used to select a different
114
+track. Track indexes start at 0. The demuxer exports the number of tracks as
115
+@var{tracks} meta data entry.
116
+
117
+For very large files, the @option{max_size} option may have to be adjusted.
118
+
106 119
 @section libquvi
107 120
 
108 121
 Play media from Internet services using the quvi project.
... ...
@@ -412,6 +412,7 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER)        += yuv4mpeg.o
412 412
 OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER)      += yuv4mpeg.o
413 413
 
414 414
 # external libraries
415
+OBJS-$(CONFIG_LIBGME_DEMUXER)            += libgme.o
415 416
 OBJS-$(CONFIG_LIBMODPLUG_DEMUXER)        += libmodplug.o
416 417
 OBJS-$(CONFIG_LIBNUT_DEMUXER)            += libnut.o
417 418
 OBJS-$(CONFIG_LIBNUT_MUXER)              += libnut.o
... ...
@@ -337,6 +337,7 @@ void av_register_all(void)
337 337
     REGISTER_PROTOCOL(UDP,              udp);
338 338
 
339 339
     /* external libraries */
340
+    REGISTER_DEMUXER (LIBGME,           libgme);
340 341
     REGISTER_DEMUXER (LIBMODPLUG,       libmodplug);
341 342
     REGISTER_MUXDEMUX(LIBNUT,           libnut);
342 343
     REGISTER_DEMUXER (LIBQUVI,          libquvi);
343 344
new file mode 100644
... ...
@@ -0,0 +1,201 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+/**
19
+* @file
20
+* libgme demuxer
21
+*/
22
+
23
+#include <gme/gme.h>
24
+#include "libavutil/avstring.h"
25
+#include "libavutil/eval.h"
26
+#include "libavutil/opt.h"
27
+#include "avformat.h"
28
+#include "internal.h"
29
+
30
+typedef struct GMEContext {
31
+    const AVClass *class;
32
+    Music_Emu *music_emu;
33
+    gme_info_t *info;   ///< selected track
34
+
35
+    /* options */
36
+    int track_index;
37
+    int sample_rate;
38
+    int64_t max_size;
39
+} GMEContext;
40
+
41
+#define OFFSET(x) offsetof(GMEContext, x)
42
+#define A AV_OPT_FLAG_AUDIO_PARAM
43
+#define D AV_OPT_FLAG_DECODING_PARAM
44
+static const AVOption options[] = {
45
+    {"track_index", "set track that should be played",        OFFSET(track_index), AV_OPT_TYPE_INT,   {.i64 = 0},                0,    INT_MAX,  A|D},
46
+    {"sample_rate", "set sample rate",                        OFFSET(sample_rate), AV_OPT_TYPE_INT,   {.i64 = 44100},            1000, 999999,   A|D},
47
+    {"max_size",    "set max file size supported (in bytes)", OFFSET(max_size),    AV_OPT_TYPE_INT64, {.i64 = 50 * 1024 * 1024}, 0,    SIZE_MAX, A|D},
48
+    {NULL}
49
+};
50
+
51
+static void add_meta(AVFormatContext *s, const char *name, const char *value)
52
+{
53
+    if (value && value[0])
54
+        av_dict_set(&s->metadata, name, value, 0);
55
+}
56
+
57
+static int load_metadata(AVFormatContext *s)
58
+{
59
+    GMEContext *gme = s->priv_data;
60
+    gme_info_t *info = gme->info;
61
+    char buf[30];
62
+
63
+    add_meta(s, "system",       info->system);
64
+    add_meta(s, "game",         info->game);
65
+    add_meta(s, "song",         info->song);
66
+    add_meta(s, "author",       info->author);
67
+    add_meta(s, "copyright",    info->copyright);
68
+    add_meta(s, "comment",      info->comment);
69
+    add_meta(s, "dumper",       info->dumper);
70
+
71
+    snprintf(buf, sizeof(buf), "%d", (int)gme_track_count(gme->music_emu));
72
+    add_meta(s, "tracks", buf);
73
+
74
+    return 0;
75
+}
76
+
77
+#define AUDIO_PKT_SIZE 512
78
+
79
+static int read_header_gme(AVFormatContext *s)
80
+{
81
+    AVStream *st;
82
+    AVIOContext *pb = s->pb;
83
+    GMEContext *gme = s->priv_data;
84
+    int64_t sz = avio_size(pb);
85
+    char *buf;
86
+    char dummy;
87
+
88
+    if (sz < 0) {
89
+        av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
90
+        sz = gme->max_size;
91
+    } else if (gme->max_size && sz > gme->max_size) {
92
+        sz = gme->max_size;
93
+    }
94
+
95
+    buf = av_malloc(sz);
96
+    if (!buf)
97
+        return AVERROR(ENOMEM);
98
+    sz = avio_read(pb, buf, sz);
99
+
100
+    // Data left means our buffer (the max_size option) is too small
101
+    if (avio_read(pb, &dummy, 1) == 1) {
102
+        av_log(s, AV_LOG_ERROR, "File size is larger than max_size option "
103
+               "value %"PRIi64", consider increasing the max_size option\n",
104
+               gme->max_size);
105
+        return AVERROR_BUFFER_TOO_SMALL;
106
+    }
107
+
108
+    if (gme_open_data(buf, sz, &gme->music_emu, gme->sample_rate)) {
109
+        av_freep(&buf);
110
+        return AVERROR_INVALIDDATA;
111
+    }
112
+    av_freep(&buf);
113
+
114
+    if (gme_track_info(gme->music_emu, &gme->info, gme->track_index))
115
+        return AVERROR_STREAM_NOT_FOUND;
116
+
117
+    if (gme_start_track(gme->music_emu, gme->track_index))
118
+        return AVERROR_UNKNOWN;
119
+
120
+    load_metadata(s);
121
+
122
+    st = avformat_new_stream(s, NULL);
123
+    if (!st)
124
+        return AVERROR(ENOMEM);
125
+    avpriv_set_pts_info(st, 64, 1, 1000);
126
+    if (st->duration > 0)
127
+        st->duration = gme->info->length;
128
+    st->codec->codec_type  = AVMEDIA_TYPE_AUDIO;
129
+    st->codec->codec_id    = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE);
130
+    st->codec->channels    = 2;
131
+    st->codec->sample_rate = gme->sample_rate;
132
+
133
+    return 0;
134
+}
135
+
136
+static int read_packet_gme(AVFormatContext *s, AVPacket *pkt)
137
+{
138
+    GMEContext *gme = s->priv_data;
139
+    int n_samples = AUDIO_PKT_SIZE / 2;
140
+    int ret;
141
+
142
+    if (gme_track_ended(gme->music_emu))
143
+        return AVERROR_EOF;
144
+
145
+    if ((ret = av_new_packet(pkt, AUDIO_PKT_SIZE)) < 0)
146
+        return ret;
147
+
148
+    if (gme_play(gme->music_emu, n_samples, (short *)pkt->data))
149
+        return AVERROR_EXTERNAL;
150
+    pkt->size = AUDIO_PKT_SIZE;
151
+
152
+    return 0;
153
+}
154
+
155
+static int read_close_gme(AVFormatContext *s)
156
+{
157
+    GMEContext *gme = s->priv_data;
158
+    gme_free_info(gme->info);
159
+    gme_delete(gme->music_emu);
160
+    return 0;
161
+}
162
+
163
+static int read_seek_gme(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
164
+{
165
+    GMEContext *gme = s->priv_data;
166
+    if (!gme_seek(gme->music_emu, (int)ts))
167
+        return AVERROR_EXTERNAL;
168
+    return 0;
169
+}
170
+
171
+static int probe_gme(AVProbeData *p)
172
+{
173
+    // Reads 4 bytes - returns "" if unknown format.
174
+    if (gme_identify_header(p->buf)[0]) {
175
+        if (p->buf_size < 16384)
176
+            return AVPROBE_SCORE_MAX / 4 + 1;
177
+        else
178
+            return AVPROBE_SCORE_MAX / 2;
179
+    }
180
+    return 0;
181
+}
182
+
183
+static const AVClass class_gme = {
184
+    .class_name = "Game Music Emu demuxer",
185
+    .item_name  = av_default_item_name,
186
+    .option     = options,
187
+    .version    = LIBAVUTIL_VERSION_INT,
188
+};
189
+
190
+AVInputFormat ff_libgme_demuxer = {
191
+    .name           = "libgme",
192
+    .long_name      = NULL_IF_CONFIG_SMALL("Game Music Emu demuxer"),
193
+    .priv_data_size = sizeof(GMEContext),
194
+    .read_probe     = probe_gme,
195
+    .read_header    = read_header_gme,
196
+    .read_packet    = read_packet_gme,
197
+    .read_close     = read_close_gme,
198
+    .read_seek      = read_seek_gme,
199
+    .priv_class     = &class_gme,
200
+};
... ...
@@ -30,8 +30,8 @@
30 30
 #include "libavutil/avutil.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 55
33
-#define LIBAVFORMAT_VERSION_MINOR 10
34
-#define LIBAVFORMAT_VERSION_MICRO 101
33
+#define LIBAVFORMAT_VERSION_MINOR 11
34
+#define LIBAVFORMAT_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
37 37
                                                LIBAVFORMAT_VERSION_MINOR, \