mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-10 11:29:55 +00:00
Merge branch 'master' into 0.11
Conflicts: ext/x264/gstx264enc.c
This commit is contained in:
commit
49f4bc87d9
3 changed files with 153 additions and 54 deletions
|
@ -418,6 +418,17 @@ exit:
|
|||
*_offset = offset;
|
||||
*len = consumed;
|
||||
|
||||
/* ensure that if we added some dummy guard bytes above, we don't claim
|
||||
to have used them as they're unknown to the caller. */
|
||||
if (mad->eos) {
|
||||
g_assert (av >= MAD_BUFFER_GUARD);
|
||||
av -= MAD_BUFFER_GUARD;
|
||||
if (*_offset > av)
|
||||
*_offset = av;
|
||||
if (*len > av)
|
||||
*len = av;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
#include "gstx264enc.h"
|
||||
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#if X264_BUILD >= 71
|
||||
#define X264_DELAYED_FRAMES_API
|
||||
|
@ -127,6 +128,10 @@
|
|||
#define X264_PRESETS
|
||||
#endif
|
||||
|
||||
#if X264_BUILD >= 95
|
||||
#define FORCE_INTRA_API
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -473,8 +478,8 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
|||
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], "
|
||||
"stream-format = (string) { byte-stream, avc }, "
|
||||
"alignment = (string) { au }, "
|
||||
"profile = (string) { high-10, high, main, constrained-baseline, "
|
||||
"high-10-intra }")
|
||||
"profile = (string) { high-10, high, main, baseline, "
|
||||
"constrained-baseline, high-10-intra }")
|
||||
);
|
||||
|
||||
static void gst_x264_enc_finalize (GObject * object);
|
||||
|
@ -923,6 +928,8 @@ gst_x264_enc_init (GstX264Enc * encoder)
|
|||
encoder->x264param.p_log_private = encoder;
|
||||
encoder->x264param.i_log_level = X264_LOG_DEBUG;
|
||||
|
||||
gst_segment_init (&encoder->segment, GST_FORMAT_TIME);
|
||||
encoder->force_key_unit_event = NULL;
|
||||
gst_x264_enc_reset (encoder);
|
||||
}
|
||||
|
||||
|
@ -932,12 +939,11 @@ gst_x264_enc_reset (GstX264Enc * encoder)
|
|||
encoder->x264enc = NULL;
|
||||
gst_video_info_init (&encoder->info);
|
||||
encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY;
|
||||
gst_segment_init (&encoder->segment, GST_FORMAT_UNDEFINED);
|
||||
|
||||
GST_OBJECT_LOCK (encoder);
|
||||
encoder->i_type = X264_TYPE_AUTO;
|
||||
if (encoder->forcekeyunit_event)
|
||||
gst_event_unref (encoder->forcekeyunit_event);
|
||||
encoder->forcekeyunit_event = NULL;
|
||||
gst_event_replace (&encoder->force_key_unit_event, NULL);
|
||||
encoder->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
}
|
||||
|
||||
|
@ -1575,7 +1581,11 @@ gst_x264_enc_sink_set_caps (GstPad * pad, GstCaps * caps)
|
|||
|
||||
profile = gst_structure_get_string (s, "profile");
|
||||
if (profile) {
|
||||
if (!strcmp (profile, "constrained-baseline")) {
|
||||
/* FIXME - if libx264 ever adds support for FMO, ASO or redundant slices
|
||||
* make sure constrained profile has a separate case which disables
|
||||
* those */
|
||||
if (!strcmp (profile, "constrained-baseline") ||
|
||||
!strcmp (profile, "baseline")) {
|
||||
encoder->peer_profile = "baseline";
|
||||
} else if (!strcmp (profile, "high-10-intra")) {
|
||||
encoder->peer_intra_profile = TRUE;
|
||||
|
@ -1733,25 +1743,31 @@ gst_x264_enc_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_CUSTOM_UPSTREAM:{
|
||||
const GstStructure *s;
|
||||
s = gst_event_get_structure (event);
|
||||
if (gst_structure_has_name (s, "GstForceKeyUnit")) {
|
||||
/* Set I frame request */
|
||||
GST_OBJECT_LOCK (encoder);
|
||||
encoder->i_type = X264_TYPE_I;
|
||||
encoder->forcekeyunit_event = gst_event_copy (event);
|
||||
GST_EVENT_TYPE (encoder->forcekeyunit_event) =
|
||||
GST_EVENT_CUSTOM_DOWNSTREAM;
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
forward = FALSE;
|
||||
gst_event_unref (event);
|
||||
}
|
||||
guint count;
|
||||
gboolean all_headers;
|
||||
|
||||
if (!gst_video_event_is_force_key_unit (event))
|
||||
goto out;
|
||||
|
||||
GST_OBJECT_LOCK (encoder);
|
||||
gst_video_event_parse_upstream_force_key_unit (event,
|
||||
&encoder->pending_key_unit_ts, &all_headers, &count);
|
||||
GST_INFO_OBJECT (encoder, "received upstream force-key-unit event, "
|
||||
"seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
|
||||
gst_event_get_seqnum (event),
|
||||
GST_TIME_ARGS (encoder->pending_key_unit_ts), all_headers, count);
|
||||
|
||||
gst_event_replace (&encoder->force_key_unit_event, event);
|
||||
gst_event_unref (event);
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
forward = FALSE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (forward)
|
||||
ret = gst_pad_push_event (encoder->sinkpad, event);
|
||||
|
||||
|
@ -1776,6 +1792,12 @@ gst_x264_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
forward = FALSE;
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_SEGMENT:
|
||||
gst_event_copy_segment (event, &encoder->segment);
|
||||
break;
|
||||
case GST_EVENT_FLUSH_STOP:
|
||||
gst_segment_init (&encoder->segment, GST_FORMAT_UNDEFINED);
|
||||
break;
|
||||
case GST_EVENT_EOS:
|
||||
gst_x264_enc_flush_frames (encoder, TRUE);
|
||||
break;
|
||||
|
@ -1797,13 +1819,24 @@ gst_x264_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
* buffers in encoder are considered (in the) past */
|
||||
}
|
||||
case GST_EVENT_CUSTOM_DOWNSTREAM:{
|
||||
const GstStructure *s;
|
||||
s = gst_event_get_structure (event);
|
||||
if (gst_structure_has_name (s, "GstForceKeyUnit")) {
|
||||
GST_OBJECT_LOCK (encoder);
|
||||
encoder->i_type = X264_TYPE_I;
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
}
|
||||
guint count;
|
||||
gboolean all_headers;
|
||||
|
||||
if (!gst_video_event_is_force_key_unit (event))
|
||||
break;
|
||||
|
||||
GST_OBJECT_LOCK (encoder);
|
||||
|
||||
gst_video_event_parse_downstream_force_key_unit (event, NULL, NULL,
|
||||
&encoder->pending_key_unit_ts, &all_headers, &count);
|
||||
GST_INFO_OBJECT (encoder, "received downstream force-key-unit event, "
|
||||
"seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
|
||||
gst_event_get_seqnum (event),
|
||||
GST_TIME_ARGS (encoder->pending_key_unit_ts), all_headers, count);
|
||||
|
||||
gst_event_replace (&encoder->force_key_unit_event, event);
|
||||
gst_event_unref (event);
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -1876,13 +1909,7 @@ gst_x264_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
|||
pic_in.img.i_stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
|
||||
}
|
||||
|
||||
GST_OBJECT_LOCK (encoder);
|
||||
pic_in.i_type = encoder->i_type;
|
||||
|
||||
/* Reset encoder forced picture type */
|
||||
encoder->i_type = X264_TYPE_AUTO;
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
|
||||
pic_in.i_type = X264_TYPE_AUTO;
|
||||
pic_in.i_pts = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
ret = gst_x264_enc_encode_frame (encoder, &pic_in, &i_nal, TRUE);
|
||||
|
@ -1906,6 +1933,45 @@ wrong_video_frame:
|
|||
}
|
||||
}
|
||||
|
||||
static GstEvent *
|
||||
check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
|
||||
GstClockTime timestamp, GstClockTime pending_key_unit_ts)
|
||||
{
|
||||
GstClockTime running_time, stream_time;
|
||||
gboolean all_headers;
|
||||
guint count;
|
||||
GstEvent *event = NULL;
|
||||
|
||||
g_return_val_if_fail (pending_event != NULL, NULL);
|
||||
g_return_val_if_fail (segment != NULL, NULL);
|
||||
|
||||
if (pending_event == NULL || timestamp == GST_CLOCK_TIME_NONE)
|
||||
goto out;
|
||||
|
||||
running_time = gst_segment_to_running_time (segment,
|
||||
GST_FORMAT_TIME, timestamp);
|
||||
|
||||
GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
|
||||
|
||||
if (running_time < pending_key_unit_ts)
|
||||
goto out;
|
||||
|
||||
stream_time = gst_segment_to_stream_time (segment,
|
||||
GST_FORMAT_TIME, timestamp);
|
||||
|
||||
gst_video_event_parse_upstream_force_key_unit (pending_event,
|
||||
NULL, &all_headers, &count);
|
||||
|
||||
event =
|
||||
gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
|
||||
running_time, all_headers, count);
|
||||
gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));
|
||||
|
||||
out:
|
||||
return event;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
|
||||
int *i_nal, gboolean send)
|
||||
|
@ -1921,7 +1987,7 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
|
|||
int encoder_return;
|
||||
GstClockTime duration;
|
||||
guint8 *data;
|
||||
GstEvent *forcekeyunit_event = NULL;
|
||||
GstEvent *event = NULL;
|
||||
|
||||
if (G_UNLIKELY (encoder->x264enc == NULL))
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
|
@ -1932,6 +1998,24 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
|
|||
if (x264_encoder_reconfig (encoder->x264enc, &encoder->x264param) < 0)
|
||||
GST_WARNING_OBJECT (encoder, "Could not reconfigure");
|
||||
}
|
||||
|
||||
if (encoder->pending_key_unit_ts != GST_CLOCK_TIME_NONE && pic_in != NULL) {
|
||||
event = check_pending_key_unit_event (encoder->force_key_unit_event,
|
||||
&encoder->segment, pic_in->i_pts, encoder->pending_key_unit_ts);
|
||||
if (event) {
|
||||
encoder->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
|
||||
gst_event_replace (&encoder->force_key_unit_event, NULL);
|
||||
|
||||
#ifdef FORCE_INTRA_API
|
||||
if (encoder->intra_refresh)
|
||||
x264_encoder_intra_refresh (encoder->x264enc);
|
||||
else
|
||||
pic_in->i_type = X264_TYPE_IDR;
|
||||
#else
|
||||
pic_in->i_type = X264_TYPE_IDR;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
|
||||
encoder_return = x264_encoder_encode (encoder->x264enc,
|
||||
|
@ -1941,7 +2025,8 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
|
|||
goto encode_failed;
|
||||
|
||||
if (!*i_nal) {
|
||||
return GST_FLOW_OK;
|
||||
ret = GST_FLOW_OK;
|
||||
goto out;
|
||||
}
|
||||
#ifndef X264_ENC_NALS
|
||||
i_size = 0;
|
||||
|
@ -1978,11 +2063,14 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
|
|||
} else {
|
||||
GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, (NULL),
|
||||
("Timestamp queue empty."));
|
||||
return GST_FLOW_ERROR;
|
||||
ret = GST_FLOW_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!send)
|
||||
return GST_FLOW_OK;
|
||||
if (!send) {
|
||||
ret = GST_FLOW_OK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_buf = gst_buffer_new_allocate (NULL, i_size, 0);
|
||||
gst_buffer_fill (out_buf, 0, data, i_size);
|
||||
|
@ -2005,25 +2093,24 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
|
|||
GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
}
|
||||
|
||||
GST_OBJECT_LOCK (encoder);
|
||||
forcekeyunit_event = encoder->forcekeyunit_event;
|
||||
encoder->forcekeyunit_event = NULL;
|
||||
GST_OBJECT_UNLOCK (encoder);
|
||||
if (forcekeyunit_event) {
|
||||
gst_structure_set ((GstStructure *)
|
||||
gst_event_get_structure (forcekeyunit_event), "timestamp",
|
||||
G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (out_buf), NULL);
|
||||
gst_pad_push_event (encoder->srcpad, forcekeyunit_event);
|
||||
}
|
||||
if (event)
|
||||
gst_pad_push_event (encoder->srcpad, gst_event_ref (event));
|
||||
|
||||
return gst_pad_push (encoder->srcpad, out_buf);
|
||||
ret = gst_pad_push (encoder->srcpad, out_buf);
|
||||
|
||||
out:
|
||||
if (event)
|
||||
gst_event_unref (event);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
encode_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x264 frame failed."),
|
||||
("x264_encoder_encode return code=%d", encoder_return));
|
||||
return GST_FLOW_ERROR;
|
||||
ret = GST_FLOW_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ struct _GstX264Enc
|
|||
/*< private >*/
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
GstSegment segment;
|
||||
|
||||
x264_t *x264enc;
|
||||
x264_param_t x264param;
|
||||
|
@ -105,9 +106,6 @@ struct _GstX264Enc
|
|||
guint8 *buffer;
|
||||
gulong buffer_size;
|
||||
|
||||
gint i_type;
|
||||
GstEvent *forcekeyunit_event;
|
||||
|
||||
/* configuration changed while playing */
|
||||
gboolean reconfig;
|
||||
|
||||
|
@ -115,6 +113,9 @@ struct _GstX264Enc
|
|||
const gchar *peer_profile;
|
||||
gboolean peer_intra_profile;
|
||||
const x264_level_t *peer_level;
|
||||
|
||||
GstClockTime pending_key_unit_ts;
|
||||
GstEvent *force_key_unit_event;
|
||||
};
|
||||
|
||||
struct _GstX264EncClass
|
||||
|
|
Loading…
Reference in a new issue