Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
33c5da70
Commit
33c5da70
authored
May 03, 2016
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
encoder/opus: move functions into the struct
parent
48d3af7d
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
168 additions
and
128 deletions
+168
-128
OpusEncoderPlugin.cxx
src/encoder/plugins/OpusEncoderPlugin.cxx
+168
-128
No files found.
src/encoder/plugins/OpusEncoderPlugin.cxx
View file @
33c5da70
...
...
@@ -67,42 +67,59 @@ struct OpusEncoder {
ogg_int64_t
granulepos
;
OpusEncoder
()
:
encoder
(
opus_encoder_plugin
),
granulepos
(
0
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
bool
Open
(
AudioFormat
&
audio_format
,
Error
&
error
);
void
Close
();
bool
DoEncode
(
bool
eos
,
Error
&
error
);
bool
End
(
Error
&
error
);
bool
Flush
(
Error
&
error
);
bool
WriteSilence
(
unsigned
fill_frames
,
Error
&
error
);
bool
Write
(
const
void
*
_data
,
size_t
length
,
Error
&
error
);
void
GenerateHead
();
void
GenerateTags
();
size_t
Read
(
void
*
dest
,
size_t
length
);
};
static
constexpr
Domain
opus_encoder_domain
(
"opus_encoder"
);
static
bool
opus_encoder_configure
(
OpusEncoder
*
encoder
,
const
ConfigBlock
&
block
,
Error
&
error
)
bool
OpusEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
const
char
*
value
=
block
.
GetBlockValue
(
"bitrate"
,
"auto"
);
if
(
strcmp
(
value
,
"auto"
)
==
0
)
encoder
->
bitrate
=
OPUS_AUTO
;
bitrate
=
OPUS_AUTO
;
else
if
(
strcmp
(
value
,
"max"
)
==
0
)
encoder
->
bitrate
=
OPUS_BITRATE_MAX
;
bitrate
=
OPUS_BITRATE_MAX
;
else
{
char
*
endptr
;
encoder
->
bitrate
=
strtoul
(
value
,
&
endptr
,
10
);
bitrate
=
strtoul
(
value
,
&
endptr
,
10
);
if
(
endptr
==
value
||
*
endptr
!=
0
||
encoder
->
bitrate
<
500
||
encoder
->
bitrate
>
512000
)
{
bitrate
<
500
||
bitrate
>
512000
)
{
error
.
Set
(
config_domain
,
"Invalid bit rate"
);
return
false
;
}
}
encoder
->
complexity
=
block
.
GetBlockValue
(
"complexity"
,
10u
);
if
(
encoder
->
complexity
>
10
)
{
complexity
=
block
.
GetBlockValue
(
"complexity"
,
10u
);
if
(
complexity
>
10
)
{
error
.
Format
(
config_domain
,
"Invalid complexity"
);
return
false
;
}
value
=
block
.
GetBlockValue
(
"signal"
,
"auto"
);
if
(
strcmp
(
value
,
"auto"
)
==
0
)
encoder
->
signal
=
OPUS_AUTO
;
signal
=
OPUS_AUTO
;
else
if
(
strcmp
(
value
,
"voice"
)
==
0
)
encoder
->
signal
=
OPUS_SIGNAL_VOICE
;
signal
=
OPUS_SIGNAL_VOICE
;
else
if
(
strcmp
(
value
,
"music"
)
==
0
)
encoder
->
signal
=
OPUS_SIGNAL_MUSIC
;
signal
=
OPUS_SIGNAL_MUSIC
;
else
{
error
.
Format
(
config_domain
,
"Invalid signal"
);
return
false
;
...
...
@@ -117,7 +134,7 @@ opus_encoder_init(const ConfigBlock &block, Error &error)
auto
*
encoder
=
new
OpusEncoder
();
/* load configuration from "block" */
if
(
!
opus_encoder_configure
(
encoder
,
block
,
error
))
{
if
(
!
encoder
->
Configure
(
block
,
error
))
{
/* configuration has failed, roll back and return error */
delete
encoder
;
return
nullptr
;
...
...
@@ -136,213 +153,231 @@ opus_encoder_finish(Encoder *_encoder)
delete
encoder
;
}
static
bool
opus_encoder_open
(
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
bool
OpusEncoder
::
Open
(
AudioFormat
&
_audio_format
,
Error
&
error
)
{
auto
*
encoder
=
(
OpusEncoder
*
)
_encoder
;
/* libopus supports only 48 kHz */
audio_format
.
sample_rate
=
48000
;
_
audio_format
.
sample_rate
=
48000
;
if
(
audio_format
.
channels
>
2
)
audio_format
.
channels
=
1
;
if
(
_
audio_format
.
channels
>
2
)
_
audio_format
.
channels
=
1
;
switch
(
audio_format
.
format
)
{
switch
(
_
audio_format
.
format
)
{
case
SampleFormat
:
:
S16
:
case
SampleFormat
:
:
FLOAT
:
break
;
case
SampleFormat
:
:
S8
:
audio_format
.
format
=
SampleFormat
::
S16
;
_
audio_format
.
format
=
SampleFormat
::
S16
;
break
;
default
:
audio_format
.
format
=
SampleFormat
::
FLOAT
;
_
audio_format
.
format
=
SampleFormat
::
FLOAT
;
break
;
}
encoder
->
audio_format
=
audio_format
;
encoder
->
frame_size
=
audio_format
.
GetFrameSize
();
audio_format
=
_
audio_format
;
frame_size
=
_
audio_format
.
GetFrameSize
();
int
error_code
;
enc
oder
->
enc
=
opus_encoder_create
(
audio_format
.
sample_rate
,
audio_format
.
channels
,
enc
=
opus_encoder_create
(
_
audio_format
.
sample_rate
,
_
audio_format
.
channels
,
OPUS_APPLICATION_AUDIO
,
&
error_code
);
if
(
enc
oder
->
enc
==
nullptr
)
{
if
(
enc
==
nullptr
)
{
error
.
Set
(
opus_encoder_domain
,
error_code
,
opus_strerror
(
error_code
));
return
false
;
}
opus_encoder_ctl
(
encoder
->
enc
,
OPUS_SET_BITRATE
(
encoder
->
bitrate
));
opus_encoder_ctl
(
encoder
->
enc
,
OPUS_SET_COMPLEXITY
(
encoder
->
complexity
));
opus_encoder_ctl
(
encoder
->
enc
,
OPUS_SET_SIGNAL
(
encoder
->
signal
));
opus_encoder_ctl
(
enc
,
OPUS_SET_BITRATE
(
bitrate
));
opus_encoder_ctl
(
enc
,
OPUS_SET_COMPLEXITY
(
complexity
));
opus_encoder_ctl
(
enc
,
OPUS_SET_SIGNAL
(
signal
));
opus_encoder_ctl
(
enc
oder
->
enc
,
OPUS_GET_LOOKAHEAD
(
&
encoder
->
lookahead
));
opus_encoder_ctl
(
enc
,
OPUS_GET_LOOKAHEAD
(
&
lookahead
));
encoder
->
buffer_frames
=
audio_format
.
sample_rate
/
50
;
encoder
->
buffer_size
=
encoder
->
frame_size
*
encoder
->
buffer_frames
;
encoder
->
buffer_position
=
0
;
encoder
->
buffer
=
(
unsigned
char
*
)
xalloc
(
encoder
->
buffer_size
);
buffer_frames
=
_
audio_format
.
sample_rate
/
50
;
buffer_size
=
frame_size
*
buffer_frames
;
buffer_position
=
0
;
buffer
=
(
unsigned
char
*
)
xalloc
(
buffer_size
);
encoder
->
stream
.
Initialize
(
GenerateOggSerial
());
encoder
->
packetno
=
0
;
stream
.
Initialize
(
GenerateOggSerial
());
packetno
=
0
;
return
true
;
}
static
bool
opus_encoder_open
(
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
return
encoder
.
Open
(
audio_format
,
error
);
}
void
OpusEncoder
::
Close
()
{
stream
.
Deinitialize
();
free
(
buffer
);
opus_encoder_destroy
(
enc
);
}
static
void
opus_encoder_close
(
Encoder
*
_encoder
)
{
auto
*
encoder
=
(
OpusEncoder
*
)
_encoder
;
encoder
->
stream
.
Deinitialize
();
free
(
encoder
->
buffer
);
opus_encoder_destroy
(
encoder
->
enc
);
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
encoder
.
Close
();
}
static
bool
opus_encoder_do_encode
(
OpusEncoder
*
encoder
,
bool
eos
,
Error
&
error
)
bool
OpusEncoder
::
DoEncode
(
bool
eos
,
Error
&
error
)
{
assert
(
encoder
->
buffer_position
==
encoder
->
buffer_size
);
assert
(
buffer_position
==
buffer_size
);
opus_int32
result
=
encoder
->
audio_format
.
format
==
SampleFormat
::
S16
?
opus_encode
(
enc
oder
->
enc
,
(
const
opus_int16
*
)
encoder
->
buffer
,
encoder
->
buffer_frames
,
encoder
->
buffer2
,
sizeof
(
encoder
->
buffer2
))
:
opus_encode_float
(
enc
oder
->
enc
,
(
const
float
*
)
encoder
->
buffer
,
encoder
->
buffer_frames
,
encoder
->
buffer2
,
sizeof
(
encoder
->
buffer2
));
audio_format
.
format
==
SampleFormat
::
S16
?
opus_encode
(
enc
,
(
const
opus_int16
*
)
buffer
,
buffer_frames
,
buffer2
,
sizeof
(
buffer2
))
:
opus_encode_float
(
enc
,
(
const
float
*
)
buffer
,
buffer_frames
,
buffer2
,
sizeof
(
buffer2
));
if
(
result
<
0
)
{
error
.
Set
(
opus_encoder_domain
,
"Opus encoder error"
);
return
false
;
}
encoder
->
granulepos
+=
encoder
->
buffer_frames
;
granulepos
+=
buffer_frames
;
ogg_packet
packet
;
packet
.
packet
=
encoder
->
buffer2
;
packet
.
packet
=
buffer2
;
packet
.
bytes
=
result
;
packet
.
b_o_s
=
false
;
packet
.
e_o_s
=
eos
;
packet
.
granulepos
=
encoder
->
granulepos
;
packet
.
packetno
=
encoder
->
packetno
++
;
encoder
->
stream
.
PacketIn
(
packet
);
packet
.
granulepos
=
granulepos
;
packet
.
packetno
=
packetno
++
;
stream
.
PacketIn
(
packet
);
encoder
->
buffer_position
=
0
;
buffer_position
=
0
;
return
true
;
}
static
bool
opus_encoder_end
(
Encoder
*
_encoder
,
Error
&
error
)
bool
OpusEncoder
::
End
(
Error
&
error
)
{
auto
*
encoder
=
(
OpusEncoder
*
)
_encoder
;
encoder
->
stream
.
Flush
();
stream
.
Flush
();
memset
(
encoder
->
buffer
+
encoder
->
buffer_position
,
0
,
encoder
->
buffer_size
-
encoder
->
buffer_position
);
encoder
->
buffer_position
=
encoder
->
buffer_size
;
memset
(
buffer
+
buffer_position
,
0
,
buffer_size
-
buffer_position
);
buffer_position
=
buffer_size
;
return
opus_encoder_do_encode
(
encoder
,
true
,
error
);
return
DoEncode
(
true
,
error
);
}
static
bool
opus_encoder_
flush
(
Encoder
*
_encoder
,
gcc_unused
Error
&
error
)
opus_encoder_
end
(
Encoder
*
_encoder
,
Error
&
error
)
{
auto
*
encoder
=
(
OpusEncoder
*
)
_encoder
;
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
return
encoder
.
End
(
error
);
}
encoder
->
stream
.
Flush
();
bool
OpusEncoder
::
Flush
(
gcc_unused
Error
&
error
)
{
stream
.
Flush
();
return
true
;
}
static
bool
opus_encoder_write_silence
(
OpusEncoder
*
encoder
,
unsigned
fill_frames
,
Error
&
error
)
opus_encoder_flush
(
Encoder
*
_encoder
,
Error
&
error
)
{
size_t
fill_bytes
=
fill_frames
*
encoder
->
frame_size
;
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
return
encoder
.
Flush
(
error
);
}
bool
OpusEncoder
::
WriteSilence
(
unsigned
fill_frames
,
Error
&
error
)
{
size_t
fill_bytes
=
fill_frames
*
frame_size
;
while
(
fill_bytes
>
0
)
{
size_t
nbytes
=
encoder
->
buffer_size
-
encoder
->
buffer_position
;
size_t
nbytes
=
buffer_size
-
buffer_position
;
if
(
nbytes
>
fill_bytes
)
nbytes
=
fill_bytes
;
memset
(
encoder
->
buffer
+
encoder
->
buffer_position
,
0
,
nbytes
);
encoder
->
buffer_position
+=
nbytes
;
memset
(
buffer
+
buffer_position
,
0
,
nbytes
);
buffer_position
+=
nbytes
;
fill_bytes
-=
nbytes
;
if
(
encoder
->
buffer_position
==
encoder
->
buffer_size
&&
!
opus_encoder_do_encode
(
encoder
,
false
,
error
))
if
(
buffer_position
==
buffer_size
&&
!
DoEncode
(
false
,
error
))
return
false
;
}
return
true
;
}
static
bool
opus_encoder_write
(
Encoder
*
_encoder
,
const
void
*
_data
,
size_t
length
,
Error
&
error
)
bool
OpusEncoder
::
Write
(
const
void
*
_data
,
size_t
length
,
Error
&
error
)
{
auto
*
encoder
=
(
OpusEncoder
*
)
_encoder
;
const
uint8_t
*
data
=
(
const
uint8_t
*
)
_data
;
if
(
encoder
->
lookahead
>
0
)
{
if
(
lookahead
>
0
)
{
/* generate some silence at the beginning of the
stream */
assert
(
encoder
->
buffer_position
==
0
);
assert
(
buffer_position
==
0
);
if
(
!
opus_encoder_write_silence
(
encoder
,
encoder
->
lookahead
,
error
))
if
(
!
WriteSilence
(
lookahead
,
error
))
return
false
;
encoder
->
lookahead
=
0
;
lookahead
=
0
;
}
while
(
length
>
0
)
{
size_t
nbytes
=
encoder
->
buffer_size
-
encoder
->
buffer_position
;
size_t
nbytes
=
buffer_size
-
buffer_position
;
if
(
nbytes
>
length
)
nbytes
=
length
;
memcpy
(
encoder
->
buffer
+
encoder
->
buffer_position
,
data
,
nbytes
);
memcpy
(
buffer
+
buffer_position
,
data
,
nbytes
);
data
+=
nbytes
;
length
-=
nbytes
;
encoder
->
buffer_position
+=
nbytes
;
buffer_position
+=
nbytes
;
if
(
encoder
->
buffer_position
==
encoder
->
buffer_size
&&
!
opus_encoder_do_encode
(
encoder
,
false
,
error
))
if
(
buffer_position
==
buffer_size
&&
!
DoEncode
(
false
,
error
))
return
false
;
}
return
true
;
}
static
void
opus_encoder_generate_head
(
OpusEncoder
*
encoder
)
static
bool
opus_encoder_write
(
Encoder
*
_encoder
,
const
void
*
data
,
size_t
length
,
Error
&
error
)
{
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
return
encoder
.
Write
(
data
,
length
,
error
);
}
void
OpusEncoder
::
GenerateHead
()
{
unsigned
char
header
[
19
];
memcpy
(
header
,
"OpusHead"
,
8
);
header
[
8
]
=
1
;
header
[
9
]
=
encoder
->
audio_format
.
channels
;
*
(
uint16_t
*
)(
header
+
10
)
=
ToLE16
(
encoder
->
lookahead
);
*
(
uint32_t
*
)(
header
+
12
)
=
ToLE32
(
encoder
->
audio_format
.
sample_rate
);
header
[
9
]
=
audio_format
.
channels
;
*
(
uint16_t
*
)(
header
+
10
)
=
ToLE16
(
lookahead
);
*
(
uint32_t
*
)(
header
+
12
)
=
ToLE32
(
audio_format
.
sample_rate
);
header
[
16
]
=
0
;
header
[
17
]
=
0
;
header
[
18
]
=
0
;
...
...
@@ -353,13 +388,13 @@ opus_encoder_generate_head(OpusEncoder *encoder)
packet
.
b_o_s
=
true
;
packet
.
e_o_s
=
false
;
packet
.
granulepos
=
0
;
packet
.
packetno
=
encoder
->
packetno
++
;
encoder
->
stream
.
PacketIn
(
packet
);
encoder
->
stream
.
Flush
();
packet
.
packetno
=
packetno
++
;
stream
.
PacketIn
(
packet
);
stream
.
Flush
();
}
static
void
opus_encoder_generate_tags
(
OpusEncoder
*
encoder
)
void
OpusEncoder
::
GenerateTags
(
)
{
const
char
*
version
=
opus_get_version_string
();
size_t
version_length
=
strlen
(
version
);
...
...
@@ -377,24 +412,29 @@ opus_encoder_generate_tags(OpusEncoder *encoder)
packet
.
b_o_s
=
false
;
packet
.
e_o_s
=
false
;
packet
.
granulepos
=
0
;
packet
.
packetno
=
encoder
->
packetno
++
;
encoder
->
stream
.
PacketIn
(
packet
);
encoder
->
stream
.
Flush
();
packet
.
packetno
=
packetno
++
;
stream
.
PacketIn
(
packet
);
stream
.
Flush
();
free
(
comments
);
}
s
tatic
s
ize_t
opus_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
size_t
OpusEncoder
::
Read
(
void
*
dest
,
size_t
length
)
{
auto
*
encoder
=
(
OpusEncoder
*
)
_encoder
;
if
(
packetno
==
0
)
GenerateHead
();
else
if
(
packetno
==
1
)
GenerateTags
();
if
(
encoder
->
packetno
==
0
)
opus_encoder_generate_head
(
encoder
);
else
if
(
encoder
->
packetno
==
1
)
opus_encoder_generate_tags
(
encoder
);
return
stream
.
PageOut
(
dest
,
length
);
}
return
encoder
->
stream
.
PageOut
(
dest
,
length
);
static
size_t
opus_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
{
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
return
encoder
.
Read
(
dest
,
length
);
}
static
const
char
*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment