-
Notifications
You must be signed in to change notification settings - Fork 187
/
FingerprintCommand.cs
206 lines (178 loc) · 9.44 KB
/
FingerprintCommand.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
namespace SoundFingerprinting.Command
{
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SoundFingerprinting.Audio;
using SoundFingerprinting.Builder;
using SoundFingerprinting.Configuration;
using SoundFingerprinting.Content;
using SoundFingerprinting.Data;
using SoundFingerprinting.Media;
using SoundFingerprinting.Video;
/// <summary>
/// Fingerprint command class that configures and builds the fingerprints from a source content file.
/// </summary>
/// <remarks>
/// Create and configure with <see cref="FingerprintCommandBuilder"/> class.
/// </remarks>
public sealed class FingerprintCommand : ISourceFrom, IWithFingerprintConfiguration
{
private readonly IFingerprintService fingerprintService;
private readonly ILogger<FingerprintCommand> logger;
private Func<AVHashes> createFingerprintsMethod;
private IAudioService audioService;
private IVideoService? videoService;
private IMediaService? mediaService;
private AVFingerprintConfiguration fingerprintConfiguration;
internal FingerprintCommand(IFingerprintService fingerprintService, ILoggerFactory loggerFactory)
{
this.fingerprintService = fingerprintService;
audioService = new SoundFingerprintingAudioService();
fingerprintConfiguration = new DefaultAVFingerprintConfiguration();
createFingerprintsMethod = () => AVHashes.Empty;
logger = loggerFactory.CreateLogger<FingerprintCommand>();
}
/// <inheritdoc cref="IFingerprintCommand.Hash"/>
public Task<AVHashes> Hash()
{
return Task.Factory.StartNew(createFingerprintsMethod);
}
/// <inheritdoc cref="ISourceFrom.From(string, MediaType)"/>
public IWithFingerprintConfiguration From(string file, MediaType mediaType = MediaType.Audio)
{
return From(file, 0d, 0d, mediaType);
}
/// <inheritdoc cref="ISourceFrom.From(AudioSamples)"/>
public IWithFingerprintConfiguration From(AudioSamples audioSamples)
{
createFingerprintsMethod = () => GetAvHashes(audioSamples);
return this;
}
/// <inheritdoc cref="ISourceFrom.From(Frames)"/>
public IWithFingerprintConfiguration From(Frames frames)
{
createFingerprintsMethod = () => GetAvHashes(frames);
return this;
}
/// <inheritdoc cref="ISourceFrom.From(AVTrack)"/>
public IWithFingerprintConfiguration From(AVTrack avTrack)
{
createFingerprintsMethod = () => GetAvHashes(avTrack);
return this;
}
/// <inheritdoc cref="ISourceFrom.From(string,double,double,MediaType)"/>
public IWithFingerprintConfiguration From(string file, double secondsToProcess, double startAtSecond, MediaType mediaType = MediaType.Audio)
{
createFingerprintsMethod = () =>
{
if (mediaType.HasFlag(MediaType.Video) && videoService == null && mediaService == null)
{
throw new ArgumentException("You need to specify a valid instance of IVideoService or IMediaService if you want to process video content from the file.");
}
// both audio and video are requested.
if (mediaType.HasFlag(MediaType.Audio | MediaType.Video))
{
if (mediaService != null)
{
logger.LogDebug("Using media service {0} to read AVTrack from file {1}", mediaService, file);
var avTrack = mediaService.ReadAVTrackFromFile(file, fingerprintConfiguration.GetTrackReadConfiguration(), secondsToProcess, startAtSecond, mediaType);
return GetAvHashes(avTrack);
}
var audioSamples = audioService.ReadMonoSamplesFromFile(file, fingerprintConfiguration.Audio.SampleRate, secondsToProcess, startAtSecond);
var frames = videoService!.ReadFramesFromFile(file, fingerprintConfiguration.GetTrackReadConfiguration().VideoConfig, secondsToProcess, startAtSecond);
return GetAvHashes(audioSamples, frames);
}
if (mediaType.HasFlag(MediaType.Audio))
{
// media service has precedence since audio service is set by default.
var serviceToUse = mediaService ?? audioService;
logger.LogDebug("Using service {Service} to read audio samples from file {File}", serviceToUse, file);
AudioSamples audioSamples = serviceToUse.ReadMonoSamplesFromFile(file, fingerprintConfiguration.Audio.SampleRate, secondsToProcess, startAtSecond);
return GetAvHashes(audioSamples);
}
if (mediaType.HasFlag(MediaType.Video))
{
// media service is used by default.
var serviceToUse = mediaService ?? videoService;
logger.LogDebug("Using service {Service} to read frames from file {File}", serviceToUse, file);
var frames = serviceToUse!.ReadFramesFromFile(file, fingerprintConfiguration.GetTrackReadConfiguration().VideoConfig, secondsToProcess, startAtSecond);
return GetAvHashes(frames);
}
logger.LogError("Unknown media type specified in fingerprint creation method {MediaType}. Returning empty hashes", mediaType);
return AVHashes.Empty;
};
return this;
}
/// <inheritdoc cref="IWithFingerprintConfiguration.WithFingerprintConfig(AVFingerprintConfiguration)"/>
public IUsingFingerprintServices WithFingerprintConfig(AVFingerprintConfiguration configuration)
{
fingerprintConfiguration = configuration;
return this;
}
/// <inheritdoc cref="IWithFingerprintConfiguration.WithFingerprintConfig(Func{AVFingerprintConfiguration,AVFingerprintConfiguration})"/>
public IUsingFingerprintServices WithFingerprintConfig(Func<AVFingerprintConfiguration, AVFingerprintConfiguration> amendFunctor)
{
fingerprintConfiguration = amendFunctor(fingerprintConfiguration);
return this;
}
/// <inheritdoc cref="IUsingFingerprintServices.UsingServices(IAudioService)"/>
public IFingerprintCommand UsingServices(IAudioService audioService)
{
this.audioService = audioService;
return this;
}
/// <inheritdoc cref="IUsingFingerprintServices.UsingServices(IVideoService)"/>
public IFingerprintCommand UsingServices(IVideoService videoService)
{
this.videoService = videoService;
return this;
}
/// <inheritdoc cref="IUsingFingerprintServices.UsingServices(IMediaService)"/>
public IFingerprintCommand UsingServices(IMediaService mediaService)
{
this.mediaService = mediaService;
return this;
}
private AVHashes GetAvHashes(AVTrack avTrack)
{
long audioElapsedMilliseconds = 0, videoElapsedMilliseconds = 0;
var (audioTrack, videoTrack) = avTrack;
var audio = audioTrack != null ? GetHashes(audioTrack.Samples, out audioElapsedMilliseconds) : null;
var video = videoTrack != null ? GetHashes(videoTrack.Frames, out videoElapsedMilliseconds) : null;
return new AVHashes(audio?.Hashes, video?.Hashes, new AVFingerprintingTime(audioElapsedMilliseconds, videoElapsedMilliseconds));
}
private AVHashes GetAvHashes(AudioSamples audioSamples, Frames frames)
{
var audio = GetHashes(audioSamples, out long audioElapsedMilliseconds);
var video = GetHashes(frames, out long videoElapsedMilliseconds);
return new AVHashes(audio.Hashes, video.Hashes, new AVFingerprintingTime(audioElapsedMilliseconds, videoElapsedMilliseconds));
}
private AVHashes GetAvHashes(AudioSamples audioSamples)
{
var audio = GetHashes(audioSamples, out long elapsedMilliseconds);
return new AVHashes(audio.Hashes, null, new AVFingerprintingTime(elapsedMilliseconds, 0));
}
private AVHashes GetAvHashes(Frames frames)
{
var video = GetHashes(frames, out long elapsedMilliseconds);
return new AVHashes(null, video.Hashes, new AVFingerprintingTime(0, elapsedMilliseconds));
}
private FingerprintsAndHashes GetHashes(AudioSamples audioSamples, out long elapsedMilliseconds)
{
var stopwatch = Stopwatch.StartNew();
var hashes = fingerprintService.CreateFingerprintsFromAudioSamples(audioSamples, fingerprintConfiguration.Audio);
elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
return hashes;
}
private FingerprintsAndHashes GetHashes(Frames frames, out long elapsedMilliseconds)
{
var stopwatch = Stopwatch.StartNew();
var videoHashes = fingerprintService.CreateFingerprintsFromImageFrames(frames, fingerprintConfiguration.Video);
elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
return videoHashes;
}
}
}