Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chained streams #667

Closed
wants to merge 10 commits into from
2 changes: 2 additions & 0 deletions include/FLAC++/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ namespace FLAC {
//@}

virtual bool set_ogg_serial_number(long value); ///< See FLAC__stream_decoder_set_ogg_serial_number()
virtual bool set_ogg_chaining(bool value); ///< See FLAC__stream_decoder_set_ogg_chaining()
virtual bool set_md5_checking(bool value); ///< See FLAC__stream_decoder_set_md5_checking()
virtual bool set_metadata_respond(::FLAC__MetadataType type); ///< See FLAC__stream_decoder_set_metadata_respond()
virtual bool set_metadata_respond_application(const FLAC__byte id[4]); ///< See FLAC__stream_decoder_set_metadata_respond_application()
Expand All @@ -133,6 +134,7 @@ namespace FLAC {

/* get_state() is not virtual since we want subclasses to be able to return their own state */
State get_state() const; ///< See FLAC__stream_decoder_get_state()
virtual bool get_ogg_chaining() const; ///< See FLAC__stream_decoder_get_ogg_chaining()
virtual bool get_md5_checking() const; ///< See FLAC__stream_decoder_get_md5_checking()
virtual FLAC__uint64 get_total_samples() const; ///< See FLAC__stream_decoder_get_total_samples()
virtual uint32_t get_channels() const; ///< See FLAC__stream_decoder_get_channels()
Expand Down
31 changes: 31 additions & 0 deletions include/FLAC/stream_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,25 @@ FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
*/
FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);

/** Set the "allow Ogg chaining" flag. If set, the Ogg decoder will
* prepare to receive a new stream once the last Ogg page arrives for
* the stream encapsulating the FLAC audio data. This can be used to
* support chained Ogg FLAC streams; a new \c STREAMINFO signals the
* beginning of a new stream.
*
* \note
* This function has no effect with native FLAC decoding.
*
* \default \c false
* \param decoder A decoder instance to set.
* \param allow Whether to allow chained streams.
* \assert
* \code decoder != NULL \endcode
* \retval FLAC__bool
* \c false if the decoder is already initialized, else \c true.
*/
FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_chaining(FLAC__StreamDecoder* decoder, FLAC__bool value);

/** Set the "MD5 signature checking" flag. If \c true, the decoder will
* compute the MD5 signature of the unencoded audio data while decoding
* and compare it to the signature from the STREAMINFO block, if it
Expand Down Expand Up @@ -906,6 +925,18 @@ FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__Str
*/
FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);

/** Get the "allow Ogg chaining" flag as described in
* \code FLAC__stream_decoder_set_ogg_chaining \endcode.
*
* \param decoder A decoder instance to query.
* \assert
* \code decoder != NULL \endcode
* \retval FLAC__bool
* See above.
*/
#define FLAC__OGG_CHAINING
FLAC_API FLAC__bool FLAC__stream_decoder_get_ogg_chaining(const FLAC__StreamDecoder* decoder);

/** Get the "MD5 signature checking" flag.
* This is the value of the setting, not whether or not the decoder is
* currently checking the MD5 (remember, it can be turned off automatically
Expand Down
3 changes: 3 additions & 0 deletions oss-fuzz/decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if ( ds.Get<bool>() ) {
use_ogg = false;
}

decoder.set_ogg_chaining(true);

if ( ds.Get<bool>() ) {
#ifdef FUZZER_DEBUG
printf("set_ogg_serial_number\n");
Expand Down
30 changes: 28 additions & 2 deletions src/flac/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ typedef struct {
FLAC__bool is_ogg;
FLAC__bool use_first_serial_number;
long serial_number;
FLAC__bool chaining;
uint32_t stream_counter;
#endif

FileFormat format;
Expand Down Expand Up @@ -105,7 +107,7 @@ static FLAC__bool is_big_endian_host_;
/*
* local routines
*/
static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename);
static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool chaining, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename);
static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred);
static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, const char *infilename);
static FLAC__bool DecoderSession_process(DecoderSession *d);
Expand Down Expand Up @@ -156,12 +158,14 @@ int flac__decode_file(const char *infilename, const char *outfilename, FLAC__boo
&decoder_session,
#if FLAC__HAS_OGG
options.is_ogg,
options.chaining,
options.use_first_serial_number,
options.serial_number,
#else
/*is_ogg=*/false,
/*use_first_serial_number=*/false,
/*serial_number=*/0,
/*chaining=*/false,
#endif
options.format,
options.force_subformat,
Expand Down Expand Up @@ -192,16 +196,20 @@ int flac__decode_file(const char *infilename, const char *outfilename, FLAC__boo
return DecoderSession_finish_ok(&decoder_session);
}

FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename)
FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool chaining, FLAC__bool use_first_serial_number, long serial_number, FileFormat format, FileSubFormat subformat, FLAC__bool treat_warnings_as_errors, FLAC__bool continue_through_decode_errors, FLAC__bool channel_map_none, FLAC__bool relaxed_foreign_metadata_handling, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, foreign_metadata_t *foreign_metadata, const char *infilename, const char *outfilename)
{
#if FLAC__HAS_OGG
d->is_ogg = is_ogg;
d->use_first_serial_number = use_first_serial_number;
d->serial_number = serial_number;
d->chaining = chaining;
d->stream_counter = 0;
#else

(void)is_ogg;
(void)use_first_serial_number;
(void)serial_number;
(void)chaining;
#endif

d->format = format;
Expand Down Expand Up @@ -365,6 +373,7 @@ FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const ch
if(decoder_session->is_ogg) {
if(!decoder_session->use_first_serial_number)
FLAC__stream_decoder_set_ogg_serial_number(decoder_session->decoder, decoder_session->serial_number);
FLAC__stream_decoder_set_ogg_chaining(decoder_session->decoder, decoder_session->chaining);
init_status = FLAC__stream_decoder_init_ogg_file(decoder_session->decoder, strcmp(infilename, "-")? infilename : 0, write_callback, metadata_callback, error_callback, /*client_data=*/decoder_session);
}
else
Expand Down Expand Up @@ -553,6 +562,12 @@ int DecoderSession_finish_ok(DecoderSession *d)
flac__utils_printf(stderr, 1, "WARNING, cannot check total number of samples since it was unset in the STREAMINFO\n");
ok = !d->treat_warnings_as_errors;
}
#if FLAC__HAS_OGG
if (d->chaining) {
stats_print_name(2, d->inbasefilename);
flac__utils_printf(stderr, 2, "%d stream(s) found\n", d->stream_counter);
}
#endif
stats_print_name(2, d->inbasefilename);
flac__utils_printf(stderr, 2, "%s \n", d->test_only? "ok ":d->analysis_mode?"done ":"done");
}
Expand Down Expand Up @@ -1456,6 +1471,16 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMet

