Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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/avstring.h"
  26. #include "libavutil/eval.h"
  27. #include "libavutil/opt.h"
  28. #include "avformat.h"
  29. #include "internal.h"
  30.  
  31. typedef struct GMEContext {
  32.     const AVClass *class;
  33.     Music_Emu *music_emu;
  34.     gme_info_t *info;   ///< selected track
  35.  
  36.     /* options */
  37.     int track_index;
  38.     int sample_rate;
  39.     int64_t max_size;
  40. } GMEContext;
  41.  
  42. #define OFFSET(x) offsetof(GMEContext, x)
  43. #define A AV_OPT_FLAG_AUDIO_PARAM
  44. #define D AV_OPT_FLAG_DECODING_PARAM
  45. static const AVOption options[] = {
  46.     {"track_index", "set track that should be played",        OFFSET(track_index), AV_OPT_TYPE_INT,   {.i64 = 0},                0,    INT_MAX,  A|D},
  47.     {"sample_rate", "set sample rate",                        OFFSET(sample_rate), AV_OPT_TYPE_INT,   {.i64 = 44100},            1000, 999999,   A|D},
  48.     {"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},
  49.     {NULL}
  50. };
  51.  
  52. static void add_meta(AVFormatContext *s, const char *name, const char *value)
  53. {
  54.     if (value && value[0])
  55.         av_dict_set(&s->metadata, name, value, 0);
  56. }
  57.  
  58. static int load_metadata(AVFormatContext *s)
  59. {
  60.     GMEContext *gme = s->priv_data;
  61.     gme_info_t *info = gme->info;
  62.     char buf[30];
  63.  
  64.     add_meta(s, "system",       info->system);
  65.     add_meta(s, "game",         info->game);
  66.     add_meta(s, "song",         info->song);
  67.     add_meta(s, "author",       info->author);
  68.     add_meta(s, "copyright",    info->copyright);
  69.     add_meta(s, "comment",      info->comment);
  70.     add_meta(s, "dumper",       info->dumper);
  71.  
  72.     snprintf(buf, sizeof(buf), "%d", (int)gme_track_count(gme->music_emu));
  73.     add_meta(s, "tracks", buf);
  74.  
  75.     return 0;
  76. }
  77.  
  78. #define AUDIO_PKT_SIZE 512
  79.  
  80. static int read_header_gme(AVFormatContext *s)
  81. {
  82.     AVStream *st;
  83.     AVIOContext *pb = s->pb;
  84.     GMEContext *gme = s->priv_data;
  85.     int64_t sz = avio_size(pb);
  86.     char *buf;
  87.     char dummy;
  88.  
  89.     if (sz < 0) {
  90.         av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
  91.         sz = gme->max_size;
  92.     } else if (gme->max_size && sz > gme->max_size) {
  93.         sz = gme->max_size;
  94.     }
  95.  
  96.     buf = av_malloc(sz);
  97.     if (!buf)
  98.         return AVERROR(ENOMEM);
  99.     sz = avio_read(pb, buf, sz);
  100.  
  101.     // Data left means our buffer (the max_size option) is too small
  102.     if (avio_read(pb, &dummy, 1) == 1) {
  103.         av_log(s, AV_LOG_ERROR, "File size is larger than max_size option "
  104.                "value %"PRIi64", consider increasing the max_size option\n",
  105.                gme->max_size);
  106.         return AVERROR_BUFFER_TOO_SMALL;
  107.     }
  108.  
  109.     if (gme_open_data(buf, sz, &gme->music_emu, gme->sample_rate)) {
  110.         av_freep(&buf);
  111.         return AVERROR_INVALIDDATA;
  112.     }
  113.     av_freep(&buf);
  114.  
  115.     if (gme_track_info(gme->music_emu, &gme->info, gme->track_index))
  116.         return AVERROR_STREAM_NOT_FOUND;
  117.  
  118.     if (gme_start_track(gme->music_emu, gme->track_index))
  119.         return AVERROR_UNKNOWN;
  120.  
  121.     load_metadata(s);
  122.  
  123.     st = avformat_new_stream(s, NULL);
  124.     if (!st)
  125.         return AVERROR(ENOMEM);
  126.     avpriv_set_pts_info(st, 64, 1, 1000);
  127.     if (st->duration > 0)
  128.         st->duration = gme->info->length;
  129.     st->codec->codec_type  = AVMEDIA_TYPE_AUDIO;
  130.     st->codec->codec_id    = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE);
  131.     st->codec->channels    = 2;
  132.     st->codec->sample_rate = gme->sample_rate;
  133.  
  134.     return 0;
  135. }
  136.  
  137. static int read_packet_gme(AVFormatContext *s, AVPacket *pkt)
  138. {
  139.     GMEContext *gme = s->priv_data;
  140.     int n_samples = AUDIO_PKT_SIZE / 2;
  141.     int ret;
  142.  
  143.     if (gme_track_ended(gme->music_emu))
  144.         return AVERROR_EOF;
  145.  
  146.     if ((ret = av_new_packet(pkt, AUDIO_PKT_SIZE)) < 0)
  147.         return ret;
  148.  
  149.     if (gme_play(gme->music_emu, n_samples, (short *)pkt->data))
  150.         return AVERROR_EXTERNAL;
  151.     pkt->size = AUDIO_PKT_SIZE;
  152.  
  153.     return 0;
  154. }
  155.  
  156. static int read_close_gme(AVFormatContext *s)
  157. {
  158.     GMEContext *gme = s->priv_data;
  159.     gme_free_info(gme->info);
  160.     gme_delete(gme->music_emu);
  161.     return 0;
  162. }
  163.  
  164. static int read_seek_gme(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
  165. {
  166.     GMEContext *gme = s->priv_data;
  167.     if (!gme_seek(gme->music_emu, (int)ts))
  168.         return AVERROR_EXTERNAL;
  169.     return 0;
  170. }
  171.  
  172. static int probe_gme(AVProbeData *p)
  173. {
  174.     // Reads 4 bytes - returns "" if unknown format.
  175.     if (gme_identify_header(p->buf)[0]) {
  176.         if (p->buf_size < 16384)
  177.             return AVPROBE_SCORE_MAX / 4 + 1;
  178.         else
  179.             return AVPROBE_SCORE_MAX / 2;
  180.     }
  181.     return 0;
  182. }
  183.  
  184. static const AVClass class_gme = {
  185.     .class_name = "Game Music Emu demuxer",
  186.     .item_name  = av_default_item_name,
  187.     .option     = options,
  188.     .version    = LIBAVUTIL_VERSION_INT,
  189. };
  190.  
  191. AVInputFormat ff_libgme_demuxer = {
  192.     .name           = "libgme",
  193.     .long_name      = NULL_IF_CONFIG_SMALL("Game Music Emu demuxer"),
  194.     .priv_data_size = sizeof(GMEContext),
  195.     .read_probe     = probe_gme,
  196.     .read_header    = read_header_gme,
  197.     .read_packet    = read_packet_gme,
  198.     .read_close     = read_close_gme,
  199.     .read_seek      = read_seek_gme,
  200.     .priv_class     = &class_gme,
  201. };
  202.