FFmpeg
Loading...
Searching...
No Matches
libgme.c
Go to the documentation of this file.
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* libgme demuxer
22*/
23
24#include <gme/gme.h>
25#include "libavutil/mem.h"
26#include "libavutil/opt.h"
27#include "avformat.h"
28#include "demux.h"
29#include "internal.h"
30
31typedef struct GMEContext {
32 const AVClass *class;
33 Music_Emu *music_emu;
34
35 /* options */
40
41#define OFFSET(x) offsetof(GMEContext, x)
42#define A AV_OPT_FLAG_AUDIO_PARAM
43#define D AV_OPT_FLAG_DECODING_PARAM
44static 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
51static 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
58{
59 GMEContext *gme = s->priv_data;
60 gme_info_t *info = NULL;
61 char buf[30];
62
63 if (gme_track_info(gme->music_emu, &info, gme->track_index))
65
66 *duration = info->length;
67 add_meta(s, "system", info->system);
68 add_meta(s, "game", info->game);
69 add_meta(s, "song", info->song);
70 add_meta(s, "author", info->author);
71 add_meta(s, "copyright", info->copyright);
72 add_meta(s, "comment", info->comment);
73 add_meta(s, "dumper", info->dumper);
74
75 snprintf(buf, sizeof(buf), "%d", (int)gme_track_count(gme->music_emu));
76 add_meta(s, "tracks", buf);
77 gme_free_info(info);
78
79 return 0;
80}
81
82#define AUDIO_PKT_SIZE 512
83
85{
86 GMEContext *gme = s->priv_data;
87 if (gme->music_emu)
88 gme_delete(gme->music_emu);
89 return 0;
90}
91
93{
94 AVStream *st;
95 AVIOContext *pb = s->pb;
96 GMEContext *gme = s->priv_data;
97 int64_t sz = avio_size(pb);
99 char *buf;
100 char dummy;
101 int ret;
102
103 if (sz < 0) {
104 av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
105 sz = gme->max_size;
106 } else if (gme->max_size && sz > gme->max_size) {
107 sz = gme->max_size;
108 }
109
110 buf = av_malloc(sz);
111 if (!buf)
112 return AVERROR(ENOMEM);
113 sz = avio_read(pb, buf, sz);
114
115 // Data left means our buffer (the max_size option) is too small
116 if (avio_read(pb, &dummy, 1) == 1) {
117 av_log(s, AV_LOG_ERROR, "File size is larger than max_size option "
118 "value %"PRIi64", consider increasing the max_size option\n",
119 gme->max_size);
120 av_freep(&buf);
122 }
123
124 if (gme_open_data(buf, sz, &gme->music_emu, gme->sample_rate)) {
125 gme->music_emu = NULL; /* Just for safety */
126 av_freep(&buf);
127 return AVERROR_INVALIDDATA;
128 }
129 av_freep(&buf);
130
131 ret = load_metadata(s, &duration);
132 if (ret < 0)
133 return ret;
134 if (gme_start_track(gme->music_emu, gme->track_index))
135 return AVERROR_UNKNOWN;
136
138 if (!st)
139 return AVERROR(ENOMEM);
140 avpriv_set_pts_info(st, 64, 1, 1000);
141 if (duration > 0)
142 st->duration = duration;
146 st->codecpar->sample_rate = gme->sample_rate;
147
148 return 0;
149}
150
152{
153 GMEContext *gme = s->priv_data;
154 int n_samples = AUDIO_PKT_SIZE / 2;
155 int ret;
156
157 if (gme_track_ended(gme->music_emu))
158 return AVERROR_EOF;
159
160 if ((ret = av_new_packet(pkt, AUDIO_PKT_SIZE)) < 0)
161 return ret;
162
163 if (gme_play(gme->music_emu, n_samples, (short *)pkt->data))
164 return AVERROR_EXTERNAL;
165
166 return 0;
167}
168
169static int read_seek_gme(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
170{
171 GMEContext *gme = s->priv_data;
172 if (!gme_seek(gme->music_emu, (int)ts))
173 return AVERROR_EXTERNAL;
174 return 0;
175}
176
177static int probe_gme(const AVProbeData *p)
178{
179 // Reads 4 bytes - returns "" if unknown format.
180 if (gme_identify_header(p->buf)[0]) {
181 if (p->buf_size < 16384)
182 return AVPROBE_SCORE_MAX / 4 ;
183 else
184 return AVPROBE_SCORE_MAX / 2;
185 }
186 return 0;
187}
188
189static const AVClass class_gme = {
190 .class_name = "Game Music Emu demuxer",
191 .item_name = av_default_item_name,
192 .option = options,
193 .version = LIBAVUTIL_VERSION_INT,
194};
195
197 .p.name = "libgme",
198 .p.long_name = NULL_IF_CONFIG_SMALL("Game Music Emu demuxer"),
199 .p.priv_class = &class_gme,
200 .priv_data_size = sizeof(GMEContext),
201 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
207};
const FFInputFormat ff_libgme_demuxer
Definition libgme.c:196
#define A(x)
Definition vpx_arith.h:28
#define D
Definition avdct.c:35
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition avformat.c:834
Main libavformat public API header.
#define AVPROBE_SCORE_MAX
maximum score
Definition avformat.h:483
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition aviobuf.c:326
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition aviobuf.c:615
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define s(width, name)
Definition cbs_vp9.c:198
static int read_probe(const AVProbeData *p)
Definition cdg.c:30
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define FF_INFMT_FLAG_INIT_CLEANUP
For an FFInputFormat with this flag set read_close() needs to be called by the caller upon read_heade...
Definition demux.h:35
static AVPacket * pkt
double value
Definition eval.c:102
static int64_t duration
Definition ffplay.c:330
static int dummy
Definition ffplay.c:3754
static int read_header(FFV1Context *f, RangeCoder *c)
Definition ffv1dec.c:578
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition opt.h:262
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_CODEC_ID_PCM_S16LE
Definition codec_id.h:330
@ AV_CODEC_ID_PCM_S16BE
Definition codec_id.h:331
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition packet.c:98
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition error.h:53
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR_STREAM_NOT_FOUND
Stream not found.
Definition error.h:67
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static av_cold int read_close(AVFormatContext *ctx)
Definition libcdio.c:143
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags)
Definition libcdio.c:151
#define AUDIO_PKT_SIZE
Definition libgme.c:82
static int load_metadata(AVFormatContext *s, int64_t *duration)
Definition libgme.c:57
static int read_seek_gme(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
Definition libgme.c:169
static int read_header_gme(AVFormatContext *s)
Definition libgme.c:92
static int probe_gme(const AVProbeData *p)
Definition libgme.c:177
static int read_close_gme(AVFormatContext *s)
Definition libgme.c:84
static int read_packet_gme(AVFormatContext *s, AVPacket *pkt)
Definition libgme.c:151
#define OFFSET(x)
Definition libgme.c:41
static const AVClass class_gme
Definition libgme.c:189
#define add_meta(s, name, meta)
Definition libopenmpt.c:72
#define AV_NE(be, le)
Definition macros.h:33
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
const char * name
Definition qsvenc.c:142
#define snprintf
Definition snprintf.h:34
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
Definition log.h:76
AVChannelLayout ch_layout
The channel layout and number of channels.
Definition codec_par.h:207
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
int sample_rate
The number of audio samples per second.
Definition codec_par.h:213
Format I/O context.
Definition avformat.h:1333
Bytestream IO Context.
Definition avio.h:160
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
This structure contains the data a format has to probe a file.
Definition avformat.h:471
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
int64_t duration
Decoding: duration of the stream, in stream time base.
Definition avformat.h:825
int sample_rate
Definition libgme.c:37
int64_t max_size
Definition libgme.c:38
int track_index
Definition libgme.c:36
Music_Emu * music_emu
Definition libgme.c:33
#define av_freep(p)
#define av_log(a,...)
static int track_index(VividasDemuxContext *viv, AVFormatContext *s, const uint8_t *buf, unsigned size)
Definition vividas.c:438