ref: 252145c713754551d66dcd5f3bb600e976e51446
parent: 9c3d76016beb8c052228a0d7033238e00a1681a6
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Sat Apr 29 23:19:49 EDT 2017
Handle the end of stream
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -78,6 +78,7 @@
int frame_size;
int decision_delay;
ogg_int64_t curr_granule;
+ ogg_int64_t end_granule;
OpusEncCallbacks callbacks;
void *user_data;
OpusHeader header;
@@ -184,6 +185,7 @@
if (ret == OPUS_OK) enc->curr_granule = -tmp;
else enc->curr_granule = 0;
}
+ enc->end_granule = 0;
comment_init(&enc->comment, &enc->comment_length, opus_get_version_string());
{
char encoder_string[1024];
@@ -256,6 +258,12 @@
enc->packetno = 2;
}
+static void shift_buffer(OggOpusEnc *enc) {
+ memmove(enc->buffer, &enc->buffer[enc->channels*enc->buffer_start], enc->channels*(enc->buffer_end-enc->buffer_start)*sizeof(*enc->buffer));
+ enc->buffer_end -= enc->buffer_start;
+ enc->buffer_start = 0;
+}
+
static void encode_buffer(OggOpusEnc *enc) {
while (enc->buffer_end-enc->buffer_start > enc->frame_size + enc->decision_delay) {
ogg_packet op;
@@ -273,6 +281,16 @@
op.e_o_s=0;
op.packetno=enc->packetno++;
op.granulepos=enc->curr_granule;
+ if (enc->curr_granule >= enc->end_granule) {
+ op.granulepos=enc->end_granule;
+ ogg_stream_packetin(&enc->os, &op);
+ while (ogg_stream_flush_fill(&enc->os, &og, 255*255)) {
+ int ret = oe_write_page(&og, &enc->callbacks, enc->user_data);
+ /* FIXME: what do we do if this fails? */
+ assert(ret != -1);
+ return;
+ }
+ }
ogg_stream_packetin(&enc->os, &op);
/* FIXME: Use flush to enforce latency constraint. */
while (ogg_stream_pageout_fill(&enc->os, &og, 255*255)) {
@@ -284,9 +302,7 @@
}
/* If we've reached the end of the buffer, move everything back to the front. */
if (enc->buffer_end == BUFFER_SAMPLES) {
- memmove(enc->buffer, &enc->buffer[enc->channels*enc->buffer_start], enc->channels*(enc->buffer_end-enc->buffer_start)*sizeof(*enc->buffer));
- enc->buffer_end -= enc->buffer_start;
- enc->buffer_start = 0;
+ shift_buffer(enc);
}
/* This function must never leave the buffer full. */
assert(enc->buffer_end < BUFFER_SAMPLES);
@@ -296,6 +312,7 @@
int ope_write_float(OggOpusEnc *enc, const float *pcm, int samples_per_channel) {
int channels = enc->channels;
if (!enc->stream_is_init) init_stream(enc);
+ enc->end_granule += samples_per_channel;
/* FIXME: Add resampling support. */
do {
int i;
@@ -317,6 +334,7 @@
int ope_write(OggOpusEnc *enc, const opus_int16 *pcm, int samples_per_channel) {
int channels = enc->channels;
if (!enc->stream_is_init) init_stream(enc);
+ enc->end_granule += samples_per_channel;
/* FIXME: Add resampling support. */
do {
int i;
@@ -335,7 +353,16 @@
}
static void finalize_stream(OggOpusEnc *enc) {
+ /* FIXME: Use a better value. */
+ int pad_samples = 3000;
if (!enc->stream_is_init) init_stream(enc);
+ shift_buffer(enc);
+ /* FIXME: Do LPC extension instead. */
+ memset(&enc->buffer[enc->channels*enc->buffer_end], 0, pad_samples*enc->channels);
+ enc->decision_delay = 0;
+ enc->buffer_end += pad_samples;
+ assert(enc->buffer_end <= BUFFER_SAMPLES);
+ encode_buffer(enc);
}
/* Close/finalize the stream. */