From: Sebastian Dröge Date: Wed, 20 Jun 2012 12:11:58 +0000 (+0100) Subject: omx: Port to video base classes from -base X-Git-Tag: 1.19.3~501^2~748 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5fdb490f1a9999d483f4a7a6c57dcf4da17d71be;p=platform%2Fupstream%2Fgstreamer.git omx: Port to video base classes from -base --- diff --git a/omx/Makefile.am b/omx/Makefile.am index 94fc485..0296128 100644 --- a/omx/Makefile.am +++ b/omx/Makefile.am @@ -13,10 +13,6 @@ libgstopenmax_la_SOURCES = \ gstomxh264enc.c \ gstomxh263enc.c \ gstomxaacenc.c \ - gstbasevideocodec.c \ - gstbasevideodecoder.c \ - gstbasevideoencoder.c \ - gstbasevideoutils.c \ gstomxrecmutex.c noinst_HEADERS = \ @@ -32,27 +28,14 @@ noinst_HEADERS = \ gstomxh264enc.h \ gstomxh263enc.h \ gstomxaacenc.h \ - gstbasevideocodec.h \ - gstbasevideodecoder.h \ - gstbasevideoencoder.h \ - gstbasevideoutils.h \ gstomxrecmutex.h -fixbaseclasses = \ - -DGstBaseVideoCodec=OMXBaseVideoCodec \ - -DGstBaseVideoCodecClass=OMXBaseVideoCodecClass \ - -DGstBaseVideoEncoder=OMXBaseVideoEncoder \ - -DGstBaseVideoEncoderClass=OMXBaseVideoEncoderClass \ - -DGstBaseVideoDecoder=OMXBaseVideoDecoder \ - -DGstBaseVideoDecoderClass=OMXBaseVideoDecoderClass - libgstopenmax_la_CFLAGS = \ -DGST_USE_UNSTABLE_API=1 \ -I$(abs_srcdir)/openmax \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) \ - $(GST_CFLAGS) \ - $(fixbaseclasses) + $(GST_CFLAGS) libgstopenmax_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) \ -lgstaudio-@GST_API_VERSION@ \ @@ -76,5 +59,5 @@ Android.mk: Makefile.am $(BUILT_SOURCES) $(libgstopenmax_la_LIBADD) \ -ldl \ -:PASSTHROUGH LOCAL_ARM_MODE:=arm \ - LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \ + LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-$(GST_API_VERSION)' \ > $@ diff --git a/omx/gstbasevideocodec.c b/omx/gstbasevideocodec.c deleted file mode 100644 index 9f839cc..0000000 --- a/omx/gstbasevideocodec.c +++ /dev/null @@ -1,343 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:gstbasevideocodec - * @short_description: Base class and objects for video codecs - * - **/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/** - * SECTION:gstbasevideocodec - * @short_description: Base class for video codecs - * @see_also: #GstBaseVideoDecoder , #GstBaseVideoEncoder - */ - -/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - -#include "gstbasevideocodec.h" - -#include -#include - -GST_DEBUG_CATEGORY (basevideocodec_debug); -#define GST_CAT_DEFAULT basevideocodec_debug - -/* GstBaseVideoCodec signals and args */ -enum -{ - LAST_SIGNAL -}; - -enum -{ - ARG_0 -}; - -static void gst_base_video_codec_finalize (GObject * object); - -static GstStateChangeReturn gst_base_video_codec_change_state (GstElement * - element, GstStateChange transition); - -static GstElementClass *parent_class = NULL; - -G_DEFINE_BOXED_TYPE (GstVideoFrameState, gst_video_frame_state, - (GBoxedCopyFunc) gst_video_frame_state_ref, - (GBoxedFreeFunc) gst_video_frame_state_unref); - -/* NOTE (Edward): Do not use G_DEFINE_* because we need to have - * a GClassInitFunc called with the target class (which the macros - * don't handle). - */ -static void gst_base_video_codec_class_init (GstBaseVideoCodecClass * klass); -static void gst_base_video_codec_init (GstBaseVideoCodec * dec, - GstBaseVideoCodecClass * klass); - -GType -gst_base_video_codec_get_type (void) -{ - static volatile gsize base_video_codec_type = 0; - - if (g_once_init_enter (&base_video_codec_type)) { - GType _type; - static const GTypeInfo base_video_codec_info = { - sizeof (GstBaseVideoCodecClass), - NULL, - NULL, - (GClassInitFunc) gst_base_video_codec_class_init, - NULL, - NULL, - sizeof (GstBaseVideoCodec), - 0, - (GInstanceInitFunc) gst_base_video_codec_init, - }; - - _type = g_type_register_static (GST_TYPE_ELEMENT, - "GstBaseVideoCodec", &base_video_codec_info, G_TYPE_FLAG_ABSTRACT); - g_once_init_leave (&base_video_codec_type, _type); - } - return base_video_codec_type; -} - -static void -gst_base_video_codec_class_init (GstBaseVideoCodecClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *element_class; - - gobject_class = G_OBJECT_CLASS (klass); - element_class = GST_ELEMENT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_base_video_codec_finalize; - - element_class->change_state = gst_base_video_codec_change_state; - - GST_DEBUG_CATEGORY_INIT (basevideocodec_debug, "basevideocodec", 0, - "Base Video Codec"); -} - -static void -gst_base_video_codec_init (GstBaseVideoCodec * base_video_codec, - GstBaseVideoCodecClass * klass) -{ - GstPadTemplate *pad_template; - - GST_DEBUG_OBJECT (base_video_codec, "gst_base_video_codec_init"); - - pad_template = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink"); - g_return_if_fail (pad_template != NULL); - - base_video_codec->sinkpad = gst_pad_new_from_template (pad_template, "sink"); - gst_element_add_pad (GST_ELEMENT (base_video_codec), - base_video_codec->sinkpad); - - pad_template = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src"); - g_return_if_fail (pad_template != NULL); - - base_video_codec->srcpad = gst_pad_new_from_template (pad_template, "src"); - gst_element_add_pad (GST_ELEMENT (base_video_codec), - base_video_codec->srcpad); - - gst_segment_init (&base_video_codec->segment, GST_FORMAT_TIME); - - g_rec_mutex_init (&base_video_codec->stream_lock); -} - -static void -gst_base_video_codec_reset (GstBaseVideoCodec * base_video_codec) -{ - GList *g; - - GST_DEBUG_OBJECT (base_video_codec, "reset"); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_codec); - for (g = base_video_codec->frames; g; g = g_list_next (g)) { - gst_video_frame_state_unref ((GstVideoFrameState *) g->data); - } - g_list_free (base_video_codec->frames); - base_video_codec->frames = NULL; - - base_video_codec->bytes = 0; - base_video_codec->time = 0; - - gst_buffer_replace (&base_video_codec->state.codec_data, NULL); - gst_caps_replace (&base_video_codec->state.caps, NULL); - memset (&base_video_codec->state, 0, sizeof (GstVideoState)); - base_video_codec->state.format = GST_VIDEO_FORMAT_UNKNOWN; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_codec); -} - -static void -gst_base_video_codec_finalize (GObject * object) -{ - GstBaseVideoCodec *base_video_codec = GST_BASE_VIDEO_CODEC (object); - - g_rec_mutex_clear (&base_video_codec->stream_lock); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static GstStateChangeReturn -gst_base_video_codec_change_state (GstElement * element, - GstStateChange transition) -{ - GstBaseVideoCodec *base_video_codec = GST_BASE_VIDEO_CODEC (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_base_video_codec_reset (base_video_codec); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_base_video_codec_reset (base_video_codec); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -/** - * gst_base_video_codec_append_frame: - * @codec: a #GstBaseVideoCodec - * @frame: the #GstVideoFrameState to append - * - * Appends a frame to the list of frames handled by the codec. - * - * Note: This should normally not be used by implementations. - **/ -void -gst_base_video_codec_append_frame (GstBaseVideoCodec * codec, - GstVideoFrameState * frame) -{ - g_return_if_fail (frame != NULL); - - gst_video_frame_state_ref (frame); - codec->frames = g_list_append (codec->frames, frame); -} - -void -gst_base_video_codec_remove_frame (GstBaseVideoCodec * codec, - GstVideoFrameState * frame) -{ - GList *link; - - g_return_if_fail (frame != NULL); - - link = g_list_find (codec->frames, frame); - if (link) { - gst_video_frame_state_unref ((GstVideoFrameState *) link->data); - codec->frames = g_list_delete_link (codec->frames, link); - } -} - -static void -_gst_video_frame_state_free (GstVideoFrameState * frame) -{ - g_return_if_fail (frame != NULL); - - GST_LOG ("Freeing frame %p (sfn:%d)", frame, frame->system_frame_number); - - if (frame->sink_buffer) { - gst_buffer_unref (frame->sink_buffer); - } - - if (frame->src_buffer) { - gst_buffer_unref (frame->src_buffer); - } - - g_list_foreach (frame->events, (GFunc) gst_event_unref, NULL); - g_list_free (frame->events); - - if (frame->coder_hook_destroy_notify && frame->coder_hook) - frame->coder_hook_destroy_notify (frame->coder_hook); - - g_slice_free (GstVideoFrameState, frame); -} - -/** - * gst_base_video_codec_new_frame: - * @base_video_codec: a #GstBaseVideoCodec - * - * Creates a new #GstVideoFrameState for usage in decoders or encoders. - * - * Returns: (transfer full): The new #GstVideoFrameState, call - * #gst_video_frame_state_unref() when done with it. - */ -GstVideoFrameState * -gst_base_video_codec_new_frame (GstBaseVideoCodec * base_video_codec) -{ - GstVideoFrameState *frame; - - frame = g_slice_new0 (GstVideoFrameState); - - frame->ref_count = 1; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_codec); - frame->system_frame_number = base_video_codec->system_frame_number; - base_video_codec->system_frame_number++; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_codec); - - GST_LOG_OBJECT (base_video_codec, "Created new frame %p (sfn:%d)", - frame, frame->system_frame_number); - - return frame; -} - -/** - * gst_video_frame_state_ref: - * @frame: a #GstVideoFrameState - * - * Increases the refcount of the given frame by one. - * - * Returns: @buf - */ -GstVideoFrameState * -gst_video_frame_state_ref (GstVideoFrameState * frame) -{ - g_return_val_if_fail (frame != NULL, NULL); - - g_atomic_int_inc (&frame->ref_count); - - return frame; -} - -/** - * gst_video_frame_state_unref: - * @frame: a #GstVideoFrameState - * - * Decreases the refcount of the frame. If the refcount reaches 0, the frame - * will be freed. - */ -void -gst_video_frame_state_unref (GstVideoFrameState * frame) -{ - g_return_if_fail (frame != NULL); - g_return_if_fail (frame->ref_count > 0); - - if (g_atomic_int_dec_and_test (&frame->ref_count)) { - _gst_video_frame_state_free (frame); - } -} diff --git a/omx/gstbasevideocodec.h b/omx/gstbasevideocodec.h deleted file mode 100644 index 256279d..0000000 --- a/omx/gstbasevideocodec.h +++ /dev/null @@ -1,289 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _GST_BASE_VIDEO_CODEC_H_ -#define _GST_BASE_VIDEO_CODEC_H_ - -#ifndef GST_USE_UNSTABLE_API -#warning "GstBaseVideoCodec is unstable API and may change in future." -#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." -#endif - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_BASE_VIDEO_CODEC \ - (gst_base_video_codec_get_type()) -#define GST_BASE_VIDEO_CODEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_VIDEO_CODEC,GstBaseVideoCodec)) -#define GST_BASE_VIDEO_CODEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_VIDEO_CODEC,GstBaseVideoCodecClass)) -#define GST_BASE_VIDEO_CODEC_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_BASE_VIDEO_CODEC,GstBaseVideoCodecClass)) -#define GST_IS_BASE_VIDEO_CODEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_VIDEO_CODEC)) -#define GST_IS_BASE_VIDEO_CODEC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_VIDEO_CODEC)) - -/** - * GST_BASE_VIDEO_CODEC_SINK_NAME: - * - * The name of the templates for the sink pad. - */ -#define GST_BASE_VIDEO_CODEC_SINK_NAME "sink" -/** - * GST_BASE_VIDEO_CODEC_SRC_NAME: - * - * The name of the templates for the source pad. - */ -#define GST_BASE_VIDEO_CODEC_SRC_NAME "src" - -/** - * GST_BASE_VIDEO_CODEC_SRC_PAD: - * @obj: base video codec instance - * - * Gives the pointer to the source #GstPad object of the element. - */ -#define GST_BASE_VIDEO_CODEC_SRC_PAD(obj) (((GstBaseVideoCodec *) (obj))->srcpad) - -/** - * GST_BASE_VIDEO_CODEC_SINK_PAD: - * @obj: base video codec instance - * - * Gives the pointer to the sink #GstPad object of the element. - */ -#define GST_BASE_VIDEO_CODEC_SINK_PAD(obj) (((GstBaseVideoCodec *) (obj))->sinkpad) - -/** - * GST_BASE_VIDEO_CODEC_FLOW_NEED_DATA: - * - * Returned while parsing to indicate more data is needed. - */ -#define GST_BASE_VIDEO_CODEC_FLOW_NEED_DATA GST_FLOW_CUSTOM_SUCCESS - -/** - * GST_BASE_VIDEO_CODEC_STREAM_LOCK: - * @codec: video codec instance - * - * Obtain a lock to protect the codec function from concurrent access. - * - * Since: 0.10.22 - */ -#define GST_BASE_VIDEO_CODEC_STREAM_LOCK(codec) g_rec_mutex_lock (&GST_BASE_VIDEO_CODEC (codec)->stream_lock) -/** - * GST_BASE_VIDEO_CODEC_STREAM_UNLOCK: - * @codec: video codec instance - * - * Release the lock that protects the codec function from concurrent access. - * - * Since: 0.10.22 - */ -#define GST_BASE_VIDEO_CODEC_STREAM_UNLOCK(codec) g_rec_mutex_unlock (&GST_BASE_VIDEO_CODEC (codec)->stream_lock) - -typedef struct _GstVideoState GstVideoState; -typedef struct _GstVideoFrameState GstVideoFrameState; -typedef struct _GstBaseVideoCodec GstBaseVideoCodec; -typedef struct _GstBaseVideoCodecClass GstBaseVideoCodecClass; - -/* GstVideoState is only used on the compressed video pad */ -/** - * GstVideoState: - * @width: Width in pixels (including borders) - * @height: Height in pixels (including borders) - * @fps_n: Numerator of framerate - * @fps_d: Denominator of framerate - * @par_n: Numerator of Pixel Aspect Ratio - * @par_d: Denominator of Pixel Aspect Ratio - * @have_interlaced: The content of the @interlaced field is present and valid - * @interlaced: %TRUE if the stream is interlaced - * @top_field_first: %TRUE if the interlaced frame is top-field-first - * @clean_width: Useful width of video in pixels (i.e. without borders) - * @clean_height: Useful height of video in pixels (i.e. without borders) - * @clean_offset_left: Horizontal offset (from the left) of useful region in pixels - * @clean_offset_top: Vertical offset (from the top) of useful region in pixels - * @bytes_per_picture: Size in bytes of each picture - * @codec_data: Optional Codec Data for the stream - * - * Information about compressed video stream. - * FIXME: Re-use GstVideoInfo for more fields. - */ -struct _GstVideoState -{ - GstCaps *caps; - GstVideoFormat format; - int width, height; - int fps_n, fps_d; - int par_n, par_d; - - gboolean have_interlaced; - gboolean interlaced; - gboolean top_field_first; - - int clean_width, clean_height; - int clean_offset_left, clean_offset_top; - - int bytes_per_picture; - - GstBuffer *codec_data; -}; - -/** - * GstVideoFrameState: - * @decode_timestamp: Decoding timestamp (aka DTS) - * @presentation_timestamp: Presentation timestamp (aka PTS) - * @presentation_duration: Duration of frame - * @system_frame_number: unique ID attributed when #GstVideoFrameState is - * created - * @decode_frame_number: Decoded frame number, increases in decoding order - * @presentation_frame_number: Presentation frame number, increases in - * presentation order. - * @distance_from_sync: Distance of the frame from a sync point, in number - * of frames. - * @is_sync_point: #TRUE if the frame is a synchronization point (like a - * keyframe) - * @is_eos: #TRUE if the frame is the last one of a segment. - * @decode_only: If #TRUE, the frame is only meant to be decoded but not - * pushed downstream - * @sink_buffer: input buffer - * @src_buffer: output buffer - * @field_index: Number of fields since beginning of stream - * @n_fields: Number of fields present in frame (default 2) - * @coder_hook: Private data called with @coder_hook_destroy_notify - * @coder_hook_destroy_notify: Called when frame is destroyed - * @deadline: Target clock time for display (running time) - * @force_keyframe: For encoders, if #TRUE a keyframe must be generated - * @force_keyframe_headers: For encoders, if #TRUE new headers must be generated - * @events: List of #GstEvent that must be pushed before the next @src_buffer - * - * State of a video frame going through the codec - **/ - -struct _GstVideoFrameState -{ - /*< private >*/ - gint ref_count; - - /*< public >*/ - GstClockTime decode_timestamp; - GstClockTime presentation_timestamp; - GstClockTime presentation_duration; - - gint system_frame_number; - gint decode_frame_number; - gint presentation_frame_number; - - int distance_from_sync; - gboolean is_sync_point; - gboolean is_eos; - - /* Frames that should not be pushed downstream and are - * not meant for display */ - gboolean decode_only; - - GstBuffer *sink_buffer; - GstBuffer *src_buffer; - - int field_index; - int n_fields; - - void *coder_hook; - GDestroyNotify coder_hook_destroy_notify; - - GstClockTime deadline; - - gboolean force_keyframe; - gboolean force_keyframe_headers; - - /* Events that should be pushed downstream *before* - * the next src_buffer */ - GList *events; -}; - -/** - * GstBaseVideoCodec: - * - * The opaque #GstBaseVideoCodec data structure. - */ -struct _GstBaseVideoCodec -{ - /*< private >*/ - GstElement element; - - /*< protected >*/ - GstPad *sinkpad; - GstPad *srcpad; - - /* protects all data processing, i.e. is locked - * in the chain function, finish_frame and when - * processing serialized events */ - GRecMutex stream_lock; - - guint64 system_frame_number; - - GList *frames; /* Protected with OBJECT_LOCK */ - GstVideoState state; /* Compressed video pad */ - GstVideoInfo info; /* Raw video pad */ - GstSegment segment; - - /* QoS properties */ - gdouble proportion; - GstClockTime earliest_time; - gboolean discont; - - gint64 bytes; - gint64 time; - - /* FIXME before moving to base */ - void *padding[GST_PADDING_LARGE]; -}; - -/** - * GstBaseVideoCodecClass: - * - * The opaque #GstBaseVideoCodecClass data structure. - */ -struct _GstBaseVideoCodecClass -{ - /*< private >*/ - GstElementClass element_class; - - /* FIXME before moving to base */ - void *padding[GST_PADDING_LARGE]; -}; - -GType gst_video_frame_state_get_type (void); -GType gst_base_video_codec_get_type (void); - -void gst_base_video_codec_append_frame (GstBaseVideoCodec *codec, GstVideoFrameState *frame); -void gst_base_video_codec_remove_frame (GstBaseVideoCodec *codec, GstVideoFrameState *frame); - -GstVideoFrameState * gst_base_video_codec_new_frame (GstBaseVideoCodec *base_video_codec); - -GstVideoFrameState * gst_video_frame_state_ref (GstVideoFrameState * frame); -void gst_video_frame_state_unref (GstVideoFrameState * frame); - -G_END_DECLS - -#endif - diff --git a/omx/gstbasevideodecoder.c b/omx/gstbasevideodecoder.c deleted file mode 100644 index 6ed38dc..0000000 --- a/omx/gstbasevideodecoder.c +++ /dev/null @@ -1,2238 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef - * Copyright (C) 2011 Mark Nauwelaerts . - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:gstbasevideodecoder - * @short_description: Base class for video decoders - * @see_also: #GstBaseTransform - * - * This base class is for video decoders turning encoded data into raw video - * frames. - * - * GstBaseVideoDecoder and subclass should cooperate as follows. - * - * - * Configuration - * - * Initially, GstBaseVideoDecoder calls @start when the decoder element - * is activated, which allows subclass to perform any global setup. - * - * - * GstBaseVideoDecoder calls @set_format to inform subclass of caps - * describing input video data that it is about to receive, including - * possibly configuration data. - * While unlikely, it might be called more than once, if changing input - * parameters require reconfiguration. - * - * - * GstBaseVideoDecoder calls @stop at end of all processing. - * - * - * - * - * - * Data processing - * - * Base class gathers input data, and optionally allows subclass - * to parse this into subsequently manageable chunks, typically - * corresponding to and referred to as 'frames'. - * - * - * Input frame is provided to subclass' @handle_frame. - * - * - * If codec processing results in decoded data, subclass should call - * @gst_base_video_decoder_finish_frame to have decoded data pushed - * downstream. - * - * - * - * - * Shutdown phase - * - * GstBaseVideoDecoder class calls @stop to inform the subclass that data - * parsing will be stopped. - * - * - * - * - * - * Subclass is responsible for providing pad template caps for - * source and sink pads. The pads need to be named "sink" and "src". It also - * needs to set the fixed caps on srcpad, when the format is ensured. This - * is typically when base class calls subclass' @set_format function, though - * it might be delayed until calling @gst_base_video_decoder_finish_frame. - * - * Subclass is also responsible for providing (presentation) timestamps - * (likely based on corresponding input ones). If that is not applicable - * or possible, baseclass provides limited framerate based interpolation. - * - * Similarly, the baseclass provides some limited (legacy) seeking support - * (upon explicit subclass request), as full-fledged support - * should rather be left to upstream demuxer, parser or alike. This simple - * approach caters for seeking and duration reporting using estimated input - * bitrates. - * - * Baseclass provides some support for reverse playback, in particular - * in case incoming data is not packetized or upstream does not provide - * fragments on keyframe boundaries. However, subclass should then be prepared - * for the parsing and frame processing stage to occur separately (rather - * than otherwise the latter immediately following the former), - * and should ensure the parsing stage properly marks keyframes or rely on - * upstream to do so properly for incoming data. - * - * Things that subclass need to take care of: - * - * Provide pad templates - * - * Set source pad caps when appropriate - * - * - * Configure some baseclass behaviour parameters. - * - * - * Optionally parse input data, if it is not considered packetized. - * Parse sync is obtained either by providing baseclass with a - * mask and pattern or a custom @scan_for_sync. When sync is established, - * @parse_data should invoke @gst_base_video_decoder_add_to_frame and - * @gst_base_video_decoder_have_frame as appropriate. - * - * - * Accept data in @handle_frame and provide decoded results to - * @gst_base_video_decoder_finish_frame. - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - -#include "gstbasevideodecoder.h" -#include "gstbasevideoutils.h" - -#include - -GST_DEBUG_CATEGORY (basevideodecoder_debug); -#define GST_CAT_DEFAULT basevideodecoder_debug - -static void gst_base_video_decoder_finalize (GObject * object); - -static gboolean gst_base_video_decoder_setcaps (GstBaseVideoDecoder * vdec, - GstCaps * caps); -static gboolean gst_base_video_decoder_sink_event (GstPad * pad, - GstObject * parent, GstEvent * event); -static gboolean gst_base_video_decoder_src_event (GstPad * pad, - GstObject * parent, GstEvent * event); -static GstFlowReturn gst_base_video_decoder_chain (GstPad * pad, - GstObject * parent, GstBuffer * buf); -static gboolean gst_base_video_decoder_sink_query (GstPad * pad, - GstObject * parent, GstQuery * query); -static GstStateChangeReturn gst_base_video_decoder_change_state (GstElement * - element, GstStateChange transition); -static gboolean gst_base_video_decoder_src_query (GstPad * pad, - GstObject * parent, GstQuery * query); -static void gst_base_video_decoder_reset (GstBaseVideoDecoder * - base_video_decoder, gboolean full); - -static GstFlowReturn -gst_base_video_decoder_have_frame_2 (GstBaseVideoDecoder * base_video_decoder); - -static guint64 -gst_base_video_decoder_get_timestamp (GstBaseVideoDecoder * base_video_decoder, - int picture_number); -static guint64 -gst_base_video_decoder_get_field_timestamp (GstBaseVideoDecoder * - base_video_decoder, int field_offset); -static guint64 gst_base_video_decoder_get_field_duration (GstBaseVideoDecoder * - base_video_decoder, int n_fields); -static GstVideoFrameState *gst_base_video_decoder_new_frame (GstBaseVideoDecoder - * base_video_decoder); - -static void gst_base_video_decoder_clear_queues (GstBaseVideoDecoder * dec); - -#define gst_base_video_decoder_parent_class parent_class -G_DEFINE_TYPE (GstBaseVideoDecoder, gst_base_video_decoder, - GST_TYPE_BASE_VIDEO_CODEC); - -static void -gst_base_video_decoder_class_init (GstBaseVideoDecoderClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = G_OBJECT_CLASS (klass); - gstelement_class = GST_ELEMENT_CLASS (klass); - - gobject_class->finalize = gst_base_video_decoder_finalize; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_base_video_decoder_change_state); - - GST_DEBUG_CATEGORY_INIT (basevideodecoder_debug, "basevideodecoder", 0, - "Base Video Decoder"); -} - -static void -gst_base_video_decoder_init (GstBaseVideoDecoder * base_video_decoder) -{ - GstPad *pad; - - GST_DEBUG_OBJECT (base_video_decoder, "gst_base_video_decoder_init"); - - pad = GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_decoder); - - gst_pad_set_chain_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_decoder_chain)); - gst_pad_set_event_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_decoder_sink_event)); - gst_pad_set_query_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_decoder_sink_query)); - - pad = GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_decoder); - - gst_pad_set_event_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_decoder_src_event)); - gst_pad_set_query_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_decoder_src_query)); - gst_pad_use_fixed_caps (pad); - - base_video_decoder->input_adapter = gst_adapter_new (); - base_video_decoder->output_adapter = gst_adapter_new (); - - gst_base_video_decoder_reset (base_video_decoder, TRUE); - - base_video_decoder->sink_clipping = TRUE; -} - -static gboolean -gst_base_video_decoder_push_src_event (GstBaseVideoDecoder * decoder, - GstEvent * event) -{ - /* 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) - return gst_pad_push_event (decoder->base_video_codec.srcpad, event); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (decoder); - decoder->current_frame_events = - g_list_prepend (decoder->current_frame_events, event); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (decoder); - - return TRUE; -} - -static gboolean -gst_base_video_decoder_setcaps (GstBaseVideoDecoder * base_video_decoder, - GstCaps * caps) -{ - GstBaseVideoDecoderClass *base_video_decoder_class; - GstStructure *structure; - const GValue *codec_data; - GstVideoState state; - gboolean ret = TRUE; - - base_video_decoder_class = - GST_BASE_VIDEO_DECODER_GET_CLASS (base_video_decoder); - - GST_DEBUG_OBJECT (base_video_decoder, "setcaps %" GST_PTR_FORMAT, caps); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - memset (&state, 0, sizeof (state)); - - state.caps = gst_caps_ref (caps); - - structure = gst_caps_get_structure (caps, 0); - - /* FIXME : Add have_{width_height|framerate|par} fields to - * GstVideoState so we can make better decisions - */ - - gst_structure_get_int (structure, "width", &state.width); - gst_structure_get_int (structure, "height", &state.height); - - if (!gst_structure_get_fraction (structure, "framerate", &state.fps_n, - &state.fps_d)) { - state.fps_n = 0; - state.fps_d = 1; - } - - if (!gst_structure_get_fraction (structure, "pixel-aspect-ratio", - &state.par_n, &state.par_d)) { - state.par_n = 0; - state.par_d = 1; - } - - state.have_interlaced = - gst_structure_get_boolean (structure, "interlaced", &state.interlaced); - - codec_data = gst_structure_get_value (structure, "codec_data"); - if (codec_data && G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) { - state.codec_data = GST_BUFFER (gst_value_get_buffer (codec_data)); - gst_buffer_ref (state.codec_data); - } - - if (base_video_decoder_class->set_format) { - GST_LOG_OBJECT (base_video_decoder, "Calling ::set_format()"); - ret = base_video_decoder_class->set_format (base_video_decoder, &state); - } - - if (ret) { - gst_buffer_replace (&GST_BASE_VIDEO_CODEC (base_video_decoder)->state. - codec_data, NULL); - gst_caps_replace (&GST_BASE_VIDEO_CODEC (base_video_decoder)->state.caps, - NULL); - GST_BASE_VIDEO_CODEC (base_video_decoder)->state = state; - } else { - gst_buffer_replace (&state.codec_data, NULL); - gst_caps_replace (&state.caps, NULL); - } - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return ret; -} - -static void -gst_base_video_decoder_finalize (GObject * object) -{ - GstBaseVideoDecoder *base_video_decoder; - - base_video_decoder = GST_BASE_VIDEO_DECODER (object); - - GST_DEBUG_OBJECT (object, "finalize"); - - if (base_video_decoder->input_adapter) { - g_object_unref (base_video_decoder->input_adapter); - base_video_decoder->input_adapter = NULL; - } - if (base_video_decoder->output_adapter) { - g_object_unref (base_video_decoder->output_adapter); - base_video_decoder->output_adapter = NULL; - } - - if (base_video_decoder->pool) { - g_object_unref (base_video_decoder->pool); - base_video_decoder->pool = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -/* hard == FLUSH, otherwise discont */ -static GstFlowReturn -gst_base_video_decoder_flush (GstBaseVideoDecoder * dec, gboolean hard) -{ - GstBaseVideoDecoderClass *klass; - GstFlowReturn ret = GST_FLOW_OK; - - klass = GST_BASE_VIDEO_DECODER_GET_CLASS (dec); - - GST_LOG_OBJECT (dec, "flush hard %d", hard); - - /* Inform subclass */ - /* FIXME ? only if hard, or tell it if hard ? */ - if (klass->reset) - klass->reset (dec); - - /* FIXME make some more distinction between hard and soft, - * but subclass may not be prepared for that */ - /* FIXME perhaps also clear pending frames ?, - * but again, subclass may still come up with one of those */ - if (!hard) { - /* TODO ? finish/drain some stuff */ - } else { - gst_segment_init (&GST_BASE_VIDEO_CODEC (dec)->segment, - GST_FORMAT_UNDEFINED); - gst_base_video_decoder_clear_queues (dec); - dec->error_count = 0; - g_list_foreach (dec->current_frame_events, (GFunc) gst_event_unref, NULL); - g_list_free (dec->current_frame_events); - dec->current_frame_events = NULL; - } - /* and get (re)set for the sequel */ - gst_base_video_decoder_reset (dec, FALSE); - - return ret; -} - -static gboolean -gst_base_video_decoder_sink_event (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - GstBaseVideoDecoder *base_video_decoder; - GstBaseVideoDecoderClass *base_video_decoder_class; - gboolean ret = FALSE; - - base_video_decoder = GST_BASE_VIDEO_DECODER (parent); - base_video_decoder_class = - GST_BASE_VIDEO_DECODER_GET_CLASS (base_video_decoder); - - GST_DEBUG_OBJECT (base_video_decoder, - "received event %d, %s", GST_EVENT_TYPE (event), - GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS: - { - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - ret = gst_base_video_decoder_setcaps (base_video_decoder, caps); - gst_event_unref (event); - break; - } - case GST_EVENT_EOS: - { - GstFlowReturn flow_ret; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - if (!base_video_decoder->packetized) { - do { - flow_ret = - base_video_decoder_class->parse_data (base_video_decoder, TRUE); - } while (flow_ret == GST_FLOW_OK); - } - - if (base_video_decoder_class->finish) { - flow_ret = base_video_decoder_class->finish (base_video_decoder); - } else { - flow_ret = GST_FLOW_OK; - } - - if (flow_ret == GST_FLOW_OK) - ret = gst_base_video_decoder_push_src_event (base_video_decoder, event); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - break; - } - case GST_EVENT_SEGMENT: - { - GstSegment seg; - GstSegment *segment = &GST_BASE_VIDEO_CODEC (base_video_decoder)->segment; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - gst_event_copy_segment (event, &seg); - - if (seg.format == GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (base_video_decoder, - "received TIME SEGMENT %" GST_SEGMENT_FORMAT, &seg); - } else { - GstFormat dformat = GST_FORMAT_TIME; - gint64 start; - - GST_DEBUG_OBJECT (base_video_decoder, - "received SEGMENT %" GST_SEGMENT_FORMAT, &seg); - /* handle newsegment as a result from our legacy simple seeking */ - /* note that initial 0 should convert to 0 in any case */ - if (base_video_decoder->do_byte_time && - gst_pad_query_convert (GST_BASE_VIDEO_CODEC_SINK_PAD - (base_video_decoder), GST_FORMAT_BYTES, seg.start, dformat, - &start)) { - /* best attempt convert */ - /* as these are only estimates, stop is kept open-ended to avoid - * premature cutting */ - GST_DEBUG_OBJECT (base_video_decoder, - "converted to TIME start %" GST_TIME_FORMAT, - GST_TIME_ARGS (seg.start)); - seg.start = start; - seg.stop = GST_CLOCK_TIME_NONE; - seg.time = start; - /* replace event */ - gst_event_unref (event); - event = gst_event_new_segment (&seg); - } else { - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - goto newseg_wrong_format; - } - } - - gst_base_video_decoder_flush (base_video_decoder, FALSE); - - base_video_decoder->timestamp_offset = seg.start; - - *segment = seg; - - ret = gst_base_video_decoder_push_src_event (base_video_decoder, event); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - break; - } - case GST_EVENT_FLUSH_STOP: - { - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - /* well, this is kind of worse than a DISCONT */ - gst_base_video_decoder_flush (base_video_decoder, TRUE); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - } - default: - /* FIXME this changes the order of events */ - ret = gst_base_video_decoder_push_src_event (base_video_decoder, event); - break; - } - -done: - return ret; - -newseg_wrong_format: - { - GST_DEBUG_OBJECT (base_video_decoder, "received non TIME newsegment"); - gst_event_unref (event); - goto done; - } -} - -/* perform upstream byte <-> time conversion (duration, seeking) - * if subclass allows and if enough data for moderately decent conversion */ -static inline gboolean -gst_base_video_decoder_do_byte (GstBaseVideoDecoder * dec) -{ - GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (dec); - - return dec->do_byte_time && (codec->bytes > 0) && (codec->time > GST_SECOND); -} - -static gboolean -gst_base_video_decoder_do_seek (GstBaseVideoDecoder * dec, GstEvent * event) -{ - GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (dec); - GstSeekFlags flags; - GstSeekType start_type, end_type; - GstFormat format; - gdouble rate; - gint64 start, start_time, end_time; - GstSegment seek_segment; - guint32 seqnum; - - gst_event_parse_seek (event, &rate, &format, &flags, &start_type, - &start_time, &end_type, &end_time); - - /* we'll handle plain open-ended flushing seeks with the simple approach */ - if (rate != 1.0) { - GST_DEBUG_OBJECT (dec, "unsupported seek: rate"); - return FALSE; - } - - if (start_type != GST_SEEK_TYPE_SET) { - GST_DEBUG_OBJECT (dec, "unsupported seek: start time"); - return FALSE; - } - - if (end_type != GST_SEEK_TYPE_NONE || - (end_type == GST_SEEK_TYPE_SET && end_time != GST_CLOCK_TIME_NONE)) { - GST_DEBUG_OBJECT (dec, "unsupported seek: end time"); - return FALSE; - } - - if (!(flags & GST_SEEK_FLAG_FLUSH)) { - GST_DEBUG_OBJECT (dec, "unsupported seek: not flushing"); - return FALSE; - } - - memcpy (&seek_segment, &codec->segment, sizeof (seek_segment)); - gst_segment_do_seek (&seek_segment, rate, format, flags, start_type, - start_time, end_type, end_time, NULL); - start_time = seek_segment.position; - - if (!gst_pad_query_convert (codec->sinkpad, GST_FORMAT_TIME, start_time, - GST_FORMAT_BYTES, &start)) { - GST_DEBUG_OBJECT (dec, "conversion failed"); - return FALSE; - } - - seqnum = gst_event_get_seqnum (event); - event = gst_event_new_seek (1.0, GST_FORMAT_BYTES, flags, - GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_NONE, -1); - gst_event_set_seqnum (event, seqnum); - - GST_DEBUG_OBJECT (dec, "seeking to %" GST_TIME_FORMAT " at byte offset %" - G_GINT64_FORMAT, GST_TIME_ARGS (start_time), start); - - return gst_pad_push_event (codec->sinkpad, event); -} - -static gboolean -gst_base_video_decoder_src_event (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - GstBaseVideoDecoder *base_video_decoder; - gboolean res = FALSE; - - base_video_decoder = GST_BASE_VIDEO_DECODER (parent); - - GST_DEBUG_OBJECT (base_video_decoder, - "received event %d, %s", GST_EVENT_TYPE (event), - GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - { - GstFormat format, tformat; - gdouble rate; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gint64 tcur, tstop; - guint32 seqnum; - - gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, - &stop_type, &stop); - seqnum = gst_event_get_seqnum (event); - - /* upstream gets a chance first */ - if ((res = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD - (base_video_decoder), event))) - break; - - /* if upstream fails for a time seek, maybe we can help if allowed */ - if (format == GST_FORMAT_TIME) { - if (gst_base_video_decoder_do_byte (base_video_decoder)) - res = gst_base_video_decoder_do_seek (base_video_decoder, event); - break; - } - - /* ... though a non-time seek can be aided as well */ - /* First bring the requested format to time */ - tformat = GST_FORMAT_TIME; - if (!(res = gst_pad_query_convert (pad, format, cur, tformat, &tcur))) - goto convert_error; - if (!(res = gst_pad_query_convert (pad, format, stop, tformat, &tstop))) - goto convert_error; - - /* then seek with time on the peer */ - event = gst_event_new_seek (rate, GST_FORMAT_TIME, - flags, cur_type, tcur, stop_type, tstop); - gst_event_set_seqnum (event, seqnum); - - res = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD - (base_video_decoder), event); - break; - } - case GST_EVENT_QOS: - { - GstQOSType type; - gdouble proportion; - GstClockTimeDiff diff; - GstClockTime timestamp; - GstClockTime duration; - - gst_event_parse_qos (event, &type, &proportion, &diff, ×tamp); - - GST_OBJECT_LOCK (base_video_decoder); - GST_BASE_VIDEO_CODEC (base_video_decoder)->proportion = proportion; - if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (timestamp))) { - if (G_UNLIKELY (diff > 0)) { - if (GST_BASE_VIDEO_CODEC (base_video_decoder)->state.fps_n > 0) - duration = - gst_util_uint64_scale (GST_SECOND, - GST_BASE_VIDEO_CODEC (base_video_decoder)->state.fps_d, - GST_BASE_VIDEO_CODEC (base_video_decoder)->state.fps_n); - else - duration = 0; - GST_BASE_VIDEO_CODEC (base_video_decoder)->earliest_time = - timestamp + 2 * diff + duration; - } else { - GST_BASE_VIDEO_CODEC (base_video_decoder)->earliest_time = - timestamp + diff; - } - } else { - GST_BASE_VIDEO_CODEC (base_video_decoder)->earliest_time = - GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (base_video_decoder); - - GST_DEBUG_OBJECT (base_video_decoder, - "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT ", %g", - GST_TIME_ARGS (timestamp), diff, proportion); - - res = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD - (base_video_decoder), event); - break; - } - default: - res = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD - (base_video_decoder), event); - break; - } -done: - return res; - -convert_error: - GST_DEBUG_OBJECT (base_video_decoder, "could not convert format"); - goto done; -} - -static gboolean -gst_base_video_decoder_src_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - GstBaseVideoDecoder *dec; - gboolean res = TRUE; - - dec = GST_BASE_VIDEO_DECODER (parent); - - GST_LOG_OBJECT (dec, "handling query: %" GST_PTR_FORMAT, query); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - GstFormat format; - gint64 time, value; - - /* upstream gets a chance first */ - if ((res = - gst_pad_peer_query (GST_BASE_VIDEO_CODEC_SINK_PAD (dec), - query))) { - GST_LOG_OBJECT (dec, "returning peer response"); - break; - } - - /* we start from the last seen time */ - time = dec->last_timestamp; - /* correct for the segment values */ - time = gst_segment_to_stream_time (&GST_BASE_VIDEO_CODEC (dec)->segment, - GST_FORMAT_TIME, time); - - GST_LOG_OBJECT (dec, - "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time)); - - /* and convert to the final format */ - gst_query_parse_position (query, &format, NULL); - if (!(res = gst_pad_query_convert (pad, GST_FORMAT_TIME, time, - format, &value))) - break; - - gst_query_set_position (query, format, value); - - GST_LOG_OBJECT (dec, - "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value, - format); - break; - } - case GST_QUERY_DURATION: - { - GstFormat format; - - /* upstream in any case */ - if ((res = gst_pad_query_default (pad, parent, query))) - break; - - gst_query_parse_duration (query, &format, NULL); - /* try answering TIME by converting from BYTE if subclass allows */ - if (format == GST_FORMAT_TIME && gst_base_video_decoder_do_byte (dec)) { - gint64 value; - - format = GST_FORMAT_BYTES; - if (gst_pad_peer_query_duration (GST_BASE_VIDEO_CODEC_SINK_PAD (dec), - format, &value)) { - GST_LOG_OBJECT (dec, "upstream size %" G_GINT64_FORMAT, value); - format = GST_FORMAT_TIME; - if (gst_pad_query_convert (GST_BASE_VIDEO_CODEC_SINK_PAD (dec), - GST_FORMAT_BYTES, value, format, &value)) { - gst_query_set_duration (query, GST_FORMAT_TIME, value); - res = TRUE; - } - } - } - break; - } - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - GST_DEBUG_OBJECT (dec, "convert query"); - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - res = gst_base_video_rawvideo_convert (&GST_BASE_VIDEO_CODEC (dec)->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; - } - default: - res = gst_pad_query_default (pad, parent, query); - } - return res; - - /* ERRORS */ -error: - { - GST_ERROR_OBJECT (dec, "query failed"); - return res; - } -} - -static gboolean -gst_base_video_decoder_sink_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - GstBaseVideoDecoder *base_video_decoder; - gboolean res = FALSE; - - base_video_decoder = GST_BASE_VIDEO_DECODER (parent); - - GST_LOG_OBJECT (base_video_decoder, "handling query: %" GST_PTR_FORMAT, - query); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONVERT: - { - GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (base_video_decoder); - 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 (&codec->state, codec->bytes, - codec->time, 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; - } - default: - res = gst_pad_query_default (pad, parent, query); - break; - } -done: - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (base_video_decoder, "query failed"); - goto done; - } -} - -typedef struct _Timestamp Timestamp; -struct _Timestamp -{ - guint64 offset; - GstClockTime timestamp; - GstClockTime duration; -}; - -static void -gst_base_video_decoder_add_timestamp (GstBaseVideoDecoder * base_video_decoder, - GstBuffer * buffer) -{ - Timestamp *ts; - - ts = g_malloc (sizeof (Timestamp)); - - GST_LOG_OBJECT (base_video_decoder, - "adding timestamp %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, - GST_TIME_ARGS (base_video_decoder->input_offset), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - - ts->offset = base_video_decoder->input_offset; - ts->timestamp = GST_BUFFER_TIMESTAMP (buffer); - ts->duration = GST_BUFFER_DURATION (buffer); - - base_video_decoder->timestamps = - g_list_append (base_video_decoder->timestamps, ts); -} - -static void -gst_base_video_decoder_get_timestamp_at_offset (GstBaseVideoDecoder * - base_video_decoder, guint64 offset, GstClockTime * timestamp, - GstClockTime * duration) -{ - Timestamp *ts; - GList *g; - - *timestamp = GST_CLOCK_TIME_NONE; - *duration = GST_CLOCK_TIME_NONE; - - g = base_video_decoder->timestamps; - while (g) { - ts = g->data; - if (ts->offset <= offset) { - *timestamp = ts->timestamp; - *duration = ts->duration; - g_free (ts); - g = g_list_next (g); - base_video_decoder->timestamps = - g_list_remove (base_video_decoder->timestamps, ts); - } else { - break; - } - } - - GST_LOG_OBJECT (base_video_decoder, - "got timestamp %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, - GST_TIME_ARGS (offset), GST_TIME_ARGS (*timestamp)); -} - -static void -gst_base_video_decoder_clear_queues (GstBaseVideoDecoder * dec) -{ - g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->queued); - dec->queued = NULL; - g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->gather); - dec->gather = NULL; - g_list_foreach (dec->decode, (GFunc) gst_video_frame_state_unref, NULL); - g_list_free (dec->decode); - dec->decode = NULL; - g_list_foreach (dec->parse, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->parse); - dec->parse = NULL; - g_list_foreach (dec->parse_gather, (GFunc) gst_video_frame_state_unref, NULL); - g_list_free (dec->parse_gather); - dec->parse_gather = NULL; - g_list_foreach (GST_BASE_VIDEO_CODEC (dec)->frames, - (GFunc) gst_video_frame_state_unref, NULL); - g_list_free (GST_BASE_VIDEO_CODEC (dec)->frames); - GST_BASE_VIDEO_CODEC (dec)->frames = NULL; -} - -static void -gst_base_video_decoder_reset (GstBaseVideoDecoder * base_video_decoder, - gboolean full) -{ - GST_DEBUG_OBJECT (base_video_decoder, "reset full %d", full); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - if (full) { - gst_segment_init (&GST_BASE_VIDEO_CODEC (base_video_decoder)->segment, - GST_FORMAT_UNDEFINED); - gst_base_video_decoder_clear_queues (base_video_decoder); - base_video_decoder->error_count = 0; - } - - GST_BASE_VIDEO_CODEC (base_video_decoder)->discont = TRUE; - base_video_decoder->have_sync = FALSE; - - base_video_decoder->timestamp_offset = GST_CLOCK_TIME_NONE; - base_video_decoder->field_index = 0; - base_video_decoder->last_timestamp = GST_CLOCK_TIME_NONE; - - base_video_decoder->input_offset = 0; - base_video_decoder->frame_offset = 0; - gst_adapter_clear (base_video_decoder->input_adapter); - gst_adapter_clear (base_video_decoder->output_adapter); - g_list_foreach (base_video_decoder->timestamps, (GFunc) g_free, NULL); - g_list_free (base_video_decoder->timestamps); - base_video_decoder->timestamps = NULL; - - if (base_video_decoder->current_frame) { - gst_video_frame_state_unref (base_video_decoder->current_frame); - base_video_decoder->current_frame = NULL; - } - - base_video_decoder->dropped = 0; - base_video_decoder->processed = 0; - - GST_BASE_VIDEO_CODEC (base_video_decoder)->system_frame_number = 0; - base_video_decoder->base_picture_number = 0; - - GST_OBJECT_LOCK (base_video_decoder); - GST_BASE_VIDEO_CODEC (base_video_decoder)->earliest_time = - GST_CLOCK_TIME_NONE; - GST_BASE_VIDEO_CODEC (base_video_decoder)->proportion = 0.5; - GST_OBJECT_UNLOCK (base_video_decoder); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); -} - -static GstFlowReturn -gst_base_video_decoder_chain_forward (GstBaseVideoDecoder * base_video_decoder, - GstBuffer * buf) -{ - GstBaseVideoDecoderClass *klass; - GstFlowReturn ret; - - klass = GST_BASE_VIDEO_DECODER_GET_CLASS (base_video_decoder); - - g_return_val_if_fail (base_video_decoder->packetized || klass->parse_data, - GST_FLOW_ERROR); - - if (base_video_decoder->current_frame == NULL) { - base_video_decoder->current_frame = - gst_base_video_decoder_new_frame (base_video_decoder); - } - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - gst_base_video_decoder_add_timestamp (base_video_decoder, buf); - } - base_video_decoder->input_offset += gst_buffer_get_size (buf); - - if (base_video_decoder->packetized) { - base_video_decoder->current_frame->sink_buffer = buf; - - if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) - base_video_decoder->current_frame->is_sync_point = TRUE; - - ret = gst_base_video_decoder_have_frame_2 (base_video_decoder); - } else { - - gst_adapter_push (base_video_decoder->input_adapter, buf); - - if (!base_video_decoder->have_sync) { - int n, m; - - GST_DEBUG_OBJECT (base_video_decoder, "no sync, scanning"); - - n = gst_adapter_available (base_video_decoder->input_adapter); - if (klass->capture_mask != 0) { - m = gst_adapter_masked_scan_uint32 (base_video_decoder->input_adapter, - klass->capture_mask, klass->capture_pattern, 0, n - 3); - } else if (klass->scan_for_sync) { - m = klass->scan_for_sync (base_video_decoder, FALSE, 0, n); - } else { - m = 0; - } - if (m == -1) { - GST_ERROR_OBJECT (base_video_decoder, "scan returned no sync"); - gst_adapter_flush (base_video_decoder->input_adapter, n - 3); - - return GST_FLOW_OK; - } else { - if (m > 0) { - if (m >= n) { - GST_ERROR_OBJECT (base_video_decoder, - "subclass scanned past end %d >= %d", m, n); - } - - gst_adapter_flush (base_video_decoder->input_adapter, m); - - if (m < n) { - GST_DEBUG_OBJECT (base_video_decoder, - "found possible sync after %d bytes (of %d)", m, n); - - /* this is only "maybe" sync */ - base_video_decoder->have_sync = TRUE; - } - } - - } - } - - do { - GST_LOG_OBJECT (base_video_decoder, "Calling ::parse_data()"); - ret = klass->parse_data (base_video_decoder, FALSE); - } while (ret == GST_FLOW_OK); - - if (ret == GST_BASE_VIDEO_DECODER_FLOW_NEED_DATA) { - return GST_FLOW_OK; - } - } - - return ret; -} - -static GstFlowReturn -gst_base_video_decoder_flush_decode (GstBaseVideoDecoder * dec) -{ - GstFlowReturn res = GST_FLOW_OK; - GList *walk; - - walk = dec->decode; - - GST_DEBUG_OBJECT (dec, "flushing buffers to decode"); - - /* clear buffer and decoder state */ - gst_base_video_decoder_flush (dec, FALSE); - - /* signal have_frame it should not capture frames */ - dec->process = TRUE; - - while (walk) { - GList *next; - GstVideoFrameState *frame = (GstVideoFrameState *) (walk->data); - GstBuffer *buf = frame->sink_buffer; - - GST_DEBUG_OBJECT (dec, "decoding frame %p, ts %" GST_TIME_FORMAT, - buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - - next = g_list_next (walk); - if (dec->current_frame) - gst_video_frame_state_unref (dec->current_frame); - dec->current_frame = frame; - gst_video_frame_state_ref (dec->current_frame); - - /* decode buffer, resulting data prepended to queue */ - res = gst_base_video_decoder_have_frame_2 (dec); - - walk = next; - } - - dec->process = FALSE; - - return res; -} - -static GstFlowReturn -gst_base_video_decoder_flush_parse (GstBaseVideoDecoder * dec) -{ - GstFlowReturn res = GST_FLOW_OK; - GList *walk; - - walk = dec->parse; - - GST_DEBUG_OBJECT (dec, "flushing buffers to parsing"); - - /* clear buffer and decoder state */ - gst_base_video_decoder_flush (dec, FALSE); - - while (walk) { - GList *next; - GstBuffer *buf = GST_BUFFER_CAST (walk->data); - - GST_DEBUG_OBJECT (dec, "parsing buffer %p, ts %" GST_TIME_FORMAT, - buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - - next = g_list_next (walk); - /* parse buffer, resulting frames prepended to parse_gather queue */ - gst_buffer_ref (buf); - res = gst_base_video_decoder_chain_forward (dec, buf); - - /* if we generated output, we can discard the buffer, else we - * keep it in the queue */ - if (dec->parse_gather) { - GST_DEBUG_OBJECT (dec, "parsed buffer to %p", dec->parse_gather->data); - dec->parse = g_list_delete_link (dec->parse, walk); - gst_buffer_unref (buf); - } else { - GST_DEBUG_OBJECT (dec, "buffer did not decode, keeping"); - } - walk = next; - } - - /* now we can process frames */ - GST_DEBUG_OBJECT (dec, "checking frames"); - while (dec->parse_gather) { - GstVideoFrameState *frame; - - frame = (GstVideoFrameState *) (dec->parse_gather->data); - /* remove from the gather list */ - dec->parse_gather = - g_list_delete_link (dec->parse_gather, dec->parse_gather); - /* copy to decode queue */ - dec->decode = g_list_prepend (dec->decode, frame); - - /* if we copied a keyframe, flush and decode the decode queue */ - if (frame->is_sync_point) { - GST_DEBUG_OBJECT (dec, "copied keyframe"); - res = gst_base_video_decoder_flush_decode (dec); - } - } - - /* now send queued data downstream */ - while (dec->queued) { - GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data); - - if (G_LIKELY (res == GST_FLOW_OK)) { - GST_DEBUG_OBJECT (dec, "pushing buffer %p of size %" G_GSIZE_FORMAT ", " - "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf, - gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - /* should be already, but let's be sure */ - buf = gst_buffer_make_writable (buf); - /* avoid stray DISCONT from forward processing, - * which have no meaning in reverse pushing */ - GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); - res = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (dec), buf); - } else { - gst_buffer_unref (buf); - } - - dec->queued = g_list_delete_link (dec->queued, dec->queued); - } - - return res; -} - -static GstFlowReturn -gst_base_video_decoder_chain_reverse (GstBaseVideoDecoder * dec, - GstBuffer * buf) -{ - GstFlowReturn result = GST_FLOW_OK; - - /* if we have a discont, move buffers to the decode list */ - if (!buf || GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { - GST_DEBUG_OBJECT (dec, "received discont"); - while (dec->gather) { - GstBuffer *gbuf; - - gbuf = GST_BUFFER_CAST (dec->gather->data); - /* remove from the gather list */ - dec->gather = g_list_delete_link (dec->gather, dec->gather); - /* copy to parse queue */ - dec->parse = g_list_prepend (dec->parse, gbuf); - } - /* parse and decode stuff in the parse queue */ - gst_base_video_decoder_flush_parse (dec); - } - - if (G_LIKELY (buf)) { - GST_DEBUG_OBJECT (dec, "gathering buffer %p of size %" G_GSIZE_FORMAT ", " - "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf, - gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - /* add buffer to gather queue */ - dec->gather = g_list_prepend (dec->gather, buf); - } - - return result; -} - -static GstFlowReturn -gst_base_video_decoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) -{ - GstBaseVideoDecoder *base_video_decoder; - GstFlowReturn ret = GST_FLOW_OK; - - base_video_decoder = GST_BASE_VIDEO_DECODER (parent); - - GST_LOG_OBJECT (base_video_decoder, - "chain %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT " size %" - G_GSIZE_FORMAT "", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), gst_buffer_get_size (buf)); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - /* NOTE: - * requiring the pad to be negotiated makes it impossible to use - * oggdemux or filesrc ! decoder */ - - if (GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.format == - GST_FORMAT_UNDEFINED) { - GstEvent *event; - GstFlowReturn ret; - GstSegment *segment = &GST_BASE_VIDEO_CODEC (base_video_decoder)->segment; - - GST_WARNING_OBJECT (base_video_decoder, - "Received buffer without a new-segment. " - "Assuming timestamps start from 0."); - - gst_segment_init (segment, GST_FORMAT_TIME); - - event = gst_event_new_segment (segment); - - ret = gst_base_video_decoder_push_src_event (base_video_decoder, event); - if (!ret) { - GST_ERROR_OBJECT (base_video_decoder, "new segment event ret=%d", ret); - ret = GST_FLOW_ERROR; - goto done; - } - } - - if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) { - gint64 ts, index; - - GST_DEBUG_OBJECT (base_video_decoder, "received DISCONT buffer"); - - /* track present position */ - ts = base_video_decoder->timestamp_offset; - index = base_video_decoder->field_index; - - gst_base_video_decoder_flush (base_video_decoder, FALSE); - - /* buffer may claim DISCONT loudly, if it can't tell us where we are now, - * we'll stick to where we were ... - * Particularly useful/needed for upstream BYTE based */ - if (GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.rate > 0.0 && - !GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - GST_DEBUG_OBJECT (base_video_decoder, - "... but restoring previous ts tracking"); - base_video_decoder->timestamp_offset = ts; - base_video_decoder->field_index = index & ~1; - } - } - - if (GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.rate > 0.0) - ret = gst_base_video_decoder_chain_forward (base_video_decoder, buf); - else - ret = gst_base_video_decoder_chain_reverse (base_video_decoder, buf); - -done: - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - return ret; -} - -static GstStateChangeReturn -gst_base_video_decoder_change_state (GstElement * element, - GstStateChange transition) -{ - GstBaseVideoDecoder *base_video_decoder; - GstBaseVideoDecoderClass *base_video_decoder_class; - GstStateChangeReturn ret; - - base_video_decoder = GST_BASE_VIDEO_DECODER (element); - base_video_decoder_class = GST_BASE_VIDEO_DECODER_GET_CLASS (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - if (base_video_decoder_class->start) { - base_video_decoder_class->start (base_video_decoder); - } - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - if (base_video_decoder_class->stop) { - base_video_decoder_class->stop (base_video_decoder); - } - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - gst_base_video_decoder_reset (base_video_decoder, TRUE); - g_list_foreach (base_video_decoder->current_frame_events, - (GFunc) gst_event_unref, NULL); - g_list_free (base_video_decoder->current_frame_events); - base_video_decoder->current_frame_events = NULL; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - break; - default: - break; - } - - return ret; -} - -static GstVideoFrameState * -gst_base_video_decoder_new_frame (GstBaseVideoDecoder * base_video_decoder) -{ - GstVideoFrameState *frame; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - frame = - gst_base_video_codec_new_frame (GST_BASE_VIDEO_CODEC - (base_video_decoder)); - - frame->decode_frame_number = frame->system_frame_number - - base_video_decoder->reorder_depth; - - frame->decode_timestamp = GST_CLOCK_TIME_NONE; - frame->presentation_timestamp = GST_CLOCK_TIME_NONE; - frame->presentation_duration = GST_CLOCK_TIME_NONE; - frame->n_fields = 2; - - frame->events = base_video_decoder->current_frame_events; - base_video_decoder->current_frame_events = NULL; - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return frame; -} - -static void -gst_base_video_decoder_prepare_finish_frame (GstBaseVideoDecoder * - base_video_decoder, GstVideoFrameState * frame) -{ - GList *l, *events = NULL; - -#ifndef GST_DISABLE_GST_DEBUG - GST_LOG_OBJECT (base_video_decoder, - "n %d in %" G_GSIZE_FORMAT " out %" G_GSIZE_FORMAT, - g_list_length (GST_BASE_VIDEO_CODEC (base_video_decoder)->frames), - gst_adapter_available (base_video_decoder->input_adapter), - gst_adapter_available (base_video_decoder->output_adapter)); -#endif - - GST_LOG_OBJECT (base_video_decoder, - "finish frame sync=%d pts=%" GST_TIME_FORMAT, frame->is_sync_point, - GST_TIME_ARGS (frame->presentation_timestamp)); - - /* Push all pending events that arrived before this frame */ - for (l = base_video_decoder->base_video_codec.frames; l; l = l->next) { - GstVideoFrameState *tmp = l->data; - - if (tmp->events) { - events = tmp->events; - tmp->events = NULL; - } - - if (tmp == frame) - break; - } - - for (l = g_list_last (events); l; l = l->prev) { - GST_LOG_OBJECT (base_video_decoder, "pushing %s event", - GST_EVENT_TYPE_NAME (l->data)); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_decoder), - l->data); - } - g_list_free (events); - - /* Check if the data should not be displayed. For example altref/invisible - * frame in vp8. In this case we should not update the timestamps. */ - if (frame->decode_only) - return; - - if (GST_CLOCK_TIME_IS_VALID (frame->presentation_timestamp)) { - if (frame->presentation_timestamp != base_video_decoder->timestamp_offset) { - GST_DEBUG_OBJECT (base_video_decoder, - "sync timestamp %" GST_TIME_FORMAT " diff %" GST_TIME_FORMAT, - GST_TIME_ARGS (frame->presentation_timestamp), - GST_TIME_ARGS (frame->presentation_timestamp - - GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.start)); - base_video_decoder->timestamp_offset = frame->presentation_timestamp; - base_video_decoder->field_index &= 1; - } else { - /* This case is for one initial timestamp and no others, e.g., - * filesrc ! decoder ! xvimagesink */ - GST_WARNING_OBJECT (base_video_decoder, - "sync timestamp didn't change, ignoring"); - frame->presentation_timestamp = GST_CLOCK_TIME_NONE; - } - } else { - if (frame->is_sync_point) { - GST_WARNING_OBJECT (base_video_decoder, - "sync point doesn't have timestamp"); - if (!GST_CLOCK_TIME_IS_VALID (base_video_decoder->timestamp_offset)) { - GST_WARNING_OBJECT (base_video_decoder, - "No base timestamp. Assuming frames start at segment start"); - base_video_decoder->timestamp_offset = - GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.start; - base_video_decoder->field_index &= 1; - } - } - } - frame->field_index = base_video_decoder->field_index; - base_video_decoder->field_index += frame->n_fields; - - if (frame->presentation_timestamp == GST_CLOCK_TIME_NONE) { - frame->presentation_timestamp = - gst_base_video_decoder_get_field_timestamp (base_video_decoder, - frame->field_index); - frame->presentation_duration = GST_CLOCK_TIME_NONE; - frame->decode_timestamp = - gst_base_video_decoder_get_timestamp (base_video_decoder, - frame->decode_frame_number); - } - if (frame->presentation_duration == GST_CLOCK_TIME_NONE) { - frame->presentation_duration = - gst_base_video_decoder_get_field_duration (base_video_decoder, - frame->n_fields); - } - - if (GST_CLOCK_TIME_IS_VALID (base_video_decoder->last_timestamp)) { - if (frame->presentation_timestamp < base_video_decoder->last_timestamp) { - GST_WARNING_OBJECT (base_video_decoder, - "decreasing timestamp (%" GST_TIME_FORMAT " < %" - GST_TIME_FORMAT ")", GST_TIME_ARGS (frame->presentation_timestamp), - GST_TIME_ARGS (base_video_decoder->last_timestamp)); - } - } - base_video_decoder->last_timestamp = frame->presentation_timestamp; -} - -static void -gst_base_video_decoder_do_finish_frame (GstBaseVideoDecoder * dec, - GstVideoFrameState * frame) -{ - gst_base_video_codec_remove_frame (GST_BASE_VIDEO_CODEC (dec), frame); - - if (frame->src_buffer) - gst_buffer_unref (frame->src_buffer); - - gst_video_frame_state_unref (frame); -} - -/** - * gst_base_video_decoder_drop_frame: - * @dec: a #GstBaseVideoDecoder - * @frame: the #GstVideoFrame to drop - * - * Similar to gst_base_video_decoder_finish_frame(), but drops @frame in any - * case and posts a QoS message with the frame's details on the bus. - * In any case, the frame is considered finished and released. - * - * Returns: a #GstFlowReturn, usually GST_FLOW_OK. - * - * Since: 0.10.23 - */ -GstFlowReturn -gst_base_video_decoder_drop_frame (GstBaseVideoDecoder * dec, - GstVideoFrameState * frame) -{ - GstClockTime stream_time, jitter, earliest_time, qostime, timestamp; - GstSegment *segment; - GstMessage *qos_msg; - gdouble proportion; - - GST_LOG_OBJECT (dec, "drop frame"); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (dec); - - gst_base_video_decoder_prepare_finish_frame (dec, frame); - - GST_DEBUG_OBJECT (dec, "dropping frame %" GST_TIME_FORMAT, - GST_TIME_ARGS (frame->presentation_timestamp)); - - dec->dropped++; - - /* post QoS message */ - timestamp = frame->presentation_timestamp; - proportion = GST_BASE_VIDEO_CODEC (dec)->proportion; - segment = &GST_BASE_VIDEO_CODEC (dec)->segment; - stream_time = - gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); - qostime = gst_segment_to_running_time (segment, GST_FORMAT_TIME, timestamp); - earliest_time = GST_BASE_VIDEO_CODEC (dec)->earliest_time; - jitter = GST_CLOCK_DIFF (qostime, earliest_time); - qos_msg = gst_message_new_qos (GST_OBJECT_CAST (dec), FALSE, - qostime, stream_time, timestamp, GST_CLOCK_TIME_NONE); - gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000); - gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS, - dec->processed, dec->dropped); - gst_element_post_message (GST_ELEMENT_CAST (dec), qos_msg); - - /* now free the frame */ - gst_base_video_decoder_do_finish_frame (dec, frame); - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (dec); - - return GST_FLOW_OK; -} - -/** - * gst_base_video_decoder_finish_frame: - * @base_video_decoder: a #GstBaseVideoDecoder - * @frame: a decoded #GstVideoFrameState - * - * @frame should have a valid decoded data buffer, whose metadata fields - * are then appropriately set according to frame data and pushed downstream. - * If no output data is provided, @frame is considered skipped. - * In any case, the frame is considered finished and released. - * - * Returns: a #GstFlowReturn resulting from sending data downstream - */ -GstFlowReturn -gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder, - GstVideoFrameState * frame) -{ - GstVideoState *state = &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; - GstBuffer *src_buffer; - GstFlowReturn ret = GST_FLOW_OK; - - GST_LOG_OBJECT (base_video_decoder, "finish frame"); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - gst_base_video_decoder_prepare_finish_frame (base_video_decoder, frame); - - base_video_decoder->processed++; - - /* no buffer data means this frame is skipped */ - if (!frame->src_buffer || frame->decode_only) { - GST_DEBUG_OBJECT (base_video_decoder, "skipping frame %" GST_TIME_FORMAT, - GST_TIME_ARGS (frame->presentation_timestamp)); - goto done; - } - - src_buffer = gst_buffer_make_writable (frame->src_buffer); - frame->src_buffer = NULL; - - GST_BUFFER_FLAG_UNSET (src_buffer, GST_BUFFER_FLAG_DELTA_UNIT); - if (state->interlaced) { - int tff = state->top_field_first; - - if (frame->field_index & 1) { - tff ^= 1; - } - if (tff) { - GST_BUFFER_FLAG_SET (src_buffer, GST_VIDEO_BUFFER_FLAG_TFF); - } else { - GST_BUFFER_FLAG_UNSET (src_buffer, GST_VIDEO_BUFFER_FLAG_TFF); - } - GST_BUFFER_FLAG_UNSET (src_buffer, GST_VIDEO_BUFFER_FLAG_RFF); - GST_BUFFER_FLAG_UNSET (src_buffer, GST_VIDEO_BUFFER_FLAG_ONEFIELD); - if (frame->n_fields == 3) { - GST_BUFFER_FLAG_SET (src_buffer, GST_VIDEO_BUFFER_FLAG_RFF); - } else if (frame->n_fields == 1) { - GST_BUFFER_FLAG_SET (src_buffer, GST_VIDEO_BUFFER_FLAG_ONEFIELD); - } - } - if (GST_BASE_VIDEO_CODEC (base_video_decoder)->discont) { - GST_BUFFER_FLAG_SET (src_buffer, GST_BUFFER_FLAG_DISCONT); - GST_BASE_VIDEO_CODEC (base_video_decoder)->discont = FALSE; - } - - GST_BUFFER_TIMESTAMP (src_buffer) = frame->presentation_timestamp; - GST_BUFFER_DURATION (src_buffer) = frame->presentation_duration; - GST_BUFFER_OFFSET (src_buffer) = GST_BUFFER_OFFSET_NONE; - GST_BUFFER_OFFSET_END (src_buffer) = GST_BUFFER_OFFSET_NONE; - - /* update rate estimate */ - GST_BASE_VIDEO_CODEC (base_video_decoder)->bytes += - gst_buffer_get_size (src_buffer); - if (GST_CLOCK_TIME_IS_VALID (frame->presentation_duration)) { - GST_BASE_VIDEO_CODEC (base_video_decoder)->time += - frame->presentation_duration; - } else { - /* better none than nothing valid */ - GST_BASE_VIDEO_CODEC (base_video_decoder)->time = GST_CLOCK_TIME_NONE; - } - - GST_LOG_OBJECT (base_video_decoder, "pushing frame ts %" GST_TIME_FORMAT - ", duration %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (src_buffer)), - GST_TIME_ARGS (GST_BUFFER_DURATION (src_buffer))); - - if (base_video_decoder->sink_clipping) { - guint64 start = GST_BUFFER_TIMESTAMP (src_buffer); - guint64 stop = GST_BUFFER_TIMESTAMP (src_buffer) + - GST_BUFFER_DURATION (src_buffer); - GstSegment *segment = &GST_BASE_VIDEO_CODEC (base_video_decoder)->segment; - - if (gst_segment_clip (segment, GST_FORMAT_TIME, start, stop, &start, &stop)) { - GST_BUFFER_TIMESTAMP (src_buffer) = start; - GST_BUFFER_DURATION (src_buffer) = stop - start; - GST_LOG_OBJECT (base_video_decoder, - "accepting buffer inside segment: %" GST_TIME_FORMAT - " %" GST_TIME_FORMAT - " seg %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT - " time %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (src_buffer)), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (src_buffer) + - GST_BUFFER_DURATION (src_buffer)), - GST_TIME_ARGS (segment->start), - GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time)); - } else { - GST_LOG_OBJECT (base_video_decoder, - "dropping buffer outside segment: %" GST_TIME_FORMAT - " %" GST_TIME_FORMAT - " seg %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT - " time %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (src_buffer)), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (src_buffer) + - GST_BUFFER_DURATION (src_buffer)), - GST_TIME_ARGS (segment->start), - GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time)); - gst_buffer_unref (src_buffer); - ret = GST_FLOW_OK; - goto done; - } - } - - /* we got data, so note things are looking up again */ - if (G_UNLIKELY (base_video_decoder->error_count)) - base_video_decoder->error_count--; - - if (GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.rate < 0.0) { - GST_LOG_OBJECT (base_video_decoder, "queued buffer"); - base_video_decoder->queued = - g_list_prepend (base_video_decoder->queued, src_buffer); - } else { - ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_decoder), - src_buffer); - } - -done: - - gst_base_video_decoder_do_finish_frame (base_video_decoder, frame); - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return ret; -} - -/** - * gst_base_video_decoder_add_to_frame: - * @base_video_decoder: a #GstBaseVideoDecoder - * @n_bytes: an encoded #GstVideoFrameState - * - * Removes next @n_bytes of input data and adds it to currently parsed frame. - */ -void -gst_base_video_decoder_add_to_frame (GstBaseVideoDecoder * base_video_decoder, - int n_bytes) -{ - GstBuffer *buf; - - GST_LOG_OBJECT (base_video_decoder, "add %d bytes to frame", n_bytes); - - if (n_bytes == 0) - return; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - if (gst_adapter_available (base_video_decoder->output_adapter) == 0) { - base_video_decoder->frame_offset = base_video_decoder->input_offset - - gst_adapter_available (base_video_decoder->input_adapter); - } - buf = gst_adapter_take_buffer (base_video_decoder->input_adapter, n_bytes); - - gst_adapter_push (base_video_decoder->output_adapter, buf); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); -} - -static guint64 -gst_base_video_decoder_get_timestamp (GstBaseVideoDecoder * base_video_decoder, - int picture_number) -{ - GstVideoState *state = &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; - - if (state->fps_d == 0 || state->fps_n == 0) { - return -1; - } - if (picture_number < base_video_decoder->base_picture_number) { - return base_video_decoder->timestamp_offset - - (gint64) gst_util_uint64_scale (base_video_decoder->base_picture_number - - picture_number, state->fps_d * GST_SECOND, state->fps_n); - } else { - return base_video_decoder->timestamp_offset + - gst_util_uint64_scale (picture_number - - base_video_decoder->base_picture_number, - state->fps_d * GST_SECOND, state->fps_n); - } -} - -static guint64 -gst_base_video_decoder_get_field_timestamp (GstBaseVideoDecoder * - base_video_decoder, int field_offset) -{ - GstVideoState *state = &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; - - if (state->fps_d == 0 || state->fps_n == 0) { - return GST_CLOCK_TIME_NONE; - } - if (field_offset < 0) { - GST_WARNING_OBJECT (base_video_decoder, "field offset < 0"); - return GST_CLOCK_TIME_NONE; - } - return base_video_decoder->timestamp_offset + - gst_util_uint64_scale (field_offset, state->fps_d * GST_SECOND, - state->fps_n * 2); -} - -static guint64 -gst_base_video_decoder_get_field_duration (GstBaseVideoDecoder * - base_video_decoder, int n_fields) -{ - GstVideoState *state = &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; - - if (state->fps_d == 0 || state->fps_n == 0) { - return GST_CLOCK_TIME_NONE; - } - if (n_fields < 0) { - GST_WARNING_OBJECT (base_video_decoder, "n_fields < 0"); - return GST_CLOCK_TIME_NONE; - } - return gst_util_uint64_scale (n_fields, state->fps_d * GST_SECOND, - state->fps_n * 2); -} - -/** - * gst_base_video_decoder_have_frame: - * @base_video_decoder: a #GstBaseVideoDecoder - * - * Gathers all data collected for currently parsed frame, gathers corresponding - * metadata and passes it along for further processing, i.e. @handle_frame. - * - * Returns: a #GstFlowReturn - */ -GstFlowReturn -gst_base_video_decoder_have_frame (GstBaseVideoDecoder * base_video_decoder) -{ - GstBuffer *buffer; - int n_available; - GstClockTime timestamp; - GstClockTime duration; - GstFlowReturn ret = GST_FLOW_OK; - - GST_LOG_OBJECT (base_video_decoder, "have_frame"); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - n_available = gst_adapter_available (base_video_decoder->output_adapter); - if (n_available) { - buffer = gst_adapter_take_buffer (base_video_decoder->output_adapter, - n_available); - } else { - buffer = gst_buffer_new_and_alloc (0); - } - - base_video_decoder->current_frame->sink_buffer = buffer; - - gst_base_video_decoder_get_timestamp_at_offset (base_video_decoder, - base_video_decoder->frame_offset, ×tamp, &duration); - - GST_BUFFER_TIMESTAMP (buffer) = timestamp; - GST_BUFFER_DURATION (buffer) = duration; - - GST_LOG_OBJECT (base_video_decoder, "collected frame size %d, " - "ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, - n_available, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration)); - - ret = gst_base_video_decoder_have_frame_2 (base_video_decoder); - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return ret; -} - -static GstFlowReturn -gst_base_video_decoder_have_frame_2 (GstBaseVideoDecoder * base_video_decoder) -{ - GstVideoFrameState *frame = base_video_decoder->current_frame; - GstBaseVideoDecoderClass *base_video_decoder_class; - GstFlowReturn ret = GST_FLOW_OK; - - base_video_decoder_class = - GST_BASE_VIDEO_DECODER_GET_CLASS (base_video_decoder); - - g_return_val_if_fail (base_video_decoder_class->handle_frame != NULL, - GST_FLOW_ERROR); - - /* capture frames and queue for later processing */ - if (GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.rate < 0.0 && - !base_video_decoder->process) { - base_video_decoder->parse_gather = - g_list_prepend (base_video_decoder->parse_gather, frame); - goto exit; - } - - frame->distance_from_sync = base_video_decoder->distance_from_sync; - base_video_decoder->distance_from_sync++; - - frame->presentation_timestamp = GST_BUFFER_TIMESTAMP (frame->sink_buffer); - frame->presentation_duration = GST_BUFFER_DURATION (frame->sink_buffer); - - GST_LOG_OBJECT (base_video_decoder, "pts %" GST_TIME_FORMAT, - GST_TIME_ARGS (frame->presentation_timestamp)); - GST_LOG_OBJECT (base_video_decoder, "dts %" GST_TIME_FORMAT, - GST_TIME_ARGS (frame->decode_timestamp)); - GST_LOG_OBJECT (base_video_decoder, "dist %d", frame->distance_from_sync); - - gst_base_video_codec_append_frame (GST_BASE_VIDEO_CODEC (base_video_decoder), - frame); - - frame->deadline = - gst_segment_to_running_time (&GST_BASE_VIDEO_CODEC - (base_video_decoder)->segment, GST_FORMAT_TIME, - frame->presentation_timestamp); - - /* do something with frame */ - GST_LOG_OBJECT (base_video_decoder, "Calling ::handle_frame()"); - ret = base_video_decoder_class->handle_frame (base_video_decoder, frame); - if (ret != GST_FLOW_OK) { - GST_DEBUG_OBJECT (base_video_decoder, "flow error %s", - gst_flow_get_name (ret)); - } - -exit: - /* current frame has either been added to parse_gather or sent to - handle frame so there is no need to unref it */ - - /* create new frame */ - base_video_decoder->current_frame = - gst_base_video_decoder_new_frame (base_video_decoder); - - return ret; -} - -/** - * gst_base_video_decoder_get_state: - * @base_video_decoder: a #GstBaseVideoDecoder - * - * Get the current #GstVideoState - * - * Returns: #GstVideoState describing format of video data. - */ -GstVideoState * -gst_base_video_decoder_get_state (GstBaseVideoDecoder * base_video_decoder) -{ - /* FIXME : Move to base codec class */ - - return &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; -} - -/** - * gst_base_video_decoder_lost_sync: - * @base_video_decoder: a #GstBaseVideoDecoder - * - * Advances out-of-sync input data by 1 byte and marks it accordingly. - */ -void -gst_base_video_decoder_lost_sync (GstBaseVideoDecoder * base_video_decoder) -{ - g_return_if_fail (GST_IS_BASE_VIDEO_DECODER (base_video_decoder)); - - GST_DEBUG_OBJECT (base_video_decoder, "lost_sync"); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - if (gst_adapter_available (base_video_decoder->input_adapter) >= 1) { - gst_adapter_flush (base_video_decoder->input_adapter, 1); - } - - base_video_decoder->have_sync = FALSE; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); -} - -/* FIXME not quite exciting; get rid of this ? */ -/** - * gst_base_video_decoder_set_sync_point: - * @base_video_decoder: a #GstBaseVideoDecoder - * - * Marks current frame as a sync point, i.e. keyframe. - */ -void -gst_base_video_decoder_set_sync_point (GstBaseVideoDecoder * base_video_decoder) -{ - GST_DEBUG_OBJECT (base_video_decoder, "set_sync_point"); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - base_video_decoder->current_frame->is_sync_point = TRUE; - base_video_decoder->distance_from_sync = 0; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); -} - -/** - * gst_base_video_decoder_get_oldest_frame: - * @base_video_decoder: a #GstBaseVideoDecoder - * - * Get the oldest pending unfinished #GstVideoFrameState - * - * Returns: oldest pending unfinished #GstVideoFrameState. - */ -GstVideoFrameState * -gst_base_video_decoder_get_oldest_frame (GstBaseVideoDecoder * - base_video_decoder) -{ - GList *g; - - /* FIXME : Move to base codec class */ - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - g = g_list_first (GST_BASE_VIDEO_CODEC (base_video_decoder)->frames); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - if (g == NULL) - return NULL; - return (GstVideoFrameState *) (g->data); -} - -/** - * gst_base_video_decoder_get_frame: - * @base_video_decoder: a #GstBaseVideoDecoder - * @frame_number: system_frame_number of a frame - * - * Get a pending unfinished #GstVideoFrameState - * - * Returns: pending unfinished #GstVideoFrameState identified by @frame_number. - */ -GstVideoFrameState * -gst_base_video_decoder_get_frame (GstBaseVideoDecoder * base_video_decoder, - int frame_number) -{ - GList *g; - GstVideoFrameState *frame = NULL; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - for (g = g_list_first (GST_BASE_VIDEO_CODEC (base_video_decoder)->frames); - g; g = g_list_next (g)) { - GstVideoFrameState *tmp = g->data; - - if (frame->system_frame_number == frame_number) { - frame = tmp; - break; - } - } - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return frame; -} - -/** - * gst_base_video_decoder_set_src_caps: - * @base_video_decoder: a #GstBaseVideoDecoder - * - * The #GstVideoInfo and #GstBufferPool will be created and negotiated - * according to those values. - * - * Returns: %TRUE if the format was properly negotiated, else %FALSE. - */ -gboolean -gst_base_video_decoder_set_src_caps (GstBaseVideoDecoder * base_video_decoder) -{ - GstCaps *caps; - GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (base_video_decoder); - GstVideoState *state = &codec->state; - GstVideoInfo *info = &codec->info; - GstQuery *query; - GstBufferPool *pool; - GstStructure *config; - guint size, min, max; - gboolean ret; - - /* minimum sense */ - g_return_val_if_fail (state->format != GST_VIDEO_FORMAT_UNKNOWN, FALSE); - g_return_val_if_fail (state->width != 0, FALSE); - g_return_val_if_fail (state->height != 0, FALSE); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - gst_video_info_set_format (info, state->format, state->width, state->height); - - /* sanitize */ - if (state->fps_n == 0 || state->fps_d == 0) { - state->fps_n = 0; - state->fps_d = 1; - } - if (state->par_n == 0 || state->par_d == 0) { - state->par_n = 1; - state->par_d = 1; - } - - info->par_n = state->par_n; - info->par_d = state->par_d; - info->fps_n = state->fps_n; - info->fps_d = state->fps_d; - - if (state->have_interlaced) { - info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED; - } - - /* FIXME : Handle chroma site */ - /* FIXME : Handle colorimetry */ - - caps = gst_video_info_to_caps (info); - - GST_DEBUG_OBJECT (base_video_decoder, "setting caps %" GST_PTR_FORMAT, caps); - - ret = - gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_decoder), - caps); - gst_caps_unref (caps); - - /* Negotiate pool */ - query = gst_query_new_allocation (caps, TRUE); - - if (!gst_pad_peer_query (codec->srcpad, query)) { - GST_DEBUG_OBJECT (codec, "didn't get downstream ALLOCATION hints"); - } - - if (gst_query_get_n_allocation_pools (query) > 0) { - /* we got configuration from our peer, parse them */ - gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); - size = MAX (size, info->size); - } else { - pool = NULL; - size = info->size; - min = max = 0; - } - - if (pool == NULL) { - /* we did not get a pool, make one ourselves then */ - pool = gst_video_buffer_pool_new (); - } - - if (base_video_decoder->pool) { - gst_buffer_pool_set_active (base_video_decoder->pool, FALSE); - gst_object_unref (base_video_decoder->pool); - } - base_video_decoder->pool = pool; - - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_set_params (config, caps, size, min, max); - state->bytes_per_picture = size; - - if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { - /* just set the option, if the pool can support it we will transparently use - * it through the video info API. We could also see if the pool support this - * option and only activate it then. */ - gst_buffer_pool_config_add_option (config, - GST_BUFFER_POOL_OPTION_VIDEO_META); - } - - /* check if downstream supports cropping */ - base_video_decoder->use_cropping = - gst_query_find_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, - NULL); - - gst_buffer_pool_set_config (pool, config); - /* and activate */ - gst_buffer_pool_set_active (pool, TRUE); - - gst_query_unref (query); - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return ret; -} - -/** - * gst_base_video_decoder_alloc_src_buffer: - * @base_video_decoder: a #GstBaseVideoDecoder - * - * Helper function that returns a buffer from the decoders' configured - * #GstBufferPool. - * - * Returns: (transfer full): allocated buffer - */ -GstBuffer * -gst_base_video_decoder_alloc_src_buffer (GstBaseVideoDecoder * - base_video_decoder) -{ - GstBuffer *buffer = NULL; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - gst_buffer_pool_acquire_buffer (base_video_decoder->pool, &buffer, NULL); - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return buffer; -} - -/** - * gst_base_video_decoder_alloc_src_frame: - * @base_video_decoder: a #GstBaseVideoDecoder - * @frame: a #GstVideoFrameState - * - * Helper function that uses @gst_pad_alloc_buffer_and_set_caps() - * to allocate a buffer to hold a video frame for @base_video_decoder's - * current #GstVideoState. Subclass should already have configured video state - * and set src pad caps. - * - * Returns: result from pad alloc call - */ -GstFlowReturn -gst_base_video_decoder_alloc_src_frame (GstBaseVideoDecoder * - base_video_decoder, GstVideoFrameState * frame) -{ - GstFlowReturn flow_ret; - - GST_LOG_OBJECT (base_video_decoder, "alloc buffer"); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - - flow_ret = - gst_buffer_pool_acquire_buffer (base_video_decoder->pool, - &frame->src_buffer, NULL); - - if (flow_ret != GST_FLOW_OK) { - GST_WARNING_OBJECT (base_video_decoder, "failed to get buffer %s", - gst_flow_get_name (flow_ret)); - } - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); - - return flow_ret; -} - -/** - * gst_base_video_decoder_get_max_decode_time: - * @base_video_decoder: a #GstBaseVideoDecoder - * @frame: a #GstVideoFrameState - * - * Determines maximum possible decoding time for @frame that will - * allow it to decode and arrive in time (as determined by QoS events). - * In particular, a negative result means decoding in time is no longer possible - * and should therefore occur as soon/skippy as possible. - * - * Returns: max decoding time. - */ -GstClockTimeDiff -gst_base_video_decoder_get_max_decode_time (GstBaseVideoDecoder * - base_video_decoder, GstVideoFrameState * frame) -{ - GstClockTimeDiff deadline; - GstClockTime earliest_time; - - GST_OBJECT_LOCK (base_video_decoder); - earliest_time = GST_BASE_VIDEO_CODEC (base_video_decoder)->earliest_time; - if (GST_CLOCK_TIME_IS_VALID (earliest_time)) - deadline = GST_CLOCK_DIFF (earliest_time, frame->deadline); - else - deadline = G_MAXINT64; - - GST_LOG_OBJECT (base_video_decoder, "earliest %" GST_TIME_FORMAT - ", frame deadline %" GST_TIME_FORMAT ", deadline %" GST_TIME_FORMAT, - GST_TIME_ARGS (earliest_time), GST_TIME_ARGS (frame->deadline), - GST_TIME_ARGS (deadline)); - - GST_OBJECT_UNLOCK (base_video_decoder); - - return deadline; -} - -/** - * gst_base_video_decoder_class_set_capture_pattern: - * @base_video_decoder_class: a #GstBaseVideoDecoderClass - * @mask: The mask used for scanning - * @pattern: The pattern used for matching - * - * Sets the mask and pattern that will be scanned for to obtain parse sync. - * Note that a non-zero @mask implies that @scan_for_sync will be ignored. - * - */ -void -gst_base_video_decoder_class_set_capture_pattern (GstBaseVideoDecoderClass * - base_video_decoder_class, guint32 mask, guint32 pattern) -{ - g_return_if_fail (((~mask) & pattern) == 0); - - GST_DEBUG ("capture mask %08x, pattern %08x", mask, pattern); - - base_video_decoder_class->capture_mask = mask; - base_video_decoder_class->capture_pattern = pattern; -} - -GstFlowReturn -_gst_base_video_decoder_error (GstBaseVideoDecoder * dec, gint weight, - GQuark domain, gint code, gchar * txt, gchar * dbg, const gchar * file, - const gchar * function, gint line) -{ - if (txt) - GST_WARNING_OBJECT (dec, "error: %s", txt); - if (dbg) - GST_WARNING_OBJECT (dec, "error: %s", dbg); - dec->error_count += weight; - GST_BASE_VIDEO_CODEC (dec)->discont = TRUE; - if (dec->max_errors < dec->error_count) { - gst_element_message_full (GST_ELEMENT (dec), GST_MESSAGE_ERROR, - domain, code, txt, dbg, file, function, line); - return GST_FLOW_ERROR; - } else { - return GST_FLOW_OK; - } -} diff --git a/omx/gstbasevideodecoder.h b/omx/gstbasevideodecoder.h deleted file mode 100644 index 53ba565..0000000 --- a/omx/gstbasevideodecoder.h +++ /dev/null @@ -1,291 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef - * Copyright (C) 2011 Mark Nauwelaerts . - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _GST_BASE_VIDEO_DECODER_H_ -#define _GST_BASE_VIDEO_DECODER_H_ - -#ifndef GST_USE_UNSTABLE_API -#warning "GstBaseVideoDecoder is unstable API and may change in future." -#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." -#endif - -#include "gstbasevideocodec.h" - -G_BEGIN_DECLS - -#define GST_TYPE_BASE_VIDEO_DECODER \ - (gst_base_video_decoder_get_type()) -#define GST_BASE_VIDEO_DECODER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_VIDEO_DECODER,GstBaseVideoDecoder)) -#define GST_BASE_VIDEO_DECODER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_VIDEO_DECODER,GstBaseVideoDecoderClass)) -#define GST_BASE_VIDEO_DECODER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_BASE_VIDEO_DECODER,GstBaseVideoDecoderClass)) -#define GST_IS_BASE_VIDEO_DECODER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_VIDEO_DECODER)) -#define GST_IS_BASE_VIDEO_DECODER_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_VIDEO_DECODER)) - -/** - * GST_BASE_VIDEO_DECODER_SINK_NAME: - * - * The name of the templates for the sink pad. - */ -#define GST_BASE_VIDEO_DECODER_SINK_NAME "sink" -/** - * GST_BASE_VIDEO_DECODER_SRC_NAME: - * - * The name of the templates for the source pad. - */ -#define GST_BASE_VIDEO_DECODER_SRC_NAME "src" - -/** - * GST_BASE_VIDEO_DECODER_FLOW_NEED_DATA: - * - * Returned while parsing to indicate more data is needed. - **/ -#define GST_BASE_VIDEO_DECODER_FLOW_NEED_DATA GST_FLOW_CUSTOM_SUCCESS - -/** - * GST_BASE_VIDEO_DECODER_FLOW_DROPPED: - * - * Returned when the event/buffer should be dropped. - */ -#define GST_BASE_VIDEO_DECODER_FLOW_DROPPED GST_FLOW_CUSTOM_SUCCESS_1 - -typedef struct _GstBaseVideoDecoder GstBaseVideoDecoder; -typedef struct _GstBaseVideoDecoderClass GstBaseVideoDecoderClass; - - -/* do not use this one, use macro below */ -GstFlowReturn _gst_base_video_decoder_error (GstBaseVideoDecoder *dec, gint weight, - GQuark domain, gint code, - gchar *txt, gchar *debug, - const gchar *file, const gchar *function, - gint line); - -/** - * GST_BASE_VIDEO_DECODER_ERROR: - * @el: the base video decoder element that generates the error - * @weight: element defined weight of the error, added to error count - * @domain: like CORE, LIBRARY, RESOURCE or STREAM (see #gstreamer-GstGError) - * @code: error code defined for that domain (see #gstreamer-GstGError) - * @text: the message to display (format string and args enclosed in - * parentheses) - * @debug: debugging information for the message (format string and args - * enclosed in parentheses) - * @ret: variable to receive return value - * - * Utility function that video decoder elements can use in case they encountered - * a data processing error that may be fatal for the current "data unit" but - * need not prevent subsequent decoding. Such errors are counted and if there - * are too many, as configured in the context's max_errors, the pipeline will - * post an error message and the application will be requested to stop further - * media processing. Otherwise, it is considered a "glitch" and only a warning - * is logged. In either case, @ret is set to the proper value to - * return to upstream/caller (indicating either GST_FLOW_ERROR or GST_FLOW_OK). - */ -#define GST_BASE_VIDEO_DECODER_ERROR(el, w, domain, code, text, debug, ret) \ -G_STMT_START { \ - gchar *__txt = _gst_element_error_printf text; \ - gchar *__dbg = _gst_element_error_printf debug; \ - GstBaseVideoDecoder *dec = GST_BASE_VIDEO_DECODER (el); \ - ret = _gst_base_video_decoder_error (dec, w, GST_ ## domain ## _ERROR, \ - GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \ - GST_FUNCTION, __LINE__); \ -} G_STMT_END - - -/** - * GstBaseVideoDecoder: - * - * The opaque #GstBaseVideoDecoder data structure. - */ -struct _GstBaseVideoDecoder -{ - /*< private >*/ - GstBaseVideoCodec base_video_codec; - - /*< protected >*/ - gboolean sink_clipping; - gboolean do_byte_time; - gboolean packetized; - gint max_errors; - - /* parse tracking */ - /* input data */ - GstAdapter *input_adapter; - /* assembles current frame */ - GstAdapter *output_adapter; - - /*< private >*/ - /* FIXME move to real private part ? - * (and introduce a context ?) */ - /* ... being tracked here; - * only available during parsing */ - /* FIXME remove and add parameter to method */ - GstVideoFrameState *current_frame; - /* events that should apply to the current frame */ - GList *current_frame_events; - /* relative offset of input data */ - guint64 input_offset; - /* relative offset of frame */ - guint64 frame_offset; - /* tracking ts and offsets */ - GList *timestamps; - /* whether parsing is in sync */ - gboolean have_sync; - - /* maybe sort-of protected ? */ - - /* combine to yield (presentation) ts */ - GstClockTime timestamp_offset; - int field_index; - - /* last outgoing ts */ - GstClockTime last_timestamp; - gint error_count; - - /* reverse playback */ - /* collect input */ - GList *gather; - /* to-be-parsed */ - GList *parse; - /* collected parsed frames */ - GList *parse_gather; - /* frames to be handled == decoded */ - GList *decode; - /* collected output */ - GList *queued; - gboolean process; - - /* no comment ... */ - guint64 base_picture_number; - int reorder_depth; - int distance_from_sync; - - /* Raw video bufferpool */ - GstBufferPool *pool; - /* Indicates whether downstream can handle - * GST_META_API_VIDEO_CROP */ - gboolean use_cropping; - - /* qos messages: frames dropped/processed */ - guint dropped; - guint processed; - - /* FIXME before moving to base */ - void *padding[GST_PADDING_LARGE]; -}; - -/** - * GstBaseVideoDecoderClass: - * @start: Optional. - * Called when the element starts processing. - * Allows opening external resources. - * @stop: Optional. - * Called when the element stops processing. - * Allows closing external resources. - * @set_format: Notifies subclass of incoming data format (caps). - * @scan_for_sync: Optional. - * Allows subclass to obtain sync for subsequent parsing - * by custom means (above an beyond scanning for specific - * marker and mask). - * @parse_data: Required for non-packetized input. - * Allows chopping incoming data into manageable units (frames) - * for subsequent decoding. - * @reset: Optional. - * Allows subclass (codec) to perform post-seek semantics reset. - * @handle_frame: Provides input data frame to subclass. - * @finish: Optional. - * Called to request subclass to dispatch any pending remaining - * data (e.g. at EOS). - * - * Subclasses can override any of the available virtual methods or not, as - * needed. At minimum @handle_frame needs to be overridden, and @set_format - * and likely as well. If non-packetized input is supported or expected, - * @parse needs to be overridden as well. - */ -struct _GstBaseVideoDecoderClass -{ - /*< private >*/ - GstBaseVideoCodecClass base_video_codec_class; - - /*< public >*/ - gboolean (*start) (GstBaseVideoDecoder *coder); - - gboolean (*stop) (GstBaseVideoDecoder *coder); - - int (*scan_for_sync) (GstBaseVideoDecoder *decoder, gboolean at_eos, - int offset, int n); - - GstFlowReturn (*parse_data) (GstBaseVideoDecoder *decoder, gboolean at_eos); - - gboolean (*set_format) (GstBaseVideoDecoder *coder, GstVideoState * state); - - gboolean (*reset) (GstBaseVideoDecoder *coder); - - GstFlowReturn (*finish) (GstBaseVideoDecoder *coder); - - GstFlowReturn (*handle_frame) (GstBaseVideoDecoder *coder, GstVideoFrameState *frame); - - - /*< private >*/ - guint32 capture_mask; - guint32 capture_pattern; - - /* FIXME before moving to base */ - void *padding[GST_PADDING_LARGE]; -}; - -void gst_base_video_decoder_class_set_capture_pattern (GstBaseVideoDecoderClass *base_video_decoder_class, - guint32 mask, guint32 pattern); - -GstVideoFrameState *gst_base_video_decoder_get_frame (GstBaseVideoDecoder *coder, - int frame_number); -GstVideoFrameState *gst_base_video_decoder_get_oldest_frame (GstBaseVideoDecoder *coder); - -void gst_base_video_decoder_add_to_frame (GstBaseVideoDecoder *base_video_decoder, - int n_bytes); -void gst_base_video_decoder_lost_sync (GstBaseVideoDecoder *base_video_decoder); -GstFlowReturn gst_base_video_decoder_have_frame (GstBaseVideoDecoder *base_video_decoder); - -void gst_base_video_decoder_set_sync_point (GstBaseVideoDecoder *base_video_decoder); -gboolean gst_base_video_decoder_set_src_caps (GstBaseVideoDecoder *base_video_decoder); -GstBuffer *gst_base_video_decoder_alloc_src_buffer (GstBaseVideoDecoder * base_video_decoder); -GstFlowReturn gst_base_video_decoder_alloc_src_frame (GstBaseVideoDecoder *base_video_decoder, - GstVideoFrameState *frame); -GstVideoState *gst_base_video_decoder_get_state (GstBaseVideoDecoder *base_video_decoder); -GstClockTimeDiff gst_base_video_decoder_get_max_decode_time ( - GstBaseVideoDecoder *base_video_decoder, - GstVideoFrameState *frame); -GstFlowReturn gst_base_video_decoder_finish_frame (GstBaseVideoDecoder *base_video_decoder, - GstVideoFrameState *frame); -GstFlowReturn gst_base_video_decoder_drop_frame (GstBaseVideoDecoder *dec, - GstVideoFrameState *frame); - -GType gst_base_video_decoder_get_type (void); - -G_END_DECLS - -#endif - diff --git a/omx/gstbasevideoencoder.c b/omx/gstbasevideoencoder.c deleted file mode 100644 index 13160ce..0000000 --- a/omx/gstbasevideoencoder.c +++ /dev/null @@ -1,1213 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef - * Copyright (C) 2011 Mark Nauwelaerts . - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:gstbasevideoencoder - * @short_description: Base class for video encoders - * @see_also: #GstBaseTransform - * - * This base class is for video encoders turning raw video into - * encoded video data. - * - * GstBaseVideoEncoder and subclass should cooperate as follows. - * - * - * Configuration - * - * Initially, GstBaseVideoEncoder calls @start when the encoder element - * is activated, which allows subclass to perform any global setup. - * - * - * GstBaseVideoEncoder calls @set_format to inform subclass of the format - * of input video data that it is about to receive. Subclass should - * setup for encoding and configure base class as appropriate - * (e.g. latency). While unlikely, it might be called more than once, - * if changing input parameters require reconfiguration. Baseclass - * will ensure that processing of current configuration is finished. - * - * - * GstBaseVideoEncoder calls @stop at end of all processing. - * - * - * - * - * - * Data processing - * - * Base class collects input data and metadata into a frame and hands - * this to subclass' @handle_frame. - * - * - * If codec processing results in encoded data, subclass should call - * @gst_base_video_encoder_finish_frame to have encoded data pushed - * downstream. - * - * - * If implemented, baseclass calls subclass @shape_output which then sends - * data downstream in desired form. Otherwise, it is sent as-is. - * - * - * GstBaseVideoEncoderClass will handle both srcpad and sinkpad events. - * Sink events will be passed to subclass if @event callback has been - * provided. - * - * - * - * - * Shutdown phase - * - * GstBaseVideoEncoder class calls @stop to inform the subclass that data - * parsing will be stopped. - * - * - * - * - * - * Subclass is responsible for providing pad template caps for - * source and sink pads. The pads need to be named "sink" and "src". It should - * also be able to provide fixed src pad caps in @getcaps by the time it calls - * @gst_base_video_encoder_finish_frame. - * - * Things that subclass need to take care of: - * - * Provide pad templates - * - * Provide source pad caps before pushing the first buffer - * - * - * Accept data in @handle_frame and provide encoded results to - * @gst_base_video_encoder_finish_frame. - * - * - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - -#include "gstbasevideoencoder.h" -#include "gstbasevideoutils.h" - -#include - -GST_DEBUG_CATEGORY (basevideoencoder_debug); -#define GST_CAT_DEFAULT basevideoencoder_debug - -typedef struct _ForcedKeyUnitEvent ForcedKeyUnitEvent; -struct _ForcedKeyUnitEvent -{ - GstClockTime running_time; - gboolean pending; /* TRUE if this was requested already */ - gboolean all_headers; - guint count; -}; - -static void -forced_key_unit_event_free (ForcedKeyUnitEvent * evt) -{ - g_slice_free (ForcedKeyUnitEvent, evt); -} - -static ForcedKeyUnitEvent * -forced_key_unit_event_new (GstClockTime running_time, gboolean all_headers, - guint count) -{ - ForcedKeyUnitEvent *evt = g_slice_new0 (ForcedKeyUnitEvent); - - evt->running_time = running_time; - evt->all_headers = all_headers; - evt->count = count; - - return evt; -} - -static void gst_base_video_encoder_finalize (GObject * object); - -static GstCaps *gst_base_video_encoder_sink_getcaps (GstPad * pad, - GstCaps * filter); -static gboolean gst_base_video_encoder_src_event (GstPad * pad, - GstObject * parent, GstEvent * event); -static gboolean gst_base_video_encoder_sink_event (GstPad * pad, - GstObject * parent, GstEvent * event); -static gboolean gst_base_video_encoder_sink_query (GstPad * pad, - GstObject * parent, GstQuery * query); -static GstFlowReturn gst_base_video_encoder_chain (GstPad * pad, - GstObject * parent, GstBuffer * buf); -static GstStateChangeReturn gst_base_video_encoder_change_state (GstElement * - element, GstStateChange transition); -static gboolean gst_base_video_encoder_src_query (GstPad * pad, - GstObject * parent, GstQuery * query); - -#define gst_base_video_encoder_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstBaseVideoEncoder, gst_base_video_encoder, - GST_TYPE_BASE_VIDEO_CODEC, G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL);); - -static void -gst_base_video_encoder_class_init (GstBaseVideoEncoderClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - GST_DEBUG_CATEGORY_INIT (basevideoencoder_debug, "basevideoencoder", 0, - "Base Video Encoder"); - - gobject_class = G_OBJECT_CLASS (klass); - gstelement_class = GST_ELEMENT_CLASS (klass); - - gobject_class->finalize = gst_base_video_encoder_finalize; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_base_video_encoder_change_state); -} - -static void -gst_base_video_encoder_reset (GstBaseVideoEncoder * base_video_encoder) -{ - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); - - base_video_encoder->presentation_frame_number = 0; - base_video_encoder->distance_from_sync = 0; - - g_list_foreach (base_video_encoder->force_key_unit, - (GFunc) forced_key_unit_event_free, NULL); - g_list_free (base_video_encoder->force_key_unit); - base_video_encoder->force_key_unit = NULL; - - base_video_encoder->drained = TRUE; - base_video_encoder->min_latency = 0; - base_video_encoder->max_latency = 0; - - gst_buffer_replace (&base_video_encoder->headers, NULL); - - g_list_foreach (base_video_encoder->current_frame_events, - (GFunc) gst_event_unref, NULL); - g_list_free (base_video_encoder->current_frame_events); - base_video_encoder->current_frame_events = NULL; - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); -} - -static void -gst_base_video_encoder_init (GstBaseVideoEncoder * base_video_encoder) -{ - GstPad *pad; - - GST_DEBUG_OBJECT (base_video_encoder, "gst_base_video_encoder_init"); - - pad = GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_encoder); - - gst_pad_set_chain_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_encoder_chain)); - gst_pad_set_event_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_encoder_sink_event)); - gst_pad_set_query_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_encoder_sink_query)); - - pad = GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder); - - gst_pad_set_query_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_encoder_src_query)); - gst_pad_set_event_function (pad, - GST_DEBUG_FUNCPTR (gst_base_video_encoder_src_event)); - - base_video_encoder->at_eos = FALSE; - base_video_encoder->headers = NULL; - - /* encoder is expected to do so */ - base_video_encoder->sink_clipping = TRUE; -} - -/** - * gst_base_video_encoder_set_headers: - * @base_video_encoder: a #GstBaseVideoEncoder - * @headers: (transfer full): the #GstBuffer containing the codec header - * - * Set the codec headers to be sent downstream whenever requested. - */ -void -gst_base_video_encoder_set_headers (GstBaseVideoEncoder * base_video_encoder, - GstBuffer * headers) -{ - GST_DEBUG_OBJECT (base_video_encoder, "new headers %p", headers); - gst_buffer_replace (&base_video_encoder->headers, headers); -} - -static gboolean -gst_base_video_encoder_drain (GstBaseVideoEncoder * enc) -{ - GstBaseVideoCodec *codec; - GstBaseVideoEncoderClass *enc_class; - gboolean ret = TRUE; - - codec = GST_BASE_VIDEO_CODEC (enc); - enc_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (enc); - - GST_DEBUG_OBJECT (enc, "draining"); - - if (enc->drained) { - GST_DEBUG_OBJECT (enc, "already drained"); - return TRUE; - } - - if (enc_class->reset) { - GST_DEBUG_OBJECT (enc, "requesting subclass to finish"); - ret = enc_class->reset (enc); - } - /* everything should be away now */ - if (codec->frames) { - /* not fatal/impossible though if subclass/codec eats stuff */ - g_list_foreach (codec->frames, (GFunc) gst_video_frame_state_unref, NULL); - g_list_free (codec->frames); - codec->frames = NULL; - } - - return ret; -} - -static gboolean -gst_base_video_encoder_sink_setcaps (GstBaseVideoEncoder * base_video_encoder, - GstCaps * caps) -{ - GstBaseVideoEncoderClass *base_video_encoder_class; - GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (base_video_encoder); - GstVideoInfo *info, tmp_info; - GstVideoState *state, tmp_state; - gboolean ret = FALSE; - gboolean changed = TRUE; - - GST_DEBUG_OBJECT (base_video_encoder, "setcaps %" GST_PTR_FORMAT, caps); - - 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_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); - - /* Get GstVideoInfo from upstream caps */ - info = &codec->info; - if (!gst_video_info_from_caps (&tmp_info, caps)) - goto exit; - - state = &codec->state; - memset (&tmp_state, 0, sizeof (tmp_state)); - - tmp_state.caps = gst_caps_ref (caps); - - /* Check if input caps changed */ - if (info->finfo) { - /* Check if anything changed */ - changed = GST_VIDEO_INFO_FORMAT (&tmp_info) != GST_VIDEO_INFO_FORMAT (info); - changed |= GST_VIDEO_INFO_FLAGS (&tmp_info) != GST_VIDEO_INFO_FLAGS (info); - changed |= GST_VIDEO_INFO_WIDTH (&tmp_info) != GST_VIDEO_INFO_WIDTH (info); - changed |= - GST_VIDEO_INFO_HEIGHT (&tmp_info) != GST_VIDEO_INFO_HEIGHT (info); - changed |= GST_VIDEO_INFO_SIZE (&tmp_info) != GST_VIDEO_INFO_SIZE (info); - changed |= GST_VIDEO_INFO_VIEWS (&tmp_info) != GST_VIDEO_INFO_VIEWS (info); - changed |= GST_VIDEO_INFO_FPS_N (&tmp_info) != GST_VIDEO_INFO_FPS_N (info); - changed |= GST_VIDEO_INFO_FPS_D (&tmp_info) != GST_VIDEO_INFO_FPS_D (info); - changed |= GST_VIDEO_INFO_PAR_N (&tmp_info) != GST_VIDEO_INFO_PAR_N (info); - changed |= GST_VIDEO_INFO_PAR_D (&tmp_info) != GST_VIDEO_INFO_PAR_D (info); - } - - /* Copy over info from input GstVideoInfo into output GstVideoFrameState */ - tmp_state.format = GST_VIDEO_INFO_FORMAT (&tmp_info); - tmp_state.bytes_per_picture = tmp_info.size; - tmp_state.width = tmp_info.width; - tmp_state.height = tmp_info.height; - tmp_state.fps_n = tmp_info.fps_n; - tmp_state.fps_d = tmp_info.fps_d; - tmp_state.par_n = tmp_info.par_n; - tmp_state.par_d = tmp_info.par_d; - tmp_state.clean_width = tmp_info.width; - tmp_state.clean_height = tmp_info.height; - tmp_state.clean_offset_left = 0; - tmp_state.clean_offset_top = 0; - /* FIXME (Edward): We need flags in GstVideoInfo to know whether - * interlaced field was present in input caps */ - tmp_state.have_interlaced = tmp_state.interlaced = - GST_VIDEO_INFO_IS_INTERLACED (&tmp_info); - - 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_info); - if (ret) { - gst_caps_replace (&state->caps, NULL); - *state = tmp_state; - *info = tmp_info; - } - } 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); - } - - return ret; -} - -static GstCaps * -gst_base_video_encoder_sink_getcaps (GstPad * pad, GstCaps * filter) -{ - GstBaseVideoEncoder *base_video_encoder; - 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 = 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_new_id_empty (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); - - filter_caps = gst_caps_merge_structure (filter_caps, s); - } - } - - GST_LOG_OBJECT (base_video_encoder, "filtered caps (first) %" GST_PTR_FORMAT, - filter_caps); - - fcaps = gst_caps_intersect (filter_caps, templ_caps); - gst_caps_unref (templ_caps); - gst_caps_unref (filter_caps); - - if (filter) { - GST_LOG_OBJECT (base_video_encoder, "intersecting with %" GST_PTR_FORMAT, - filter); - filter_caps = gst_caps_intersect (fcaps, filter); - gst_caps_unref (fcaps); - fcaps = filter_caps; - } - -done: - - gst_caps_replace (&allowed, NULL); - - GST_LOG_OBJECT (base_video_encoder, "Returning caps %" GST_PTR_FORMAT, fcaps); - - g_object_unref (base_video_encoder); - return fcaps; -} - -static gboolean -gst_base_video_encoder_sink_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CAPS: - { - GstCaps *filter, *caps; - - gst_query_parse_caps (query, &filter); - caps = gst_base_video_encoder_sink_getcaps (pad, filter); - gst_query_set_caps_result (query, caps); - gst_caps_unref (caps); - res = TRUE; - break; - } - default: - res = gst_pad_query_default (pad, parent, query); - break; - } - return res; -} - -static void -gst_base_video_encoder_finalize (GObject * object) -{ - GstBaseVideoEncoder *base_video_encoder = (GstBaseVideoEncoder *) object; - GST_DEBUG_OBJECT (object, "finalize"); - - gst_buffer_replace (&base_video_encoder->headers, NULL); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_base_video_encoder_sink_eventfunc (GstBaseVideoEncoder * base_video_encoder, - GstEvent * event) -{ - GstBaseVideoEncoderClass *base_video_encoder_class; - gboolean ret = FALSE; - - base_video_encoder_class = - GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS: - { - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - ret = gst_base_video_encoder_sink_setcaps (base_video_encoder, caps); - gst_event_unref (event); - } - break; - case GST_EVENT_EOS: - { - GstFlowReturn flow_ret; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); - base_video_encoder->at_eos = TRUE; - - if (base_video_encoder_class->finish) { - flow_ret = base_video_encoder_class->finish (base_video_encoder); - } else { - flow_ret = GST_FLOW_OK; - } - - ret = (flow_ret == GST_BASE_VIDEO_ENCODER_FLOW_DROPPED); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); - break; - } - case GST_EVENT_SEGMENT: - { - const GstSegment *segment; - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); - gst_event_parse_segment (event, &segment); - - GST_DEBUG_OBJECT (base_video_encoder, "newseg rate %g, applied rate %g, " - "format %d, start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT - ", pos = %" GST_TIME_FORMAT, segment->rate, segment->applied_rate, - segment->format, GST_TIME_ARGS (segment->start), - GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->position)); - - if (segment->format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (base_video_encoder, "received non TIME newsegment"); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); - break; - } - - base_video_encoder->at_eos = FALSE; - - gst_segment_copy_into (segment, &GST_BASE_VIDEO_CODEC - (base_video_encoder)->segment); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); - break; - } - case GST_EVENT_CUSTOM_DOWNSTREAM: - { - if (gst_video_event_is_force_key_unit (event)) { - GstClockTime running_time; - gboolean all_headers; - guint count; - - if (gst_video_event_parse_downstream_force_key_unit (event, - NULL, NULL, &running_time, &all_headers, &count)) { - ForcedKeyUnitEvent *fevt; - - GST_OBJECT_LOCK (base_video_encoder); - fevt = forced_key_unit_event_new (running_time, all_headers, count); - base_video_encoder->force_key_unit = - g_list_append (base_video_encoder->force_key_unit, fevt); - GST_OBJECT_UNLOCK (base_video_encoder); - - GST_DEBUG_OBJECT (base_video_encoder, - "force-key-unit event: running-time %" GST_TIME_FORMAT - ", all_headers %d, count %u", - GST_TIME_ARGS (running_time), all_headers, count); - } - gst_event_unref (event); - ret = TRUE; - } - break; - } - default: - break; - } - - return ret; -} - -static gboolean -gst_base_video_encoder_sink_event (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - GstBaseVideoEncoder *enc; - GstBaseVideoEncoderClass *klass; - gboolean handled = FALSE; - gboolean ret = TRUE; - - enc = GST_BASE_VIDEO_ENCODER (parent); - 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"); - - return ret; -} - -static gboolean -gst_base_video_encoder_src_event (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - GstBaseVideoEncoder *base_video_encoder; - gboolean ret = FALSE; - - base_video_encoder = GST_BASE_VIDEO_ENCODER (parent); - - GST_LOG_OBJECT (base_video_encoder, "handling event: %" GST_PTR_FORMAT, - event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CUSTOM_UPSTREAM: - { - if (gst_video_event_is_force_key_unit (event)) { - GstClockTime running_time; - gboolean all_headers; - guint count; - - if (gst_video_event_parse_upstream_force_key_unit (event, - &running_time, &all_headers, &count)) { - ForcedKeyUnitEvent *fevt; - - GST_OBJECT_LOCK (base_video_encoder); - fevt = forced_key_unit_event_new (running_time, all_headers, count); - base_video_encoder->force_key_unit = - g_list_append (base_video_encoder->force_key_unit, fevt); - GST_OBJECT_UNLOCK (base_video_encoder); - - GST_DEBUG_OBJECT (base_video_encoder, - "force-key-unit event: running-time %" GST_TIME_FORMAT - ", all_headers %d, count %u", - GST_TIME_ARGS (running_time), all_headers, count); - } - 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; - } - - return ret; -} - -static gboolean -gst_base_video_encoder_src_query (GstPad * pad, GstObject * parent, - GstQuery * query) -{ - GstBaseVideoEncoder *enc; - gboolean res; - - enc = GST_BASE_VIDEO_ENCODER (parent); - - GST_LOG_OBJECT (enc, "handling query: %" GST_PTR_FORMAT, query); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONVERT: - { - GstBaseVideoCodec *codec = GST_BASE_VIDEO_CODEC (enc); - 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 (&codec->state, - codec->bytes, codec->time, 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_peer_query (GST_BASE_VIDEO_CODEC_SINK_PAD (enc), query); - if (res) { - gst_query_parse_latency (query, &live, &min_latency, &max_latency); - GST_DEBUG_OBJECT (enc, "Peer latency: live %d, min %" - GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - - GST_OBJECT_LOCK (enc); - min_latency += enc->min_latency; - if (max_latency != GST_CLOCK_TIME_NONE) { - max_latency += enc->max_latency; - } - GST_OBJECT_UNLOCK (enc); - - gst_query_set_latency (query, live, min_latency, max_latency); - } - } - break; - default: - res = gst_pad_query_default (pad, parent, query); - } - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (enc, "query failed"); - return res; - } -} - -static GstFlowReturn -gst_base_video_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) -{ - GstBaseVideoEncoder *base_video_encoder; - GstBaseVideoEncoderClass *klass; - GstVideoFrameState *frame; - GstFlowReturn ret = GST_FLOW_OK; - - base_video_encoder = GST_BASE_VIDEO_ENCODER (parent); - 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); - - GST_LOG_OBJECT (base_video_encoder, - "received buffer of size %" G_GSIZE_FORMAT " with ts %" GST_TIME_FORMAT - ", duration %" GST_TIME_FORMAT, gst_buffer_get_size (buf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - if (base_video_encoder->at_eos) { - ret = GST_FLOW_EOS; - goto done; - } - - if (base_video_encoder->sink_clipping) { - guint64 start = GST_BUFFER_TIMESTAMP (buf); - guint64 stop = start + GST_BUFFER_DURATION (buf); - guint64 clip_start; - guint64 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++; - - GST_OBJECT_LOCK (base_video_encoder); - if (base_video_encoder->force_key_unit) { - ForcedKeyUnitEvent *fevt = NULL; - GstClockTime running_time; - GList *l; - - running_time = gst_segment_to_running_time (&GST_BASE_VIDEO_CODEC - (base_video_encoder)->segment, GST_FORMAT_TIME, - GST_BUFFER_TIMESTAMP (buf)); - - for (l = base_video_encoder->force_key_unit; l; l = l->next) { - ForcedKeyUnitEvent *tmp = l->data; - - /* Skip pending keyunits */ - if (tmp->pending) - continue; - - /* Simple case, keyunit ASAP */ - if (tmp->running_time == GST_CLOCK_TIME_NONE) { - fevt = tmp; - break; - } - - /* Event for before this frame */ - if (tmp->running_time <= running_time) { - fevt = tmp; - break; - } - } - - if (fevt) { - GST_DEBUG_OBJECT (base_video_encoder, - "Forcing a key unit at running time %" GST_TIME_FORMAT, - GST_TIME_ARGS (running_time)); - frame->force_keyframe = TRUE; - frame->force_keyframe_headers = fevt->all_headers; - fevt->pending = TRUE; - } - } - GST_OBJECT_UNLOCK (base_video_encoder); - - 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); - - return ret; -} - -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) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_base_video_encoder_reset (base_video_encoder); - if (base_video_encoder_class->start) { - if (!base_video_encoder_class->start (base_video_encoder)) - goto start_error; - } - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_base_video_encoder_reset (base_video_encoder); - if (base_video_encoder_class->stop) { - if (!base_video_encoder_class->stop (base_video_encoder)) - goto stop_error; - } - break; - default: - break; - } - - return ret; - -start_error: - GST_WARNING_OBJECT (base_video_encoder, "failed to start"); - return GST_STATE_CHANGE_FAILURE; - -stop_error: - GST_WARNING_OBJECT (base_video_encoder, "failed to stop"); - return GST_STATE_CHANGE_FAILURE; -} - -/** - * gst_base_video_encoder_finish_frame: - * @base_video_encoder: a #GstBaseVideoEncoder - * @frame: an encoded #GstVideoFrameState - * - * @frame must have a valid encoded data buffer, whose metadata fields - * are then appropriately set according to frame data or no buffer at - * all if the frame should be dropped. - * It is subsequently pushed downstream or provided to @shape_output. - * In any case, the frame is considered finished and released. - * - * Returns: a #GstFlowReturn resulting from sending data downstream - */ -GstFlowReturn -gst_base_video_encoder_finish_frame (GstBaseVideoEncoder * base_video_encoder, - GstVideoFrameState * frame) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstBaseVideoEncoderClass *base_video_encoder_class; - GList *l; - GstBuffer *headers = NULL; - - base_video_encoder_class = - GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); - - GST_LOG_OBJECT (base_video_encoder, - "finish frame fpn %d", frame->presentation_frame_number); - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); - - /* Push all pending events that arrived before this frame */ - for (l = base_video_encoder->base_video_codec.frames; l; l = l->next) { - GstVideoFrameState *tmp = l->data; - - if (tmp->events) { - GList *k; - - for (k = g_list_last (tmp->events); k; k = k->prev) - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), - k->data); - g_list_free (tmp->events); - tmp->events = NULL; - } - - if (tmp == frame) - break; - } - - /* no buffer data means this frame is skipped/dropped */ - if (!frame->src_buffer) { - GST_DEBUG_OBJECT (base_video_encoder, "skipping frame %" GST_TIME_FORMAT, - GST_TIME_ARGS (frame->presentation_timestamp)); - goto done; - } - - if (frame->is_sync_point && base_video_encoder->force_key_unit) { - GstClockTime stream_time, running_time; - GstEvent *ev; - ForcedKeyUnitEvent *fevt = NULL; - GList *l; - - running_time = gst_segment_to_running_time (&GST_BASE_VIDEO_CODEC - (base_video_encoder)->segment, GST_FORMAT_TIME, - frame->presentation_timestamp); - - /* re-use upstream event if any so it also conveys any additional - * info upstream arranged in there */ - GST_OBJECT_LOCK (base_video_encoder); - for (l = base_video_encoder->force_key_unit; l; l = l->next) { - ForcedKeyUnitEvent *tmp = l->data; - - /* Skip non-pending keyunits */ - if (!tmp->pending) - continue; - - /* Simple case, keyunit ASAP */ - if (tmp->running_time == GST_CLOCK_TIME_NONE) { - fevt = tmp; - break; - } - - /* Event for before this frame */ - if (tmp->running_time <= running_time) { - fevt = tmp; - break; - } - } - - if (fevt) { - base_video_encoder->force_key_unit = - g_list_remove (base_video_encoder->force_key_unit, fevt); - } - GST_OBJECT_UNLOCK (base_video_encoder); - - if (fevt) { - stream_time = - gst_segment_to_stream_time (&GST_BASE_VIDEO_CODEC - (base_video_encoder)->segment, GST_FORMAT_TIME, - frame->presentation_timestamp); - - ev = gst_video_event_new_downstream_force_key_unit - (frame->presentation_timestamp, stream_time, running_time, - fevt->all_headers, fevt->count); - - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), - ev); - - if (fevt->all_headers) { - if (base_video_encoder->headers) { - headers = gst_buffer_ref (base_video_encoder->headers); - headers = gst_buffer_make_writable (headers); - } - } - - GST_DEBUG_OBJECT (base_video_encoder, - "Forced key unit: running-time %" GST_TIME_FORMAT - ", all_headers %d, count %u", - GST_TIME_ARGS (running_time), fevt->all_headers, fevt->count); - forced_key_unit_event_free (fevt); - } - } - - if (frame->is_sync_point) { - GST_LOG_OBJECT (base_video_encoder, "key frame"); - base_video_encoder->distance_from_sync = 0; - GST_BUFFER_FLAG_UNSET (frame->src_buffer, GST_BUFFER_FLAG_DELTA_UNIT); - } else { - GST_BUFFER_FLAG_SET (frame->src_buffer, GST_BUFFER_FLAG_DELTA_UNIT); - } - - frame->distance_from_sync = base_video_encoder->distance_from_sync; - base_video_encoder->distance_from_sync++; - - frame->decode_frame_number = frame->system_frame_number - 1; - if (frame->decode_frame_number < 0) { - frame->decode_timestamp = 0; - } else { - frame->decode_timestamp = gst_util_uint64_scale (frame->decode_frame_number, - GST_SECOND * GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_d, - GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_n); - } - - GST_BUFFER_TIMESTAMP (frame->src_buffer) = frame->presentation_timestamp; - GST_BUFFER_DURATION (frame->src_buffer) = frame->presentation_duration; - GST_BUFFER_OFFSET (frame->src_buffer) = frame->decode_timestamp; - - if (G_UNLIKELY (headers)) { - GST_BUFFER_TIMESTAMP (headers) = frame->presentation_timestamp; - GST_BUFFER_DURATION (headers) = 0; - GST_BUFFER_OFFSET (headers) = frame->decode_timestamp; - } - - /* update rate estimate */ - GST_BASE_VIDEO_CODEC (base_video_encoder)->bytes += - gst_buffer_get_size (frame->src_buffer); - if (GST_CLOCK_TIME_IS_VALID (frame->presentation_duration)) { - GST_BASE_VIDEO_CODEC (base_video_encoder)->time += - frame->presentation_duration; - } else { - /* better none than nothing valid */ - GST_BASE_VIDEO_CODEC (base_video_encoder)->time = GST_CLOCK_TIME_NONE; - } - - if (G_UNLIKELY (GST_BASE_VIDEO_CODEC (base_video_encoder)->discont)) { - GST_LOG_OBJECT (base_video_encoder, "marking discont"); - GST_BUFFER_FLAG_SET (frame->src_buffer, GST_BUFFER_FLAG_DISCONT); - GST_BASE_VIDEO_CODEC (base_video_encoder)->discont = FALSE; - } - - if (base_video_encoder_class->shape_output) { - ret = base_video_encoder_class->shape_output (base_video_encoder, frame); - } else { - ret = - gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), - frame->src_buffer); - } - frame->src_buffer = NULL; - -done: - /* handed out */ - GST_BASE_VIDEO_CODEC (base_video_encoder)->frames = - g_list_remove (GST_BASE_VIDEO_CODEC (base_video_encoder)->frames, frame); - - gst_video_frame_state_unref (frame); - - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); - - return ret; -} - -/** - * gst_base_video_encoder_get_state: - * @base_video_encoder: a #GstBaseVideoEncoder - * - * Get the current #GstVideoState - * - * Returns: #GstVideoState describing format of video data. - */ -const GstVideoState * -gst_base_video_encoder_get_state (GstBaseVideoEncoder * base_video_encoder) -{ - /* FIXME : Move to base codec class */ - - return &GST_BASE_VIDEO_CODEC (base_video_encoder)->state; -} - -/** - * gst_base_video_encoder_set_latency: - * @base_video_encoder: a #GstBaseVideoEncoder - * @min_latency: minimum latency - * @max_latency: maximum latency - * - * Informs baseclass of encoding latency. - */ -void -gst_base_video_encoder_set_latency (GstBaseVideoEncoder * base_video_encoder, - GstClockTime min_latency, GstClockTime max_latency) -{ - g_return_if_fail (GST_CLOCK_TIME_IS_VALID (min_latency)); - g_return_if_fail (max_latency >= min_latency); - - GST_OBJECT_LOCK (base_video_encoder); - base_video_encoder->min_latency = min_latency; - base_video_encoder->max_latency = max_latency; - GST_OBJECT_UNLOCK (base_video_encoder); - - gst_element_post_message (GST_ELEMENT_CAST (base_video_encoder), - gst_message_new_latency (GST_OBJECT_CAST (base_video_encoder))); -} - -/** - * gst_base_video_encoder_set_latency_fields: - * @base_video_encoder: a #GstBaseVideoEncoder - * @n_fields: latency in fields - * - * Informs baseclass of encoding latency in terms of fields (both min - * and max latency). - */ -void -gst_base_video_encoder_set_latency_fields (GstBaseVideoEncoder * - base_video_encoder, int n_fields) -{ - gint64 latency; - - /* 0 numerator is used for "don't know" */ - if (GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_n == 0) - return; - - latency = gst_util_uint64_scale (n_fields, - GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_d * GST_SECOND, - 2 * GST_BASE_VIDEO_CODEC (base_video_encoder)->state.fps_n); - - gst_base_video_encoder_set_latency (base_video_encoder, latency, latency); - -} - -/** - * gst_base_video_encoder_get_oldest_frame: - * @base_video_encoder: a #GstBaseVideoEncoder - * - * Get the oldest unfinished pending #GstVideoFrameState - * - * Returns: oldest unfinished pending #GstVideoFrameState - */ -GstVideoFrameState * -gst_base_video_encoder_get_oldest_frame (GstBaseVideoEncoder * - base_video_encoder) -{ - GList *g; - - /* FIXME : Move to base codec class */ - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_encoder); - g = g_list_first (GST_BASE_VIDEO_CODEC (base_video_encoder)->frames); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_encoder); - - if (g == NULL) - return NULL; - return (GstVideoFrameState *) (g->data); -} - -/* FIXME there could probably be more of these; - * get by presentation_number, by presentation_time ? */ diff --git a/omx/gstbasevideoencoder.h b/omx/gstbasevideoencoder.h deleted file mode 100644 index 5a34d4b..0000000 --- a/omx/gstbasevideoencoder.h +++ /dev/null @@ -1,185 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef - * Copyright (C) 2011 Mark Nauwelaerts . - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _GST_BASE_VIDEO_ENCODER_H_ -#define _GST_BASE_VIDEO_ENCODER_H_ - -#ifndef GST_USE_UNSTABLE_API -#warning "GstBaseVideoEncoder is unstable API and may change in future." -#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." -#endif - -#include "gstbasevideocodec.h" - -G_BEGIN_DECLS - -#define GST_TYPE_BASE_VIDEO_ENCODER \ - (gst_base_video_encoder_get_type()) -#define GST_BASE_VIDEO_ENCODER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_VIDEO_ENCODER,GstBaseVideoEncoder)) -#define GST_BASE_VIDEO_ENCODER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_VIDEO_ENCODER,GstBaseVideoEncoderClass)) -#define GST_BASE_VIDEO_ENCODER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_BASE_VIDEO_ENCODER,GstBaseVideoEncoderClass)) -#define GST_IS_BASE_VIDEO_ENCODER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_VIDEO_ENCODER)) -#define GST_IS_BASE_VIDEO_ENCODER_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_VIDEO_ENCODER)) - -/** - * GST_BASE_VIDEO_ENCODER_SINK_NAME: - * - * The name of the templates for the sink pad. - */ -#define GST_BASE_VIDEO_ENCODER_SINK_NAME "sink" -/** - * GST_BASE_VIDEO_ENCODER_SRC_NAME: - * - * The name of the templates for the source pad. - */ -#define GST_BASE_VIDEO_ENCODER_SRC_NAME "src" - -/** - * GST_BASE_VIDEO_ENCODER_FLOW_DROPPED: - * - * Returned when the event/buffer should be dropped. - */ -#define GST_BASE_VIDEO_ENCODER_FLOW_DROPPED GST_FLOW_CUSTOM_SUCCESS_1 - -typedef struct _GstBaseVideoEncoder GstBaseVideoEncoder; -typedef struct _GstBaseVideoEncoderClass GstBaseVideoEncoderClass; - -/** - * GstBaseVideoEncoder: - * - * The opaque #GstBaseVideoEncoder data structure. - */ -struct _GstBaseVideoEncoder -{ - /*< private >*/ - GstBaseVideoCodec base_video_codec; - - /*< protected >*/ - gboolean sink_clipping; - - guint64 presentation_frame_number; - int distance_from_sync; - - /*< private >*/ - /* FIXME move to real private part ? - * (and introduce a context ?) */ - gboolean drained; - gboolean at_eos; - - gint64 min_latency; - gint64 max_latency; - - GList *current_frame_events; - - GstBuffer *headers; - - GList *force_key_unit; /* List of pending forced keyunits */ - - void *padding[GST_PADDING_LARGE]; -}; - -/** - * GstBaseVideoEncoderClass: - * @start: Optional. - * Called when the element starts processing. - * Allows opening external resources. - * @stop: Optional. - * Called when the element stops processing. - * Allows closing external resources. - * @set_format: Optional. - * Notifies subclass of incoming data format. - * GstVideoInfo fields have already been - * set according to provided caps. - * @handle_frame: Provides input frame to subclass. - * @reset: Optional. - * Allows subclass (codec) to perform post-seek semantics reset. - * @finish: Optional. - * Called to request subclass to dispatch any pending remaining - * data (e.g. at EOS). - * @shape_output: Optional. - * Allows subclass to push frame downstream in whatever - * shape or form it deems appropriate. If not provided, - * provided encoded frame data is simply pushed downstream. - * @event: Optional. - * Event handler on the sink pad. This function should return - * TRUE if the event was handled and should be discarded - * (i.e. not unref'ed). - * - * Subclasses can override any of the available virtual methods or not, as - * needed. At minimum @handle_frame needs to be overridden, and @set_format - * and @get_caps are likely needed as well. - */ -struct _GstBaseVideoEncoderClass -{ - /*< private >*/ - GstBaseVideoCodecClass base_video_codec_class; - - /*< public >*/ - /* virtual methods for subclasses */ - - gboolean (*start) (GstBaseVideoEncoder *coder); - - gboolean (*stop) (GstBaseVideoEncoder *coder); - - gboolean (*set_format) (GstBaseVideoEncoder *coder, - GstVideoInfo *info); - - GstFlowReturn (*handle_frame) (GstBaseVideoEncoder *coder, - GstVideoFrameState *frame); - - gboolean (*reset) (GstBaseVideoEncoder *coder); - GstFlowReturn (*finish) (GstBaseVideoEncoder *coder); - - GstFlowReturn (*shape_output) (GstBaseVideoEncoder *coder, - GstVideoFrameState *frame); - - gboolean (*event) (GstBaseVideoEncoder *coder, - GstEvent *event); - - /*< private >*/ - /* FIXME before moving to base */ - gpointer _gst_reserved[GST_PADDING_LARGE]; -}; - -GType gst_base_video_encoder_get_type (void); - -const GstVideoState* gst_base_video_encoder_get_state (GstBaseVideoEncoder *base_video_encoder); - -GstVideoFrameState* gst_base_video_encoder_get_oldest_frame (GstBaseVideoEncoder *coder); -GstFlowReturn gst_base_video_encoder_finish_frame (GstBaseVideoEncoder *base_video_encoder, - GstVideoFrameState *frame); - -void gst_base_video_encoder_set_latency (GstBaseVideoEncoder *base_video_encoder, - GstClockTime min_latency, GstClockTime max_latency); -void gst_base_video_encoder_set_latency_fields (GstBaseVideoEncoder *base_video_encoder, - int n_fields); -void gst_base_video_encoder_set_headers (GstBaseVideoEncoder *base_video_encoder, - GstBuffer *headers); -G_END_DECLS - -#endif - diff --git a/omx/gstbasevideoutils.c b/omx/gstbasevideoutils.c deleted file mode 100644 index 507ad07..0000000 --- a/omx/gstbasevideoutils.c +++ /dev/null @@ -1,159 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstbasevideoutils.h" - -#include - -GST_DEBUG_CATEGORY_EXTERN (basevideocodec_debug); -#define GST_CAT_DEFAULT basevideocodec_debug - - -gboolean -gst_base_video_rawvideo_convert (GstVideoState * state, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = FALSE; - - g_return_val_if_fail (dest_format != NULL, FALSE); - g_return_val_if_fail (dest_value != NULL, FALSE); - - if (src_format == *dest_format || src_value == 0 || src_value == -1) { - *dest_value = src_value; - return TRUE; - } - - if (src_format == GST_FORMAT_BYTES && - *dest_format == GST_FORMAT_DEFAULT && state->bytes_per_picture != 0) { - /* convert bytes to frames */ - *dest_value = gst_util_uint64_scale_int (src_value, 1, - state->bytes_per_picture); - res = TRUE; - } else if (src_format == GST_FORMAT_DEFAULT && - *dest_format == GST_FORMAT_BYTES && state->bytes_per_picture != 0) { - /* convert bytes to frames */ - *dest_value = src_value * state->bytes_per_picture; - res = TRUE; - } else if (src_format == GST_FORMAT_DEFAULT && - *dest_format == GST_FORMAT_TIME && state->fps_n != 0) { - /* convert frames to time */ - /* FIXME add segment time? */ - *dest_value = gst_util_uint64_scale (src_value, - GST_SECOND * state->fps_d, state->fps_n); - res = TRUE; - } else if (src_format == GST_FORMAT_TIME && - *dest_format == GST_FORMAT_DEFAULT && state->fps_d != 0) { - /* convert time to frames */ - /* FIXME subtract segment time? */ - *dest_value = gst_util_uint64_scale (src_value, state->fps_n, - GST_SECOND * state->fps_d); - res = TRUE; - } else if (src_format == GST_FORMAT_TIME && - *dest_format == GST_FORMAT_BYTES && state->fps_d != 0 && - state->bytes_per_picture != 0) { - /* convert time to frames */ - /* FIXME subtract segment time? */ - *dest_value = gst_util_uint64_scale (src_value, - state->fps_n * state->bytes_per_picture, GST_SECOND * state->fps_d); - res = TRUE; - } else if (src_format == GST_FORMAT_BYTES && - *dest_format == GST_FORMAT_TIME && state->fps_n != 0 && - state->bytes_per_picture != 0) { - /* convert frames to time */ - /* FIXME add segment time? */ - *dest_value = gst_util_uint64_scale (src_value, - GST_SECOND * state->fps_d, state->fps_n * state->bytes_per_picture); - res = TRUE; - } - - return res; -} - -gboolean -gst_base_video_encoded_video_convert (GstVideoState * state, - gint64 bytes, gint64 time, GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = FALSE; - - g_return_val_if_fail (dest_format != NULL, FALSE); - g_return_val_if_fail (dest_value != NULL, FALSE); - - if (G_UNLIKELY (src_format == *dest_format || src_value == 0 || - src_value == -1)) { - if (dest_value) - *dest_value = src_value; - return TRUE; - } - - if (bytes <= 0 || time <= 0) { - GST_DEBUG ("not enough metadata yet to convert"); - goto exit; - } - - switch (src_format) { - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = gst_util_uint64_scale (src_value, time, bytes); - res = TRUE; - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - *dest_value = gst_util_uint64_scale (src_value, bytes, time); - res = TRUE; - break; - default: - res = FALSE; - } - break; - default: - GST_DEBUG ("unhandled conversion from %d to %d", src_format, - *dest_format); - res = FALSE; - } - -exit: - return res; -} - -GstClockTime -gst_video_state_get_timestamp (const GstVideoState * state, - GstSegment * segment, int frame_number) -{ - if (frame_number < 0) { - return segment->start - - (gint64) gst_util_uint64_scale (-frame_number, - state->fps_d * GST_SECOND, state->fps_n); - } else { - return segment->start + - gst_util_uint64_scale (frame_number, - state->fps_d * GST_SECOND, state->fps_n); - } -} diff --git a/omx/gstbasevideoutils.h b/omx/gstbasevideoutils.h deleted file mode 100644 index aeca2d1..0000000 --- a/omx/gstbasevideoutils.h +++ /dev/null @@ -1,46 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _GST_BASE_VIDEO_UTILS_H_ -#define _GST_BASE_VIDEO_UTILS_H_ - -#ifndef GST_USE_UNSTABLE_API -#warning "GstBaseVideoCodec is unstable API and may change in future." -#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." -#endif - -#include -#include -#include "gstbasevideocodec.h" - -G_BEGIN_DECLS - -gboolean gst_base_video_rawvideo_convert (GstVideoState *state, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 *dest_value); -gboolean gst_base_video_encoded_video_convert (GstVideoState * state, - gint64 bytes, gint64 time, GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value); - -GstClockTime gst_video_state_get_timestamp (const GstVideoState *state, - GstSegment *segment, int frame_number); - -G_END_DECLS - -#endif diff --git a/omx/gstomxh263dec.c b/omx/gstomxh263dec.c index aaa4f2e..8cc5fd6 100644 --- a/omx/gstomxh263dec.c +++ b/omx/gstomxh263dec.c @@ -31,9 +31,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_h263_dec_debug_category); /* prototypes */ static gboolean gst_omx_h263_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); static gboolean gst_omx_h263_dec_set_format (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); enum { @@ -78,14 +78,14 @@ gst_omx_h263_dec_init (GstOMXH263Dec * self) static gboolean gst_omx_h263_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state) + GstOMXPort * port, GstVideoCodecState * state) { return FALSE; } static gboolean gst_omx_h263_dec_set_format (GstOMXVideoDec * dec, GstOMXPort * port, - GstVideoState * state) + GstVideoCodecState * state) { gboolean ret; OMX_PARAM_PORTDEFINITIONTYPE port_def; diff --git a/omx/gstomxh263enc.c b/omx/gstomxh263enc.c index 615c58e..a97f98b 100644 --- a/omx/gstomxh263enc.c +++ b/omx/gstomxh263enc.c @@ -31,9 +31,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_h263_enc_debug_category); /* prototypes */ static gboolean gst_omx_h263_enc_set_format (GstOMXVideoEnc * enc, - GstOMXPort * port, GstVideoInfo * state); + GstOMXPort * port, GstVideoCodecState * state); static GstCaps *gst_omx_h263_enc_get_caps (GstOMXVideoEnc * enc, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); enum { @@ -77,7 +77,7 @@ gst_omx_h263_enc_init (GstOMXH263Enc * self) static gboolean gst_omx_h263_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, - GstVideoInfo * info) + GstVideoCodecState * state) { GstOMXH263Enc *self = GST_OMX_H263_ENC (enc); GstCaps *peercaps; @@ -87,8 +87,8 @@ gst_omx_h263_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, OMX_ERRORTYPE err; guint profile_id, level_id; - peercaps = gst_pad_peer_query_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (enc), - gst_pad_get_pad_template_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (enc))); + peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc), + gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc))); if (peercaps) { GstStructure *s; @@ -195,7 +195,7 @@ unsupported_level: static GstCaps * gst_omx_h263_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port, - GstVideoState * state) + GstVideoCodecState * state) { GstOMXH263Enc *self = GST_OMX_H263_ENC (enc); GstCaps *caps; @@ -203,16 +203,7 @@ gst_omx_h263_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port, OMX_VIDEO_PARAM_PROFILELEVELTYPE param; guint profile, level; - caps = - gst_caps_new_simple ("video/x-h263", "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, NULL); - - if (state->fps_n != 0) - gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, NULL); - if (state->par_n != 1 || state->par_d != 1) - gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, - state->par_n, state->par_d, NULL); + caps = gst_caps_new_empty_simple ("video/x-h263"); GST_OMX_INIT_STRUCT (¶m); param.nPortIndex = GST_OMX_VIDEO_ENC (self)->out_port->index; diff --git a/omx/gstomxh264dec.c b/omx/gstomxh264dec.c index 66cc3f1..b9e560f 100644 --- a/omx/gstomxh264dec.c +++ b/omx/gstomxh264dec.c @@ -31,9 +31,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_h264_dec_debug_category); /* prototypes */ static gboolean gst_omx_h264_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); static gboolean gst_omx_h264_dec_set_format (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); enum { @@ -79,14 +79,14 @@ gst_omx_h264_dec_init (GstOMXH264Dec * self) static gboolean gst_omx_h264_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state) + GstOMXPort * port, GstVideoCodecState * state) { return FALSE; } static gboolean gst_omx_h264_dec_set_format (GstOMXVideoDec * dec, GstOMXPort * port, - GstVideoState * state) + GstVideoCodecState * state) { gboolean ret; OMX_PARAM_PORTDEFINITIONTYPE port_def; diff --git a/omx/gstomxh264enc.c b/omx/gstomxh264enc.c index 9d34e4e..4035366 100644 --- a/omx/gstomxh264enc.c +++ b/omx/gstomxh264enc.c @@ -31,11 +31,11 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_h264_enc_debug_category); /* prototypes */ static gboolean gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, - GstOMXPort * port, GstVideoInfo * info); + GstOMXPort * port, GstVideoCodecState * state); static GstCaps *gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); static GstFlowReturn gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * - self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoFrameState * frame); + self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame); enum { @@ -81,7 +81,7 @@ gst_omx_h264_enc_init (GstOMXH264Enc * self) static gboolean gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, - GstVideoInfo * info) + GstVideoCodecState * state) { GstOMXH264Enc *self = GST_OMX_H264_ENC (enc); GstCaps *peercaps; @@ -91,8 +91,8 @@ gst_omx_h264_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, OMX_ERRORTYPE err; const gchar *profile_string, *level_string; - peercaps = gst_pad_peer_query_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (enc), - gst_pad_get_pad_template_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (enc))); + peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc), + gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc))); if (peercaps) { GstStructure *s; @@ -197,7 +197,7 @@ unsupported_level: static GstCaps * gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port, - GstVideoState * state) + GstVideoCodecState * state) { GstOMXH264Enc *self = GST_OMX_H264_ENC (enc); GstCaps *caps; @@ -205,16 +205,7 @@ gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port, OMX_VIDEO_PARAM_PROFILELEVELTYPE param; const gchar *profile, *level; - caps = - gst_caps_new_simple ("video/x-h264", "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, NULL); - - if (state->fps_n != 0) - gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, NULL); - if (state->par_n != 1 || state->par_d != 1) - gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, - state->par_n, state->par_d, NULL); + caps = gst_caps_new_empty_simple ("video/x-h264"); GST_OMX_INIT_STRUCT (¶m); param.nPortIndex = GST_OMX_VIDEO_ENC (self)->out_port->index; @@ -315,7 +306,7 @@ gst_omx_h264_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port, static GstFlowReturn gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, - GstOMXBuffer * buf, GstVideoFrameState * frame) + GstOMXBuffer * buf, GstVideoCodecFrame * frame) { if (buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { /* The codec data is SPS/PPS with a startcode => bytestream stream format @@ -325,6 +316,7 @@ gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, if (buf->omx_buf->nFilledLen >= 4 && GST_READ_UINT32_BE (buf->omx_buf->pBuffer + buf->omx_buf->nOffset) == 0x00000001) { + GList *l = NULL; GstBuffer *hdrs; GstMapInfo map = GST_MAP_INFO_INIT; @@ -338,8 +330,8 @@ gst_omx_h264_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, buf->omx_buf->pBuffer + buf->omx_buf->nOffset, buf->omx_buf->nFilledLen); gst_buffer_unmap (hdrs, &map); - gst_base_video_encoder_set_headers (GST_BASE_VIDEO_ENCODER (self), hdrs); - gst_buffer_unref (hdrs); + l = g_list_append (l, hdrs); + gst_video_encoder_set_headers (GST_VIDEO_ENCODER (self), l); } } diff --git a/omx/gstomxmpeg4videodec.c b/omx/gstomxmpeg4videodec.c index e52e936..456c628 100644 --- a/omx/gstomxmpeg4videodec.c +++ b/omx/gstomxmpeg4videodec.c @@ -31,9 +31,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_mpeg4_video_dec_debug_category); /* prototypes */ static gboolean gst_omx_mpeg4_video_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); static gboolean gst_omx_mpeg4_video_dec_set_format (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); enum { @@ -81,14 +81,14 @@ gst_omx_mpeg4_video_dec_init (GstOMXMPEG4VideoDec * self) static gboolean gst_omx_mpeg4_video_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state) + GstOMXPort * port, GstVideoCodecState * state) { return FALSE; } static gboolean gst_omx_mpeg4_video_dec_set_format (GstOMXVideoDec * dec, GstOMXPort * port, - GstVideoState * state) + GstVideoCodecState * state) { gboolean ret; OMX_PARAM_PORTDEFINITIONTYPE port_def; diff --git a/omx/gstomxmpeg4videoenc.c b/omx/gstomxmpeg4videoenc.c index dc972f1..48117c2 100644 --- a/omx/gstomxmpeg4videoenc.c +++ b/omx/gstomxmpeg4videoenc.c @@ -31,9 +31,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_mpeg4_video_enc_debug_category); /* prototypes */ static gboolean gst_omx_mpeg4_video_enc_set_format (GstOMXVideoEnc * enc, - GstOMXPort * port, GstVideoInfo * info); + GstOMXPort * port, GstVideoCodecState * state); static GstCaps *gst_omx_mpeg4_video_enc_get_caps (GstOMXVideoEnc * enc, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); enum { @@ -81,7 +81,7 @@ gst_omx_mpeg4_video_enc_init (GstOMXMPEG4VideoEnc * self) static gboolean gst_omx_mpeg4_video_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, - GstVideoInfo * info) + GstVideoCodecState * state) { GstOMXMPEG4VideoEnc *self = GST_OMX_MPEG4_VIDEO_ENC (enc); GstCaps *peercaps, *intersection; @@ -91,13 +91,13 @@ gst_omx_mpeg4_video_enc_set_format (GstOMXVideoEnc * enc, GstOMXPort * port, OMX_ERRORTYPE err; const gchar *profile_string, *level_string; - peercaps = gst_pad_peer_query_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (enc), NULL); + peercaps = gst_pad_peer_query_caps (GST_VIDEO_ENCODER_SRC_PAD (enc), NULL); if (peercaps) { GstStructure *s; intersection = gst_caps_intersect (peercaps, - gst_pad_get_pad_template_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (enc))); + gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (enc))); gst_caps_unref (peercaps); if (gst_caps_is_empty (intersection)) { @@ -204,7 +204,7 @@ unsupported_level: static GstCaps * gst_omx_mpeg4_video_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port, - GstVideoState * state) + GstVideoCodecState * state) { GstOMXMPEG4VideoEnc *self = GST_OMX_MPEG4_VIDEO_ENC (enc); GstCaps *caps; @@ -214,15 +214,7 @@ gst_omx_mpeg4_video_enc_get_caps (GstOMXVideoEnc * enc, GstOMXPort * port, caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4, - "systemstream", G_TYPE_BOOLEAN, FALSE, "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, NULL); - - if (state->fps_n != 0) - gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, NULL); - if (state->par_n != 1 || state->par_d != 1) - gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, - state->par_n, state->par_d, NULL); + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); GST_OMX_INIT_STRUCT (¶m); param.nPortIndex = GST_OMX_VIDEO_ENC (self)->out_port->index; diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c index 730769e..a6869f0 100644 --- a/omx/gstomxvideodec.c +++ b/omx/gstomxvideodec.c @@ -49,18 +49,18 @@ static GstStateChangeReturn gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_omx_video_dec_start (GstBaseVideoDecoder * decoder); -static gboolean gst_omx_video_dec_stop (GstBaseVideoDecoder * decoder); -static gboolean gst_omx_video_dec_set_format (GstBaseVideoDecoder * decoder, - GstVideoState * state); -static gboolean gst_omx_video_dec_reset (GstBaseVideoDecoder * decoder); -static GstFlowReturn gst_omx_video_dec_parse_data (GstBaseVideoDecoder * - decoder, gboolean at_eos); -static GstFlowReturn gst_omx_video_dec_handle_frame (GstBaseVideoDecoder * - decoder, GstVideoFrameState * frame); -static GstFlowReturn gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder); - -static GstFlowReturn gst_omx_video_dec_drain (GstOMXVideoDec * self); +static gboolean gst_omx_video_dec_start (GstVideoDecoder * decoder); +static gboolean gst_omx_video_dec_stop (GstVideoDecoder * decoder); +static gboolean gst_omx_video_dec_set_format (GstVideoDecoder * decoder, + GstVideoCodecState * state); +static gboolean gst_omx_video_dec_reset (GstVideoDecoder * decoder, + gboolean hard); +static GstFlowReturn gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame); +static GstFlowReturn gst_omx_video_dec_finish (GstVideoDecoder * decoder); + +static GstFlowReturn gst_omx_video_dec_drain (GstOMXVideoDec * self, + gboolean is_eos); enum { @@ -75,32 +75,28 @@ enum G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec, - GST_TYPE_BASE_VIDEO_DECODER, DEBUG_INIT); + GST_TYPE_VIDEO_DECODER, DEBUG_INIT); static void gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstBaseVideoDecoderClass *base_video_decoder_class = - GST_BASE_VIDEO_DECODER_CLASS (klass); + GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass); gobject_class->finalize = gst_omx_video_dec_finalize; element_class->change_state = GST_DEBUG_FUNCPTR (gst_omx_video_dec_change_state); - base_video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_dec_start); - base_video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_dec_stop); - base_video_decoder_class->reset = GST_DEBUG_FUNCPTR (gst_omx_video_dec_reset); - base_video_decoder_class->set_format = + video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_dec_start); + video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_dec_stop); + video_decoder_class->reset = GST_DEBUG_FUNCPTR (gst_omx_video_dec_reset); + video_decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_video_dec_set_format); - base_video_decoder_class->parse_data = - GST_DEBUG_FUNCPTR (gst_omx_video_dec_parse_data); - base_video_decoder_class->handle_frame = + video_decoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_omx_video_dec_handle_frame); - base_video_decoder_class->finish = - GST_DEBUG_FUNCPTR (gst_omx_video_dec_finish); + video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_dec_finish); klass->cdata.default_src_template_caps = "video/x-raw, " "width = " GST_VIDEO_SIZE_RANGE ", " @@ -110,7 +106,7 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass) static void gst_omx_video_dec_init (GstOMXVideoDec * self) { - GST_BASE_VIDEO_DECODER (self)->packetized = TRUE; + gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE); self->drain_lock = g_mutex_new (); self->drain_cond = g_cond_new (); @@ -277,19 +273,22 @@ gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition) #define MAX_FRAME_DIST_TICKS (5 * OMX_TICKS_PER_SECOND) #define MAX_FRAME_DIST_FRAMES (100) -static GstVideoFrameState * +static GstVideoCodecFrame * _find_nearest_frame (GstOMXVideoDec * self, GstOMXBuffer * buf) { GList *l, *best_l = NULL; GList *finish_frames = NULL; - GstVideoFrameState *best = NULL; + GstVideoCodecFrame *best = NULL; guint64 best_timestamp = 0; guint64 best_diff = G_MAXUINT64; BufferIdentification *best_id = NULL; + GList *frames; - for (l = GST_BASE_VIDEO_CODEC (self)->frames; l; l = l->next) { - GstVideoFrameState *tmp = l->data; - BufferIdentification *id = tmp->coder_hook; + frames = gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)); + + for (l = frames; l; l = l->next) { + GstVideoCodecFrame *tmp = l->data; + BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp); guint64 timestamp, diff; /* This happens for frames that were just added but @@ -320,9 +319,9 @@ _find_nearest_frame (GstOMXVideoDec * self, GstOMXBuffer * buf) } if (best_id) { - for (l = GST_BASE_VIDEO_CODEC (self)->frames; l && l != best_l; l = l->next) { - GstVideoFrameState *tmp = l->data; - BufferIdentification *id = tmp->coder_hook; + for (l = frames; l && l != best_l; l = l->next) { + GstVideoCodecFrame *tmp = l->data; + BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp); guint64 diff_ticks, diff_frames; if (id->timestamp > best_timestamp) @@ -344,11 +343,16 @@ _find_nearest_frame (GstOMXVideoDec * self, GstOMXBuffer * buf) if (finish_frames) { g_warning ("Too old frames, bug in decoder -- please file a bug"); for (l = finish_frames; l; l = l->next) { - gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), - l->data); + gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), l->data); } } + if (best) + gst_video_codec_frame_ref (best); + + g_list_foreach (frames, (GFunc) gst_video_codec_frame_unref, NULL); + g_list_free (frames); + return best; } @@ -356,14 +360,15 @@ static gboolean gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, GstOMXBuffer * inbuf, GstBuffer * outbuf) { - GstVideoState *state = &GST_BASE_VIDEO_CODEC (self)->state; + GstVideoCodecState *state = + gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self)); + GstVideoInfo *vinfo = &state->info; OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->out_port->port_def; gboolean ret = FALSE; - GstVideoInfo vinfo; GstVideoFrame frame; - if (state->width != port_def->format.video.nFrameWidth || - state->height != port_def->format.video.nFrameHeight) { + if (vinfo->width != port_def->format.video.nFrameWidth || + vinfo->height != port_def->format.video.nFrameHeight) { GST_ERROR_OBJECT (self, "Width or height do not match"); goto done; } @@ -383,25 +388,24 @@ gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, GstOMXBuffer * inbuf, /* Different strides */ - gst_video_info_from_caps (&vinfo, state->caps); - - switch (state->format) { + switch (vinfo->finfo->format) { case GST_VIDEO_FORMAT_I420:{ gint i, j, height; guint8 *src, *dest; gint src_stride, dest_stride; + gst_video_frame_map (&frame, vinfo, outbuf, GST_MAP_WRITE); for (i = 0; i < 3; i++) { if (i == 0) { src_stride = port_def->format.video.nStride; - dest_stride = vinfo.stride[0]; + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i); /* XXX: Try this if no stride was set */ if (src_stride == 0) src_stride = dest_stride; } else { src_stride = port_def->format.video.nStride / 2; - dest_stride = vinfo.stride[1]; + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i); /* XXX: Try this if no stride was set */ if (src_stride == 0) @@ -418,7 +422,6 @@ gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, GstOMXBuffer * inbuf, (port_def->format.video.nSliceHeight / 2) * (port_def->format.video.nStride / 2); - gst_video_frame_map (&frame, &vinfo, outbuf, GST_MAP_WRITE); dest = GST_VIDEO_FRAME_COMP_DATA (&frame, i); height = GST_VIDEO_FRAME_HEIGHT (&frame); @@ -427,8 +430,8 @@ gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, GstOMXBuffer * inbuf, src += src_stride; dest += dest_stride; } - gst_video_frame_unmap (&frame); } + gst_video_frame_unmap (&frame); ret = TRUE; break; } @@ -437,17 +440,18 @@ gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, GstOMXBuffer * inbuf, guint8 *src, *dest; gint src_stride, dest_stride; + gst_video_frame_map (&frame, vinfo, outbuf, GST_MAP_WRITE); for (i = 0; i < 2; i++) { if (i == 0) { src_stride = port_def->format.video.nStride; - dest_stride = vinfo.stride[0]; + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i); /* XXX: Try this if no stride was set */ if (src_stride == 0) src_stride = dest_stride; } else { src_stride = port_def->format.video.nStride; - dest_stride = vinfo.stride[1]; + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i); /* XXX: Try this if no stride was set */ if (src_stride == 0) @@ -460,7 +464,6 @@ gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, GstOMXBuffer * inbuf, port_def->format.video.nSliceHeight * port_def->format.video.nStride; - gst_video_frame_map (&frame, &vinfo, outbuf, GST_MAP_WRITE); dest = GST_VIDEO_FRAME_COMP_DATA (&frame, i); height = GST_VIDEO_FRAME_HEIGHT (&frame); @@ -469,8 +472,8 @@ gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, GstOMXBuffer * inbuf, src += src_stride; dest += dest_stride; } - gst_video_frame_unmap (&frame); } + gst_video_frame_unmap (&frame); ret = TRUE; break; } @@ -492,6 +495,8 @@ done: OMX_TICKS_PER_SECOND); } + gst_video_codec_state_unref (state); + return ret; } @@ -501,7 +506,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) GstOMXVideoDecClass *klass; GstOMXPort *port = self->out_port; GstOMXBuffer *buf = NULL; - GstVideoFrameState *frame; + GstVideoCodecFrame *frame; GstFlowReturn flow_ret = GST_FLOW_OK; GstOMXAcquireBufferReturn acq_return; GstClockTimeDiff deadline; @@ -521,48 +526,52 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) return; } - if (!gst_pad_has_current_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (self)) + if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (self)) || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURED) { - GstVideoState *state = &GST_BASE_VIDEO_CODEC (self)->state; + GstVideoCodecState *state; OMX_PARAM_PORTDEFINITIONTYPE port_def; + GstVideoFormat format; GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps"); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_LOCK (self); gst_omx_port_get_port_definition (port, &port_def); g_assert (port_def.format.video.eCompressionFormat == OMX_VIDEO_CodingUnused); switch (port_def.format.video.eColorFormat) { case OMX_COLOR_FormatYUV420Planar: - state->format = GST_VIDEO_FORMAT_I420; + format = GST_VIDEO_FORMAT_I420; break; case OMX_COLOR_FormatYUV420SemiPlanar: - state->format = GST_VIDEO_FORMAT_NV12; + format = GST_VIDEO_FORMAT_NV12; break; default: GST_ERROR_OBJECT (self, "Unsupported color format: %d", port_def.format.video.eColorFormat); if (buf) gst_omx_port_release_buffer (self->out_port, buf); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); goto caps_failed; break; } - state->width = port_def.format.video.nFrameWidth; - state->height = port_def.format.video.nFrameHeight; + state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self), + format, port_def.format.video.nFrameWidth, + port_def.format.video.nFrameHeight, self->input_state); /* Take framerate and pixel-aspect-ratio from sinkpad caps */ - if (!gst_base_video_decoder_set_src_caps (GST_BASE_VIDEO_DECODER (self))) { + if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { if (buf) gst_omx_port_release_buffer (self->out_port, buf); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + gst_video_codec_state_unref (state); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); goto caps_failed; } - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + gst_video_codec_state_unref (state); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); /* Now get a buffer */ if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) @@ -585,20 +594,18 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) goto flushing; } - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_LOCK (self); frame = _find_nearest_frame (self, buf); is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); if (frame - && (deadline = gst_base_video_decoder_get_max_decode_time - (GST_BASE_VIDEO_DECODER (self), frame)) < 0) { + && (deadline = gst_video_decoder_get_max_decode_time + (GST_VIDEO_DECODER (self), frame)) < 0) { GST_WARNING_OBJECT (self, "Frame is too late, dropping (deadline %" GST_TIME_FORMAT ")", GST_TIME_ARGS (-deadline)); - flow_ret = - gst_base_video_decoder_drop_frame (GST_BASE_VIDEO_DECODER (self), - frame); + flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); } else if (!frame && buf->omx_buf->nFilledLen > 0) { GstBuffer *outbuf; @@ -610,8 +617,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) GST_ERROR_OBJECT (self, "No corresponding frame found"); outbuf = - gst_base_video_decoder_alloc_src_buffer (GST_BASE_VIDEO_DECODER - (self)); + gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self)); if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) { gst_buffer_unref (outbuf); @@ -619,38 +625,27 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) goto invalid_buffer; } - flow_ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (self), outbuf); + flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf); } else if (buf->omx_buf->nFilledLen > 0) { - if (GST_BASE_VIDEO_CODEC (self)->state.bytes_per_picture == 0) { - /* FIXME: If the sinkpad caps change we have currently no way - * to allocate new src buffers because basevideodecoder assumes - * that the caps on both pads are equivalent all the time - */ - GST_WARNING_OBJECT (self, - "Caps change pending and still have buffers for old caps -- dropping"); - } else - if (gst_base_video_decoder_alloc_src_frame (GST_BASE_VIDEO_DECODER - (self), frame) == GST_FLOW_OK) { + if ((flow_ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER + (self), frame)) == GST_FLOW_OK) { /* FIXME: This currently happens because of a race condition too. * We first need to reconfigure the output port and then the input * port if both need reconfiguration. */ - if (!gst_omx_video_dec_fill_buffer (self, buf, frame->src_buffer)) { - gst_buffer_replace (&frame->src_buffer, NULL); + if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) { + gst_buffer_replace (&frame->output_buffer, NULL); flow_ret = - gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER - (self), frame); + gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); gst_omx_port_release_buffer (self->out_port, buf); goto invalid_buffer; } + flow_ret = + gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); } - flow_ret = - gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), - frame); } else if (frame != NULL) { flow_ret = - gst_base_video_decoder_finish_frame (GST_BASE_VIDEO_DECODER (self), - frame); + gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); } if (is_eos || flow_ret == GST_FLOW_EOS) { @@ -674,14 +669,14 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) self->downstream_flow_ret = flow_ret; } else { g_assert ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_LOCK (self); flow_ret = GST_FLOW_EOS; } if (flow_ret != GST_FLOW_OK) goto flow_error; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); return; @@ -691,9 +686,8 @@ component_error: ("OpenMAX component in error state %s (0x%08x)", gst_omx_component_get_last_error_string (self->component), gst_omx_component_get_last_error (self->component))); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), - gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; self->started = FALSE; return; @@ -702,7 +696,7 @@ component_error: flushing: { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_FLUSHING; self->started = FALSE; return; @@ -713,19 +707,19 @@ flow_error: if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); } self->started = FALSE; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); return; } @@ -733,9 +727,8 @@ reconfigure_error: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Unable to reconfigure output port")); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), - gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; self->started = FALSE; return; @@ -745,21 +738,19 @@ invalid_buffer: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Invalid sized input buffer")); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), - gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; self->started = FALSE; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); return; } caps_failed: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps")); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), - gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; self->started = FALSE; return; @@ -767,7 +758,7 @@ caps_failed: } static gboolean -gst_omx_video_dec_start (GstBaseVideoDecoder * decoder) +gst_omx_video_dec_start (GstVideoDecoder * decoder) { GstOMXVideoDec *self; gboolean ret; @@ -778,14 +769,14 @@ gst_omx_video_dec_start (GstBaseVideoDecoder * decoder) self->eos = FALSE; self->downstream_flow_ret = GST_FLOW_OK; ret = - gst_pad_start_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self), (GstTaskFunction) gst_omx_video_dec_loop, self, NULL); return ret; } static gboolean -gst_omx_video_dec_stop (GstBaseVideoDecoder * decoder) +gst_omx_video_dec_stop (GstVideoDecoder * decoder) { GstOMXVideoDec *self; @@ -796,7 +787,7 @@ gst_omx_video_dec_stop (GstBaseVideoDecoder * decoder) gst_omx_port_set_flushing (self->in_port, TRUE); gst_omx_port_set_flushing (self->out_port, TRUE); - gst_pad_stop_task (GST_BASE_VIDEO_CODEC_SRC_PAD (decoder)); + gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder)); if (gst_omx_component_get_state (self->component, 0) > OMX_StateIdle) gst_omx_component_set_state (self->component, OMX_StateIdle); @@ -814,6 +805,10 @@ gst_omx_video_dec_stop (GstBaseVideoDecoder * decoder) gst_buffer_replace (&self->codec_data, NULL); + if (self->input_state) + gst_video_codec_state_unref (self->input_state); + self->input_state = NULL; + GST_DEBUG_OBJECT (self, "Stopped decoder"); return TRUE; @@ -823,7 +818,8 @@ static gboolean gst_omx_video_dec_negotiate (GstOMXVideoDec * self) { GstOMXPort *port = self->out_port; - GstVideoState *state = &GST_BASE_VIDEO_CODEC (self)->state; + GstVideoCodecState *state = self->input_state; + GstVideoInfo *info = &state->info; OMX_VIDEO_PARAM_PORTFORMATTYPE param; OMX_ERRORTYPE err; GstCaps *comp_supported_caps; @@ -835,10 +831,10 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self) const gchar *format_str; templ_caps = - gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_VIDEO_CODEC_SRC_PAD + gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_DECODER_SRC_PAD (self))); peer_caps = - gst_pad_peer_query_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (self), templ_caps); + gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (self), templ_caps); if (peer_caps) { intersection = peer_caps; gst_caps_unref (templ_caps); @@ -849,10 +845,10 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self) GST_OMX_INIT_STRUCT (¶m); param.nPortIndex = port->index; param.nIndex = 0; - if (state->fps_n == 0) + if (info->fps_n == 0) param.xFramerate = 0; else - param.xFramerate = (state->fps_n << 16) / (state->fps_d); + param.xFramerate = (info->fps_n << 16) / (info->fps_d); old_index = -1; comp_supported_caps = gst_caps_new_empty (); @@ -895,7 +891,6 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self) intersection = tmp; } - if (gst_caps_is_empty (intersection)) { gst_caps_unref (intersection); GST_ERROR_OBJECT (self, "Empty caps"); @@ -942,11 +937,12 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self) } static gboolean -gst_omx_video_dec_set_format (GstBaseVideoDecoder * decoder, - GstVideoState * state) +gst_omx_video_dec_set_format (GstVideoDecoder * decoder, + GstVideoCodecState * state) { GstOMXVideoDec *self; GstOMXVideoDecClass *klass; + GstVideoInfo *info = &state->info; gboolean is_format_change = FALSE; gboolean needs_disable = FALSE; OMX_PARAM_PORTDEFINITIONTYPE port_def; @@ -961,12 +957,12 @@ gst_omx_video_dec_set_format (GstBaseVideoDecoder * decoder, /* Check if the caps change is a real format change or if only irrelevant * parts of the caps have changed or nothing at all. */ - is_format_change |= port_def.format.video.nFrameWidth != state->width; - is_format_change |= port_def.format.video.nFrameHeight != state->height; + is_format_change |= port_def.format.video.nFrameWidth != info->width; + is_format_change |= port_def.format.video.nFrameHeight != info->height; is_format_change |= (port_def.format.video.xFramerate == 0 - && state->fps_n != 0) + && info->fps_n != 0) || (port_def.format.video.xFramerate != - (state->fps_n << 16) / (state->fps_d)); + (info->fps_n << 16) / (info->fps_d)); is_format_change |= (self->codec_data != state->codec_data); if (klass->is_format_change) is_format_change |= klass->is_format_change (self, self->in_port, state); @@ -981,18 +977,21 @@ gst_omx_video_dec_set_format (GstBaseVideoDecoder * decoder, if (needs_disable && !is_format_change) { GST_DEBUG_OBJECT (self, "Already running and caps did not change the format"); + if (self->input_state) + gst_video_codec_state_unref (self->input_state); + self->input_state = gst_video_codec_state_ref (state); return TRUE; } if (needs_disable && is_format_change) { - gst_omx_video_dec_drain (self); + gst_omx_video_dec_drain (self, FALSE); if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) { - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); - gst_omx_video_dec_stop (GST_BASE_VIDEO_DECODER (self)); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); + gst_omx_video_dec_stop (GST_VIDEO_DECODER (self)); gst_omx_video_dec_close (self); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_LOCK (self); if (!gst_omx_video_dec_open (self)) return FALSE; @@ -1005,14 +1004,17 @@ gst_omx_video_dec_set_format (GstBaseVideoDecoder * decoder, if (gst_omx_port_set_enabled (self->in_port, FALSE) != OMX_ErrorNone) return FALSE; } + if (self->input_state) + gst_video_codec_state_unref (self->input_state); + self->input_state = NULL; } - port_def.format.video.nFrameWidth = state->width; - port_def.format.video.nFrameHeight = state->height; - if (state->fps_n == 0) + port_def.format.video.nFrameWidth = info->width; + port_def.format.video.nFrameHeight = info->height; + if (info->fps_n == 0) port_def.format.video.xFramerate = 0; else - port_def.format.video.xFramerate = (state->fps_n << 16) / (state->fps_d); + port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d); if (!gst_omx_port_update_port_definition (self->in_port, &port_def)) return FALSE; @@ -1027,6 +1029,7 @@ gst_omx_video_dec_set_format (GstBaseVideoDecoder * decoder, } gst_buffer_replace (&self->codec_data, state->codec_data); + self->input_state = gst_video_codec_state_ref (state); if (!gst_omx_video_dec_negotiate (self)) return FALSE; @@ -1073,33 +1076,33 @@ gst_omx_video_dec_set_format (GstBaseVideoDecoder * decoder, /* Start the srcpad loop again */ self->downstream_flow_ret = GST_FLOW_OK; - gst_pad_start_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self), (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL); return TRUE; } static gboolean -gst_omx_video_dec_reset (GstBaseVideoDecoder * decoder) +gst_omx_video_dec_reset (GstVideoDecoder * decoder, gboolean hard) { GstOMXVideoDec *self; self = GST_OMX_VIDEO_DEC (decoder); - GST_DEBUG_OBJECT (self, "Resetting decoder"); + /* FIXME: Handle different values of hard */ - gst_omx_video_dec_drain (self); + GST_DEBUG_OBJECT (self, "Resetting decoder"); gst_omx_port_set_flushing (self->in_port, TRUE); gst_omx_port_set_flushing (self->out_port, TRUE); /* Wait until the srcpad loop is finished, - * unlock GST_BASE_VIDEO_CODEC_STREAM_LOCK to prevent deadlocks + * unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks * caused by using this lock from inside the loop function */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); - GST_PAD_STREAM_LOCK (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); - GST_PAD_STREAM_UNLOCK (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); + GST_PAD_STREAM_LOCK (GST_VIDEO_DECODER_SRC_PAD (self)); + GST_PAD_STREAM_UNLOCK (GST_VIDEO_DECODER_SRC_PAD (self)); + GST_VIDEO_DECODER_STREAM_LOCK (self); gst_omx_port_set_flushing (self->in_port, FALSE); gst_omx_port_set_flushing (self->out_port, FALSE); @@ -1108,7 +1111,7 @@ gst_omx_video_dec_reset (GstBaseVideoDecoder * decoder) self->last_upstream_ts = 0; self->eos = FALSE; self->downstream_flow_ret = GST_FLOW_OK; - gst_pad_start_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self), (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL); GST_DEBUG_OBJECT (self, "Reset decoder"); @@ -1117,14 +1120,8 @@ gst_omx_video_dec_reset (GstBaseVideoDecoder * decoder) } static GstFlowReturn -gst_omx_video_dec_parse_data (GstBaseVideoDecoder * decoder, gboolean at_eos) -{ - return GST_FLOW_OK; -} - -static GstFlowReturn -gst_omx_video_dec_handle_frame (GstBaseVideoDecoder * decoder, - GstVideoFrameState * frame) +gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame) { GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR; GstOMXVideoDec *self; @@ -1144,8 +1141,8 @@ gst_omx_video_dec_handle_frame (GstBaseVideoDecoder * decoder, return GST_FLOW_EOS; } - timestamp = frame->presentation_timestamp; - duration = frame->presentation_duration; + timestamp = frame->pts; + duration = frame->duration; if (self->downstream_flow_ret != GST_FLOW_OK) { GST_ERROR_OBJECT (self, "Downstream returned %s", @@ -1165,13 +1162,13 @@ gst_omx_video_dec_handle_frame (GstBaseVideoDecoder * decoder, } } - while (offset < gst_buffer_get_size (frame->sink_buffer)) { + while (offset < gst_buffer_get_size (frame->input_buffer)) { /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); acq_ret = gst_omx_port_acquire_buffer (self->in_port, &buf); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_LOCK (self); if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) { goto component_error; @@ -1237,7 +1234,7 @@ gst_omx_video_dec_handle_frame (GstBaseVideoDecoder * decoder, if (offset != 0 && duration != GST_CLOCK_TIME_NONE) { timestamp_offset = gst_util_uint64_scale (offset, duration, - gst_buffer_get_size (frame->sink_buffer)); + gst_buffer_get_size (frame->input_buffer)); } if (timestamp != GST_CLOCK_TIME_NONE) { @@ -1249,21 +1246,19 @@ gst_omx_video_dec_handle_frame (GstBaseVideoDecoder * decoder, if (duration != GST_CLOCK_TIME_NONE) { buf->omx_buf->nTickCount = gst_util_uint64_scale (buf->omx_buf->nFilledLen, duration, - gst_buffer_get_size (frame->sink_buffer)); + gst_buffer_get_size (frame->input_buffer)); self->last_upstream_ts += duration; } if (offset == 0) { BufferIdentification *id = g_slice_new0 (BufferIdentification); - if (!GST_BUFFER_FLAG_IS_SET (frame->sink_buffer, - GST_BUFFER_FLAG_DELTA_UNIT)) + if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) buf->omx_buf->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; id->timestamp = buf->omx_buf->nTimeStamp; - frame->coder_hook = id; - frame->coder_hook_destroy_notify = - (GDestroyNotify) buffer_identification_free; + gst_video_codec_frame_set_user_data (frame, id, + (GDestroyNotify) buffer_identification_free); } /* TODO: Set flags @@ -1319,66 +1314,17 @@ reconfigure_error: } static GstFlowReturn -gst_omx_video_dec_finish (GstBaseVideoDecoder * decoder) +gst_omx_video_dec_finish (GstVideoDecoder * decoder) { GstOMXVideoDec *self; - GstOMXVideoDecClass *klass; - GstOMXBuffer *buf; - GstOMXAcquireBufferReturn acq_ret; self = GST_OMX_VIDEO_DEC (decoder); - klass = GST_OMX_VIDEO_DEC_GET_CLASS (self); - - GST_DEBUG_OBJECT (self, "Sending EOS to the component"); - - /* Don't send EOS buffer twice, this doesn't work */ - if (self->eos) { - GST_DEBUG_OBJECT (self, "Component is already EOS"); - return GST_BASE_VIDEO_DECODER_FLOW_DROPPED; - } - self->eos = TRUE; - - if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) { - GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers"); - - /* Insert a NULL into the queue to signal EOS */ - gst_omx_rec_mutex_lock (&self->out_port->port_lock); - g_queue_push_tail (self->out_port->pending_buffers, NULL); - g_cond_broadcast (self->out_port->port_cond); - gst_omx_rec_mutex_unlock (&self->out_port->port_lock); - - return GST_BASE_VIDEO_DECODER_FLOW_DROPPED; - } - - /* Make sure to release the base class stream lock, otherwise - * _loop() can't call _finish_frame() and we might block forever - * because no input buffers are released */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); - - /* Send an EOS buffer to the component and let the base - * class drop the EOS event. We will send it later when - * the EOS buffer arrives on the output port. */ - acq_ret = gst_omx_port_acquire_buffer (self->in_port, &buf); - if (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK) { - buf->omx_buf->nFilledLen = 0; - buf->omx_buf->nTimeStamp = - gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND, - GST_SECOND); - buf->omx_buf->nTickCount = 0; - buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS; - gst_omx_port_release_buffer (self->in_port, buf); - GST_DEBUG_OBJECT (self, "Sent EOS to the component"); - } else { - GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", acq_ret); - } - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); - return GST_BASE_VIDEO_DECODER_FLOW_DROPPED; + return gst_omx_video_dec_drain (self, TRUE); } static GstFlowReturn -gst_omx_video_dec_drain (GstOMXVideoDec * self) +gst_omx_video_dec_drain (GstOMXVideoDec * self, gboolean is_eos) { GstOMXVideoDecClass *klass; GstOMXBuffer *buf; @@ -1399,6 +1345,8 @@ gst_omx_video_dec_drain (GstOMXVideoDec * self) GST_DEBUG_OBJECT (self, "Component is EOS already"); return GST_FLOW_OK; } + if (is_eos) + self->eos = TRUE; if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) { GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers"); @@ -1408,14 +1356,14 @@ gst_omx_video_dec_drain (GstOMXVideoDec * self) /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_DECODER_STREAM_UNLOCK (self); /* Send an EOS buffer to the component and let the base * class drop the EOS event. We will send it later when * the EOS buffer arrives on the output port. */ acq_ret = gst_omx_port_acquire_buffer (self->in_port, &buf); if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) { - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_LOCK (self); GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d", acq_ret); return GST_FLOW_ERROR; @@ -1446,7 +1394,7 @@ gst_omx_video_dec_drain (GstOMXVideoDec * self) } g_mutex_unlock (self->drain_lock); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_DECODER_STREAM_LOCK (self); self->started = FALSE; diff --git a/omx/gstomxvideodec.h b/omx/gstomxvideodec.h index a22b7b2..914dce4 100644 --- a/omx/gstomxvideodec.h +++ b/omx/gstomxvideodec.h @@ -22,7 +22,7 @@ #define __GST_OMX_VIDEO_DEC_H__ #include -#include "gstbasevideodecoder.h" +#include #include "gstomx.h" @@ -46,7 +46,7 @@ typedef struct _GstOMXVideoDecClass GstOMXVideoDecClass; struct _GstOMXVideoDec { - GstBaseVideoDecoder parent; + GstVideoDecoder parent; /* < protected > */ GstOMXCore *core; @@ -54,6 +54,7 @@ struct _GstOMXVideoDec GstOMXPort *in_port, *out_port; /* < private > */ + GstVideoCodecState *input_state; GstBuffer *codec_data; /* TRUE if the component is configured and saw * the first buffer */ @@ -75,13 +76,13 @@ struct _GstOMXVideoDec struct _GstOMXVideoDecClass { - GstBaseVideoDecoderClass parent_class; + GstVideoDecoderClass parent_class; GstOMXClassData cdata; - gboolean (*is_format_change) (GstOMXVideoDec * self, GstOMXPort * port, GstVideoState * state); - gboolean (*set_format) (GstOMXVideoDec * self, GstOMXPort * port, GstVideoState * state); - GstFlowReturn (*prepare_frame) (GstOMXVideoDec * self, GstVideoFrameState *frame); + gboolean (*is_format_change) (GstOMXVideoDec * self, GstOMXPort * port, GstVideoCodecState * state); + gboolean (*set_format) (GstOMXVideoDec * self, GstOMXPort * port, GstVideoCodecState * state); + GstFlowReturn (*prepare_frame) (GstOMXVideoDec * self, GstVideoCodecFrame *frame); }; GType gst_omx_video_dec_get_type (void); diff --git a/omx/gstomxvideoenc.c b/omx/gstomxvideoenc.c index 7d94b31..ca4f572 100644 --- a/omx/gstomxvideoenc.c +++ b/omx/gstomxvideoenc.c @@ -78,19 +78,21 @@ static GstStateChangeReturn gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_omx_video_enc_start (GstBaseVideoEncoder * encoder); -static gboolean gst_omx_video_enc_stop (GstBaseVideoEncoder * encoder); -static gboolean gst_omx_video_enc_set_format (GstBaseVideoEncoder * encoder, - GstVideoInfo * info); -static gboolean gst_omx_video_enc_reset (GstBaseVideoEncoder * encoder); -static GstFlowReturn gst_omx_video_enc_handle_frame (GstBaseVideoEncoder * - encoder, GstVideoFrameState * frame); -static gboolean gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder); - -static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self); +static gboolean gst_omx_video_enc_start (GstVideoEncoder * encoder); +static gboolean gst_omx_video_enc_stop (GstVideoEncoder * encoder); +static gboolean gst_omx_video_enc_set_format (GstVideoEncoder * encoder, + GstVideoCodecState * state); +static gboolean gst_omx_video_enc_reset (GstVideoEncoder * encoder, + gboolean hard); +static GstFlowReturn gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder, + GstVideoCodecFrame * frame); +static gboolean gst_omx_video_enc_finish (GstVideoEncoder * encoder); + +static GstFlowReturn gst_omx_video_enc_drain (GstOMXVideoEnc * self, + gboolean at_eos); static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * - self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoFrameState * frame); + self, GstOMXPort * port, GstOMXBuffer * buf, GstVideoCodecFrame * frame); enum { @@ -116,15 +118,14 @@ enum "debug category for gst-omx video encoder base class"); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoEnc, gst_omx_video_enc, - GST_TYPE_BASE_VIDEO_ENCODER, DEBUG_INIT); + GST_TYPE_VIDEO_ENCODER, DEBUG_INIT); static void gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstBaseVideoEncoderClass *base_video_encoder_class = - GST_BASE_VIDEO_ENCODER_CLASS (klass); + GstVideoEncoderClass *video_encoder_class = GST_VIDEO_ENCODER_CLASS (klass); gobject_class->finalize = gst_omx_video_enc_finalize; @@ -170,15 +171,14 @@ gst_omx_video_enc_class_init (GstOMXVideoEncClass * klass) element_class->change_state = GST_DEBUG_FUNCPTR (gst_omx_video_enc_change_state); - base_video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_enc_start); - base_video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_enc_stop); - base_video_encoder_class->reset = GST_DEBUG_FUNCPTR (gst_omx_video_enc_reset); - base_video_encoder_class->set_format = + video_encoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_enc_start); + video_encoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_enc_stop); + video_encoder_class->reset = GST_DEBUG_FUNCPTR (gst_omx_video_enc_reset); + video_encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_video_enc_set_format); - base_video_encoder_class->handle_frame = + video_encoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_omx_video_enc_handle_frame); - base_video_encoder_class->finish = - GST_DEBUG_FUNCPTR (gst_omx_video_enc_finish); + video_encoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_enc_finish); klass->cdata.default_sink_template_caps = "video/x-raw, " "width = " GST_VIDEO_SIZE_RANGE ", " @@ -512,19 +512,22 @@ gst_omx_video_enc_change_state (GstElement * element, GstStateChange transition) #define MAX_FRAME_DIST_TICKS (5 * OMX_TICKS_PER_SECOND) #define MAX_FRAME_DIST_FRAMES (100) -static GstVideoFrameState * +static GstVideoCodecFrame * _find_nearest_frame (GstOMXVideoEnc * self, GstOMXBuffer * buf) { GList *l, *best_l = NULL; GList *finish_frames = NULL; - GstVideoFrameState *best = NULL; + GstVideoCodecFrame *best = NULL; guint64 best_timestamp = 0; guint64 best_diff = G_MAXUINT64; BufferIdentification *best_id = NULL; + GList *frames; + + frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self)); - for (l = GST_BASE_VIDEO_CODEC (self)->frames; l; l = l->next) { - GstVideoFrameState *tmp = l->data; - BufferIdentification *id = tmp->coder_hook; + for (l = frames; l; l = l->next) { + GstVideoCodecFrame *tmp = l->data; + BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp); guint64 timestamp, diff; /* This happens for frames that were just added but @@ -555,9 +558,9 @@ _find_nearest_frame (GstOMXVideoEnc * self, GstOMXBuffer * buf) } if (best_id) { - for (l = GST_BASE_VIDEO_CODEC (self)->frames; l && l != best_l; l = l->next) { - GstVideoFrameState *tmp = l->data; - BufferIdentification *id = tmp->coder_hook; + for (l = frames; l && l != best_l; l = l->next) { + GstVideoCodecFrame *tmp = l->data; + BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp); guint64 diff_ticks, diff_frames; if (id->timestamp > best_timestamp) @@ -579,30 +582,34 @@ _find_nearest_frame (GstOMXVideoEnc * self, GstOMXBuffer * buf) if (finish_frames) { g_warning ("Too old frames, bug in encoder -- please file a bug"); for (l = finish_frames; l; l = l->next) { - gst_base_video_encoder_finish_frame (GST_BASE_VIDEO_ENCODER (self), - l->data); + gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), l->data); } } + if (best) + gst_video_codec_frame_ref (best); + + g_list_foreach (frames, (GFunc) gst_video_codec_frame_unref, NULL); + g_list_free (frames); + return best; } static GstFlowReturn gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, - GstOMXBuffer * buf, GstVideoFrameState * frame) + GstOMXBuffer * buf, GstVideoCodecFrame * frame) { GstOMXVideoEncClass *klass = GST_OMX_VIDEO_ENC_GET_CLASS (self); GstFlowReturn flow_ret = GST_FLOW_OK; if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG) && buf->omx_buf->nFilledLen > 0) { - GstCaps *caps; + GstVideoCodecState *state; GstBuffer *codec_data; GstMapInfo map = GST_MAP_INFO_INIT; + GstCaps *caps; - caps = - gst_caps_copy (gst_pad_get_current_caps (GST_BASE_VIDEO_CODEC_SRC_PAD - (self))); + caps = klass->get_caps (self, self->out_port, self->input_state); codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen); gst_buffer_map (codec_data, &map, GST_MAP_WRITE); @@ -610,13 +617,12 @@ gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, buf->omx_buf->pBuffer + buf->omx_buf->nOffset, buf->omx_buf->nFilledLen); gst_buffer_unmap (codec_data, &map); - - gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); - if (!gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (self), caps)) { - gst_caps_unref (caps); + state = + gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps, + self->input_state); + state->codec_data = codec_data; + if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) return GST_FLOW_NOT_NEGOTIATED; - } - gst_caps_unref (caps); flow_ret = GST_FLOW_OK; } else if (buf->omx_buf->nFilledLen > 0) { GstBuffer *outbuf; @@ -645,29 +651,26 @@ gst_omx_video_enc_handle_output_frame (GstOMXVideoEnc * self, GstOMXPort * port, if ((klass->cdata.hacks & GST_OMX_HACK_SYNCFRAME_FLAG_NOT_USED) || (buf->omx_buf->nFlags & OMX_BUFFERFLAG_SYNCFRAME)) { if (frame) - frame->is_sync_point = TRUE; + GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); else GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); } else { if (frame) - frame->is_sync_point = FALSE; + GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame); else GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); } if (frame) { - frame->src_buffer = outbuf; + frame->output_buffer = outbuf; flow_ret = - gst_base_video_encoder_finish_frame (GST_BASE_VIDEO_ENCODER (self), - frame); + gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame); } else { GST_ERROR_OBJECT (self, "No corresponding frame found"); - flow_ret = gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (self), outbuf); + flow_ret = gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), outbuf); } } else if (frame != NULL) { - flow_ret = - gst_base_video_encoder_finish_frame (GST_BASE_VIDEO_ENCODER (self), - frame); + flow_ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame); } return flow_ret; @@ -679,7 +682,7 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self) GstOMXVideoEncClass *klass; GstOMXPort *port = self->out_port; GstOMXBuffer *buf = NULL; - GstVideoFrameState *frame; + GstVideoCodecFrame *frame; GstFlowReturn flow_ret = GST_FLOW_OK; GstOMXAcquireBufferReturn acq_return; gboolean is_eos; @@ -698,33 +701,35 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self) return; } - if (!gst_pad_has_current_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (self)) + if (!gst_pad_has_current_caps (GST_VIDEO_ENCODER_SRC_PAD (self)) || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURED) { - GstVideoState *state = &GST_BASE_VIDEO_CODEC (self)->state; GstCaps *caps; + GstVideoCodecState *state; - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_ENCODER_STREAM_LOCK (self); GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps"); - caps = klass->get_caps (self, self->out_port, state); + caps = klass->get_caps (self, self->out_port, self->input_state); if (!caps) { if (buf) gst_omx_port_release_buffer (self->out_port, buf); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); goto caps_failed; } + state = + gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self), caps, + self->input_state); + gst_video_codec_state_unref (state); - if (!gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (self), caps)) { - gst_caps_unref (caps); + if (!gst_video_encoder_negotiate (GST_VIDEO_ENCODER (self))) { if (buf) gst_omx_port_release_buffer (self->out_port, buf); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); goto caps_failed; } - gst_caps_unref (caps); - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); /* Now get a buffer */ if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) @@ -747,7 +752,7 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self) goto flushing; } - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_ENCODER_STREAM_LOCK (self); frame = _find_nearest_frame (self, buf); is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); @@ -777,14 +782,14 @@ gst_omx_video_enc_loop (GstOMXVideoEnc * self) } else { g_assert ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_ENCODER_STREAM_LOCK (self); flow_ret = GST_FLOW_EOS; } if (flow_ret != GST_FLOW_OK) goto flow_error; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); return; @@ -794,9 +799,8 @@ component_error: ("OpenMAX component in error state %s (0x%08x)", gst_omx_component_get_last_error_string (self->component), gst_omx_component_get_last_error (self->component))); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), - gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; self->started = FALSE; return; @@ -804,7 +808,7 @@ component_error: flushing: { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_FLUSHING; self->started = FALSE; return; @@ -814,28 +818,27 @@ flow_error: if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); } self->started = FALSE; - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); return; } reconfigure_error: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Unable to reconfigure output port")); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), - gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; self->started = FALSE; return; @@ -843,9 +846,8 @@ reconfigure_error: caps_failed: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps")); - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (self), - gst_event_new_eos ()); - gst_pad_pause_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); + gst_pad_push_event (GST_VIDEO_ENCODER_SRC_PAD (self), gst_event_new_eos ()); + gst_pad_pause_task (GST_VIDEO_ENCODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; self->started = FALSE; return; @@ -853,7 +855,7 @@ caps_failed: } static gboolean -gst_omx_video_enc_start (GstBaseVideoEncoder * encoder) +gst_omx_video_enc_start (GstVideoEncoder * encoder) { GstOMXVideoEnc *self; gboolean ret; @@ -864,14 +866,14 @@ gst_omx_video_enc_start (GstBaseVideoEncoder * encoder) self->eos = FALSE; self->downstream_flow_ret = GST_FLOW_OK; ret = - gst_pad_start_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self), (GstTaskFunction) gst_omx_video_enc_loop, self, NULL); return ret; } static gboolean -gst_omx_video_enc_stop (GstBaseVideoEncoder * encoder) +gst_omx_video_enc_stop (GstVideoEncoder * encoder) { GstOMXVideoEnc *self; @@ -882,7 +884,7 @@ gst_omx_video_enc_stop (GstBaseVideoEncoder * encoder) gst_omx_port_set_flushing (self->in_port, TRUE); gst_omx_port_set_flushing (self->out_port, TRUE); - gst_pad_stop_task (GST_BASE_VIDEO_CODEC_SRC_PAD (encoder)); + gst_pad_stop_task (GST_VIDEO_ENCODER_SRC_PAD (encoder)); if (gst_omx_component_get_state (self->component, 0) > OMX_StateIdle) gst_omx_component_set_state (self->component, OMX_StateIdle); @@ -891,6 +893,10 @@ gst_omx_video_enc_stop (GstBaseVideoEncoder * encoder) self->started = FALSE; self->eos = FALSE; + if (self->input_state) + gst_video_codec_state_unref (self->input_state); + self->input_state = NULL; + g_mutex_lock (self->drain_lock); self->draining = FALSE; g_cond_broadcast (self->drain_cond); @@ -902,13 +908,14 @@ gst_omx_video_enc_stop (GstBaseVideoEncoder * encoder) } static gboolean -gst_omx_video_enc_set_format (GstBaseVideoEncoder * encoder, - GstVideoInfo * info) +gst_omx_video_enc_set_format (GstVideoEncoder * encoder, + GstVideoCodecState * state) { GstOMXVideoEnc *self; GstOMXVideoEncClass *klass; gboolean needs_disable = FALSE; OMX_PARAM_PORTDEFINITIONTYPE port_def; + GstVideoInfo *info = &state->info; self = GST_OMX_VIDEO_ENC (encoder); klass = GST_OMX_VIDEO_ENC_GET_CLASS (encoder); @@ -926,7 +933,7 @@ gst_omx_video_enc_set_format (GstBaseVideoEncoder * encoder, * format change happened we can just exit here. */ if (needs_disable) { - gst_omx_video_enc_drain (self); + gst_omx_video_enc_drain (self, FALSE); if (gst_omx_port_manual_reconfigure (self->in_port, TRUE) != OMX_ErrorNone) return FALSE; @@ -964,7 +971,7 @@ gst_omx_video_enc_set_format (GstBaseVideoEncoder * encoder, return FALSE; if (klass->set_format) { - if (!klass->set_format (self, self->in_port, info)) { + if (!klass->set_format (self, self->in_port, state)) { GST_ERROR_OBJECT (self, "Subclass failed to set the new format"); return FALSE; } @@ -1010,16 +1017,20 @@ gst_omx_video_enc_set_format (GstBaseVideoEncoder * encoder, return FALSE; } + if (self->input_state) + gst_video_codec_state_unref (self->input_state); + self->input_state = gst_video_codec_state_ref (self->input_state); + /* Start the srcpad loop again */ self->downstream_flow_ret = GST_FLOW_OK; - gst_pad_start_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self), (GstTaskFunction) gst_omx_video_enc_loop, encoder, NULL); return TRUE; } static gboolean -gst_omx_video_enc_reset (GstBaseVideoEncoder * encoder) +gst_omx_video_enc_reset (GstVideoEncoder * encoder, gboolean hard) { GstOMXVideoEnc *self; @@ -1027,18 +1038,16 @@ gst_omx_video_enc_reset (GstBaseVideoEncoder * encoder) GST_DEBUG_OBJECT (self, "Resetting encoder"); - gst_omx_video_enc_drain (self); - gst_omx_port_set_flushing (self->in_port, TRUE); gst_omx_port_set_flushing (self->out_port, TRUE); /* Wait until the srcpad loop is finished, - * unlock GST_BASE_VIDEO_CODEC_STREAM_LOCK to prevent deadlocks + * unlock GST_VIDEO_ENCODER_STREAM_LOCK to prevent deadlocks * caused by using this lock from inside the loop function */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); - GST_PAD_STREAM_LOCK (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); - GST_PAD_STREAM_UNLOCK (GST_BASE_VIDEO_CODEC_SRC_PAD (self)); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); + GST_PAD_STREAM_LOCK (GST_VIDEO_ENCODER_SRC_PAD (self)); + GST_PAD_STREAM_UNLOCK (GST_VIDEO_ENCODER_SRC_PAD (self)); + GST_VIDEO_ENCODER_STREAM_LOCK (self); gst_omx_port_set_flushing (self->in_port, FALSE); gst_omx_port_set_flushing (self->out_port, FALSE); @@ -1047,7 +1056,7 @@ gst_omx_video_enc_reset (GstBaseVideoEncoder * encoder) self->last_upstream_ts = 0; self->eos = FALSE; self->downstream_flow_ret = GST_FLOW_OK; - gst_pad_start_task (GST_BASE_VIDEO_CODEC_SRC_PAD (self), + gst_pad_start_task (GST_VIDEO_ENCODER_SRC_PAD (self), (GstTaskFunction) gst_omx_video_enc_loop, encoder, NULL); return TRUE; @@ -1057,14 +1066,15 @@ static gboolean gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, GstOMXBuffer * outbuf) { - GstVideoState *state = &GST_BASE_VIDEO_CODEC (self)->state; + GstVideoCodecState *state = + gst_video_encoder_get_output_state (GST_VIDEO_ENCODER (self)); + GstVideoInfo *info = &state->info; OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->in_port->port_def; gboolean ret = FALSE; - GstVideoInfo vinfo; GstVideoFrame frame; - if (state->width != port_def->format.video.nFrameWidth || - state->height != port_def->format.video.nFrameHeight) { + if (info->width != port_def->format.video.nFrameWidth || + info->height != port_def->format.video.nFrameHeight) { GST_ERROR_OBJECT (self, "Width or height do not match"); goto done; } @@ -1083,9 +1093,7 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, /* Different strides */ - gst_video_info_from_caps (&vinfo, state->caps); - - switch (state->format) { + switch (info->finfo->format) { case GST_VIDEO_FORMAT_I420:{ gint i, j, height; guint8 *src, *dest; @@ -1093,17 +1101,23 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, outbuf->omx_buf->nFilledLen = 0; + if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) { + GST_ERROR_OBJECT (self, "Invalid input buffer size"); + ret = FALSE; + break; + } + for (i = 0; i < 3; i++) { if (i == 0) { dest_stride = port_def->format.video.nStride; - src_stride = vinfo.stride[0]; + src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0); /* XXX: Try this if no stride was set */ if (dest_stride == 0) dest_stride = src_stride; } else { dest_stride = port_def->format.video.nStride / 2; - src_stride = vinfo.stride[1]; + src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1); /* XXX: Try this if no stride was set */ if (dest_stride == 0) @@ -1120,11 +1134,6 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, (port_def->format.video.nSliceHeight / 2) * (port_def->format.video.nStride / 2); - if (!gst_video_frame_map (&frame, &vinfo, inbuf, GST_MAP_READ)) { - GST_ERROR_OBJECT (self, "Invalid input buffer size"); - ret = FALSE; - break; - } src = GST_VIDEO_FRAME_COMP_DATA (&frame, i); height = GST_VIDEO_FRAME_HEIGHT (&frame); @@ -1141,9 +1150,8 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, src += src_stride; dest += dest_stride; } - - gst_video_frame_unmap (&frame); } + gst_video_frame_unmap (&frame); ret = TRUE; break; } @@ -1154,16 +1162,22 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, outbuf->omx_buf->nFilledLen = 0; + if (!gst_video_frame_map (&frame, info, inbuf, GST_MAP_READ)) { + GST_ERROR_OBJECT (self, "Invalid input buffer size"); + ret = FALSE; + break; + } + for (i = 0; i < 2; i++) { if (i == 0) { dest_stride = port_def->format.video.nStride; - src_stride = vinfo.stride[0]; + src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0); /* XXX: Try this if no stride was set */ if (dest_stride == 0) dest_stride = src_stride; } else { dest_stride = port_def->format.video.nStride; - src_stride = vinfo.stride[1]; + src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1); /* XXX: Try this if no stride was set */ if (dest_stride == 0) @@ -1176,13 +1190,6 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, port_def->format.video.nSliceHeight * port_def->format.video.nStride; - - - if (!gst_video_frame_map (&frame, &vinfo, inbuf, GST_MAP_READ)) { - GST_ERROR_OBJECT (self, "Invalid input buffer size"); - ret = FALSE; - break; - } src = GST_VIDEO_FRAME_COMP_DATA (&frame, i); height = GST_VIDEO_FRAME_HEIGHT (&frame); @@ -1200,8 +1207,8 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, dest += dest_stride; } - gst_video_frame_unmap (&frame); } + gst_video_frame_unmap (&frame); ret = TRUE; break; } @@ -1212,12 +1219,15 @@ gst_omx_video_enc_fill_buffer (GstOMXVideoEnc * self, GstBuffer * inbuf, } done: + + gst_video_codec_state_unref (state); + return ret; } static GstFlowReturn -gst_omx_video_enc_handle_frame (GstBaseVideoEncoder * encoder, - GstVideoFrameState * frame) +gst_omx_video_enc_handle_frame (GstVideoEncoder * encoder, + GstVideoCodecFrame * frame) { GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR; GstOMXVideoEnc *self; @@ -1246,9 +1256,9 @@ gst_omx_video_enc_handle_frame (GstBaseVideoEncoder * encoder, /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); acq_ret = gst_omx_port_acquire_buffer (self->in_port, &buf); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_ENCODER_STREAM_LOCK (self); if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) { goto component_error; @@ -1280,7 +1290,7 @@ gst_omx_video_enc_handle_frame (GstBaseVideoEncoder * encoder, } /* Now handle the frame */ - if (frame->force_keyframe) { + if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) { OMX_ERRORTYPE err; OMX_CONFIG_INTRAREFRESHVOPTYPE config; @@ -1294,37 +1304,34 @@ gst_omx_video_enc_handle_frame (GstBaseVideoEncoder * encoder, if (err != OMX_ErrorNone) GST_ERROR_OBJECT (self, "Failed to force a keyframe: %s (0x%08x)", gst_omx_error_to_string (err), err); - - frame->force_keyframe = FALSE; } /* Copy the buffer content in chunks of size as requested * by the port */ - if (!gst_omx_video_enc_fill_buffer (self, frame->sink_buffer, buf)) { + if (!gst_omx_video_enc_fill_buffer (self, frame->input_buffer, buf)) { gst_omx_port_release_buffer (self->in_port, buf); goto buffer_fill_error; } - timestamp = frame->presentation_timestamp; + timestamp = frame->pts; if (timestamp != GST_CLOCK_TIME_NONE) { buf->omx_buf->nTimeStamp = gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND); self->last_upstream_ts = timestamp; } - duration = frame->presentation_duration; + duration = frame->duration; if (duration != GST_CLOCK_TIME_NONE) { buf->omx_buf->nTickCount = gst_util_uint64_scale (buf->omx_buf->nFilledLen, duration, - gst_buffer_get_size (frame->sink_buffer)); + gst_buffer_get_size (frame->input_buffer)); self->last_upstream_ts += duration; } id = g_slice_new0 (BufferIdentification); id->timestamp = buf->omx_buf->nTimeStamp; - frame->coder_hook = id; - frame->coder_hook_destroy_notify = - (GDestroyNotify) buffer_identification_free; + gst_video_codec_frame_set_user_data (frame, id, + (GDestroyNotify) buffer_identification_free); self->started = TRUE; gst_omx_port_release_buffer (self->in_port, buf); @@ -1369,66 +1376,17 @@ buffer_fill_error: } static GstFlowReturn -gst_omx_video_enc_finish (GstBaseVideoEncoder * encoder) +gst_omx_video_enc_finish (GstVideoEncoder * encoder) { GstOMXVideoEnc *self; - GstOMXVideoEncClass *klass; - GstOMXBuffer *buf; - GstOMXAcquireBufferReturn acq_ret; self = GST_OMX_VIDEO_ENC (encoder); - klass = GST_OMX_VIDEO_ENC_GET_CLASS (self); - - GST_DEBUG_OBJECT (self, "Sending EOS to the component"); - - /* Don't send EOS buffer twice, this doesn't work */ - if (self->eos) { - GST_DEBUG_OBJECT (self, "Component is already EOS"); - return GST_BASE_VIDEO_ENCODER_FLOW_DROPPED; - } - self->eos = TRUE; - - if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) { - GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers"); - - /* Insert a NULL into the queue to signal EOS */ - gst_omx_rec_mutex_lock (&self->out_port->port_lock); - g_queue_push_tail (self->out_port->pending_buffers, NULL); - g_cond_broadcast (self->out_port->port_cond); - gst_omx_rec_mutex_unlock (&self->out_port->port_lock); - - return GST_BASE_VIDEO_ENCODER_FLOW_DROPPED; - } - - /* Make sure to release the base class stream lock, otherwise - * _loop() can't call _finish_frame() and we might block forever - * because no input buffers are released */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); - - /* Send an EOS buffer to the component and let the base - * class drop the EOS event. We will send it later when - * the EOS buffer arrives on the output port. */ - acq_ret = gst_omx_port_acquire_buffer (self->in_port, &buf); - if (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK) { - buf->omx_buf->nFilledLen = 0; - buf->omx_buf->nTimeStamp = - gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND, - GST_SECOND); - buf->omx_buf->nTickCount = 0; - buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS; - gst_omx_port_release_buffer (self->in_port, buf); - GST_DEBUG_OBJECT (self, "Sent EOS to the component"); - } else { - GST_ERROR_OBJECT (self, "Failed to acquire buffer for EOS: %d", acq_ret); - } - - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); - return GST_BASE_VIDEO_ENCODER_FLOW_DROPPED; + return gst_omx_video_enc_drain (self, TRUE); } static GstFlowReturn -gst_omx_video_enc_drain (GstOMXVideoEnc * self) +gst_omx_video_enc_drain (GstOMXVideoEnc * self, gboolean at_eos) { GstOMXVideoEncClass *klass; GstOMXBuffer *buf; @@ -1449,6 +1407,8 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self) GST_DEBUG_OBJECT (self, "Component is EOS already"); return GST_FLOW_OK; } + if (at_eos) + self->eos = TRUE; if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) { GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers"); @@ -1458,14 +1418,14 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self) /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ - GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (self); + GST_VIDEO_ENCODER_STREAM_UNLOCK (self); /* Send an EOS buffer to the component and let the base * class drop the EOS event. We will send it later when * the EOS buffer arrives on the output port. */ acq_ret = gst_omx_port_acquire_buffer (self->in_port, &buf); if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) { - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_ENCODER_STREAM_LOCK (self); GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d", acq_ret); return GST_FLOW_ERROR; @@ -1484,7 +1444,7 @@ gst_omx_video_enc_drain (GstOMXVideoEnc * self) g_cond_wait (self->drain_cond, self->drain_lock); GST_DEBUG_OBJECT (self, "Drained component"); g_mutex_unlock (self->drain_lock); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (self); + GST_VIDEO_ENCODER_STREAM_LOCK (self); self->started = FALSE; diff --git a/omx/gstomxvideoenc.h b/omx/gstomxvideoenc.h index e87e98f..41ad7c8 100644 --- a/omx/gstomxvideoenc.h +++ b/omx/gstomxvideoenc.h @@ -22,7 +22,7 @@ #define __GST_OMX_VIDEO_ENC_H__ #include -#include "gstbasevideoencoder.h" +#include #include "gstomx.h" @@ -46,7 +46,7 @@ typedef struct _GstOMXVideoEncClass GstOMXVideoEncClass; struct _GstOMXVideoEnc { - GstBaseVideoEncoder parent; + GstVideoEncoder parent; /* < protected > */ @@ -57,6 +57,7 @@ struct _GstOMXVideoEnc GstOMXPort *in_port, *out_port; /* < private > */ + GstVideoCodecState *input_state; /* TRUE if the component is configured and saw * the first buffer */ gboolean started; @@ -84,13 +85,13 @@ struct _GstOMXVideoEnc struct _GstOMXVideoEncClass { - GstBaseVideoEncoderClass parent_class; + GstVideoEncoderClass parent_class; GstOMXClassData cdata; - gboolean (*set_format) (GstOMXVideoEnc * self, GstOMXPort * port, GstVideoInfo * info ); - GstCaps *(*get_caps) (GstOMXVideoEnc * self, GstOMXPort * port, GstVideoState * state); - GstFlowReturn (*handle_output_frame) (GstOMXVideoEnc * self, GstOMXPort * port, GstOMXBuffer * buffer, GstVideoFrameState * frame); + gboolean (*set_format) (GstOMXVideoEnc * self, GstOMXPort * port, GstVideoCodecState * state); + GstCaps *(*get_caps) (GstOMXVideoEnc * self, GstOMXPort * port, GstVideoCodecState * state); + GstFlowReturn (*handle_output_frame) (GstOMXVideoEnc * self, GstOMXPort * port, GstOMXBuffer * buffer, GstVideoCodecFrame * frame); }; GType gst_omx_video_enc_get_type (void); diff --git a/omx/gstomxwmvdec.c b/omx/gstomxwmvdec.c index ef2cf13..f443d75 100644 --- a/omx/gstomxwmvdec.c +++ b/omx/gstomxwmvdec.c @@ -31,9 +31,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_wmv_dec_debug_category); /* prototypes */ static gboolean gst_omx_wmv_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); static gboolean gst_omx_wmv_dec_set_format (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state); + GstOMXPort * port, GstVideoCodecState * state); enum { @@ -78,14 +78,14 @@ gst_omx_wmv_dec_init (GstOMXWMVDec * self) static gboolean gst_omx_wmv_dec_is_format_change (GstOMXVideoDec * dec, - GstOMXPort * port, GstVideoState * state) + GstOMXPort * port, GstVideoCodecState * state) { return FALSE; } static gboolean gst_omx_wmv_dec_set_format (GstOMXVideoDec * dec, GstOMXPort * port, - GstVideoState * state) + GstVideoCodecState * state) { gboolean ret; OMX_PARAM_PORTDEFINITIONTYPE port_def;