theoraenc: do not reset the encoder when we need a keyframe

Instead, remember we need a keyframe, and we will force the encoder
to emit one next time we submit a new frame.
Since libtheora does not have an API to request a keyframe, we reset
the max keyframe interval to 1 temporarily.

This has the advantage that the rate control keeps its history,
and that the encoder won't choose different quant tables or
somesuch, thus requiring new streamheaders (although this is
probably only a theoretical possibility). Should also be a
bit faster than resetting the encoder.

https://bugzilla.gnome.org/show_bug.cgi?id=663350
This commit is contained in:
Vincent Penquerc'h 2013-02-25 10:49:19 +00:00 committed by Tim-Philipp Müller
parent 76d71da1c4
commit da673880eb

View file

@ -940,12 +940,16 @@ theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
{ {
th_ycbcr_buffer ycbcr; th_ycbcr_buffer ycbcr;
gint res; gint res, keyframe_interval;
GstVideoFrame vframe; GstVideoFrame vframe;
if (force_keyframe) { if (force_keyframe) {
theora_enc_reset (enc); /* if we want a keyframe, temporarily reset the max keyframe interval
theora_enc_reset_ts (enc, running_time, frame->presentation_frame_number); * to 1, which will cause libtheora to emit one. There is no API to
* request a keyframe at the moment. */
keyframe_interval = 1;
th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
&keyframe_interval, sizeof (keyframe_interval));
} }
if (enc->multipass_cache_fd if (enc->multipass_cache_fd
@ -976,6 +980,16 @@ theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
ret = GST_FLOW_OK; ret = GST_FLOW_OK;
while (th_encode_packetout (enc->encoder, 0, &op)) { while (th_encode_packetout (enc->encoder, 0, &op)) {
/* Reset the max keyframe interval to its original state, and reset
* the flag so we don't create more keyframes if we loop */
if (force_keyframe) {
keyframe_interval =
enc->keyframe_auto ? enc->keyframe_force : enc->keyframe_freq;
th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
&keyframe_interval, sizeof (keyframe_interval));
force_keyframe = FALSE;
}
ret = theora_push_packet (enc, &op); ret = theora_push_packet (enc, &op);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
goto beach; goto beach;