mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-10 19:31:12 +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;
|
*_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
GST_OBJECT_LOCK (encoder);
|
goto out;
|
||||||
encoder->i_type = X264_TYPE_I;
|
|
||||||
encoder->forcekeyunit_event = gst_event_copy (event);
|
GST_OBJECT_LOCK (encoder);
|
||||||
GST_EVENT_TYPE (encoder->forcekeyunit_event) =
|
gst_video_event_parse_upstream_force_key_unit (event,
|
||||||
GST_EVENT_CUSTOM_DOWNSTREAM;
|
&encoder->pending_key_unit_ts, &all_headers, &count);
|
||||||
GST_OBJECT_UNLOCK (encoder);
|
GST_INFO_OBJECT (encoder, "received upstream force-key-unit event, "
|
||||||
forward = FALSE;
|
"seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
|
||||||
gst_event_unref (event);
|
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;
|
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")) {
|
|
||||||
GST_OBJECT_LOCK (encoder);
|
if (!gst_video_event_is_force_key_unit (event))
|
||||||
encoder->i_type = X264_TYPE_I;
|
break;
|
||||||
GST_OBJECT_UNLOCK (encoder);
|
|
||||||
}
|
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;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue