2 * Chromaprint fingerprinting muxer
3 * Copyright (c) 2015 rcombs
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/opt.h"
25 #include "libavutil/thread.h"
26 #include <chromaprint.h>
28 #define CPR_VERSION_INT AV_VERSION_INT(CHROMAPRINT_VERSION_MAJOR, \
29 CHROMAPRINT_VERSION_MINOR, \
30 CHROMAPRINT_VERSION_PATCH)
32 static AVMutex chromaprint_mutex
= AV_MUTEX_INITIALIZER
;
34 typedef enum FingerprintFormat
{
36 FINGERPRINT_COMPRESSED
,
40 typedef struct ChromaprintMuxContext
{
42 int silence_threshold
;
44 FingerprintFormat fp_format
;
45 #if CPR_VERSION_INT >= AV_VERSION_INT(1, 4, 0)
46 ChromaprintContext
*ctx
;
48 ChromaprintContext ctx
;
50 } ChromaprintMuxContext
;
52 static void deinit(AVFormatContext
*s
)
54 ChromaprintMuxContext
*const cpr
= s
->priv_data
;
57 ff_mutex_lock(&chromaprint_mutex
);
58 chromaprint_free(cpr
->ctx
);
59 ff_mutex_unlock(&chromaprint_mutex
);
63 static av_cold
int init(AVFormatContext
*s
)
65 ChromaprintMuxContext
*cpr
= s
->priv_data
;
68 ff_mutex_lock(&chromaprint_mutex
);
69 cpr
->ctx
= chromaprint_new(cpr
->algorithm
);
70 ff_mutex_unlock(&chromaprint_mutex
);
73 av_log(s
, AV_LOG_ERROR
, "Failed to create chromaprint context.\n");
74 return AVERROR_EXTERNAL
;
77 if (cpr
->silence_threshold
!= -1) {
78 #if CPR_VERSION_INT >= AV_VERSION_INT(0, 7, 0)
79 if (!chromaprint_set_option(cpr
->ctx
, "silence_threshold", cpr
->silence_threshold
)) {
80 av_log(s
, AV_LOG_ERROR
, "Failed to set silence threshold. Setting silence_threshold requires -algorithm 3 option.\n");
81 return AVERROR_EXTERNAL
;
84 av_log(s
, AV_LOG_ERROR
, "Setting the silence threshold requires Chromaprint "
85 "version 0.7.0 or later.\n");
86 return AVERROR(ENOSYS
);
92 if (st
->codecpar
->ch_layout
.nb_channels
> 2) {
93 av_log(s
, AV_LOG_ERROR
, "Only up to 2 channels are supported\n");
94 return AVERROR(EINVAL
);
97 if (st
->codecpar
->sample_rate
< 1000) {
98 av_log(s
, AV_LOG_ERROR
, "Sampling rate must be at least 1000\n");
99 return AVERROR(EINVAL
);
102 if (!chromaprint_start(cpr
->ctx
, st
->codecpar
->sample_rate
, st
->codecpar
->ch_layout
.nb_channels
)) {
103 av_log(s
, AV_LOG_ERROR
, "Failed to start chromaprint\n");
104 return AVERROR_EXTERNAL
;
110 static int write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
112 ChromaprintMuxContext
*cpr
= s
->priv_data
;
113 return chromaprint_feed(cpr
->ctx
, (const int16_t *)pkt
->data
, pkt
->size
/ 2) ? 0 : AVERROR(EINVAL
);
116 static int write_trailer(AVFormatContext
*s
)
118 ChromaprintMuxContext
*cpr
= s
->priv_data
;
119 AVIOContext
*pb
= s
->pb
;
122 int size
, enc_size
, ret
= AVERROR_EXTERNAL
;
124 if (!chromaprint_finish(cpr
->ctx
)) {
125 av_log(s
, AV_LOG_ERROR
, "Failed to generate fingerprint\n");
129 if (!chromaprint_get_raw_fingerprint(cpr
->ctx
, (uint32_t **)&fp
, &size
)) {
130 av_log(s
, AV_LOG_ERROR
, "Failed to retrieve fingerprint\n");
134 switch (cpr
->fp_format
) {
135 case FINGERPRINT_RAW
:
136 avio_write(pb
, fp
, size
* 4); //fp points to array of uint32_t
138 case FINGERPRINT_COMPRESSED
:
139 case FINGERPRINT_BASE64
:
140 if (!chromaprint_encode_fingerprint(fp
, size
, cpr
->algorithm
, &enc_fp
, &enc_size
,
141 cpr
->fp_format
== FINGERPRINT_BASE64
)) {
142 av_log(s
, AV_LOG_ERROR
, "Failed to encode fingerprint\n");
145 avio_write(pb
, enc_fp
, enc_size
);
152 chromaprint_dealloc(fp
);
154 chromaprint_dealloc(enc_fp
);
158 #define OFFSET(x) offsetof(ChromaprintMuxContext, x)
159 #define FLAGS AV_OPT_FLAG_ENCODING_PARAM
160 static const AVOption options
[] = {
161 { "silence_threshold", "threshold for detecting silence", OFFSET(silence_threshold
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, 32767, FLAGS
},
162 { "algorithm", "version of the fingerprint algorithm", OFFSET(algorithm
), AV_OPT_TYPE_INT
, { .i64
= CHROMAPRINT_ALGORITHM_DEFAULT
}, CHROMAPRINT_ALGORITHM_TEST1
, INT_MAX
, FLAGS
},
163 { "fp_format", "fingerprint format to write", OFFSET(fp_format
), AV_OPT_TYPE_INT
, { .i64
= FINGERPRINT_BASE64
}, FINGERPRINT_RAW
, FINGERPRINT_BASE64
, FLAGS
, .unit
= "fp_format" },
164 { "raw", "binary raw fingerprint", 0, AV_OPT_TYPE_CONST
, {.i64
= FINGERPRINT_RAW
}, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "fp_format"},
165 { "compressed", "binary compressed fingerprint", 0, AV_OPT_TYPE_CONST
, {.i64
= FINGERPRINT_COMPRESSED
}, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "fp_format"},
166 { "base64", "Base64 compressed fingerprint", 0, AV_OPT_TYPE_CONST
, {.i64
= FINGERPRINT_BASE64
}, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "fp_format"},
170 static const AVClass chromaprint_class
= {
171 .class_name
= "chromaprint muxer",
172 .item_name
= av_default_item_name
,
174 .version
= LIBAVUTIL_VERSION_INT
,
177 const FFOutputFormat ff_chromaprint_muxer
= {
178 .p
.name
= "chromaprint",
179 .p
.long_name
= NULL_IF_CONFIG_SMALL("Chromaprint"),
180 .priv_data_size
= sizeof(ChromaprintMuxContext
),
181 .p
.audio_codec
= AV_NE(AV_CODEC_ID_PCM_S16BE
, AV_CODEC_ID_PCM_S16LE
),
182 .p
.video_codec
= AV_CODEC_ID_NONE
,
183 .p
.subtitle_codec
= AV_CODEC_ID_NONE
,
184 .flags_internal
= FF_OFMT_FLAG_MAX_ONE_OF_EACH
|
185 FF_OFMT_FLAG_ONLY_DEFAULT_CODECS
,
187 .write_packet
= write_packet
,
188 .write_trailer
= write_trailer
,
190 .p
.flags
= AVFMT_NOTIMESTAMPS
,
191 .p
.priv_class
= &chromaprint_class
,