Merge branch 'master' into 0.11

Conflicts:
	ext/x264/gstx264enc.c
This commit is contained in:
Wim Taymans 2012-02-10 17:00:33 +01:00
commit 49f4bc87d9
3 changed files with 153 additions and 54 deletions

View file

@ -418,6 +418,17 @@ exit:
*_offset = offset; *_offset = offset;
*len = consumed; *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; return ret;
} }

View file

@ -97,6 +97,7 @@
#include "gstx264enc.h" #include "gstx264enc.h"
#include <gst/pbutils/pbutils.h> #include <gst/pbutils/pbutils.h>
#include <gst/video/video.h>
#if X264_BUILD >= 71 #if X264_BUILD >= 71
#define X264_DELAYED_FRAMES_API #define X264_DELAYED_FRAMES_API
@ -127,6 +128,10 @@
#define X264_PRESETS #define X264_PRESETS
#endif #endif
#if X264_BUILD >= 95
#define FORCE_INTRA_API
#endif
#include <string.h> #include <string.h>
#include <stdlib.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 ], " "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], "
"stream-format = (string) { byte-stream, avc }, " "stream-format = (string) { byte-stream, avc }, "
"alignment = (string) { au }, " "alignment = (string) { au }, "
"profile = (string) { high-10, high, main, constrained-baseline, " "profile = (string) { high-10, high, main, baseline, "
"high-10-intra }") "constrained-baseline, high-10-intra }")
); );
static void gst_x264_enc_finalize (GObject * object); 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.p_log_private = encoder;
encoder->x264param.i_log_level = X264_LOG_DEBUG; 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); gst_x264_enc_reset (encoder);
} }
@ -932,12 +939,11 @@ gst_x264_enc_reset (GstX264Enc * encoder)
encoder->x264enc = NULL; encoder->x264enc = NULL;
gst_video_info_init (&encoder->info); gst_video_info_init (&encoder->info);
encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY; encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY;
gst_segment_init (&encoder->segment, GST_FORMAT_UNDEFINED);
GST_OBJECT_LOCK (encoder); GST_OBJECT_LOCK (encoder);
encoder->i_type = X264_TYPE_AUTO; gst_event_replace (&encoder->force_key_unit_event, NULL);
if (encoder->forcekeyunit_event) encoder->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
gst_event_unref (encoder->forcekeyunit_event);
encoder->forcekeyunit_event = NULL;
GST_OBJECT_UNLOCK (encoder); 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"); profile = gst_structure_get_string (s, "profile");
if (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"; encoder->peer_profile = "baseline";
} else if (!strcmp (profile, "high-10-intra")) { } else if (!strcmp (profile, "high-10-intra")) {
encoder->peer_intra_profile = TRUE; 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)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CUSTOM_UPSTREAM:{ case GST_EVENT_CUSTOM_UPSTREAM:{
const GstStructure *s; guint count;
s = gst_event_get_structure (event); gboolean all_headers;
if (gst_structure_has_name (s, "GstForceKeyUnit")) {
/* Set I frame request */ if (!gst_video_event_is_force_key_unit (event))
goto out;
GST_OBJECT_LOCK (encoder); GST_OBJECT_LOCK (encoder);
encoder->i_type = X264_TYPE_I; gst_video_event_parse_upstream_force_key_unit (event,
encoder->forcekeyunit_event = gst_event_copy (event); &encoder->pending_key_unit_ts, &all_headers, &count);
GST_EVENT_TYPE (encoder->forcekeyunit_event) = GST_INFO_OBJECT (encoder, "received upstream force-key-unit event, "
GST_EVENT_CUSTOM_DOWNSTREAM; "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); GST_OBJECT_UNLOCK (encoder);
forward = FALSE; forward = FALSE;
gst_event_unref (event);
}
break; break;
} }
default: default:
break; break;
} }
out:
if (forward) if (forward)
ret = gst_pad_push_event (encoder->sinkpad, event); 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; forward = FALSE;
break; 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: case GST_EVENT_EOS:
gst_x264_enc_flush_frames (encoder, TRUE); gst_x264_enc_flush_frames (encoder, TRUE);
break; break;
@ -1797,13 +1819,24 @@ gst_x264_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
* buffers in encoder are considered (in the) past */ * buffers in encoder are considered (in the) past */
} }
case GST_EVENT_CUSTOM_DOWNSTREAM:{ case GST_EVENT_CUSTOM_DOWNSTREAM:{
const GstStructure *s; guint count;
s = gst_event_get_structure (event); gboolean all_headers;
if (gst_structure_has_name (s, "GstForceKeyUnit")) {
if (!gst_video_event_is_force_key_unit (event))
break;
GST_OBJECT_LOCK (encoder); GST_OBJECT_LOCK (encoder);
encoder->i_type = X264_TYPE_I;
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); GST_OBJECT_UNLOCK (encoder);
}
break; break;
} }
default: 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); pic_in.img.i_stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
} }
GST_OBJECT_LOCK (encoder); pic_in.i_type = X264_TYPE_AUTO;
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_pts = GST_BUFFER_TIMESTAMP (buf); pic_in.i_pts = GST_BUFFER_TIMESTAMP (buf);
ret = gst_x264_enc_encode_frame (encoder, &pic_in, &i_nal, TRUE); 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 static GstFlowReturn
gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in, gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
int *i_nal, gboolean send) int *i_nal, gboolean send)
@ -1921,7 +1987,7 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
int encoder_return; int encoder_return;
GstClockTime duration; GstClockTime duration;
guint8 *data; guint8 *data;
GstEvent *forcekeyunit_event = NULL; GstEvent *event = NULL;
if (G_UNLIKELY (encoder->x264enc == NULL)) if (G_UNLIKELY (encoder->x264enc == NULL))
return GST_FLOW_NOT_NEGOTIATED; 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) if (x264_encoder_reconfig (encoder->x264enc, &encoder->x264param) < 0)
GST_WARNING_OBJECT (encoder, "Could not reconfigure"); 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); GST_OBJECT_UNLOCK (encoder);
encoder_return = x264_encoder_encode (encoder->x264enc, 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; goto encode_failed;
if (!*i_nal) { if (!*i_nal) {
return GST_FLOW_OK; ret = GST_FLOW_OK;
goto out;
} }
#ifndef X264_ENC_NALS #ifndef X264_ENC_NALS
i_size = 0; i_size = 0;
@ -1978,11 +2063,14 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in,
} else { } else {
GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, (NULL), GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, (NULL),
("Timestamp queue empty.")); ("Timestamp queue empty."));
return GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
goto out;
} }
if (!send) if (!send) {
return GST_FLOW_OK; ret = GST_FLOW_OK;
goto out;
}
out_buf = gst_buffer_new_allocate (NULL, i_size, 0); out_buf = gst_buffer_new_allocate (NULL, i_size, 0);
gst_buffer_fill (out_buf, 0, data, i_size); 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_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DELTA_UNIT);
} }
GST_OBJECT_LOCK (encoder); if (event)
forcekeyunit_event = encoder->forcekeyunit_event; gst_pad_push_event (encoder->srcpad, gst_event_ref (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);
}
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 */ /* ERRORS */
encode_failed: encode_failed:
{ {
GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x264 frame failed."), GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x264 frame failed."),
("x264_encoder_encode return code=%d", encoder_return)); ("x264_encoder_encode return code=%d", encoder_return));
return GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
goto out;
} }
} }

View file

@ -49,6 +49,7 @@ struct _GstX264Enc
/*< private >*/ /*< private >*/
GstPad *sinkpad; GstPad *sinkpad;
GstPad *srcpad; GstPad *srcpad;
GstSegment segment;
x264_t *x264enc; x264_t *x264enc;
x264_param_t x264param; x264_param_t x264param;
@ -105,9 +106,6 @@ struct _GstX264Enc
guint8 *buffer; guint8 *buffer;
gulong buffer_size; gulong buffer_size;
gint i_type;
GstEvent *forcekeyunit_event;
/* configuration changed while playing */ /* configuration changed while playing */
gboolean reconfig; gboolean reconfig;
@ -115,6 +113,9 @@ struct _GstX264Enc
const gchar *peer_profile; const gchar *peer_profile;
gboolean peer_intra_profile; gboolean peer_intra_profile;
const x264_level_t *peer_level; const x264_level_t *peer_level;
GstClockTime pending_key_unit_ts;
GstEvent *force_key_unit_event;
}; };
struct _GstX264EncClass struct _GstX264EncClass