Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Rodger Combs authored on 2015/10/04 07:24:06... | ... |
@@ -196,6 +196,7 @@ Individual component options: |
196 | 196 |
External library support: |
197 | 197 |
--enable-avisynth enable reading of AviSynth script files [no] |
198 | 198 |
--disable-bzlib disable bzlib [autodetect] |
199 |
+ --enable-chromaprint enable audio fingerprinting with chromaprint [no] |
|
199 | 200 |
--enable-fontconfig enable fontconfig, useful for drawtext filter [no] |
200 | 201 |
--enable-frei0r enable frei0r video filtering [no] |
201 | 202 |
--enable-gnutls enable gnutls, needed for https support |
... | ... |
@@ -1367,6 +1368,7 @@ EXAMPLE_LIST=" |
1367 | 1367 |
EXTERNAL_LIBRARY_LIST=" |
1368 | 1368 |
avisynth |
1369 | 1369 |
bzlib |
1370 |
+ chromaprint |
|
1370 | 1371 |
crystalhd |
1371 | 1372 |
decklink |
1372 | 1373 |
frei0r |
... | ... |
@@ -2507,6 +2509,7 @@ vc1_parser_select="mpegvideo startcode vc1_decoder" |
2507 | 2507 |
mjpeg2jpeg_bsf_select="jpegtables" |
2508 | 2508 |
|
2509 | 2509 |
# external libraries |
2510 |
+chromaprint_muxer_deps="chromaprint" |
|
2510 | 2511 |
libaacplus_encoder_deps="libaacplus" |
2511 | 2512 |
libcelt_decoder_deps="libcelt" |
2512 | 2513 |
libdcadec_decoder_deps="libdcadec" |
... | ... |
@@ -5255,6 +5258,7 @@ enabled avfoundation_indev && { check_lib2 CoreGraphics/CoreGraphics.h CGGetActi |
5255 | 5255 |
enabled avisynth && { { check_lib2 "windows.h" LoadLibrary; } || |
5256 | 5256 |
{ check_lib2 "dlfcn.h" dlopen -ldl; } || |
5257 | 5257 |
die "ERROR: LoadLibrary/dlopen not found for avisynth"; } |
5258 |
+enabled chromaprint && require chromaprint chromaprint.h chromaprint_get_version -lchromaprint |
|
5258 | 5259 |
enabled decklink && { check_header DeckLinkAPI.h || die "ERROR: DeckLinkAPI.h header not found"; } |
5259 | 5260 |
enabled frei0r && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; } |
5260 | 5261 |
enabled gnutls && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init |
... | ... |
@@ -37,6 +37,41 @@ ID3v2.3 and ID3v2.4) are supported. The default is version 4. |
37 | 37 |
|
38 | 38 |
@end table |
39 | 39 |
|
40 |
+@anchor{chromaprint} |
|
41 |
+@section chromaprint |
|
42 |
+ |
|
43 |
+Chromaprint fingerprinter |
|
44 |
+ |
|
45 |
+This muxer feeds audio data to the Chromaprint library, which generates |
|
46 |
+a fingerprint for the provided audio data. It takes a single signed |
|
47 |
+native-endian 16-bit raw audio stream. |
|
48 |
+ |
|
49 |
+@subsection Options |
|
50 |
+ |
|
51 |
+@table @option |
|
52 |
+@item silence_threshold |
|
53 |
+Threshold for detecting silence, ranges from 0 to 32767. -1 for default |
|
54 |
+(required for use with the AcoustID service). |
|
55 |
+ |
|
56 |
+@item algorithm |
|
57 |
+Algorithm index to fingerprint with. |
|
58 |
+ |
|
59 |
+@item fp_format |
|
60 |
+Format to output the fingerprint as. Accepts the following options: |
|
61 |
+@table @samp |
|
62 |
+@item raw |
|
63 |
+Binary raw fingerprint |
|
64 |
+ |
|
65 |
+@item compressed |
|
66 |
+Binary compressed fingerprint |
|
67 |
+ |
|
68 |
+@item base64 |
|
69 |
+Base64 compressed fingerprint |
|
70 |
+ |
|
71 |
+@end table |
|
72 |
+ |
|
73 |
+@end table |
|
74 |
+ |
|
40 | 75 |
@anchor{crc} |
41 | 76 |
@section crc |
42 | 77 |
|
... | ... |
@@ -487,6 +487,7 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpegenc.o |
487 | 487 |
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpegdec.o |
488 | 488 |
|
489 | 489 |
# external libraries |
490 |
+OBJS-$(CONFIG_CHROMAPRINT_MUXER) += chromaprint.o |
|
490 | 491 |
OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o |
491 | 492 |
OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o |
492 | 493 |
OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o |
... | ... |
@@ -391,6 +391,7 @@ void av_register_all(void) |
391 | 391 |
REGISTER_PROTOCOL(UNIX, unix); |
392 | 392 |
|
393 | 393 |
/* external libraries */ |
394 |
+ REGISTER_MUXER (CHROMAPRINT, chromaprint); |
|
394 | 395 |
REGISTER_DEMUXER (LIBGME, libgme); |
395 | 396 |
REGISTER_DEMUXER (LIBMODPLUG, libmodplug); |
396 | 397 |
REGISTER_MUXDEMUX(LIBNUT, libnut); |
397 | 398 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,186 @@ |
0 |
+/* |
|
1 |
+ * Chromaprint fingerprinting muxer |
|
2 |
+ * Copyright (c) 2015 Rodger Combs |
|
3 |
+ * |
|
4 |
+ * This file is part of FFmpeg. |
|
5 |
+ * |
|
6 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
7 |
+ * modify it under the terms of the GNU Lesser General Public |
|
8 |
+ * License as published by the Free Software Foundation; either |
|
9 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
10 |
+ * |
|
11 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
+ * Lesser General Public License for more details. |
|
15 |
+ * |
|
16 |
+ * You should have received a copy of the GNU Lesser General Public |
|
17 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
18 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#include "avformat.h" |
|
22 |
+#include "libavutil/opt.h" |
|
23 |
+#include "libavcodec/internal.h" |
|
24 |
+#include <chromaprint.h> |
|
25 |
+ |
|
26 |
+#define CPR_VERSION_INT AV_VERSION_INT(CHROMAPRINT_VERSION_MAJOR, \ |
|
27 |
+ CHROMAPRINT_VERSION_MINOR, \ |
|
28 |
+ CHROMAPRINT_VERSION_PATCH) |
|
29 |
+ |
|
30 |
+typedef enum FingerprintFormat { |
|
31 |
+ FINGERPRINT_RAW, |
|
32 |
+ FINGERPRINT_COMPRESSED, |
|
33 |
+ FINGERPRINT_BASE64, |
|
34 |
+} FingerprintFormat; |
|
35 |
+ |
|
36 |
+typedef struct ChromaprintMuxContext { |
|
37 |
+ const AVClass *class; |
|
38 |
+ int silence_threshold; |
|
39 |
+ int algorithm; |
|
40 |
+ FingerprintFormat fp_format; |
|
41 |
+ ChromaprintContext ctx; |
|
42 |
+} ChromaprintMuxContext; |
|
43 |
+ |
|
44 |
+static void cleanup(ChromaprintMuxContext *cpr) |
|
45 |
+{ |
|
46 |
+ if (cpr->ctx) { |
|
47 |
+ avpriv_lock_avformat(); |
|
48 |
+ chromaprint_free(cpr->ctx); |
|
49 |
+ avpriv_unlock_avformat(); |
|
50 |
+ } |
|
51 |
+} |
|
52 |
+ |
|
53 |
+static int write_header(AVFormatContext *s) |
|
54 |
+{ |
|
55 |
+ ChromaprintMuxContext *cpr = s->priv_data; |
|
56 |
+ AVStream *st; |
|
57 |
+ |
|
58 |
+ avpriv_lock_avformat(); |
|
59 |
+ cpr->ctx = chromaprint_new(cpr->algorithm); |
|
60 |
+ avpriv_unlock_avformat(); |
|
61 |
+ |
|
62 |
+ if (!cpr->ctx) { |
|
63 |
+ av_log(s, AV_LOG_ERROR, "Failed to create chromaprint context.\n"); |
|
64 |
+ return AVERROR(ENOMEM); |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+ if (cpr->silence_threshold != -1) { |
|
68 |
+#if CPR_VERSION_INT >= AV_VERSION_INT(0, 7, 0) |
|
69 |
+ if (!chromaprint_set_option(cpr->ctx, "silence_threshold", cpr->silence_threshold)) { |
|
70 |
+ av_log(s, AV_LOG_ERROR, "Failed to set silence threshold.\n"); |
|
71 |
+ goto fail; |
|
72 |
+ } |
|
73 |
+#else |
|
74 |
+ av_log(s, AV_LOG_ERROR, "Setting the silence threshold requires Chromaprint " |
|
75 |
+ "version 0.7.0 or later.\n"); |
|
76 |
+ goto fail; |
|
77 |
+#endif |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ if (s->nb_streams != 1) { |
|
81 |
+ av_log(s, AV_LOG_ERROR, "Only one stream is supported\n"); |
|
82 |
+ goto fail; |
|
83 |
+ } |
|
84 |
+ |
|
85 |
+ st = s->streams[0]; |
|
86 |
+ |
|
87 |
+ if (st->codec->channels > 2) { |
|
88 |
+ av_log(s, AV_LOG_ERROR, "Only up to 2 channels are supported\n"); |
|
89 |
+ goto fail; |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ if (st->codec->sample_rate < 1000) { |
|
93 |
+ av_log(s, AV_LOG_ERROR, "Sampling rate must be at least 1000\n"); |
|
94 |
+ goto fail; |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+ if (!chromaprint_start(cpr->ctx, st->codec->sample_rate, st->codec->channels)) { |
|
98 |
+ av_log(s, AV_LOG_ERROR, "Failed to start chromaprint\n"); |
|
99 |
+ goto fail; |
|
100 |
+ } |
|
101 |
+ |
|
102 |
+ return 0; |
|
103 |
+fail: |
|
104 |
+ cleanup(cpr); |
|
105 |
+ return AVERROR(EINVAL); |
|
106 |
+} |
|
107 |
+ |
|
108 |
+static int write_packet(AVFormatContext *s, AVPacket *pkt) |
|
109 |
+{ |
|
110 |
+ ChromaprintMuxContext *cpr = s->priv_data; |
|
111 |
+ return chromaprint_feed(cpr->ctx, pkt->data, pkt->size / 2) ? 0 : AVERROR(EINVAL); |
|
112 |
+} |
|
113 |
+ |
|
114 |
+static int write_trailer(AVFormatContext *s) |
|
115 |
+{ |
|
116 |
+ ChromaprintMuxContext *cpr = s->priv_data; |
|
117 |
+ AVIOContext *pb = s->pb; |
|
118 |
+ void *fp = NULL, *enc_fp = NULL; |
|
119 |
+ int size, enc_size, ret = AVERROR(EINVAL); |
|
120 |
+ |
|
121 |
+ if (!chromaprint_finish(cpr->ctx)) { |
|
122 |
+ av_log(s, AV_LOG_ERROR, "Failed to generate fingerprint\n"); |
|
123 |
+ goto fail; |
|
124 |
+ } |
|
125 |
+ |
|
126 |
+ if (!chromaprint_get_raw_fingerprint(cpr->ctx, &fp, &size)) { |
|
127 |
+ av_log(s, AV_LOG_ERROR, "Failed to retrieve fingerprint\n"); |
|
128 |
+ goto fail; |
|
129 |
+ } |
|
130 |
+ |
|
131 |
+ switch (cpr->fp_format) { |
|
132 |
+ case FINGERPRINT_RAW: |
|
133 |
+ avio_write(pb, fp, size); |
|
134 |
+ break; |
|
135 |
+ case FINGERPRINT_COMPRESSED: |
|
136 |
+ case FINGERPRINT_BASE64: |
|
137 |
+ if (!chromaprint_encode_fingerprint(fp, size, cpr->algorithm, &enc_fp, &enc_size, |
|
138 |
+ cpr->fp_format == FINGERPRINT_BASE64)) { |
|
139 |
+ av_log(s, AV_LOG_ERROR, "Failed to encode fingerprint\n"); |
|
140 |
+ goto fail; |
|
141 |
+ } |
|
142 |
+ avio_write(pb, enc_fp, enc_size); |
|
143 |
+ break; |
|
144 |
+ } |
|
145 |
+ |
|
146 |
+ ret = 0; |
|
147 |
+fail: |
|
148 |
+ if (fp) |
|
149 |
+ chromaprint_dealloc(fp); |
|
150 |
+ if (enc_fp) |
|
151 |
+ chromaprint_dealloc(enc_fp); |
|
152 |
+ cleanup(cpr); |
|
153 |
+ return ret; |
|
154 |
+} |
|
155 |
+ |
|
156 |
+#define OFFSET(x) offsetof(ChromaprintMuxContext, x) |
|
157 |
+#define FLAGS AV_OPT_FLAG_ENCODING_PARAM |
|
158 |
+static const AVOption options[] = { |
|
159 |
+ { "silence_threshold", "threshold for detecting silence", OFFSET(silence_threshold), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32767, FLAGS }, |
|
160 |
+ { "algorithm", "version of the fingerprint algorithm", OFFSET(algorithm), AV_OPT_TYPE_INT, { .i64 = CHROMAPRINT_ALGORITHM_DEFAULT }, CHROMAPRINT_ALGORITHM_TEST1, INT_MAX, FLAGS }, |
|
161 |
+ { "fp_format", "fingerprint format to write", OFFSET(fp_format), AV_OPT_TYPE_INT, { .i64 = FINGERPRINT_BASE64 }, FINGERPRINT_RAW, FINGERPRINT_BASE64, FLAGS }, |
|
162 |
+ { "raw", "binary raw fingerprint", 0, AV_OPT_TYPE_CONST, {.i64 = FINGERPRINT_RAW }, INT_MIN, INT_MAX, FLAGS, "fp_format"}, |
|
163 |
+ { "compressed", "binary compressed fingerprint", 0, AV_OPT_TYPE_CONST, {.i64 = FINGERPRINT_COMPRESSED }, INT_MIN, INT_MAX, FLAGS, "fp_format"}, |
|
164 |
+ { "base64", "Base64 compressed fingerprint", 0, AV_OPT_TYPE_CONST, {.i64 = FINGERPRINT_BASE64 }, INT_MIN, INT_MAX, FLAGS, "fp_format"}, |
|
165 |
+ { NULL }, |
|
166 |
+}; |
|
167 |
+ |
|
168 |
+static const AVClass chromaprint_class = { |
|
169 |
+ .class_name = "chromaprint muxer", |
|
170 |
+ .item_name = av_default_item_name, |
|
171 |
+ .option = options, |
|
172 |
+ .version = LIBAVUTIL_VERSION_INT, |
|
173 |
+}; |
|
174 |
+ |
|
175 |
+AVOutputFormat ff_chromaprint_muxer = { |
|
176 |
+ .name = "chromaprint", |
|
177 |
+ .long_name = NULL_IF_CONFIG_SMALL("Chromaprint"), |
|
178 |
+ .priv_data_size = sizeof(ChromaprintMuxContext), |
|
179 |
+ .audio_codec = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), |
|
180 |
+ .write_header = write_header, |
|
181 |
+ .write_packet = write_packet, |
|
182 |
+ .write_trailer = write_trailer, |
|
183 |
+ .flags = AVFMT_NOTIMESTAMPS, |
|
184 |
+ .priv_class = &chromaprint_class, |
|
185 |
+}; |
... | ... |
@@ -30,8 +30,8 @@ |
30 | 30 |
#include "libavutil/version.h" |
31 | 31 |
|
32 | 32 |
#define LIBAVFORMAT_VERSION_MAJOR 57 |
33 |
-#define LIBAVFORMAT_VERSION_MINOR 2 |
|
34 |
-#define LIBAVFORMAT_VERSION_MICRO 102 |
|
33 |
+#define LIBAVFORMAT_VERSION_MINOR 3 |
|
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, \ |