... | ... |
@@ -19,10 +19,10 @@ |
19 | 19 |
/** |
20 | 20 |
* @file |
21 | 21 |
* ModPlug demuxer |
22 |
-* @todo metadata |
|
23 | 22 |
*/ |
24 | 23 |
|
25 | 24 |
#include <libmodplug/modplug.h> |
25 |
+#include "libavutil/avstring.h" |
|
26 | 26 |
#include "libavutil/opt.h" |
27 | 27 |
#include "avformat.h" |
28 | 28 |
|
... | ... |
@@ -68,6 +68,59 @@ static const AVOption options[] = { |
68 | 68 |
} \ |
69 | 69 |
} while (0) |
70 | 70 |
|
71 |
+#define ADD_META_MULTIPLE_ENTRIES(entry_name, fname) do { \ |
|
72 |
+ if (n_## entry_name ##s) { \ |
|
73 |
+ unsigned i, n = 0; \ |
|
74 |
+ \ |
|
75 |
+ for (i = 0; i < n_## entry_name ##s; i++) { \ |
|
76 |
+ char item_name[64] = {0}; \ |
|
77 |
+ fname(f, i, item_name); \ |
|
78 |
+ if (!*item_name) \ |
|
79 |
+ continue; \ |
|
80 |
+ if (n) \ |
|
81 |
+ av_dict_set(&s->metadata, #entry_name, "\n", AV_DICT_APPEND); \ |
|
82 |
+ av_dict_set(&s->metadata, #entry_name, item_name, AV_DICT_APPEND); \ |
|
83 |
+ n++; \ |
|
84 |
+ } \ |
|
85 |
+ \ |
|
86 |
+ extra = av_asprintf(", %u/%u " #entry_name "%s", \ |
|
87 |
+ n, n_## entry_name ##s, n > 1 ? "s" : ""); \ |
|
88 |
+ if (!extra) \ |
|
89 |
+ return AVERROR(ENOMEM); \ |
|
90 |
+ av_dict_set(&s->metadata, "extra info", extra, AV_DICT_APPEND); \ |
|
91 |
+ av_free(extra); \ |
|
92 |
+ } \ |
|
93 |
+} while (0) |
|
94 |
+ |
|
95 |
+static int modplug_load_metadata(AVFormatContext *s) |
|
96 |
+{ |
|
97 |
+ ModPlugContext *modplug = s->priv_data; |
|
98 |
+ ModPlugFile *f = modplug->f; |
|
99 |
+ char *extra; |
|
100 |
+ const char *name = ModPlug_GetName(f); |
|
101 |
+ const char *msg = ModPlug_GetMessage(f); |
|
102 |
+ |
|
103 |
+ unsigned n_instruments = ModPlug_NumInstruments(f); |
|
104 |
+ unsigned n_samples = ModPlug_NumSamples(f); |
|
105 |
+ unsigned n_patterns = ModPlug_NumPatterns(f); |
|
106 |
+ unsigned n_channels = ModPlug_NumChannels(f); |
|
107 |
+ |
|
108 |
+ if (name && *name) av_dict_set(&s->metadata, "name", name, 0); |
|
109 |
+ if (msg && *msg) av_dict_set(&s->metadata, "message", msg, 0); |
|
110 |
+ |
|
111 |
+ extra = av_asprintf("%u pattern%s, %u channel%s", |
|
112 |
+ n_patterns, n_patterns > 1 ? "s" : "", |
|
113 |
+ n_channels, n_channels > 1 ? "s" : ""); |
|
114 |
+ if (!extra) |
|
115 |
+ return AVERROR(ENOMEM); |
|
116 |
+ av_dict_set(&s->metadata, "extra info", extra, AV_DICT_DONT_STRDUP_VAL); |
|
117 |
+ |
|
118 |
+ ADD_META_MULTIPLE_ENTRIES(instrument, ModPlug_InstrumentName); |
|
119 |
+ ADD_META_MULTIPLE_ENTRIES(sample, ModPlug_SampleName); |
|
120 |
+ |
|
121 |
+ return 0; |
|
122 |
+} |
|
123 |
+ |
|
71 | 124 |
static int modplug_read_header(AVFormatContext *s, AVFormatParameters *ap) |
72 | 125 |
{ |
73 | 126 |
AVStream *st; |
... | ... |
@@ -127,7 +180,8 @@ static int modplug_read_header(AVFormatContext *s, AVFormatParameters *ap) |
127 | 127 |
st->codec->codec_id = CODEC_ID_PCM_S16LE; |
128 | 128 |
st->codec->channels = settings.mChannels; |
129 | 129 |
st->codec->sample_rate = settings.mFrequency; |
130 |
- return 0; |
|
130 |
+ |
|
131 |
+ return modplug_load_metadata(s); |
|
131 | 132 |
} |
132 | 133 |
|
133 | 134 |
static int modplug_read_packet(AVFormatContext *s, AVPacket *pkt) |