Reviewed-by: Stefano Sabatini <stefasab@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
... | ... |
@@ -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, \ |