diff options
-rw-r--r-- | gst-libs/gst/video/Makefile.am | 8 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideocodec.c | 343 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideocodec.h | 289 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideodecoder.c | 2237 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideodecoder.h | 291 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideoencoder.c | 1213 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideoencoder.h | 185 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideoutils.c | 159 | ||||
-rw-r--r-- | gst-libs/gst/video/gstbasevideoutils.h | 46 |
9 files changed, 0 insertions, 4771 deletions
diff --git a/gst-libs/gst/video/Makefile.am b/gst-libs/gst/video/Makefile.am index 52abc1df1..be87cd970 100644 --- a/gst-libs/gst/video/Makefile.am +++ b/gst-libs/gst/video/Makefile.am @@ -4,20 +4,12 @@ lib_LTLIBRARIES = libgstbasevideo-@GST_API_VERSION@.la CLEANFILES = $(BUILT_SOURCES) libgstbasevideo_@GST_API_VERSION@_la_SOURCES = \ - gstbasevideocodec.c \ - gstbasevideoutils.c \ - gstbasevideodecoder.c \ - gstbasevideoencoder.c \ gstsurfacemeta.c \ gstsurfaceconverter.c \ videocontext.c libgstbasevideo_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/video libgstbasevideo_@GST_API_VERSION@include_HEADERS = \ - gstbasevideocodec.h \ - gstbasevideoutils.h \ - gstbasevideodecoder.h \ - gstbasevideoencoder.h \ gstsurfacemeta.h \ gstsurfaceconverter.h \ videocontext.h diff --git a/gst-libs/gst/video/gstbasevideocodec.c b/gst-libs/gst/video/gstbasevideocodec.c deleted file mode 100644 index 9f839ccb8..000000000 --- a/gst-libs/gst/video/gstbasevideocodec.c +++ /dev/null @@ -1,343 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 David Schleef <ds@schleef.org> - * - * 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 <string.h> -#include <math.h> - -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/gst-libs/gst/video/gstbasevideocodec.h b/gst-libs/gst/video/gstbasevideocodec.h deleted file mode 100644 index 256279d78..000000000 --- a/gst-libs/gst/video/gstbasevideocodec.h +++ /dev/null @@ -1,289 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.org> - * - * 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 <gst/gst.h> -#include <gst/base/gstadapter.h> -#include <gst/video/video.h> -#include <gst/video/gstvideopool.h> -#include <gst/video/gstvideometa.h> - -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/gst-libs/gst/video/gstbasevideodecoder.c b/gst-libs/gst/video/gstbasevideodecoder.c deleted file mode 100644 index 271551d4f..000000000 --- a/gst-libs/gst/video/gstbasevideodecoder.c +++ /dev/null @@ -1,2237 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.org> - * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>. - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost <stefan.kost@nokia.com> - * - * 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. - * <orderedlist> - * <listitem> - * <itemizedlist><title>Configuration</title> - * <listitem><para> - * Initially, GstBaseVideoDecoder calls @start when the decoder element - * is activated, which allows subclass to perform any global setup. - * </para></listitem> - * <listitem><para> - * 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. - * </para></listitem> - * <listitem><para> - * GstBaseVideoDecoder calls @stop at end of all processing. - * </para></listitem> - * </itemizedlist> - * </listitem> - * <listitem> - * <itemizedlist> - * <title>Data processing</title> - * <listitem><para> - * Base class gathers input data, and optionally allows subclass - * to parse this into subsequently manageable chunks, typically - * corresponding to and referred to as 'frames'. - * </para></listitem> - * <listitem><para> - * Input frame is provided to subclass' @handle_frame. - * </para></listitem> - * <listitem><para> - * If codec processing results in decoded data, subclass should call - * @gst_base_video_decoder_finish_frame to have decoded data pushed - * downstream. - * </para></listitem> - * </itemizedlist> - * </listitem> - * <listitem> - * <itemizedlist><title>Shutdown phase</title> - * <listitem><para> - * GstBaseVideoDecoder class calls @stop to inform the subclass that data - * parsing will be stopped. - * </para></listitem> - * </itemizedlist> - * </listitem> - * </orderedlist> - * - * 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: - * <itemizedlist> - * <listitem><para>Provide pad templates</para></listitem> - * <listitem><para> - * Set source pad caps when appropriate - * </para></listitem> - * <listitem><para> - * Configure some baseclass behaviour parameters. - * </para></listitem> - * <listitem><para> - * 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. - * </para></listitem> - * <listitem><para> - * Accept data in @handle_frame and provide decoded results to - * @gst_base_video_decoder_finish_frame. - * </para></listitem> - * </itemizedlist> - */ - -#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 <string.h> - -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_has_allocation_meta (query, GST_VIDEO_META_API_TYPE)) { - /* 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_has_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE); - - 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/gst-libs/gst/video/gstbasevideodecoder.h b/gst-libs/gst/video/gstbasevideodecoder.h deleted file mode 100644 index 4e65b65a7..000000000 --- a/gst-libs/gst/video/gstbasevideodecoder.h +++ /dev/null @@ -1,291 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.org> - * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>. - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost <stefan.kost@nokia.com> - * - * 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 <gst/video/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/gst-libs/gst/video/gstbasevideoencoder.c b/gst-libs/gst/video/gstbasevideoencoder.c deleted file mode 100644 index 13160ce0a..000000000 --- a/gst-libs/gst/video/gstbasevideoencoder.c +++ /dev/null @@ -1,1213 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.org> - * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>. - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost <stefan.kost@nokia.com> - * - * 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. - * <orderedlist> - * <listitem> - * <itemizedlist><title>Configuration</title> - * <listitem><para> - * Initially, GstBaseVideoEncoder calls @start when the encoder element - * is activated, which allows subclass to perform any global setup. - * </para></listitem> - * <listitem><para> - * 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. - * </para></listitem> - * <listitem><para> - * GstBaseVideoEncoder calls @stop at end of all processing. - * </para></listitem> - * </itemizedlist> - * </listitem> - * <listitem> - * <itemizedlist> - * <title>Data processing</title> - * <listitem><para> - * Base class collects input data and metadata into a frame and hands - * this to subclass' @handle_frame. - * </para></listitem> - * <listitem><para> - * If codec processing results in encoded data, subclass should call - * @gst_base_video_encoder_finish_frame to have encoded data pushed - * downstream. - * </para></listitem> - * <listitem><para> - * If implemented, baseclass calls subclass @shape_output which then sends - * data downstream in desired form. Otherwise, it is sent as-is. - * </para></listitem> - * <listitem><para> - * GstBaseVideoEncoderClass will handle both srcpad and sinkpad events. - * Sink events will be passed to subclass if @event callback has been - * provided. - * </para></listitem> - * </itemizedlist> - * </listitem> - * <listitem> - * <itemizedlist><title>Shutdown phase</title> - * <listitem><para> - * GstBaseVideoEncoder class calls @stop to inform the subclass that data - * parsing will be stopped. - * </para></listitem> - * </itemizedlist> - * </listitem> - * </orderedlist> - * - * 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: - * <itemizedlist> - * <listitem><para>Provide pad templates</para></listitem> - * <listitem><para> - * Provide source pad caps before pushing the first buffer - * </para></listitem> - * <listitem><para> - * Accept data in @handle_frame and provide encoded results to - * @gst_base_video_encoder_finish_frame. - * </para></listitem> - * </itemizedlist> - * - */ - -#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 <string.h> - -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/gst-libs/gst/video/gstbasevideoencoder.h b/gst-libs/gst/video/gstbasevideoencoder.h deleted file mode 100644 index c969629a3..000000000 --- a/gst-libs/gst/video/gstbasevideoencoder.h +++ /dev/null @@ -1,185 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.org> - * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>. - * Copyright (C) 2011 Nokia Corporation. All rights reserved. - * Contact: Stefan Kost <stefan.kost@nokia.com> - * - * 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 <gst/video/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/gst-libs/gst/video/gstbasevideoutils.c b/gst-libs/gst/video/gstbasevideoutils.c deleted file mode 100644 index 507ad07da..000000000 --- a/gst-libs/gst/video/gstbasevideoutils.c +++ /dev/null @@ -1,159 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.org> - * - * 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 <string.h> - -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/gst-libs/gst/video/gstbasevideoutils.h b/gst-libs/gst/video/gstbasevideoutils.h deleted file mode 100644 index aeca2d1b7..000000000 --- a/gst-libs/gst/video/gstbasevideoutils.h +++ /dev/null @@ -1,46 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.org> - * - * 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 <gst/gst.h> -#include <gst/video/video.h> -#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 |