mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 15:51:11 +00:00
[MOVED FROM BAD 050/134] vp8enc: Implement multipass encoding
Fixes bug #621348.
This commit is contained in:
parent
7f3e1a1484
commit
83ffb384d0
1 changed files with 189 additions and 40 deletions
|
@ -79,6 +79,10 @@ struct _GstVP8Enc
|
||||||
int max_keyframe_distance;
|
int max_keyframe_distance;
|
||||||
int speed;
|
int speed;
|
||||||
int threads;
|
int threads;
|
||||||
|
enum vpx_enc_pass multipass_mode;
|
||||||
|
gchar *multipass_cache_file;
|
||||||
|
GByteArray *first_pass_cache_content;
|
||||||
|
vpx_fixed_buf_t last_pass_cache_content;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
|
|
||||||
|
@ -117,6 +121,8 @@ enum
|
||||||
#define DEFAULT_MAX_KEYFRAME_DISTANCE 60
|
#define DEFAULT_MAX_KEYFRAME_DISTANCE 60
|
||||||
#define DEFAULT_SPEED 0
|
#define DEFAULT_SPEED 0
|
||||||
#define DEFAULT_THREADS 1
|
#define DEFAULT_THREADS 1
|
||||||
|
#define DEFAULT_MULTIPASS_MODE VPX_RC_ONE_PASS
|
||||||
|
#define DEFAULT_MULTIPASS_CACHE_FILE NULL
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -128,7 +134,9 @@ enum
|
||||||
PROP_MAX_LATENCY,
|
PROP_MAX_LATENCY,
|
||||||
PROP_MAX_KEYFRAME_DISTANCE,
|
PROP_MAX_KEYFRAME_DISTANCE,
|
||||||
PROP_SPEED,
|
PROP_SPEED,
|
||||||
PROP_THREADS
|
PROP_THREADS,
|
||||||
|
PROP_MULTIPASS_MODE,
|
||||||
|
PROP_MULTIPASS_CACHE_FILE
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GST_VP8_ENC_MODE_TYPE (gst_vp8_enc_mode_get_type())
|
#define GST_VP8_ENC_MODE_TYPE (gst_vp8_enc_mode_get_type())
|
||||||
|
@ -153,6 +161,29 @@ gst_vp8_enc_mode_get_type (void)
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GST_VP8_ENC_MULTIPASS_MODE_TYPE (gst_vp8_enc_multipass_mode_get_type())
|
||||||
|
static GType
|
||||||
|
gst_vp8_enc_multipass_mode_get_type (void)
|
||||||
|
{
|
||||||
|
static const GEnumValue values[] = {
|
||||||
|
{VPX_RC_ONE_PASS, "One pass encoding (default)", "one-pass"},
|
||||||
|
{VPX_RC_FIRST_PASS, "First pass of multipass encoding", "first-pass"},
|
||||||
|
{VPX_RC_LAST_PASS, "Last pass of multipass encoding", "last-pass"},
|
||||||
|
{0, NULL, NULL}
|
||||||
|
};
|
||||||
|
static volatile GType id = 0;
|
||||||
|
|
||||||
|
if (g_once_init_enter ((gsize *) & id)) {
|
||||||
|
GType _id;
|
||||||
|
|
||||||
|
_id = g_enum_register_static ("GstVP8EncMultipassMode", values);
|
||||||
|
|
||||||
|
g_once_init_leave ((gsize *) & id, _id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
static void gst_vp8_enc_finalize (GObject * object);
|
static void gst_vp8_enc_finalize (GObject * object);
|
||||||
static void gst_vp8_enc_set_property (GObject * object, guint prop_id,
|
static void gst_vp8_enc_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
|
@ -294,6 +325,18 @@ gst_vp8_enc_class_init (GstVP8EncClass * klass)
|
||||||
1, 64, DEFAULT_THREADS,
|
1, 64, DEFAULT_THREADS,
|
||||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE,
|
||||||
|
g_param_spec_enum ("multipass-mode", "Multipass Mode",
|
||||||
|
"Multipass encode mode",
|
||||||
|
GST_VP8_ENC_MULTIPASS_MODE_TYPE, DEFAULT_MULTIPASS_MODE,
|
||||||
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE,
|
||||||
|
g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
|
||||||
|
"Multipass cache file",
|
||||||
|
DEFAULT_MULTIPASS_CACHE_FILE,
|
||||||
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_vp8enc_debug, "vp8enc", 0, "VP8 Encoder");
|
GST_DEBUG_CATEGORY_INIT (gst_vp8enc_debug, "vp8enc", 0, "VP8 Encoder");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,6 +352,8 @@ gst_vp8_enc_init (GstVP8Enc * gst_vp8_enc, GstVP8EncClass * klass)
|
||||||
gst_vp8_enc->error_resilient = DEFAULT_ERROR_RESILIENT;
|
gst_vp8_enc->error_resilient = DEFAULT_ERROR_RESILIENT;
|
||||||
gst_vp8_enc->max_latency = DEFAULT_MAX_LATENCY;
|
gst_vp8_enc->max_latency = DEFAULT_MAX_LATENCY;
|
||||||
gst_vp8_enc->max_keyframe_distance = DEFAULT_MAX_KEYFRAME_DISTANCE;
|
gst_vp8_enc->max_keyframe_distance = DEFAULT_MAX_KEYFRAME_DISTANCE;
|
||||||
|
gst_vp8_enc->multipass_mode = DEFAULT_MULTIPASS_MODE;
|
||||||
|
gst_vp8_enc->multipass_cache_file = DEFAULT_MULTIPASS_CACHE_FILE;
|
||||||
|
|
||||||
/* FIXME: Add sink/src event vmethods */
|
/* FIXME: Add sink/src event vmethods */
|
||||||
gst_vp8_enc->base_sink_event_func =
|
gst_vp8_enc->base_sink_event_func =
|
||||||
|
@ -327,6 +372,9 @@ gst_vp8_enc_finalize (GObject * object)
|
||||||
g_return_if_fail (GST_IS_GST_VP8_ENC (object));
|
g_return_if_fail (GST_IS_GST_VP8_ENC (object));
|
||||||
gst_vp8_enc = GST_VP8_ENC (object);
|
gst_vp8_enc = GST_VP8_ENC (object);
|
||||||
|
|
||||||
|
g_free (gst_vp8_enc->multipass_cache_file);
|
||||||
|
gst_vp8_enc->multipass_cache_file = NULL;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -366,6 +414,14 @@ gst_vp8_enc_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_THREADS:
|
case PROP_THREADS:
|
||||||
gst_vp8_enc->threads = g_value_get_int (value);
|
gst_vp8_enc->threads = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MULTIPASS_MODE:
|
||||||
|
gst_vp8_enc->multipass_mode = g_value_get_enum (value);
|
||||||
|
break;
|
||||||
|
case PROP_MULTIPASS_CACHE_FILE:
|
||||||
|
if (gst_vp8_enc->multipass_cache_file)
|
||||||
|
g_free (gst_vp8_enc->multipass_cache_file);
|
||||||
|
gst_vp8_enc->multipass_cache_file = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -405,6 +461,12 @@ gst_vp8_enc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_THREADS:
|
case PROP_THREADS:
|
||||||
g_value_set_int (value, gst_vp8_enc->threads);
|
g_value_set_int (value, gst_vp8_enc->threads);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MULTIPASS_MODE:
|
||||||
|
g_value_set_enum (value, gst_vp8_enc->multipass_mode);
|
||||||
|
break;
|
||||||
|
case PROP_MULTIPASS_CACHE_FILE:
|
||||||
|
g_value_set_string (value, gst_vp8_enc->multipass_cache_file);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -437,6 +499,17 @@ gst_vp8_enc_stop (GstBaseVideoEncoder * base_video_encoder)
|
||||||
encoder->inited = FALSE;
|
encoder->inited = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (encoder->first_pass_cache_content) {
|
||||||
|
g_byte_array_free (encoder->first_pass_cache_content, TRUE);
|
||||||
|
encoder->first_pass_cache_content = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder->last_pass_cache_content.buf) {
|
||||||
|
g_free (encoder->last_pass_cache_content.buf);
|
||||||
|
encoder->last_pass_cache_content.buf = NULL;
|
||||||
|
encoder->last_pass_cache_content.sz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
gst_tag_setter_reset_tags (GST_TAG_SETTER (encoder));
|
gst_tag_setter_reset_tags (GST_TAG_SETTER (encoder));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -564,7 +637,24 @@ gst_vp8_enc_finish (GstBaseVideoEncoder * base_video_encoder)
|
||||||
GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz,
|
GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz,
|
||||||
pkt->kind);
|
pkt->kind);
|
||||||
|
|
||||||
if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
|
if (pkt->kind == VPX_CODEC_STATS_PKT
|
||||||
|
&& encoder->multipass_mode == VPX_RC_FIRST_PASS) {
|
||||||
|
GST_LOG_OBJECT (encoder, "handling STATS packet");
|
||||||
|
|
||||||
|
g_byte_array_append (encoder->first_pass_cache_content,
|
||||||
|
pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz);
|
||||||
|
|
||||||
|
frame = gst_base_video_encoder_get_oldest_frame (base_video_encoder);
|
||||||
|
if (frame != NULL) {
|
||||||
|
buffer = gst_buffer_new ();
|
||||||
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_PREROLL);
|
||||||
|
frame->src_buffer = buffer;
|
||||||
|
gst_base_video_encoder_finish_frame (base_video_encoder, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
||||||
|
continue;
|
||||||
|
} else if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
|
||||||
GST_LOG_OBJECT (encoder, "non frame pkt: %d", pkt->kind);
|
GST_LOG_OBJECT (encoder, "non frame pkt: %d", pkt->kind);
|
||||||
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
||||||
continue;
|
continue;
|
||||||
|
@ -596,6 +686,19 @@ gst_vp8_enc_finish (GstBaseVideoEncoder * base_video_encoder)
|
||||||
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (encoder->multipass_mode == VPX_RC_FIRST_PASS
|
||||||
|
&& encoder->multipass_cache_file) {
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
|
if (!g_file_set_contents (encoder->multipass_cache_file,
|
||||||
|
(const gchar *) encoder->first_pass_cache_content->data,
|
||||||
|
encoder->first_pass_cache_content->len, &err)) {
|
||||||
|
GST_ELEMENT_ERROR (encoder, RESOURCE, WRITE, (NULL),
|
||||||
|
("Failed to write multipass cache file: %s", err->message));
|
||||||
|
g_error_free (err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,7 +786,6 @@ gst_vp8_enc_handle_frame (GstBaseVideoEncoder * base_video_encoder,
|
||||||
cfg.g_timebase.den = base_video_encoder->state.fps_n;
|
cfg.g_timebase.den = base_video_encoder->state.fps_n;
|
||||||
|
|
||||||
cfg.g_error_resilient = encoder->error_resilient;
|
cfg.g_error_resilient = encoder->error_resilient;
|
||||||
cfg.g_pass = VPX_RC_ONE_PASS;
|
|
||||||
cfg.g_lag_in_frames = encoder->max_latency;
|
cfg.g_lag_in_frames = encoder->max_latency;
|
||||||
cfg.g_threads = encoder->threads;
|
cfg.g_threads = encoder->threads;
|
||||||
cfg.rc_end_usage = encoder->mode;
|
cfg.rc_end_usage = encoder->mode;
|
||||||
|
@ -699,6 +801,31 @@ gst_vp8_enc_handle_frame (GstBaseVideoEncoder * base_video_encoder,
|
||||||
cfg.kf_min_dist = 0;
|
cfg.kf_min_dist = 0;
|
||||||
cfg.kf_max_dist = encoder->max_keyframe_distance;
|
cfg.kf_max_dist = encoder->max_keyframe_distance;
|
||||||
|
|
||||||
|
cfg.g_pass = encoder->multipass_mode;
|
||||||
|
if (encoder->multipass_mode == VPX_RC_FIRST_PASS) {
|
||||||
|
encoder->first_pass_cache_content = g_byte_array_sized_new (4096);
|
||||||
|
} else if (encoder->multipass_mode == VPX_RC_LAST_PASS) {
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
if (!encoder->multipass_cache_file) {
|
||||||
|
GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ,
|
||||||
|
("No multipass cache file provided"), (NULL));
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_file_get_contents (encoder->multipass_cache_file,
|
||||||
|
(gchar **) & encoder->last_pass_cache_content.buf,
|
||||||
|
&encoder->last_pass_cache_content.sz, &err)) {
|
||||||
|
GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ,
|
||||||
|
("Failed to read multipass cache file provided"), ("%s",
|
||||||
|
err->message));
|
||||||
|
g_error_free (err);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
cfg.rc_twopass_stats_in = encoder->last_pass_cache_content;
|
||||||
|
}
|
||||||
|
|
||||||
status = vpx_codec_enc_init (&encoder->encoder, &vpx_codec_vp8_cx_algo,
|
status = vpx_codec_enc_init (&encoder->encoder, &vpx_codec_vp8_cx_algo,
|
||||||
&cfg, 0);
|
&cfg, 0);
|
||||||
if (status != VPX_CODEC_OK) {
|
if (status != VPX_CODEC_OK) {
|
||||||
|
@ -750,7 +877,24 @@ gst_vp8_enc_handle_frame (GstBaseVideoEncoder * base_video_encoder,
|
||||||
GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz,
|
GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz,
|
||||||
pkt->kind);
|
pkt->kind);
|
||||||
|
|
||||||
if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
|
if (pkt->kind == VPX_CODEC_STATS_PKT
|
||||||
|
&& encoder->multipass_mode == VPX_RC_FIRST_PASS) {
|
||||||
|
GST_LOG_OBJECT (encoder, "handling STATS packet");
|
||||||
|
|
||||||
|
g_byte_array_append (encoder->first_pass_cache_content,
|
||||||
|
pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz);
|
||||||
|
|
||||||
|
frame = gst_base_video_encoder_get_oldest_frame (base_video_encoder);
|
||||||
|
if (frame != NULL) {
|
||||||
|
buffer = gst_buffer_new ();
|
||||||
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_PREROLL);
|
||||||
|
frame->src_buffer = buffer;
|
||||||
|
gst_base_video_encoder_finish_frame (base_video_encoder, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
||||||
|
continue;
|
||||||
|
} else if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
|
||||||
GST_LOG_OBJECT (encoder, "non frame pkt: %d", pkt->kind);
|
GST_LOG_OBJECT (encoder, "non frame pkt: %d", pkt->kind);
|
||||||
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter);
|
||||||
continue;
|
continue;
|
||||||
|
@ -813,45 +957,48 @@ gst_vp8_enc_shape_output (GstBaseVideoEncoder * base_video_encoder,
|
||||||
|
|
||||||
state = gst_base_video_encoder_get_state (base_video_encoder);
|
state = gst_base_video_encoder_get_state (base_video_encoder);
|
||||||
|
|
||||||
for (inv_count = 0, l = hook->invisible; l; inv_count++, l = l->next) {
|
buf = frame->src_buffer;
|
||||||
buf = l->data;
|
frame->src_buffer = NULL;
|
||||||
|
|
||||||
if (l == hook->invisible && frame->is_sync_point) {
|
if (hook) {
|
||||||
|
for (inv_count = 0, l = hook->invisible; l; inv_count++, l = l->next) {
|
||||||
|
buf = l->data;
|
||||||
|
|
||||||
|
if (l == hook->invisible && frame->is_sync_point) {
|
||||||
|
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
|
encoder->keyframe_distance = 0;
|
||||||
|
} else {
|
||||||
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
|
encoder->keyframe_distance++;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_BUFFER_TIMESTAMP (buf) = gst_video_state_get_timestamp (state,
|
||||||
|
&base_video_encoder->segment, frame->presentation_frame_number);
|
||||||
|
GST_BUFFER_DURATION (buf) = 0;
|
||||||
|
GST_BUFFER_OFFSET_END (buf) =
|
||||||
|
_to_granulepos (frame->presentation_frame_number + 1,
|
||||||
|
inv_count, encoder->keyframe_distance);
|
||||||
|
GST_BUFFER_OFFSET (buf) =
|
||||||
|
gst_util_uint64_scale (frame->presentation_frame_number + 1,
|
||||||
|
GST_SECOND * state->fps_d, state->fps_n);
|
||||||
|
|
||||||
|
gst_buffer_set_caps (buf, base_video_encoder->caps);
|
||||||
|
ret =
|
||||||
|
gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), buf);
|
||||||
|
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
GST_WARNING_OBJECT (encoder, "flow error %d", ret);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hook->invisible && frame->is_sync_point) {
|
||||||
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
encoder->keyframe_distance = 0;
|
encoder->keyframe_distance = 0;
|
||||||
} else {
|
} else {
|
||||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
encoder->keyframe_distance++;
|
encoder->keyframe_distance++;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (buf) = gst_video_state_get_timestamp (state,
|
|
||||||
&base_video_encoder->segment, frame->presentation_frame_number);
|
|
||||||
GST_BUFFER_DURATION (buf) = 0;
|
|
||||||
GST_BUFFER_OFFSET_END (buf) =
|
|
||||||
_to_granulepos (frame->presentation_frame_number + 1,
|
|
||||||
inv_count, encoder->keyframe_distance);
|
|
||||||
GST_BUFFER_OFFSET (buf) =
|
|
||||||
gst_util_uint64_scale (frame->presentation_frame_number + 1,
|
|
||||||
GST_SECOND * state->fps_d, state->fps_n);
|
|
||||||
|
|
||||||
gst_buffer_set_caps (buf, base_video_encoder->caps);
|
|
||||||
ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), buf);
|
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK) {
|
|
||||||
GST_WARNING_OBJECT (encoder, "flow error %d", ret);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = frame->src_buffer;
|
|
||||||
frame->src_buffer = NULL;
|
|
||||||
|
|
||||||
if (!hook->invisible && frame->is_sync_point) {
|
|
||||||
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
|
||||||
encoder->keyframe_distance = 0;
|
|
||||||
} else {
|
|
||||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
|
||||||
encoder->keyframe_distance++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (buf) = gst_video_state_get_timestamp (state,
|
GST_BUFFER_TIMESTAMP (buf) = gst_video_state_get_timestamp (state,
|
||||||
|
@ -874,10 +1021,12 @@ gst_vp8_enc_shape_output (GstBaseVideoEncoder * base_video_encoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
g_list_foreach (hook->invisible, (GFunc) gst_mini_object_unref, NULL);
|
if (hook) {
|
||||||
g_list_free (hook->invisible);
|
g_list_foreach (hook->invisible, (GFunc) gst_mini_object_unref, NULL);
|
||||||
g_slice_free (GstVP8EncCoderHook, hook);
|
g_list_free (hook->invisible);
|
||||||
frame->coder_hook = NULL;
|
g_slice_free (GstVP8EncCoderHook, hook);
|
||||||
|
frame->coder_hook = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue