forked from mixxxdj/mixxx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
soundsourcemediafoundation.h
112 lines (85 loc) · 3.71 KB
/
soundsourcemediafoundation.h
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
#pragma once
#include <mfidl.h>
#include <mfreadwrite.h>
#include "sources/soundsourceprovider.h"
#include "util/readaheadsamplebuffer.h"
namespace mixxx {
class StreamUnitConverter final {
const static SINT kStreamUnitsPerSecond = 1000 * 1000 * 10; // frame length = 100 ns
public:
StreamUnitConverter()
: m_pAudioSource(nullptr),
m_fromSampleFramesToStreamUnits(0),
m_fromStreamUnitsToSampleFrames(0) {
}
explicit StreamUnitConverter(const AudioSource* pAudioSource)
: m_pAudioSource(pAudioSource),
m_fromSampleFramesToStreamUnits(double(kStreamUnitsPerSecond) / double(pAudioSource->getSignalInfo().getSampleRate())),
m_fromStreamUnitsToSampleFrames(double(pAudioSource->getSignalInfo().getSampleRate()) / double(kStreamUnitsPerSecond)) {
// The stream units should actually be much shorter than
// sample frames to minimize jitter and rounding. Even a
// frame at 192 kHz has a length of about 5000 ns >> 100 ns.
DEBUG_ASSERT(m_fromSampleFramesToStreamUnits > 50);
DEBUG_ASSERT(m_fromStreamUnitsToSampleFrames < 0.02);
}
LONGLONG fromFrameIndex(SINT frameIndex) const {
DEBUG_ASSERT(m_fromSampleFramesToStreamUnits > 0);
// Used for seeking, so we need to round down to hit the
// corresponding stream unit where the given stream unit
// starts. The reader will skip samples until it reaches
// the actual target position for reading.
const SINT frameIndexOffset = frameIndex - m_pAudioSource->frameIndexMin();
return static_cast<LONGLONG>(floor(frameIndexOffset * m_fromSampleFramesToStreamUnits));
}
SINT toFrameIndex(LONGLONG streamPos) const {
DEBUG_ASSERT(m_fromStreamUnitsToSampleFrames > 0);
// The stream reports positions in units of 100ns. We have
// to round(!) this value to obtain the actual position in
// sample frames.
const SINT frameIndexOffset = static_cast<SINT>(round(streamPos * m_fromStreamUnitsToSampleFrames));
return m_pAudioSource->frameIndexMin() + frameIndexOffset;
}
private:
const AudioSource* m_pAudioSource;
double m_fromSampleFramesToStreamUnits;
double m_fromStreamUnitsToSampleFrames;
};
class SoundSourceMediaFoundation : public SoundSource {
public:
static const QString kDisplayName;
explicit SoundSourceMediaFoundation(const QUrl& url);
~SoundSourceMediaFoundation() override;
void close() override;
protected:
ReadableSampleFrames readSampleFramesClamped(
const WritableSampleFrames& sampleFrames) override;
private:
OpenResult tryOpen(
OpenMode mode,
const AudioSource::OpenParams& params) override;
bool configureAudioStream(const AudioSource::OpenParams& params);
bool readProperties();
void seekSampleFrame(SINT frameIndex);
HRESULT m_hrCoInitialize;
HRESULT m_hrMFStartup;
IMFSourceReader* m_pSourceReader;
StreamUnitConverter m_streamUnitConverter;
SINT m_currentFrameIndex;
ReadAheadSampleBuffer m_sampleBuffer;
};
class SoundSourceProviderMediaFoundation : public SoundSourceProvider {
public:
static const QString kDisplayName;
static const QStringList kSupportedFileTypes;
QString getDisplayName() const override {
return kDisplayName + QChar(' ') + getVersionString();
}
QStringList getSupportedFileTypes() const override {
return kSupportedFileTypes;
}
SoundSourceProviderPriority getPriorityHint(
const QString& supportedFileType) const override;
SoundSourcePointer newSoundSource(const QUrl& url) override;
QString getVersionString() const;
};
} // namespace mixxx