ref: 579863e2d890b5d457024f16ff3202328914811a
parent: b7cd8aaf92e2fdfb25f6648c8c3119be6078120a
author: Jean-Marc Valin <[email protected]>
date: Tue May 2 09:13:30 EDT 2017
Some refactoring for chaining
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -74,6 +74,21 @@
FILE *file;
};
+typedef struct EncStream EncStream;
+
+struct EncStream {
+ void *user_data;
+ ogg_stream_state os;
+ int serialno_is_set;
+ int serialno;
+ int stream_is_init;
+ int packetno;
+ char *comment;
+ int comment_length;
+ int seen_file_icons;
+ EncStream *next;
+};
+
struct OggOpusEnc {
OpusMSEncoder *st;
int rate;
@@ -89,17 +104,9 @@
ogg_int64_t end_granule;
ogg_int64_t last_page_granule;
OpusEncCallbacks callbacks;
- void *user_data;
OpusHeader header;
int comment_padding;
- char *comment;
- int serialno_is_set;
- int serialno;
- int comment_length;
- int seen_file_icons;
- ogg_stream_state os;
- int stream_is_init;
- int packetno;
+ EncStream *streams;
};
static int oe_flush_page(OggOpusEnc *enc) {
@@ -106,9 +113,9 @@
ogg_page og;
int ret;
int written = 0;
- while ( (ret = ogg_stream_flush(&enc->os, &og)) ) {
+ while ( (ret = ogg_stream_flush(&enc->streams->os, &og)) ) {
if (!ret) break;
- ret = oe_write_page(&og, &enc->callbacks, enc->user_data);
+ ret = oe_write_page(&og, &enc->callbacks, enc->streams->user_data);
if (ret == -1) {
return -1;
}
@@ -174,6 +181,9 @@
}
if ( (enc = malloc(sizeof(*enc))) == NULL) goto fail;
+ enc->streams = NULL;
+ if ( (enc->streams = malloc(sizeof(*enc->streams))) == NULL) goto fail;
+ enc->streams->next = NULL;
enc->rate = rate;
enc->channels = channels;
enc->frame_size = 960;
@@ -180,8 +190,8 @@
enc->decision_delay = 96000;
enc->max_ogg_delay = 48000;
enc->comment_padding = 512;
- enc->serialno_is_set = 0;
- enc->seen_file_icons = 0;
+ enc->streams->serialno_is_set = 0;
+ enc->streams->seen_file_icons = 0;
enc->header.channels=channels;
enc->header.channel_mapping=family;
enc->header.input_sample_rate=rate;
@@ -200,8 +210,8 @@
enc->re = NULL;
}
opus_multistream_encoder_ctl(st, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS));
- enc->stream_is_init = 0;
- enc->comment = NULL;
+ enc->streams->stream_is_init = 0;
+ enc->streams->comment = NULL;
{
opus_int32 tmp;
int ret;
@@ -212,18 +222,18 @@
enc->curr_granule = 0;
enc->end_granule = 0;
enc->last_page_granule = 0;
- comment_init(&enc->comment, &enc->comment_length, opus_get_version_string());
+ comment_init(&enc->streams->comment, &enc->streams->comment_length, opus_get_version_string());
{
char encoder_string[1024];
snprintf(encoder_string, sizeof(encoder_string), "%s version %s", PACKAGE_NAME, PACKAGE_VERSION);
- comment_add(&enc->comment, &enc->comment_length, "ENCODER", encoder_string);
+ comment_add(&enc->streams->comment, &enc->streams->comment_length, "ENCODER", encoder_string);
}
- if (enc->comment == NULL) goto fail;
+ if (enc->streams->comment == NULL) goto fail;
if ( (enc->buffer = malloc(sizeof(*enc->buffer)*BUFFER_SAMPLES*channels)) == NULL) goto fail;
enc->buffer_start = enc->buffer_end = 0;
enc->st = st;
enc->callbacks = *callbacks;
- enc->user_data = user_data;
+ enc->streams->user_data = user_data;
if (error) *error = OPUS_OK;
return enc;
fail:
@@ -230,6 +240,10 @@
if (enc) {
free(enc);
if (enc->buffer) free(enc->buffer);
+ if (enc->streams) {
+ free(enc->streams);
+ if (enc->streams->comment) free (enc->streams->comment);
+ }
}
if (st) {
opus_multistream_encoder_destroy(st);
@@ -239,19 +253,19 @@
static void init_stream(OggOpusEnc *enc) {
time_t start_time;
- assert(!enc->stream_is_init);
- if (!enc->serialno_is_set) {
+ assert(!enc->streams->stream_is_init);
+ if (!enc->streams->serialno_is_set) {
start_time = time(NULL);
srand(((getpid()&65535)<<15)^start_time);
- enc->serialno = rand();
+ enc->streams->serialno = rand();
}
- if (ogg_stream_init(&enc->os, enc->serialno) == -1) {
+ if (ogg_stream_init(&enc->streams->os, enc->streams->serialno) == -1) {
assert(0);
/* FIXME: How the hell do we handle that? */
}
- comment_pad(&enc->comment, &enc->comment_length, enc->comment_padding);
+ comment_pad(&enc->streams->comment, &enc->streams->comment_length, enc->comment_padding);
/*Write header*/
{
@@ -268,20 +282,20 @@
op.e_o_s=0;
op.granulepos=0;
op.packetno=0;
- ogg_stream_packetin(&enc->os, &op);
+ ogg_stream_packetin(&enc->streams->os, &op);
oe_flush_page(enc);
- op.packet = (unsigned char *)enc->comment;
- op.bytes = enc->comment_length;
+ op.packet = (unsigned char *)enc->streams->comment;
+ op.bytes = enc->streams->comment_length;
op.b_o_s = 0;
op.e_o_s = 0;
op.granulepos = 0;
op.packetno = 1;
- ogg_stream_packetin(&enc->os, &op);
+ ogg_stream_packetin(&enc->streams->os, &op);
oe_flush_page(enc);
}
- enc->stream_is_init = 1;
- enc->packetno = 2;
+ enc->streams->stream_is_init = 1;
+ enc->streams->packetno = 2;
}
static void shift_buffer(OggOpusEnc *enc) {
@@ -307,24 +321,24 @@
op.packet=packet;
op.bytes=nbBytes;
op.b_o_s=0;
- op.packetno=enc->packetno++;
+ op.packetno=enc->streams->packetno++;
op.granulepos=enc->curr_granule;
op.e_o_s=enc->curr_granule >= end_granule48k;
if (op.e_o_s) op.granulepos=end_granule48k;
- ogg_stream_packetin(&enc->os, &op);
+ ogg_stream_packetin(&enc->streams->os, &op);
/* FIXME: Also flush on too many segments. */
flush_needed = op.e_o_s || enc->curr_granule - enc->last_page_granule > enc->max_ogg_delay;
if (flush_needed) {
- while (ogg_stream_flush_fill(&enc->os, &og, 255*255)) {
+ while (ogg_stream_flush_fill(&enc->streams->os, &og, 255*255)) {
if (ogg_page_packets(&og) != 0) enc->last_page_granule = ogg_page_granulepos(&og);
- int ret = oe_write_page(&og, &enc->callbacks, enc->user_data);
+ int ret = oe_write_page(&og, &enc->callbacks, enc->streams->user_data);
/* FIXME: what do we do if this fails? */
assert(ret != -1);
}
} else {
- while (ogg_stream_pageout_fill(&enc->os, &og, 255*255)) {
+ while (ogg_stream_pageout_fill(&enc->streams->os, &og, 255*255)) {
if (ogg_page_packets(&og) != 0) enc->last_page_granule = ogg_page_granulepos(&og);
- int ret = oe_write_page(&og, &enc->callbacks, enc->user_data);
+ int ret = oe_write_page(&og, &enc->callbacks, enc->streams->user_data);
/* FIXME: what do we do if this fails? */
assert(ret != -1);
}
@@ -343,7 +357,7 @@
/* Add/encode any number of float samples to the file. */
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);
+ if (!enc->streams->stream_is_init) init_stream(enc);
if (samples_per_channel < 0) return OPE_BAD_ARG;
enc->end_granule += samples_per_channel;
do {
@@ -374,7 +388,7 @@
/* Add/encode any number of int16 samples to the file. */
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);
+ if (!enc->streams->stream_is_init) init_stream(enc);
if (samples_per_channel < 0) return OPE_BAD_ARG;
enc->end_granule += samples_per_channel;
do {
@@ -407,7 +421,7 @@
static void finalize_stream(OggOpusEnc *enc) {
/* FIXME: Use a better value. */
int pad_samples = 3000;
- if (!enc->stream_is_init) init_stream(enc);
+ if (!enc->streams->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);
@@ -420,11 +434,11 @@
/* Close/finalize the stream. */
int ope_close_and_free(OggOpusEnc *enc) {
finalize_stream(enc);
- enc->callbacks.close(enc->user_data);
- free(enc->comment);
+ enc->callbacks.close(enc->streams->user_data);
+ free(enc->streams->comment);
free(enc->buffer);
opus_multistream_encoder_destroy(enc->st);
- if (enc->stream_is_init) ogg_stream_clear(&enc->os);
+ if (enc->streams->stream_is_init) ogg_stream_clear(&enc->streams->os);
if (enc->re) speex_resampler_destroy(enc->re);
free(enc);
return OPE_OK;
@@ -432,8 +446,10 @@
/* Ends the stream and create a new stream within the same file. */
int ope_chain_current(OggOpusEnc *enc) {
+ EncStream *stream = enc->streams;
+ while (stream->next) stream = stream->next;
/* FIXME: Make sure we don't end up calling the close callback too early. */
- return ope_continue_new_callbacks(enc, enc->user_data);
+ return ope_continue_new_callbacks(enc, stream->user_data);
}
/* Ends the stream and create a new file. */
@@ -452,8 +468,8 @@
/* Add a comment to the file (can only be called before encoding samples). */
int ope_add_comment(OggOpusEnc *enc, const char *tag, const char *val) {
- if (enc->stream_is_init) return OPE_TOO_LATE;
- if (comment_add(&enc->comment, &enc->comment_length, tag, val)) return OPE_INTERNAL_ERROR;
+ if (enc->streams->stream_is_init) return OPE_TOO_LATE;
+ if (comment_add(&enc->streams->comment, &enc->streams->comment_length, tag, val)) return OPE_INTERNAL_ERROR;
return OPE_OK;
}
@@ -460,14 +476,14 @@
int ope_add_picture(OggOpusEnc *enc, const char *spec) {
const char *error_message;
char *picture_data;
- if (enc->stream_is_init) return OPE_TOO_LATE;
- picture_data = parse_picture_specification(spec, &error_message, &enc->seen_file_icons);
+ if (enc->streams->stream_is_init) return OPE_TOO_LATE;
+ picture_data = parse_picture_specification(spec, &error_message, &enc->streams->seen_file_icons);
if(picture_data==NULL){
/* FIXME: return proper errors rather than printing a message. */
fprintf(stderr,"Error parsing picture option: %s\n",error_message);
return OPE_BAD_ARG;
}
- comment_add(&enc->comment, &enc->comment_length, "METADATA_BLOCK_PICTURE", picture_data);
+ comment_add(&enc->streams->comment, &enc->streams->comment_length, "METADATA_BLOCK_PICTURE", picture_data);
free(picture_data);
return OPE_OK;
}
@@ -474,14 +490,13 @@
/* Sets the Opus comment vendor string (optional, defaults to library info). */
int ope_set_vendor_string(OggOpusEnc *enc, const char *vendor) {
- if (enc->stream_is_init) return OPE_TOO_LATE;
- (void)enc;
+ if (enc->streams->stream_is_init) return OPE_TOO_LATE;
(void)vendor;
return OPE_UNIMPLEMENTED;
}
int ope_flush_header(OggOpusEnc *enc) {
- if (enc->stream_is_init) return OPE_TOO_LATE;
+ if (enc->streams->stream_is_init) return OPE_TOO_LATE;
else init_stream(enc);
return OPE_OK;
}
@@ -583,8 +598,8 @@
case OPE_SET_SERIALNO_REQUEST:
{
opus_int32 value = va_arg(ap, opus_int32);
- enc->serialno = value;
- enc->serialno_is_set = 1;
+ enc->streams->serialno = value;
+ enc->streams->serialno_is_set = 1;
ret = OPE_OK;
}
break;