static gboolean gst_base_video_encoder_sink_setcaps (GstPad * pad, GstCaps * caps) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; gboolean ret; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); GST_DEBUG ("setcaps"); gst_base_video_state_from_caps (&base_video_encoder->state, caps); ret = base_video_encoder_class->set_format (base_video_encoder, &base_video_encoder->state); if (ret) { ret = base_video_encoder_class->start (base_video_encoder); } g_object_unref (base_video_encoder); return ret; }
static void gst_base_video_encoder_finalize (GObject * object) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; GList *g; g_return_if_fail (GST_IS_BASE_VIDEO_ENCODER (object)); base_video_encoder = GST_BASE_VIDEO_ENCODER (object); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (object); GST_DEBUG ("finalize"); for (g = base_video_encoder->frames; g; g = g_list_next (g)) { gst_base_video_codec_free_frame ((GstVideoFrame *) g->data); } g_list_free (base_video_encoder->frames); if (base_video_encoder->caps) { gst_caps_unref (base_video_encoder->caps); base_video_encoder->caps = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
static GstStateChangeReturn gst_base_video_encoder_change_state (GstElement * element, GstStateChange transition) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; GstStateChangeReturn ret; base_video_encoder = GST_BASE_VIDEO_ENCODER (element); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (element); switch (transition) { default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: if (base_video_encoder_class->stop) { base_video_encoder_class->stop (base_video_encoder); } break; default: break; } return ret; }
static gboolean gst_base_video_encoder_src_query (GstPad * pad, GstQuery * query) { GstBaseVideoEncoder *enc; gboolean res; GstPad *peerpad; enc = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); peerpad = gst_pad_get_peer (GST_BASE_VIDEO_CODEC_SINK_PAD (enc)); switch GST_QUERY_TYPE (query) { case GST_QUERY_CONVERT: { GstFormat src_fmt, dest_fmt; gint64 src_val, dest_val; gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); res = gst_base_video_encoded_video_convert (&GST_BASE_VIDEO_CODEC (enc)->state, src_fmt, src_val, &dest_fmt, &dest_val); if (!res) goto error; gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); break; } case GST_QUERY_LATENCY: { gboolean live; GstClockTime min_latency, max_latency; res = gst_pad_query (peerpad, query); if (res) { gst_query_parse_latency (query, &live, &min_latency, &max_latency); min_latency += enc->min_latency; if (max_latency != GST_CLOCK_TIME_NONE) { max_latency += enc->max_latency; } gst_query_set_latency (query, live, min_latency, max_latency); } } break; default: res = gst_pad_query_default (pad, query); } gst_object_unref (peerpad); gst_object_unref (enc); return res; error: GST_DEBUG_OBJECT (enc, "query failed"); gst_object_unref (peerpad); gst_object_unref (enc); return res; }
static gboolean gst_base_video_encoder_sink_setcaps (GstPad * pad, GstCaps * caps) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; GstStructure *structure; GstVideoState *state; gboolean ret; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); GST_DEBUG ("setcaps"); state = &GST_BASE_VIDEO_CODEC (base_video_encoder)->state; structure = gst_caps_get_structure (caps, 0); gst_video_format_parse_caps (caps, &state->format, &state->width, &state->height); state->fps_n = 0; state->fps_d = 1; gst_video_parse_caps_framerate (caps, &state->fps_n, &state->fps_d); if (state->fps_d == 0) { state->fps_n = 0; state->fps_d = 1; } state->par_n = 1; state->par_d = 1; gst_video_parse_caps_pixel_aspect_ratio (caps, &state->par_n, &state->par_d); state->have_interlaced = gst_structure_get_boolean (structure, "interlaced", &state->interlaced); state->clean_width = state->width; state->clean_height = state->height; state->clean_offset_left = 0; state->clean_offset_top = 0; ret = base_video_encoder_class->set_format (base_video_encoder, &GST_BASE_VIDEO_CODEC (base_video_encoder)->state); if (ret) { ret = base_video_encoder_class->start (base_video_encoder); } g_object_unref (base_video_encoder); return ret; }
static GstFlowReturn gst_base_video_encoder_chain (GstPad * pad, GstBuffer * buf) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *klass; GstVideoFrame *frame; if (!gst_pad_is_negotiated (pad)) { return GST_FLOW_NOT_NEGOTIATED; } base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); klass = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); if (base_video_encoder->a.at_eos) { return GST_FLOW_UNEXPECTED; } if (base_video_encoder->sink_clipping) { gint64 start = GST_BUFFER_TIMESTAMP (buf); gint64 stop = start + GST_BUFFER_DURATION (buf); gint64 clip_start; gint64 clip_stop; if (!gst_segment_clip (&GST_BASE_VIDEO_CODEC (base_video_encoder)->segment, GST_FORMAT_TIME, start, stop, &clip_start, &clip_stop)) { GST_DEBUG ("clipping to segment dropped frame"); goto done; } } frame = gst_base_video_codec_new_frame (GST_BASE_VIDEO_CODEC (base_video_encoder)); frame->sink_buffer = buf; frame->presentation_timestamp = GST_BUFFER_TIMESTAMP (buf); frame->presentation_duration = GST_BUFFER_DURATION (buf); frame->presentation_frame_number = base_video_encoder->presentation_frame_number; base_video_encoder->presentation_frame_number++; GST_BASE_VIDEO_CODEC (base_video_encoder)->frames = g_list_append (GST_BASE_VIDEO_CODEC (base_video_encoder)->frames, frame); klass->handle_frame (base_video_encoder, frame); done: g_object_unref (base_video_encoder); return GST_FLOW_OK; }
static void gst_base_video_encoder_finalize (GObject * object) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; g_return_if_fail (GST_IS_BASE_VIDEO_ENCODER (object)); base_video_encoder = GST_BASE_VIDEO_ENCODER (object); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (object); GST_DEBUG ("finalize"); G_OBJECT_CLASS (parent_class)->finalize (object); }
static gboolean gst_base_video_encoder_sink_event (GstPad * pad, GstEvent * event) { GstBaseVideoEncoder *enc; GstBaseVideoEncoderClass *klass; gboolean handled = FALSE; gboolean ret = TRUE; enc = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); klass = GST_BASE_VIDEO_ENCODER_GET_CLASS (enc); GST_DEBUG_OBJECT (enc, "received event %d, %s", GST_EVENT_TYPE (event), GST_EVENT_TYPE_NAME (event)); if (klass->event) handled = klass->event (enc, event); if (!handled) handled = gst_base_video_encoder_sink_eventfunc (enc, event); if (!handled) { /* Forward non-serialized events and EOS/FLUSH_STOP immediately. * For EOS this is required because no buffer or serialized event * will come after EOS and nothing could trigger another * _finish_frame() call. * * If the subclass handles sending of EOS manually it can return * _DROPPED from ::finish() and all other subclasses should have * decoded/flushed all remaining data before this * * For FLUSH_STOP this is required because it is expected * to be forwarded immediately and no buffers are queued anyway. */ if (!GST_EVENT_IS_SERIALIZED (event) || GST_EVENT_TYPE (event) == GST_EVENT_EOS || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) { ret = gst_pad_push_event (enc->base_video_codec.srcpad, event); } else { GST_BASE_VIDEO_CODEC_STREAM_LOCK (enc); enc->current_frame_events = g_list_prepend (enc->current_frame_events, event); GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (enc); } } GST_DEBUG_OBJECT (enc, "event handled"); gst_object_unref (enc); return ret; }
static gboolean gst_base_video_encoder_src_event (GstPad * pad, GstEvent * event) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; gboolean ret = FALSE; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); 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")) { GST_OBJECT_LOCK (base_video_encoder); base_video_encoder->force_keyframe = TRUE; GST_OBJECT_UNLOCK (base_video_encoder); gst_event_unref (event); ret = TRUE; } else { ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_encoder), event); } break; } default: ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_encoder), event); break; } gst_object_unref (base_video_encoder); return ret; }
static gboolean gst_base_video_encoder_sink_event (GstPad * pad, GstEvent * event) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; gboolean ret = FALSE; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: { if (base_video_encoder_class->finish) { base_video_encoder_class->finish (base_video_encoder); } ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; case GST_EVENT_NEWSEGMENT: { gboolean update; double rate; double applied_rate; GstFormat format; gint64 start; gint64 stop; gint64 position; gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &format, &start, &stop, &position); if (format != GST_FORMAT_TIME) goto newseg_wrong_format; GST_DEBUG ("new segment %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (position)); gst_segment_set_newsegment_full (&GST_BASE_VIDEO_CODEC (base_video_encoder)->segment, update, rate, applied_rate, format, start, stop, position); ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; case GST_EVENT_CUSTOM_DOWNSTREAM: { const GstStructure *s; s = gst_event_get_structure (event); if (gst_structure_has_name (s, "GstForceKeyUnit")) { GST_OBJECT_LOCK (base_video_encoder); base_video_encoder->force_keyframe = TRUE; GST_OBJECT_UNLOCK (base_video_encoder); gst_event_unref (event); ret = GST_FLOW_OK; } else { ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; } default: /* FIXME this changes the order of events */ ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); break; } done: gst_object_unref (base_video_encoder); return ret; newseg_wrong_format: { GST_DEBUG_OBJECT (base_video_encoder, "received non TIME newsegment"); gst_event_unref (event); goto done; } }
static gboolean gst_base_video_encoder_sink_event (GstPad * pad, GstEvent * event) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; gboolean ret = FALSE; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: { if (base_video_encoder_class->finish) { base_video_encoder_class->finish (base_video_encoder); } ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; case GST_EVENT_NEWSEGMENT: { gboolean update; double rate; double applied_rate; GstFormat format; gint64 start; gint64 stop; gint64 position; gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &format, &start, &stop, &position); if (format != GST_FORMAT_TIME) goto newseg_wrong_format; GST_DEBUG ("new segment %lld %lld", start, position); gst_segment_set_newsegment_full (&base_video_encoder->segment, update, rate, applied_rate, format, start, stop, position); ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; default: /* FIXME this changes the order of events */ ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); break; } done: gst_object_unref (base_video_encoder); return ret; newseg_wrong_format: { GST_DEBUG_OBJECT (base_video_encoder, "received non TIME newsegment"); gst_event_unref (event); goto done; } }
static GstFlowReturn gst_base_video_encoder_chain (GstPad * pad, GstBuffer * buf) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *klass; GstVideoFrame *frame; GstFlowReturn ret = GST_FLOW_OK; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); klass = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); g_return_val_if_fail (klass->handle_frame != NULL, GST_FLOW_ERROR); GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); if (!GST_PAD_CAPS (pad)) { ret = GST_FLOW_NOT_NEGOTIATED; goto done; } GST_LOG_OBJECT (base_video_encoder, "received buffer of size %d with ts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); if (base_video_encoder->a.at_eos) { ret = GST_FLOW_UNEXPECTED; goto done; } if (base_video_encoder->sink_clipping) { gint64 start = GST_BUFFER_TIMESTAMP (buf); gint64 stop = start + GST_BUFFER_DURATION (buf); gint64 clip_start; gint64 clip_stop; if (!gst_segment_clip (&GST_BASE_VIDEO_CODEC (base_video_encoder)->segment, GST_FORMAT_TIME, start, stop, &clip_start, &clip_stop)) { GST_DEBUG_OBJECT (base_video_encoder, "clipping to segment dropped frame"); goto done; } } if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) { GST_LOG_OBJECT (base_video_encoder, "marked discont"); GST_BASE_VIDEO_CODEC (base_video_encoder)->discont = TRUE; } frame = gst_base_video_codec_new_frame (GST_BASE_VIDEO_CODEC (base_video_encoder)); frame->events = base_video_encoder->current_frame_events; base_video_encoder->current_frame_events = NULL; frame->sink_buffer = buf; frame->presentation_timestamp = GST_BUFFER_TIMESTAMP (buf); frame->presentation_duration = GST_BUFFER_DURATION (buf); frame->presentation_frame_number = base_video_encoder->presentation_frame_number; base_video_encoder->presentation_frame_number++; frame->force_keyframe = base_video_encoder->force_keyframe; base_video_encoder->force_keyframe = FALSE; GST_BASE_VIDEO_CODEC (base_video_encoder)->frames = g_list_append (GST_BASE_VIDEO_CODEC (base_video_encoder)->frames, frame); /* new data, more finish needed */ base_video_encoder->drained = FALSE; GST_LOG_OBJECT (base_video_encoder, "passing frame pfn %d to subclass", frame->presentation_frame_number); ret = klass->handle_frame (base_video_encoder, frame); done: GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); g_object_unref (base_video_encoder); return ret; }
static GstCaps * gst_base_video_encoder_sink_getcaps (GstPad * pad) { GstBaseVideoEncoder *base_video_encoder; const GstCaps *templ_caps; GstCaps *allowed; GstCaps *fcaps, *filter_caps; gint i, j; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); /* FIXME: Allow subclass to override this? */ /* Allow downstream to specify width/height/framerate/PAR constraints * and forward them upstream for video converters to handle */ templ_caps = gst_pad_get_pad_template_caps (GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_encoder)); allowed = gst_pad_get_allowed_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder)); if (!allowed || gst_caps_is_empty (allowed) || gst_caps_is_any (allowed)) { fcaps = gst_caps_copy (templ_caps); goto done; } GST_LOG_OBJECT (base_video_encoder, "template caps %" GST_PTR_FORMAT, templ_caps); GST_LOG_OBJECT (base_video_encoder, "allowed caps %" GST_PTR_FORMAT, allowed); filter_caps = gst_caps_new_empty (); for (i = 0; i < gst_caps_get_size (templ_caps); i++) { GQuark q_name = gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i)); for (j = 0; j < gst_caps_get_size (allowed); j++) { const GstStructure *allowed_s = gst_caps_get_structure (allowed, j); const GValue *val; GstStructure *s; s = gst_structure_id_empty_new (q_name); if ((val = gst_structure_get_value (allowed_s, "width"))) gst_structure_set_value (s, "width", val); if ((val = gst_structure_get_value (allowed_s, "height"))) gst_structure_set_value (s, "height", val); if ((val = gst_structure_get_value (allowed_s, "framerate"))) gst_structure_set_value (s, "framerate", val); if ((val = gst_structure_get_value (allowed_s, "pixel-aspect-ratio"))) gst_structure_set_value (s, "pixel-aspect-ratio", val); gst_caps_merge_structure (filter_caps, s); } } fcaps = gst_caps_intersect (filter_caps, templ_caps); gst_caps_unref (filter_caps); done: gst_caps_replace (&allowed, NULL); GST_LOG_OBJECT (base_video_encoder, "Returning caps %" GST_PTR_FORMAT, fcaps); return fcaps; }
static gboolean gst_base_video_encoder_sink_setcaps (GstPad * pad, GstCaps * caps) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; GstStructure *structure; GstVideoState *state, tmp_state; gboolean ret; gboolean changed = FALSE; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); /* subclass should do something here ... */ g_return_val_if_fail (base_video_encoder_class->set_format != NULL, FALSE); GST_DEBUG_OBJECT (base_video_encoder, "setcaps %" GST_PTR_FORMAT, caps); GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); state = &GST_BASE_VIDEO_CODEC (base_video_encoder)->state; memset (&tmp_state, 0, sizeof (tmp_state)); tmp_state.caps = gst_caps_ref (caps); structure = gst_caps_get_structure (caps, 0); ret = gst_video_format_parse_caps (caps, &tmp_state.format, &tmp_state.width, &tmp_state.height); if (!ret) goto exit; changed = (tmp_state.format != state->format || tmp_state.width != state->width || tmp_state.height != state->height); if (!gst_video_parse_caps_framerate (caps, &tmp_state.fps_n, &tmp_state.fps_d)) { tmp_state.fps_n = 0; tmp_state.fps_d = 1; } changed = changed || (tmp_state.fps_n != state->fps_n || tmp_state.fps_d != state->fps_d); if (!gst_video_parse_caps_pixel_aspect_ratio (caps, &tmp_state.par_n, &tmp_state.par_d)) { tmp_state.par_n = 1; tmp_state.par_d = 1; } changed = changed || (tmp_state.par_n != state->par_n || tmp_state.par_d != state->par_d); tmp_state.have_interlaced = gst_structure_get_boolean (structure, "interlaced", &tmp_state.interlaced); changed = changed || (tmp_state.have_interlaced != state->have_interlaced || tmp_state.interlaced != state->interlaced); tmp_state.bytes_per_picture = gst_video_format_get_size (tmp_state.format, tmp_state.width, tmp_state.height); tmp_state.clean_width = tmp_state.width; tmp_state.clean_height = tmp_state.height; tmp_state.clean_offset_left = 0; tmp_state.clean_offset_top = 0; if (changed) { /* arrange draining pending frames */ gst_base_video_encoder_drain (base_video_encoder); /* and subclass should be ready to configure format at any time around */ if (base_video_encoder_class->set_format) ret = base_video_encoder_class->set_format (base_video_encoder, &tmp_state); if (ret) { gst_caps_replace (&state->caps, NULL); *state = tmp_state; } } else { /* no need to stir things up */ GST_DEBUG_OBJECT (base_video_encoder, "new video format identical to configured format"); gst_caps_unref (tmp_state.caps); ret = TRUE; } exit: GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); if (!ret) { GST_WARNING_OBJECT (base_video_encoder, "rejected caps %" GST_PTR_FORMAT, caps); } g_object_unref (base_video_encoder); return ret; }
static GstFlowReturn gst_vp8_enc_process (GstVP8Enc * encoder) { vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *pkt; GstBaseVideoEncoder *base_video_encoder; GstVP8EncCoderHook *hook; GstVideoFrame *frame; GstFlowReturn ret = GST_FLOW_OK; base_video_encoder = GST_BASE_VIDEO_ENCODER (encoder); pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); while (pkt != NULL) { GstBuffer *buffer; gboolean invisible; GST_DEBUG_OBJECT (encoder, "packet %u type %d", (guint) pkt->data.frame.sz, pkt->kind); 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); pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); continue; } invisible = (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) != 0; frame = gst_base_video_encoder_get_oldest_frame (base_video_encoder); g_assert (frame != NULL); frame->is_sync_point = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; hook = frame->coder_hook; buffer = gst_buffer_new_and_alloc (pkt->data.frame.sz); memcpy (GST_BUFFER_DATA (buffer), pkt->data.frame.buf, pkt->data.frame.sz); if (hook->image) g_slice_free (vpx_image_t, hook->image); hook->image = NULL; if (invisible) { hook->invisible = g_list_append (hook->invisible, buffer); } else { frame->src_buffer = buffer; ret = gst_base_video_encoder_finish_frame (base_video_encoder, frame); } pkt = vpx_codec_get_cx_data (&encoder->encoder, &iter); } return ret; }