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
e7edc026
Commit
e7edc026
authored
May 04, 2016
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
encoder/Interface: move instance methods to abstract class
Rename struct Encoder to PreparedEncoder, and add a new (abstract) class Encoder which represents one encoder instance.
parent
69bf8350
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
773 additions
and
992 deletions
+773
-992
EncoderInterface.hxx
src/encoder/EncoderInterface.hxx
+94
-188
EncoderPlugin.hxx
src/encoder/EncoderPlugin.hxx
+10
-29
ToOutputStream.cxx
src/encoder/ToOutputStream.cxx
+1
-1
ToOutputStream.hxx
src/encoder/ToOutputStream.hxx
+1
-1
FlacEncoderPlugin.cxx
src/encoder/plugins/FlacEncoderPlugin.cxx
+115
-120
LameEncoderPlugin.cxx
src/encoder/plugins/LameEncoderPlugin.cxx
+70
-79
NullEncoderPlugin.cxx
src/encoder/plugins/NullEncoderPlugin.cxx
+28
-50
OpusEncoderPlugin.cxx
src/encoder/plugins/OpusEncoderPlugin.cxx
+74
-111
ShineEncoderPlugin.cxx
src/encoder/plugins/ShineEncoderPlugin.cxx
+91
-104
TwolameEncoderPlugin.cxx
src/encoder/plugins/TwolameEncoderPlugin.cxx
+87
-95
VorbisEncoderPlugin.cxx
src/encoder/plugins/VorbisEncoderPlugin.cxx
+84
-90
WaveEncoderPlugin.cxx
src/encoder/plugins/WaveEncoderPlugin.cxx
+45
-58
RecorderOutputPlugin.cxx
src/output/plugins/RecorderOutputPlugin.cxx
+19
-16
ShoutOutputPlugin.cxx
src/output/plugins/ShoutOutputPlugin.cxx
+16
-15
HttpdInternal.hxx
src/output/plugins/httpd/HttpdInternal.hxx
+3
-1
HttpdOutputPlugin.cxx
src/output/plugins/httpd/HttpdOutputPlugin.cxx
+16
-16
run_encoder.cxx
test/run_encoder.cxx
+8
-7
test_vorbis_encoder.cxx
test/test_vorbis_encoder.cxx
+11
-11
No files found.
src/encoder/EncoderInterface.hxx
View file @
e7edc026
...
...
@@ -21,223 +21,129 @@
#define MPD_ENCODER_INTERFACE_HXX
#include "EncoderPlugin.hxx"
#include "Compiler.h"
#include <assert.h>
#include <stddef.h>
struct
Encoder
{
const
EncoderPlugin
&
plugin
;
struct
Tag
;
#ifndef NDEBUG
bool
open
,
pre_tag
,
tag
,
end
;
#endif
class
Encoder
{
const
bool
implements_tag
;
explicit
Encoder
(
const
EncoderPlugin
&
_plugin
)
:
plugin
(
_plugin
)
#ifndef NDEBUG
,
open
(
false
)
#endif
{}
public
:
explicit
Encoder
(
bool
_implements_tag
)
:
implements_tag
(
_implements_tag
)
{}
virtual
~
Encoder
()
{}
bool
ImplementsTag
()
const
{
return
implements_tag
;
}
/**
* Frees an #Encoder object.
* Ends the stream: flushes the encoder object, generate an
* end-of-stream marker (if applicable), make everything which
* might currently be buffered available by encoder_read().
*
* After this function has been called, the encoder may not be
* usable for more data, and only Read() and Close() can be
* called.
*
* @return true on success
*/
void
Dispose
()
{
assert
(
!
open
);
plugin
.
finish
(
this
);
virtual
bool
End
(
gcc_unused
Error
&
error
)
{
return
true
;
}
/**
* Opens the object. You must call this prior to using it.
* Before you free it, you must call Close(). You may open
* and close (reuse) one encoder any number of times.
* Flushes an encoder object, make everything which might
* currently be buffered available by Read().
*
* After this function returns successfully and before the
* first encoder_write() call, you should invoke
* encoder_read() to obtain the file header.
*
* @param audio_format the encoder's input audio format; the plugin
* may modify the struct to adapt it to its abilities
* @return true on success
*/
bool
Open
(
AudioFormat
&
audio_format
,
Error
&
error
)
{
assert
(
!
open
);
bool
success
=
plugin
.
open
(
this
,
audio_format
,
error
);
#ifndef NDEBUG
open
=
success
;
pre_tag
=
tag
=
end
=
false
;
#endif
return
success
;
virtual
bool
Flush
(
gcc_unused
Error
&
error
)
{
return
true
;
}
/**
* Closes the object. This disables the encoder, and readies
* it for reusal by calling Open() again.
* Prepare for sending a tag to the encoder. This is used by
* some encoders to flush the previous sub-stream, in
* preparation to begin a new one.
*
* @return true on success
*/
void
Close
()
{
assert
(
open
);
if
(
plugin
.
close
!=
nullptr
)
plugin
.
close
(
this
);
#ifndef NDEBUG
open
=
false
;
#endif
virtual
bool
PreTag
(
gcc_unused
Error
&
error
)
{
return
true
;
}
};
/**
* Ends the stream: flushes the encoder object, generate an
* end-of-stream marker (if applicable), make everything which might
* currently be buffered available by encoder_read().
*
* After this function has been called, the encoder may not be usable
* for more data, and only encoder_read() and Encoder::Close() can be
* called.
*
* @param encoder the encoder
* @return true on success
*/
static
inline
bool
encoder_end
(
Encoder
*
encoder
,
Error
&
error
)
{
assert
(
encoder
->
open
);
assert
(
!
encoder
->
end
);
#ifndef NDEBUG
encoder
->
end
=
true
;
#endif
/* this method is optional */
return
encoder
->
plugin
.
end
!=
nullptr
?
encoder
->
plugin
.
end
(
encoder
,
error
)
:
true
;
}
/**
* Flushes an encoder object, make everything which might currently be
* buffered available by encoder_read().
*
* @param encoder the encoder
* @return true on success
*/
static
inline
bool
encoder_flush
(
Encoder
*
encoder
,
Error
&
error
)
{
assert
(
encoder
->
open
);
assert
(
!
encoder
->
pre_tag
);
assert
(
!
encoder
->
tag
);
assert
(
!
encoder
->
end
);
/* this method is optional */
return
encoder
->
plugin
.
flush
!=
nullptr
?
encoder
->
plugin
.
flush
(
encoder
,
error
)
:
true
;
}
/**
* Prepare for sending a tag to the encoder. This is used by some
* encoders to flush the previous sub-stream, in preparation to begin
* a new one.
*
* @param encoder the encoder
* @return true on success
*/
static
inline
bool
encoder_pre_tag
(
Encoder
*
encoder
,
Error
&
error
)
{
assert
(
encoder
->
open
);
assert
(
!
encoder
->
pre_tag
);
assert
(
!
encoder
->
tag
);
assert
(
!
encoder
->
end
);
/* this method is optional */
bool
success
=
encoder
->
plugin
.
pre_tag
!=
nullptr
?
encoder
->
plugin
.
pre_tag
(
encoder
,
error
)
:
true
;
#ifndef NDEBUG
encoder
->
pre_tag
=
success
;
#endif
return
success
;
}
/**
* Sends a tag to the encoder.
*
* Instructions: call PreTag(); then obtain flushed data with
* Read(); finally call Tag().
*
* @param tag the tag object
* @return true on success
*/
virtual
bool
SendTag
(
gcc_unused
const
Tag
&
tag
,
gcc_unused
Error
&
error
)
{
return
true
;
}
/**
* Sends a tag to the encoder.
*
* Instructions: call encoder_pre_tag(); then obtain flushed data with
* encoder_read(); finally call encoder_tag().
*
* @param encoder the encoder
* @param tag the tag object
* @return true on success
*/
static
inline
bool
encoder_tag
(
Encoder
*
encoder
,
const
Tag
&
tag
,
Error
&
error
)
{
assert
(
encoder
->
open
);
assert
(
!
encoder
->
pre_tag
);
assert
(
encoder
->
tag
);
assert
(
!
encoder
->
end
);
/**
* Writes raw PCM data to the encoder.
*
* @param data the buffer containing PCM samples
* @param length the length of the buffer in bytes
* @return true on success
*/
virtual
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
error
)
=
0
;
#ifndef NDEBUG
encoder
->
tag
=
false
;
#endif
/**
* Reads encoded data from the encoder.
*
* Call this repeatedly until no more data is returned.
*
* @param dest the destination buffer to copy to
* @param length the maximum length of the destination buffer
* @return the number of bytes written to #dest
*/
virtual
size_t
Read
(
void
*
dest
,
size_t
length
)
=
0
;
};
/* this method is optional */
return
encoder
->
plugin
.
tag
!=
nullptr
?
encoder
->
plugin
.
tag
(
encoder
,
tag
,
error
)
:
true
;
}
struct
PreparedEncoder
{
const
EncoderPlugin
&
plugin
;
/**
* Writes raw PCM data to the encoder.
*
* @param encoder the encoder
* @param data the buffer containing PCM samples
* @param length the length of the buffer in bytes
* @return true on success
*/
static
inline
bool
encoder_write
(
Encoder
*
encoder
,
const
void
*
data
,
size_t
length
,
Error
&
error
)
{
assert
(
encoder
->
open
);
assert
(
!
encoder
->
pre_tag
);
assert
(
!
encoder
->
tag
);
assert
(
!
encoder
->
end
);
explicit
PreparedEncoder
(
const
EncoderPlugin
&
_plugin
)
:
plugin
(
_plugin
)
{}
return
encoder
->
plugin
.
write
(
encoder
,
data
,
length
,
error
);
}
/**
* Reads encoded data from the encoder.
*
* Call this repeatedly until no more data is returned.
*
* @param encoder the encoder
* @param dest the destination buffer to copy to
* @param length the maximum length of the destination buffer
* @return the number of bytes written to #dest
*/
static
inline
size_t
encoder_read
(
Encoder
*
encoder
,
void
*
dest
,
size_t
length
)
{
assert
(
encoder
->
open
);
assert
(
!
encoder
->
pre_tag
||
!
encoder
->
tag
);
/**
* Frees an #Encoder object.
*/
void
Dispose
()
{
plugin
.
finish
(
this
);
}
#ifndef NDEBUG
if
(
encoder
->
pre_tag
)
{
encoder
->
pre_tag
=
false
;
encoder
->
tag
=
true
;
/**
* Opens the object. You must call this prior to using it.
* Before you free it, you must call Close(). You may open
* and close (reuse) one encoder any number of times.
*
* After this function returns successfully and before the
* first encoder_write() call, you should invoke
* encoder_read() to obtain the file header.
*
* @param audio_format the encoder's input audio format; the plugin
* may modify the struct to adapt it to its abilities
* @return true on success
*/
Encoder
*
Open
(
AudioFormat
&
audio_format
,
Error
&
error
)
{
return
plugin
.
open
(
this
,
audio_format
,
error
);
}
#endif
return
encoder
->
plugin
.
read
(
encoder
,
dest
,
length
);
}
};
/**
* Get mime type of encoded content.
...
...
@@ -245,7 +151,7 @@ encoder_read(Encoder *encoder, void *dest, size_t length)
* @return an constant string, nullptr on failure
*/
static
inline
const
char
*
encoder_get_mime_type
(
Encoder
*
encoder
)
encoder_get_mime_type
(
Prepared
Encoder
*
encoder
)
{
/* this method is optional */
return
encoder
->
plugin
.
get_mime_type
!=
nullptr
...
...
src/encoder/EncoderPlugin.hxx
View file @
e7edc026
...
...
@@ -20,44 +20,25 @@
#ifndef MPD_ENCODER_PLUGIN_HXX
#define MPD_ENCODER_PLUGIN_HXX
#include <stddef.h>
struct
Encoder
;
struct
PreparedEncoder
;
class
Encoder
;
struct
AudioFormat
;
struct
ConfigBlock
;
struct
Tag
;
class
Error
;
struct
EncoderPlugin
{
const
char
*
name
;
Encoder
*
(
*
init
)(
const
ConfigBlock
&
block
,
Error
&
error
);
void
(
*
finish
)(
Encoder
*
encoder
);
bool
(
*
open
)(
Encoder
*
encoder
,
AudioFormat
&
audio_format
,
Error
&
error
);
void
(
*
close
)(
Encoder
*
encoder
);
PreparedEncoder
*
(
*
init
)(
const
ConfigBlock
&
block
,
Error
&
error
);
bool
(
*
end
)(
Encoder
*
encoder
,
Error
&
erro
r
);
void
(
*
finish
)(
PreparedEncoder
*
encode
r
);
bool
(
*
flush
)(
Encoder
*
encoder
,
Error
&
error
);
bool
(
*
pre_tag
)(
Encoder
*
encoder
,
Error
&
error
);
bool
(
*
tag
)(
Encoder
*
encoder
,
const
Tag
&
tag
,
Error
&
error
);
bool
(
*
write
)(
Encoder
*
encoder
,
const
void
*
data
,
size_t
length
,
Error
&
error
);
size_t
(
*
read
)(
Encoder
*
encoder
,
void
*
dest
,
size_t
length
);
Encoder
*
(
*
open
)(
PreparedEncoder
*
encoder
,
AudioFormat
&
audio_format
,
Error
&
error
);
const
char
*
(
*
get_mime_type
)(
Encoder
*
encoder
);
const
char
*
(
*
get_mime_type
)(
Prepared
Encoder
*
encoder
);
};
/**
...
...
@@ -67,7 +48,7 @@ struct EncoderPlugin {
* @param error location to store the error occurring, or nullptr to ignore errors.
* @return an encoder object on success, nullptr on failure
*/
static
inline
Encoder
*
static
inline
Prepared
Encoder
*
encoder_init
(
const
EncoderPlugin
&
plugin
,
const
ConfigBlock
&
block
,
Error
&
error
)
{
...
...
src/encoder/ToOutputStream.cxx
View file @
e7edc026
...
...
@@ -29,7 +29,7 @@ EncoderToOutputStream(OutputStream &os, Encoder &encoder)
/* read from the encoder */
char
buffer
[
32768
];
size_t
nbytes
=
encoder
_read
(
&
encoder
,
buffer
,
sizeof
(
buffer
));
size_t
nbytes
=
encoder
.
Read
(
buffer
,
sizeof
(
buffer
));
if
(
nbytes
==
0
)
return
;
...
...
src/encoder/ToOutputStream.hxx
View file @
e7edc026
...
...
@@ -22,8 +22,8 @@
#include "check.h"
struct
Encoder
;
class
OutputStream
;
class
Encoder
;
void
EncoderToOutputStream
(
OutputStream
&
os
,
Encoder
&
encoder
);
...
...
src/encoder/plugins/FlacEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -23,7 +23,6 @@
#include "AudioFormat.hxx"
#include "pcm/PcmBuffer.hxx"
#include "config/ConfigError.hxx"
#include "util/Manual.hxx"
#include "util/DynamicFifoBuffer.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
...
...
@@ -34,13 +33,10 @@
#error libFLAC is too old
#endif
struct
flac_e
ncoder
{
Encoder
encoder
;
class
FlacEncoder
final
:
public
E
ncoder
{
const
AudioFormat
audio_format
;
AudioFormat
audio_format
;
unsigned
compression
;
FLAC__StreamEncoder
*
fse
;
FLAC__StreamEncoder
*
const
fse
;
PcmBuffer
expand_buffer
;
...
...
@@ -48,29 +44,76 @@ struct flac_encoder {
* This buffer will hold encoded data from libFLAC until it is
* picked up with flac_encoder_read().
*/
Manual
<
DynamicFifoBuffer
<
uint8_t
>>
output_buffer
;
DynamicFifoBuffer
<
uint8_t
>
output_buffer
;
public
:
FlacEncoder
(
AudioFormat
_audio_format
,
FLAC__StreamEncoder
*
_fse
)
:
Encoder
(
false
),
audio_format
(
_audio_format
),
fse
(
_fse
),
output_buffer
(
8192
)
{}
~
FlacEncoder
()
override
{
FLAC__stream_encoder_delete
(
fse
);
}
bool
Init
(
Error
&
error
);
/* virtual methods from class Encoder */
bool
End
(
Error
&
)
override
{
(
void
)
FLAC__stream_encoder_finish
(
fse
);
return
true
;
}
flac_encoder
()
:
encoder
(
flac_encoder_plugin
)
{}
bool
Flush
(
Error
&
)
override
{
(
void
)
FLAC__stream_encoder_finish
(
fse
);
return
true
;
}
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
;
size_t
Read
(
void
*
dest
,
size_t
length
)
override
{
return
output_buffer
.
Read
((
uint8_t
*
)
dest
,
length
);
}
private
:
static
FLAC__StreamEncoderWriteStatus
WriteCallback
(
const
FLAC__StreamEncoder
*
,
const
FLAC__byte
data
[],
size_t
bytes
,
gcc_unused
unsigned
samples
,
gcc_unused
unsigned
current_frame
,
void
*
client_data
)
{
auto
&
encoder
=
*
(
FlacEncoder
*
)
client_data
;
encoder
.
output_buffer
.
Append
((
const
uint8_t
*
)
data
,
bytes
);
return
FLAC__STREAM_ENCODER_WRITE_STATUS_OK
;
}
};
struct
PreparedFlacEncoder
{
PreparedEncoder
encoder
;
unsigned
compression
;
PreparedFlacEncoder
()
:
encoder
(
flac_encoder_plugin
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
};
static
constexpr
Domain
flac_encoder_domain
(
"vorbis_encoder"
);
static
bool
flac_encoder_configure
(
struct
flac_encoder
*
encoder
,
const
ConfigBlock
&
block
,
gcc_unused
Error
&
error
)
bool
PreparedFlacEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
)
{
encoder
->
compression
=
block
.
GetBlockValue
(
"compression"
,
5u
);
compression
=
block
.
GetBlockValue
(
"compression"
,
5u
);
return
true
;
}
static
Encoder
*
static
Prepared
Encoder
*
flac_encoder_init
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
flac_encoder
*
encoder
=
new
flac_e
ncoder
();
auto
*
encoder
=
new
PreparedFlacE
ncoder
();
/* load configuration from "block" */
if
(
!
flac_encoder_configure
(
encoder
,
block
,
error
))
{
if
(
!
encoder
->
Configure
(
block
,
error
))
{
/* configuration has failed, roll back and return error */
delete
encoder
;
return
nullptr
;
...
...
@@ -80,9 +123,9 @@ flac_encoder_init(const ConfigBlock &block, Error &error)
}
static
void
flac_encoder_finish
(
Encoder
*
_encoder
)
flac_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
struct
flac_encoder
*
encoder
=
(
struct
flac_e
ncoder
*
)
_encoder
;
auto
*
encoder
=
(
PreparedFlacE
ncoder
*
)
_encoder
;
/* the real libFLAC cleanup was already performed by
flac_encoder_close(), so no real work here */
...
...
@@ -90,71 +133,67 @@ flac_encoder_finish(Encoder *_encoder)
}
static
bool
flac_encoder_setup
(
struct
flac_encoder
*
encoder
,
unsigned
bits_per_sample
,
flac_encoder_setup
(
FLAC__StreamEncoder
*
fse
,
unsigned
compression
,
const
AudioFormat
&
audio_format
,
unsigned
bits_per_sample
,
Error
&
error
)
{
if
(
!
FLAC__stream_encoder_set_compression_level
(
encoder
->
fse
,
encoder
->
compression
))
{
if
(
!
FLAC__stream_encoder_set_compression_level
(
fse
,
compression
))
{
error
.
Format
(
config_domain
,
"error setting flac compression to %d"
,
encoder
->
compression
);
compression
);
return
false
;
}
if
(
!
FLAC__stream_encoder_set_channels
(
encoder
->
fse
,
encoder
->
audio_format
.
channels
))
{
if
(
!
FLAC__stream_encoder_set_channels
(
fse
,
audio_format
.
channels
))
{
error
.
Format
(
config_domain
,
"error setting flac channels num to %d"
,
encoder
->
audio_format
.
channels
);
audio_format
.
channels
);
return
false
;
}
if
(
!
FLAC__stream_encoder_set_bits_per_sample
(
encoder
->
fse
,
bits_per_sample
))
{
if
(
!
FLAC__stream_encoder_set_bits_per_sample
(
fse
,
bits_per_sample
))
{
error
.
Format
(
config_domain
,
"error setting flac bit format to %d"
,
bits_per_sample
);
return
false
;
}
if
(
!
FLAC__stream_encoder_set_sample_rate
(
encoder
->
fse
,
encoder
->
audio_format
.
sample_rate
))
{
if
(
!
FLAC__stream_encoder_set_sample_rate
(
fse
,
audio_format
.
sample_rate
))
{
error
.
Format
(
config_domain
,
"error setting flac sample rate to %d"
,
encoder
->
audio_format
.
sample_rate
);
audio_format
.
sample_rate
);
return
false
;
}
return
true
;
}
static
FLAC__StreamEncoderWriteStatus
flac_write_callback
(
gcc_unused
const
FLAC__StreamEncoder
*
fse
,
const
FLAC__byte
data
[],
size_t
bytes
,
gcc_unused
unsigned
samples
,
gcc_unused
unsigned
current_frame
,
void
*
client_data
)
bool
FlacEncoder
::
Init
(
Error
&
error
)
{
struct
flac_encoder
*
encoder
=
(
struct
flac_encoder
*
)
client_data
;
//transfer data to buffer
encoder
->
output_buffer
->
Append
((
const
uint8_t
*
)
data
,
bytes
);
return
FLAC__STREAM_ENCODER_WRITE_STATUS_OK
;
}
/* this immediately outputs data through callback */
static
void
flac_encoder_close
(
Encoder
*
_encoder
)
{
struct
flac_encoder
*
encoder
=
(
struct
flac_encoder
*
)
_encoder
;
auto
init_status
=
FLAC__stream_encoder_init_stream
(
fse
,
WriteCallback
,
nullptr
,
nullptr
,
nullptr
,
this
);
FLAC__stream_encoder_delete
(
encoder
->
fse
);
if
(
init_status
!=
FLAC__STREAM_ENCODER_INIT_STATUS_OK
)
{
error
.
Format
(
flac_encoder_domain
,
"failed to initialize encoder: %s
\n
"
,
FLAC__StreamEncoderInitStatusString
[
init_status
]);
return
false
;
}
encoder
->
expand_buffer
.
Clear
();
encoder
->
output_buffer
.
Destruct
();
return
true
;
}
static
bool
flac_encoder_open
(
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
static
Encoder
*
flac_encoder_open
(
Prepared
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
struct
flac_encoder
*
encoder
=
(
struct
flac_e
ncoder
*
)
_encoder
;
auto
*
encoder
=
(
PreparedFlacE
ncoder
*
)
_encoder
;
unsigned
bits_per_sample
;
/* FIXME: flac should support 32bit as well */
...
...
@@ -176,51 +215,26 @@ flac_encoder_open(Encoder *_encoder, AudioFormat &audio_format, Error &error)
audio_format
.
format
=
SampleFormat
::
S24_P32
;
}
encoder
->
audio_format
=
audio_format
;
/* allocate the encoder */
encoder
->
fse
=
FLAC__stream_encoder_new
();
if
(
encoder
->
fse
==
nullptr
)
{
error
.
Set
(
flac_encoder_domain
,
"
flac
_new() failed"
);
return
false
;
auto
fse
=
FLAC__stream_encoder_new
();
if
(
fse
==
nullptr
)
{
error
.
Set
(
flac_encoder_domain
,
"
FLAC__stream_encoder
_new() failed"
);
return
nullptr
;
}
if
(
!
flac_encoder_setup
(
encoder
,
bits_per_sample
,
error
))
{
FLAC__stream_encoder_delete
(
encoder
->
fse
);
return
false
;
if
(
!
flac_encoder_setup
(
fse
,
encoder
->
compression
,
audio_format
,
bits_per_sample
,
error
))
{
FLAC__stream_encoder_delete
(
fse
);
return
nullptr
;
}
encoder
->
output_buffer
.
Construct
(
8192
);
/* this immediately outputs data through callback */
{
FLAC__StreamEncoderInitStatus
init_status
;
init_status
=
FLAC__stream_encoder_init_stream
(
encoder
->
fse
,
flac_write_callback
,
nullptr
,
nullptr
,
nullptr
,
encoder
);
if
(
init_status
!=
FLAC__STREAM_ENCODER_INIT_STATUS_OK
)
{
error
.
Format
(
flac_encoder_domain
,
"failed to initialize encoder: %s
\n
"
,
FLAC__StreamEncoderInitStatusString
[
init_status
]);
flac_encoder_close
(
_encoder
);
return
false
;
}
auto
*
e
=
new
FlacEncoder
(
audio_format
,
fse
);
if
(
!
e
->
Init
(
error
))
{
delete
e
;
return
nullptr
;
}
return
true
;
}
static
bool
flac_encoder_flush
(
Encoder
*
_encoder
,
gcc_unused
Error
&
error
)
{
struct
flac_encoder
*
encoder
=
(
struct
flac_encoder
*
)
_encoder
;
(
void
)
FLAC__stream_encoder_finish
(
encoder
->
fse
);
return
true
;
return
e
;
}
static
inline
void
...
...
@@ -241,31 +255,27 @@ pcm16_to_flac(int32_t *out, const int16_t *in, unsigned num_samples)
}
}
static
bool
flac_encoder_write
(
Encoder
*
_encoder
,
const
void
*
data
,
size_t
length
,
gcc_unused
Error
&
error
)
bool
FlacEncoder
::
Write
(
const
void
*
data
,
size_t
length
,
Error
&
error
)
{
struct
flac_encoder
*
encoder
=
(
struct
flac_encoder
*
)
_encoder
;
unsigned
num_frames
,
num_samples
;
void
*
exbuffer
;
const
void
*
buffer
=
nullptr
;
/* format conversion */
num_frames
=
length
/
encoder
->
audio_format
.
GetFrameSize
();
num_samples
=
num_frames
*
encoder
->
audio_format
.
channels
;
const
unsigned
num_frames
=
length
/
audio_format
.
GetFrameSize
();
const
unsigned
num_samples
=
num_frames
*
audio_format
.
channels
;
switch
(
encoder
->
audio_format
.
format
)
{
switch
(
audio_format
.
format
)
{
case
SampleFormat
:
:
S8
:
exbuffer
=
e
ncoder
->
e
xpand_buffer
.
Get
(
length
*
4
);
exbuffer
=
expand_buffer
.
Get
(
length
*
4
);
pcm8_to_flac
((
int32_t
*
)
exbuffer
,
(
const
int8_t
*
)
data
,
num_samples
);
buffer
=
exbuffer
;
break
;
case
SampleFormat
:
:
S16
:
exbuffer
=
e
ncoder
->
e
xpand_buffer
.
Get
(
length
*
2
);
exbuffer
=
expand_buffer
.
Get
(
length
*
2
);
pcm16_to_flac
((
int32_t
*
)
exbuffer
,
(
const
int16_t
*
)
data
,
num_samples
);
buffer
=
exbuffer
;
...
...
@@ -284,7 +294,7 @@ flac_encoder_write(Encoder *_encoder,
/* feed samples to encoder */
if
(
!
FLAC__stream_encoder_process_interleaved
(
encoder
->
fse
,
if
(
!
FLAC__stream_encoder_process_interleaved
(
fse
,
(
const
FLAC__int32
*
)
buffer
,
num_frames
))
{
error
.
Set
(
flac_encoder_domain
,
"flac encoder process failed"
);
...
...
@@ -294,16 +304,8 @@ flac_encoder_write(Encoder *_encoder,
return
true
;
}
static
size_t
flac_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
{
struct
flac_encoder
*
encoder
=
(
struct
flac_encoder
*
)
_encoder
;
return
encoder
->
output_buffer
->
Read
((
uint8_t
*
)
dest
,
length
);
}
static
const
char
*
flac_encoder_get_mime_type
(
gcc_unused
Encoder
*
_encoder
)
flac_encoder_get_mime_type
(
gcc_unused
Prepared
Encoder
*
_encoder
)
{
return
"audio/flac"
;
}
...
...
@@ -313,13 +315,6 @@ const EncoderPlugin flac_encoder_plugin = {
flac_encoder_init
,
flac_encoder_finish
,
flac_encoder_open
,
flac_encoder_close
,
flac_encoder_flush
,
flac_encoder_flush
,
nullptr
,
nullptr
,
flac_encoder_write
,
flac_encoder_read
,
flac_encoder_get_mime_type
,
};
src/encoder/plugins/LameEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -24,7 +24,6 @@
#include "config/ConfigError.hxx"
#include "util/NumberParser.hxx"
#include "util/ReusableArray.hxx"
#include "util/Manual.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
...
...
@@ -33,19 +32,34 @@
#include <assert.h>
#include <string.h>
struct
LameEncoder
final
{
Encoder
encoder
;
class
LameEncoder
final
:
public
Encoder
{
const
AudioFormat
audio_format
;
AudioFormat
audio_format
;
float
quality
;
int
bitrate
;
lame_global_flags
*
const
gfp
;
ReusableArray
<
unsigned
char
,
32768
>
output_buffer
;
unsigned
char
*
output_begin
=
nullptr
,
*
output_end
=
nullptr
;
public
:
LameEncoder
(
const
AudioFormat
_audio_format
,
lame_global_flags
*
_gfp
)
:
Encoder
(
false
),
audio_format
(
_audio_format
),
gfp
(
_gfp
)
{}
~
LameEncoder
()
override
;
/* virtual methods from class Encoder */
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
;
size_t
Read
(
void
*
dest
,
size_t
length
)
override
;
};
lame_global_flags
*
gfp
;
struct
PreparedLameEncoder
final
{
PreparedEncoder
encoder
;
Manual
<
ReusableArray
<
unsigned
char
,
32768
>>
output_buffer
;
unsigned
char
*
output_begin
,
*
output_end
;
float
quality
;
int
bitrate
;
LameEncoder
()
:
encoder
(
lame_encoder_plugin
)
{}
Prepared
LameEncoder
()
:
encoder
(
lame_encoder_plugin
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
};
...
...
@@ -53,7 +67,7 @@ struct LameEncoder final {
static
constexpr
Domain
lame_encoder_domain
(
"lame_encoder"
);
bool
LameEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
Prepared
LameEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
const
char
*
value
;
char
*
endptr
;
...
...
@@ -100,10 +114,10 @@ LameEncoder::Configure(const ConfigBlock &block, Error &error)
return
true
;
}
static
Encoder
*
static
Prepared
Encoder
*
lame_encoder_init
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
LameEncoder
*
encoder
=
new
LameEncoder
();
auto
*
encoder
=
new
Prepared
LameEncoder
();
/* load configuration from "block" */
if
(
!
encoder
->
Configure
(
block
,
error
))
{
...
...
@@ -116,9 +130,9 @@ lame_encoder_init(const ConfigBlock &block, Error &error)
}
static
void
lame_encoder_finish
(
Encoder
*
_encoder
)
lame_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
LameEncoder
*
encoder
=
(
LameEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
LameEncoder
*
)
_encoder
;
/* the real liblame cleanup was already performed by
lame_encoder_close(), so no real work here */
...
...
@@ -126,17 +140,18 @@ lame_encoder_finish(Encoder *_encoder)
}
static
bool
lame_encoder_setup
(
LameEncoder
*
encoder
,
Error
&
error
)
lame_encoder_setup
(
lame_global_flags
*
gfp
,
float
quality
,
int
bitrate
,
const
AudioFormat
&
audio_format
,
Error
&
error
)
{
if
(
encoder
->
quality
>=
-
1.0
)
{
if
(
quality
>=
-
1.0
)
{
/* a quality was configured (VBR) */
if
(
0
!=
lame_set_VBR
(
encoder
->
gfp
,
vbr_rh
))
{
if
(
0
!=
lame_set_VBR
(
gfp
,
vbr_rh
))
{
error
.
Set
(
lame_encoder_domain
,
"error setting lame VBR mode"
);
return
false
;
}
if
(
0
!=
lame_set_VBR_q
(
encoder
->
gfp
,
encoder
->
quality
))
{
if
(
0
!=
lame_set_VBR_q
(
gfp
,
quality
))
{
error
.
Set
(
lame_encoder_domain
,
"error setting lame VBR quality"
);
return
false
;
...
...
@@ -144,35 +159,32 @@ lame_encoder_setup(LameEncoder *encoder, Error &error)
}
else
{
/* a bit rate was configured */
if
(
0
!=
lame_set_brate
(
encoder
->
gfp
,
encoder
->
bitrate
))
{
if
(
0
!=
lame_set_brate
(
gfp
,
bitrate
))
{
error
.
Set
(
lame_encoder_domain
,
"error setting lame bitrate"
);
return
false
;
}
}
if
(
0
!=
lame_set_num_channels
(
encoder
->
gfp
,
encoder
->
audio_format
.
channels
))
{
if
(
0
!=
lame_set_num_channels
(
gfp
,
audio_format
.
channels
))
{
error
.
Set
(
lame_encoder_domain
,
"error setting lame num channels"
);
return
false
;
}
if
(
0
!=
lame_set_in_samplerate
(
encoder
->
gfp
,
encoder
->
audio_format
.
sample_rate
))
{
if
(
0
!=
lame_set_in_samplerate
(
gfp
,
audio_format
.
sample_rate
))
{
error
.
Set
(
lame_encoder_domain
,
"error setting lame sample rate"
);
return
false
;
}
if
(
0
!=
lame_set_out_samplerate
(
encoder
->
gfp
,
encoder
->
audio_format
.
sample_rate
))
{
if
(
0
!=
lame_set_out_samplerate
(
gfp
,
audio_format
.
sample_rate
))
{
error
.
Set
(
lame_encoder_domain
,
"error setting lame out sample rate"
);
return
false
;
}
if
(
0
>
lame_init_params
(
encoder
->
gfp
))
{
if
(
0
>
lame_init_params
(
gfp
))
{
error
.
Set
(
lame_encoder_domain
,
"error initializing lame params"
);
return
false
;
...
...
@@ -181,98 +193,84 @@ lame_encoder_setup(LameEncoder *encoder, Error &error)
return
true
;
}
static
bool
lame_encoder_open
(
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
static
Encoder
*
lame_encoder_open
(
PreparedEncoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
LameEncoder
*
encoder
=
(
LameEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
LameEncoder
*
)
_encoder
;
audio_format
.
format
=
SampleFormat
::
S16
;
audio_format
.
channels
=
2
;
encoder
->
audio_format
=
audio_format
;
encoder
->
gfp
=
lame_init
();
if
(
encoder
->
gfp
==
nullptr
)
{
auto
gfp
=
lame_init
();
if
(
gfp
==
nullptr
)
{
error
.
Set
(
lame_encoder_domain
,
"lame_init() failed"
);
return
false
;
return
nullptr
;
}
if
(
!
lame_encoder_setup
(
encoder
,
error
))
{
lame_close
(
encoder
->
gfp
);
return
false
;
if
(
!
lame_encoder_setup
(
gfp
,
encoder
->
quality
,
encoder
->
bitrate
,
audio_format
,
error
))
{
lame_close
(
gfp
);
return
nullptr
;
}
encoder
->
output_buffer
.
Construct
();
encoder
->
output_begin
=
encoder
->
output_end
=
nullptr
;
return
true
;
return
new
LameEncoder
(
audio_format
,
gfp
);
}
static
void
lame_encoder_close
(
Encoder
*
_encoder
)
LameEncoder
::~
LameEncoder
()
{
LameEncoder
*
encoder
=
(
LameEncoder
*
)
_encoder
;
lame_close
(
encoder
->
gfp
);
encoder
->
output_buffer
.
Destruct
();
lame_close
(
gfp
);
}
static
bool
lame_encoder_write
(
Encoder
*
_encoder
,
const
void
*
data
,
size_t
length
,
bool
LameEncoder
::
Write
(
const
void
*
data
,
size_t
length
,
gcc_unused
Error
&
error
)
{
LameEncoder
*
encoder
=
(
LameEncoder
*
)
_encoder
;
const
int16_t
*
src
=
(
const
int16_t
*
)
data
;
assert
(
encoder
->
output_begin
==
encoder
->
output_end
);
assert
(
output_begin
==
output_end
);
const
unsigned
num_frames
=
length
/
encoder
->
audio_format
.
GetFrameSize
();
const
unsigned
num_samples
=
length
/
encoder
->
audio_format
.
GetSampleSize
();
const
unsigned
num_frames
=
length
/
audio_format
.
GetFrameSize
();
const
unsigned
num_samples
=
length
/
audio_format
.
GetSampleSize
();
/* worst-case formula according to LAME documentation */
const
size_t
output_buffer_size
=
5
*
num_samples
/
4
+
7200
;
const
auto
output_buffer
=
encoder
->
output_buffer
->
Get
(
output_buffer_size
);
const
auto
dest
=
output_buffer
.
Get
(
output_buffer_size
);
/* this is for only 16-bit audio */
int
bytes_out
=
lame_encode_buffer_interleaved
(
encoder
->
gfp
,
int
bytes_out
=
lame_encode_buffer_interleaved
(
gfp
,
const_cast
<
short
*>
(
src
),
num_frames
,
output_buffer
,
output_buffer_size
);
dest
,
output_buffer_size
);
if
(
bytes_out
<
0
)
{
error
.
Set
(
lame_encoder_domain
,
"lame encoder failed"
);
return
false
;
}
encoder
->
output_begin
=
output_buffer
;
encoder
->
output_end
=
output_buffer
+
bytes_out
;
output_begin
=
dest
;
output_end
=
dest
+
bytes_out
;
return
true
;
}
s
tatic
s
ize_t
lame_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
size_t
LameEncoder
::
Read
(
void
*
dest
,
size_t
length
)
{
LameEncoder
*
encoder
=
(
LameEncoder
*
)
_encoder
;
const
auto
begin
=
encoder
->
output_begin
;
assert
(
begin
<=
encoder
->
output_end
);
const
size_t
remainning
=
encoder
->
output_end
-
begin
;
const
auto
begin
=
output_begin
;
assert
(
begin
<=
output_end
);
const
size_t
remainning
=
output_end
-
begin
;
if
(
length
>
remainning
)
length
=
remainning
;
memcpy
(
dest
,
begin
,
length
);
encoder
->
output_begin
=
begin
+
length
;
output_begin
=
begin
+
length
;
return
length
;
}
static
const
char
*
lame_encoder_get_mime_type
(
gcc_unused
Encoder
*
_encoder
)
lame_encoder_get_mime_type
(
gcc_unused
Prepared
Encoder
*
_encoder
)
{
return
"audio/mpeg"
;
}
...
...
@@ -282,12 +280,5 @@ const EncoderPlugin lame_encoder_plugin = {
lame_encoder_init
,
lame_encoder_finish
,
lame_encoder_open
,
lame_encoder_close
,
nullptr
,
nullptr
,
nullptr
,
nullptr
,
lame_encoder_write
,
lame_encoder_read
,
lame_encoder_get_mime_type
,
};
src/encoder/plugins/NullEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -20,73 +20,58 @@
#include "config.h"
#include "NullEncoderPlugin.hxx"
#include "../EncoderAPI.hxx"
#include "util/Manual.hxx"
#include "util/DynamicFifoBuffer.hxx"
#include "Compiler.h"
#include <assert.h>
struct
NullEncoder
final
{
Encoder
encoder
;
Manual
<
DynamicFifoBuffer
<
uint8_t
>>
buffer
;
class
NullEncoder
final
:
public
Encoder
{
DynamicFifoBuffer
<
uint8_t
>
buffer
;
public
:
NullEncoder
()
:
Encoder
(
false
),
buffer
(
8192
)
{}
/* virtual methods from class Encoder */
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
{
buffer
.
Append
((
const
uint8_t
*
)
data
,
length
);
return
true
;
}
size_t
Read
(
void
*
dest
,
size_t
length
)
override
{
return
buffer
.
Read
((
uint8_t
*
)
dest
,
length
);
}
};
struct
PreparedNullEncoder
final
{
PreparedEncoder
encoder
;
PreparedNullEncoder
()
:
encoder
(
null_encoder_plugin
)
{}
};
static
Encoder
*
static
Prepared
Encoder
*
null_encoder_init
(
gcc_unused
const
ConfigBlock
&
block
,
gcc_unused
Error
&
error
)
{
NullEncoder
*
encoder
=
new
NullEncoder
();
auto
*
encoder
=
new
Prepared
NullEncoder
();
return
&
encoder
->
encoder
;
}
static
void
null_encoder_finish
(
Encoder
*
_encoder
)
null_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
NullEncoder
*
encoder
=
(
NullEncoder
*
)
_encoder
;
auto
*
encoder
=
(
PreparedNullEncoder
*
)
_encoder
;
delete
encoder
;
}
static
void
null_encoder_close
(
Encoder
*
_encoder
)
{
NullEncoder
*
encoder
=
(
NullEncoder
*
)
_encoder
;
encoder
->
buffer
.
Destruct
();
}
static
bool
null_encoder_open
(
Encoder
*
_encoder
,
static
Encoder
*
null_encoder_open
(
gcc_unused
PreparedEncoder
*
encoder
,
gcc_unused
AudioFormat
&
audio_format
,
gcc_unused
Error
&
error
)
{
NullEncoder
*
encoder
=
(
NullEncoder
*
)
_encoder
;
encoder
->
buffer
.
Construct
(
8192
);
return
true
;
}
static
bool
null_encoder_write
(
Encoder
*
_encoder
,
const
void
*
data
,
size_t
length
,
gcc_unused
Error
&
error
)
{
NullEncoder
*
encoder
=
(
NullEncoder
*
)
_encoder
;
encoder
->
buffer
->
Append
((
const
uint8_t
*
)
data
,
length
);
return
length
;
}
static
size_t
null_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
{
NullEncoder
*
encoder
=
(
NullEncoder
*
)
_encoder
;
return
encoder
->
buffer
->
Read
((
uint8_t
*
)
dest
,
length
);
return
new
NullEncoder
();
}
const
EncoderPlugin
null_encoder_plugin
=
{
...
...
@@ -94,12 +79,5 @@ const EncoderPlugin null_encoder_plugin = {
null_encoder_init
,
null_encoder_finish
,
null_encoder_open
,
null_encoder_close
,
nullptr
,
nullptr
,
nullptr
,
nullptr
,
null_encoder_write
,
null_encoder_read
,
nullptr
,
};
src/encoder/plugins/OpusEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -35,26 +35,18 @@
#include <assert.h>
#include <stdlib.h>
struct
OpusEncoder
{
/** the base class */
Encoder
encoder
;
/* configuration */
opus_int32
bitrate
;
int
complexity
;
int
signal
;
/* runtime information */
namespace
{
AudioFormat
audio_format
;
class
OpusEncoder
final
:
public
Encoder
{
const
AudioFormat
audio_format
;
size_t
frame_size
;
const
size_t
frame_size
;
size_t
buffer_frames
,
buffer_size
,
buffer_position
;
uint8_t
*
buffer
;
const
size_t
buffer_frames
,
buffer_size
;
size_t
buffer_position
=
0
;
uint8_t
*
const
buffer
;
OpusEncoder
*
enc
;
::
OpusEncoder
*
const
enc
;
unsigned
char
buffer2
[
1275
*
3
+
7
];
...
...
@@ -62,35 +54,49 @@ struct OpusEncoder {
int
lookahead
;
ogg_int64_t
packetno
;
ogg_int64_t
packetno
=
0
;
ogg_int64_t
granulepos
;
OpusEncoder
()
:
encoder
(
opus_encoder_plugin
),
granulepos
(
0
)
{}
public
:
OpusEncoder
(
AudioFormat
&
_audio_format
,
::
OpusEncoder
*
_enc
);
~
OpusEncoder
()
override
;
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
bool
Open
(
AudioFormat
&
audio_format
,
Error
&
error
);
void
Close
();
bool
DoEncode
(
bool
eos
,
Error
&
error
);
/* virtual methods from class Encoder */
bool
End
(
Error
&
)
override
;
bool
Flush
(
Error
&
)
override
;
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
;
bool
End
(
Error
&
error
);
bool
Flush
(
Error
&
error
);
size_t
Read
(
void
*
dest
,
size_t
length
)
override
;
private
:
bool
DoEncode
(
bool
eos
,
Error
&
error
);
bool
WriteSilence
(
unsigned
fill_frames
,
Error
&
error
);
bool
Write
(
const
void
*
_data
,
size_t
length
,
Error
&
error
);
void
GenerateHead
();
void
GenerateTags
();
};
struct
PreparedOpusEncoder
{
/** the base class */
PreparedEncoder
encoder
;
size_t
Read
(
void
*
dest
,
size_t
length
);
/* configuration */
opus_int32
bitrate
;
int
complexity
;
int
signal
;
PreparedOpusEncoder
()
:
encoder
(
opus_encoder_plugin
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
Encoder
*
Open
(
AudioFormat
&
audio_format
,
Error
&
error
);
};
static
constexpr
Domain
opus_encoder_domain
(
"opus_encoder"
);
bool
OpusEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
Prepared
OpusEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
const
char
*
value
=
block
.
GetBlockValue
(
"bitrate"
,
"auto"
);
if
(
strcmp
(
value
,
"auto"
)
==
0
)
...
...
@@ -128,10 +134,10 @@ OpusEncoder::Configure(const ConfigBlock &block, Error &error)
return
true
;
}
static
Encoder
*
static
Prepared
Encoder
*
opus_encoder_init
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
auto
*
encoder
=
new
OpusEncoder
();
auto
*
encoder
=
new
Prepared
OpusEncoder
();
/* load configuration from "block" */
if
(
!
encoder
->
Configure
(
block
,
error
))
{
...
...
@@ -144,93 +150,86 @@ opus_encoder_init(const ConfigBlock &block, Error &error)
}
static
void
opus_encoder_finish
(
Encoder
*
_encoder
)
opus_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
auto
*
encoder
=
(
OpusEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
OpusEncoder
*
)
_encoder
;
/* the real libopus cleanup was already performed by
opus_encoder_close(), so no real work here */
delete
encoder
;
}
bool
OpusEncoder
::
Open
(
AudioFormat
&
_audio_format
,
Error
&
error
)
OpusEncoder
::
OpusEncoder
(
AudioFormat
&
_audio_format
,
::
OpusEncoder
*
_enc
)
:
Encoder
(
false
),
audio_format
(
_audio_format
),
frame_size
(
_audio_format
.
GetFrameSize
()),
buffer_frames
(
_audio_format
.
sample_rate
/
50
),
buffer_size
(
frame_size
*
buffer_frames
),
buffer
((
unsigned
char
*
)
xalloc
(
buffer_size
)),
enc
(
_enc
)
{
opus_encoder_ctl
(
enc
,
OPUS_GET_LOOKAHEAD
(
&
lookahead
));
stream
.
Initialize
(
GenerateOggSerial
());
}
Encoder
*
PreparedOpusEncoder
::
Open
(
AudioFormat
&
audio_format
,
Error
&
error
)
{
/* 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
;
}
audio_format
=
_audio_format
;
frame_size
=
_audio_format
.
GetFrameSize
();
int
error_code
;
enc
=
opus_encoder_create
(
_
audio_format
.
sample_rate
,
_
audio_format
.
channels
,
OPUS_APPLICATION_AUDIO
,
&
error_code
);
auto
*
enc
=
opus_encoder_create
(
audio_format
.
sample_rate
,
audio_format
.
channels
,
OPUS_APPLICATION_AUDIO
,
&
error_code
);
if
(
enc
==
nullptr
)
{
error
.
Set
(
opus_encoder_domain
,
error_code
,
opus_strerror
(
error_code
));
return
false
;
return
nullptr
;
}
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
,
OPUS_GET_LOOKAHEAD
(
&
lookahead
));
buffer_frames
=
_audio_format
.
sample_rate
/
50
;
buffer_size
=
frame_size
*
buffer_frames
;
buffer_position
=
0
;
buffer
=
(
unsigned
char
*
)
xalloc
(
buffer_size
);
stream
.
Initialize
(
GenerateOggSerial
());
packetno
=
0
;
return
true
;
return
new
OpusEncoder
(
audio_format
,
enc
);
}
static
bool
opus_encoder_open
(
Encoder
*
_encoder
,
static
Encoder
*
opus_encoder_open
(
Prepared
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
auto
&
encoder
=
*
(
Prepared
OpusEncoder
*
)
_encoder
;
return
encoder
.
Open
(
audio_format
,
error
);
}
void
OpusEncoder
::
Close
()
OpusEncoder
::~
OpusEncoder
()
{
stream
.
Deinitialize
();
free
(
buffer
);
opus_encoder_destroy
(
enc
);
}
static
void
opus_encoder_close
(
Encoder
*
_encoder
)
{
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
encoder
.
Close
();
}
bool
OpusEncoder
::
DoEncode
(
bool
eos
,
Error
&
error
)
{
...
...
@@ -281,13 +280,6 @@ OpusEncoder::End(Error &error)
return
DoEncode
(
true
,
error
);
}
static
bool
opus_encoder_end
(
Encoder
*
_encoder
,
Error
&
error
)
{
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
return
encoder
.
End
(
error
);
}
bool
OpusEncoder
::
Flush
(
gcc_unused
Error
&
error
)
{
...
...
@@ -295,14 +287,6 @@ OpusEncoder::Flush(gcc_unused Error &error)
return
true
;
}
static
bool
opus_encoder_flush
(
Encoder
*
_encoder
,
Error
&
error
)
{
auto
&
encoder
=
*
(
OpusEncoder
*
)
_encoder
;
return
encoder
.
Flush
(
error
);
}
bool
OpusEncoder
::
WriteSilence
(
unsigned
fill_frames
,
Error
&
error
)
{
...
...
@@ -360,15 +344,6 @@ OpusEncoder::Write(const void *_data, size_t length, Error &error)
return
true
;
}
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
()
{
...
...
@@ -430,30 +405,18 @@ OpusEncoder::Read(void *dest, size_t length)
return
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
*
opus_encoder_get_mime_type
(
gcc_unused
Encoder
*
_encoder
)
opus_encoder_get_mime_type
(
gcc_unused
Prepared
Encoder
*
_encoder
)
{
return
"audio/ogg"
;
}
}
const
EncoderPlugin
opus_encoder_plugin
=
{
"opus"
,
opus_encoder_init
,
opus_encoder_finish
,
opus_encoder_open
,
opus_encoder_close
,
opus_encoder_end
,
opus_encoder_flush
,
nullptr
,
nullptr
,
opus_encoder_write
,
opus_encoder_read
,
opus_encoder_get_mime_type
,
};
src/encoder/plugins/ShineEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -22,7 +22,6 @@
#include "../EncoderAPI.hxx"
#include "AudioFormat.hxx"
#include "config/ConfigError.hxx"
#include "util/Manual.hxx"
#include "util/DynamicFifoBuffer.hxx"
#include "util/Error.hxx"
...
...
@@ -34,32 +33,71 @@ extern "C"
static
constexpr
size_t
BUFFER_INIT_SIZE
=
8192
;
static
constexpr
unsigned
CHANNELS
=
2
;
struct
Shine
Encoder
{
Encoder
encoder
;
class
ShineEncoder
final
:
public
Encoder
{
const
AudioFormat
audio_format
;
AudioFormat
audio_format
;
const
shine_t
shine
;
shine_t
shin
e
;
const
size_t
frame_siz
e
;
shine_config_t
config
;
/* workaround for bug:
https://github.com/savonet/shine/issues/11 */
size_t
input_pos
=
SHINE_MAX_SAMPLES
+
1
;
size_t
frame_size
;
size_t
input_pos
;
int16_t
*
stereo
[
CHANNELS
];
Manual
<
DynamicFifoBuffer
<
uint8_t
>>
output_buffer
;
DynamicFifoBuffer
<
uint8_t
>
output_buffer
;
public
:
ShineEncoder
(
AudioFormat
_audio_format
,
shine_t
_shine
)
:
Encoder
(
false
),
audio_format
(
_audio_format
),
shine
(
_shine
),
frame_size
(
shine_samples_per_pass
(
shine
)),
stereo
{
new
int16_t
[
frame_size
],
new
int16_t
[
frame_size
]},
output_buffer
(
BUFFER_INIT_SIZE
)
{}
~
ShineEncoder
()
override
{
if
(
input_pos
>
SHINE_MAX_SAMPLES
)
{
/* write zero chunk */
input_pos
=
0
;
WriteChunk
(
true
);
}
shine_close
(
shine
);
delete
[]
stereo
[
0
];
delete
[]
stereo
[
1
];
}
bool
WriteChunk
(
bool
flush
);
/* virtual methods from class Encoder */
bool
End
(
Error
&
error
)
override
{
return
Flush
(
error
);
}
bool
Flush
(
Error
&
)
override
;
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
;
size_t
Read
(
void
*
dest
,
size_t
length
)
override
{
return
output_buffer
.
Read
((
uint8_t
*
)
dest
,
length
);
}
};
ShineEncoder
()
:
encoder
(
shine_encoder_plugin
){}
struct
PreparedShineEncoder
{
PreparedEncoder
encoder
;
shine_config_t
config
;
PreparedShineEncoder
()
:
encoder
(
shine_encoder_plugin
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
bool
Setup
(
Error
&
error
);
bool
WriteChunk
(
bool
flush
);
};
inline
bool
ShineEncoder
::
Configure
(
const
ConfigBlock
&
block
,
gcc_unused
Error
&
error
)
PreparedShineEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
)
{
shine_set_config_mpeg_defaults
(
&
config
.
mpeg
);
config
.
mpeg
.
bitr
=
block
.
GetBlockValue
(
"bitrate"
,
128
);
...
...
@@ -67,10 +105,10 @@ ShineEncoder::Configure(const ConfigBlock &block, gcc_unused Error &error)
return
true
;
}
static
Encoder
*
static
Prepared
Encoder
*
shine_encoder_init
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
ShineEncoder
*
encoder
=
new
ShineEncoder
();
auto
*
encoder
=
new
Prepared
ShineEncoder
();
/* load configuration from "block" */
if
(
!
encoder
->
Configure
(
block
,
error
))
{
...
...
@@ -83,16 +121,20 @@ shine_encoder_init(const ConfigBlock &block, Error &error)
}
static
void
shine_encoder_finish
(
Encoder
*
_encoder
)
shine_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
ShineEncoder
*
encoder
=
(
ShineEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
ShineEncoder
*
)
_encoder
;
delete
encoder
;
}
inline
bool
ShineEncoder
::
Setup
(
Error
&
error
)
static
shine_t
SetupShine
(
shine_config_t
config
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
audio_format
.
format
=
SampleFormat
::
S16
;
audio_format
.
channels
=
CHANNELS
;
config
.
mpeg
.
mode
=
audio_format
.
channels
==
2
?
STEREO
:
MONO
;
config
.
wave
.
samplerate
=
audio_format
.
sample_rate
;
config
.
wave
.
channels
=
...
...
@@ -106,61 +148,28 @@ ShineEncoder::Setup(Error &error)
config
.
wave
.
samplerate
,
config
.
mpeg
.
bitr
);
return
false
;
return
nullptr
;
}
shine
=
shine_initialise
(
&
config
);
if
(
!
shine
)
{
auto
shine
=
shine_initialise
(
&
config
);
if
(
!
shine
)
error
.
Format
(
config_domain
,
"error initializing shine."
);
return
false
;
}
frame_size
=
shine_samples_per_pass
(
shine
);
return
true
;
}
static
bool
shine_encoder_open
(
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
ShineEncoder
*
encoder
=
(
ShineEncoder
*
)
_encoder
;
audio_format
.
format
=
SampleFormat
::
S16
;
audio_format
.
channels
=
CHANNELS
;
encoder
->
audio_format
=
audio_format
;
if
(
!
encoder
->
Setup
(
error
))
return
false
;
encoder
->
stereo
[
0
]
=
new
int16_t
[
encoder
->
frame_size
];
encoder
->
stereo
[
1
]
=
new
int16_t
[
encoder
->
frame_size
];
/* workaround for bug:
https://github.com/savonet/shine/issues/11 */
encoder
->
input_pos
=
SHINE_MAX_SAMPLES
+
1
;
encoder
->
output_buffer
.
Construct
(
BUFFER_INIT_SIZE
);
return
true
;
return
shine
;
}
static
void
shine_encoder_close
(
Encoder
*
_encoder
)
static
Encoder
*
shine_encoder_open
(
PreparedEncoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
ShineEncoder
*
encoder
=
(
ShineEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
ShineEncoder
*
)
_encoder
;
if
(
encoder
->
input_pos
>
SHINE_MAX_SAMPLES
)
{
/* write zero chunk */
encoder
->
input_pos
=
0
;
encoder
->
WriteChunk
(
true
);
}
auto
shine
=
SetupShine
(
encoder
->
config
,
audio_format
,
error
);
if
(
!
shine
)
return
nullptr
;
shine_close
(
encoder
->
shine
);
delete
[]
encoder
->
stereo
[
0
];
delete
[]
encoder
->
stereo
[
1
];
encoder
->
output_buffer
.
Destruct
();
return
new
ShineEncoder
(
audio_format
,
shine
);
}
bool
...
...
@@ -179,7 +188,7 @@ ShineEncoder::WriteChunk(bool flush)
shine_encode_buffer
(
shine
,
stereo
,
&
written
);
if
(
written
>
0
)
output_buffer
->
Append
(
out
,
written
);
output_buffer
.
Append
(
out
,
written
);
input_pos
=
0
;
}
...
...
@@ -187,65 +196,50 @@ ShineEncoder::WriteChunk(bool flush)
return
true
;
}
static
bool
shine_encoder_write
(
Encoder
*
_encoder
,
const
void
*
_data
,
size_t
length
,
gcc_unused
Error
&
error
)
bool
ShineEncoder
::
Write
(
const
void
*
_data
,
size_t
length
,
gcc_unused
Error
&
error
)
{
ShineEncoder
*
encoder
=
(
ShineEncoder
*
)
_encoder
;
const
int16_t
*
data
=
(
const
int16_t
*
)
_data
;
length
/=
sizeof
(
*
data
)
*
encoder
->
audio_format
.
channels
;
length
/=
sizeof
(
*
data
)
*
audio_format
.
channels
;
size_t
written
=
0
;
if
(
encoder
->
input_pos
>
SHINE_MAX_SAMPLES
)
{
encoder
->
input_pos
=
0
;
}
if
(
input_pos
>
SHINE_MAX_SAMPLES
)
input_pos
=
0
;
/* write all data to de-interleaved buffers */
while
(
written
<
length
)
{
for
(;
written
<
length
&&
encoder
->
input_pos
<
encoder
->
frame_size
;
written
++
,
encoder
->
input_pos
++
)
{
written
<
length
&&
input_pos
<
frame_size
;
written
++
,
input_pos
++
)
{
const
size_t
base
=
written
*
encoder
->
audio_format
.
channels
;
encoder
->
stereo
[
0
][
encoder
->
input_pos
]
=
data
[
base
];
encoder
->
stereo
[
1
][
encoder
->
input_pos
]
=
data
[
base
+
1
];
written
*
audio_format
.
channels
;
stereo
[
0
][
input_pos
]
=
data
[
base
];
stereo
[
1
][
input_pos
]
=
data
[
base
+
1
];
}
/* write if chunk is filled */
encoder
->
WriteChunk
(
false
);
WriteChunk
(
false
);
}
return
true
;
}
static
bool
shine_encoder_flush
(
Encoder
*
_encoder
,
gcc_unused
Error
&
error
)
bool
ShineEncoder
::
Flush
(
gcc_unused
Error
&
error
)
{
ShineEncoder
*
encoder
=
(
ShineEncoder
*
)
_encoder
;
/* flush buffers and flush shine */
encoder
->
WriteChunk
(
true
);
WriteChunk
(
true
);
int
written
;
const
uint8_t
*
data
=
shine_flush
(
encoder
->
shine
,
&
written
);
const
uint8_t
*
data
=
shine_flush
(
shine
,
&
written
);
if
(
written
>
0
)
encoder
->
output_buffer
->
Append
(
data
,
written
);
output_buffer
.
Append
(
data
,
written
);
return
true
;
}
static
size_t
shine_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
{
ShineEncoder
*
encoder
=
(
ShineEncoder
*
)
_encoder
;
return
encoder
->
output_buffer
->
Read
((
uint8_t
*
)
dest
,
length
);
}
static
const
char
*
shine_encoder_get_mime_type
(
gcc_unused
Encoder
*
_encoder
)
shine_encoder_get_mime_type
(
gcc_unused
Prepared
Encoder
*
_encoder
)
{
return
"audio/mpeg"
;
}
...
...
@@ -255,12 +249,5 @@ const EncoderPlugin shine_encoder_plugin = {
shine_encoder_init
,
shine_encoder_finish
,
shine_encoder_open
,
shine_encoder_close
,
shine_encoder_flush
,
shine_encoder_flush
,
nullptr
,
nullptr
,
shine_encoder_write
,
shine_encoder_read
,
shine_encoder_get_mime_type
,
};
src/encoder/plugins/TwolameEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -32,26 +32,53 @@
#include <assert.h>
#include <string.h>
struct
TwolameEncoder
final
{
Encoder
encoder
;
AudioFormat
audio_format
;
float
quality
;
int
bitrate
;
class
TwolameEncoder
final
:
public
Encoder
{
const
AudioFormat
audio_format
;
twolame_options
*
options
;
unsigned
char
output_buffer
[
32768
];
size_t
output_buffer_length
;
size_t
output_buffer_position
;
size_t
output_buffer_length
=
0
;
size_t
output_buffer_position
=
0
;
/**
* Call libtwolame's flush function when the output_buffer is
* empty?
*/
bool
flush
;
bool
flush
=
false
;
TwolameEncoder
()
:
encoder
(
twolame_encoder_plugin
)
{}
public
:
TwolameEncoder
(
const
AudioFormat
_audio_format
,
twolame_options
*
_options
)
:
Encoder
(
false
),
audio_format
(
_audio_format
),
options
(
_options
)
{}
~
TwolameEncoder
()
override
;
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
/* virtual methods from class Encoder */
bool
End
(
Error
&
)
override
{
flush
=
true
;
return
true
;
}
bool
Flush
(
Error
&
)
override
{
flush
=
true
;
return
true
;
}
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
;
size_t
Read
(
void
*
dest
,
size_t
length
)
override
;
};
struct
PreparedTwolameEncoder
final
{
PreparedEncoder
encoder
;
float
quality
;
int
bitrate
;
PreparedTwolameEncoder
()
:
encoder
(
twolame_encoder_plugin
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
};
...
...
@@ -59,7 +86,7 @@ struct TwolameEncoder final {
static
constexpr
Domain
twolame_encoder_domain
(
"twolame_encoder"
);
bool
TwolameEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
Prepared
TwolameEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
const
char
*
value
;
char
*
endptr
;
...
...
@@ -106,13 +133,13 @@ TwolameEncoder::Configure(const ConfigBlock &block, Error &error)
return
true
;
}
static
Encoder
*
static
Prepared
Encoder
*
twolame_encoder_init
(
const
ConfigBlock
&
block
,
Error
&
error_r
)
{
FormatDebug
(
twolame_encoder_domain
,
"libtwolame version %s"
,
get_twolame_version
());
TwolameEncoder
*
encoder
=
new
TwolameEncoder
();
auto
*
encoder
=
new
Prepared
TwolameEncoder
();
/* load configuration from "block" */
if
(
!
encoder
->
Configure
(
block
,
error_r
))
{
...
...
@@ -125,9 +152,9 @@ twolame_encoder_init(const ConfigBlock &block, Error &error_r)
}
static
void
twolame_encoder_finish
(
Encoder
*
_encoder
)
twolame_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
TwolameEncoder
*
encoder
=
(
TwolameEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
TwolameEncoder
*
)
_encoder
;
/* the real libtwolame cleanup was already performed by
twolame_encoder_close(), so no real work here */
...
...
@@ -135,17 +162,18 @@ twolame_encoder_finish(Encoder *_encoder)
}
static
bool
twolame_encoder_setup
(
TwolameEncoder
*
encoder
,
Error
&
error
)
twolame_encoder_setup
(
twolame_options
*
options
,
float
quality
,
int
bitrate
,
const
AudioFormat
&
audio_format
,
Error
&
error
)
{
if
(
encoder
->
quality
>=
-
1.0
)
{
if
(
quality
>=
-
1.0
)
{
/* a quality was configured (VBR) */
if
(
0
!=
twolame_set_VBR
(
encoder
->
options
,
true
))
{
if
(
0
!=
twolame_set_VBR
(
options
,
true
))
{
error
.
Set
(
twolame_encoder_domain
,
"error setting twolame VBR mode"
);
return
false
;
}
if
(
0
!=
twolame_set_VBR_q
(
encoder
->
options
,
encoder
->
quality
))
{
if
(
0
!=
twolame_set_VBR_q
(
options
,
quality
))
{
error
.
Set
(
twolame_encoder_domain
,
"error setting twolame VBR quality"
);
return
false
;
...
...
@@ -153,28 +181,27 @@ twolame_encoder_setup(TwolameEncoder *encoder, Error &error)
}
else
{
/* a bit rate was configured */
if
(
0
!=
twolame_set_brate
(
encoder
->
options
,
encoder
->
bitrate
))
{
if
(
0
!=
twolame_set_brate
(
options
,
bitrate
))
{
error
.
Set
(
twolame_encoder_domain
,
"error setting twolame bitrate"
);
return
false
;
}
}
if
(
0
!=
twolame_set_num_channels
(
encoder
->
options
,
encoder
->
audio_format
.
channels
))
{
if
(
0
!=
twolame_set_num_channels
(
options
,
audio_format
.
channels
))
{
error
.
Set
(
twolame_encoder_domain
,
"error setting twolame num channels"
);
return
false
;
}
if
(
0
!=
twolame_set_in_samplerate
(
encoder
->
options
,
encoder
->
audio_format
.
sample_rate
))
{
if
(
0
!=
twolame_set_in_samplerate
(
options
,
audio_format
.
sample_rate
))
{
error
.
Set
(
twolame_encoder_domain
,
"error setting twolame sample rate"
);
return
false
;
}
if
(
0
>
twolame_init_params
(
encoder
->
options
))
{
if
(
0
>
twolame_init_params
(
options
))
{
error
.
Set
(
twolame_encoder_domain
,
"error initializing twolame params"
);
return
false
;
...
...
@@ -183,117 +210,89 @@ twolame_encoder_setup(TwolameEncoder *encoder, Error &error)
return
true
;
}
static
bool
twolame_encoder_open
(
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
static
Encoder
*
twolame_encoder_open
(
Prepared
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
TwolameEncoder
*
encoder
=
(
TwolameEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
TwolameEncoder
*
)
_encoder
;
audio_format
.
format
=
SampleFormat
::
S16
;
audio_format
.
channels
=
2
;
encoder
->
audio_format
=
audio_format
;
encoder
->
options
=
twolame_init
();
if
(
encoder
->
options
==
nullptr
)
{
auto
options
=
twolame_init
();
if
(
options
==
nullptr
)
{
error
.
Set
(
twolame_encoder_domain
,
"twolame_init() failed"
);
return
false
;
return
nullptr
;
}
if
(
!
twolame_encoder_setup
(
encoder
,
error
))
{
twolame_close
(
&
encoder
->
options
);
return
false
;
if
(
!
twolame_encoder_setup
(
options
,
encoder
->
quality
,
encoder
->
bitrate
,
audio_format
,
error
))
{
twolame_close
(
&
options
);
return
nullptr
;
}
encoder
->
output_buffer_length
=
0
;
encoder
->
output_buffer_position
=
0
;
encoder
->
flush
=
false
;
return
true
;
return
new
TwolameEncoder
(
audio_format
,
options
);
}
static
void
twolame_encoder_close
(
Encoder
*
_encoder
)
TwolameEncoder
::~
TwolameEncoder
()
{
TwolameEncoder
*
encoder
=
(
TwolameEncoder
*
)
_encoder
;
twolame_close
(
&
encoder
->
options
);
twolame_close
(
&
options
);
}
static
bool
twolame_encoder_flush
(
Encoder
*
_encoder
,
gcc_unused
Error
&
error
)
{
TwolameEncoder
*
encoder
=
(
TwolameEncoder
*
)
_encoder
;
encoder
->
flush
=
true
;
return
true
;
}
static
bool
twolame_encoder_write
(
Encoder
*
_encoder
,
const
void
*
data
,
size_t
length
,
bool
TwolameEncoder
::
Write
(
const
void
*
data
,
size_t
length
,
gcc_unused
Error
&
error
)
{
TwolameEncoder
*
encoder
=
(
TwolameEncoder
*
)
_encoder
;
const
int16_t
*
src
=
(
const
int16_t
*
)
data
;
assert
(
encoder
->
output_buffer_position
==
encoder
->
output_buffer_length
);
assert
(
output_buffer_position
==
output_buffer_length
);
const
unsigned
num_frames
=
length
/
encoder
->
audio_format
.
GetFrameSize
();
const
unsigned
num_frames
=
length
/
audio_format
.
GetFrameSize
();
int
bytes_out
=
twolame_encode_buffer_interleaved
(
encoder
->
options
,
int
bytes_out
=
twolame_encode_buffer_interleaved
(
options
,
src
,
num_frames
,
encoder
->
output_buffer
,
sizeof
(
encoder
->
output_buffer
));
output_buffer
,
sizeof
(
output_buffer
));
if
(
bytes_out
<
0
)
{
error
.
Set
(
twolame_encoder_domain
,
"twolame encoder failed"
);
return
false
;
}
encoder
->
output_buffer_length
=
(
size_t
)
bytes_out
;
encoder
->
output_buffer_position
=
0
;
output_buffer_length
=
(
size_t
)
bytes_out
;
output_buffer_position
=
0
;
return
true
;
}
s
tatic
s
ize_t
twolame_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
size_t
TwolameEncoder
::
Read
(
void
*
dest
,
size_t
length
)
{
TwolameEncoder
*
encoder
=
(
TwolameEncoder
*
)
_encoder
;
assert
(
encoder
->
output_buffer_position
<=
encoder
->
output_buffer_length
);
assert
(
output_buffer_position
<=
output_buffer_length
);
if
(
encoder
->
output_buffer_position
==
encoder
->
output_buffer_length
&&
encoder
->
flush
)
{
int
ret
=
twolame_encode_flush
(
encoder
->
options
,
encoder
->
output_buffer
,
sizeof
(
encoder
->
output_buffer
));
if
(
output_buffer_position
==
output_buffer_length
&&
flush
)
{
int
ret
=
twolame_encode_flush
(
options
,
output_buffer
,
sizeof
(
output_buffer
));
if
(
ret
>
0
)
{
encoder
->
output_buffer_length
=
(
size_t
)
ret
;
encoder
->
output_buffer_position
=
0
;
output_buffer_length
=
(
size_t
)
ret
;
output_buffer_position
=
0
;
}
encoder
->
flush
=
false
;
flush
=
false
;
}
const
size_t
remainning
=
encoder
->
output_buffer_length
-
encoder
->
output_buffer_position
;
const
size_t
remainning
=
output_buffer_length
-
output_buffer_position
;
if
(
length
>
remainning
)
length
=
remainning
;
memcpy
(
dest
,
encoder
->
output_buffer
+
encoder
->
output_buffer_position
,
length
);
memcpy
(
dest
,
output_buffer
+
output_buffer_position
,
length
);
encoder
->
output_buffer_position
+=
length
;
output_buffer_position
+=
length
;
return
length
;
}
static
const
char
*
twolame_encoder_get_mime_type
(
gcc_unused
Encoder
*
_encoder
)
twolame_encoder_get_mime_type
(
gcc_unused
Prepared
Encoder
*
_encoder
)
{
return
"audio/mpeg"
;
}
...
...
@@ -303,12 +302,5 @@ const EncoderPlugin twolame_encoder_plugin = {
twolame_encoder_init
,
twolame_encoder_finish
,
twolame_encoder_open
,
twolame_encoder_close
,
twolame_encoder_flush
,
twolame_encoder_flush
,
nullptr
,
nullptr
,
twolame_encoder_write
,
twolame_encoder_read
,
twolame_encoder_get_mime_type
,
};
src/encoder/plugins/VorbisEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -31,17 +31,7 @@
#include <vorbis/vorbisenc.h>
struct
VorbisEncoder
{
/** the base class */
Encoder
encoder
;
/* configuration */
float
quality
;
int
bitrate
;
/* runtime information */
class
VorbisEncoder
final
:
public
Encoder
{
AudioFormat
audio_format
;
vorbis_dsp_state
vd
;
...
...
@@ -50,22 +40,57 @@ struct VorbisEncoder {
OggStream
stream
;
VorbisEncoder
()
:
encoder
(
vorbis_encoder_plugin
)
{}
public
:
VorbisEncoder
()
:
Encoder
(
true
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
virtual
~
VorbisEncoder
()
{
Clear
();
}
bool
Reinit
(
Error
&
error
);
bool
Open
(
float
quality
,
int
bitrate
,
AudioFormat
&
audio_format
,
Error
&
error
);
/* virtual methods from class Encoder */
bool
End
(
Error
&
error
)
override
{
return
PreTag
(
error
);
}
bool
Flush
(
Error
&
error
)
override
;
bool
PreTag
(
Error
&
error
)
override
;
bool
SendTag
(
const
Tag
&
tag
,
Error
&
error
)
override
;
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
;
size_t
Read
(
void
*
dest
,
size_t
length
)
override
{
return
stream
.
PageOut
(
dest
,
length
);
}
private
:
void
HeaderOut
(
vorbis_comment
&
vc
);
void
SendHeader
();
void
BlockOut
();
void
Clear
();
};
struct
PreparedVorbisEncoder
{
/** the base class */
PreparedEncoder
encoder
;
/* configuration */
float
quality
;
int
bitrate
;
PreparedVorbisEncoder
()
:
encoder
(
vorbis_encoder_plugin
)
{}
bool
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
);
};
static
constexpr
Domain
vorbis_encoder_domain
(
"vorbis_encoder"
);
bool
VorbisEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
Prepared
VorbisEncoder
::
Configure
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
const
char
*
value
=
block
.
GetBlockValue
(
"quality"
);
if
(
value
!=
nullptr
)
{
...
...
@@ -111,10 +136,10 @@ VorbisEncoder::Configure(const ConfigBlock &block, Error &error)
return
true
;
}
static
Encoder
*
static
Prepared
Encoder
*
vorbis_encoder_init
(
const
ConfigBlock
&
block
,
Error
&
error
)
{
auto
*
encoder
=
new
VorbisEncoder
();
auto
*
encoder
=
new
Prepared
VorbisEncoder
();
/* load configuration from "block" */
if
(
!
encoder
->
Configure
(
block
,
error
))
{
...
...
@@ -127,9 +152,9 @@ vorbis_encoder_init(const ConfigBlock &block, Error &error)
}
static
void
vorbis_encoder_finish
(
Encoder
*
_encoder
)
vorbis_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
VorbisEncoder
*
encoder
=
(
VorbisEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
VorbisEncoder
*
)
_encoder
;
/* the real libvorbis/libogg cleanup was already performed by
vorbis_encoder_close(), so no real work here */
...
...
@@ -137,8 +162,12 @@ vorbis_encoder_finish(Encoder *_encoder)
}
bool
VorbisEncoder
::
Reinit
(
Error
&
error
)
VorbisEncoder
::
Open
(
float
quality
,
int
bitrate
,
AudioFormat
&
_audio_format
,
Error
&
error
)
{
_audio_format
.
format
=
SampleFormat
::
FLOAT
;
audio_format
=
_audio_format
;
vorbis_info_init
(
&
vi
);
if
(
quality
>=
-
1.0
)
{
...
...
@@ -171,6 +200,8 @@ VorbisEncoder::Reinit(Error &error)
vorbis_block_init
(
&
vd
,
&
vb
);
stream
.
Initialize
(
GenerateOggSerial
());
SendHeader
();
return
true
;
}
...
...
@@ -197,23 +228,20 @@ VorbisEncoder::SendHeader()
vorbis_comment_clear
(
&
vc
);
}
static
bool
vorbis_encoder_open
(
Encoder
*
_encoder
,
static
Encoder
*
vorbis_encoder_open
(
Prepared
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
auto
&
encoder
=
*
(
VorbisEncoder
*
)
_encoder
;
audio_format
.
format
=
SampleFormat
::
FLOAT
;
auto
&
encoder
=
*
(
PreparedVorbisEncoder
*
)
_encoder
;
encoder
.
audio_format
=
audio_format
;
if
(
!
encoder
.
Reinit
(
error
))
return
false
;
encoder
.
SendHeader
();
auto
*
e
=
new
VorbisEncoder
();
if
(
!
e
->
Open
(
encoder
.
quality
,
encoder
.
bitrate
,
audio_format
,
error
))
{
delete
e
;
return
nullptr
;
}
return
tru
e
;
return
e
;
}
void
...
...
@@ -225,14 +253,6 @@ VorbisEncoder::Clear()
vorbis_info_clear
(
&
vi
);
}
static
void
vorbis_encoder_close
(
Encoder
*
_encoder
)
{
auto
&
encoder
=
*
(
VorbisEncoder
*
)
_encoder
;
encoder
.
Clear
();
}
void
VorbisEncoder
::
BlockOut
()
{
...
...
@@ -246,31 +266,27 @@ VorbisEncoder::BlockOut()
}
}
static
bool
vorbis_encoder_flush
(
Encoder
*
_encoder
,
gcc_unused
Error
&
error
)
bool
VorbisEncoder
::
Flush
(
gcc_unused
Error
&
error
)
{
auto
&
encoder
=
*
(
VorbisEncoder
*
)
_encoder
;
encoder
.
stream
.
Flush
();
stream
.
Flush
();
return
true
;
}
static
bool
vorbis_encoder_pre_tag
(
Encoder
*
_encoder
,
gcc_unused
Error
&
error
)
bool
VorbisEncoder
::
PreTag
(
gcc_unused
Error
&
error
)
{
auto
&
encoder
=
*
(
VorbisEncoder
*
)
_encoder
;
vorbis_analysis_wrote
(
&
encoder
.
vd
,
0
);
encoder
.
BlockOut
();
vorbis_analysis_wrote
(
&
vd
,
0
);
BlockOut
();
/* reinitialize vorbis_dsp_state and vorbis_block to reset the
end-of-stream marker */
vorbis_block_clear
(
&
encoder
.
vb
);
vorbis_dsp_clear
(
&
encoder
.
vd
);
vorbis_analysis_init
(
&
encoder
.
vd
,
&
encoder
.
vi
);
vorbis_block_init
(
&
encoder
.
vd
,
&
encoder
.
vb
);
vorbis_block_clear
(
&
vb
);
vorbis_dsp_clear
(
&
vd
);
vorbis_analysis_init
(
&
vd
,
&
vi
);
vorbis_block_init
(
&
vd
,
&
vb
);
encoder
.
stream
.
Flush
();
stream
.
Flush
();
return
true
;
}
...
...
@@ -284,11 +300,9 @@ copy_tag_to_vorbis_comment(vorbis_comment *vc, const Tag &tag)
}
}
static
bool
vorbis_encoder_tag
(
Encoder
*
_encoder
,
const
Tag
&
tag
,
gcc_unused
Error
&
error
)
bool
VorbisEncoder
::
SendTag
(
const
Tag
&
tag
,
gcc_unused
Error
&
error
)
{
auto
&
encoder
=
*
(
VorbisEncoder
*
)
_encoder
;
vorbis_comment
comment
;
/* write the vorbis_comment object */
...
...
@@ -298,11 +312,11 @@ vorbis_encoder_tag(Encoder *_encoder, const Tag &tag,
/* reset ogg_stream_state and begin a new stream */
encoder
.
stream
.
Reinitialize
(
GenerateOggSerial
());
stream
.
Reinitialize
(
GenerateOggSerial
());
/* send that vorbis_comment to the ogg_stream_state */
encoder
.
HeaderOut
(
comment
);
HeaderOut
(
comment
);
vorbis_comment_clear
(
&
comment
);
return
true
;
...
...
@@ -317,38 +331,25 @@ interleaved_to_vorbis_buffer(float **dest, const float *src,
dest
[
j
][
i
]
=
*
src
++
;
}
static
bool
vorbis_encoder_write
(
Encoder
*
_encoder
,
const
void
*
data
,
size_t
length
,
gcc_unused
Error
&
error
)
bool
VorbisEncoder
::
Write
(
const
void
*
data
,
size_t
length
,
gcc_unused
Error
&
error
)
{
auto
&
encoder
=
*
(
VorbisEncoder
*
)
_encoder
;
unsigned
num_frames
=
length
/
encoder
.
audio_format
.
GetFrameSize
();
unsigned
num_frames
=
length
/
audio_format
.
GetFrameSize
();
/* this is for only 16-bit audio */
interleaved_to_vorbis_buffer
(
vorbis_analysis_buffer
(
&
encoder
.
vd
,
num_frames
),
interleaved_to_vorbis_buffer
(
vorbis_analysis_buffer
(
&
vd
,
num_frames
),
(
const
float
*
)
data
,
num_frames
,
encoder
.
audio_format
.
channels
);
audio_format
.
channels
);
vorbis_analysis_wrote
(
&
encoder
.
vd
,
num_frames
);
encoder
.
BlockOut
();
vorbis_analysis_wrote
(
&
vd
,
num_frames
);
BlockOut
();
return
true
;
}
static
size_t
vorbis_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
{
auto
&
encoder
=
*
(
VorbisEncoder
*
)
_encoder
;
return
encoder
.
stream
.
PageOut
(
dest
,
length
);
}
static
const
char
*
vorbis_encoder_get_mime_type
(
gcc_unused
Encoder
*
_encoder
)
vorbis_encoder_get_mime_type
(
gcc_unused
Prepared
Encoder
*
_encoder
)
{
return
"audio/ogg"
;
}
...
...
@@ -358,12 +359,5 @@ const EncoderPlugin vorbis_encoder_plugin = {
vorbis_encoder_init
,
vorbis_encoder_finish
,
vorbis_encoder_open
,
vorbis_encoder_close
,
vorbis_encoder_pre_tag
,
vorbis_encoder_flush
,
vorbis_encoder_pre_tag
,
vorbis_encoder_tag
,
vorbis_encoder_write
,
vorbis_encoder_read
,
vorbis_encoder_get_mime_type
,
};
src/encoder/plugins/WaveEncoderPlugin.cxx
View file @
e7edc026
...
...
@@ -21,7 +21,6 @@
#include "WaveEncoderPlugin.hxx"
#include "../EncoderAPI.hxx"
#include "system/ByteOrder.hxx"
#include "util/Manual.hxx"
#include "util/DynamicFifoBuffer.hxx"
#include <assert.h>
...
...
@@ -29,13 +28,26 @@
static
constexpr
uint16_t
WAVE_FORMAT_PCM
=
1
;
struct
WaveEncoder
{
Encoder
encoder
;
class
WaveEncoder
final
:
public
Encoder
{
unsigned
bits
;
Manual
<
DynamicFifoBuffer
<
uint8_t
>
>
buffer
;
DynamicFifoBuffer
<
uint8_t
>
buffer
;
WaveEncoder
()
:
encoder
(
wave_encoder_plugin
)
{}
public
:
WaveEncoder
(
AudioFormat
&
audio_format
);
/* virtual methods from class Encoder */
bool
Write
(
const
void
*
data
,
size_t
length
,
Error
&
)
override
;
size_t
Read
(
void
*
dest
,
size_t
length
)
override
{
return
buffer
.
Read
((
uint8_t
*
)
dest
,
length
);
}
};
struct
PreparedWaveEncoder
{
PreparedEncoder
encoder
;
PreparedWaveEncoder
()
:
encoder
(
wave_encoder_plugin
)
{}
};
struct
WaveHeader
{
...
...
@@ -80,78 +92,71 @@ fill_wave_header(WaveHeader *header, int channels, int bits,
header
->
riff_size
=
ToLE32
(
4
+
(
8
+
16
)
+
(
8
+
data_size
));
}
static
Encoder
*
static
Prepared
Encoder
*
wave_encoder_init
(
gcc_unused
const
ConfigBlock
&
block
,
gcc_unused
Error
&
error
)
{
WaveEncoder
*
encoder
=
new
WaveEncoder
();
auto
*
encoder
=
new
Prepared
WaveEncoder
();
return
&
encoder
->
encoder
;
}
static
void
wave_encoder_finish
(
Encoder
*
_encoder
)
wave_encoder_finish
(
Prepared
Encoder
*
_encoder
)
{
WaveEncoder
*
encoder
=
(
WaveEncoder
*
)
_encoder
;
auto
*
encoder
=
(
Prepared
WaveEncoder
*
)
_encoder
;
delete
encoder
;
}
static
bool
wave_encoder_open
(
Encoder
*
_encoder
,
AudioFormat
&
audio_format
,
gcc_unused
Error
&
error
)
WaveEncoder
::
WaveEncoder
(
AudioFormat
&
audio_format
)
:
Encoder
(
false
),
buffer
(
8192
)
{
WaveEncoder
*
encoder
=
(
WaveEncoder
*
)
_encoder
;
assert
(
audio_format
.
IsValid
());
switch
(
audio_format
.
format
)
{
case
SampleFormat
:
:
S8
:
encoder
->
bits
=
8
;
bits
=
8
;
break
;
case
SampleFormat
:
:
S16
:
encoder
->
bits
=
16
;
bits
=
16
;
break
;
case
SampleFormat
:
:
S24_P32
:
encoder
->
bits
=
24
;
bits
=
24
;
break
;
case
SampleFormat
:
:
S32
:
encoder
->
bits
=
32
;
bits
=
32
;
break
;
default
:
audio_format
.
format
=
SampleFormat
::
S16
;
encoder
->
bits
=
16
;
bits
=
16
;
break
;
}
encoder
->
buffer
.
Construct
(
8192
);
auto
range
=
encoder
->
buffer
->
Write
();
auto
range
=
buffer
.
Write
();
assert
(
range
.
size
>=
sizeof
(
WaveHeader
));
auto
*
header
=
(
WaveHeader
*
)
range
.
data
;
/* create PCM wave header in initial buffer */
fill_wave_header
(
header
,
audio_format
.
channels
,
encoder
->
bits
,
bits
,
audio_format
.
sample_rate
,
(
encoder
->
bits
/
8
)
*
audio_format
.
channels
);
encoder
->
buffer
->
Append
(
sizeof
(
*
header
));
(
bits
/
8
)
*
audio_format
.
channels
);
return
true
;
buffer
.
Append
(
sizeof
(
*
header
))
;
}
static
void
wave_encoder_close
(
Encoder
*
_encoder
)
static
Encoder
*
wave_encoder_open
(
gcc_unused
PreparedEncoder
*
_encoder
,
AudioFormat
&
audio_format
,
gcc_unused
Error
&
error
)
{
WaveEncoder
*
encoder
=
(
WaveEncoder
*
)
_encoder
;
encoder
->
buffer
.
Destruct
();
return
new
WaveEncoder
(
audio_format
);
}
static
size_t
...
...
@@ -194,17 +199,14 @@ pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length)
return
(
dst8
-
dst_old
);
}
static
bool
wave_encoder_write
(
Encoder
*
_encoder
,
const
void
*
src
,
size_t
length
,
bool
WaveEncoder
::
Write
(
const
void
*
src
,
size_t
length
,
gcc_unused
Error
&
error
)
{
WaveEncoder
*
encoder
=
(
WaveEncoder
*
)
_encoder
;
uint8_t
*
dst
=
encoder
->
buffer
->
Write
(
length
);
uint8_t
*
dst
=
buffer
.
Write
(
length
);
if
(
IsLittleEndian
())
{
switch
(
encoder
->
bits
)
{
switch
(
bits
)
{
case
8
:
case
16
:
case
32
:
// optimized cases
...
...
@@ -215,7 +217,7 @@ wave_encoder_write(Encoder *_encoder,
break
;
}
}
else
{
switch
(
encoder
->
bits
)
{
switch
(
bits
)
{
case
8
:
memcpy
(
dst
,
src
,
length
);
break
;
...
...
@@ -233,20 +235,12 @@ wave_encoder_write(Encoder *_encoder,
}
}
encoder
->
buffer
->
Append
(
length
);
buffer
.
Append
(
length
);
return
true
;
}
static
size_t
wave_encoder_read
(
Encoder
*
_encoder
,
void
*
dest
,
size_t
length
)
{
WaveEncoder
*
encoder
=
(
WaveEncoder
*
)
_encoder
;
return
encoder
->
buffer
->
Read
((
uint8_t
*
)
dest
,
length
);
}
static
const
char
*
wave_encoder_get_mime_type
(
gcc_unused
Encoder
*
_encoder
)
wave_encoder_get_mime_type
(
gcc_unused
Prepared
Encoder
*
_encoder
)
{
return
"audio/wav"
;
}
...
...
@@ -256,12 +250,5 @@ const EncoderPlugin wave_encoder_plugin = {
wave_encoder_init
,
wave_encoder_finish
,
wave_encoder_open
,
wave_encoder_close
,
nullptr
,
nullptr
,
nullptr
,
nullptr
,
wave_encoder_write
,
wave_encoder_read
,
wave_encoder_get_mime_type
,
};
src/output/plugins/RecorderOutputPlugin.cxx
View file @
e7edc026
...
...
@@ -47,7 +47,8 @@ class RecorderOutput {
/**
* The configured encoder plugin.
*/
Encoder
*
encoder
=
nullptr
;
PreparedEncoder
*
prepared_encoder
=
nullptr
;
Encoder
*
encoder
;
/**
* The destination file name.
...
...
@@ -75,8 +76,8 @@ class RecorderOutput {
:
base
(
recorder_output_plugin
)
{}
~
RecorderOutput
()
{
if
(
encoder
!=
nullptr
)
encoder
->
Dispose
();
if
(
prepared_
encoder
!=
nullptr
)
prepared_
encoder
->
Dispose
();
}
bool
Initialize
(
const
ConfigBlock
&
block
,
Error
&
error_r
)
{
...
...
@@ -148,8 +149,8 @@ RecorderOutput::Configure(const ConfigBlock &block, Error &error)
/* initialize encoder */
encoder
=
encoder_init
(
*
encoder_plugin
,
block
,
error
);
if
(
encoder
==
nullptr
)
prepared_
encoder
=
encoder_init
(
*
encoder_plugin
,
block
,
error
);
if
(
prepared_
encoder
==
nullptr
)
return
false
;
return
true
;
...
...
@@ -205,7 +206,8 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
/* open the encoder */
if
(
!
encoder
->
Open
(
audio_format
,
error
))
{
encoder
=
prepared_encoder
->
Open
(
audio_format
,
error
);
if
(
encoder
==
nullptr
)
{
delete
file
;
return
false
;
}
...
...
@@ -214,7 +216,7 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
try
{
EncoderToFile
();
}
catch
(
const
std
::
exception
&
e
)
{
encoder
->
Close
()
;
delete
encoder
;
error
.
Set
(
recorder_domain
,
e
.
what
());
return
false
;
}
...
...
@@ -224,7 +226,7 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
/* close the encoder for now; it will be opened as
soon as we have received a tag */
encoder
->
Close
()
;
delete
encoder
;
}
return
true
;
...
...
@@ -237,19 +239,19 @@ RecorderOutput::Commit(Error &error)
/* flush the encoder and write the rest to the file */
bool
success
=
encoder
_end
(
encoder
,
error
);
bool
success
=
encoder
->
End
(
error
);
if
(
success
)
{
try
{
EncoderToFile
();
}
catch
(...)
{
encoder
->
Close
()
;
delete
encoder
;
throw
;
}
}
/* now really close everything */
encoder
->
Close
()
;
delete
encoder
;
if
(
success
)
{
try
{
...
...
@@ -326,7 +328,8 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error)
}
AudioFormat
new_audio_format
=
effective_audio_format
;
if
(
!
encoder
->
Open
(
new_audio_format
,
error
))
{
encoder
=
prepared_encoder
->
Open
(
new_audio_format
,
error
);
if
(
encoder
==
nullptr
)
{
delete
new_file
;
return
false
;
}
...
...
@@ -338,7 +341,7 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error)
try
{
EncoderToOutputStream
(
*
new_file
,
*
encoder
);
}
catch
(
const
std
::
exception
&
e
)
{
encoder
->
Close
()
;
delete
encoder
;
delete
new_file
;
error
.
Set
(
recorder_domain
,
e
.
what
());
return
false
;
...
...
@@ -386,7 +389,7 @@ RecorderOutput::SendTag(const Tag &tag)
}
Error
error
;
if
(
!
encoder
_pre_tag
(
encoder
,
error
))
{
if
(
!
encoder
->
PreTag
(
error
))
{
LogError
(
error
);
return
;
}
...
...
@@ -398,7 +401,7 @@ RecorderOutput::SendTag(const Tag &tag)
return
;
}
if
(
!
encoder
_tag
(
encoder
,
tag
,
error
))
if
(
!
encoder
->
SendTag
(
tag
,
error
))
LogError
(
error
);
}
...
...
@@ -413,7 +416,7 @@ RecorderOutput::Play(const void *chunk, size_t size, Error &error)
return
size
;
}
if
(
!
encoder
_write
(
encoder
,
chunk
,
size
,
error
))
if
(
!
encoder
->
Write
(
chunk
,
size
,
error
))
return
0
;
try
{
...
...
src/output/plugins/ShoutOutputPlugin.cxx
View file @
e7edc026
...
...
@@ -45,7 +45,8 @@ struct ShoutOutput final {
shout_t
*
shout_conn
;
shout_metadata_t
*
shout_meta
;
Encoder
*
encoder
=
nullptr
;
PreparedEncoder
*
prepared_encoder
=
nullptr
;
Encoder
*
encoder
;
float
quality
=
-
2.0
;
int
bitrate
=
-
1
;
...
...
@@ -93,8 +94,7 @@ ShoutOutput::~ShoutOutput()
if
(
shout_init_count
==
0
)
shout_shutdown
();
if
(
encoder
!=
nullptr
)
encoder
->
Dispose
();
delete
prepared_encoder
;
}
static
const
EncoderPlugin
*
...
...
@@ -192,8 +192,8 @@ ShoutOutput::Configure(const ConfigBlock &block, Error &error)
return
false
;
}
encoder
=
encoder_init
(
*
encoder_plugin
,
block
,
error
);
if
(
encoder
==
nullptr
)
prepared_
encoder
=
encoder_init
(
*
encoder_plugin
,
block
,
error
);
if
(
prepared_
encoder
==
nullptr
)
return
false
;
unsigned
shout_format
;
...
...
@@ -345,8 +345,8 @@ write_page(ShoutOutput *sd, Error &error)
assert
(
sd
->
encoder
!=
nullptr
);
while
(
true
)
{
size_t
nbytes
=
encoder_read
(
sd
->
encod
er
,
sd
->
buffer
,
sizeof
(
sd
->
buffer
));
size_t
nbytes
=
sd
->
encoder
->
Read
(
sd
->
buff
er
,
sizeof
(
sd
->
buffer
));
if
(
nbytes
==
0
)
return
true
;
...
...
@@ -362,10 +362,10 @@ void
ShoutOutput
::
Close
()
{
if
(
encoder
!=
nullptr
)
{
if
(
encoder
_end
(
encoder
,
IgnoreError
()))
if
(
encoder
->
End
(
IgnoreError
()))
write_page
(
this
,
IgnoreError
());
encoder
->
Close
()
;
delete
encoder
;
}
if
(
shout_get_connected
(
shout_conn
)
!=
SHOUTERR_UNCONNECTED
&&
...
...
@@ -406,13 +406,14 @@ ShoutOutput::Open(AudioFormat &audio_format, Error &error)
if
(
!
shout_connect
(
this
,
error
))
return
false
;
if
(
!
encoder
->
Open
(
audio_format
,
error
))
{
encoder
=
prepared_encoder
->
Open
(
audio_format
,
error
);
if
(
encoder
==
nullptr
)
{
shout_close
(
shout_conn
);
return
false
;
}
if
(
!
write_page
(
this
,
error
))
{
encoder
->
Close
()
;
delete
encoder
;
shout_close
(
shout_conn
);
return
false
;
}
...
...
@@ -433,7 +434,7 @@ ShoutOutput::Delay() const
size_t
ShoutOutput
::
Play
(
const
void
*
chunk
,
size_t
size
,
Error
&
error
)
{
return
encoder
_write
(
encoder
,
chunk
,
size
,
error
)
&&
return
encoder
->
Write
(
chunk
,
size
,
error
)
&&
write_page
(
this
,
error
)
?
size
:
0
;
...
...
@@ -476,13 +477,13 @@ shout_tag_to_metadata(const Tag &tag, char *dest, size_t size)
void
ShoutOutput
::
SendTag
(
const
Tag
&
tag
)
{
if
(
encoder
->
plugin
.
tag
!=
nullptr
)
{
if
(
encoder
->
ImplementsTag
()
)
{
/* encoder plugin supports stream tags */
Error
error
;
if
(
!
encoder
_pre_tag
(
encoder
,
error
)
||
if
(
!
encoder
->
PreTag
(
error
)
||
!
write_page
(
this
,
error
)
||
!
encoder
_tag
(
encoder
,
tag
,
error
))
{
!
encoder
->
SendTag
(
tag
,
error
))
{
LogError
(
error
);
return
;
}
...
...
src/output/plugins/httpd/HttpdInternal.hxx
View file @
e7edc026
...
...
@@ -45,7 +45,8 @@ class EventLoop;
class
ServerSocket
;
class
HttpdClient
;
class
Page
;
struct
Encoder
;
struct
PreparedEncoder
;
class
Encoder
;
struct
Tag
;
class
HttpdOutput
final
:
ServerSocket
,
DeferredMonitor
{
...
...
@@ -60,6 +61,7 @@ class HttpdOutput final : ServerSocket, DeferredMonitor {
/**
* The configured encoder plugin.
*/
PreparedEncoder
*
prepared_encoder
=
nullptr
;
Encoder
*
encoder
;
/**
...
...
src/output/plugins/httpd/HttpdOutputPlugin.cxx
View file @
e7edc026
...
...
@@ -63,8 +63,8 @@ HttpdOutput::~HttpdOutput()
if
(
metadata
!=
nullptr
)
metadata
->
Unref
();
if
(
encoder
!=
nullptr
)
encoder
->
Dispose
();
if
(
prepared_
encoder
!=
nullptr
)
prepared_
encoder
->
Dispose
();
}
...
...
@@ -123,12 +123,12 @@ HttpdOutput::Configure(const ConfigBlock &block, Error &error)
/* initialize encoder */
encoder
=
encoder_init
(
*
encoder_plugin
,
block
,
error
);
if
(
encoder
==
nullptr
)
prepared_
encoder
=
encoder_init
(
*
encoder_plugin
,
block
,
error
);
if
(
prepared_
encoder
==
nullptr
)
return
false
;
/* determine content type */
content_type
=
encoder_get_mime_type
(
encoder
);
content_type
=
encoder_get_mime_type
(
prepared_
encoder
);
if
(
content_type
==
nullptr
)
content_type
=
"application/octet-stream"
;
...
...
@@ -169,7 +169,7 @@ inline void
HttpdOutput
::
AddClient
(
int
fd
)
{
auto
*
client
=
new
HttpdClient
(
*
this
,
fd
,
GetEventLoop
(),
encoder
->
plugin
.
tag
==
nullptr
);
!
encoder
->
ImplementsTag
()
);
clients
.
push_front
(
*
client
);
/* pass metadata to client */
...
...
@@ -250,15 +250,14 @@ HttpdOutput::ReadPage()
/* we have fed a lot of input into the encoder, but it
didn't give anything back yet - flush now to avoid
buffer underruns */
encoder
_flush
(
encoder
,
IgnoreError
());
encoder
->
Flush
(
IgnoreError
());
unflushed_input
=
0
;
}
size_t
size
=
0
;
do
{
size_t
nbytes
=
encoder_read
(
encoder
,
buffer
+
size
,
sizeof
(
buffer
)
-
size
);
size_t
nbytes
=
encoder
->
Read
(
buffer
+
size
,
sizeof
(
buffer
)
-
size
);
if
(
nbytes
==
0
)
break
;
...
...
@@ -292,7 +291,8 @@ httpd_output_disable(AudioOutput *ao)
inline
bool
HttpdOutput
::
OpenEncoder
(
AudioFormat
&
audio_format
,
Error
&
error
)
{
if
(
!
encoder
->
Open
(
audio_format
,
error
))
encoder
=
prepared_encoder
->
Open
(
audio_format
,
error
);
if
(
encoder
==
nullptr
)
return
false
;
/* we have to remember the encoder header, i.e. the first
...
...
@@ -351,7 +351,7 @@ HttpdOutput::Close()
if
(
header
!=
nullptr
)
header
->
Unref
();
encoder
->
Close
()
;
delete
encoder
;
}
static
void
...
...
@@ -441,7 +441,7 @@ HttpdOutput::BroadcastFromEncoder()
inline
bool
HttpdOutput
::
EncodeAndPlay
(
const
void
*
chunk
,
size_t
size
,
Error
&
error
)
{
if
(
!
encoder
_write
(
encoder
,
chunk
,
size
,
error
))
if
(
!
encoder
->
Write
(
chunk
,
size
,
error
))
return
false
;
unflushed_input
+=
size
;
...
...
@@ -491,18 +491,18 @@ httpd_output_pause(AudioOutput *ao)
inline
void
HttpdOutput
::
SendTag
(
const
Tag
&
tag
)
{
if
(
encoder
->
plugin
.
tag
!=
nullptr
)
{
if
(
encoder
->
ImplementsTag
()
)
{
/* embed encoder tags */
/* flush the current stream, and end it */
encoder
_pre_tag
(
encoder
,
IgnoreError
());
encoder
->
PreTag
(
IgnoreError
());
BroadcastFromEncoder
();
/* send the tag to the encoder - which starts a new
stream now */
encoder
_tag
(
encoder
,
tag
,
IgnoreError
());
encoder
->
SendTag
(
tag
,
IgnoreError
());
/* the first page generated by the encoder will now be
used as the new "header" page, which is sent to all
...
...
test/run_encoder.cxx
View file @
e7edc026
...
...
@@ -65,8 +65,8 @@ int main(int argc, char **argv)
try
{
Error
error
;
const
auto
encoder
=
encoder_init
(
*
plugin
,
block
,
error
);
if
(
encoder
==
NULL
)
{
const
auto
p_
encoder
=
encoder_init
(
*
plugin
,
block
,
error
);
if
(
p_encoder
==
nullptr
)
{
LogError
(
error
,
"Failed to initialize encoder"
);
return
EXIT_FAILURE
;
}
...
...
@@ -81,7 +81,8 @@ int main(int argc, char **argv)
}
}
if
(
!
encoder
->
Open
(
audio_format
,
error
))
{
auto
*
encoder
=
p_encoder
->
Open
(
audio_format
,
error
);
if
(
encoder
==
nullptr
)
{
LogError
(
error
,
"Failed to open encoder"
);
return
EXIT_FAILURE
;
}
...
...
@@ -94,7 +95,7 @@ int main(int argc, char **argv)
ssize_t
nbytes
;
while
((
nbytes
=
read
(
0
,
buffer
,
sizeof
(
buffer
)))
>
0
)
{
if
(
!
encoder
_write
(
encoder
,
buffer
,
nbytes
,
error
))
{
if
(
!
encoder
->
Write
(
buffer
,
nbytes
,
error
))
{
LogError
(
error
,
"encoder_write() failed"
);
return
EXIT_FAILURE
;
}
...
...
@@ -102,15 +103,15 @@ int main(int argc, char **argv)
EncoderToOutputStream
(
os
,
*
encoder
);
}
if
(
!
encoder
_end
(
encoder
,
error
))
{
if
(
!
encoder
->
End
(
error
))
{
LogError
(
error
,
"encoder_flush() failed"
);
return
EXIT_FAILURE
;
}
EncoderToOutputStream
(
os
,
*
encoder
);
encoder
->
Close
()
;
encoder
->
Dispose
();
delete
encoder
;
p_
encoder
->
Dispose
();
return
EXIT_SUCCESS
;
}
catch
(
const
std
::
exception
&
e
)
{
...
...
test/test_vorbis_encoder.cxx
View file @
e7edc026
...
...
@@ -48,15 +48,15 @@ main(gcc_unused int argc, gcc_unused char **argv)
ConfigBlock
block
;
block
.
AddBlockParam
(
"quality"
,
"5.0"
,
-
1
);
const
auto
encoder
=
encoder_init
(
*
plugin
,
block
,
IgnoreError
());
assert
(
encoder
!=
NULL
);
const
auto
p_
encoder
=
encoder_init
(
*
plugin
,
block
,
IgnoreError
());
assert
(
p_encoder
!=
nullptr
);
try
{
/* open the encoder */
AudioFormat
audio_format
(
44100
,
SampleFormat
::
S16
,
2
);
success
=
encoder
->
Open
(
audio_format
,
IgnoreError
());
assert
(
success
);
auto
encoder
=
p_
encoder
->
Open
(
audio_format
,
IgnoreError
());
assert
(
encoder
!=
nullptr
);
StdioOutputStream
os
(
stdout
);
...
...
@@ -64,14 +64,14 @@ main(gcc_unused int argc, gcc_unused char **argv)
/* write a block of data */
success
=
encoder
_write
(
encoder
,
zero
,
sizeof
(
zero
),
IgnoreError
());
success
=
encoder
->
Write
(
zero
,
sizeof
(
zero
),
IgnoreError
());
assert
(
success
);
EncoderToOutputStream
(
os
,
*
encoder
);
/* write a tag */
success
=
encoder
_pre_tag
(
encoder
,
IgnoreError
());
success
=
encoder
->
PreTag
(
IgnoreError
());
assert
(
success
);
EncoderToOutputStream
(
os
,
*
encoder
);
...
...
@@ -85,25 +85,25 @@ main(gcc_unused int argc, gcc_unused char **argv)
tag_builder
.
Commit
(
tag
);
}
success
=
encoder
_tag
(
encoder
,
tag
,
IgnoreError
());
success
=
encoder
->
SendTag
(
tag
,
IgnoreError
());
assert
(
success
);
EncoderToOutputStream
(
os
,
*
encoder
);
/* write another block of data */
success
=
encoder
_write
(
encoder
,
zero
,
sizeof
(
zero
),
IgnoreError
());
success
=
encoder
->
Write
(
zero
,
sizeof
(
zero
),
IgnoreError
());
assert
(
success
);
/* finish */
success
=
encoder
_end
(
encoder
,
IgnoreError
());
success
=
encoder
->
End
(
IgnoreError
());
assert
(
success
);
EncoderToOutputStream
(
os
,
*
encoder
);
encoder
->
Close
()
;
encoder
->
Dispose
();
delete
encoder
;
p_
encoder
->
Dispose
();
return
EXIT_SUCCESS
;
}
catch
(
const
std
::
exception
&
e
)
{
...
...
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