shithub: libopusenc

Download patch

ref: 781c80da9c9691c7877208b1a20568aadf82c97c
parent: f945f600e904c59cb4824b1c513c0cfb4c1abdfd
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Wed May 3 11:15:32 EDT 2017

Should remove remaining chaining glitches by increasing the overlap

A side effect of this is that it breaks gstreamer

--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -108,6 +108,8 @@
   ogg_int64_t curr_granule;
   ogg_int64_t write_granule;
   ogg_int64_t last_page_granule;
+  unsigned char *chaining_keyframe;
+  int chaining_keyframe_length;
   OpusEncCallbacks callbacks;
   OpusHeader header;
   int comment_padding;
@@ -228,6 +230,8 @@
   enc->frame_size = 960;
   enc->decision_delay = 96000;
   enc->max_ogg_delay = 48000;
+  enc->chaining_keyframe = NULL;
+  enc->chaining_keyframe_length = -1;
   enc->comment_padding = 512;
   enc->header.channels=channels;
   enc->header.channel_mapping=family;
@@ -338,9 +342,13 @@
     ogg_page og;
     int nbBytes;
     unsigned char packet[MAX_PACKET_SIZE];
+    int is_keyframe=0;
     opus_multistream_encoder_ctl(enc->st, OPUS_GET_PREDICTION_DISABLED(&pred));
-    if (enc->curr_granule + enc->frame_size>= end_granule48k && enc->streams->next) {
+    /* FIXME: a frame that follows a keyframe generally doesn't need to be a keyframe
+       unless there's two consecutive stream boundaries. */
+    if (enc->curr_granule + 2*enc->frame_size>= end_granule48k && enc->streams->next) {
       opus_multistream_encoder_ctl(enc->st, OPUS_SET_PREDICTION_DISABLED(1));
+      is_keyframe = 1;
     }
     nbBytes = opus_multistream_encode_float(enc->st, &enc->buffer[enc->channels*enc->buffer_start],
         enc->buffer_end-enc->buffer_start, packet, MAX_PACKET_SIZE);
@@ -386,11 +394,34 @@
         /* We're done with this stream, start the next one. */
         enc->header.preskip = end_granule48k + enc->frame_size - enc->curr_granule;
         enc->streams->granule_offset = enc->curr_granule - enc->frame_size;
+        if (enc->chaining_keyframe) {
+          enc->header.preskip += enc->frame_size;
+          enc->streams->granule_offset -= enc->frame_size;
+        }
         init_stream(enc);
+        if (enc->chaining_keyframe) {
+          ogg_packet op2;
+          op2.packet = enc->chaining_keyframe;
+          op2.bytes = enc->chaining_keyframe_length;
+          op2.b_o_s = 0;
+          op2.e_o_s = 0;
+          op2.packetno=enc->streams->packetno++;
+          op2.granulepos=enc->curr_granule - enc->streams->granule_offset - enc->frame_size;
+          ogg_stream_packetin(&enc->streams->os, &op2);
+        }
         end_granule48k = (enc->streams->end_granule*48000 + enc->rate - 1)/enc->rate + enc->global_granule_offset;
         cont = 1;
       }
     } while (cont);
+    if (enc->chaining_keyframe) free(enc->chaining_keyframe);
+    if (is_keyframe) {
+      enc->chaining_keyframe = malloc(nbBytes);
+      enc->chaining_keyframe_length = nbBytes;
+      memcpy(enc->chaining_keyframe, packet, nbBytes);
+    } else {
+      enc->chaining_keyframe = NULL;
+      enc->chaining_keyframe_length = -1;
+    }
     enc->buffer_start += enc->frame_size;
   }
   /* If we've reached the end of the buffer, move everything back to the front. */
@@ -486,6 +517,7 @@
 /* Close/finalize the stream. */
 int ope_close_and_free(OggOpusEnc *enc) {
   finalize_all_streams(enc);
+  if (enc->chaining_keyframe) free(enc->chaining_keyframe);
   free(enc->buffer);
   opus_multistream_encoder_destroy(enc->st);
   if (enc->re) speex_resampler_destroy(enc->re);