forked from jfchapman/VUPlayer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DecoderOpus.cpp
135 lines (130 loc) · 4.58 KB
/
DecoderOpus.cpp
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
#include "DecoderOpus.h"
#include "Utility.h"
DecoderOpus::DecoderOpus( const std::wstring& filename ) :
Decoder(),
m_OpusFile( nullptr )
{
int error = 0;
const std::string filepath = WideStringToUTF8( filename );
m_OpusFile = op_open_file( filepath.c_str(), &error );
if ( nullptr != m_OpusFile ) {
const OpusHead* head = op_head( m_OpusFile, -1 /*link*/ );
if ( nullptr != head ) {
SetSampleRate( 48000 );
SetChannels( head->channel_count );
const ogg_int64_t pcmTotal = op_pcm_total( m_OpusFile, -1 /*link*/ );
SetDuration( static_cast<float>( pcmTotal ) / 48000 );
const opus_int32 bitrate = op_bitrate( m_OpusFile, -1 );
if ( bitrate > 0 ) {
SetBitrate( static_cast<float>( bitrate ) / 1000 );
}
}
} else {
throw std::runtime_error( "DecoderOpus could not load file" );
}
}
DecoderOpus::~DecoderOpus()
{
if ( nullptr != m_OpusFile ) {
op_free( m_OpusFile );
}
}
long DecoderOpus::Read( float* buffer, const long sampleCount )
{
long samplesRead = 0;
const long channels = GetChannels();
if ( ( channels > 0 ) && ( sampleCount > 0 ) ) {
while ( samplesRead < sampleCount ) {
const int samplesToRead = sampleCount - samplesRead;
const int bufSize = samplesToRead * channels;
const int result = op_read_float( m_OpusFile, buffer + samplesRead * channels, bufSize, nullptr /*link*/ );
if ( result > 0 ) {
// For multi-channel streams, change from Opus to BASS channel ordering.
switch ( channels ) {
case 3 : {
// (left, center, right) ->
// (left, right, center)
int offset = samplesRead * channels;
for ( int n = 0; n < result; n++, offset += channels ) {
std::swap( buffer[ offset + 1 ], buffer[ offset + 2 ] );
}
break;
}
case 5 : {
// (front left, front center, front right, rear left, rear right) ->
// (front left, front right, front center, rear left, rear right)
int offset = samplesRead * channels;
for ( int n = 0; n < result; n++, offset += channels ) {
std::swap( buffer[ offset + 1 ], buffer[ offset + 2 ] );
}
break;
}
case 6 : {
// (front left, front center, front right, rear left, rear right, LFE) ->
// (front left, front right, front center, LFE, rear left, rear right)
int offset = samplesRead * channels;
for ( int n = 0; n < result; n++, offset += channels ) {
std::swap( buffer[ offset + 1 ], buffer[ offset + 2 ] );
const float rearL = buffer[ offset + 3 ];
const float rearR = buffer[ offset + 4 ];
const float lfe = buffer[ offset + 5 ];
buffer[ offset + 3 ] = lfe;
buffer[ offset + 4 ] = rearL;
buffer[ offset + 5 ] = rearR;
}
break;
}
case 7 : {
// (front left, front center, front right, side left, side right, rear center, LFE) ->
// (front left, front right, front center, LFE, rear center, side left, side right)
int offset = samplesRead * channels;
for ( int n = 0; n < result; n++, offset += channels ) {
std::swap( buffer[ offset + 1 ], buffer[ offset + 2 ] );
const float sideL = buffer[ offset + 3 ];
const float sideR = buffer[ offset + 4 ];
const float rearC = buffer[ offset + 5 ];
const float lfe = buffer[ offset + 6 ];
buffer[ offset + 3 ] = lfe;
buffer[ offset + 4 ] = rearC;
buffer[ offset + 5 ] = sideL;
buffer[ offset + 6 ] = sideR;
}
break;
}
case 8 : {
// (front left, front center, front right, side left, side right, rear left, rear right, LFE) ->
// (front left, front right, front center, LFE, rear left, rear right, side left, side right)
int offset = samplesRead * channels;
for ( int n = 0; n < result; n++, offset += channels ) {
std::swap( buffer[ offset + 1 ], buffer[ offset + 2 ] );
const float sideL = buffer[ offset + 3 ];
const float sideR = buffer[ offset + 4 ];
const float rearL = buffer[ offset + 5 ];
const float rearR = buffer[ offset + 6 ];
const float lfe = buffer[ offset + 7 ];
buffer[ offset + 3 ] = lfe;
buffer[ offset + 4 ] = rearL;
buffer[ offset + 5 ] = rearR;
buffer[ offset + 6 ] = sideL;
buffer[ offset + 7 ] = sideR;
}
break;
}
default: {
break;
}
}
samplesRead += result;
} else {
break;
}
}
}
return samplesRead;
}
float DecoderOpus::Seek( const float position )
{
const ogg_int64_t offset = static_cast<ogg_int64_t>( position * GetSampleRate() );
const float seekPosition = ( 0 == op_pcm_seek( m_OpusFile, offset ) ) ? position : 0;
return seekPosition;
}