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