mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 02:31:03 +00:00
Add draft design for forcing keyframes in encoders and implement in theoraenc.
Original commit message from CVS: * docs/design/draft-keyframe-force.txt: * ext/theora/theoraenc.c: (theora_enc_sink_event), (theora_enc_chain): Add draft design for forcing keyframes in encoders and implement in theoraenc.
This commit is contained in:
parent
ba42031248
commit
80c1e3d27c
3 changed files with 107 additions and 6 deletions
|
@ -1,3 +1,11 @@
|
|||
2007-06-05 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* docs/design/draft-keyframe-force.txt:
|
||||
* ext/theora/theoraenc.c: (theora_enc_sink_event),
|
||||
(theora_enc_chain):
|
||||
Add draft design for forcing keyframes in encoders and implement in
|
||||
theoraenc.
|
||||
|
||||
2007-06-05 Jan Schmidt <thaytan@mad.scientist.com>
|
||||
|
||||
* configure.ac:
|
||||
|
|
72
docs/design/draft-keyframe-force.txt
Normal file
72
docs/design/draft-keyframe-force.txt
Normal file
|
@ -0,0 +1,72 @@
|
|||
Forcing keyframes
|
||||
-----------------
|
||||
|
||||
Consider the following use case:
|
||||
|
||||
We have a pipeline that performs video and audio capture from a live source,
|
||||
compesses and muxes the streams and writes the resulting data into a file.
|
||||
|
||||
Inside the uncompressed video data we have a specific pattern inserted at
|
||||
specific moments that should trigger a switch to a new file, meaning, we close
|
||||
the existing file we are writing to and start writing to a new file.
|
||||
|
||||
We want the new file to start with a keyframe so that one can start decoding
|
||||
the file immediatly.
|
||||
|
||||
Components:
|
||||
|
||||
1) We need an element that is able to detect the pattern in the video stream.
|
||||
|
||||
2) We need to inform the video encoder that it should start encoding a keyframe
|
||||
starting from exactly the frame with the pattern.
|
||||
|
||||
3) We need to inform the demuxer that it should flush out any pending data and
|
||||
start creating the start of a new file with the keyframe as a first video
|
||||
frame.
|
||||
|
||||
4) We need to inform the sink element that it should start writing to the next
|
||||
file. This requires application interaction to instruct the sink of the new
|
||||
filename. The application should also be free to ignore the boundary and
|
||||
continue to write to the existing file. The application will typically use
|
||||
an event pad probe to detect the custom event.
|
||||
|
||||
Implementation:
|
||||
|
||||
The implementation would consist of generating a GST_EVENT_CUSTOM_DOWNSTREAM
|
||||
event that marks the keyframe boundary. This event is inserted into the
|
||||
pipeline by the application upon a certain trigger. In the above use case this
|
||||
trigger would be given by the element that detects the pattern, in the form of
|
||||
an element message.
|
||||
|
||||
The custom event would travel further downstream to instruct encoder, muxer and
|
||||
sink about the possible switch.
|
||||
|
||||
The information passed in the event consists of:
|
||||
|
||||
name: GstForceKeyUnit
|
||||
(G_TYPE_UINT64)"timestamp" : the timestamp of the buffer that
|
||||
triggered the event.
|
||||
(G_TYPE_UINT64)"stream-time" : the stream position that triggered the
|
||||
event.
|
||||
(G_TYPE_UINT64)"running_time" : the running time of the stream when the
|
||||
event was triggered.
|
||||
.... : optional other data fields.
|
||||
|
||||
Note that this event is purely informational, no element is required to
|
||||
perform an action but it should forward the event downstream, just like any
|
||||
other event it does not handle.
|
||||
|
||||
Elements understanding the event should behave as follows:
|
||||
|
||||
1) The video encoder receives the event before the next frame. Upon reception
|
||||
of the event it schedules to encode the next frame as a keyframe.
|
||||
Before pushing out the encoded keyframe it must push the GstForceKeyUnit
|
||||
event downstream.
|
||||
|
||||
2) The muxer receives the GstForceKeyUnit event and flushes out its current state,
|
||||
preparing to produce data that can be used as a keyunit. Before pushing out
|
||||
the new data it pushes the GstForceKeyUnit event downstream.
|
||||
|
||||
3) The application receives the GstForceKeyUnit on a sink padprobe of the sink
|
||||
and reconfigures the sink to make it perform new actions after receiving
|
||||
the next buffer.
|
|
@ -565,8 +565,31 @@ theora_enc_sink_event (GstPad * pad, GstEvent * event)
|
|||
}
|
||||
res = gst_pad_push_event (enc->srcpad, event);
|
||||
break;
|
||||
case GST_EVENT_CUSTOM_DOWNSTREAM:
|
||||
{
|
||||
const GstStructure *s;
|
||||
|
||||
s = gst_event_get_structure (event);
|
||||
|
||||
if (gst_structure_has_name (s, "GstForceKeyUnit")) {
|
||||
GstClockTime next_ts;
|
||||
|
||||
/* make sure timestamps increment after reseting the decoder */
|
||||
next_ts = enc->next_ts + enc->timestamp_offset;
|
||||
|
||||
theora_enc_reset (enc);
|
||||
enc->granulepos_offset =
|
||||
gst_util_uint64_scale (next_ts, enc->fps_n,
|
||||
GST_SECOND * enc->fps_d);
|
||||
enc->timestamp_offset = next_ts;
|
||||
enc->next_ts = 0;
|
||||
}
|
||||
res = gst_pad_push_event (enc->srcpad, event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = gst_pad_push_event (enc->srcpad, event);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -697,9 +720,8 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
|||
}
|
||||
|
||||
enc->granulepos_offset =
|
||||
gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buffer), enc->fps_n,
|
||||
GST_SECOND * enc->fps_d);
|
||||
enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buffer);
|
||||
gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d);
|
||||
enc->timestamp_offset = in_time;
|
||||
enc->next_ts = 0;
|
||||
}
|
||||
|
||||
|
@ -855,9 +877,8 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
|||
if (theora_enc_is_discontinuous (enc, buffer)) {
|
||||
theora_enc_reset (enc);
|
||||
enc->granulepos_offset =
|
||||
gst_util_uint64_scale (GST_BUFFER_TIMESTAMP (buffer), enc->fps_n,
|
||||
GST_SECOND * enc->fps_d);
|
||||
enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buffer);
|
||||
gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d);
|
||||
enc->timestamp_offset = in_time;
|
||||
enc->next_ts = 0;
|
||||
enc->next_discont = TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue