From bdf7ebf411a0aad64c2ba8c4219e97a291bf5a45 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 7 Apr 2012 11:14:45 +0200 Subject: ffmpegenc/dec: Remove audio/video specific code Makes each file more manageable, second step to porting to base classes --- ext/ffmpeg/gstffmpeg.c | 6 +- ext/ffmpeg/gstffmpeg.h | 6 +- ext/ffmpeg/gstffmpegcfg.c | 40 +- ext/ffmpeg/gstffmpegcfg.h | 8 +- ext/ffmpeg/gstffmpegdec.c | 1991 +++--------------------------------------- ext/ffmpeg/gstffmpegenc.c | 1015 +++++---------------- ext/ffmpeg/gstffmpegenc.h | 57 +- ext/ffmpeg/gstffmpegviddec.c | 779 +++++------------ ext/ffmpeg/gstffmpegvidenc.c | 501 +++-------- ext/ffmpeg/gstffmpegvidenc.h | 39 +- 10 files changed, 768 insertions(+), 3674 deletions(-) diff --git a/ext/ffmpeg/gstffmpeg.c b/ext/ffmpeg/gstffmpeg.c index 88a43bc..5d3867a 100644 --- a/ext/ffmpeg/gstffmpeg.c +++ b/ext/ffmpeg/gstffmpeg.c @@ -138,8 +138,10 @@ plugin_init (GstPlugin * plugin) av_register_all (); - gst_ffmpegenc_register (plugin); - gst_ffmpegdec_register (plugin); + gst_ffmpegaudenc_register (plugin); + gst_ffmpegvidenc_register (plugin); + gst_ffmpegauddec_register (plugin); + gst_ffmpegviddec_register (plugin); gst_ffmpegdemux_register (plugin); gst_ffmpegmux_register (plugin); gst_ffmpegdeinterlace_register (plugin); diff --git a/ext/ffmpeg/gstffmpeg.h b/ext/ffmpeg/gstffmpeg.h index 667fa51..2cbddd4 100644 --- a/ext/ffmpeg/gstffmpeg.h +++ b/ext/ffmpeg/gstffmpeg.h @@ -44,8 +44,10 @@ extern gboolean _shut_up_I_am_probing; #endif extern gboolean gst_ffmpegdemux_register (GstPlugin * plugin); -extern gboolean gst_ffmpegdec_register (GstPlugin * plugin); -extern gboolean gst_ffmpegenc_register (GstPlugin * plugin); +extern gboolean gst_ffmpegauddec_register (GstPlugin * plugin); +extern gboolean gst_ffmpegviddec_register (GstPlugin * plugin); +extern gboolean gst_ffmpegaudenc_register (GstPlugin * plugin); +extern gboolean gst_ffmpegvidenc_register (GstPlugin * plugin); extern gboolean gst_ffmpegmux_register (GstPlugin * plugin); extern gboolean gst_ffmpegcsp_register (GstPlugin * plugin); #if 0 diff --git a/ext/ffmpeg/gstffmpegcfg.c b/ext/ffmpeg/gstffmpegcfg.c index 6b87cc3..d9bf4e3 100644 --- a/ext/ffmpeg/gstffmpegcfg.c +++ b/ext/ffmpeg/gstffmpegcfg.c @@ -26,7 +26,7 @@ #endif #include "gstffmpeg.h" -#include "gstffmpegenc.h" +#include "gstffmpegvidenc.h" #include "gstffmpegcfg.h" #include @@ -49,7 +49,7 @@ gst_ffmpeg_pass_get_type (void) }; ffmpeg_pass_type = - g_enum_register_static ("GstFFMpegEncPass", ffmpeg_passes); + g_enum_register_static ("GstFFMpegVidEncPass", ffmpeg_passes); } return ffmpeg_pass_type; @@ -71,7 +71,7 @@ gst_ffmpeg_lim_pass_get_type (void) }; ffmpeg_lim_pass_type = - g_enum_register_static ("GstFFMpegEncLimPass", ffmpeg_lim_passes); + g_enum_register_static ("GstFFMpegVidEncLimPass", ffmpeg_lim_passes); } return ffmpeg_lim_pass_type; @@ -94,7 +94,8 @@ gst_ffmpeg_mb_decision_get_type (void) }; ffmpeg_mb_decision_type = - g_enum_register_static ("GstFFMpegEncMBDecision", ffmpeg_mb_decisions); + g_enum_register_static ("GstFFMpegVidEncMBDecision", + ffmpeg_mb_decisions); } return ffmpeg_mb_decision_type; @@ -207,7 +208,8 @@ gst_ffmpeg_quant_type_get_type (void) }; ffmpeg_quant_type_type = - g_enum_register_static ("GstFFMpegEncQuantTypes", ffmpeg_quant_types); + g_enum_register_static ("GstFFMpegVidEncQuantTypes", + ffmpeg_quant_types); } return ffmpeg_quant_type_type; @@ -228,7 +230,7 @@ gst_ffmpeg_pre_me_get_type (void) }; ffmpeg_pre_me_type = - g_enum_register_static ("GstFFMpegEncPreME", ffmpeg_pre_mes); + g_enum_register_static ("GstFFMpegVidEncPreME", ffmpeg_pre_mes); } return ffmpeg_pre_me_type; @@ -249,7 +251,8 @@ gst_ffmpeg_pred_method_get_type (void) }; ffmpeg_pred_method = - g_enum_register_static ("GstFFMpegEncPredMethod", ffmpeg_pred_methods); + g_enum_register_static ("GstFFMpegVidEncPredMethod", + ffmpeg_pred_methods); } return ffmpeg_pred_method; @@ -325,7 +328,7 @@ struct _GParamSpecData /* properties whose member offset is higher than the config base * can be copied directly at context configuration time; * and can also retrieve a default value from lavc */ -#define CONTEXT_CONFIG_OFFSET G_STRUCT_OFFSET (GstFFMpegEnc, config) +#define CONTEXT_CONFIG_OFFSET G_STRUCT_OFFSET (GstFFMpegVidEnc, config) /* additional info is named pointer specified by the quark */ static GQuark quark; @@ -340,7 +343,7 @@ static GList *property_list; default, include, exclude) \ G_STMT_START { \ GParamSpecData *_qdata = g_new0 (GParamSpecData, 1); \ - GstFFMpegEnc _enc; \ + GstFFMpegVidEnc _enc; \ _qdata->offset = G_STRUCT_OFFSET (struct_type, member); \ _qdata->size = sizeof (_enc.member); \ _qdata->lavc_default = default; \ @@ -351,7 +354,7 @@ G_STMT_START { \ } G_STMT_END #define gst_ffmpeg_add_pspec(pspec, member, default, include, exclude) \ - gst_ffmpeg_add_pspec_full (pspec, property_list, GstFFMpegEnc, member, \ + gst_ffmpeg_add_pspec_full (pspec, property_list, GstFFMpegVidEnc, member, \ default, include, exclude) /* ==== BEGIN CONFIGURATION SECTION ==== */ @@ -756,7 +759,7 @@ gst_ffmpeg_cfg_codec_has_pspec (enum CodecID codec_id, GParamSpec * pspec) /* install all properties for klass that have been registered in property_list */ void -gst_ffmpeg_cfg_install_property (GstFFMpegEncClass * klass, guint base) +gst_ffmpeg_cfg_install_property (GstFFMpegVidEncClass * klass, guint base) { GParamSpec *pspec; GList *list; @@ -888,7 +891,7 @@ gboolean gst_ffmpeg_cfg_set_property (GObject * object, const GValue * value, GParamSpec * pspec) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (object); + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) (object); GParamSpecData *qdata; qdata = g_param_spec_get_qdata (pspec, quark); @@ -956,7 +959,7 @@ gboolean gst_ffmpeg_cfg_get_property (GObject * object, GValue * value, GParamSpec * pspec) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (object); + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) (object); GParamSpecData *qdata; qdata = g_param_spec_get_qdata (pspec, quark); @@ -1016,7 +1019,7 @@ gst_ffmpeg_cfg_get_property (GObject * object, } void -gst_ffmpeg_cfg_set_defaults (GstFFMpegEnc * ffmpegenc) +gst_ffmpeg_cfg_set_defaults (GstFFMpegVidEnc * ffmpegenc) { GParamSpec **pspecs; guint num_props, i; @@ -1044,10 +1047,11 @@ gst_ffmpeg_cfg_set_defaults (GstFFMpegEnc * ffmpegenc) void -gst_ffmpeg_cfg_fill_context (GstFFMpegEnc * ffmpegenc, AVCodecContext * context) +gst_ffmpeg_cfg_fill_context (GstFFMpegVidEnc * ffmpegenc, + AVCodecContext * context) { - GstFFMpegEncClass *klass - = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); + GstFFMpegVidEncClass *klass + = (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); GParamSpec *pspec; GParamSpecData *qdata; GList *list; @@ -1079,7 +1083,7 @@ gst_ffmpeg_cfg_fill_context (GstFFMpegEnc * ffmpegenc, AVCodecContext * context) } void -gst_ffmpeg_cfg_finalize (GstFFMpegEnc * ffmpegenc) +gst_ffmpeg_cfg_finalize (GstFFMpegVidEnc * ffmpegenc) { GParamSpec **pspecs; guint num_props, i; diff --git a/ext/ffmpeg/gstffmpegcfg.h b/ext/ffmpeg/gstffmpegcfg.h index 1dcaade..5251eb2 100644 --- a/ext/ffmpeg/gstffmpegcfg.h +++ b/ext/ffmpeg/gstffmpegcfg.h @@ -25,7 +25,7 @@ G_BEGIN_DECLS void gst_ffmpeg_cfg_init (void); -void gst_ffmpeg_cfg_install_property (GstFFMpegEncClass * klass, guint base); +void gst_ffmpeg_cfg_install_property (GstFFMpegVidEncClass * klass, guint base); gboolean gst_ffmpeg_cfg_set_property (GObject * object, const GValue * value, GParamSpec * pspec); @@ -33,9 +33,9 @@ gboolean gst_ffmpeg_cfg_set_property (GObject * object, gboolean gst_ffmpeg_cfg_get_property (GObject * object, GValue * value, GParamSpec * pspec); -void gst_ffmpeg_cfg_fill_context (GstFFMpegEnc * ffmpegenc, AVCodecContext * context); -void gst_ffmpeg_cfg_set_defaults (GstFFMpegEnc * ffmpegenc); -void gst_ffmpeg_cfg_finalize (GstFFMpegEnc * ffmpegenc); +void gst_ffmpeg_cfg_fill_context (GstFFMpegVidEnc * ffmpegenc, AVCodecContext * context); +void gst_ffmpeg_cfg_set_defaults (GstFFMpegVidEnc * ffmpegenc); +void gst_ffmpeg_cfg_finalize (GstFFMpegVidEnc * ffmpegenc); G_END_DECLS diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c index 719c538..5f4fdbb 100644 --- a/ext/ffmpeg/gstffmpegdec.c +++ b/ext/ffmpeg/gstffmpegdec.c @@ -31,7 +31,6 @@ #endif #include -#include #include "gstffmpeg.h" #include "gstffmpegcodecmap.h" @@ -40,7 +39,7 @@ /* define to enable alternative buffer refcounting algorithm */ #undef EXTRA_REF -typedef struct _GstFFMpegDec GstFFMpegDec; +typedef struct _GstFFMpegAudDec GstFFMpegAudDec; #define MAX_TS_MASK 0xff @@ -56,7 +55,7 @@ typedef struct gint64 offset; } GstTSInfo; -struct _GstFFMpegDec +struct _GstFFMpegAudDec { GstElement element; @@ -66,21 +65,9 @@ struct _GstFFMpegDec /* decoding */ AVCodecContext *context; - AVFrame *picture; gboolean opened; union { - struct - { - gint width, height; - gint clip_width, clip_height; - gint par_n, par_d; - gint fps_n, fps_d; - gint old_fps_n, old_fps_d; - gboolean interlaced; - - enum PixelFormat pix_fmt; - } video; struct { gint channels; @@ -88,18 +75,10 @@ struct _GstFFMpegDec gint depth; } audio; } format; - gboolean waiting_for_key; gboolean discont; gboolean clear_ts; /* for tracking DTS/PTS */ - gboolean has_b_frames; - gboolean reordered_in; - GstClockTime last_in; - GstClockTime last_diff; - guint last_frames; - gboolean reordered_out; - GstClockTime last_out; GstClockTime next_out; /* parsing */ @@ -107,46 +86,20 @@ struct _GstFFMpegDec * See bug #566250 */ AVCodecParserContext *pctx; GstBuffer *pcache; - guint8 *padded; - guint padded_size; - - GValue *par; /* pixel aspect ratio of incoming data */ - gboolean current_dr; /* if direct rendering is enabled */ - gboolean extra_ref; /* keep extra ref around in get/release */ - - /* some properties */ - enum AVDiscard skip_frame; - gint lowres; - gboolean direct_rendering; - gboolean do_padding; - gboolean debug_mv; - gboolean crop; - int max_threads; - - /* QoS stuff *//* with LOCK */ - gdouble proportion; - GstClockTime earliest_time; - gint64 processed; - gint64 dropped; /* clipping segment */ GstSegment segment; - gboolean is_realvideo; - GstTSInfo ts_info[MAX_TS_MASK + 1]; gint ts_idx; /* reverse playback queue */ GList *queued; - - /* Can downstream allocate 16bytes aligned data. */ - gboolean can_allocate_aligned; }; -typedef struct _GstFFMpegDecClass GstFFMpegDecClass; +typedef struct _GstFFMpegAudDecClass GstFFMpegAudDecClass; -struct _GstFFMpegDecClass +struct _GstFFMpegAudDecClass { GstElementClass parent_class; @@ -158,7 +111,7 @@ struct _GstFFMpegDecClass static const GstTSInfo ts_info_none = { -1, -1, -1, -1 }; static const GstTSInfo * -gst_ts_info_store (GstFFMpegDec * dec, GstClockTime timestamp, +gst_ts_info_store (GstFFMpegAudDec * dec, GstClockTime timestamp, GstClockTime duration, gint64 offset) { gint idx = dec->ts_idx; @@ -172,7 +125,7 @@ gst_ts_info_store (GstFFMpegDec * dec, GstClockTime timestamp, } static const GstTSInfo * -gst_ts_info_get (GstFFMpegDec * dec, gint idx) +gst_ts_info_get (GstFFMpegAudDec * dec, gint idx) { if (G_UNLIKELY (idx < 0 || idx > MAX_TS_MASK)) return GST_TS_INFO_NONE; @@ -181,124 +134,47 @@ gst_ts_info_get (GstFFMpegDec * dec, gint idx) } #define GST_TYPE_FFMPEGDEC \ - (gst_ffmpegdec_get_type()) + (gst_ffmpegauddec_get_type()) #define GST_FFMPEGDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegDec)) -#define GST_FFMPEGDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegDecClass)) + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegAudDec)) +#define GST_FFMPEGAUDDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegAudDecClass)) #define GST_IS_FFMPEGDEC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC)) -#define GST_IS_FFMPEGDEC_CLASS(klass) \ +#define GST_IS_FFMPEGAUDDEC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC)) -#define DEFAULT_LOWRES 0 -#define DEFAULT_SKIPFRAME 0 -#define DEFAULT_DIRECT_RENDERING TRUE -#define DEFAULT_DO_PADDING TRUE -#define DEFAULT_DEBUG_MV FALSE -#define DEFAULT_CROP TRUE -#define DEFAULT_MAX_THREADS 0 - -enum -{ - PROP_0, - PROP_LOWRES, - PROP_SKIPFRAME, - PROP_DIRECT_RENDERING, - PROP_DO_PADDING, - PROP_DEBUG_MV, - PROP_CROP, - PROP_MAX_THREADS, - PROP_LAST -}; - /* A number of function prototypes are given so we can refer to them later. */ -static void gst_ffmpegdec_base_init (GstFFMpegDecClass * klass); -static void gst_ffmpegdec_class_init (GstFFMpegDecClass * klass); -static void gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec); -static void gst_ffmpegdec_finalize (GObject * object); +static void gst_ffmpegauddec_base_init (GstFFMpegAudDecClass * klass); +static void gst_ffmpegauddec_class_init (GstFFMpegAudDecClass * klass); +static void gst_ffmpegauddec_init (GstFFMpegAudDec * ffmpegdec); +static void gst_ffmpegauddec_finalize (GObject * object); -static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery * query); -static gboolean gst_ffmpegdec_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_ffmpegauddec_setcaps (GstPad * pad, GstCaps * caps); +static gboolean gst_ffmpegauddec_sink_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_ffmpegauddec_chain (GstPad * pad, GstBuffer * buf); -static gboolean gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_ffmpegdec_chain (GstPad * pad, GstBuffer * buf); - -static GstStateChangeReturn gst_ffmpegdec_change_state (GstElement * element, +static GstStateChangeReturn gst_ffmpegauddec_change_state (GstElement * element, GstStateChange transition); -static void gst_ffmpegdec_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_ffmpegdec_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -static gboolean gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, +static gboolean gst_ffmpegauddec_negotiate (GstFFMpegAudDec * ffmpegdec, gboolean force); -/* some sort of bufferpool handling, but different */ -static int gst_ffmpegdec_get_buffer (AVCodecContext * context, - AVFrame * picture); -static void gst_ffmpegdec_release_buffer (AVCodecContext * context, - AVFrame * picture); - -static void gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec); +static void gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec); #define GST_FFDEC_PARAMS_QDATA g_quark_from_static_string("ffdec-params") static GstElementClass *parent_class = NULL; -#define GST_FFMPEGDEC_TYPE_LOWRES (gst_ffmpegdec_lowres_get_type()) -static GType -gst_ffmpegdec_lowres_get_type (void) -{ - static GType ffmpegdec_lowres_type = 0; - - if (!ffmpegdec_lowres_type) { - static const GEnumValue ffmpegdec_lowres[] = { - {0, "0", "full"}, - {1, "1", "1/2-size"}, - {2, "2", "1/4-size"}, - {0, NULL, NULL}, - }; - - ffmpegdec_lowres_type = - g_enum_register_static ("GstFFMpegDecLowres", ffmpegdec_lowres); - } - - return ffmpegdec_lowres_type; -} - -#define GST_FFMPEGDEC_TYPE_SKIPFRAME (gst_ffmpegdec_skipframe_get_type()) -static GType -gst_ffmpegdec_skipframe_get_type (void) -{ - static GType ffmpegdec_skipframe_type = 0; - - if (!ffmpegdec_skipframe_type) { - static const GEnumValue ffmpegdec_skipframe[] = { - {0, "0", "Skip nothing"}, - {1, "1", "Skip B-frames"}, - {2, "2", "Skip IDCT/Dequantization"}, - {5, "5", "Skip everything"}, - {0, NULL, NULL}, - }; - - ffmpegdec_skipframe_type = - g_enum_register_static ("GstFFMpegDecSkipFrame", ffmpegdec_skipframe); - } - - return ffmpegdec_skipframe_type; -} static void -gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) +gst_ffmpegauddec_base_init (GstFFMpegAudDecClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstPadTemplate *sinktempl, *srctempl; GstCaps *sinkcaps, *srccaps; AVCodec *in_plugin; - gchar *longname, *classification, *description; + gchar *longname, *description; in_plugin = (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), @@ -307,16 +183,13 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) /* construct the element details struct */ longname = g_strdup_printf ("FFmpeg %s decoder", in_plugin->long_name); - classification = g_strdup_printf ("Codec/Decoder/%s", - (in_plugin->type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio"); description = g_strdup_printf ("FFmpeg %s decoder", in_plugin->name); - gst_element_class_set_details_simple (element_class, longname, classification, - description, + gst_element_class_set_details_simple (element_class, longname, + "Codec/Decoder/Audio", description, "Wim Taymans , " "Ronald Bultje , " "Edward Hervey "); g_free (longname); - g_free (classification); g_free (description); /* get the caps */ @@ -325,12 +198,8 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) GST_DEBUG ("Couldn't get sink caps for decoder '%s'", in_plugin->name); sinkcaps = gst_caps_from_string ("unknown/unknown"); } - if (in_plugin->type == AVMEDIA_TYPE_VIDEO) { - srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv"); - } else { - srccaps = gst_ffmpeg_codectype_to_audio_caps (NULL, - in_plugin->id, FALSE, in_plugin); - } + srccaps = gst_ffmpeg_codectype_to_audio_caps (NULL, + in_plugin->id, FALSE, in_plugin); if (!srccaps) { GST_DEBUG ("Couldn't get source caps for decoder '%s'", in_plugin->name); srccaps = gst_caps_from_string ("unknown/unknown"); @@ -350,268 +219,76 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) } static void -gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) +gst_ffmpegauddec_class_init (GstFFMpegAudDecClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); - gobject_class->finalize = gst_ffmpegdec_finalize; - - gobject_class->set_property = gst_ffmpegdec_set_property; - gobject_class->get_property = gst_ffmpegdec_get_property; - - if (klass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { - int caps; - - g_object_class_install_property (gobject_class, PROP_SKIPFRAME, - g_param_spec_enum ("skip-frame", "Skip frames", - "Which types of frames to skip during decoding", - GST_FFMPEGDEC_TYPE_SKIPFRAME, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_LOWRES, - g_param_spec_enum ("lowres", "Low resolution", - "At which resolution to decode images", GST_FFMPEGDEC_TYPE_LOWRES, - 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_DIRECT_RENDERING, - g_param_spec_boolean ("direct-rendering", "Direct Rendering", - "Enable direct rendering", DEFAULT_DIRECT_RENDERING, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_DO_PADDING, - g_param_spec_boolean ("do-padding", "Do Padding", - "Add 0 padding before decoding data", DEFAULT_DO_PADDING, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_DEBUG_MV, - g_param_spec_boolean ("debug-mv", "Debug motion vectors", - "Whether ffmpeg should print motion vectors on top of the image", - DEFAULT_DEBUG_MV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#if 0 - g_object_class_install_property (gobject_class, PROP_CROP, - g_param_spec_boolean ("crop", "Crop", - "Crop images to the display region", - DEFAULT_CROP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#endif - - caps = klass->in_plugin->capabilities; - if (caps & (CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS)) { - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_THREADS, - g_param_spec_int ("max-threads", "Maximum decode threads", - "Maximum number of worker threads to spawn. (0 = auto)", - 0, G_MAXINT, DEFAULT_MAX_THREADS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - } - } + gobject_class->finalize = gst_ffmpegauddec_finalize; - gstelement_class->change_state = gst_ffmpegdec_change_state; + gstelement_class->change_state = gst_ffmpegauddec_change_state; } static void -gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec) +gst_ffmpegauddec_init (GstFFMpegAudDec * ffmpegdec) { - GstFFMpegDecClass *oclass; + GstFFMpegAudDecClass *oclass; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); /* setup pads */ ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); gst_pad_set_setcaps_function (ffmpegdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_setcaps)); + GST_DEBUG_FUNCPTR (gst_ffmpegauddec_setcaps)); gst_pad_set_event_function (ffmpegdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_sink_event)); + GST_DEBUG_FUNCPTR (gst_ffmpegauddec_sink_event)); gst_pad_set_chain_function (ffmpegdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_chain)); + GST_DEBUG_FUNCPTR (gst_ffmpegauddec_chain)); gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad); ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); gst_pad_use_fixed_caps (ffmpegdec->srcpad); - gst_pad_set_event_function (ffmpegdec->srcpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_src_event)); - gst_pad_set_query_function (ffmpegdec->srcpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_query)); gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad); /* some ffmpeg data */ ffmpegdec->context = avcodec_alloc_context (); - ffmpegdec->picture = avcodec_alloc_frame (); ffmpegdec->pctx = NULL; ffmpegdec->pcache = NULL; - ffmpegdec->par = NULL; ffmpegdec->opened = FALSE; - ffmpegdec->waiting_for_key = TRUE; - ffmpegdec->skip_frame = ffmpegdec->lowres = 0; - ffmpegdec->direct_rendering = DEFAULT_DIRECT_RENDERING; - ffmpegdec->do_padding = DEFAULT_DO_PADDING; - ffmpegdec->debug_mv = DEFAULT_DEBUG_MV; - ffmpegdec->crop = DEFAULT_CROP; - ffmpegdec->max_threads = DEFAULT_MAX_THREADS; - - ffmpegdec->format.video.par_n = -1; - ffmpegdec->format.video.fps_n = -1; - ffmpegdec->format.video.old_fps_n = -1; - gst_segment_init (&ffmpegdec->segment, GST_FORMAT_TIME); - /* We initially assume downstream can allocate 16 bytes aligned buffers */ - ffmpegdec->can_allocate_aligned = TRUE; + gst_segment_init (&ffmpegdec->segment, GST_FORMAT_TIME); } static void -gst_ffmpegdec_finalize (GObject * object) +gst_ffmpegauddec_finalize (GObject * object) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object; + GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) object; if (ffmpegdec->context != NULL) { av_free (ffmpegdec->context); ffmpegdec->context = NULL; } - if (ffmpegdec->picture != NULL) { - av_free (ffmpegdec->picture); - ffmpegdec->picture = NULL; - } - G_OBJECT_CLASS (parent_class)->finalize (object); } -static gboolean -gst_ffmpegdec_query (GstPad * pad, GstQuery * query) -{ - GstFFMpegDec *ffmpegdec; - gboolean res = FALSE; - - ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY: - { - GST_DEBUG_OBJECT (ffmpegdec, "latency query %d", - ffmpegdec->context->has_b_frames); - if ((res = gst_pad_peer_query (ffmpegdec->sinkpad, query))) { - if (ffmpegdec->context->has_b_frames) { - gboolean live; - GstClockTime min_lat, max_lat, our_lat; - - gst_query_parse_latency (query, &live, &min_lat, &max_lat); - if (ffmpegdec->format.video.fps_n > 0) - our_lat = - gst_util_uint64_scale_int (ffmpegdec->context->has_b_frames * - GST_SECOND, ffmpegdec->format.video.fps_d, - ffmpegdec->format.video.fps_n); - else - our_lat = - gst_util_uint64_scale_int (ffmpegdec->context->has_b_frames * - GST_SECOND, 1, 25); - if (min_lat != -1) - min_lat += our_lat; - if (max_lat != -1) - max_lat += our_lat; - gst_query_set_latency (query, live, min_lat, max_lat); - } - } - } - break; - default: - res = gst_pad_query_default (pad, query); - break; - } - - gst_object_unref (ffmpegdec); - - return res; -} - static void -gst_ffmpegdec_reset_ts (GstFFMpegDec * ffmpegdec) +gst_ffmpegauddec_reset_ts (GstFFMpegAudDec * ffmpegdec) { - ffmpegdec->last_in = GST_CLOCK_TIME_NONE; - ffmpegdec->last_diff = GST_CLOCK_TIME_NONE; - ffmpegdec->last_frames = 0; - ffmpegdec->last_out = GST_CLOCK_TIME_NONE; ffmpegdec->next_out = GST_CLOCK_TIME_NONE; - ffmpegdec->reordered_in = FALSE; - ffmpegdec->reordered_out = FALSE; -} - -static void -gst_ffmpegdec_update_qos (GstFFMpegDec * ffmpegdec, gdouble proportion, - GstClockTime timestamp) -{ - GST_LOG_OBJECT (ffmpegdec, "update QOS: %f, %" GST_TIME_FORMAT, - proportion, GST_TIME_ARGS (timestamp)); - - GST_OBJECT_LOCK (ffmpegdec); - ffmpegdec->proportion = proportion; - ffmpegdec->earliest_time = timestamp; - GST_OBJECT_UNLOCK (ffmpegdec); -} - -static void -gst_ffmpegdec_reset_qos (GstFFMpegDec * ffmpegdec) -{ - gst_ffmpegdec_update_qos (ffmpegdec, 0.5, GST_CLOCK_TIME_NONE); - ffmpegdec->processed = 0; - ffmpegdec->dropped = 0; -} - -static void -gst_ffmpegdec_read_qos (GstFFMpegDec * ffmpegdec, gdouble * proportion, - GstClockTime * timestamp) -{ - GST_OBJECT_LOCK (ffmpegdec); - *proportion = ffmpegdec->proportion; - *timestamp = ffmpegdec->earliest_time; - GST_OBJECT_UNLOCK (ffmpegdec); -} - -static gboolean -gst_ffmpegdec_src_event (GstPad * pad, GstEvent * event) -{ - GstFFMpegDec *ffmpegdec; - gboolean res; - - ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_QOS: - { - gdouble proportion; - GstClockTimeDiff diff; - GstClockTime timestamp; - - gst_event_parse_qos (event, &proportion, &diff, ×tamp); - - /* update our QoS values */ - gst_ffmpegdec_update_qos (ffmpegdec, proportion, timestamp + diff); - - /* forward upstream */ - res = gst_pad_push_event (ffmpegdec->sinkpad, event); - break; - } - default: - /* forward upstream */ - res = gst_pad_push_event (ffmpegdec->sinkpad, event); - break; - } - - gst_object_unref (ffmpegdec); - - return res; } /* with LOCK */ static void -gst_ffmpegdec_close (GstFFMpegDec * ffmpegdec) +gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec) { if (!ffmpegdec->opened) return; GST_LOG_OBJECT (ffmpegdec, "closing ffmpeg codec"); - if (ffmpegdec->par) { - g_free (ffmpegdec->par); - ffmpegdec->par = NULL; - } - if (ffmpegdec->context->priv_data) gst_ffmpeg_avcodec_close (ffmpegdec->context); ffmpegdec->opened = FALSE; @@ -634,98 +311,46 @@ gst_ffmpegdec_close (GstFFMpegDec * ffmpegdec) av_parser_close (ffmpegdec->pctx); ffmpegdec->pctx = NULL; } - - ffmpegdec->format.video.par_n = -1; - ffmpegdec->format.video.fps_n = -1; - ffmpegdec->format.video.old_fps_n = -1; - ffmpegdec->format.video.interlaced = FALSE; } /* with LOCK */ static gboolean -gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec) +gst_ffmpegauddec_open (GstFFMpegAudDec * ffmpegdec) { - GstFFMpegDecClass *oclass; + GstFFMpegAudDecClass *oclass; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); if (gst_ffmpeg_avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0) goto could_not_open; ffmpegdec->opened = TRUE; - ffmpegdec->is_realvideo = FALSE; GST_LOG_OBJECT (ffmpegdec, "Opened ffmpeg codec %s, id %d", oclass->in_plugin->name, oclass->in_plugin->id); - /* open a parser if we can */ - switch (oclass->in_plugin->id) { - case CODEC_ID_MPEG4: - case CODEC_ID_MJPEG: - case CODEC_ID_VC1: - GST_LOG_OBJECT (ffmpegdec, "not using parser, blacklisted codec"); - ffmpegdec->pctx = NULL; - break; - case CODEC_ID_H264: - /* For H264, only use a parser if there is no context data, if there is, - * we're talking AVC */ - if (ffmpegdec->context->extradata_size == 0) { - GST_LOG_OBJECT (ffmpegdec, "H264 with no extradata, creating parser"); - ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id); - } else { - GST_LOG_OBJECT (ffmpegdec, - "H264 with extradata implies framed data - not using parser"); - ffmpegdec->pctx = NULL; - } - break; - case CODEC_ID_RV10: - case CODEC_ID_RV30: - case CODEC_ID_RV20: - case CODEC_ID_RV40: - ffmpegdec->is_realvideo = TRUE; - break; - default: - if (!ffmpegdec->turnoff_parser) { - ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id); - if (ffmpegdec->pctx) - GST_LOG_OBJECT (ffmpegdec, "Using parser %p", ffmpegdec->pctx); - else - GST_LOG_OBJECT (ffmpegdec, "No parser for codec"); - } else { - GST_LOG_OBJECT (ffmpegdec, "Parser deactivated for format"); - } - break; + if (!ffmpegdec->turnoff_parser) { + ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id); + if (ffmpegdec->pctx) + GST_LOG_OBJECT (ffmpegdec, "Using parser %p", ffmpegdec->pctx); + else + GST_LOG_OBJECT (ffmpegdec, "No parser for codec"); + } else { + GST_LOG_OBJECT (ffmpegdec, "Parser deactivated for format"); } - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - ffmpegdec->format.video.width = 0; - ffmpegdec->format.video.height = 0; - ffmpegdec->format.video.clip_width = -1; - ffmpegdec->format.video.clip_height = -1; - ffmpegdec->format.video.pix_fmt = PIX_FMT_NB; - ffmpegdec->format.video.interlaced = FALSE; - break; - case AVMEDIA_TYPE_AUDIO: - ffmpegdec->format.audio.samplerate = 0; - ffmpegdec->format.audio.channels = 0; - ffmpegdec->format.audio.depth = 0; - break; - default: - break; - } + ffmpegdec->format.audio.samplerate = 0; + ffmpegdec->format.audio.channels = 0; + ffmpegdec->format.audio.depth = 0; - gst_ffmpegdec_reset_ts (ffmpegdec); - /* FIXME, reset_qos holds the LOCK */ - ffmpegdec->proportion = 0.0; - ffmpegdec->earliest_time = -1; + gst_ffmpegauddec_reset_ts (ffmpegdec); return TRUE; /* ERRORS */ could_not_open: { - gst_ffmpegdec_close (ffmpegdec); + gst_ffmpegauddec_close (ffmpegdec); GST_DEBUG_OBJECT (ffmpegdec, "ffdec_%s: Failed to open FFMPEG codec", oclass->in_plugin->name); return FALSE; @@ -733,129 +358,41 @@ could_not_open: } static gboolean -gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) +gst_ffmpegauddec_setcaps (GstPad * pad, GstCaps * caps) { - GstFFMpegDec *ffmpegdec; - GstFFMpegDecClass *oclass; + GstFFMpegAudDec *ffmpegdec; + GstFFMpegAudDecClass *oclass; GstStructure *structure; - const GValue *par; - const GValue *fps; gboolean ret = TRUE; - ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad)); - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + ffmpegdec = (GstFFMpegAudDec *) (gst_pad_get_parent (pad)); + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_DEBUG_OBJECT (pad, "setcaps called"); GST_OBJECT_LOCK (ffmpegdec); - /* stupid check for VC1 */ - if ((oclass->in_plugin->id == CODEC_ID_WMV3) || - (oclass->in_plugin->id == CODEC_ID_VC1)) - oclass->in_plugin->id = gst_ffmpeg_caps_to_codecid (caps, NULL); - /* close old session */ if (ffmpegdec->opened) { GST_OBJECT_UNLOCK (ffmpegdec); - gst_ffmpegdec_drain (ffmpegdec); + gst_ffmpegauddec_drain (ffmpegdec); GST_OBJECT_LOCK (ffmpegdec); - gst_ffmpegdec_close (ffmpegdec); + gst_ffmpegauddec_close (ffmpegdec); /* and reset the defaults that were set when a context is created */ avcodec_get_context_defaults (ffmpegdec->context); } - /* set buffer functions */ - if (oclass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { - ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer; - ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer; - ffmpegdec->context->draw_horiz_band = NULL; - } - /* default is to let format decide if it needs a parser */ ffmpegdec->turnoff_parser = FALSE; - ffmpegdec->has_b_frames = FALSE; - - GST_LOG_OBJECT (ffmpegdec, "size %dx%d", ffmpegdec->context->width, - ffmpegdec->context->height); - /* get size and so */ gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, oclass->in_plugin->type, caps, ffmpegdec->context); - GST_LOG_OBJECT (ffmpegdec, "size after %dx%d", ffmpegdec->context->width, - ffmpegdec->context->height); - - if (!ffmpegdec->context->time_base.den || !ffmpegdec->context->time_base.num) { - GST_DEBUG_OBJECT (ffmpegdec, "forcing 25/1 framerate"); - ffmpegdec->context->time_base.num = 1; - ffmpegdec->context->time_base.den = 25; - } - /* get pixel aspect ratio if it's set */ structure = gst_caps_get_structure (caps, 0); - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - if (par) { - GST_DEBUG_OBJECT (ffmpegdec, "sink caps have pixel-aspect-ratio of %d:%d", - gst_value_get_fraction_numerator (par), - gst_value_get_fraction_denominator (par)); - /* should be NULL */ - if (ffmpegdec->par) - g_free (ffmpegdec->par); - ffmpegdec->par = g_new0 (GValue, 1); - gst_value_init_and_copy (ffmpegdec->par, par); - } - - /* get the framerate from incoming caps. fps_n is set to -1 when - * there is no valid framerate */ - fps = gst_structure_get_value (structure, "framerate"); - if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) { - ffmpegdec->format.video.fps_n = gst_value_get_fraction_numerator (fps); - ffmpegdec->format.video.fps_d = gst_value_get_fraction_denominator (fps); - GST_DEBUG_OBJECT (ffmpegdec, "Using framerate %d/%d from incoming caps", - ffmpegdec->format.video.fps_n, ffmpegdec->format.video.fps_d); - } else { - ffmpegdec->format.video.fps_n = -1; - GST_DEBUG_OBJECT (ffmpegdec, "Using framerate from codec"); - } - - /* figure out if we can use direct rendering */ - ffmpegdec->current_dr = FALSE; - ffmpegdec->extra_ref = FALSE; - if (ffmpegdec->direct_rendering) { - GST_DEBUG_OBJECT (ffmpegdec, "trying to enable direct rendering"); - if (oclass->in_plugin->capabilities & CODEC_CAP_DR1) { - if (oclass->in_plugin->id == CODEC_ID_H264) { - GST_DEBUG_OBJECT (ffmpegdec, "disable direct rendering setup for H264"); - /* does not work, many stuff reads outside of the planes */ - ffmpegdec->current_dr = FALSE; - ffmpegdec->extra_ref = TRUE; - } else if ((oclass->in_plugin->id == CODEC_ID_SVQ1) || - (oclass->in_plugin->id == CODEC_ID_VP5) || - (oclass->in_plugin->id == CODEC_ID_VP6) || - (oclass->in_plugin->id == CODEC_ID_VP6F) || - (oclass->in_plugin->id == CODEC_ID_VP6A)) { - GST_DEBUG_OBJECT (ffmpegdec, - "disable direct rendering setup for broken stride support"); - /* does not work, uses a incompatible stride. See #610613 */ - ffmpegdec->current_dr = FALSE; - ffmpegdec->extra_ref = TRUE; - } else { - GST_DEBUG_OBJECT (ffmpegdec, "enabled direct rendering"); - ffmpegdec->current_dr = TRUE; - } - } else { - GST_DEBUG_OBJECT (ffmpegdec, "direct rendering not supported"); - } - } - if (ffmpegdec->current_dr) { - /* do *not* draw edges when in direct rendering, for some reason it draws - * outside of the memory. */ - ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE; - } - /* for AAC we only use av_parse if not on stream-format==raw or ==loas */ if (oclass->in_plugin->id == CODEC_ID_AAC || oclass->in_plugin->id == CODEC_ID_AAC_LATM) { @@ -876,48 +413,12 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT; ffmpegdec->context->error_recognition = 1; - /* for slow cpus */ - ffmpegdec->context->lowres = ffmpegdec->lowres; - ffmpegdec->context->skip_frame = ffmpegdec->skip_frame; - - /* ffmpeg can draw motion vectors on top of the image (not every decoder - * supports it) */ - ffmpegdec->context->debug_mv = ffmpegdec->debug_mv; - - if (ffmpegdec->max_threads == 0) { - if (!(oclass->in_plugin->capabilities & CODEC_CAP_AUTO_THREADS)) - ffmpegdec->context->thread_count = gst_ffmpeg_auto_max_threads (); - else - ffmpegdec->context->thread_count = 0; - } else - ffmpegdec->context->thread_count = ffmpegdec->max_threads; - - ffmpegdec->context->thread_type = FF_THREAD_SLICE; - /* open codec - we don't select an output pix_fmt yet, * simply because we don't know! We only get it * during playback... */ - if (!gst_ffmpegdec_open (ffmpegdec)) + if (!gst_ffmpegauddec_open (ffmpegdec)) goto open_failed; - /* clipping region */ - gst_structure_get_int (structure, "width", - &ffmpegdec->format.video.clip_width); - gst_structure_get_int (structure, "height", - &ffmpegdec->format.video.clip_height); - - GST_DEBUG_OBJECT (pad, "clipping to %dx%d", - ffmpegdec->format.video.clip_width, ffmpegdec->format.video.clip_height); - - /* take into account the lowres property */ - if (ffmpegdec->format.video.clip_width != -1) - ffmpegdec->format.video.clip_width >>= ffmpegdec->lowres; - if (ffmpegdec->format.video.clip_height != -1) - ffmpegdec->format.video.clip_height >>= ffmpegdec->lowres; - - GST_DEBUG_OBJECT (pad, "final clipping to %dx%d", - ffmpegdec->format.video.clip_width, ffmpegdec->format.video.clip_height); - done: GST_OBJECT_UNLOCK (ffmpegdec); @@ -929,365 +430,34 @@ done: open_failed: { GST_DEBUG_OBJECT (ffmpegdec, "Failed to open"); - if (ffmpegdec->par) { - g_free (ffmpegdec->par); - ffmpegdec->par = NULL; - } ret = FALSE; goto done; } } -static GstFlowReturn -alloc_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf, - gint width, gint height) -{ - GstFlowReturn ret; - gint fsize; - - ret = GST_FLOW_ERROR; - *outbuf = NULL; - - GST_LOG_OBJECT (ffmpegdec, "alloc output buffer"); - - /* see if we need renegotiation */ - if (G_UNLIKELY (!gst_ffmpegdec_negotiate (ffmpegdec, FALSE))) - goto negotiate_failed; - - /* get the size of the gstreamer output buffer given a - * width/height/format */ - fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt, - width, height); - - if (!ffmpegdec->context->palctrl && ffmpegdec->can_allocate_aligned) { - GST_LOG_OBJECT (ffmpegdec, "calling pad_alloc"); - /* no pallete, we can use the buffer size to alloc */ - ret = gst_pad_alloc_buffer_and_set_caps (ffmpegdec->srcpad, - GST_BUFFER_OFFSET_NONE, fsize, - GST_PAD_CAPS (ffmpegdec->srcpad), outbuf); - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto alloc_failed; - - /* If buffer isn't 128-bit aligned, create a memaligned one ourselves */ - if (((uintptr_t) GST_BUFFER_DATA (*outbuf)) % 16) { - GST_DEBUG_OBJECT (ffmpegdec, - "Downstream can't allocate aligned buffers."); - ffmpegdec->can_allocate_aligned = FALSE; - gst_buffer_unref (*outbuf); - *outbuf = new_aligned_buffer (fsize, GST_PAD_CAPS (ffmpegdec->srcpad)); - } - } else { - GST_LOG_OBJECT (ffmpegdec, - "not calling pad_alloc, we have a pallete or downstream can't give 16 byte aligned buffers."); - /* for paletted data we can't use pad_alloc_buffer(), because - * fsize contains the size of the palette, so the overall size - * is bigger than ffmpegcolorspace's unit size, which will - * prompt GstBaseTransform to complain endlessly ... */ - *outbuf = new_aligned_buffer (fsize, GST_PAD_CAPS (ffmpegdec->srcpad)); - ret = GST_FLOW_OK; - } - /* set caps, we do this here because the buffer is still writable here and we - * are sure to be negotiated */ - gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (ffmpegdec->srcpad)); - - return ret; - - /* special cases */ -negotiate_failed: - { - GST_DEBUG_OBJECT (ffmpegdec, "negotiate failed"); - return GST_FLOW_NOT_NEGOTIATED; - } -alloc_failed: - { - GST_DEBUG_OBJECT (ffmpegdec, "pad_alloc failed %d (%s)", ret, - gst_flow_get_name (ret)); - return ret; - } -} - -static int -gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture) -{ - GstBuffer *buf = NULL; - GstFFMpegDec *ffmpegdec; - gint width, height; - gint coded_width, coded_height; - gint res; - - ffmpegdec = (GstFFMpegDec *) context->opaque; - - GST_DEBUG_OBJECT (ffmpegdec, "getting buffer"); - - /* apply the last info we have seen to this picture, when we get the - * picture back from ffmpeg we can use this to correctly timestamp the output - * buffer */ - picture->reordered_opaque = context->reordered_opaque; - /* make sure we don't free the buffer when it's not ours */ - picture->opaque = NULL; - - /* take width and height before clipping */ - width = context->width; - height = context->height; - coded_width = context->coded_width; - coded_height = context->coded_height; - - GST_LOG_OBJECT (ffmpegdec, "dimension %dx%d, coded %dx%d", width, height, - coded_width, coded_height); - if (!ffmpegdec->current_dr) { - GST_LOG_OBJECT (ffmpegdec, "direct rendering disabled, fallback alloc"); - res = avcodec_default_get_buffer (context, picture); - - GST_LOG_OBJECT (ffmpegdec, "linsize %d %d %d", picture->linesize[0], - picture->linesize[1], picture->linesize[2]); - GST_LOG_OBJECT (ffmpegdec, "data %u %u %u", 0, - (guint) (picture->data[1] - picture->data[0]), - (guint) (picture->data[2] - picture->data[0])); - return res; - } - - switch (context->codec_type) { - case AVMEDIA_TYPE_VIDEO: - /* some ffmpeg video plugins don't see the point in setting codec_type ... */ - case AVMEDIA_TYPE_UNKNOWN: - { - GstFlowReturn ret; - gint clip_width, clip_height; - - /* take final clipped output size */ - if ((clip_width = ffmpegdec->format.video.clip_width) == -1) - clip_width = width; - if ((clip_height = ffmpegdec->format.video.clip_height) == -1) - clip_height = height; - - GST_LOG_OBJECT (ffmpegdec, "raw outsize %d/%d", width, height); - - /* this is the size ffmpeg needs for the buffer */ - avcodec_align_dimensions (context, &width, &height); - - GST_LOG_OBJECT (ffmpegdec, "aligned outsize %d/%d, clip %d/%d", - width, height, clip_width, clip_height); - - if (width != clip_width || height != clip_height) { - /* We can't alloc if we need to clip the output buffer later */ - GST_LOG_OBJECT (ffmpegdec, "we need clipping, fallback alloc"); - return avcodec_default_get_buffer (context, picture); - } - - /* alloc with aligned dimensions for ffmpeg */ - ret = alloc_output_buffer (ffmpegdec, &buf, width, height); - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - /* alloc default buffer when we can't get one from downstream */ - GST_LOG_OBJECT (ffmpegdec, "alloc failed, fallback alloc"); - return avcodec_default_get_buffer (context, picture); - } - - /* copy the right pointers and strides in the picture object */ - gst_ffmpeg_avpicture_fill ((AVPicture *) picture, - GST_BUFFER_DATA (buf), context->pix_fmt, width, height); - break; - } - case AVMEDIA_TYPE_AUDIO: - default: - GST_ERROR_OBJECT (ffmpegdec, - "_get_buffer() should never get called for non-video buffers !"); - g_assert_not_reached (); - break; - } - - /* tell ffmpeg we own this buffer, tranfer the ref we have on the buffer to - * the opaque data. */ - picture->type = FF_BUFFER_TYPE_USER; - picture->age = 256 * 256 * 256 * 64; - picture->opaque = buf; - -#ifdef EXTRA_REF - if (picture->reference != 0 || ffmpegdec->extra_ref) { - GST_DEBUG_OBJECT (ffmpegdec, "adding extra ref"); - gst_buffer_ref (buf); - } -#endif - - GST_LOG_OBJECT (ffmpegdec, "returned buffer %p", buf); - - return 0; -} - -static void -gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture) -{ - gint i; - GstBuffer *buf; - GstFFMpegDec *ffmpegdec; - - ffmpegdec = (GstFFMpegDec *) context->opaque; - - /* check if it was our buffer */ - if (picture->opaque == NULL) { - GST_DEBUG_OBJECT (ffmpegdec, "default release buffer"); - avcodec_default_release_buffer (context, picture); - return; - } - - /* we remove the opaque data now */ - buf = GST_BUFFER_CAST (picture->opaque); - GST_DEBUG_OBJECT (ffmpegdec, "release buffer %p", buf); - picture->opaque = NULL; - -#ifdef EXTRA_REF - if (picture->reference != 0 || ffmpegdec->extra_ref) { - GST_DEBUG_OBJECT (ffmpegdec, "remove extra ref"); - gst_buffer_unref (buf); - } -#else - gst_buffer_unref (buf); -#endif - - /* zero out the reference in ffmpeg */ - for (i = 0; i < 4; i++) { - picture->data[i] = NULL; - picture->linesize[i] = 0; - } -} - -static void -gst_ffmpegdec_add_pixel_aspect_ratio (GstFFMpegDec * ffmpegdec, - GstStructure * s) -{ - gboolean demuxer_par_set = FALSE; - gboolean decoder_par_set = FALSE; - gint demuxer_num = 1, demuxer_denom = 1; - gint decoder_num = 1, decoder_denom = 1; - - GST_OBJECT_LOCK (ffmpegdec); - - if (ffmpegdec->par) { - demuxer_num = gst_value_get_fraction_numerator (ffmpegdec->par); - demuxer_denom = gst_value_get_fraction_denominator (ffmpegdec->par); - demuxer_par_set = TRUE; - GST_DEBUG_OBJECT (ffmpegdec, "Demuxer PAR: %d:%d", demuxer_num, - demuxer_denom); - } - - if (ffmpegdec->context->sample_aspect_ratio.num && - ffmpegdec->context->sample_aspect_ratio.den) { - decoder_num = ffmpegdec->context->sample_aspect_ratio.num; - decoder_denom = ffmpegdec->context->sample_aspect_ratio.den; - decoder_par_set = TRUE; - GST_DEBUG_OBJECT (ffmpegdec, "Decoder PAR: %d:%d", decoder_num, - decoder_denom); - } - - GST_OBJECT_UNLOCK (ffmpegdec); - - if (!demuxer_par_set && !decoder_par_set) - goto no_par; - - if (demuxer_par_set && !decoder_par_set) - goto use_demuxer_par; - - if (decoder_par_set && !demuxer_par_set) - goto use_decoder_par; - - /* Both the demuxer and the decoder provide a PAR. If one of - * the two PARs is 1:1 and the other one is not, use the one - * that is not 1:1. */ - if (demuxer_num == demuxer_denom && decoder_num != decoder_denom) - goto use_decoder_par; - - if (decoder_num == decoder_denom && demuxer_num != demuxer_denom) - goto use_demuxer_par; - - /* Both PARs are non-1:1, so use the PAR provided by the demuxer */ - goto use_demuxer_par; - -use_decoder_par: - { - GST_DEBUG_OBJECT (ffmpegdec, - "Setting decoder provided pixel-aspect-ratio of %u:%u", decoder_num, - decoder_denom); - gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, decoder_num, - decoder_denom, NULL); - return; - } - -use_demuxer_par: - { - GST_DEBUG_OBJECT (ffmpegdec, - "Setting demuxer provided pixel-aspect-ratio of %u:%u", demuxer_num, - demuxer_denom); - gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, demuxer_num, - demuxer_denom, NULL); - return; - } -no_par: - { - GST_DEBUG_OBJECT (ffmpegdec, - "Neither demuxer nor codec provide a pixel-aspect-ratio"); - return; - } -} - static gboolean -gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, gboolean force) +gst_ffmpegauddec_negotiate (GstFFMpegAudDec * ffmpegdec, gboolean force) { - GstFFMpegDecClass *oclass; + GstFFMpegAudDecClass *oclass; GstCaps *caps; + gint depth; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - if (!force && ffmpegdec->format.video.width == ffmpegdec->context->width - && ffmpegdec->format.video.height == ffmpegdec->context->height - && ffmpegdec->format.video.fps_n == ffmpegdec->format.video.old_fps_n - && ffmpegdec->format.video.fps_d == ffmpegdec->format.video.old_fps_d - && ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt - && ffmpegdec->format.video.par_n == - ffmpegdec->context->sample_aspect_ratio.num - && ffmpegdec->format.video.par_d == - ffmpegdec->context->sample_aspect_ratio.den) - return TRUE; - GST_DEBUG_OBJECT (ffmpegdec, - "Renegotiating video from %dx%d@ %d:%d PAR %d/%d fps to %dx%d@ %d:%d PAR %d/%d fps", - ffmpegdec->format.video.width, ffmpegdec->format.video.height, - ffmpegdec->format.video.par_n, ffmpegdec->format.video.par_d, - ffmpegdec->format.video.old_fps_n, ffmpegdec->format.video.old_fps_n, - ffmpegdec->context->width, ffmpegdec->context->height, - ffmpegdec->context->sample_aspect_ratio.num, - ffmpegdec->context->sample_aspect_ratio.den, - ffmpegdec->format.video.fps_n, ffmpegdec->format.video.fps_d); - ffmpegdec->format.video.width = ffmpegdec->context->width; - ffmpegdec->format.video.height = ffmpegdec->context->height; - ffmpegdec->format.video.old_fps_n = ffmpegdec->format.video.fps_n; - ffmpegdec->format.video.old_fps_d = ffmpegdec->format.video.fps_d; - ffmpegdec->format.video.pix_fmt = ffmpegdec->context->pix_fmt; - ffmpegdec->format.video.par_n = - ffmpegdec->context->sample_aspect_ratio.num; - ffmpegdec->format.video.par_d = - ffmpegdec->context->sample_aspect_ratio.den; - break; - case AVMEDIA_TYPE_AUDIO: - { - gint depth = av_smp_format_depth (ffmpegdec->context->sample_fmt); - if (!force && ffmpegdec->format.audio.samplerate == - ffmpegdec->context->sample_rate && - ffmpegdec->format.audio.channels == ffmpegdec->context->channels && - ffmpegdec->format.audio.depth == depth) - return TRUE; - GST_DEBUG_OBJECT (ffmpegdec, - "Renegotiating audio from %dHz@%dchannels (%d) to %dHz@%dchannels (%d)", - ffmpegdec->format.audio.samplerate, ffmpegdec->format.audio.channels, - ffmpegdec->format.audio.depth, - ffmpegdec->context->sample_rate, ffmpegdec->context->channels, depth); - ffmpegdec->format.audio.samplerate = ffmpegdec->context->sample_rate; - ffmpegdec->format.audio.channels = ffmpegdec->context->channels; - ffmpegdec->format.audio.depth = depth; - } - break; - default: - break; - } + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + + depth = av_smp_format_depth (ffmpegdec->context->sample_fmt); + if (!force && ffmpegdec->format.audio.samplerate == + ffmpegdec->context->sample_rate && + ffmpegdec->format.audio.channels == ffmpegdec->context->channels && + ffmpegdec->format.audio.depth == depth) + return TRUE; + GST_DEBUG_OBJECT (ffmpegdec, + "Renegotiating audio from %dHz@%dchannels (%d) to %dHz@%dchannels (%d)", + ffmpegdec->format.audio.samplerate, ffmpegdec->format.audio.channels, + ffmpegdec->format.audio.depth, + ffmpegdec->context->sample_rate, ffmpegdec->context->channels, depth); + ffmpegdec->format.audio.samplerate = ffmpegdec->context->sample_rate; + ffmpegdec->format.audio.channels = ffmpegdec->context->channels; + ffmpegdec->format.audio.depth = depth; caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type, ffmpegdec->context, oclass->in_plugin->id, FALSE); @@ -1295,45 +465,6 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, gboolean force) if (caps == NULL) goto no_caps; - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - { - gint width, height; - gboolean interlaced; - - width = ffmpegdec->format.video.clip_width; - height = ffmpegdec->format.video.clip_height; - interlaced = ffmpegdec->format.video.interlaced; - - if (width != -1 && height != -1) { - /* overwrite the output size with the dimension of the - * clipping region but only if they are smaller. */ - if (width < ffmpegdec->context->width) - gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL); - if (height < ffmpegdec->context->height) - gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL); - } - gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced, - NULL); - - /* If a demuxer provided a framerate then use it (#313970) */ - if (ffmpegdec->format.video.fps_n != -1) { - gst_caps_set_simple (caps, "framerate", - GST_TYPE_FRACTION, ffmpegdec->format.video.fps_n, - ffmpegdec->format.video.fps_d, NULL); - } - gst_ffmpegdec_add_pixel_aspect_ratio (ffmpegdec, - gst_caps_get_structure (caps, 0)); - break; - } - case AVMEDIA_TYPE_AUDIO: - { - break; - } - default: - break; - } - if (!gst_pad_set_caps (ffmpegdec->srcpad, caps)) goto caps_failed; @@ -1373,287 +504,9 @@ caps_failed: } } -/* perform qos calculations before decoding the next frame. - * - * Sets the skip_frame flag and if things are really bad, skips to the next - * keyframe. - * - * Returns TRUE if the frame should be decoded, FALSE if the frame can be dropped - * entirely. - */ -static gboolean -gst_ffmpegdec_do_qos (GstFFMpegDec * ffmpegdec, GstClockTime timestamp, - gboolean * mode_switch) -{ - GstClockTimeDiff diff; - gdouble proportion; - GstClockTime qostime, earliest_time; - gboolean res = TRUE; - - *mode_switch = FALSE; - - /* no timestamp, can't do QoS */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) - goto no_qos; - - /* get latest QoS observation values */ - gst_ffmpegdec_read_qos (ffmpegdec, &proportion, &earliest_time); - - /* skip qos if we have no observation (yet) */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) { - /* no skip_frame initialy */ - ffmpegdec->context->skip_frame = AVDISCARD_DEFAULT; - goto no_qos; - } - - /* qos is done on running time of the timestamp */ - qostime = gst_segment_to_running_time (&ffmpegdec->segment, GST_FORMAT_TIME, - timestamp); - - /* timestamp can be out of segment, then we don't do QoS */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime))) - goto no_qos; - - /* see how our next timestamp relates to the latest qos timestamp. negative - * values mean we are early, positive values mean we are too late. */ - diff = GST_CLOCK_DIFF (qostime, earliest_time); - - GST_DEBUG_OBJECT (ffmpegdec, "QOS: qostime %" GST_TIME_FORMAT - ", earliest %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), - GST_TIME_ARGS (earliest_time)); - - /* if we using less than 40% of the available time, we can try to - * speed up again when we were slow. */ - if (proportion < 0.4 && diff < 0) { - goto normal_mode; - } else { - if (diff >= 0) { - /* we're too slow, try to speed up */ - if (ffmpegdec->waiting_for_key) { - /* we were waiting for a keyframe, that's ok */ - goto skipping; - } - /* switch to skip_frame mode */ - goto skip_frame; - } - } - -no_qos: - ffmpegdec->processed++; - return TRUE; - -skipping: - { - res = FALSE; - goto drop_qos; - } -normal_mode: - { - if (ffmpegdec->context->skip_frame != AVDISCARD_DEFAULT) { - ffmpegdec->context->skip_frame = AVDISCARD_DEFAULT; - *mode_switch = TRUE; - GST_DEBUG_OBJECT (ffmpegdec, "QOS: normal mode %g < 0.4", proportion); - } - ffmpegdec->processed++; - return TRUE; - } -skip_frame: - { - if (ffmpegdec->context->skip_frame != AVDISCARD_NONREF) { - ffmpegdec->context->skip_frame = AVDISCARD_NONREF; - *mode_switch = TRUE; - GST_DEBUG_OBJECT (ffmpegdec, - "QOS: hurry up, diff %" G_GINT64_FORMAT " >= 0", diff); - } - goto drop_qos; - } -drop_qos: - { - GstClockTime stream_time, jitter; - GstMessage *qos_msg; - - ffmpegdec->dropped++; - stream_time = - gst_segment_to_stream_time (&ffmpegdec->segment, GST_FORMAT_TIME, - timestamp); - jitter = GST_CLOCK_DIFF (qostime, earliest_time); - qos_msg = - gst_message_new_qos (GST_OBJECT_CAST (ffmpegdec), 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, - ffmpegdec->processed, ffmpegdec->dropped); - gst_element_post_message (GST_ELEMENT_CAST (ffmpegdec), qos_msg); - - return res; - } -} - -/* returns TRUE if buffer is within segment, else FALSE. - * if Buffer is on segment border, it's timestamp and duration will be clipped */ -static gboolean -clip_video_buffer (GstFFMpegDec * dec, GstBuffer * buf, GstClockTime in_ts, - GstClockTime in_dur) -{ - gboolean res = TRUE; - gint64 cstart, cstop; - GstClockTime stop; - - GST_LOG_OBJECT (dec, - "timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT, - GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur)); - - /* can't clip without TIME segment */ - if (G_UNLIKELY (dec->segment.format != GST_FORMAT_TIME)) - goto beach; - - /* we need a start time */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) - goto beach; - - /* generate valid stop, if duration unknown, we have unknown stop */ - stop = - GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE; - - /* now clip */ - res = - gst_segment_clip (&dec->segment, GST_FORMAT_TIME, in_ts, stop, &cstart, - &cstop); - if (G_UNLIKELY (!res)) - goto beach; - - /* we're pretty sure the duration of this buffer is not till the end of this - * segment (which _clip will assume when the stop is -1) */ - if (stop == GST_CLOCK_TIME_NONE) - cstop = GST_CLOCK_TIME_NONE; - - /* update timestamp and possibly duration if the clipped stop time is - * valid */ - GST_BUFFER_TIMESTAMP (buf) = cstart; - if (GST_CLOCK_TIME_IS_VALID (cstop)) - GST_BUFFER_DURATION (buf) = cstop - cstart; - - GST_LOG_OBJECT (dec, - "clipped timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT, - GST_TIME_ARGS (cstart), GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - -beach: - GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : "")); - return res; -} - - -/* figure out if the current picture is a keyframe, return TRUE if that is - * the case. */ -static gboolean -check_keyframe (GstFFMpegDec * ffmpegdec) -{ - GstFFMpegDecClass *oclass; - gboolean is_itype = FALSE; - gboolean is_reference = FALSE; - gboolean iskeyframe; - - /* figure out if we are dealing with a keyframe */ - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - - /* remember that we have B frames, we need this for the DTS -> PTS conversion - * code */ - if (!ffmpegdec->has_b_frames && ffmpegdec->picture->pict_type == FF_B_TYPE) { - GST_DEBUG_OBJECT (ffmpegdec, "we have B frames"); - ffmpegdec->has_b_frames = TRUE; - /* Emit latency message to recalculate it */ - gst_element_post_message (GST_ELEMENT_CAST (ffmpegdec), - gst_message_new_latency (GST_OBJECT_CAST (ffmpegdec))); - } - - is_itype = (ffmpegdec->picture->pict_type == FF_I_TYPE); - is_reference = (ffmpegdec->picture->reference == 1); - - iskeyframe = (is_itype || is_reference || ffmpegdec->picture->key_frame) - || (oclass->in_plugin->id == CODEC_ID_INDEO3) - || (oclass->in_plugin->id == CODEC_ID_MSZH) - || (oclass->in_plugin->id == CODEC_ID_ZLIB) - || (oclass->in_plugin->id == CODEC_ID_VP3) - || (oclass->in_plugin->id == CODEC_ID_HUFFYUV); - - GST_LOG_OBJECT (ffmpegdec, - "current picture: type: %d, is_keyframe:%d, is_itype:%d, is_reference:%d", - ffmpegdec->picture->pict_type, iskeyframe, is_itype, is_reference); - - return iskeyframe; -} - -/* get an outbuf buffer with the current picture */ -static GstFlowReturn -get_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf) -{ - GstFlowReturn ret; - - ret = GST_FLOW_OK; - *outbuf = NULL; - - if (ffmpegdec->picture->opaque != NULL) { - /* we allocated a picture already for ffmpeg to decode into, let's pick it - * up and use it now. */ - *outbuf = (GstBuffer *) ffmpegdec->picture->opaque; - GST_LOG_OBJECT (ffmpegdec, "using opaque buffer %p", *outbuf); -#ifndef EXTRA_REF - gst_buffer_ref (*outbuf); -#endif - } else { - AVPicture pic, *outpic; - gint width, height; - - GST_LOG_OBJECT (ffmpegdec, "get output buffer"); - - /* figure out size of output buffer, this is the clipped output size because - * we will copy the picture into it but only when the clipping region is - * smaller than the actual picture size. */ - if ((width = ffmpegdec->format.video.clip_width) == -1) - width = ffmpegdec->context->width; - else if (width > ffmpegdec->context->width) - width = ffmpegdec->context->width; - - if ((height = ffmpegdec->format.video.clip_height) == -1) - height = ffmpegdec->context->height; - else if (height > ffmpegdec->context->height) - height = ffmpegdec->context->height; - - GST_LOG_OBJECT (ffmpegdec, "clip width %d/height %d", width, height); - - ret = alloc_output_buffer (ffmpegdec, outbuf, width, height); - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto alloc_failed; - - /* original ffmpeg code does not handle odd sizes correctly. - * This patched up version does */ - gst_ffmpeg_avpicture_fill (&pic, GST_BUFFER_DATA (*outbuf), - ffmpegdec->context->pix_fmt, width, height); - - outpic = (AVPicture *) ffmpegdec->picture; - - GST_LOG_OBJECT (ffmpegdec, "linsize %d %d %d", outpic->linesize[0], - outpic->linesize[1], outpic->linesize[2]); - GST_LOG_OBJECT (ffmpegdec, "data %u %u %u", 0, - (guint) (outpic->data[1] - outpic->data[0]), - (guint) (outpic->data[2] - outpic->data[0])); - - av_picture_copy (&pic, outpic, ffmpegdec->context->pix_fmt, width, height); - } - ffmpegdec->picture->reordered_opaque = -1; - - return ret; - - /* special cases */ -alloc_failed: - { - GST_DEBUG_OBJECT (ffmpegdec, "pad_alloc failed"); - return ret; - } -} static void -clear_queued (GstFFMpegDec * ffmpegdec) +clear_queued (GstFFMpegAudDec * ffmpegdec) { g_list_foreach (ffmpegdec->queued, (GFunc) gst_mini_object_unref, NULL); g_list_free (ffmpegdec->queued); @@ -1661,7 +514,7 @@ clear_queued (GstFFMpegDec * ffmpegdec) } static GstFlowReturn -flush_queued (GstFFMpegDec * ffmpegdec) +flush_queued (GstFFMpegAudDec * ffmpegdec) { GstFlowReturn res = GST_FLOW_OK; @@ -1692,380 +545,10 @@ gst_avpacket_init (AVPacket * packet, guint8 * data, guint size) packet->size = size; } -/* gst_ffmpegdec_[video|audio]_frame: - * ffmpegdec: - * data: pointer to the data to decode - * size: size of data in bytes - * in_timestamp: incoming timestamp. - * in_duration: incoming duration. - * in_offset: incoming offset (frame number). - * outbuf: outgoing buffer. Different from NULL ONLY if it contains decoded data. - * ret: Return flow. - * - * Returns: number of bytes used in decoding. The check for successful decode is - * outbuf being non-NULL. - */ -static gint -gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, - guint8 * data, guint size, - const GstTSInfo * dec_info, GstBuffer ** outbuf, GstFlowReturn * ret) -{ - gint len = -1; - gint have_data; - gboolean iskeyframe; - gboolean mode_switch; - gboolean decode; - gint skip_frame = AVDISCARD_DEFAULT; - GstClockTime out_timestamp, out_duration, out_pts; - gint64 out_offset; - const GstTSInfo *out_info; - AVPacket packet; - - *ret = GST_FLOW_OK; - *outbuf = NULL; - - ffmpegdec->context->opaque = ffmpegdec; - - /* in case we skip frames */ - ffmpegdec->picture->pict_type = -1; - - /* run QoS code, we don't stop decoding the frame when we are late because - * else we might skip a reference frame */ - decode = gst_ffmpegdec_do_qos (ffmpegdec, dec_info->timestamp, &mode_switch); - - if (ffmpegdec->is_realvideo && data != NULL) { - gint slice_count; - gint i; - - /* setup the slice table for realvideo */ - if (ffmpegdec->context->slice_offset == NULL) - ffmpegdec->context->slice_offset = g_malloc (sizeof (guint32) * 1000); - - slice_count = (*data++) + 1; - ffmpegdec->context->slice_count = slice_count; - - for (i = 0; i < slice_count; i++) { - data += 4; - ffmpegdec->context->slice_offset[i] = GST_READ_UINT32_LE (data); - data += 4; - } - } - - if (!decode) { - /* no decoding needed, save previous skip_frame value and brutely skip - * decoding everything */ - skip_frame = ffmpegdec->context->skip_frame; - ffmpegdec->context->skip_frame = AVDISCARD_NONREF; - } - - /* save reference to the timing info */ - ffmpegdec->context->reordered_opaque = (gint64) dec_info->idx; - ffmpegdec->picture->reordered_opaque = (gint64) dec_info->idx; - - GST_DEBUG_OBJECT (ffmpegdec, "stored opaque values idx %d", dec_info->idx); - - /* now decode the frame */ - gst_avpacket_init (&packet, data, size); - len = avcodec_decode_video2 (ffmpegdec->context, - ffmpegdec->picture, &have_data, &packet); - - /* restore previous state */ - if (!decode) - ffmpegdec->context->skip_frame = skip_frame; - - GST_DEBUG_OBJECT (ffmpegdec, "after decode: len %d, have_data %d", - len, have_data); - - /* when we are in skip_frame mode, don't complain when ffmpeg returned - * no data because we told it to skip stuff. */ - if (len < 0 && (mode_switch || ffmpegdec->context->skip_frame)) - len = 0; - - if (len > 0 && have_data <= 0 && (mode_switch - || ffmpegdec->context->skip_frame)) { - /* we consumed some bytes but nothing decoded and we are skipping frames, - * disable the interpollation of DTS timestamps */ - ffmpegdec->last_out = -1; - } - - /* no data, we're done */ - if (len < 0 || have_data <= 0) - goto beach; - - /* get the output picture timing info again */ - out_info = gst_ts_info_get (ffmpegdec, ffmpegdec->picture->reordered_opaque); - out_pts = out_info->timestamp; - out_duration = out_info->duration; - out_offset = out_info->offset; - - GST_DEBUG_OBJECT (ffmpegdec, - "pts %" G_GUINT64_FORMAT " duration %" G_GUINT64_FORMAT " offset %" - G_GINT64_FORMAT, out_pts, out_duration, out_offset); - GST_DEBUG_OBJECT (ffmpegdec, "picture: pts %" G_GUINT64_FORMAT, - (guint64) ffmpegdec->picture->pts); - GST_DEBUG_OBJECT (ffmpegdec, "picture: num %d", - ffmpegdec->picture->coded_picture_number); - GST_DEBUG_OBJECT (ffmpegdec, "picture: ref %d", - ffmpegdec->picture->reference); - GST_DEBUG_OBJECT (ffmpegdec, "picture: display %d", - ffmpegdec->picture->display_picture_number); - GST_DEBUG_OBJECT (ffmpegdec, "picture: opaque %p", - ffmpegdec->picture->opaque); - GST_DEBUG_OBJECT (ffmpegdec, "picture: reordered opaque %" G_GUINT64_FORMAT, - (guint64) ffmpegdec->picture->reordered_opaque); - GST_DEBUG_OBJECT (ffmpegdec, "repeat_pict:%d", - ffmpegdec->picture->repeat_pict); - GST_DEBUG_OBJECT (ffmpegdec, "interlaced_frame:%d", - ffmpegdec->picture->interlaced_frame); - - if (G_UNLIKELY (ffmpegdec->picture->interlaced_frame != - ffmpegdec->format.video.interlaced)) { - GST_WARNING ("Change in interlacing ! picture:%d, recorded:%d", - ffmpegdec->picture->interlaced_frame, - ffmpegdec->format.video.interlaced); - ffmpegdec->format.video.interlaced = ffmpegdec->picture->interlaced_frame; - gst_ffmpegdec_negotiate (ffmpegdec, TRUE); - } - - - /* Whether a frame is interlaced or not is unknown at the time of - buffer allocation, so caps on the buffer in opaque will have - the previous frame's interlaced flag set. So if interlacedness - has changed since allocation, we update the buffer (if any) - caps now with the correct interlaced flag. */ - if (ffmpegdec->picture->opaque != NULL) { - GstBuffer *buffer = ffmpegdec->picture->opaque; - if (GST_BUFFER_CAPS (buffer) && GST_PAD_CAPS (ffmpegdec->srcpad)) { - GstStructure *s = gst_caps_get_structure (GST_BUFFER_CAPS (buffer), 0); - gboolean interlaced; - gboolean found = gst_structure_get_boolean (s, "interlaced", &interlaced); - if (!found || (! !interlaced != ! !ffmpegdec->format.video.interlaced)) { - GST_DEBUG_OBJECT (ffmpegdec, - "Buffer interlacing does not match pad, updating"); - buffer = gst_buffer_make_metadata_writable (buffer); - gst_buffer_set_caps (buffer, GST_PAD_CAPS (ffmpegdec->srcpad)); - ffmpegdec->picture->opaque = buffer; - } - } - } - - /* check if we are dealing with a keyframe here, this will also check if we - * are dealing with B frames. */ - iskeyframe = check_keyframe (ffmpegdec); - - /* check that the timestamps go upwards */ - if (ffmpegdec->last_out != -1 && ffmpegdec->last_out > out_pts) { - /* timestamps go backwards, this means frames were reordered and we must - * be dealing with DTS as the buffer timestamps */ - if (!ffmpegdec->reordered_out) { - GST_DEBUG_OBJECT (ffmpegdec, "detected reordered out timestamps"); - ffmpegdec->reordered_out = TRUE; - } - if (ffmpegdec->reordered_in) { - /* we reset the input reordering here because we want to recover from an - * occasionally wrong reordered input timestamp */ - GST_DEBUG_OBJECT (ffmpegdec, "assuming DTS input timestamps"); - ffmpegdec->reordered_in = FALSE; - } - } - - if (out_pts == 0 && out_pts == ffmpegdec->last_out) { - GST_LOG_OBJECT (ffmpegdec, "ffmpeg returns 0 timestamps, ignoring"); - /* some codecs only output 0 timestamps, when that happens, make us select an - * output timestamp based on the input timestamp. We do this by making the - * ffmpeg timestamp and the interpollated next timestamp invalid. */ - out_pts = -1; - ffmpegdec->next_out = -1; - } else - ffmpegdec->last_out = out_pts; - - /* we assume DTS as input timestamps unless we see reordered input - * timestamps */ - if (!ffmpegdec->reordered_in && ffmpegdec->reordered_out) { - /* PTS and DTS are the same for keyframes */ - if (!iskeyframe && ffmpegdec->next_out != -1) { - /* interpolate all timestamps except for keyframes, FIXME, this is - * wrong when QoS is active. */ - GST_DEBUG_OBJECT (ffmpegdec, "interpolate timestamps"); - out_pts = -1; - out_offset = -1; - } - } - - /* when we're waiting for a keyframe, see if we have one or drop the current - * non-keyframe */ - if (G_UNLIKELY (ffmpegdec->waiting_for_key)) { - if (G_LIKELY (!iskeyframe)) - goto drop_non_keyframe; - - /* we have a keyframe, we can stop waiting for one */ - ffmpegdec->waiting_for_key = FALSE; - } - - /* get a handle to the output buffer */ - *ret = get_output_buffer (ffmpegdec, outbuf); - if (G_UNLIKELY (*ret != GST_FLOW_OK)) - goto no_output; - - /* - * Timestamps: - * - * 1) Copy picture timestamp if valid - * 2) else interpolate from previous output timestamp - * 3) else copy input timestamp - */ - out_timestamp = -1; - if (out_pts != -1) { - /* Get (interpolated) timestamp from FFMPEG */ - out_timestamp = (GstClockTime) out_pts; - GST_LOG_OBJECT (ffmpegdec, "using timestamp %" GST_TIME_FORMAT - " returned by ffmpeg", GST_TIME_ARGS (out_timestamp)); - } - if (!GST_CLOCK_TIME_IS_VALID (out_timestamp) && ffmpegdec->next_out != -1) { - out_timestamp = ffmpegdec->next_out; - GST_LOG_OBJECT (ffmpegdec, "using next timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (out_timestamp)); - } - if (!GST_CLOCK_TIME_IS_VALID (out_timestamp)) { - out_timestamp = dec_info->timestamp; - GST_LOG_OBJECT (ffmpegdec, "using in timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (out_timestamp)); - } - GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp; - - /* - * Offset: - * 0) Use stored input offset (from opaque) - * 1) Use value converted from timestamp if valid - * 2) Use input offset if valid - */ - if (out_offset != GST_BUFFER_OFFSET_NONE) { - /* out_offset already contains the offset from ts_info */ - GST_LOG_OBJECT (ffmpegdec, "Using offset returned by ffmpeg"); - } else if (out_timestamp != GST_CLOCK_TIME_NONE) { - GstFormat out_fmt = GST_FORMAT_DEFAULT; - GST_LOG_OBJECT (ffmpegdec, "Using offset converted from timestamp"); - /* FIXME, we should really remove this as it's not nice at all to do - * upstream queries for each frame to get the frame offset. We also can't - * really remove this because it is the only way of setting frame offsets - * on outgoing buffers. We should have metadata so that the upstream peer - * can set a frame number on the encoded data. */ - gst_pad_query_peer_convert (ffmpegdec->sinkpad, - GST_FORMAT_TIME, out_timestamp, &out_fmt, &out_offset); - } else if (dec_info->offset != GST_BUFFER_OFFSET_NONE) { - /* FIXME, the input offset is input media specific and might not - * be the same for the output media. (byte offset as input, frame number - * as output, for example) */ - GST_LOG_OBJECT (ffmpegdec, "using in_offset %" G_GINT64_FORMAT, - dec_info->offset); - out_offset = dec_info->offset; - } else { - GST_LOG_OBJECT (ffmpegdec, "no valid offset found"); - out_offset = GST_BUFFER_OFFSET_NONE; - } - GST_BUFFER_OFFSET (*outbuf) = out_offset; - - /* - * Duration: - * - * 1) Use reordered input duration if valid - * 2) Else use input duration - * 3) else use input framerate - * 4) else use ffmpeg framerate - */ - if (GST_CLOCK_TIME_IS_VALID (out_duration)) { - /* We have a valid (reordered) duration */ - GST_LOG_OBJECT (ffmpegdec, "Using duration returned by ffmpeg"); - } else if (GST_CLOCK_TIME_IS_VALID (dec_info->duration)) { - GST_LOG_OBJECT (ffmpegdec, "using in_duration"); - out_duration = dec_info->duration; - } else if (GST_CLOCK_TIME_IS_VALID (ffmpegdec->last_diff)) { - GST_LOG_OBJECT (ffmpegdec, "using last-diff"); - out_duration = ffmpegdec->last_diff; - } else { - /* if we have an input framerate, use that */ - if (ffmpegdec->format.video.fps_n != -1 && - (ffmpegdec->format.video.fps_n != 1000 && - ffmpegdec->format.video.fps_d != 1)) { - GST_LOG_OBJECT (ffmpegdec, "using input framerate for duration"); - out_duration = gst_util_uint64_scale_int (GST_SECOND, - ffmpegdec->format.video.fps_d, ffmpegdec->format.video.fps_n); - } else { - /* don't try to use the decoder's framerate when it seems a bit abnormal, - * which we assume when den >= 1000... */ - if (ffmpegdec->context->time_base.num != 0 && - (ffmpegdec->context->time_base.den > 0 && - ffmpegdec->context->time_base.den < 1000)) { - GST_LOG_OBJECT (ffmpegdec, "using decoder's framerate for duration"); - out_duration = gst_util_uint64_scale_int (GST_SECOND, - ffmpegdec->context->time_base.num * - ffmpegdec->context->ticks_per_frame, - ffmpegdec->context->time_base.den); - } else { - GST_LOG_OBJECT (ffmpegdec, "no valid duration found"); - } - } - } - - /* Take repeat_pict into account */ - if (GST_CLOCK_TIME_IS_VALID (out_duration)) { - out_duration += out_duration * ffmpegdec->picture->repeat_pict / 2; - } - GST_BUFFER_DURATION (*outbuf) = out_duration; - - if (out_timestamp != -1 && out_duration != -1 && out_duration != 0) - ffmpegdec->next_out = out_timestamp + out_duration; - else - ffmpegdec->next_out = -1; - - /* palette is not part of raw video frame in gst and the size - * of the outgoing buffer needs to be adjusted accordingly */ - if (ffmpegdec->context->palctrl != NULL) - GST_BUFFER_SIZE (*outbuf) -= AVPALETTE_SIZE; - - /* now see if we need to clip the buffer against the segment boundaries. */ - if (G_UNLIKELY (!clip_video_buffer (ffmpegdec, *outbuf, out_timestamp, - out_duration))) - goto clipped; - - /* mark as keyframe or delta unit */ - if (!iskeyframe) - GST_BUFFER_FLAG_SET (*outbuf, GST_BUFFER_FLAG_DELTA_UNIT); - - if (ffmpegdec->picture->top_field_first) - GST_BUFFER_FLAG_SET (*outbuf, GST_VIDEO_BUFFER_TFF); - - -beach: - GST_DEBUG_OBJECT (ffmpegdec, "return flow %d, out %p, len %d", - *ret, *outbuf, len); - return len; - - /* special cases */ -drop_non_keyframe: - { - GST_WARNING_OBJECT (ffmpegdec, "Dropping non-keyframe (seek/init)"); - goto beach; - } -no_output: - { - GST_DEBUG_OBJECT (ffmpegdec, "no output buffer"); - len = -1; - goto beach; - } -clipped: - { - GST_DEBUG_OBJECT (ffmpegdec, "buffer clipped"); - gst_buffer_unref (*outbuf); - *outbuf = NULL; - goto beach; - } -} - /* returns TRUE if buffer is within segment, else FALSE. * if Buffer is on segment border, it's timestamp and duration will be clipped */ static gboolean -clip_audio_buffer (GstFFMpegDec * dec, GstBuffer * buf, GstClockTime in_ts, +clip_audio_buffer (GstFFMpegAudDec * dec, GstBuffer * buf, GstClockTime in_ts, GstClockTime in_dur) { GstClockTime stop; @@ -2133,7 +616,7 @@ out_of_segment: } static gint -gst_ffmpegdec_audio_frame (GstFFMpegDec * ffmpegdec, +gst_ffmpegauddec_audio_frame (GstFFMpegAudDec * ffmpegdec, AVCodec * in_plugin, guint8 * data, guint size, const GstTSInfo * dec_info, GstBuffer ** outbuf, GstFlowReturn * ret) { @@ -2161,7 +644,7 @@ gst_ffmpegdec_audio_frame (GstFFMpegDec * ffmpegdec, if (len >= 0 && have_data > 0) { GST_DEBUG_OBJECT (ffmpegdec, "Creating output buffer"); - if (!gst_ffmpegdec_negotiate (ffmpegdec, FALSE)) { + if (!gst_ffmpegauddec_negotiate (ffmpegdec, FALSE)) { gst_buffer_unref (*outbuf); *outbuf = NULL; len = -1; @@ -2247,7 +730,7 @@ clipped: } } -/* gst_ffmpegdec_frame: +/* gst_ffmpegauddec_frame: * ffmpegdec: * data: pointer to the data to decode * size: size of data in bytes @@ -2262,11 +745,11 @@ clipped: */ static gint -gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, +gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec, guint8 * data, guint size, gint * got_data, const GstTSInfo * dec_info, GstFlowReturn * ret) { - GstFFMpegDecClass *oclass; + GstFFMpegAudDecClass *oclass; GstBuffer *outbuf = NULL; gint have_data = 0, len = 0; @@ -2279,31 +762,18 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, *ret = GST_FLOW_OK; ffmpegdec->context->frame_number++; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - len = - gst_ffmpegdec_video_frame (ffmpegdec, data, size, dec_info, &outbuf, - ret); - break; - case AVMEDIA_TYPE_AUDIO: - len = - gst_ffmpegdec_audio_frame (ffmpegdec, oclass->in_plugin, data, size, - dec_info, &outbuf, ret); - - /* if we did not get an output buffer and we have a pending discont, don't - * clear the input timestamps, we will put them on the next buffer because - * else we might create the first buffer with a very big timestamp gap. */ - if (outbuf == NULL && ffmpegdec->discont) { - GST_DEBUG_OBJECT (ffmpegdec, "no buffer but keeping timestamp"); - ffmpegdec->clear_ts = FALSE; - } - break; - default: - GST_ERROR_OBJECT (ffmpegdec, "Asked to decode non-audio/video frame !"); - g_assert_not_reached (); - break; + len = + gst_ffmpegauddec_audio_frame (ffmpegdec, oclass->in_plugin, data, size, + dec_info, &outbuf, ret); + + /* if we did not get an output buffer and we have a pending discont, don't + * clear the input timestamps, we will put them on the next buffer because + * else we might create the first buffer with a very big timestamp gap. */ + if (outbuf == NULL && ffmpegdec->discont) { + GST_DEBUG_OBJECT (ffmpegdec, "no buffer but keeping timestamp"); + ffmpegdec->clear_ts = FALSE; } if (outbuf) @@ -2362,11 +832,11 @@ no_codec: } static void -gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) +gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec) { - GstFFMpegDecClass *oclass; + GstFFMpegAudDecClass *oclass; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); if (oclass->in_plugin->capabilities & CODEC_CAP_DELAY) { gint have_data, len, try = 0; @@ -2378,7 +848,7 @@ gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) GstFlowReturn ret; len = - gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data, &ts_info_none, + gst_ffmpegauddec_frame (ffmpegdec, NULL, 0, &have_data, &ts_info_none, &ret); if (len < 0 || have_data == 0) break; @@ -2391,7 +861,7 @@ gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) } static void -gst_ffmpegdec_flush_pcache (GstFFMpegDec * ffmpegdec) +gst_ffmpegauddec_flush_pcache (GstFFMpegAudDec * ffmpegdec) { if (ffmpegdec->pctx) { gint size, bsize; @@ -2416,12 +886,12 @@ gst_ffmpegdec_flush_pcache (GstFFMpegDec * ffmpegdec) } static gboolean -gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) +gst_ffmpegauddec_sink_event (GstPad * pad, GstEvent * event) { - GstFFMpegDec *ffmpegdec; + GstFFMpegAudDec *ffmpegdec; gboolean ret = FALSE; - ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); + ffmpegdec = (GstFFMpegAudDec *) gst_pad_get_parent (pad); GST_DEBUG_OBJECT (ffmpegdec, "Handling %s event", GST_EVENT_TYPE_NAME (event)); @@ -2429,7 +899,7 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: { - gst_ffmpegdec_drain (ffmpegdec); + gst_ffmpegauddec_drain (ffmpegdec); break; } case GST_EVENT_FLUSH_STOP: @@ -2437,10 +907,8 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) if (ffmpegdec->opened) { avcodec_flush_buffers (ffmpegdec->context); } - gst_ffmpegdec_reset_ts (ffmpegdec); - gst_ffmpegdec_reset_qos (ffmpegdec); - gst_ffmpegdec_flush_pcache (ffmpegdec); - ffmpegdec->waiting_for_key = TRUE; + gst_ffmpegauddec_reset_ts (ffmpegdec); + gst_ffmpegauddec_flush_pcache (ffmpegdec); gst_segment_init (&ffmpegdec->segment, GST_FORMAT_TIME); clear_queued (ffmpegdec); break; @@ -2499,7 +967,7 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) /* drain pending frames before trying to use the new segment, queued * buffers belonged to the previous segment. */ if (ffmpegdec->context->codec) - gst_ffmpegdec_drain (ffmpegdec); + gst_ffmpegauddec_drain (ffmpegdec); GST_DEBUG_OBJECT (ffmpegdec, "NEWSEGMENT in time start %" GST_TIME_FORMAT " -- stop %" @@ -2538,10 +1006,10 @@ invalid_format: } static GstFlowReturn -gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) +gst_ffmpegauddec_chain (GstPad * pad, GstBuffer * inbuf) { - GstFFMpegDec *ffmpegdec; - GstFFMpegDecClass *oclass; + GstFFMpegAudDec *ffmpegdec; + GstFFMpegAudDecClass *oclass; guint8 *data, *bdata; gint size, bsize, len, have_data; GstFlowReturn ret = GST_FLOW_OK; @@ -2552,7 +1020,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) const GstTSInfo *in_info; const GstTSInfo *dec_info; - ffmpegdec = (GstFFMpegDec *) (GST_PAD_PARENT (pad)); + ffmpegdec = (GstFFMpegAudDec *) (GST_PAD_PARENT (pad)); if (G_UNLIKELY (!ffmpegdec->opened)) goto not_negotiated; @@ -2567,28 +1035,17 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) if (G_UNLIKELY (discont)) { GST_DEBUG_OBJECT (ffmpegdec, "received DISCONT"); /* drain what we have queued */ - gst_ffmpegdec_drain (ffmpegdec); - gst_ffmpegdec_flush_pcache (ffmpegdec); + gst_ffmpegauddec_drain (ffmpegdec); + gst_ffmpegauddec_flush_pcache (ffmpegdec); ffmpegdec->discont = TRUE; - gst_ffmpegdec_reset_ts (ffmpegdec); + gst_ffmpegauddec_reset_ts (ffmpegdec); } /* by default we clear the input timestamp after decoding each frame so that * interpollation can work. */ ffmpegdec->clear_ts = TRUE; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - - /* do early keyframe check pretty bad to rely on the keyframe flag in the - * source for this as it might not even be parsed (UDP/file/..). */ - if (G_UNLIKELY (ffmpegdec->waiting_for_key)) { - GST_DEBUG_OBJECT (ffmpegdec, "waiting for keyframe"); - if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT) && - oclass->in_plugin->type != AVMEDIA_TYPE_AUDIO) - goto skip_keyframe; + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - GST_DEBUG_OBJECT (ffmpegdec, "got keyframe"); - ffmpegdec->waiting_for_key = FALSE; - } /* parse cache joining. If there is cached data */ if (ffmpegdec->pcache) { /* join with previous data */ @@ -2605,32 +1062,6 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) /* get handle to timestamp info, we can pass this around to ffmpeg */ in_info = gst_ts_info_store (ffmpegdec, in_timestamp, in_duration, in_offset); - if (in_timestamp != -1) { - /* check for increasing timestamps if they are jumping backwards, we - * probably are dealing with PTS as timestamps */ - if (!ffmpegdec->reordered_in && ffmpegdec->last_in != -1) { - if (in_timestamp < ffmpegdec->last_in) { - GST_LOG_OBJECT (ffmpegdec, "detected reordered input timestamps"); - ffmpegdec->reordered_in = TRUE; - ffmpegdec->last_diff = GST_CLOCK_TIME_NONE; - } else if (in_timestamp > ffmpegdec->last_in) { - GstClockTime diff; - /* keep track of timestamp diff to estimate duration */ - diff = in_timestamp - ffmpegdec->last_in; - /* need to scale with amount of frames in the interval */ - if (ffmpegdec->last_frames) - diff /= ffmpegdec->last_frames; - - GST_LOG_OBJECT (ffmpegdec, "estimated duration %" GST_TIME_FORMAT " %u", - GST_TIME_ARGS (diff), ffmpegdec->last_frames); - - ffmpegdec->last_diff = diff; - } - } - ffmpegdec->last_in = in_timestamp; - ffmpegdec->last_frames = 0; - } - GST_LOG_OBJECT (ffmpegdec, "Received new data of size %u, offset:%" G_GUINT64_FORMAT ", ts:%" GST_TIME_FORMAT ", dur:%" GST_TIME_FORMAT ", info %d", @@ -2649,23 +1080,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) bdata = GST_BUFFER_DATA (inbuf); bsize = GST_BUFFER_SIZE (inbuf); - if (ffmpegdec->do_padding) { - /* add padding */ - if (ffmpegdec->padded_size < bsize + FF_INPUT_BUFFER_PADDING_SIZE) { - ffmpegdec->padded_size = bsize + FF_INPUT_BUFFER_PADDING_SIZE; - ffmpegdec->padded = g_realloc (ffmpegdec->padded, ffmpegdec->padded_size); - GST_LOG_OBJECT (ffmpegdec, "resized padding buffer to %d", - ffmpegdec->padded_size); - } - memcpy (ffmpegdec->padded, bdata, bsize); - memset (ffmpegdec->padded + bsize, 0, FF_INPUT_BUFFER_PADDING_SIZE); - - bdata = ffmpegdec->padded; - } - do { - guint8 tmp_padding[FF_INPUT_BUFFER_PADDING_SIZE]; - /* parse, if at all possible */ if (ffmpegdec->pctx) { gint res; @@ -2723,19 +1138,10 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) dec_info = in_info; } - if (ffmpegdec->do_padding) { - /* add temporary padding */ - memcpy (tmp_padding, data + size, FF_INPUT_BUFFER_PADDING_SIZE); - memset (data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); - } - /* decode a frame of audio/video now */ len = - gst_ffmpegdec_frame (ffmpegdec, data, size, &have_data, dec_info, &ret); - - if (ffmpegdec->do_padding) { - memcpy (data + size, tmp_padding, FF_INPUT_BUFFER_PADDING_SIZE); - } + gst_ffmpegauddec_frame (ffmpegdec, data, size, &have_data, dec_info, + &ret); if (ret != GST_FLOW_OK) { GST_LOG_OBJECT (ffmpegdec, "breaking because of flow ret %s", @@ -2785,7 +1191,6 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) } else { ffmpegdec->clear_ts = TRUE; } - ffmpegdec->last_frames++; GST_LOG_OBJECT (ffmpegdec, "Before (while bsize>0). bsize:%d , bdata:%p", bsize, bdata); @@ -2816,25 +1221,19 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) /* ERRORS */ not_negotiated: { - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), ("ffdec_%s: input format was not set before data start", oclass->in_plugin->name)); gst_buffer_unref (inbuf); return GST_FLOW_NOT_NEGOTIATED; } -skip_keyframe: - { - GST_DEBUG_OBJECT (ffmpegdec, "skipping non keyframe"); - gst_buffer_unref (inbuf); - return GST_FLOW_OK; - } } static GstStateChangeReturn -gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition) +gst_ffmpegauddec_change_state (GstElement * element, GstStateChange transition) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element; + GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) element; GstStateChangeReturn ret; ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); @@ -2842,13 +1241,9 @@ gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (ffmpegdec); - gst_ffmpegdec_close (ffmpegdec); + gst_ffmpegauddec_close (ffmpegdec); GST_OBJECT_UNLOCK (ffmpegdec); clear_queued (ffmpegdec); - g_free (ffmpegdec->padded); - ffmpegdec->padded = NULL; - ffmpegdec->padded_size = 0; - ffmpegdec->can_allocate_aligned = TRUE; break; default: break; @@ -2857,89 +1252,19 @@ gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition) return ret; } -static void -gst_ffmpegdec_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object; - - switch (prop_id) { - case PROP_LOWRES: - ffmpegdec->lowres = ffmpegdec->context->lowres = g_value_get_enum (value); - break; - case PROP_SKIPFRAME: - ffmpegdec->skip_frame = ffmpegdec->context->skip_frame = - g_value_get_enum (value); - break; - case PROP_DIRECT_RENDERING: - ffmpegdec->direct_rendering = g_value_get_boolean (value); - break; - case PROP_DO_PADDING: - ffmpegdec->do_padding = g_value_get_boolean (value); - break; - case PROP_DEBUG_MV: - ffmpegdec->debug_mv = ffmpegdec->context->debug_mv = - g_value_get_boolean (value); - break; - case PROP_CROP: - ffmpegdec->crop = g_value_get_boolean (value); - break; - case PROP_MAX_THREADS: - ffmpegdec->max_threads = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_ffmpegdec_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object; - - switch (prop_id) { - case PROP_LOWRES: - g_value_set_enum (value, ffmpegdec->context->lowres); - break; - case PROP_SKIPFRAME: - g_value_set_enum (value, ffmpegdec->context->skip_frame); - break; - case PROP_DIRECT_RENDERING: - g_value_set_boolean (value, ffmpegdec->direct_rendering); - break; - case PROP_DO_PADDING: - g_value_set_boolean (value, ffmpegdec->do_padding); - break; - case PROP_DEBUG_MV: - g_value_set_boolean (value, ffmpegdec->context->debug_mv); - break; - case PROP_CROP: - g_value_set_boolean (value, ffmpegdec->crop); - break; - case PROP_MAX_THREADS: - g_value_set_int (value, ffmpegdec->max_threads); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - gboolean -gst_ffmpegdec_register (GstPlugin * plugin) +gst_ffmpegauddec_register (GstPlugin * plugin) { GTypeInfo typeinfo = { - sizeof (GstFFMpegDecClass), - (GBaseInitFunc) gst_ffmpegdec_base_init, + sizeof (GstFFMpegAudDecClass), + (GBaseInitFunc) gst_ffmpegauddec_base_init, NULL, - (GClassInitFunc) gst_ffmpegdec_class_init, + (GClassInitFunc) gst_ffmpegauddec_class_init, NULL, NULL, - sizeof (GstFFMpegDec), + sizeof (GstFFMpegAudDec), 0, - (GInstanceInitFunc) gst_ffmpegdec_init, + (GInstanceInitFunc) gst_ffmpegauddec_init, }; GType type; AVCodec *in_plugin; @@ -2954,17 +1279,13 @@ gst_ffmpegdec_register (GstPlugin * plugin) gchar *plugin_name; /* only decoders */ - if (!in_plugin->decode) { + if (!in_plugin->decode || in_plugin->type != AVMEDIA_TYPE_AUDIO) { goto next; } /* no quasi-codecs, please */ - if (in_plugin->id == CODEC_ID_RAWVIDEO || - in_plugin->id == CODEC_ID_V210 || - in_plugin->id == CODEC_ID_V210X || - in_plugin->id == CODEC_ID_R210 || - (in_plugin->id >= CODEC_ID_PCM_S16LE && - in_plugin->id <= CODEC_ID_PCM_BLURAY)) { + if (in_plugin->id >= CODEC_ID_PCM_S16LE && + in_plugin->id <= CODEC_ID_PCM_BLURAY) { goto next; } @@ -2978,33 +1299,13 @@ gst_ffmpegdec_register (GstPlugin * plugin) goto next; } - /* No vdpau plugins until we can figure out how to properly use them - * outside of ffmpeg. */ - if (g_str_has_suffix (in_plugin->name, "_vdpau")) { - GST_DEBUG - ("Ignoring VDPAU decoder %s. We can't handle this outside of ffmpeg", - in_plugin->name); - goto next; - } - - if (g_str_has_suffix (in_plugin->name, "_xvmc")) { - GST_DEBUG - ("Ignoring XVMC decoder %s. We can't handle this outside of ffmpeg", - in_plugin->name); - goto next; - } - GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name); /* no codecs for which we're GUARANTEED to have better alternatives */ - /* MPEG1VIDEO : the mpeg2video decoder is preferred */ /* MP1 : Use MP3 for decoding */ /* MP2 : Use MP3 for decoding */ /* Theora: Use libtheora based theoradec */ - if (!strcmp (in_plugin->name, "gif") || - !strcmp (in_plugin->name, "vorbis") || - !strcmp (in_plugin->name, "theora") || - !strcmp (in_plugin->name, "mpeg1video") || + if (!strcmp (in_plugin->name, "vorbis") || !strcmp (in_plugin->name, "wavpack") || !strcmp (in_plugin->name, "mp1") || !strcmp (in_plugin->name, "mp2") || @@ -3038,25 +1339,13 @@ gst_ffmpegdec_register (GstPlugin * plugin) * msmpeg4v3 same, as it outperforms divxdec for divx3 playback. * VC1/WMV3 are not working and thus unpreferred for now. */ switch (in_plugin->id) { - case CODEC_ID_MPEG4: - case CODEC_ID_MSMPEG4V3: - case CODEC_ID_H264: case CODEC_ID_RA_144: case CODEC_ID_RA_288: - case CODEC_ID_RV10: - case CODEC_ID_RV20: - case CODEC_ID_RV30: - case CODEC_ID_RV40: case CODEC_ID_COOK: rank = GST_RANK_PRIMARY; break; - /* DVVIDEO: we have a good dv decoder, fast on both ppc as well as x86. - * They say libdv's quality is better though. leave as secondary. - * note: if you change this, see the code in gstdv.c in good/ext/dv. - * - * SIPR: decoder should have a higher rank than realaudiodec. + /* SIPR: decoder should have a higher rank than realaudiodec. */ - case CODEC_ID_DVVIDEO: case CODEC_ID_SIPR: rank = GST_RANK_SECONDARY; break; diff --git a/ext/ffmpeg/gstffmpegenc.c b/ext/ffmpeg/gstffmpegenc.c index f3dd34d..7a841e1 100644 --- a/ext/ffmpeg/gstffmpegenc.c +++ b/ext/ffmpeg/gstffmpegenc.c @@ -40,18 +40,9 @@ #include "gstffmpegcodecmap.h" #include "gstffmpegutils.h" #include "gstffmpegenc.h" -#include "gstffmpegcfg.h" -#define DEFAULT_VIDEO_BITRATE 300000 /* in bps */ -#define DEFAULT_VIDEO_GOP_SIZE 15 #define DEFAULT_AUDIO_BITRATE 128000 -#define DEFAULT_WIDTH 352 -#define DEFAULT_HEIGHT 288 - - -#define VIDEO_BUFFER_SIZE (1024*1024) - enum { /* FILL ME */ @@ -62,71 +53,44 @@ enum { ARG_0, ARG_BIT_RATE, - ARG_GOP_SIZE, - ARG_ME_METHOD, ARG_BUFSIZE, ARG_RTP_PAYLOAD_SIZE, - ARG_CFG_BASE }; -#define GST_TYPE_ME_METHOD (gst_ffmpegenc_me_method_get_type()) -static GType -gst_ffmpegenc_me_method_get_type (void) -{ - static GType ffmpegenc_me_method_type = 0; - static GEnumValue ffmpegenc_me_methods[] = { - {ME_ZERO, "None (Very low quality)", "zero"}, - {ME_FULL, "Full (Slow, unmaintained)", "full"}, - {ME_LOG, "Logarithmic (Low quality, unmaintained)", "logarithmic"}, - {ME_PHODS, "phods (Low quality, unmaintained)", "phods"}, - {ME_EPZS, "EPZS (Best quality, Fast)", "epzs"}, - {ME_X1, "X1 (Experimental)", "x1"}, - {0, NULL, NULL}, - }; - if (!ffmpegenc_me_method_type) { - ffmpegenc_me_method_type = - g_enum_register_static ("GstFFMpegEncMeMethod", ffmpegenc_me_methods); - } - return ffmpegenc_me_method_type; -} /* A number of function prototypes are given so we can refer to them later. */ -static void gst_ffmpegenc_class_init (GstFFMpegEncClass * klass); -static void gst_ffmpegenc_base_init (GstFFMpegEncClass * klass); -static void gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc); -static void gst_ffmpegenc_finalize (GObject * object); - -static gboolean gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_ffmpegenc_getcaps (GstPad * pad); -static GstFlowReturn gst_ffmpegenc_chain_video (GstPad * pad, - GstBuffer * buffer); -static GstFlowReturn gst_ffmpegenc_chain_audio (GstPad * pad, +static void gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass); +static void gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass); +static void gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc); +static void gst_ffmpegaudenc_finalize (GObject * object); + +static gboolean gst_ffmpegaudenc_setcaps (GstPad * pad, GstCaps * caps); +static GstCaps *gst_ffmpegaudenc_getcaps (GstPad * pad); +static GstFlowReturn gst_ffmpegaudenc_chain_audio (GstPad * pad, GstBuffer * buffer); -static gboolean gst_ffmpegenc_event_video (GstPad * pad, GstEvent * event); -static gboolean gst_ffmpegenc_event_src (GstPad * pad, GstEvent * event); -static void gst_ffmpegenc_set_property (GObject * object, +static void gst_ffmpegaudenc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_ffmpegenc_get_property (GObject * object, +static void gst_ffmpegaudenc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_ffmpegenc_change_state (GstElement * element, +static GstStateChangeReturn gst_ffmpegaudenc_change_state (GstElement * element, GstStateChange transition); #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("ffenc-params") static GstElementClass *parent_class = NULL; -/*static guint gst_ffmpegenc_signals[LAST_SIGNAL] = { 0 }; */ +/*static guint gst_ffmpegaudenc_signals[LAST_SIGNAL] = { 0 }; */ static void -gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) +gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); AVCodec *in_plugin; GstPadTemplate *srctempl = NULL, *sinktempl = NULL; GstCaps *srccaps = NULL, *sinkcaps = NULL; - gchar *longname, *classification, *description; + gchar *longname, *description; in_plugin = (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), @@ -135,15 +99,12 @@ gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) /* construct the element details struct */ longname = g_strdup_printf ("FFmpeg %s encoder", in_plugin->long_name); - classification = g_strdup_printf ("Codec/Encoder/%s", - (in_plugin->type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio"); description = g_strdup_printf ("FFmpeg %s encoder", in_plugin->name); - gst_element_class_set_details_simple (element_class, longname, classification, - description, + gst_element_class_set_details_simple (element_class, longname, + "Codec/Encoder/Audio", description, "Wim Taymans , " "Ronald Bultje "); g_free (longname); - g_free (classification); g_free (description); if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) { @@ -151,13 +112,8 @@ gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) srccaps = gst_caps_new_simple ("unknown/unknown", NULL); } - if (in_plugin->type == AVMEDIA_TYPE_VIDEO) { - sinkcaps = gst_caps_from_string - ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray"); - } else { - sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL, - in_plugin->id, TRUE, in_plugin); - } + sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL, + in_plugin->id, TRUE, in_plugin); if (!sinkcaps) { GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name); sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL); @@ -180,7 +136,7 @@ gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) } static void -gst_ffmpegenc_class_init (GstFFMpegEncClass * klass) +gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; @@ -190,514 +146,192 @@ gst_ffmpegenc_class_init (GstFFMpegEncClass * klass) parent_class = g_type_class_peek_parent (klass); - gobject_class->set_property = gst_ffmpegenc_set_property; - gobject_class->get_property = gst_ffmpegenc_get_property; + gobject_class->set_property = gst_ffmpegaudenc_set_property; + gobject_class->get_property = gst_ffmpegaudenc_get_property; - if (klass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, - g_param_spec_ulong ("bitrate", "Bit Rate", - "Target Video Bitrate", 0, G_MAXULONG, DEFAULT_VIDEO_BITRATE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GOP_SIZE, - g_param_spec_int ("gop-size", "GOP Size", - "Number of frames within one GOP", 0, G_MAXINT, - DEFAULT_VIDEO_GOP_SIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ME_METHOD, - g_param_spec_enum ("me-method", "ME Method", "Motion Estimation Method", - GST_TYPE_ME_METHOD, ME_EPZS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* FIXME 0.11: Make this property read-only */ - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE, - g_param_spec_ulong ("buffer-size", "Buffer Size", - "Size of the video buffers. " - "Note: Setting this property has no effect " - "and is deprecated!", 0, G_MAXULONG, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - ARG_RTP_PAYLOAD_SIZE, g_param_spec_ulong ("rtp-payload-size", - "RTP Payload Size", "Target GOB length", 0, G_MAXULONG, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* register additional properties, possibly dependent on the exact CODEC */ - gst_ffmpeg_cfg_install_property (klass, ARG_CFG_BASE); - } else if (klass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { + if (klass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, g_param_spec_ulong ("bitrate", "Bit Rate", "Target Audio Bitrate", 0, G_MAXULONG, DEFAULT_AUDIO_BITRATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } - gstelement_class->change_state = gst_ffmpegenc_change_state; + gstelement_class->change_state = gst_ffmpegaudenc_change_state; - gobject_class->finalize = gst_ffmpegenc_finalize; + gobject_class->finalize = gst_ffmpegaudenc_finalize; } static void -gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc) +gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc) { - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); + GstFFMpegAudEncClass *oclass = + (GstFFMpegAudEncClass *) (G_OBJECT_GET_CLASS (ffmpegaudenc)); /* setup pads */ - ffmpegenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); - gst_pad_set_setcaps_function (ffmpegenc->sinkpad, gst_ffmpegenc_setcaps); - gst_pad_set_getcaps_function (ffmpegenc->sinkpad, gst_ffmpegenc_getcaps); - ffmpegenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); - gst_pad_use_fixed_caps (ffmpegenc->srcpad); + ffmpegaudenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); + gst_pad_set_setcaps_function (ffmpegaudenc->sinkpad, + gst_ffmpegaudenc_setcaps); + gst_pad_set_getcaps_function (ffmpegaudenc->sinkpad, + gst_ffmpegaudenc_getcaps); + ffmpegaudenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); + gst_pad_use_fixed_caps (ffmpegaudenc->srcpad); /* ffmpeg objects */ - ffmpegenc->context = avcodec_alloc_context (); - ffmpegenc->picture = avcodec_alloc_frame (); - ffmpegenc->opened = FALSE; - - ffmpegenc->file = NULL; - ffmpegenc->delay = g_queue_new (); - - if (oclass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { - gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegenc_chain_video); - /* so we know when to flush the buffers on EOS */ - gst_pad_set_event_function (ffmpegenc->sinkpad, gst_ffmpegenc_event_video); - gst_pad_set_event_function (ffmpegenc->srcpad, gst_ffmpegenc_event_src); - - ffmpegenc->bitrate = DEFAULT_VIDEO_BITRATE; - ffmpegenc->me_method = ME_EPZS; - ffmpegenc->buffer_size = 512 * 1024; - ffmpegenc->gop_size = DEFAULT_VIDEO_GOP_SIZE; - ffmpegenc->rtp_payload_size = 0; - - ffmpegenc->lmin = 2; - ffmpegenc->lmax = 31; - ffmpegenc->max_key_interval = 0; - - gst_ffmpeg_cfg_set_defaults (ffmpegenc); - } else if (oclass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { - gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegenc_chain_audio); - - ffmpegenc->bitrate = DEFAULT_AUDIO_BITRATE; + ffmpegaudenc->context = avcodec_alloc_context (); + ffmpegaudenc->opened = FALSE; + + if (oclass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { + gst_pad_set_chain_function (ffmpegaudenc->sinkpad, + gst_ffmpegaudenc_chain_audio); + + ffmpegaudenc->bitrate = DEFAULT_AUDIO_BITRATE; } - gst_element_add_pad (GST_ELEMENT (ffmpegenc), ffmpegenc->sinkpad); - gst_element_add_pad (GST_ELEMENT (ffmpegenc), ffmpegenc->srcpad); + gst_element_add_pad (GST_ELEMENT (ffmpegaudenc), ffmpegaudenc->sinkpad); + gst_element_add_pad (GST_ELEMENT (ffmpegaudenc), ffmpegaudenc->srcpad); - ffmpegenc->adapter = gst_adapter_new (); + ffmpegaudenc->adapter = gst_adapter_new (); } static void -gst_ffmpegenc_finalize (GObject * object) +gst_ffmpegaudenc_finalize (GObject * object) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) object; + GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) object; - gst_ffmpeg_cfg_finalize (ffmpegenc); /* close old session */ - if (ffmpegenc->opened) { - gst_ffmpeg_avcodec_close (ffmpegenc->context); - ffmpegenc->opened = FALSE; + if (ffmpegaudenc->opened) { + gst_ffmpeg_avcodec_close (ffmpegaudenc->context); + ffmpegaudenc->opened = FALSE; } /* clean up remaining allocated data */ - av_free (ffmpegenc->context); - av_free (ffmpegenc->picture); - - g_queue_free (ffmpegenc->delay); - g_free (ffmpegenc->filename); + av_free (ffmpegaudenc->context); - g_object_unref (ffmpegenc->adapter); + g_object_unref (ffmpegaudenc->adapter); G_OBJECT_CLASS (parent_class)->finalize (object); } static GstCaps * -gst_ffmpegenc_get_possible_sizes (GstFFMpegEnc * ffmpegenc, GstPad * pad, - const GstCaps * caps) +gst_ffmpegaudenc_getcaps (GstPad * pad) { - GstCaps *othercaps = NULL; - GstCaps *tmpcaps = NULL; - GstCaps *intersect = NULL; - guint i; - - othercaps = gst_pad_peer_get_caps (ffmpegenc->srcpad); - - if (!othercaps) - return gst_caps_copy (caps); - - intersect = gst_caps_intersect (othercaps, - gst_pad_get_pad_template_caps (ffmpegenc->srcpad)); - gst_caps_unref (othercaps); - - if (gst_caps_is_empty (intersect)) - return intersect; - - if (gst_caps_is_any (intersect)) - return gst_caps_copy (caps); - - tmpcaps = gst_caps_new_empty (); - - for (i = 0; i < gst_caps_get_size (intersect); i++) { - GstStructure *s = gst_caps_get_structure (intersect, i); - const GValue *height = NULL; - const GValue *width = NULL; - const GValue *framerate = NULL; - GstStructure *tmps; - - height = gst_structure_get_value (s, "height"); - width = gst_structure_get_value (s, "width"); - framerate = gst_structure_get_value (s, "framerate"); - - tmps = gst_structure_new ("video/x-raw-rgb", NULL); - if (width) - gst_structure_set_value (tmps, "width", width); - if (height) - gst_structure_set_value (tmps, "height", height); - if (framerate) - gst_structure_set_value (tmps, "framerate", framerate); - gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps)); - - gst_structure_set_name (tmps, "video/x-raw-yuv"); - gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps)); - - gst_structure_set_name (tmps, "video/x-raw-gray"); - gst_caps_merge_structure (tmpcaps, tmps); - } - gst_caps_unref (intersect); - - intersect = gst_caps_intersect (caps, tmpcaps); - gst_caps_unref (tmpcaps); - - return intersect; -} - - -static GstCaps * -gst_ffmpegenc_getcaps (GstPad * pad) -{ - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); - AVCodecContext *ctx = NULL; - enum PixelFormat pixfmt; + GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) GST_PAD_PARENT (pad); GstCaps *caps = NULL; - GstCaps *finalcaps = NULL; - gint i; - GST_DEBUG_OBJECT (ffmpegenc, "getting caps"); + GST_DEBUG_OBJECT (ffmpegaudenc, "getting caps"); /* audio needs no special care */ - if (oclass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { - caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - - GST_DEBUG_OBJECT (ffmpegenc, "audio caps, return template %" GST_PTR_FORMAT, - caps); - - return caps; - } - - /* cached */ - if (oclass->sinkcaps) { - caps = gst_ffmpegenc_get_possible_sizes (ffmpegenc, pad, oclass->sinkcaps); - GST_DEBUG_OBJECT (ffmpegenc, "return cached caps %" GST_PTR_FORMAT, caps); - return caps; - } - - /* create cache etc. */ - - /* shut up the logging while we autoprobe; we don't want warnings and - * errors about unsupported formats */ - /* FIXME: if someone cares about this disabling the logging for other - * instances/threads/..., one could investigate if there is a way to - * set this as a struct member on the av context, and check it from the - * log handler */ -#ifndef GST_DISABLE_GST_DEBUG - _shut_up_I_am_probing = TRUE; -#endif - GST_DEBUG_OBJECT (ffmpegenc, "probing caps"); - i = pixfmt = 0; - /* check pixfmt until deemed finished */ - for (pixfmt = 0;; pixfmt++) { - GstCaps *tmpcaps; - - /* override looping all pixfmt if codec declares pixfmts; - * these may not properly check and report supported pixfmt during _init */ - if (oclass->in_plugin->pix_fmts) { - if ((pixfmt = oclass->in_plugin->pix_fmts[i++]) == PIX_FMT_NONE) { - GST_DEBUG_OBJECT (ffmpegenc, - "At the end of official pixfmt for this codec, breaking out"); - break; - } - GST_DEBUG_OBJECT (ffmpegenc, - "Got an official pixfmt [%d], attempting to get caps", pixfmt); - tmpcaps = gst_ffmpeg_pixfmt_to_caps (pixfmt, NULL, oclass->in_plugin->id); - if (tmpcaps) { - GST_DEBUG_OBJECT (ffmpegenc, "Got caps, breaking out"); - if (!caps) - caps = gst_caps_new_empty (); - gst_caps_append (caps, tmpcaps); - continue; - } - GST_DEBUG_OBJECT (ffmpegenc, - "Couldn't figure out caps without context, trying again with a context"); - } - - GST_DEBUG_OBJECT (ffmpegenc, "pixfmt :%d", pixfmt); - if (pixfmt >= PIX_FMT_NB) { - GST_WARNING ("Invalid pixfmt, breaking out"); - break; - } - - /* need to start with a fresh codec_context each time around, since - * codec_close may have released stuff causing the next pass to segfault */ - ctx = avcodec_alloc_context (); - if (!ctx) { - GST_DEBUG_OBJECT (ffmpegenc, "no context"); - break; - } - - /* set some default properties */ - ctx->width = DEFAULT_WIDTH; - ctx->height = DEFAULT_HEIGHT; - ctx->time_base.num = 1; - ctx->time_base.den = 25; - ctx->ticks_per_frame = 1; - ctx->bit_rate = DEFAULT_VIDEO_BITRATE; - /* makes it silent */ - ctx->strict_std_compliance = -1; - - ctx->pix_fmt = pixfmt; - - GST_DEBUG ("Attempting to open codec"); - if (gst_ffmpeg_avcodec_open (ctx, oclass->in_plugin) >= 0 && - ctx->pix_fmt == pixfmt) { - ctx->width = -1; - if (!caps) - caps = gst_caps_new_empty (); - tmpcaps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type, ctx, - oclass->in_plugin->id, TRUE); - if (tmpcaps) - gst_caps_append (caps, tmpcaps); - else - GST_LOG_OBJECT (ffmpegenc, - "Couldn't get caps for oclass->in_plugin->name:%s", - oclass->in_plugin->name); - gst_ffmpeg_avcodec_close (ctx); - } else { - GST_DEBUG_OBJECT (ffmpegenc, "Opening codec failed with pixfmt : %d", - pixfmt); - } - if (ctx->priv_data) - gst_ffmpeg_avcodec_close (ctx); - av_free (ctx); - } -#ifndef GST_DISABLE_GST_DEBUG - _shut_up_I_am_probing = FALSE; -#endif - - /* make sure we have something */ - if (!caps) { - caps = gst_ffmpegenc_get_possible_sizes (ffmpegenc, pad, - gst_pad_get_pad_template_caps (pad)); - GST_DEBUG_OBJECT (ffmpegenc, "probing gave nothing, " - "return template %" GST_PTR_FORMAT, caps); - return caps; - } - - GST_DEBUG_OBJECT (ffmpegenc, "probed caps gave %" GST_PTR_FORMAT, caps); - oclass->sinkcaps = gst_caps_copy (caps); + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - finalcaps = gst_ffmpegenc_get_possible_sizes (ffmpegenc, pad, caps); - gst_caps_unref (caps); + GST_DEBUG_OBJECT (ffmpegaudenc, + "audio caps, return template %" GST_PTR_FORMAT, caps); - return finalcaps; + return caps; } static gboolean -gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps) +gst_ffmpegaudenc_setcaps (GstPad * pad, GstCaps * caps) { GstCaps *other_caps; GstCaps *allowed_caps; GstCaps *icaps; - enum PixelFormat pix_fmt; - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); + GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) GST_PAD_PARENT (pad); + GstFFMpegAudEncClass *oclass = + (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); /* close old session */ - if (ffmpegenc->opened) { - gst_ffmpeg_avcodec_close (ffmpegenc->context); - ffmpegenc->opened = FALSE; + if (ffmpegaudenc->opened) { + gst_ffmpeg_avcodec_close (ffmpegaudenc->context); + ffmpegaudenc->opened = FALSE; /* fixed src caps; * so clear src caps for proper (re-)negotiation */ - gst_pad_set_caps (ffmpegenc->srcpad, NULL); + gst_pad_set_caps (ffmpegaudenc->srcpad, NULL); } /* set defaults */ - avcodec_get_context_defaults (ffmpegenc->context); + avcodec_get_context_defaults (ffmpegaudenc->context); /* if we set it in _getcaps we should set it also in _link */ - ffmpegenc->context->strict_std_compliance = -1; + ffmpegaudenc->context->strict_std_compliance = -1; /* user defined properties */ - ffmpegenc->context->bit_rate = ffmpegenc->bitrate; - ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate; - ffmpegenc->context->gop_size = ffmpegenc->gop_size; - ffmpegenc->context->me_method = ffmpegenc->me_method; - GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext to bitrate %lu, gop_size %d", - ffmpegenc->bitrate, ffmpegenc->gop_size); + ffmpegaudenc->context->bit_rate = ffmpegaudenc->bitrate; + ffmpegaudenc->context->bit_rate_tolerance = ffmpegaudenc->bitrate; + GST_DEBUG_OBJECT (ffmpegaudenc, "Setting avcontext to bitrate %lu", + ffmpegaudenc->bitrate); /* RTP payload used for GOB production (for Asterisk) */ - if (ffmpegenc->rtp_payload_size) { - ffmpegenc->context->rtp_payload_size = ffmpegenc->rtp_payload_size; - } - - /* additional avcodec settings */ - /* first fill in the majority by copying over */ - gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context); - - /* then handle some special cases */ - ffmpegenc->context->lmin = (ffmpegenc->lmin * FF_QP2LAMBDA + 0.5); - ffmpegenc->context->lmax = (ffmpegenc->lmax * FF_QP2LAMBDA + 0.5); - - if (ffmpegenc->interlaced) { - ffmpegenc->context->flags |= - CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME; - ffmpegenc->picture->interlaced_frame = TRUE; - /* if this is not the case, a filter element should be used to swap fields */ - ffmpegenc->picture->top_field_first = TRUE; + if (ffmpegaudenc->rtp_payload_size) { + ffmpegaudenc->context->rtp_payload_size = ffmpegaudenc->rtp_payload_size; } /* some other defaults */ - ffmpegenc->context->rc_strategy = 2; - ffmpegenc->context->b_frame_strategy = 0; - ffmpegenc->context->coder_type = 0; - ffmpegenc->context->context_model = 0; - ffmpegenc->context->scenechange_threshold = 0; - ffmpegenc->context->inter_threshold = 0; - - /* and last but not least the pass; CBR, 2-pass, etc */ - ffmpegenc->context->flags |= ffmpegenc->pass; - switch (ffmpegenc->pass) { - /* some additional action depends on type of pass */ - case CODEC_FLAG_QSCALE: - ffmpegenc->context->global_quality - = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer; - break; - case CODEC_FLAG_PASS1: /* need to prepare a stats file */ - /* we don't close when changing caps, fingers crossed */ - if (!ffmpegenc->file) - ffmpegenc->file = g_fopen (ffmpegenc->filename, "w"); - if (!ffmpegenc->file) { - GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE, - (("Could not open file \"%s\" for writing."), ffmpegenc->filename), - GST_ERROR_SYSTEM); - return FALSE; - } - break; - case CODEC_FLAG_PASS2: - { /* need to read the whole stats file ! */ - gsize size; - - if (!g_file_get_contents (ffmpegenc->filename, - &ffmpegenc->context->stats_in, &size, NULL)) { - GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ, - (("Could not get contents of file \"%s\"."), ffmpegenc->filename), - GST_ERROR_SYSTEM); - return FALSE; - } + ffmpegaudenc->context->rc_strategy = 2; + ffmpegaudenc->context->b_frame_strategy = 0; + ffmpegaudenc->context->coder_type = 0; + ffmpegaudenc->context->context_model = 0; + ffmpegaudenc->context->scenechange_threshold = 0; + ffmpegaudenc->context->inter_threshold = 0; - break; - } - default: - break; - } /* fetch pix_fmt and so on */ gst_ffmpeg_caps_with_codectype (oclass->in_plugin->type, - caps, ffmpegenc->context); - if (!ffmpegenc->context->time_base.den) { - ffmpegenc->context->time_base.den = 25; - ffmpegenc->context->time_base.num = 1; - ffmpegenc->context->ticks_per_frame = 1; + caps, ffmpegaudenc->context); + if (!ffmpegaudenc->context->time_base.den) { + ffmpegaudenc->context->time_base.den = 25; + ffmpegaudenc->context->time_base.num = 1; + ffmpegaudenc->context->ticks_per_frame = 1; } else if ((oclass->in_plugin->id == CODEC_ID_MPEG4) - && (ffmpegenc->context->time_base.den > 65535)) { + && (ffmpegaudenc->context->time_base.den > 65535)) { /* MPEG4 Standards do not support time_base denominator greater than * (1<<16) - 1 . We therefore scale them down. * Agreed, it will not be the exact framerate... but the difference * shouldn't be that noticeable */ - ffmpegenc->context->time_base.num = - (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num, - 65535, ffmpegenc->context->time_base.den); - ffmpegenc->context->time_base.den = 65535; - GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d", - ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num); - } - - pix_fmt = ffmpegenc->context->pix_fmt; - - /* max-key-interval may need the framerate set above */ - if (ffmpegenc->max_key_interval) { - AVCodecContext *ctx; - - /* override gop-size */ - ctx = ffmpegenc->context; - ctx->gop_size = (ffmpegenc->max_key_interval < 0) ? - (-ffmpegenc->max_key_interval - * (ctx->time_base.den * ctx->ticks_per_frame / ctx->time_base.num)) - : ffmpegenc->max_key_interval; + ffmpegaudenc->context->time_base.num = + (gint) gst_util_uint64_scale_int (ffmpegaudenc->context->time_base.num, + 65535, ffmpegaudenc->context->time_base.den); + ffmpegaudenc->context->time_base.den = 65535; + GST_LOG_OBJECT (ffmpegaudenc, "MPEG4 : scaled down framerate to %d / %d", + ffmpegaudenc->context->time_base.den, + ffmpegaudenc->context->time_base.num); } /* open codec */ - if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) { - if (ffmpegenc->context->priv_data) - gst_ffmpeg_avcodec_close (ffmpegenc->context); - if (ffmpegenc->context->stats_in) - g_free (ffmpegenc->context->stats_in); - GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to open FFMPEG codec", + if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) { + if (ffmpegaudenc->context->priv_data) + gst_ffmpeg_avcodec_close (ffmpegaudenc->context); + if (ffmpegaudenc->context->stats_in) + g_free (ffmpegaudenc->context->stats_in); + GST_DEBUG_OBJECT (ffmpegaudenc, "ffenc_%s: Failed to open FFMPEG codec", oclass->in_plugin->name); return FALSE; } /* second pass stats buffer no longer needed */ - if (ffmpegenc->context->stats_in) - g_free (ffmpegenc->context->stats_in); - - /* is the colourspace correct? */ - if (pix_fmt != ffmpegenc->context->pix_fmt) { - gst_ffmpeg_avcodec_close (ffmpegenc->context); - GST_DEBUG_OBJECT (ffmpegenc, - "ffenc_%s: AV wants different colourspace (%d given, %d wanted)", - oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt); - return FALSE; - } - /* we may have failed mapping caps to a pixfmt, - * and quite some codecs do not make up their own mind about that - * in any case, _NONE can never work out later on */ - if (oclass->in_plugin->type == AVMEDIA_TYPE_VIDEO && pix_fmt == PIX_FMT_NONE) { - GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to determine input format", - oclass->in_plugin->name); - return FALSE; - } + if (ffmpegaudenc->context->stats_in) + g_free (ffmpegaudenc->context->stats_in); /* some codecs support more than one format, first auto-choose one */ - GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ..."); - allowed_caps = gst_pad_get_allowed_caps (ffmpegenc->srcpad); + GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ..."); + allowed_caps = gst_pad_get_allowed_caps (ffmpegaudenc->srcpad); if (!allowed_caps) { - GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps"); + GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps"); /* we need to copy because get_allowed_caps returns a ref, and * get_pad_template_caps doesn't */ allowed_caps = - gst_caps_copy (gst_pad_get_pad_template_caps (ffmpegenc->srcpad)); + gst_caps_copy (gst_pad_get_pad_template_caps (ffmpegaudenc->srcpad)); } - GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps); + GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps); gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, - oclass->in_plugin->type, allowed_caps, ffmpegenc->context); + oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context); /* try to set this caps on the other side */ other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id, - ffmpegenc->context, TRUE); + ffmpegaudenc->context, TRUE); if (!other_caps) { - gst_ffmpeg_avcodec_close (ffmpegenc->context); + gst_ffmpeg_avcodec_close (ffmpegaudenc->context); GST_DEBUG ("Unsupported codec - no caps found"); return FALSE; } @@ -720,132 +354,23 @@ gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps) icaps = newcaps; } - if (!gst_pad_set_caps (ffmpegenc->srcpad, icaps)) { - gst_ffmpeg_avcodec_close (ffmpegenc->context); + if (!gst_pad_set_caps (ffmpegaudenc->srcpad, icaps)) { + gst_ffmpeg_avcodec_close (ffmpegaudenc->context); gst_caps_unref (icaps); return FALSE; } gst_caps_unref (icaps); /* success! */ - ffmpegenc->opened = TRUE; + ffmpegaudenc->opened = TRUE; return TRUE; } -static void -ffmpegenc_setup_working_buf (GstFFMpegEnc * ffmpegenc) -{ - guint wanted_size = - ffmpegenc->context->width * ffmpegenc->context->height * 6 + - FF_MIN_BUFFER_SIZE; - - /* Above is the buffer size used by ffmpeg/ffmpeg.c */ - - if (ffmpegenc->working_buf == NULL || - ffmpegenc->working_buf_size != wanted_size) { - if (ffmpegenc->working_buf) - g_free (ffmpegenc->working_buf); - ffmpegenc->working_buf_size = wanted_size; - ffmpegenc->working_buf = g_malloc (ffmpegenc->working_buf_size); - } - ffmpegenc->buffer_size = wanted_size; -} static GstFlowReturn -gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf) -{ - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad)); - GstBuffer *outbuf; - gint ret_size = 0, frame_size; - gboolean force_keyframe; - - GST_DEBUG_OBJECT (ffmpegenc, - "Received buffer of time %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf))); - - GST_OBJECT_LOCK (ffmpegenc); - force_keyframe = ffmpegenc->force_keyframe; - ffmpegenc->force_keyframe = FALSE; - GST_OBJECT_UNLOCK (ffmpegenc); - - if (force_keyframe) - ffmpegenc->picture->pict_type = FF_I_TYPE; - - frame_size = gst_ffmpeg_avpicture_fill ((AVPicture *) ffmpegenc->picture, - GST_BUFFER_DATA (inbuf), - ffmpegenc->context->pix_fmt, - ffmpegenc->context->width, ffmpegenc->context->height); - g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (inbuf), GST_FLOW_ERROR); - - ffmpegenc->picture->pts = - gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (inbuf) / - ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base); - - ffmpegenc_setup_working_buf (ffmpegenc); - - ret_size = avcodec_encode_video (ffmpegenc->context, - ffmpegenc->working_buf, ffmpegenc->working_buf_size, ffmpegenc->picture); - - if (ret_size < 0) { -#ifndef GST_DISABLE_GST_DEBUG - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); - GST_ERROR_OBJECT (ffmpegenc, - "ffenc_%s: failed to encode buffer", oclass->in_plugin->name); -#endif /* GST_DISABLE_GST_DEBUG */ - gst_buffer_unref (inbuf); - return GST_FLOW_OK; - } - - /* handle b-frame delay when no output, so we don't output empty frames; - * timestamps and so can permute a bit between coding and display order - * but keyframes should still end up with the proper metadata */ - g_queue_push_tail (ffmpegenc->delay, inbuf); - if (ret_size) - inbuf = g_queue_pop_head (ffmpegenc->delay); - else - return GST_FLOW_OK; - - /* save stats info if there is some as well as a stats file */ - if (ffmpegenc->file && ffmpegenc->context->stats_out) - if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0) - GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE, - (("Could not write to file \"%s\"."), ffmpegenc->filename), - GST_ERROR_SYSTEM); - - outbuf = gst_buffer_new_and_alloc (ret_size); - memcpy (GST_BUFFER_DATA (outbuf), ffmpegenc->working_buf, ret_size); - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf); - GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf); - /* buggy codec may not set coded_frame */ - if (ffmpegenc->context->coded_frame) { - if (!ffmpegenc->context->coded_frame->key_frame) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); - } else - GST_WARNING_OBJECT (ffmpegenc, "codec did not provide keyframe info"); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad)); - - gst_buffer_unref (inbuf); - - /* Reset frame type */ - if (ffmpegenc->picture->pict_type) - ffmpegenc->picture->pict_type = 0; - - if (force_keyframe) { - gst_pad_push_event (ffmpegenc->srcpad, - gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, - gst_structure_new ("GstForceKeyUnit", - "timestamp", G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), - NULL))); - } - - return gst_pad_push (ffmpegenc->srcpad, outbuf); -} - -static GstFlowReturn -gst_ffmpegenc_encode_audio (GstFFMpegEnc * ffmpegenc, guint8 * audio_in, - guint in_size, guint max_size, GstClockTime timestamp, +gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc, + guint8 * audio_in, guint in_size, guint max_size, GstClockTime timestamp, GstClockTime duration, gboolean discont) { GstBuffer *outbuf; @@ -854,45 +379,45 @@ gst_ffmpegenc_encode_audio (GstFFMpegEnc * ffmpegenc, guint8 * audio_in, gint res; GstFlowReturn ret; - ctx = ffmpegenc->context; + ctx = ffmpegaudenc->context; /* We need to provide at least ffmpegs minimal buffer size */ outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE); audio_out = GST_BUFFER_DATA (outbuf); - GST_LOG_OBJECT (ffmpegenc, "encoding buffer of max size %d", max_size); - if (ffmpegenc->buffer_size != max_size) - ffmpegenc->buffer_size = max_size; + GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer of max size %d", max_size); + if (ffmpegaudenc->buffer_size != max_size) + ffmpegaudenc->buffer_size = max_size; res = avcodec_encode_audio (ctx, audio_out, max_size, (short *) audio_in); if (res < 0) { - GST_ERROR_OBJECT (ffmpegenc, "Failed to encode buffer: %d", res); + GST_ERROR_OBJECT (ffmpegaudenc, "Failed to encode buffer: %d", res); gst_buffer_unref (outbuf); return GST_FLOW_OK; } - GST_LOG_OBJECT (ffmpegenc, "got output size %d", res); + GST_LOG_OBJECT (ffmpegaudenc, "got output size %d", res); GST_BUFFER_SIZE (outbuf) = res; GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = duration; if (discont) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad)); + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegaudenc->srcpad)); - GST_LOG_OBJECT (ffmpegenc, "pushing size %d, timestamp %" GST_TIME_FORMAT, + GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d, timestamp %" GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp)); - ret = gst_pad_push (ffmpegenc->srcpad, outbuf); + ret = gst_pad_push (ffmpegaudenc->srcpad, outbuf); return ret; } static GstFlowReturn -gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) +gst_ffmpegaudenc_chain_audio (GstPad * pad, GstBuffer * inbuf) { - GstFFMpegEnc *ffmpegenc; - GstFFMpegEncClass *oclass; + GstFFMpegAudEnc *ffmpegaudenc; + GstFFMpegAudEncClass *oclass; AVCodecContext *ctx; GstClockTime timestamp, duration; guint size, frame_size; @@ -902,17 +427,17 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) gboolean discont; guint8 *in_data; - ffmpegenc = (GstFFMpegEnc *) (GST_OBJECT_PARENT (pad)); - oclass = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); + ffmpegaudenc = (GstFFMpegAudEnc *) (GST_OBJECT_PARENT (pad)); + oclass = (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); - ctx = ffmpegenc->context; + ctx = ffmpegaudenc->context; size = GST_BUFFER_SIZE (inbuf); timestamp = GST_BUFFER_TIMESTAMP (inbuf); duration = GST_BUFFER_DURATION (inbuf); discont = GST_BUFFER_IS_DISCONT (inbuf); - GST_DEBUG_OBJECT (ffmpegenc, + GST_DEBUG_OBJECT (ffmpegaudenc, "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), size); @@ -924,17 +449,17 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) guint avail, frame_bytes; if (discont) { - GST_LOG_OBJECT (ffmpegenc, "DISCONT, clear adapter"); - gst_adapter_clear (ffmpegenc->adapter); - ffmpegenc->discont = TRUE; + GST_LOG_OBJECT (ffmpegaudenc, "DISCONT, clear adapter"); + gst_adapter_clear (ffmpegaudenc->adapter); + ffmpegaudenc->discont = TRUE; } - if (gst_adapter_available (ffmpegenc->adapter) == 0) { + if (gst_adapter_available (ffmpegaudenc->adapter) == 0) { /* lock on to new timestamp */ - GST_LOG_OBJECT (ffmpegenc, "taking buffer timestamp %" GST_TIME_FORMAT, + GST_LOG_OBJECT (ffmpegaudenc, "taking buffer timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); - ffmpegenc->adapter_ts = timestamp; - ffmpegenc->adapter_consumed = 0; + ffmpegaudenc->adapter_ts = timestamp; + ffmpegaudenc->adapter_consumed = 0; } else { GstClockTime upstream_time; GstClockTime consumed_time; @@ -942,18 +467,20 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) /* use timestamp at head of the adapter */ consumed_time = - gst_util_uint64_scale (ffmpegenc->adapter_consumed, GST_SECOND, + gst_util_uint64_scale (ffmpegaudenc->adapter_consumed, GST_SECOND, ctx->sample_rate); - timestamp = ffmpegenc->adapter_ts + consumed_time; - GST_LOG_OBJECT (ffmpegenc, "taking adapter timestamp %" GST_TIME_FORMAT + timestamp = ffmpegaudenc->adapter_ts + consumed_time; + GST_LOG_OBJECT (ffmpegaudenc, "taking adapter timestamp %" GST_TIME_FORMAT " and adding consumed time %" GST_TIME_FORMAT, - GST_TIME_ARGS (ffmpegenc->adapter_ts), GST_TIME_ARGS (consumed_time)); + GST_TIME_ARGS (ffmpegaudenc->adapter_ts), + GST_TIME_ARGS (consumed_time)); /* check with upstream timestamps, if too much deviation, * forego some timestamp perfection in favour of upstream syncing * (particularly in case these do not happen to come in multiple * of frame size) */ - upstream_time = gst_adapter_prev_timestamp (ffmpegenc->adapter, &bytes); + upstream_time = + gst_adapter_prev_timestamp (ffmpegaudenc->adapter, &bytes); if (GST_CLOCK_TIME_IS_VALID (upstream_time)) { GstClockTimeDiff diff; @@ -963,32 +490,33 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) diff = upstream_time - timestamp; /* relaxed difference, rather than half a sample or so ... */ if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) { - GST_DEBUG_OBJECT (ffmpegenc, "adapter timestamp drifting, " + GST_DEBUG_OBJECT (ffmpegaudenc, "adapter timestamp drifting, " "taking upstream timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (upstream_time)); timestamp = upstream_time; /* samples corresponding to bytes */ - ffmpegenc->adapter_consumed = bytes / (osize * ctx->channels); - ffmpegenc->adapter_ts = upstream_time - - gst_util_uint64_scale (ffmpegenc->adapter_consumed, GST_SECOND, + ffmpegaudenc->adapter_consumed = bytes / (osize * ctx->channels); + ffmpegaudenc->adapter_ts = upstream_time - + gst_util_uint64_scale (ffmpegaudenc->adapter_consumed, GST_SECOND, ctx->sample_rate); - ffmpegenc->discont = TRUE; + ffmpegaudenc->discont = TRUE; } } } - GST_LOG_OBJECT (ffmpegenc, "pushing buffer in adapter"); - gst_adapter_push (ffmpegenc->adapter, inbuf); + GST_LOG_OBJECT (ffmpegaudenc, "pushing buffer in adapter"); + gst_adapter_push (ffmpegaudenc->adapter, inbuf); /* first see how many bytes we need to feed to the decoder. */ frame_bytes = frame_size * osize * ctx->channels; - avail = gst_adapter_available (ffmpegenc->adapter); + avail = gst_adapter_available (ffmpegaudenc->adapter); - GST_LOG_OBJECT (ffmpegenc, "frame_bytes %u, avail %u", frame_bytes, avail); + GST_LOG_OBJECT (ffmpegaudenc, "frame_bytes %u, avail %u", frame_bytes, + avail); /* while there is more than a frame size in the adapter, consume it */ while (avail >= frame_bytes) { - GST_LOG_OBJECT (ffmpegenc, "taking %u bytes from the adapter", + GST_LOG_OBJECT (ffmpegaudenc, "taking %u bytes from the adapter", frame_bytes); /* Note that we take frame_bytes and add frame_size. @@ -996,24 +524,25 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) * or samplesize to divide by the samplerate */ /* take an audio buffer out of the adapter */ - in_data = (guint8 *) gst_adapter_peek (ffmpegenc->adapter, frame_bytes); - ffmpegenc->adapter_consumed += frame_size; + in_data = + (guint8 *) gst_adapter_peek (ffmpegaudenc->adapter, frame_bytes); + ffmpegaudenc->adapter_consumed += frame_size; /* calculate timestamp and duration relative to start of adapter and to * the amount of samples we consumed */ duration = - gst_util_uint64_scale (ffmpegenc->adapter_consumed, GST_SECOND, + gst_util_uint64_scale (ffmpegaudenc->adapter_consumed, GST_SECOND, ctx->sample_rate); - duration -= (timestamp - ffmpegenc->adapter_ts); + duration -= (timestamp - ffmpegaudenc->adapter_ts); /* 4 times the input size should be big enough... */ out_size = frame_bytes * 4; ret = - gst_ffmpegenc_encode_audio (ffmpegenc, in_data, frame_bytes, out_size, - timestamp, duration, ffmpegenc->discont); + gst_ffmpegaudenc_encode_audio (ffmpegaudenc, in_data, frame_bytes, + out_size, timestamp, duration, ffmpegaudenc->discont); - gst_adapter_flush (ffmpegenc->adapter, frame_bytes); + gst_adapter_flush (ffmpegaudenc->adapter, frame_bytes); if (ret != GST_FLOW_OK) goto push_failed; @@ -1021,23 +550,23 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) /* advance the adapter timestamp with the duration */ timestamp += duration; - ffmpegenc->discont = FALSE; - avail = gst_adapter_available (ffmpegenc->adapter); + ffmpegaudenc->discont = FALSE; + avail = gst_adapter_available (ffmpegaudenc->adapter); } - GST_LOG_OBJECT (ffmpegenc, "%u bytes left in the adapter", avail); + GST_LOG_OBJECT (ffmpegaudenc, "%u bytes left in the adapter", avail); } else { /* we have no frame_size, feed the encoder all the data and expect a fixed * output size */ int coded_bps = av_get_bits_per_sample (oclass->in_plugin->id); - GST_LOG_OBJECT (ffmpegenc, "coded bps %d, osize %d", coded_bps, osize); + GST_LOG_OBJECT (ffmpegaudenc, "coded bps %d, osize %d", coded_bps, osize); out_size = size / osize; if (coded_bps) out_size = (out_size * coded_bps) / 8; in_data = (guint8 *) GST_BUFFER_DATA (inbuf); - ret = gst_ffmpegenc_encode_audio (ffmpegenc, in_data, size, out_size, + ret = gst_ffmpegaudenc_encode_audio (ffmpegaudenc, in_data, size, out_size, timestamp, duration, discont); gst_buffer_unref (inbuf); @@ -1050,144 +579,24 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) /* ERRORS */ push_failed: { - GST_DEBUG_OBJECT (ffmpegenc, "Failed to push buffer %d (%s)", ret, + GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to push buffer %d (%s)", ret, gst_flow_get_name (ret)); return ret; } } -static void -gst_ffmpegenc_flush_buffers (GstFFMpegEnc * ffmpegenc, gboolean send) -{ - GstBuffer *outbuf, *inbuf; - gint ret_size; - - GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send); - - /* no need to empty codec if there is none */ - if (!ffmpegenc->opened) - goto flush; - - while (!g_queue_is_empty (ffmpegenc->delay)) { - - ffmpegenc_setup_working_buf (ffmpegenc); - - ret_size = avcodec_encode_video (ffmpegenc->context, - ffmpegenc->working_buf, ffmpegenc->working_buf_size, NULL); - - if (ret_size < 0) { /* there should be something, notify and give up */ -#ifndef GST_DISABLE_GST_DEBUG - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); - GST_WARNING_OBJECT (ffmpegenc, - "ffenc_%s: failed to flush buffer", oclass->in_plugin->name); -#endif /* GST_DISABLE_GST_DEBUG */ - break; - } - - /* save stats info if there is some as well as a stats file */ - if (ffmpegenc->file && ffmpegenc->context->stats_out) - if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0) - GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE, - (("Could not write to file \"%s\"."), ffmpegenc->filename), - GST_ERROR_SYSTEM); - - /* handle b-frame delay when no output, so we don't output empty frames */ - inbuf = g_queue_pop_head (ffmpegenc->delay); - - outbuf = gst_buffer_new_and_alloc (ret_size); - memcpy (GST_BUFFER_DATA (outbuf), ffmpegenc->working_buf, ret_size); - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf); - GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf); - - if (!ffmpegenc->context->coded_frame->key_frame) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad)); - - gst_buffer_unref (inbuf); - - if (send) - gst_pad_push (ffmpegenc->srcpad, outbuf); - else - gst_buffer_unref (outbuf); - } - -flush: - { - /* make sure that we empty the queue, is still needed if we had to break */ - while (!g_queue_is_empty (ffmpegenc->delay)) - gst_buffer_unref (g_queue_pop_head (ffmpegenc->delay)); - } -} - -static gboolean -gst_ffmpegenc_event_video (GstPad * pad, GstEvent * event) -{ - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - gst_ffmpegenc_flush_buffers (ffmpegenc, TRUE); - break; - /* no flushing if flush received, - * buffers in encoder are considered (in the) past */ - - case GST_EVENT_CUSTOM_DOWNSTREAM:{ - const GstStructure *s; - s = gst_event_get_structure (event); - if (gst_structure_has_name (s, "GstForceKeyUnit")) { - ffmpegenc->picture->pict_type = FF_I_TYPE; - } - break; - } - default: - break; - } - - return gst_pad_push_event (ffmpegenc->srcpad, event); -} - -static gboolean -gst_ffmpegenc_event_src (GstPad * pad, GstEvent * event) -{ - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad)); - gboolean forward = TRUE; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CUSTOM_UPSTREAM:{ - const GstStructure *s; - s = gst_event_get_structure (event); - if (gst_structure_has_name (s, "GstForceKeyUnit")) { - GST_OBJECT_LOCK (ffmpegenc); - ffmpegenc->force_keyframe = TRUE; - GST_OBJECT_UNLOCK (ffmpegenc); - forward = FALSE; - gst_event_unref (event); - } - break; - } - - default: - break; - } - - if (forward) - return gst_pad_push_event (ffmpegenc->sinkpad, event); - else - return TRUE; -} static void -gst_ffmpegenc_set_property (GObject * object, +gst_ffmpegaudenc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstFFMpegEnc *ffmpegenc; + GstFFMpegAudEnc *ffmpegaudenc; /* Get a pointer of the right type. */ - ffmpegenc = (GstFFMpegEnc *) (object); + ffmpegaudenc = (GstFFMpegAudEnc *) (object); - if (ffmpegenc->opened) { - GST_WARNING_OBJECT (ffmpegenc, + if (ffmpegaudenc->opened) { + GST_WARNING_OBJECT (ffmpegaudenc, "Can't change properties once decoder is setup !"); return; } @@ -1195,63 +604,49 @@ gst_ffmpegenc_set_property (GObject * object, /* Check the argument id to see which argument we're setting. */ switch (prop_id) { case ARG_BIT_RATE: - ffmpegenc->bitrate = g_value_get_ulong (value); - break; - case ARG_GOP_SIZE: - ffmpegenc->gop_size = g_value_get_int (value); - break; - case ARG_ME_METHOD: - ffmpegenc->me_method = g_value_get_enum (value); + ffmpegaudenc->bitrate = g_value_get_ulong (value); break; case ARG_BUFSIZE: break; case ARG_RTP_PAYLOAD_SIZE: - ffmpegenc->rtp_payload_size = g_value_get_ulong (value); + ffmpegaudenc->rtp_payload_size = g_value_get_ulong (value); break; default: - if (!gst_ffmpeg_cfg_set_property (object, value, pspec)) - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /* The set function is simply the inverse of the get fuction. */ static void -gst_ffmpegenc_get_property (GObject * object, +gst_ffmpegaudenc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstFFMpegEnc *ffmpegenc; + GstFFMpegAudEnc *ffmpegaudenc; /* It's not null if we got it, but it might not be ours */ - ffmpegenc = (GstFFMpegEnc *) (object); + ffmpegaudenc = (GstFFMpegAudEnc *) (object); switch (prop_id) { case ARG_BIT_RATE: - g_value_set_ulong (value, ffmpegenc->bitrate); - break; - case ARG_GOP_SIZE: - g_value_set_int (value, ffmpegenc->gop_size); - break; - case ARG_ME_METHOD: - g_value_set_enum (value, ffmpegenc->me_method); + g_value_set_ulong (value, ffmpegaudenc->bitrate); break; case ARG_BUFSIZE: - g_value_set_ulong (value, ffmpegenc->buffer_size); + g_value_set_ulong (value, ffmpegaudenc->buffer_size); break; case ARG_RTP_PAYLOAD_SIZE: - g_value_set_ulong (value, ffmpegenc->rtp_payload_size); + g_value_set_ulong (value, ffmpegaudenc->rtp_payload_size); break; default: - if (!gst_ffmpeg_cfg_get_property (object, value, pspec)) - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GstStateChangeReturn -gst_ffmpegenc_change_state (GstElement * element, GstStateChange transition) +gst_ffmpegaudenc_change_state (GstElement * element, GstStateChange transition) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) element; + GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) element; GstStateChangeReturn result; switch (transition) { @@ -1263,21 +658,11 @@ gst_ffmpegenc_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_ffmpegenc_flush_buffers (ffmpegenc, FALSE); - if (ffmpegenc->opened) { - gst_ffmpeg_avcodec_close (ffmpegenc->context); - ffmpegenc->opened = FALSE; - } - gst_adapter_clear (ffmpegenc->adapter); - - if (ffmpegenc->file) { - fclose (ffmpegenc->file); - ffmpegenc->file = NULL; - } - if (ffmpegenc->working_buf) { - g_free (ffmpegenc->working_buf); - ffmpegenc->working_buf = NULL; + if (ffmpegaudenc->opened) { + gst_ffmpeg_avcodec_close (ffmpegaudenc->context); + ffmpegaudenc->opened = FALSE; } + gst_adapter_clear (ffmpegaudenc->adapter); break; default: break; @@ -1286,18 +671,18 @@ gst_ffmpegenc_change_state (GstElement * element, GstStateChange transition) } gboolean -gst_ffmpegenc_register (GstPlugin * plugin) +gst_ffmpegaudenc_register (GstPlugin * plugin) { GTypeInfo typeinfo = { - sizeof (GstFFMpegEncClass), - (GBaseInitFunc) gst_ffmpegenc_base_init, + sizeof (GstFFMpegAudEncClass), + (GBaseInitFunc) gst_ffmpegaudenc_base_init, NULL, - (GClassInitFunc) gst_ffmpegenc_class_init, + (GClassInitFunc) gst_ffmpegaudenc_class_init, NULL, NULL, - sizeof (GstFFMpegEnc), + sizeof (GstFFMpegAudEnc), 0, - (GInstanceInitFunc) gst_ffmpegenc_init, + (GInstanceInitFunc) gst_ffmpegaudenc_init, }; GType type; AVCodec *in_plugin; @@ -1305,16 +690,12 @@ gst_ffmpegenc_register (GstPlugin * plugin) GST_LOG ("Registering encoders"); - /* build global ffmpeg param/property info */ - gst_ffmpeg_cfg_init (); - in_plugin = av_codec_next (NULL); while (in_plugin) { gchar *type_name; /* Skip non-AV codecs */ - if (in_plugin->type != AVMEDIA_TYPE_AUDIO && - in_plugin->type != AVMEDIA_TYPE_VIDEO) + if (in_plugin->type != AVMEDIA_TYPE_AUDIO) goto next; /* no quasi codecs, please */ diff --git a/ext/ffmpeg/gstffmpegenc.h b/ext/ffmpeg/gstffmpegenc.h index c13a0d3..ec49d8e 100644 --- a/ext/ffmpeg/gstffmpegenc.h +++ b/ext/ffmpeg/gstffmpegenc.h @@ -21,16 +21,16 @@ * object definition and other useful things. */ -#ifndef __GST_FFMPEGENC_H__ -#define __GST_FFMPEGENC_H__ +#ifndef __GST_FFMPEGAUDENC_H__ +#define __GST_FFMPEGAUDENC_H__ G_BEGIN_DECLS #include -typedef struct _GstFFMpegEnc GstFFMpegEnc; +typedef struct _GstFFMpegAudEnc GstFFMpegAudEnc; -struct _GstFFMpegEnc +struct _GstFFMpegAudEnc { GstElement element; @@ -39,7 +39,6 @@ struct _GstFFMpegEnc GstPad *sinkpad; AVCodecContext *context; - AVFrame *picture; gboolean opened; GstClockTime adapter_ts; guint64 adapter_consumed; @@ -48,39 +47,17 @@ struct _GstFFMpegEnc /* cache */ gulong bitrate; - gint me_method; - gint gop_size; gulong buffer_size; gulong rtp_payload_size; - guint8 *working_buf; - gulong working_buf_size; - - /* settings with some special handling */ - guint pass; - gfloat quantizer; - gchar *filename; - guint lmin; - guint lmax; - gint max_key_interval; - gboolean interlaced; - - /* statistics file */ - FILE *file; - - /* for b-frame delay handling */ - GQueue *delay; - /* other settings are copied over straight, * include a context here, rather than copy-and-past it from avcodec.h */ AVCodecContext config; - - gboolean force_keyframe; }; -typedef struct _GstFFMpegEncClass GstFFMpegEncClass; +typedef struct _GstFFMpegAudEncClass GstFFMpegAudEncClass; -struct _GstFFMpegEncClass +struct _GstFFMpegAudEncClass { GstElementClass parent_class; @@ -89,17 +66,17 @@ struct _GstFFMpegEncClass GstCaps *sinkcaps; }; -#define GST_TYPE_FFMPEGENC \ - (gst_ffmpegenc_get_type()) -#define GST_FFMPEGENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGENC,GstFFMpegEnc)) -#define GST_FFMPEGENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGENC,GstFFMpegEncClass)) -#define GST_IS_FFMPEGENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGENC)) -#define GST_IS_FFMPEGENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGENC)) +#define GST_TYPE_FFMPEGAUDENC \ + (gst_ffmpegaudenc_get_type()) +#define GST_FFMPEGAUDENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGAUDENC,GstFFMpegAudEnc)) +#define GST_FFMPEGAUDENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGAUDENC,GstFFMpegAudEncClass)) +#define GST_IS_FFMPEGAUDENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGAUDENC)) +#define GST_IS_FFMPEGAUDENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGAUDENC)) G_END_DECLS -#endif /* __GST_FFMPEGENC_H__ */ +#endif /* __GST_FFMPEGAUDENC_H__ */ diff --git a/ext/ffmpeg/gstffmpegviddec.c b/ext/ffmpeg/gstffmpegviddec.c index 918abf8..3184bac 100644 --- a/ext/ffmpeg/gstffmpegviddec.c +++ b/ext/ffmpeg/gstffmpegviddec.c @@ -40,7 +40,7 @@ /* define to enable alternative buffer refcounting algorithm */ #undef EXTRA_REF -typedef struct _GstFFMpegDec GstFFMpegDec; +typedef struct _GstFFMpegVidDec GstFFMpegVidDec; #define MAX_TS_MASK 0xff @@ -56,7 +56,7 @@ typedef struct gint64 offset; } GstTSInfo; -struct _GstFFMpegDec +struct _GstFFMpegVidDec { GstElement element; @@ -81,12 +81,6 @@ struct _GstFFMpegDec enum PixelFormat pix_fmt; } video; - struct - { - gint channels; - gint samplerate; - gint depth; - } audio; } format; gboolean waiting_for_key; gboolean discont; @@ -144,9 +138,9 @@ struct _GstFFMpegDec gboolean can_allocate_aligned; }; -typedef struct _GstFFMpegDecClass GstFFMpegDecClass; +typedef struct _GstFFMpegVidDecClass GstFFMpegVidDecClass; -struct _GstFFMpegDecClass +struct _GstFFMpegVidDecClass { GstElementClass parent_class; @@ -158,7 +152,7 @@ struct _GstFFMpegDecClass static const GstTSInfo ts_info_none = { -1, -1, -1, -1 }; static const GstTSInfo * -gst_ts_info_store (GstFFMpegDec * dec, GstClockTime timestamp, +gst_ts_info_store (GstFFMpegVidDec * dec, GstClockTime timestamp, GstClockTime duration, gint64 offset) { gint idx = dec->ts_idx; @@ -172,7 +166,7 @@ gst_ts_info_store (GstFFMpegDec * dec, GstClockTime timestamp, } static const GstTSInfo * -gst_ts_info_get (GstFFMpegDec * dec, gint idx) +gst_ts_info_get (GstFFMpegVidDec * dec, gint idx) { if (G_UNLIKELY (idx < 0 || idx > MAX_TS_MASK)) return GST_TS_INFO_NONE; @@ -181,14 +175,14 @@ gst_ts_info_get (GstFFMpegDec * dec, gint idx) } #define GST_TYPE_FFMPEGDEC \ - (gst_ffmpegdec_get_type()) + (gst_ffmpegviddec_get_type()) #define GST_FFMPEGDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegDec)) -#define GST_FFMPEGDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegDecClass)) + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegVidDec)) +#define GST_FFMPEGVIDDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegVidDecClass)) #define GST_IS_FFMPEGDEC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC)) -#define GST_IS_FFMPEGDEC_CLASS(klass) \ +#define GST_IS_FFMPEGVIDDEC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC)) #define DEFAULT_LOWRES 0 @@ -213,44 +207,44 @@ enum }; /* A number of function prototypes are given so we can refer to them later. */ -static void gst_ffmpegdec_base_init (GstFFMpegDecClass * klass); -static void gst_ffmpegdec_class_init (GstFFMpegDecClass * klass); -static void gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec); -static void gst_ffmpegdec_finalize (GObject * object); +static void gst_ffmpegviddec_base_init (GstFFMpegVidDecClass * klass); +static void gst_ffmpegviddec_class_init (GstFFMpegVidDecClass * klass); +static void gst_ffmpegviddec_init (GstFFMpegVidDec * ffmpegdec); +static void gst_ffmpegviddec_finalize (GObject * object); -static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery * query); -static gboolean gst_ffmpegdec_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_ffmpegviddec_query (GstPad * pad, GstQuery * query); +static gboolean gst_ffmpegviddec_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_ffmpegdec_chain (GstPad * pad, GstBuffer * buf); +static gboolean gst_ffmpegviddec_setcaps (GstPad * pad, GstCaps * caps); +static gboolean gst_ffmpegviddec_sink_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_ffmpegviddec_chain (GstPad * pad, GstBuffer * buf); -static GstStateChangeReturn gst_ffmpegdec_change_state (GstElement * element, +static GstStateChangeReturn gst_ffmpegviddec_change_state (GstElement * element, GstStateChange transition); -static void gst_ffmpegdec_set_property (GObject * object, +static void gst_ffmpegviddec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_ffmpegdec_get_property (GObject * object, +static void gst_ffmpegviddec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, +static gboolean gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec, gboolean force); /* some sort of bufferpool handling, but different */ -static int gst_ffmpegdec_get_buffer (AVCodecContext * context, +static int gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture); -static void gst_ffmpegdec_release_buffer (AVCodecContext * context, +static void gst_ffmpegviddec_release_buffer (AVCodecContext * context, AVFrame * picture); -static void gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec); +static void gst_ffmpegviddec_drain (GstFFMpegVidDec * ffmpegdec); #define GST_FFDEC_PARAMS_QDATA g_quark_from_static_string("ffdec-params") static GstElementClass *parent_class = NULL; -#define GST_FFMPEGDEC_TYPE_LOWRES (gst_ffmpegdec_lowres_get_type()) +#define GST_FFMPEGVIDDEC_TYPE_LOWRES (gst_ffmpegviddec_lowres_get_type()) static GType -gst_ffmpegdec_lowres_get_type (void) +gst_ffmpegviddec_lowres_get_type (void) { static GType ffmpegdec_lowres_type = 0; @@ -263,15 +257,15 @@ gst_ffmpegdec_lowres_get_type (void) }; ffmpegdec_lowres_type = - g_enum_register_static ("GstFFMpegDecLowres", ffmpegdec_lowres); + g_enum_register_static ("GstFFMpegVidDecLowres", ffmpegdec_lowres); } return ffmpegdec_lowres_type; } -#define GST_FFMPEGDEC_TYPE_SKIPFRAME (gst_ffmpegdec_skipframe_get_type()) +#define GST_FFMPEGVIDDEC_TYPE_SKIPFRAME (gst_ffmpegviddec_skipframe_get_type()) static GType -gst_ffmpegdec_skipframe_get_type (void) +gst_ffmpegviddec_skipframe_get_type (void) { static GType ffmpegdec_skipframe_type = 0; @@ -285,20 +279,21 @@ gst_ffmpegdec_skipframe_get_type (void) }; ffmpegdec_skipframe_type = - g_enum_register_static ("GstFFMpegDecSkipFrame", ffmpegdec_skipframe); + g_enum_register_static ("GstFFMpegVidDecSkipFrame", + ffmpegdec_skipframe); } return ffmpegdec_skipframe_type; } static void -gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) +gst_ffmpegviddec_base_init (GstFFMpegVidDecClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstPadTemplate *sinktempl, *srctempl; GstCaps *sinkcaps, *srccaps; AVCodec *in_plugin; - gchar *longname, *classification, *description; + gchar *longname, *description; in_plugin = (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), @@ -307,16 +302,13 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) /* construct the element details struct */ longname = g_strdup_printf ("FFmpeg %s decoder", in_plugin->long_name); - classification = g_strdup_printf ("Codec/Decoder/%s", - (in_plugin->type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio"); description = g_strdup_printf ("FFmpeg %s decoder", in_plugin->name); - gst_element_class_set_details_simple (element_class, longname, classification, - description, + gst_element_class_set_details_simple (element_class, longname, + "Codec/Decoder/Video", description, "Wim Taymans , " "Ronald Bultje , " "Edward Hervey "); g_free (longname); - g_free (classification); g_free (description); /* get the caps */ @@ -325,16 +317,7 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) GST_DEBUG ("Couldn't get sink caps for decoder '%s'", in_plugin->name); sinkcaps = gst_caps_from_string ("unknown/unknown"); } - if (in_plugin->type == AVMEDIA_TYPE_VIDEO) { - srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv"); - } else { - srccaps = gst_ffmpeg_codectype_to_audio_caps (NULL, - in_plugin->id, FALSE, in_plugin); - } - if (!srccaps) { - GST_DEBUG ("Couldn't get source caps for decoder '%s'", in_plugin->name); - srccaps = gst_caps_from_string ("unknown/unknown"); - } + srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv"); /* pad templates */ sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, @@ -350,17 +333,17 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) } static void -gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) +gst_ffmpegviddec_class_init (GstFFMpegVidDecClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); - gobject_class->finalize = gst_ffmpegdec_finalize; + gobject_class->finalize = gst_ffmpegviddec_finalize; - gobject_class->set_property = gst_ffmpegdec_set_property; - gobject_class->get_property = gst_ffmpegdec_get_property; + gobject_class->set_property = gst_ffmpegviddec_set_property; + gobject_class->get_property = gst_ffmpegviddec_get_property; if (klass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { int caps; @@ -368,12 +351,13 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) g_object_class_install_property (gobject_class, PROP_SKIPFRAME, g_param_spec_enum ("skip-frame", "Skip frames", "Which types of frames to skip during decoding", - GST_FFMPEGDEC_TYPE_SKIPFRAME, 0, + GST_FFMPEGVIDDEC_TYPE_SKIPFRAME, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_LOWRES, g_param_spec_enum ("lowres", "Low resolution", - "At which resolution to decode images", GST_FFMPEGDEC_TYPE_LOWRES, - 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "At which resolution to decode images", + GST_FFMPEGVIDDEC_TYPE_LOWRES, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_DIRECT_RENDERING, g_param_spec_boolean ("direct-rendering", "Direct Rendering", "Enable direct rendering", DEFAULT_DIRECT_RENDERING, @@ -403,32 +387,32 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) } } - gstelement_class->change_state = gst_ffmpegdec_change_state; + gstelement_class->change_state = gst_ffmpegviddec_change_state; } static void -gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec) +gst_ffmpegviddec_init (GstFFMpegVidDec * ffmpegdec) { - GstFFMpegDecClass *oclass; + GstFFMpegVidDecClass *oclass; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); /* setup pads */ ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); gst_pad_set_setcaps_function (ffmpegdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_setcaps)); + GST_DEBUG_FUNCPTR (gst_ffmpegviddec_setcaps)); gst_pad_set_event_function (ffmpegdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_sink_event)); + GST_DEBUG_FUNCPTR (gst_ffmpegviddec_sink_event)); gst_pad_set_chain_function (ffmpegdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_chain)); + GST_DEBUG_FUNCPTR (gst_ffmpegviddec_chain)); gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad); ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); gst_pad_use_fixed_caps (ffmpegdec->srcpad); gst_pad_set_event_function (ffmpegdec->srcpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_src_event)); + GST_DEBUG_FUNCPTR (gst_ffmpegviddec_src_event)); gst_pad_set_query_function (ffmpegdec->srcpad, - GST_DEBUG_FUNCPTR (gst_ffmpegdec_query)); + GST_DEBUG_FUNCPTR (gst_ffmpegviddec_query)); gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad); /* some ffmpeg data */ @@ -456,9 +440,9 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec) } static void -gst_ffmpegdec_finalize (GObject * object) +gst_ffmpegviddec_finalize (GObject * object) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object; + GstFFMpegVidDec *ffmpegdec = (GstFFMpegVidDec *) object; if (ffmpegdec->context != NULL) { av_free (ffmpegdec->context); @@ -474,12 +458,12 @@ gst_ffmpegdec_finalize (GObject * object) } static gboolean -gst_ffmpegdec_query (GstPad * pad, GstQuery * query) +gst_ffmpegviddec_query (GstPad * pad, GstQuery * query) { - GstFFMpegDec *ffmpegdec; + GstFFMpegVidDec *ffmpegdec; gboolean res = FALSE; - ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); + ffmpegdec = (GstFFMpegVidDec *) gst_pad_get_parent (pad); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY: @@ -521,7 +505,7 @@ gst_ffmpegdec_query (GstPad * pad, GstQuery * query) } static void -gst_ffmpegdec_reset_ts (GstFFMpegDec * ffmpegdec) +gst_ffmpegviddec_reset_ts (GstFFMpegVidDec * ffmpegdec) { ffmpegdec->last_in = GST_CLOCK_TIME_NONE; ffmpegdec->last_diff = GST_CLOCK_TIME_NONE; @@ -533,7 +517,7 @@ gst_ffmpegdec_reset_ts (GstFFMpegDec * ffmpegdec) } static void -gst_ffmpegdec_update_qos (GstFFMpegDec * ffmpegdec, gdouble proportion, +gst_ffmpegviddec_update_qos (GstFFMpegVidDec * ffmpegdec, gdouble proportion, GstClockTime timestamp) { GST_LOG_OBJECT (ffmpegdec, "update QOS: %f, %" GST_TIME_FORMAT, @@ -546,15 +530,15 @@ gst_ffmpegdec_update_qos (GstFFMpegDec * ffmpegdec, gdouble proportion, } static void -gst_ffmpegdec_reset_qos (GstFFMpegDec * ffmpegdec) +gst_ffmpegviddec_reset_qos (GstFFMpegVidDec * ffmpegdec) { - gst_ffmpegdec_update_qos (ffmpegdec, 0.5, GST_CLOCK_TIME_NONE); + gst_ffmpegviddec_update_qos (ffmpegdec, 0.5, GST_CLOCK_TIME_NONE); ffmpegdec->processed = 0; ffmpegdec->dropped = 0; } static void -gst_ffmpegdec_read_qos (GstFFMpegDec * ffmpegdec, gdouble * proportion, +gst_ffmpegviddec_read_qos (GstFFMpegVidDec * ffmpegdec, gdouble * proportion, GstClockTime * timestamp) { GST_OBJECT_LOCK (ffmpegdec); @@ -564,12 +548,12 @@ gst_ffmpegdec_read_qos (GstFFMpegDec * ffmpegdec, gdouble * proportion, } static gboolean -gst_ffmpegdec_src_event (GstPad * pad, GstEvent * event) +gst_ffmpegviddec_src_event (GstPad * pad, GstEvent * event) { - GstFFMpegDec *ffmpegdec; + GstFFMpegVidDec *ffmpegdec; gboolean res; - ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); + ffmpegdec = (GstFFMpegVidDec *) gst_pad_get_parent (pad); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_QOS: @@ -581,7 +565,7 @@ gst_ffmpegdec_src_event (GstPad * pad, GstEvent * event) gst_event_parse_qos (event, &proportion, &diff, ×tamp); /* update our QoS values */ - gst_ffmpegdec_update_qos (ffmpegdec, proportion, timestamp + diff); + gst_ffmpegviddec_update_qos (ffmpegdec, proportion, timestamp + diff); /* forward upstream */ res = gst_pad_push_event (ffmpegdec->sinkpad, event); @@ -600,7 +584,7 @@ gst_ffmpegdec_src_event (GstPad * pad, GstEvent * event) /* with LOCK */ static void -gst_ffmpegdec_close (GstFFMpegDec * ffmpegdec) +gst_ffmpegviddec_close (GstFFMpegVidDec * ffmpegdec) { if (!ffmpegdec->opened) return; @@ -643,11 +627,11 @@ gst_ffmpegdec_close (GstFFMpegDec * ffmpegdec) /* with LOCK */ static gboolean -gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec) +gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec) { - GstFFMpegDecClass *oclass; + GstFFMpegVidDecClass *oclass; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); if (gst_ffmpeg_avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0) goto could_not_open; @@ -697,25 +681,14 @@ gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec) break; } - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - ffmpegdec->format.video.width = 0; - ffmpegdec->format.video.height = 0; - ffmpegdec->format.video.clip_width = -1; - ffmpegdec->format.video.clip_height = -1; - ffmpegdec->format.video.pix_fmt = PIX_FMT_NB; - ffmpegdec->format.video.interlaced = FALSE; - break; - case AVMEDIA_TYPE_AUDIO: - ffmpegdec->format.audio.samplerate = 0; - ffmpegdec->format.audio.channels = 0; - ffmpegdec->format.audio.depth = 0; - break; - default: - break; - } + ffmpegdec->format.video.width = 0; + ffmpegdec->format.video.height = 0; + ffmpegdec->format.video.clip_width = -1; + ffmpegdec->format.video.clip_height = -1; + ffmpegdec->format.video.pix_fmt = PIX_FMT_NB; + ffmpegdec->format.video.interlaced = FALSE; - gst_ffmpegdec_reset_ts (ffmpegdec); + gst_ffmpegviddec_reset_ts (ffmpegdec); /* FIXME, reset_qos holds the LOCK */ ffmpegdec->proportion = 0.0; ffmpegdec->earliest_time = -1; @@ -725,7 +698,7 @@ gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec) /* ERRORS */ could_not_open: { - gst_ffmpegdec_close (ffmpegdec); + gst_ffmpegviddec_close (ffmpegdec); GST_DEBUG_OBJECT (ffmpegdec, "ffdec_%s: Failed to open FFMPEG codec", oclass->in_plugin->name); return FALSE; @@ -733,17 +706,17 @@ could_not_open: } static gboolean -gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) +gst_ffmpegviddec_setcaps (GstPad * pad, GstCaps * caps) { - GstFFMpegDec *ffmpegdec; - GstFFMpegDecClass *oclass; + GstFFMpegVidDec *ffmpegdec; + GstFFMpegVidDecClass *oclass; GstStructure *structure; const GValue *par; const GValue *fps; gboolean ret = TRUE; - ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad)); - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + ffmpegdec = (GstFFMpegVidDec *) (gst_pad_get_parent (pad)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_DEBUG_OBJECT (pad, "setcaps called"); @@ -757,9 +730,9 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) /* close old session */ if (ffmpegdec->opened) { GST_OBJECT_UNLOCK (ffmpegdec); - gst_ffmpegdec_drain (ffmpegdec); + gst_ffmpegviddec_drain (ffmpegdec); GST_OBJECT_LOCK (ffmpegdec); - gst_ffmpegdec_close (ffmpegdec); + gst_ffmpegviddec_close (ffmpegdec); /* and reset the defaults that were set when a context is created */ avcodec_get_context_defaults (ffmpegdec->context); @@ -767,8 +740,8 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) /* set buffer functions */ if (oclass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { - ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer; - ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer; + ffmpegdec->context->get_buffer = gst_ffmpegviddec_get_buffer; + ffmpegdec->context->release_buffer = gst_ffmpegviddec_release_buffer; ffmpegdec->context->draw_horiz_band = NULL; } @@ -897,7 +870,7 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) /* open codec - we don't select an output pix_fmt yet, * simply because we don't know! We only get it * during playback... */ - if (!gst_ffmpegdec_open (ffmpegdec)) + if (!gst_ffmpegviddec_open (ffmpegdec)) goto open_failed; /* clipping region */ @@ -939,7 +912,7 @@ open_failed: } static GstFlowReturn -alloc_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf, +alloc_output_buffer (GstFFMpegVidDec * ffmpegdec, GstBuffer ** outbuf, gint width, gint height) { GstFlowReturn ret; @@ -951,7 +924,7 @@ alloc_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf, GST_LOG_OBJECT (ffmpegdec, "alloc output buffer"); /* see if we need renegotiation */ - if (G_UNLIKELY (!gst_ffmpegdec_negotiate (ffmpegdec, FALSE))) + if (G_UNLIKELY (!gst_ffmpegviddec_negotiate (ffmpegdec, FALSE))) goto negotiate_failed; /* get the size of the gstreamer output buffer given a @@ -1007,15 +980,18 @@ alloc_failed: } static int -gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture) +gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture) { GstBuffer *buf = NULL; - GstFFMpegDec *ffmpegdec; + GstFFMpegVidDec *ffmpegdec; gint width, height; gint coded_width, coded_height; gint res; + GstFlowReturn ret; + gint clip_width, clip_height; - ffmpegdec = (GstFFMpegDec *) context->opaque; + + ffmpegdec = (GstFFMpegVidDec *) context->opaque; GST_DEBUG_OBJECT (ffmpegdec, "getting buffer"); @@ -1046,55 +1022,38 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture) return res; } - switch (context->codec_type) { - case AVMEDIA_TYPE_VIDEO: - /* some ffmpeg video plugins don't see the point in setting codec_type ... */ - case AVMEDIA_TYPE_UNKNOWN: - { - GstFlowReturn ret; - gint clip_width, clip_height; - - /* take final clipped output size */ - if ((clip_width = ffmpegdec->format.video.clip_width) == -1) - clip_width = width; - if ((clip_height = ffmpegdec->format.video.clip_height) == -1) - clip_height = height; - - GST_LOG_OBJECT (ffmpegdec, "raw outsize %d/%d", width, height); + /* take final clipped output size */ + if ((clip_width = ffmpegdec->format.video.clip_width) == -1) + clip_width = width; + if ((clip_height = ffmpegdec->format.video.clip_height) == -1) + clip_height = height; - /* this is the size ffmpeg needs for the buffer */ - avcodec_align_dimensions (context, &width, &height); + GST_LOG_OBJECT (ffmpegdec, "raw outsize %d/%d", width, height); - GST_LOG_OBJECT (ffmpegdec, "aligned outsize %d/%d, clip %d/%d", - width, height, clip_width, clip_height); + /* this is the size ffmpeg needs for the buffer */ + avcodec_align_dimensions (context, &width, &height); - if (width != clip_width || height != clip_height) { - /* We can't alloc if we need to clip the output buffer later */ - GST_LOG_OBJECT (ffmpegdec, "we need clipping, fallback alloc"); - return avcodec_default_get_buffer (context, picture); - } + GST_LOG_OBJECT (ffmpegdec, "aligned outsize %d/%d, clip %d/%d", + width, height, clip_width, clip_height); - /* alloc with aligned dimensions for ffmpeg */ - ret = alloc_output_buffer (ffmpegdec, &buf, width, height); - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - /* alloc default buffer when we can't get one from downstream */ - GST_LOG_OBJECT (ffmpegdec, "alloc failed, fallback alloc"); - return avcodec_default_get_buffer (context, picture); - } + if (width != clip_width || height != clip_height) { + /* We can't alloc if we need to clip the output buffer later */ + GST_LOG_OBJECT (ffmpegdec, "we need clipping, fallback alloc"); + return avcodec_default_get_buffer (context, picture); + } - /* copy the right pointers and strides in the picture object */ - gst_ffmpeg_avpicture_fill ((AVPicture *) picture, - GST_BUFFER_DATA (buf), context->pix_fmt, width, height); - break; - } - case AVMEDIA_TYPE_AUDIO: - default: - GST_ERROR_OBJECT (ffmpegdec, - "_get_buffer() should never get called for non-video buffers !"); - g_assert_not_reached (); - break; + /* alloc with aligned dimensions for ffmpeg */ + ret = alloc_output_buffer (ffmpegdec, &buf, width, height); + if (G_UNLIKELY (ret != GST_FLOW_OK)) { + /* alloc default buffer when we can't get one from downstream */ + GST_LOG_OBJECT (ffmpegdec, "alloc failed, fallback alloc"); + return avcodec_default_get_buffer (context, picture); } + /* copy the right pointers and strides in the picture object */ + gst_ffmpeg_avpicture_fill ((AVPicture *) picture, + GST_BUFFER_DATA (buf), context->pix_fmt, width, height); + /* tell ffmpeg we own this buffer, tranfer the ref we have on the buffer to * the opaque data. */ picture->type = FF_BUFFER_TYPE_USER; @@ -1114,13 +1073,13 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture) } static void -gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture) +gst_ffmpegviddec_release_buffer (AVCodecContext * context, AVFrame * picture) { gint i; GstBuffer *buf; - GstFFMpegDec *ffmpegdec; + GstFFMpegVidDec *ffmpegdec; - ffmpegdec = (GstFFMpegDec *) context->opaque; + ffmpegdec = (GstFFMpegVidDec *) context->opaque; /* check if it was our buffer */ if (picture->opaque == NULL) { @@ -1151,7 +1110,7 @@ gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture) } static void -gst_ffmpegdec_add_pixel_aspect_ratio (GstFFMpegDec * ffmpegdec, +gst_ffmpegviddec_add_pixel_aspect_ratio (GstFFMpegVidDec * ffmpegdec, GstStructure * s) { gboolean demuxer_par_set = FALSE; @@ -1229,65 +1188,41 @@ no_par: } static gboolean -gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, gboolean force) +gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec, gboolean force) { - GstFFMpegDecClass *oclass; + GstFFMpegVidDecClass *oclass; GstCaps *caps; - - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - if (!force && ffmpegdec->format.video.width == ffmpegdec->context->width - && ffmpegdec->format.video.height == ffmpegdec->context->height - && ffmpegdec->format.video.fps_n == ffmpegdec->format.video.old_fps_n - && ffmpegdec->format.video.fps_d == ffmpegdec->format.video.old_fps_d - && ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt - && ffmpegdec->format.video.par_n == - ffmpegdec->context->sample_aspect_ratio.num - && ffmpegdec->format.video.par_d == - ffmpegdec->context->sample_aspect_ratio.den) - return TRUE; - GST_DEBUG_OBJECT (ffmpegdec, - "Renegotiating video from %dx%d@ %d:%d PAR %d/%d fps to %dx%d@ %d:%d PAR %d/%d fps", - ffmpegdec->format.video.width, ffmpegdec->format.video.height, - ffmpegdec->format.video.par_n, ffmpegdec->format.video.par_d, - ffmpegdec->format.video.old_fps_n, ffmpegdec->format.video.old_fps_n, - ffmpegdec->context->width, ffmpegdec->context->height, - ffmpegdec->context->sample_aspect_ratio.num, - ffmpegdec->context->sample_aspect_ratio.den, - ffmpegdec->format.video.fps_n, ffmpegdec->format.video.fps_d); - ffmpegdec->format.video.width = ffmpegdec->context->width; - ffmpegdec->format.video.height = ffmpegdec->context->height; - ffmpegdec->format.video.old_fps_n = ffmpegdec->format.video.fps_n; - ffmpegdec->format.video.old_fps_d = ffmpegdec->format.video.fps_d; - ffmpegdec->format.video.pix_fmt = ffmpegdec->context->pix_fmt; - ffmpegdec->format.video.par_n = - ffmpegdec->context->sample_aspect_ratio.num; - ffmpegdec->format.video.par_d = - ffmpegdec->context->sample_aspect_ratio.den; - break; - case AVMEDIA_TYPE_AUDIO: - { - gint depth = av_smp_format_depth (ffmpegdec->context->sample_fmt); - if (!force && ffmpegdec->format.audio.samplerate == - ffmpegdec->context->sample_rate && - ffmpegdec->format.audio.channels == ffmpegdec->context->channels && - ffmpegdec->format.audio.depth == depth) - return TRUE; - GST_DEBUG_OBJECT (ffmpegdec, - "Renegotiating audio from %dHz@%dchannels (%d) to %dHz@%dchannels (%d)", - ffmpegdec->format.audio.samplerate, ffmpegdec->format.audio.channels, - ffmpegdec->format.audio.depth, - ffmpegdec->context->sample_rate, ffmpegdec->context->channels, depth); - ffmpegdec->format.audio.samplerate = ffmpegdec->context->sample_rate; - ffmpegdec->format.audio.channels = ffmpegdec->context->channels; - ffmpegdec->format.audio.depth = depth; - } - break; - default: - break; - } + gint width, height; + gboolean interlaced; + + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + + if (!force && ffmpegdec->format.video.width == ffmpegdec->context->width + && ffmpegdec->format.video.height == ffmpegdec->context->height + && ffmpegdec->format.video.fps_n == ffmpegdec->format.video.old_fps_n + && ffmpegdec->format.video.fps_d == ffmpegdec->format.video.old_fps_d + && ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt + && ffmpegdec->format.video.par_n == + ffmpegdec->context->sample_aspect_ratio.num + && ffmpegdec->format.video.par_d == + ffmpegdec->context->sample_aspect_ratio.den) + return TRUE; + GST_DEBUG_OBJECT (ffmpegdec, + "Renegotiating video from %dx%d@ %d:%d PAR %d/%d fps to %dx%d@ %d:%d PAR %d/%d fps", + ffmpegdec->format.video.width, ffmpegdec->format.video.height, + ffmpegdec->format.video.par_n, ffmpegdec->format.video.par_d, + ffmpegdec->format.video.old_fps_n, ffmpegdec->format.video.old_fps_n, + ffmpegdec->context->width, ffmpegdec->context->height, + ffmpegdec->context->sample_aspect_ratio.num, + ffmpegdec->context->sample_aspect_ratio.den, + ffmpegdec->format.video.fps_n, ffmpegdec->format.video.fps_d); + ffmpegdec->format.video.width = ffmpegdec->context->width; + ffmpegdec->format.video.height = ffmpegdec->context->height; + ffmpegdec->format.video.old_fps_n = ffmpegdec->format.video.fps_n; + ffmpegdec->format.video.old_fps_d = ffmpegdec->format.video.fps_d; + ffmpegdec->format.video.pix_fmt = ffmpegdec->context->pix_fmt; + ffmpegdec->format.video.par_n = ffmpegdec->context->sample_aspect_ratio.num; + ffmpegdec->format.video.par_d = ffmpegdec->context->sample_aspect_ratio.den; caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type, ffmpegdec->context, oclass->in_plugin->id, FALSE); @@ -1295,44 +1230,28 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, gboolean force) if (caps == NULL) goto no_caps; - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - { - gint width, height; - gboolean interlaced; + width = ffmpegdec->format.video.clip_width; + height = ffmpegdec->format.video.clip_height; + interlaced = ffmpegdec->format.video.interlaced; - width = ffmpegdec->format.video.clip_width; - height = ffmpegdec->format.video.clip_height; - interlaced = ffmpegdec->format.video.interlaced; - - if (width != -1 && height != -1) { - /* overwrite the output size with the dimension of the - * clipping region but only if they are smaller. */ - if (width < ffmpegdec->context->width) - gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL); - if (height < ffmpegdec->context->height) - gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL); - } - gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced, - NULL); - - /* If a demuxer provided a framerate then use it (#313970) */ - if (ffmpegdec->format.video.fps_n != -1) { - gst_caps_set_simple (caps, "framerate", - GST_TYPE_FRACTION, ffmpegdec->format.video.fps_n, - ffmpegdec->format.video.fps_d, NULL); - } - gst_ffmpegdec_add_pixel_aspect_ratio (ffmpegdec, - gst_caps_get_structure (caps, 0)); - break; - } - case AVMEDIA_TYPE_AUDIO: - { - break; - } - default: - break; + if (width != -1 && height != -1) { + /* overwrite the output size with the dimension of the + * clipping region but only if they are smaller. */ + if (width < ffmpegdec->context->width) + gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL); + if (height < ffmpegdec->context->height) + gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL); } + gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced, NULL); + + /* If a demuxer provided a framerate then use it (#313970) */ + if (ffmpegdec->format.video.fps_n != -1) { + gst_caps_set_simple (caps, "framerate", + GST_TYPE_FRACTION, ffmpegdec->format.video.fps_n, + ffmpegdec->format.video.fps_d, NULL); + } + gst_ffmpegviddec_add_pixel_aspect_ratio (ffmpegdec, + gst_caps_get_structure (caps, 0)); if (!gst_pad_set_caps (ffmpegdec->srcpad, caps)) goto caps_failed; @@ -1382,7 +1301,7 @@ caps_failed: * entirely. */ static gboolean -gst_ffmpegdec_do_qos (GstFFMpegDec * ffmpegdec, GstClockTime timestamp, +gst_ffmpegviddec_do_qos (GstFFMpegVidDec * ffmpegdec, GstClockTime timestamp, gboolean * mode_switch) { GstClockTimeDiff diff; @@ -1397,7 +1316,7 @@ gst_ffmpegdec_do_qos (GstFFMpegDec * ffmpegdec, GstClockTime timestamp, goto no_qos; /* get latest QoS observation values */ - gst_ffmpegdec_read_qos (ffmpegdec, &proportion, &earliest_time); + gst_ffmpegviddec_read_qos (ffmpegdec, &proportion, &earliest_time); /* skip qos if we have no observation (yet) */ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) { @@ -1492,7 +1411,7 @@ drop_qos: /* returns TRUE if buffer is within segment, else FALSE. * if Buffer is on segment border, it's timestamp and duration will be clipped */ static gboolean -clip_video_buffer (GstFFMpegDec * dec, GstBuffer * buf, GstClockTime in_ts, +clip_video_buffer (GstFFMpegVidDec * dec, GstBuffer * buf, GstClockTime in_ts, GstClockTime in_dur) { gboolean res = TRUE; @@ -1546,15 +1465,15 @@ beach: /* figure out if the current picture is a keyframe, return TRUE if that is * the case. */ static gboolean -check_keyframe (GstFFMpegDec * ffmpegdec) +check_keyframe (GstFFMpegVidDec * ffmpegdec) { - GstFFMpegDecClass *oclass; + GstFFMpegVidDecClass *oclass; gboolean is_itype = FALSE; gboolean is_reference = FALSE; gboolean iskeyframe; /* figure out if we are dealing with a keyframe */ - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); /* remember that we have B frames, we need this for the DTS -> PTS conversion * code */ @@ -1585,7 +1504,7 @@ check_keyframe (GstFFMpegDec * ffmpegdec) /* get an outbuf buffer with the current picture */ static GstFlowReturn -get_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf) +get_output_buffer (GstFFMpegVidDec * ffmpegdec, GstBuffer ** outbuf) { GstFlowReturn ret; @@ -1653,7 +1572,7 @@ alloc_failed: } static void -clear_queued (GstFFMpegDec * ffmpegdec) +clear_queued (GstFFMpegVidDec * ffmpegdec) { g_list_foreach (ffmpegdec->queued, (GFunc) gst_mini_object_unref, NULL); g_list_free (ffmpegdec->queued); @@ -1661,7 +1580,7 @@ clear_queued (GstFFMpegDec * ffmpegdec) } static GstFlowReturn -flush_queued (GstFFMpegDec * ffmpegdec) +flush_queued (GstFFMpegVidDec * ffmpegdec) { GstFlowReturn res = GST_FLOW_OK; @@ -1692,7 +1611,7 @@ gst_avpacket_init (AVPacket * packet, guint8 * data, guint size) packet->size = size; } -/* gst_ffmpegdec_[video|audio]_frame: +/* gst_ffmpegviddec_[video|audio]_frame: * ffmpegdec: * data: pointer to the data to decode * size: size of data in bytes @@ -1706,7 +1625,7 @@ gst_avpacket_init (AVPacket * packet, guint8 * data, guint size) * outbuf being non-NULL. */ static gint -gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, +gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec, guint8 * data, guint size, const GstTSInfo * dec_info, GstBuffer ** outbuf, GstFlowReturn * ret) { @@ -1731,7 +1650,8 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, /* run QoS code, we don't stop decoding the frame when we are late because * else we might skip a reference frame */ - decode = gst_ffmpegdec_do_qos (ffmpegdec, dec_info->timestamp, &mode_switch); + decode = + gst_ffmpegviddec_do_qos (ffmpegdec, dec_info->timestamp, &mode_switch); if (ffmpegdec->is_realvideo && data != NULL) { gint slice_count; @@ -1824,7 +1744,7 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, ffmpegdec->picture->interlaced_frame, ffmpegdec->format.video.interlaced); ffmpegdec->format.video.interlaced = ffmpegdec->picture->interlaced_frame; - gst_ffmpegdec_negotiate (ffmpegdec, TRUE); + gst_ffmpegviddec_negotiate (ffmpegdec, TRUE); } @@ -2062,192 +1982,8 @@ clipped: } } -/* returns TRUE if buffer is within segment, else FALSE. - * if Buffer is on segment border, it's timestamp and duration will be clipped */ -static gboolean -clip_audio_buffer (GstFFMpegDec * dec, GstBuffer * buf, GstClockTime in_ts, - GstClockTime in_dur) -{ - GstClockTime stop; - gint64 diff, ctime, cstop; - gboolean res = TRUE; - - GST_LOG_OBJECT (dec, - "timestamp:%" GST_TIME_FORMAT ", duration:%" GST_TIME_FORMAT - ", size %u", GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur), - GST_BUFFER_SIZE (buf)); - - /* can't clip without TIME segment */ - if (G_UNLIKELY (dec->segment.format != GST_FORMAT_TIME)) - goto beach; - - /* we need a start time */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) - goto beach; - - /* trust duration */ - stop = in_ts + in_dur; - - res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME, in_ts, stop, &ctime, - &cstop); - if (G_UNLIKELY (!res)) - goto out_of_segment; - - /* see if some clipping happened */ - if (G_UNLIKELY ((diff = ctime - in_ts) > 0)) { - /* bring clipped time to bytes */ - diff = - gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, - GST_SECOND) * (dec->format.audio.depth * dec->format.audio.channels); - - GST_DEBUG_OBJECT (dec, "clipping start to %" GST_TIME_FORMAT " %" - G_GINT64_FORMAT " bytes", GST_TIME_ARGS (ctime), diff); - - GST_BUFFER_SIZE (buf) -= diff; - GST_BUFFER_DATA (buf) += diff; - } - if (G_UNLIKELY ((diff = stop - cstop) > 0)) { - /* bring clipped time to bytes */ - diff = - gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, - GST_SECOND) * (dec->format.audio.depth * dec->format.audio.channels); - - GST_DEBUG_OBJECT (dec, "clipping stop to %" GST_TIME_FORMAT " %" - G_GINT64_FORMAT " bytes", GST_TIME_ARGS (cstop), diff); - - GST_BUFFER_SIZE (buf) -= diff; - } - GST_BUFFER_TIMESTAMP (buf) = ctime; - GST_BUFFER_DURATION (buf) = cstop - ctime; - -beach: - GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : "")); - return res; - - /* ERRORS */ -out_of_segment: - { - GST_LOG_OBJECT (dec, "out of segment"); - goto beach; - } -} - -static gint -gst_ffmpegdec_audio_frame (GstFFMpegDec * ffmpegdec, - AVCodec * in_plugin, guint8 * data, guint size, - const GstTSInfo * dec_info, GstBuffer ** outbuf, GstFlowReturn * ret) -{ - gint len = -1; - gint have_data = AVCODEC_MAX_AUDIO_FRAME_SIZE; - GstClockTime out_timestamp, out_duration; - gint64 out_offset; - AVPacket packet; - - GST_DEBUG_OBJECT (ffmpegdec, - "size:%d, offset:%" G_GINT64_FORMAT ", ts:%" GST_TIME_FORMAT ", dur:%" - GST_TIME_FORMAT ", ffmpegdec->next_out:%" GST_TIME_FORMAT, size, - dec_info->offset, GST_TIME_ARGS (dec_info->timestamp), - GST_TIME_ARGS (dec_info->duration), GST_TIME_ARGS (ffmpegdec->next_out)); - - *outbuf = - new_aligned_buffer (AVCODEC_MAX_AUDIO_FRAME_SIZE, - GST_PAD_CAPS (ffmpegdec->srcpad)); - - gst_avpacket_init (&packet, data, size); - len = avcodec_decode_audio3 (ffmpegdec->context, - (int16_t *) GST_BUFFER_DATA (*outbuf), &have_data, &packet); - GST_DEBUG_OBJECT (ffmpegdec, - "Decode audio: len=%d, have_data=%d", len, have_data); - - if (len >= 0 && have_data > 0) { - GST_DEBUG_OBJECT (ffmpegdec, "Creating output buffer"); - if (!gst_ffmpegdec_negotiate (ffmpegdec, FALSE)) { - gst_buffer_unref (*outbuf); - *outbuf = NULL; - len = -1; - goto beach; - } - - /* Buffer size */ - GST_BUFFER_SIZE (*outbuf) = have_data; - - /* - * Timestamps: - * - * 1) Copy input timestamp if valid - * 2) else interpolate from previous input timestamp - */ - /* always take timestamps from the input buffer if any */ - if (GST_CLOCK_TIME_IS_VALID (dec_info->timestamp)) { - out_timestamp = dec_info->timestamp; - } else { - out_timestamp = ffmpegdec->next_out; - } - - /* - * Duration: - * - * 1) calculate based on number of samples - */ - out_duration = gst_util_uint64_scale (have_data, GST_SECOND, - ffmpegdec->format.audio.depth * ffmpegdec->format.audio.channels * - ffmpegdec->format.audio.samplerate); - - /* offset: - * - * Just copy - */ - out_offset = dec_info->offset; - GST_DEBUG_OBJECT (ffmpegdec, - "Buffer created. Size:%d , timestamp:%" GST_TIME_FORMAT " , duration:%" - GST_TIME_FORMAT, have_data, - GST_TIME_ARGS (out_timestamp), GST_TIME_ARGS (out_duration)); - - GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp; - GST_BUFFER_DURATION (*outbuf) = out_duration; - GST_BUFFER_OFFSET (*outbuf) = out_offset; - gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (ffmpegdec->srcpad)); - - /* the next timestamp we'll use when interpolating */ - if (GST_CLOCK_TIME_IS_VALID (out_timestamp)) - ffmpegdec->next_out = out_timestamp + out_duration; - - /* now see if we need to clip the buffer against the segment boundaries. */ - if (G_UNLIKELY (!clip_audio_buffer (ffmpegdec, *outbuf, out_timestamp, - out_duration))) - goto clipped; - - } else { - gst_buffer_unref (*outbuf); - *outbuf = NULL; - } - - /* If we don't error out after the first failed read with the AAC decoder, - * we must *not* carry on pushing data, else we'll cause segfaults... */ - if (len == -1 && (in_plugin->id == CODEC_ID_AAC - || in_plugin->id == CODEC_ID_AAC_LATM)) { - GST_ELEMENT_ERROR (ffmpegdec, STREAM, DECODE, (NULL), - ("Decoding of AAC stream by FFMPEG failed.")); - *ret = GST_FLOW_ERROR; - } - -beach: - GST_DEBUG_OBJECT (ffmpegdec, "return flow %d, out %p, len %d", - *ret, *outbuf, len); - return len; - - /* ERRORS */ -clipped: - { - GST_DEBUG_OBJECT (ffmpegdec, "buffer clipped"); - gst_buffer_unref (*outbuf); - *outbuf = NULL; - goto beach; - } -} - -/* gst_ffmpegdec_frame: +/* gst_ffmpegviddec_frame: * ffmpegdec: * data: pointer to the data to decode * size: size of data in bytes @@ -2262,11 +1998,11 @@ clipped: */ static gint -gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, +gst_ffmpegviddec_frame (GstFFMpegVidDec * ffmpegdec, guint8 * data, guint size, gint * got_data, const GstTSInfo * dec_info, GstFlowReturn * ret) { - GstFFMpegDecClass *oclass; + GstFFMpegVidDecClass *oclass; GstBuffer *outbuf = NULL; gint have_data = 0, len = 0; @@ -2279,32 +2015,11 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, *ret = GST_FLOW_OK; ffmpegdec->context->frame_number++; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - switch (oclass->in_plugin->type) { - case AVMEDIA_TYPE_VIDEO: - len = - gst_ffmpegdec_video_frame (ffmpegdec, data, size, dec_info, &outbuf, - ret); - break; - case AVMEDIA_TYPE_AUDIO: - len = - gst_ffmpegdec_audio_frame (ffmpegdec, oclass->in_plugin, data, size, - dec_info, &outbuf, ret); - - /* if we did not get an output buffer and we have a pending discont, don't - * clear the input timestamps, we will put them on the next buffer because - * else we might create the first buffer with a very big timestamp gap. */ - if (outbuf == NULL && ffmpegdec->discont) { - GST_DEBUG_OBJECT (ffmpegdec, "no buffer but keeping timestamp"); - ffmpegdec->clear_ts = FALSE; - } - break; - default: - GST_ERROR_OBJECT (ffmpegdec, "Asked to decode non-audio/video frame !"); - g_assert_not_reached (); - break; - } + len = + gst_ffmpegviddec_video_frame (ffmpegdec, data, size, dec_info, + &outbuf, ret); if (outbuf) have_data = 1; @@ -2362,11 +2077,11 @@ no_codec: } static void -gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) +gst_ffmpegviddec_drain (GstFFMpegVidDec * ffmpegdec) { - GstFFMpegDecClass *oclass; + GstFFMpegVidDecClass *oclass; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); if (oclass->in_plugin->capabilities & CODEC_CAP_DELAY) { gint have_data, len, try = 0; @@ -2378,7 +2093,7 @@ gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) GstFlowReturn ret; len = - gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data, &ts_info_none, + gst_ffmpegviddec_frame (ffmpegdec, NULL, 0, &have_data, &ts_info_none, &ret); if (len < 0 || have_data == 0) break; @@ -2391,7 +2106,7 @@ gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) } static void -gst_ffmpegdec_flush_pcache (GstFFMpegDec * ffmpegdec) +gst_ffmpegviddec_flush_pcache (GstFFMpegVidDec * ffmpegdec) { if (ffmpegdec->pctx) { gint size, bsize; @@ -2416,12 +2131,12 @@ gst_ffmpegdec_flush_pcache (GstFFMpegDec * ffmpegdec) } static gboolean -gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) +gst_ffmpegviddec_sink_event (GstPad * pad, GstEvent * event) { - GstFFMpegDec *ffmpegdec; + GstFFMpegVidDec *ffmpegdec; gboolean ret = FALSE; - ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); + ffmpegdec = (GstFFMpegVidDec *) gst_pad_get_parent (pad); GST_DEBUG_OBJECT (ffmpegdec, "Handling %s event", GST_EVENT_TYPE_NAME (event)); @@ -2429,7 +2144,7 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: { - gst_ffmpegdec_drain (ffmpegdec); + gst_ffmpegviddec_drain (ffmpegdec); break; } case GST_EVENT_FLUSH_STOP: @@ -2437,9 +2152,9 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) if (ffmpegdec->opened) { avcodec_flush_buffers (ffmpegdec->context); } - gst_ffmpegdec_reset_ts (ffmpegdec); - gst_ffmpegdec_reset_qos (ffmpegdec); - gst_ffmpegdec_flush_pcache (ffmpegdec); + gst_ffmpegviddec_reset_ts (ffmpegdec); + gst_ffmpegviddec_reset_qos (ffmpegdec); + gst_ffmpegviddec_flush_pcache (ffmpegdec); ffmpegdec->waiting_for_key = TRUE; gst_segment_init (&ffmpegdec->segment, GST_FORMAT_TIME); clear_queued (ffmpegdec); @@ -2499,7 +2214,7 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) /* drain pending frames before trying to use the new segment, queued * buffers belonged to the previous segment. */ if (ffmpegdec->context->codec) - gst_ffmpegdec_drain (ffmpegdec); + gst_ffmpegviddec_drain (ffmpegdec); GST_DEBUG_OBJECT (ffmpegdec, "NEWSEGMENT in time start %" GST_TIME_FORMAT " -- stop %" @@ -2538,10 +2253,10 @@ invalid_format: } static GstFlowReturn -gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) +gst_ffmpegviddec_chain (GstPad * pad, GstBuffer * inbuf) { - GstFFMpegDec *ffmpegdec; - GstFFMpegDecClass *oclass; + GstFFMpegVidDec *ffmpegdec; + GstFFMpegVidDecClass *oclass; guint8 *data, *bdata; gint size, bsize, len, have_data; GstFlowReturn ret = GST_FLOW_OK; @@ -2552,7 +2267,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) const GstTSInfo *in_info; const GstTSInfo *dec_info; - ffmpegdec = (GstFFMpegDec *) (GST_PAD_PARENT (pad)); + ffmpegdec = (GstFFMpegVidDec *) (GST_PAD_PARENT (pad)); if (G_UNLIKELY (!ffmpegdec->opened)) goto not_negotiated; @@ -2566,17 +2281,17 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) if (G_UNLIKELY (discont)) { GST_DEBUG_OBJECT (ffmpegdec, "received DISCONT"); /* drain what we have queued */ - gst_ffmpegdec_drain (ffmpegdec); - gst_ffmpegdec_flush_pcache (ffmpegdec); + gst_ffmpegviddec_drain (ffmpegdec); + gst_ffmpegviddec_flush_pcache (ffmpegdec); avcodec_flush_buffers (ffmpegdec->context); ffmpegdec->discont = TRUE; - gst_ffmpegdec_reset_ts (ffmpegdec); + gst_ffmpegviddec_reset_ts (ffmpegdec); } /* by default we clear the input timestamp after decoding each frame so that * interpollation can work. */ ffmpegdec->clear_ts = TRUE; - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); /* do early keyframe check pretty bad to rely on the keyframe flag in the * source for this as it might not even be parsed (UDP/file/..). */ @@ -2731,7 +2446,8 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) /* decode a frame of audio/video now */ len = - gst_ffmpegdec_frame (ffmpegdec, data, size, &have_data, dec_info, &ret); + gst_ffmpegviddec_frame (ffmpegdec, data, size, &have_data, dec_info, + &ret); if (ffmpegdec->do_padding) { memcpy (data + size, tmp_padding, FF_INPUT_BUFFER_PADDING_SIZE); @@ -2816,7 +2532,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) /* ERRORS */ not_negotiated: { - oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), ("ffdec_%s: input format was not set before data start", oclass->in_plugin->name)); @@ -2832,9 +2548,9 @@ skip_keyframe: } static GstStateChangeReturn -gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition) +gst_ffmpegviddec_change_state (GstElement * element, GstStateChange transition) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element; + GstFFMpegVidDec *ffmpegdec = (GstFFMpegVidDec *) element; GstStateChangeReturn ret; ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); @@ -2842,7 +2558,7 @@ gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: GST_OBJECT_LOCK (ffmpegdec); - gst_ffmpegdec_close (ffmpegdec); + gst_ffmpegviddec_close (ffmpegdec); GST_OBJECT_UNLOCK (ffmpegdec); clear_queued (ffmpegdec); g_free (ffmpegdec->padded); @@ -2858,10 +2574,10 @@ gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition) } static void -gst_ffmpegdec_set_property (GObject * object, +gst_ffmpegviddec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object; + GstFFMpegVidDec *ffmpegdec = (GstFFMpegVidDec *) object; switch (prop_id) { case PROP_LOWRES: @@ -2894,10 +2610,10 @@ gst_ffmpegdec_set_property (GObject * object, } static void -gst_ffmpegdec_get_property (GObject * object, +gst_ffmpegviddec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object; + GstFFMpegVidDec *ffmpegdec = (GstFFMpegVidDec *) object; switch (prop_id) { case PROP_LOWRES: @@ -2928,18 +2644,18 @@ gst_ffmpegdec_get_property (GObject * object, } gboolean -gst_ffmpegdec_register (GstPlugin * plugin) +gst_ffmpegviddec_register (GstPlugin * plugin) { GTypeInfo typeinfo = { - sizeof (GstFFMpegDecClass), - (GBaseInitFunc) gst_ffmpegdec_base_init, + sizeof (GstFFMpegVidDecClass), + (GBaseInitFunc) gst_ffmpegviddec_base_init, NULL, - (GClassInitFunc) gst_ffmpegdec_class_init, + (GClassInitFunc) gst_ffmpegviddec_class_init, NULL, NULL, - sizeof (GstFFMpegDec), + sizeof (GstFFMpegVidDec), 0, - (GInstanceInitFunc) gst_ffmpegdec_init, + (GInstanceInitFunc) gst_ffmpegviddec_init, }; GType type; AVCodec *in_plugin; @@ -3002,14 +2718,8 @@ gst_ffmpegdec_register (GstPlugin * plugin) /* MP2 : Use MP3 for decoding */ /* Theora: Use libtheora based theoradec */ if (!strcmp (in_plugin->name, "gif") || - !strcmp (in_plugin->name, "vorbis") || !strcmp (in_plugin->name, "theora") || !strcmp (in_plugin->name, "mpeg1video") || - !strcmp (in_plugin->name, "wavpack") || - !strcmp (in_plugin->name, "mp1") || - !strcmp (in_plugin->name, "mp2") || - !strcmp (in_plugin->name, "libfaad") || - !strcmp (in_plugin->name, "mpeg4aac") || !strcmp (in_plugin->name, "ass") || !strcmp (in_plugin->name, "srt") || !strcmp (in_plugin->name, "pgssub") || @@ -3041,28 +2751,19 @@ gst_ffmpegdec_register (GstPlugin * plugin) case CODEC_ID_MPEG4: case CODEC_ID_MSMPEG4V3: case CODEC_ID_H264: - case CODEC_ID_RA_144: - case CODEC_ID_RA_288: case CODEC_ID_RV10: case CODEC_ID_RV20: case CODEC_ID_RV30: case CODEC_ID_RV40: - case CODEC_ID_COOK: rank = GST_RANK_PRIMARY; break; /* DVVIDEO: we have a good dv decoder, fast on both ppc as well as x86. * They say libdv's quality is better though. leave as secondary. * note: if you change this, see the code in gstdv.c in good/ext/dv. - * - * SIPR: decoder should have a higher rank than realaudiodec. */ case CODEC_ID_DVVIDEO: - case CODEC_ID_SIPR: rank = GST_RANK_SECONDARY; break; - case CODEC_ID_MP3: - rank = GST_RANK_NONE; - break; default: rank = GST_RANK_MARGINAL; break; diff --git a/ext/ffmpeg/gstffmpegvidenc.c b/ext/ffmpeg/gstffmpegvidenc.c index f3dd34d..7bca239 100644 --- a/ext/ffmpeg/gstffmpegvidenc.c +++ b/ext/ffmpeg/gstffmpegvidenc.c @@ -39,12 +39,11 @@ #include "gstffmpeg.h" #include "gstffmpegcodecmap.h" #include "gstffmpegutils.h" -#include "gstffmpegenc.h" +#include "gstffmpegvidenc.h" #include "gstffmpegcfg.h" #define DEFAULT_VIDEO_BITRATE 300000 /* in bps */ #define DEFAULT_VIDEO_GOP_SIZE 15 -#define DEFAULT_AUDIO_BITRATE 128000 #define DEFAULT_WIDTH 352 #define DEFAULT_HEIGHT 288 @@ -69,9 +68,9 @@ enum ARG_CFG_BASE }; -#define GST_TYPE_ME_METHOD (gst_ffmpegenc_me_method_get_type()) +#define GST_TYPE_ME_METHOD (gst_ffmpegvidenc_me_method_get_type()) static GType -gst_ffmpegenc_me_method_get_type (void) +gst_ffmpegvidenc_me_method_get_type (void) { static GType ffmpegenc_me_method_type = 0; static GEnumValue ffmpegenc_me_methods[] = { @@ -85,48 +84,47 @@ gst_ffmpegenc_me_method_get_type (void) }; if (!ffmpegenc_me_method_type) { ffmpegenc_me_method_type = - g_enum_register_static ("GstFFMpegEncMeMethod", ffmpegenc_me_methods); + g_enum_register_static ("GstFFMpegVidEncMeMethod", + ffmpegenc_me_methods); } return ffmpegenc_me_method_type; } /* A number of function prototypes are given so we can refer to them later. */ -static void gst_ffmpegenc_class_init (GstFFMpegEncClass * klass); -static void gst_ffmpegenc_base_init (GstFFMpegEncClass * klass); -static void gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc); -static void gst_ffmpegenc_finalize (GObject * object); - -static gboolean gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps); -static GstCaps *gst_ffmpegenc_getcaps (GstPad * pad); -static GstFlowReturn gst_ffmpegenc_chain_video (GstPad * pad, +static void gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass); +static void gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass); +static void gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc); +static void gst_ffmpegvidenc_finalize (GObject * object); + +static gboolean gst_ffmpegvidenc_setcaps (GstPad * pad, GstCaps * caps); +static GstCaps *gst_ffmpegvidenc_getcaps (GstPad * pad); +static GstFlowReturn gst_ffmpegvidenc_chain_video (GstPad * pad, GstBuffer * buffer); -static GstFlowReturn gst_ffmpegenc_chain_audio (GstPad * pad, - GstBuffer * buffer); -static gboolean gst_ffmpegenc_event_video (GstPad * pad, GstEvent * event); -static gboolean gst_ffmpegenc_event_src (GstPad * pad, GstEvent * event); +static gboolean gst_ffmpegvidenc_event_video (GstPad * pad, GstEvent * event); +static gboolean gst_ffmpegvidenc_event_src (GstPad * pad, GstEvent * event); -static void gst_ffmpegenc_set_property (GObject * object, +static void gst_ffmpegvidenc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_ffmpegenc_get_property (GObject * object, +static void gst_ffmpegvidenc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_ffmpegenc_change_state (GstElement * element, +static GstStateChangeReturn gst_ffmpegvidenc_change_state (GstElement * element, GstStateChange transition); #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("ffenc-params") static GstElementClass *parent_class = NULL; -/*static guint gst_ffmpegenc_signals[LAST_SIGNAL] = { 0 }; */ +/*static guint gst_ffmpegvidenc_signals[LAST_SIGNAL] = { 0 }; */ static void -gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) +gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); AVCodec *in_plugin; GstPadTemplate *srctempl = NULL, *sinktempl = NULL; GstCaps *srccaps = NULL, *sinkcaps = NULL; - gchar *longname, *classification, *description; + gchar *longname, *description; in_plugin = (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), @@ -135,15 +133,12 @@ gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) /* construct the element details struct */ longname = g_strdup_printf ("FFmpeg %s encoder", in_plugin->long_name); - classification = g_strdup_printf ("Codec/Encoder/%s", - (in_plugin->type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio"); description = g_strdup_printf ("FFmpeg %s encoder", in_plugin->name); - gst_element_class_set_details_simple (element_class, longname, classification, - description, + gst_element_class_set_details_simple (element_class, longname, + "Codec/Encoder/Video", description, "Wim Taymans , " "Ronald Bultje "); g_free (longname); - g_free (classification); g_free (description); if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) { @@ -151,17 +146,8 @@ gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) srccaps = gst_caps_new_simple ("unknown/unknown", NULL); } - if (in_plugin->type == AVMEDIA_TYPE_VIDEO) { - sinkcaps = gst_caps_from_string - ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray"); - } else { - sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL, - in_plugin->id, TRUE, in_plugin); - } - if (!sinkcaps) { - GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name); - sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL); - } + sinkcaps = gst_caps_from_string + ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray"); /* pad templates */ sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, @@ -180,7 +166,7 @@ gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) } static void -gst_ffmpegenc_class_init (GstFFMpegEncClass * klass) +gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; @@ -190,60 +176,52 @@ gst_ffmpegenc_class_init (GstFFMpegEncClass * klass) parent_class = g_type_class_peek_parent (klass); - gobject_class->set_property = gst_ffmpegenc_set_property; - gobject_class->get_property = gst_ffmpegenc_get_property; - - if (klass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, - g_param_spec_ulong ("bitrate", "Bit Rate", - "Target Video Bitrate", 0, G_MAXULONG, DEFAULT_VIDEO_BITRATE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GOP_SIZE, - g_param_spec_int ("gop-size", "GOP Size", - "Number of frames within one GOP", 0, G_MAXINT, - DEFAULT_VIDEO_GOP_SIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ME_METHOD, - g_param_spec_enum ("me-method", "ME Method", "Motion Estimation Method", - GST_TYPE_ME_METHOD, ME_EPZS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* FIXME 0.11: Make this property read-only */ - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE, - g_param_spec_ulong ("buffer-size", "Buffer Size", - "Size of the video buffers. " - "Note: Setting this property has no effect " - "and is deprecated!", 0, G_MAXULONG, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - ARG_RTP_PAYLOAD_SIZE, g_param_spec_ulong ("rtp-payload-size", - "RTP Payload Size", "Target GOB length", 0, G_MAXULONG, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* register additional properties, possibly dependent on the exact CODEC */ - gst_ffmpeg_cfg_install_property (klass, ARG_CFG_BASE); - } else if (klass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, - g_param_spec_ulong ("bitrate", "Bit Rate", - "Target Audio Bitrate", 0, G_MAXULONG, DEFAULT_AUDIO_BITRATE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - } - - gstelement_class->change_state = gst_ffmpegenc_change_state; - - gobject_class->finalize = gst_ffmpegenc_finalize; + gobject_class->set_property = gst_ffmpegvidenc_set_property; + gobject_class->get_property = gst_ffmpegvidenc_get_property; + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, + g_param_spec_ulong ("bitrate", "Bit Rate", + "Target Video Bitrate", 0, G_MAXULONG, DEFAULT_VIDEO_BITRATE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GOP_SIZE, + g_param_spec_int ("gop-size", "GOP Size", + "Number of frames within one GOP", 0, G_MAXINT, + DEFAULT_VIDEO_GOP_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ME_METHOD, + g_param_spec_enum ("me-method", "ME Method", "Motion Estimation Method", + GST_TYPE_ME_METHOD, ME_EPZS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /* FIXME 0.11: Make this property read-only */ + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE, + g_param_spec_ulong ("buffer-size", "Buffer Size", + "Size of the video buffers. " + "Note: Setting this property has no effect " + "and is deprecated!", 0, G_MAXULONG, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), + ARG_RTP_PAYLOAD_SIZE, g_param_spec_ulong ("rtp-payload-size", + "RTP Payload Size", "Target GOB length", 0, G_MAXULONG, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /* register additional properties, possibly dependent on the exact CODEC */ + gst_ffmpeg_cfg_install_property (klass, ARG_CFG_BASE); + + gstelement_class->change_state = gst_ffmpegvidenc_change_state; + + gobject_class->finalize = gst_ffmpegvidenc_finalize; } static void -gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc) +gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc) { - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); + GstFFMpegVidEncClass *oclass = + (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); /* setup pads */ ffmpegenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); - gst_pad_set_setcaps_function (ffmpegenc->sinkpad, gst_ffmpegenc_setcaps); - gst_pad_set_getcaps_function (ffmpegenc->sinkpad, gst_ffmpegenc_getcaps); + gst_pad_set_setcaps_function (ffmpegenc->sinkpad, gst_ffmpegvidenc_setcaps); + gst_pad_set_getcaps_function (ffmpegenc->sinkpad, gst_ffmpegvidenc_getcaps); ffmpegenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); gst_pad_use_fixed_caps (ffmpegenc->srcpad); @@ -255,39 +233,31 @@ gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc) ffmpegenc->file = NULL; ffmpegenc->delay = g_queue_new (); - if (oclass->in_plugin->type == AVMEDIA_TYPE_VIDEO) { - gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegenc_chain_video); - /* so we know when to flush the buffers on EOS */ - gst_pad_set_event_function (ffmpegenc->sinkpad, gst_ffmpegenc_event_video); - gst_pad_set_event_function (ffmpegenc->srcpad, gst_ffmpegenc_event_src); - - ffmpegenc->bitrate = DEFAULT_VIDEO_BITRATE; - ffmpegenc->me_method = ME_EPZS; - ffmpegenc->buffer_size = 512 * 1024; - ffmpegenc->gop_size = DEFAULT_VIDEO_GOP_SIZE; - ffmpegenc->rtp_payload_size = 0; + gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegvidenc_chain_video); + /* so we know when to flush the buffers on EOS */ + gst_pad_set_event_function (ffmpegenc->sinkpad, gst_ffmpegvidenc_event_video); + gst_pad_set_event_function (ffmpegenc->srcpad, gst_ffmpegvidenc_event_src); - ffmpegenc->lmin = 2; - ffmpegenc->lmax = 31; - ffmpegenc->max_key_interval = 0; + ffmpegenc->bitrate = DEFAULT_VIDEO_BITRATE; + ffmpegenc->me_method = ME_EPZS; + ffmpegenc->buffer_size = 512 * 1024; + ffmpegenc->gop_size = DEFAULT_VIDEO_GOP_SIZE; + ffmpegenc->rtp_payload_size = 0; - gst_ffmpeg_cfg_set_defaults (ffmpegenc); - } else if (oclass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { - gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegenc_chain_audio); + ffmpegenc->lmin = 2; + ffmpegenc->lmax = 31; + ffmpegenc->max_key_interval = 0; - ffmpegenc->bitrate = DEFAULT_AUDIO_BITRATE; - } + gst_ffmpeg_cfg_set_defaults (ffmpegenc); gst_element_add_pad (GST_ELEMENT (ffmpegenc), ffmpegenc->sinkpad); gst_element_add_pad (GST_ELEMENT (ffmpegenc), ffmpegenc->srcpad); - - ffmpegenc->adapter = gst_adapter_new (); } static void -gst_ffmpegenc_finalize (GObject * object) +gst_ffmpegvidenc_finalize (GObject * object) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) object; + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) object; gst_ffmpeg_cfg_finalize (ffmpegenc); @@ -304,13 +274,11 @@ gst_ffmpegenc_finalize (GObject * object) g_queue_free (ffmpegenc->delay); g_free (ffmpegenc->filename); - g_object_unref (ffmpegenc->adapter); - G_OBJECT_CLASS (parent_class)->finalize (object); } static GstCaps * -gst_ffmpegenc_get_possible_sizes (GstFFMpegEnc * ffmpegenc, GstPad * pad, +gst_ffmpegvidenc_get_possible_sizes (GstFFMpegVidEnc * ffmpegenc, GstPad * pad, const GstCaps * caps) { GstCaps *othercaps = NULL; @@ -371,11 +339,11 @@ gst_ffmpegenc_get_possible_sizes (GstFFMpegEnc * ffmpegenc, GstPad * pad, static GstCaps * -gst_ffmpegenc_getcaps (GstPad * pad) +gst_ffmpegvidenc_getcaps (GstPad * pad) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) GST_PAD_PARENT (pad); + GstFFMpegVidEncClass *oclass = + (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); AVCodecContext *ctx = NULL; enum PixelFormat pixfmt; GstCaps *caps = NULL; @@ -384,19 +352,10 @@ gst_ffmpegenc_getcaps (GstPad * pad) GST_DEBUG_OBJECT (ffmpegenc, "getting caps"); - /* audio needs no special care */ - if (oclass->in_plugin->type == AVMEDIA_TYPE_AUDIO) { - caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - - GST_DEBUG_OBJECT (ffmpegenc, "audio caps, return template %" GST_PTR_FORMAT, - caps); - - return caps; - } - /* cached */ if (oclass->sinkcaps) { - caps = gst_ffmpegenc_get_possible_sizes (ffmpegenc, pad, oclass->sinkcaps); + caps = + gst_ffmpegvidenc_get_possible_sizes (ffmpegenc, pad, oclass->sinkcaps); GST_DEBUG_OBJECT (ffmpegenc, "return cached caps %" GST_PTR_FORMAT, caps); return caps; } @@ -495,7 +454,7 @@ gst_ffmpegenc_getcaps (GstPad * pad) /* make sure we have something */ if (!caps) { - caps = gst_ffmpegenc_get_possible_sizes (ffmpegenc, pad, + caps = gst_ffmpegvidenc_get_possible_sizes (ffmpegenc, pad, gst_pad_get_pad_template_caps (pad)); GST_DEBUG_OBJECT (ffmpegenc, "probing gave nothing, " "return template %" GST_PTR_FORMAT, caps); @@ -505,22 +464,22 @@ gst_ffmpegenc_getcaps (GstPad * pad) GST_DEBUG_OBJECT (ffmpegenc, "probed caps gave %" GST_PTR_FORMAT, caps); oclass->sinkcaps = gst_caps_copy (caps); - finalcaps = gst_ffmpegenc_get_possible_sizes (ffmpegenc, pad, caps); + finalcaps = gst_ffmpegvidenc_get_possible_sizes (ffmpegenc, pad, caps); gst_caps_unref (caps); return finalcaps; } static gboolean -gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps) +gst_ffmpegvidenc_setcaps (GstPad * pad, GstCaps * caps) { GstCaps *other_caps; GstCaps *allowed_caps; GstCaps *icaps; enum PixelFormat pix_fmt; - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) GST_PAD_PARENT (pad); + GstFFMpegVidEncClass *oclass = + (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); /* close old session */ if (ffmpegenc->opened) { @@ -734,7 +693,7 @@ gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps) } static void -ffmpegenc_setup_working_buf (GstFFMpegEnc * ffmpegenc) +ffmpegenc_setup_working_buf (GstFFMpegVidEnc * ffmpegenc) { guint wanted_size = ffmpegenc->context->width * ffmpegenc->context->height * 6 + @@ -753,9 +712,9 @@ ffmpegenc_setup_working_buf (GstFFMpegEnc * ffmpegenc) } static GstFlowReturn -gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf) +gst_ffmpegvidenc_chain_video (GstPad * pad, GstBuffer * inbuf) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad)); + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) (GST_PAD_PARENT (pad)); GstBuffer *outbuf; gint ret_size = 0, frame_size; gboolean force_keyframe; @@ -789,8 +748,8 @@ gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf) if (ret_size < 0) { #ifndef GST_DISABLE_GST_DEBUG - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); + GstFFMpegVidEncClass *oclass = + (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_ERROR_OBJECT (ffmpegenc, "ffenc_%s: failed to encode buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ @@ -843,221 +802,8 @@ gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf) return gst_pad_push (ffmpegenc->srcpad, outbuf); } -static GstFlowReturn -gst_ffmpegenc_encode_audio (GstFFMpegEnc * ffmpegenc, guint8 * audio_in, - guint in_size, guint max_size, GstClockTime timestamp, - GstClockTime duration, gboolean discont) -{ - GstBuffer *outbuf; - AVCodecContext *ctx; - guint8 *audio_out; - gint res; - GstFlowReturn ret; - - ctx = ffmpegenc->context; - - /* We need to provide at least ffmpegs minimal buffer size */ - outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE); - audio_out = GST_BUFFER_DATA (outbuf); - - GST_LOG_OBJECT (ffmpegenc, "encoding buffer of max size %d", max_size); - if (ffmpegenc->buffer_size != max_size) - ffmpegenc->buffer_size = max_size; - - res = avcodec_encode_audio (ctx, audio_out, max_size, (short *) audio_in); - - if (res < 0) { - GST_ERROR_OBJECT (ffmpegenc, "Failed to encode buffer: %d", res); - gst_buffer_unref (outbuf); - return GST_FLOW_OK; - } - GST_LOG_OBJECT (ffmpegenc, "got output size %d", res); - - GST_BUFFER_SIZE (outbuf) = res; - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - GST_BUFFER_DURATION (outbuf) = duration; - if (discont) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad)); - - GST_LOG_OBJECT (ffmpegenc, "pushing size %d, timestamp %" GST_TIME_FORMAT, - res, GST_TIME_ARGS (timestamp)); - - ret = gst_pad_push (ffmpegenc->srcpad, outbuf); - - return ret; -} - -static GstFlowReturn -gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) -{ - GstFFMpegEnc *ffmpegenc; - GstFFMpegEncClass *oclass; - AVCodecContext *ctx; - GstClockTime timestamp, duration; - guint size, frame_size; - gint osize; - GstFlowReturn ret; - gint out_size; - gboolean discont; - guint8 *in_data; - - ffmpegenc = (GstFFMpegEnc *) (GST_OBJECT_PARENT (pad)); - oclass = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); - - ctx = ffmpegenc->context; - - size = GST_BUFFER_SIZE (inbuf); - timestamp = GST_BUFFER_TIMESTAMP (inbuf); - duration = GST_BUFFER_DURATION (inbuf); - discont = GST_BUFFER_IS_DISCONT (inbuf); - - GST_DEBUG_OBJECT (ffmpegenc, - "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT - ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), size); - - frame_size = ctx->frame_size; - osize = av_get_bits_per_sample_format (ctx->sample_fmt) / 8; - - if (frame_size > 1) { - /* we have a frame_size, feed the encoder multiples of this frame size */ - guint avail, frame_bytes; - - if (discont) { - GST_LOG_OBJECT (ffmpegenc, "DISCONT, clear adapter"); - gst_adapter_clear (ffmpegenc->adapter); - ffmpegenc->discont = TRUE; - } - - if (gst_adapter_available (ffmpegenc->adapter) == 0) { - /* lock on to new timestamp */ - GST_LOG_OBJECT (ffmpegenc, "taking buffer timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (timestamp)); - ffmpegenc->adapter_ts = timestamp; - ffmpegenc->adapter_consumed = 0; - } else { - GstClockTime upstream_time; - GstClockTime consumed_time; - guint64 bytes; - - /* use timestamp at head of the adapter */ - consumed_time = - gst_util_uint64_scale (ffmpegenc->adapter_consumed, GST_SECOND, - ctx->sample_rate); - timestamp = ffmpegenc->adapter_ts + consumed_time; - GST_LOG_OBJECT (ffmpegenc, "taking adapter timestamp %" GST_TIME_FORMAT - " and adding consumed time %" GST_TIME_FORMAT, - GST_TIME_ARGS (ffmpegenc->adapter_ts), GST_TIME_ARGS (consumed_time)); - - /* check with upstream timestamps, if too much deviation, - * forego some timestamp perfection in favour of upstream syncing - * (particularly in case these do not happen to come in multiple - * of frame size) */ - upstream_time = gst_adapter_prev_timestamp (ffmpegenc->adapter, &bytes); - if (GST_CLOCK_TIME_IS_VALID (upstream_time)) { - GstClockTimeDiff diff; - - upstream_time += - gst_util_uint64_scale (bytes, GST_SECOND, - ctx->sample_rate * osize * ctx->channels); - diff = upstream_time - timestamp; - /* relaxed difference, rather than half a sample or so ... */ - if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) { - GST_DEBUG_OBJECT (ffmpegenc, "adapter timestamp drifting, " - "taking upstream timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (upstream_time)); - timestamp = upstream_time; - /* samples corresponding to bytes */ - ffmpegenc->adapter_consumed = bytes / (osize * ctx->channels); - ffmpegenc->adapter_ts = upstream_time - - gst_util_uint64_scale (ffmpegenc->adapter_consumed, GST_SECOND, - ctx->sample_rate); - ffmpegenc->discont = TRUE; - } - } - } - - GST_LOG_OBJECT (ffmpegenc, "pushing buffer in adapter"); - gst_adapter_push (ffmpegenc->adapter, inbuf); - - /* first see how many bytes we need to feed to the decoder. */ - frame_bytes = frame_size * osize * ctx->channels; - avail = gst_adapter_available (ffmpegenc->adapter); - - GST_LOG_OBJECT (ffmpegenc, "frame_bytes %u, avail %u", frame_bytes, avail); - - /* while there is more than a frame size in the adapter, consume it */ - while (avail >= frame_bytes) { - GST_LOG_OBJECT (ffmpegenc, "taking %u bytes from the adapter", - frame_bytes); - - /* Note that we take frame_bytes and add frame_size. - * Makes sense when resyncing because you don't have to count channels - * or samplesize to divide by the samplerate */ - - /* take an audio buffer out of the adapter */ - in_data = (guint8 *) gst_adapter_peek (ffmpegenc->adapter, frame_bytes); - ffmpegenc->adapter_consumed += frame_size; - - /* calculate timestamp and duration relative to start of adapter and to - * the amount of samples we consumed */ - duration = - gst_util_uint64_scale (ffmpegenc->adapter_consumed, GST_SECOND, - ctx->sample_rate); - duration -= (timestamp - ffmpegenc->adapter_ts); - - /* 4 times the input size should be big enough... */ - out_size = frame_bytes * 4; - - ret = - gst_ffmpegenc_encode_audio (ffmpegenc, in_data, frame_bytes, out_size, - timestamp, duration, ffmpegenc->discont); - - gst_adapter_flush (ffmpegenc->adapter, frame_bytes); - - if (ret != GST_FLOW_OK) - goto push_failed; - - /* advance the adapter timestamp with the duration */ - timestamp += duration; - - ffmpegenc->discont = FALSE; - avail = gst_adapter_available (ffmpegenc->adapter); - } - GST_LOG_OBJECT (ffmpegenc, "%u bytes left in the adapter", avail); - } else { - /* we have no frame_size, feed the encoder all the data and expect a fixed - * output size */ - int coded_bps = av_get_bits_per_sample (oclass->in_plugin->id); - - GST_LOG_OBJECT (ffmpegenc, "coded bps %d, osize %d", coded_bps, osize); - - out_size = size / osize; - if (coded_bps) - out_size = (out_size * coded_bps) / 8; - - in_data = (guint8 *) GST_BUFFER_DATA (inbuf); - ret = gst_ffmpegenc_encode_audio (ffmpegenc, in_data, size, out_size, - timestamp, duration, discont); - gst_buffer_unref (inbuf); - - if (ret != GST_FLOW_OK) - goto push_failed; - } - - return GST_FLOW_OK; - - /* ERRORS */ -push_failed: - { - GST_DEBUG_OBJECT (ffmpegenc, "Failed to push buffer %d (%s)", ret, - gst_flow_get_name (ret)); - return ret; - } -} - static void -gst_ffmpegenc_flush_buffers (GstFFMpegEnc * ffmpegenc, gboolean send) +gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send) { GstBuffer *outbuf, *inbuf; gint ret_size; @@ -1077,8 +823,8 @@ gst_ffmpegenc_flush_buffers (GstFFMpegEnc * ffmpegenc, gboolean send) if (ret_size < 0) { /* there should be something, notify and give up */ #ifndef GST_DISABLE_GST_DEBUG - GstFFMpegEncClass *oclass = - (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); + GstFFMpegVidEncClass *oclass = + (GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); GST_WARNING_OBJECT (ffmpegenc, "ffenc_%s: failed to flush buffer", oclass->in_plugin->name); #endif /* GST_DISABLE_GST_DEBUG */ @@ -1121,13 +867,13 @@ flush: } static gboolean -gst_ffmpegenc_event_video (GstPad * pad, GstEvent * event) +gst_ffmpegvidenc_event_video (GstPad * pad, GstEvent * event) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad)); + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) (GST_PAD_PARENT (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: - gst_ffmpegenc_flush_buffers (ffmpegenc, TRUE); + gst_ffmpegvidenc_flush_buffers (ffmpegenc, TRUE); break; /* no flushing if flush received, * buffers in encoder are considered (in the) past */ @@ -1148,9 +894,9 @@ gst_ffmpegenc_event_video (GstPad * pad, GstEvent * event) } static gboolean -gst_ffmpegenc_event_src (GstPad * pad, GstEvent * event) +gst_ffmpegvidenc_event_src (GstPad * pad, GstEvent * event) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad)); + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) (GST_PAD_PARENT (pad)); gboolean forward = TRUE; switch (GST_EVENT_TYPE (event)) { @@ -1178,13 +924,13 @@ gst_ffmpegenc_event_src (GstPad * pad, GstEvent * event) } static void -gst_ffmpegenc_set_property (GObject * object, +gst_ffmpegvidenc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstFFMpegEnc *ffmpegenc; + GstFFMpegVidEnc *ffmpegenc; /* Get a pointer of the right type. */ - ffmpegenc = (GstFFMpegEnc *) (object); + ffmpegenc = (GstFFMpegVidEnc *) (object); if (ffmpegenc->opened) { GST_WARNING_OBJECT (ffmpegenc, @@ -1217,13 +963,13 @@ gst_ffmpegenc_set_property (GObject * object, /* The set function is simply the inverse of the get fuction. */ static void -gst_ffmpegenc_get_property (GObject * object, +gst_ffmpegvidenc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstFFMpegEnc *ffmpegenc; + GstFFMpegVidEnc *ffmpegenc; /* It's not null if we got it, but it might not be ours */ - ffmpegenc = (GstFFMpegEnc *) (object); + ffmpegenc = (GstFFMpegVidEnc *) (object); switch (prop_id) { case ARG_BIT_RATE: @@ -1249,9 +995,9 @@ gst_ffmpegenc_get_property (GObject * object, } static GstStateChangeReturn -gst_ffmpegenc_change_state (GstElement * element, GstStateChange transition) +gst_ffmpegvidenc_change_state (GstElement * element, GstStateChange transition) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) element; + GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) element; GstStateChangeReturn result; switch (transition) { @@ -1263,13 +1009,11 @@ gst_ffmpegenc_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_ffmpegenc_flush_buffers (ffmpegenc, FALSE); + gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE); if (ffmpegenc->opened) { gst_ffmpeg_avcodec_close (ffmpegenc->context); ffmpegenc->opened = FALSE; } - gst_adapter_clear (ffmpegenc->adapter); - if (ffmpegenc->file) { fclose (ffmpegenc->file); ffmpegenc->file = NULL; @@ -1286,18 +1030,18 @@ gst_ffmpegenc_change_state (GstElement * element, GstStateChange transition) } gboolean -gst_ffmpegenc_register (GstPlugin * plugin) +gst_ffmpegvidenc_register (GstPlugin * plugin) { GTypeInfo typeinfo = { - sizeof (GstFFMpegEncClass), - (GBaseInitFunc) gst_ffmpegenc_base_init, + sizeof (GstFFMpegVidEncClass), + (GBaseInitFunc) gst_ffmpegvidenc_base_init, NULL, - (GClassInitFunc) gst_ffmpegenc_class_init, + (GClassInitFunc) gst_ffmpegvidenc_class_init, NULL, NULL, - sizeof (GstFFMpegEnc), + sizeof (GstFFMpegVidEnc), 0, - (GInstanceInitFunc) gst_ffmpegenc_init, + (GInstanceInitFunc) gst_ffmpegvidenc_init, }; GType type; AVCodec *in_plugin; @@ -1313,8 +1057,7 @@ gst_ffmpegenc_register (GstPlugin * plugin) gchar *type_name; /* Skip non-AV codecs */ - if (in_plugin->type != AVMEDIA_TYPE_AUDIO && - in_plugin->type != AVMEDIA_TYPE_VIDEO) + if (in_plugin->type != AVMEDIA_TYPE_VIDEO) goto next; /* no quasi codecs, please */ diff --git a/ext/ffmpeg/gstffmpegvidenc.h b/ext/ffmpeg/gstffmpegvidenc.h index c13a0d3..a77d4ca 100644 --- a/ext/ffmpeg/gstffmpegvidenc.h +++ b/ext/ffmpeg/gstffmpegvidenc.h @@ -21,16 +21,14 @@ * object definition and other useful things. */ -#ifndef __GST_FFMPEGENC_H__ -#define __GST_FFMPEGENC_H__ +#ifndef __GST_FFMPEGVIDENC_H__ +#define __GST_FFMPEGVIDENC_H__ G_BEGIN_DECLS -#include +typedef struct _GstFFMpegVidEnc GstFFMpegVidEnc; -typedef struct _GstFFMpegEnc GstFFMpegEnc; - -struct _GstFFMpegEnc +struct _GstFFMpegVidEnc { GstElement element; @@ -41,9 +39,6 @@ struct _GstFFMpegEnc AVCodecContext *context; AVFrame *picture; gboolean opened; - GstClockTime adapter_ts; - guint64 adapter_consumed; - GstAdapter *adapter; gboolean discont; /* cache */ @@ -78,9 +73,9 @@ struct _GstFFMpegEnc gboolean force_keyframe; }; -typedef struct _GstFFMpegEncClass GstFFMpegEncClass; +typedef struct _GstFFMpegVidEncClass GstFFMpegVidEncClass; -struct _GstFFMpegEncClass +struct _GstFFMpegVidEncClass { GstElementClass parent_class; @@ -89,17 +84,17 @@ struct _GstFFMpegEncClass GstCaps *sinkcaps; }; -#define GST_TYPE_FFMPEGENC \ - (gst_ffmpegenc_get_type()) -#define GST_FFMPEGENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGENC,GstFFMpegEnc)) -#define GST_FFMPEGENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGENC,GstFFMpegEncClass)) -#define GST_IS_FFMPEGENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGENC)) -#define GST_IS_FFMPEGENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGENC)) +#define GST_TYPE_FFMPEGVIDENC \ + (gst_ffmpegvidenc_get_type()) +#define GST_FFMPEGVIDENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGVIDENC,GstFFMpegVidEnc)) +#define GST_FFMPEGVIDENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGVIDENC,GstFFMpegVidEncClass)) +#define GST_IS_FFMPEGVIDENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGVIDENC)) +#define GST_IS_FFMPEGVIDENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGVIDENC)) G_END_DECLS -#endif /* __GST_FFMPEGENC_H__ */ +#endif /* __GST_FFMPEGVIDENC_H__ */ -- cgit v1.2.3