(void)decoder;

#if FLAC__HAS_OGG
if (decoder_session->frame_counter && decoder_session->is_ogg && decoder_session->chaining) {
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
decoder_session->stream_counter++;
decoder_session->total_samples += metadata->data.stream_info.total_samples;
}
return;
}
#endif

if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
FLAC__uint64 skip, until;

Expand All @@ -1472,6 +1497,7 @@ void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMet
decoder_session->bps = metadata->data.stream_info.bits_per_sample;
decoder_session->channels = metadata->data.stream_info.channels;
decoder_session->sample_rate = metadata->data.stream_info.sample_rate;
decoder_session->stream_counter = 1;

if(!flac__utils_canonicalize_skip_until_specification(decoder_session->skip_specification, decoder_session->sample_rate)) {
flac__utils_printf(stderr, 1, "%s: ERROR, value of --skip is too large\n", decoder_session->inbasefilename);
Expand Down
1 change: 1 addition & 0 deletions src/flac/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ typedef struct {
FLAC__bool is_ogg;
FLAC__bool use_first_serial_number;
long serial_number;
FLAC__bool chaining;
#endif
utils__SkipUntilSpecification skip_specification;
utils__SkipUntilSpecification until_specification;
Expand Down
8 changes: 8 additions & 0 deletions src/flac/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ static struct share__option long_options_[] = {
{ "padding" , share__required_argument, 0, 'P' },
#if FLAC__HAS_OGG
{ "ogg" , share__no_argument, 0, 0 },
{ "chaining" , share__no_argument, 0, 0 },
{ "serial-number" , share__required_argument, 0, 0 },
#endif
{ "blocksize" , share__required_argument, 0, 'b' },
Expand Down Expand Up @@ -240,6 +241,7 @@ static struct {
FLAC__bool analyze;
FLAC__bool use_ogg;
FLAC__bool has_serial_number; /* true iff --serial-number was used */
FLAC__bool chaining;
long serial_number; /* this is the Ogg serial number and is unused for native FLAC */
FLAC__bool force_to_stdout;
FLAC__bool force_raw_format;
Expand Down Expand Up @@ -565,6 +567,7 @@ FLAC__bool init_options(void)
option_values.test_only = false;
option_values.analyze = false;
option_values.use_ogg = false;
option_values.chaining = false;
option_values.has_serial_number = false;
option_values.serial_number = 0;
option_values.force_to_stdout = false;
Expand Down Expand Up @@ -805,6 +808,9 @@ int parse_option(int short_option, const char *long_option, const char *option_a
else if(0 == strcmp(long_option, "ogg")) {
option_values.use_ogg = true;
}
else if (0 == strcmp(long_option, "chaining")) {
option_values.chaining = true;
}
else if(0 == strcmp(long_option, "serial-number")) {
option_values.has_serial_number = true;
option_values.serial_number = atol(option_argument);
Expand Down Expand Up @@ -1302,6 +1308,7 @@ void show_help(void)
printf(" --until={#|[+|-]mm:ss.ss} Stop at the given sample for each input file\n");
#if FLAC__HAS_OGG
printf(" --ogg Use Ogg as transport layer\n");
printf(" --chaining Allow Ogg stream chaining decoding\n");
printf(" --serial-number Serial number to use for the FLAC stream\n");
#endif
printf("analysis options:\n");
Expand Down Expand Up @@ -2313,6 +2320,7 @@ int decode_file(const char *infilename)
decode_options.force_subformat = output_subformat;
#if FLAC__HAS_OGG
decode_options.is_ogg = treat_as_ogg;
decode_options.chaining = option_values.chaining;
decode_options.use_first_serial_number = !option_values.has_serial_number;
decode_options.serial_number = option_values.serial_number;
#endif
Expand Down
12 changes: 12 additions & 0 deletions src/libFLAC++/stream_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ namespace FLAC {
return static_cast<bool>(::FLAC__stream_decoder_set_ogg_serial_number(decoder_, value));
}

bool Stream::set_ogg_chaining(bool value)
{
FLAC__ASSERT(is_valid());
return static_cast<bool>(::FLAC__stream_decoder_set_ogg_chaining(decoder_, value));
}

bool Stream::set_md5_checking(bool value)
{
FLAC__ASSERT(is_valid());
Expand Down Expand Up @@ -122,6 +128,12 @@ namespace FLAC {
return State(::FLAC__stream_decoder_get_state(decoder_));
}

bool Stream::get_ogg_chaining() const
{
FLAC__ASSERT(is_valid());
return static_cast<bool>(::FLAC__stream_decoder_get_ogg_chaining(decoder_));
}

bool Stream::get_md5_checking() const
{
FLAC__ASSERT(is_valid());
Expand Down
7 changes: 6 additions & 1 deletion src/libFLAC/include/private/ogg_decoder_aspect.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ typedef struct FLAC__OggDecoderAspect {
uint32_t version_major, version_minor;
FLAC__bool need_serial_number;
FLAC__bool end_of_stream;
FLAC__bool page_eos;
FLAC__bool chaining;
FLAC__bool have_working_page; /* only if true will the following vars be valid */
ogg_page working_page;
FLAC__bool have_working_packet; /* only if true will the following vars be valid */
Expand All @@ -60,7 +62,10 @@ void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect);
FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect);
void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect);
void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect);
void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect);
void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect* aspect);
bool FLAC__ogg_decoder_aspect_page_eos(FLAC__OggDecoderAspect* aspect, bool reset);
void FLAC__ogg_decoder_aspect_set_chaining(FLAC__OggDecoderAspect* aspect, FLAC__bool value);
FLAC__bool FLAC__ogg_decoder_aspect_get_chaining(FLAC__OggDecoderAspect* aspect);

typedef enum {
FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0,
Expand Down
32 changes: 31 additions & 1 deletion src/libFLAC/ogg_decoder_aspect.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect)

aspect->end_of_stream = false;
aspect->have_working_page = false;
aspect->page_eos = false;

return true;
}
Expand All @@ -82,6 +83,7 @@ void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect,
void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect)
{
aspect->use_first_serial_number = true;
aspect->chaining = false;
}

void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
Expand All @@ -90,6 +92,7 @@ void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
(void)ogg_sync_reset(&aspect->sync_state);
aspect->end_of_stream = false;
aspect->have_working_page = false;
aspect->page_eos = false;
}

