static GstStateChangeReturn gst_y4m_encode_change_state (GstElement * element, GstStateChange transition) { GstY4mEncode *filter = GST_Y4M_ENCODE (element); GstStateChangeReturn ret; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_READY_TO_PAUSED: break; default: break; } ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state, (element, transition), GST_STATE_CHANGE_SUCCESS); if (ret != GST_STATE_CHANGE_SUCCESS) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: gst_y4m_encode_reset (filter); break; default: break; } return GST_STATE_CHANGE_SUCCESS; }
static void gst_y4m_encode_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstY4mEncode G_GNUC_UNUSED *filter; g_return_if_fail (GST_IS_Y4M_ENCODE (object)); filter = GST_Y4M_ENCODE (object); switch (prop_id) { default: break; } }
static void gst_y4m_encode_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstY4mEncode G_GNUC_UNUSED *filter; g_return_if_fail (GST_IS_Y4M_ENCODE (object)); filter = GST_Y4M_ENCODE (object); switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static GstFlowReturn gst_y4m_encode_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstY4mEncode *filter = GST_Y4M_ENCODE (encoder); GstClockTime timestamp; /* check we got some decent info from caps */ if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN) goto not_negotiated; timestamp = GST_BUFFER_TIMESTAMP (frame->input_buffer); if (G_UNLIKELY (!filter->header)) { gboolean tff = FALSE; if (GST_VIDEO_INFO_IS_INTERLACED (&filter->info)) { tff = GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF); } frame->output_buffer = gst_y4m_encode_get_stream_header (filter, tff); filter->header = TRUE; frame->output_buffer = gst_buffer_append (frame->output_buffer, gst_y4m_encode_get_frame_header (filter)); } else { frame->output_buffer = gst_y4m_encode_get_frame_header (filter); } frame->output_buffer = gst_buffer_append (frame->output_buffer, gst_buffer_copy (frame->input_buffer)); /* decorate */ frame->output_buffer = gst_buffer_make_writable (frame->output_buffer); GST_BUFFER_TIMESTAMP (frame->output_buffer) = timestamp; return gst_video_encoder_finish_frame (encoder, frame); not_negotiated: { GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), ("format wasn't negotiated")); return GST_FLOW_NOT_NEGOTIATED; } }
static gboolean gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps) { gboolean ret; GstY4mEncode *filter; GstVideoInfo info; filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad)); if (!gst_video_info_from_caps (&info, vscaps)) goto invalid_format; switch (GST_VIDEO_INFO_FORMAT (&info)) { case GST_VIDEO_FORMAT_I420: filter->colorspace = "420"; break; case GST_VIDEO_FORMAT_Y42B: filter->colorspace = "422"; break; case GST_VIDEO_FORMAT_Y41B: filter->colorspace = "411"; break; case GST_VIDEO_FORMAT_Y444: filter->colorspace = "444"; break; default: goto invalid_format; } filter->info = info; /* the template caps will do for the src pad, should always accept */ ret = gst_pad_set_caps (filter->srcpad, gst_static_pad_template_get_caps (&y4mencode_src_factory)); filter->negotiated = ret; return ret; /* ERRORS */ invalid_format: { GST_ERROR_OBJECT (filter, "got invalid caps"); return FALSE; } }
static GstFlowReturn gst_y4m_encode_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstY4mEncode *filter = GST_Y4M_ENCODE (parent); GstBuffer *outbuf; GstClockTime timestamp; /* check we got some decent info from caps */ if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN) goto not_negotiated; timestamp = GST_BUFFER_TIMESTAMP (buf); if (G_UNLIKELY (!filter->header)) { gboolean tff; if (GST_VIDEO_INFO_IS_INTERLACED (&filter->info)) { tff = GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF); } outbuf = gst_y4m_encode_get_stream_header (filter, tff); filter->header = TRUE; outbuf = gst_buffer_append (outbuf, gst_y4m_encode_get_frame_header (filter)); } else { outbuf = gst_y4m_encode_get_frame_header (filter); } /* join with data, FIXME, strides are all wrong etc */ outbuf = gst_buffer_append (outbuf, buf); /* decorate */ outbuf = gst_buffer_make_writable (outbuf); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; return gst_pad_push (filter->srcpad, outbuf); /* ERRORS */ not_negotiated: { GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), ("format wasn't negotiated before chain function")); gst_buffer_unref (buf); return GST_FLOW_NOT_NEGOTIATED; } }
static gboolean gst_y4m_encode_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) { GstY4mEncode *y4menc; GstVideoInfo *info; GstVideoCodecState *output_state; y4menc = GST_Y4M_ENCODE (encoder); info = &state->info; switch (GST_VIDEO_INFO_FORMAT (info)) { case GST_VIDEO_FORMAT_I420: y4menc->colorspace = "420"; break; case GST_VIDEO_FORMAT_Y42B: y4menc->colorspace = "422"; break; case GST_VIDEO_FORMAT_Y41B: y4menc->colorspace = "411"; break; case GST_VIDEO_FORMAT_Y444: y4menc->colorspace = "444"; break; default: goto invalid_format; } y4menc->info = *info; output_state = gst_video_encoder_set_output_state (encoder, gst_static_pad_template_get_caps (&y4mencode_src_factory), state); gst_video_codec_state_unref (output_state); return TRUE; invalid_format: { GST_ERROR_OBJECT (y4menc, "Invalid format"); return FALSE; } }
static GstFlowReturn gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf) { GstY4mEncode *filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad)); GstBuffer *outbuf; GstClockTime timestamp; /* check we got some decent info from caps */ if (filter->width < 0) { GST_ELEMENT_ERROR ("filter", CORE, NEGOTIATION, (NULL), ("format wasn't negotiated before chain function")); gst_buffer_unref (buf); return GST_FLOW_NOT_NEGOTIATED; } timestamp = GST_BUFFER_TIMESTAMP (buf); if (G_UNLIKELY (!filter->header)) { if (filter->interlaced == TRUE) { if (GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_TFF)) { filter->top_field_first = TRUE; } else { filter->top_field_first = FALSE; } } outbuf = gst_y4m_encode_get_stream_header (filter); filter->header = TRUE; outbuf = gst_buffer_join (outbuf, gst_y4m_encode_get_frame_header (filter)); } else { outbuf = gst_y4m_encode_get_frame_header (filter); } /* join with data */ outbuf = gst_buffer_join (outbuf, buf); /* decorate */ gst_buffer_make_metadata_writable (outbuf); gst_buffer_set_caps (outbuf, GST_PAD_CAPS (filter->srcpad)); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; return gst_pad_push (filter->srcpad, outbuf); }
static gboolean gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps) { GstY4mEncode *filter; GstStructure *structure; gboolean res; gint w, h; guint32 fourcc; const GValue *fps, *par, *interlaced; filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad)); structure = gst_caps_get_structure (vscaps, 0); res = gst_structure_get_int (structure, "width", &w); res &= gst_structure_get_int (structure, "height", &h); res &= ((fps = gst_structure_get_value (structure, "framerate")) != NULL); res &= gst_structure_get_fourcc (structure, "format", &fourcc); switch (fourcc) { /* Translate fourcc to Y4M colorspace code */ case GST_MAKE_FOURCC ('I', '4', '2', '0'): case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'): filter->colorspace = "420"; break; case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): filter->colorspace = "422"; break; case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): filter->colorspace = "411"; break; case GST_MAKE_FOURCC ('Y', '4', '4', '4'): filter->colorspace = "444"; break; default: res = FALSE; break; } if (!res || w <= 0 || h <= 0 || !GST_VALUE_HOLDS_FRACTION (fps)) return FALSE; /* optional interlaced info */ interlaced = gst_structure_get_value (structure, "interlaced"); /* optional par info */ par = gst_structure_get_value (structure, "pixel-aspect-ratio"); filter->width = w; filter->height = h; filter->fps_num = gst_value_get_fraction_numerator (fps); filter->fps_den = gst_value_get_fraction_denominator (fps); if ((par != NULL) && GST_VALUE_HOLDS_FRACTION (par)) { filter->par_num = gst_value_get_fraction_numerator (par); filter->par_den = gst_value_get_fraction_denominator (par); } else { /* indicates unknown */ filter->par_num = 0; filter->par_den = 0; } if ((interlaced != NULL) && G_VALUE_HOLDS (interlaced, G_TYPE_BOOLEAN)) { filter->interlaced = g_value_get_boolean (interlaced); } else { /* assume progressive if no interlaced property in caps */ filter->interlaced = FALSE; } /* the template caps will do for the src pad, should always accept */ return gst_pad_set_caps (filter->srcpad, gst_static_pad_template_get_caps (&y4mencode_src_factory)); }