diff --git a/NEWS b/NEWS index caa3cd073..5a215dadd 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ ver 0.16.8 (2012/??/??) - ffmpeg: read the "year" tag * encoder: - vorbis: generate end-of-stream packet before tag + - vorbis: generate end-of-stream packet when playback ends * output: - jack: check for connection failure before starting playback - jack: workaround for libjack1 crash bug diff --git a/src/encoder/flac_encoder.c b/src/encoder/flac_encoder.c index 6389513ef..e2c455e3a 100644 --- a/src/encoder/flac_encoder.c +++ b/src/encoder/flac_encoder.c @@ -354,6 +354,7 @@ const struct encoder_plugin flac_encoder_plugin = { .finish = flac_encoder_finish, .open = flac_encoder_open, .close = flac_encoder_close, + .end = flac_encoder_flush, .flush = flac_encoder_flush, .write = flac_encoder_write, .read = flac_encoder_read, diff --git a/src/encoder/twolame_encoder.c b/src/encoder/twolame_encoder.c index d20af551b..073c3128f 100644 --- a/src/encoder/twolame_encoder.c +++ b/src/encoder/twolame_encoder.c @@ -300,6 +300,7 @@ const struct encoder_plugin twolame_encoder_plugin = { .finish = twolame_encoder_finish, .open = twolame_encoder_open, .close = twolame_encoder_close, + .end = twolame_encoder_flush, .flush = twolame_encoder_flush, .write = twolame_encoder_write, .read = twolame_encoder_read, diff --git a/src/encoder/vorbis_encoder.c b/src/encoder/vorbis_encoder.c index 519d7cbf6..9f09b2ac7 100644 --- a/src/encoder/vorbis_encoder.c +++ b/src/encoder/vorbis_encoder.c @@ -405,6 +405,7 @@ const struct encoder_plugin vorbis_encoder_plugin = { .finish = vorbis_encoder_finish, .open = vorbis_encoder_open, .close = vorbis_encoder_close, + .end = vorbis_encoder_pre_tag, .flush = vorbis_encoder_flush, .pre_tag = vorbis_encoder_pre_tag, .tag = vorbis_encoder_tag, diff --git a/src/encoder_plugin.h b/src/encoder_plugin.h index af3f76a40..70eee51a2 100644 --- a/src/encoder_plugin.h +++ b/src/encoder_plugin.h @@ -35,7 +35,7 @@ struct encoder { const struct encoder_plugin *plugin; #ifndef NDEBUG - bool open, pre_tag, tag; + bool open, pre_tag, tag, end; #endif }; @@ -53,6 +53,8 @@ struct encoder_plugin { void (*close)(struct encoder *encoder); + bool (*end)(struct encoder *encoder, GError **error); + bool (*flush)(struct encoder *encoder, GError **error); bool (*pre_tag)(struct encoder *encoder, GError **error); @@ -132,7 +134,7 @@ encoder_open(struct encoder *encoder, struct audio_format *audio_format, bool success = encoder->plugin->open(encoder, audio_format, error); #ifndef NDEBUG encoder->open = success; - encoder->pre_tag = encoder->tag = false; + encoder->pre_tag = encoder->tag = encoder->end = false; #endif return success; } @@ -156,6 +158,35 @@ encoder_close(struct encoder *encoder) #endif } +/** + * Ends the stream: flushes the encoder object, generate an + * end-of-stream marker (if applicable), make everything which might + * currently be buffered available by encoder_read(). + * + * After this function has been called, the encoder may not be usable + * for more data, and only encoder_read() and encoder_close() can be + * called. + * + * @param encoder the encoder + * @param error location to store the error occuring, or NULL to ignore errors. + * @return true on success + */ +static inline bool +encoder_end(struct encoder *encoder, GError **error) +{ + assert(encoder->open); + assert(!encoder->end); + +#ifndef NDEBUG + encoder->end = true; +#endif + + /* this method is optional */ + return encoder->plugin->end != NULL + ? encoder->plugin->end(encoder, error) + : true; +} + /** * Flushes an encoder object, make everything which might currently be * buffered available by encoder_read(). @@ -170,6 +201,7 @@ encoder_flush(struct encoder *encoder, GError **error) assert(encoder->open); assert(!encoder->pre_tag); assert(!encoder->tag); + assert(!encoder->end); /* this method is optional */ return encoder->plugin->flush != NULL @@ -193,6 +225,7 @@ encoder_pre_tag(struct encoder *encoder, GError **error) assert(encoder->open); assert(!encoder->pre_tag); assert(!encoder->tag); + assert(!encoder->end); /* this method is optional */ bool success = encoder->plugin->pre_tag != NULL @@ -222,6 +255,7 @@ encoder_tag(struct encoder *encoder, const struct tag *tag, GError **error) assert(encoder->open); assert(!encoder->pre_tag); assert(encoder->tag); + assert(!encoder->end); #ifndef NDEBUG encoder->tag = false; @@ -249,6 +283,7 @@ encoder_write(struct encoder *encoder, const void *data, size_t length, assert(encoder->open); assert(!encoder->pre_tag); assert(!encoder->tag); + assert(!encoder->end); return encoder->plugin->write(encoder, data, length, error); } diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c index 10d64106c..2f088a107 100644 --- a/src/output/recorder_output_plugin.c +++ b/src/output/recorder_output_plugin.c @@ -191,7 +191,7 @@ recorder_output_close(void *data) /* flush the encoder and write the rest to the file */ - if (encoder_flush(recorder->encoder, NULL)) + if (encoder_end(recorder->encoder, NULL)) recorder_output_encoder_to_file(recorder, NULL); /* now really close everything */ diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c index 35efd9fc7..27ef3b993 100644 --- a/src/output/shout_plugin.c +++ b/src/output/shout_plugin.c @@ -358,7 +358,7 @@ static void close_shout_conn(struct shout_data * sd) sd->buf.len = 0; if (sd->encoder != NULL) { - if (encoder_flush(sd->encoder, NULL)) + if (encoder_end(sd->encoder, NULL)) write_page(sd, NULL); encoder_close(sd->encoder); diff --git a/test/run_encoder.c b/test/run_encoder.c index 16e633029..4c05a06c7 100644 --- a/test/run_encoder.c +++ b/test/run_encoder.c @@ -121,7 +121,7 @@ int main(int argc, char **argv) encoder_to_stdout(encoder); } - ret = encoder_flush(encoder, &error); + ret = encoder_end(encoder, &error); if (!ret) { g_printerr("encoder_flush() failed: %s\n", error->message); diff --git a/test/test_vorbis_encoder.c b/test/test_vorbis_encoder.c index 370a8a59e..969ab7687 100644 --- a/test/test_vorbis_encoder.c +++ b/test/test_vorbis_encoder.c @@ -99,7 +99,7 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv) /* finish */ - success = encoder_flush(encoder, NULL); + success = encoder_end(encoder, NULL); assert(success); encoder_to_stdout(encoder);