void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
Expand All @@ -100,6 +103,23 @@ void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
aspect->need_serial_number = true;
}

bool FLAC__ogg_decoder_aspect_page_eos(FLAC__OggDecoderAspect* aspect, bool reset)
{
bool page_eos = aspect->page_eos;
if (reset) aspect->page_eos = false;
return page_eos;
}

void FLAC__ogg_decoder_aspect_set_chaining(FLAC__OggDecoderAspect* aspect, FLAC__bool value)
{
aspect->chaining = value;
}

FLAC__bool FLAC__ogg_decoder_aspect_get_chaining(FLAC__OggDecoderAspect* aspect)
{
return aspect->chaining;
}

FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data)
{
static const size_t OGG_BYTES_CHUNK = 8192;
Expand Down Expand Up @@ -191,19 +211,29 @@ FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(
}
}
}
else if (aspect->page_eos) {
/* we've now consumed all packets of the last page */
aspect->need_serial_number = true;
return *bytes ? FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK :
FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
}
else {
/* try and get another page */
const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
if (ret > 0) {
/* got a page, grab the serial number if necessary */
if(aspect->need_serial_number) {
aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
aspect->serial_number = ogg_page_serialno(&aspect->working_page);
ogg_stream_reset_serialno(&aspect->stream_state, aspect->serial_number);
aspect->need_serial_number = false;
}
if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
aspect->have_working_page = true;
aspect->have_working_packet = false;
}
if(aspect->chaining && ogg_page_eos(&aspect->working_page) != 0) {
aspect->page_eos = true;
}
/* else do nothing, could be a page from another stream */
}
else if (ret == 0) {
Expand Down
Loading
Loading