gstreamer/gst/flx/gstflxdec.c

1001 lines
28 KiB
C
Raw Normal View History

/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
* Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-flxdec
* @title: flxdec
*
* This element decodes fli/flc/flx-video into raw video
*/
/*
* http://www.coolutils.com/Formats/FLI
* http://woodshole.er.usgs.gov/operations/modeling/flc.html
* http://www.compuphase.com/flic.htm
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "flx_fmt.h"
#include "gstflxdec.h"
#include <gst/video/video.h>
#define JIFFIE (GST_SECOND/70)
ext/flac/gstflacdec.c: Only return true if we actually filled something in. Prevents player applications from showing... Original commit message from CVS: * ext/flac/gstflacdec.c: (gst_flacdec_src_query): Only return true if we actually filled something in. Prevents player applications from showing a random length for flac files. * gst-libs/gst/riff/riff-read.c: (gst_riff_read_class_init), (gst_riff_read_use_event), (gst_riff_read_handle_event), (gst_riff_read_seek), (gst_riff_read_skip), (gst_riff_read_strh), (gst_riff_read_strf_vids_with_data), (gst_riff_read_strf_auds_with_data), (gst_riff_read_strf_iavs): OK, ok, so I implemented event handling. Apparently it's normal that we receive random events at random points without asking for it. * gst/avi/gstavidemux.c: (gst_avi_demux_reset), (gst_avi_demux_src_convert), (gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event), (gst_avi_demux_stream_index), (gst_avi_demux_sync), (gst_avi_demux_stream_scan), (gst_avi_demux_massage_index), (gst_avi_demux_stream_header), (gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data), (gst_avi_demux_loop): * gst/avi/gstavidemux.h: Implement non-lineair chunk handling and subchunk processing. The first solves playback of AVI files where the audio and video data of individual buffers that we read are not synchronized. This should not happen according to the wonderful AVI specs, but of course it does happen in reality. It is also a prerequisite for the second. Subchunk processing allows us to cut chunks in small pieces and process each of these pieces separately. This is required because I've seen several AVI files with incredibly large audio chunks, even some files with only one audio chunk for the whole file. This allows for proper playback including seeking. This patch is supposed to fix all AVI A/V sync issues. * gst/flx/gstflxdec.c: (gst_flxdec_class_init), (flx_decode_chunks), (flx_decode_color), (gst_flxdec_loop): Work. * gst/modplug/gstmodplug.cc: Proper return value setting for the query() function. * gst/playback/gstplaybasebin.c: (setup_source): Being in non-playing state (after, e.g., EOS) is not necessarily a bad thing. Allow for that. This fixes playback of short files. They don't actually playback fully now, because the clock already runs. This means that small files (<500kB) with a small length (<2sec) will still not or barely play. Other files, such as mod or flx, will work correctly, however.
2004-09-29 09:45:40 +00:00
GST_DEBUG_CATEGORY_STATIC (flxdec_debug);
#define GST_CAT_DEFAULT flxdec_debug
/* input */
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-fli")
);
#if G_BYTE_ORDER == G_BIG_ENDIAN
#define RGB_ORDER "xRGB"
#else
#define RGB_ORDER "BGRx"
#endif
/* output */
static GstStaticPadTemplate src_video_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (RGB_ORDER))
);
Fix a bunch of leaks shown by the newly-added states test. Original commit message from CVS: * ext/flac/gstflacenc.c: (gst_flac_enc_finalize): * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_class_init), (gst_gconf_audio_sink_dispose), (gst_gconf_audio_sink_finalize): * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init), (gst_gconf_audio_src_class_init), (gst_gconf_audio_src_dispose), (gst_gconf_audio_src_finalize), (do_toggle_element): * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init), (gst_gconf_video_sink_class_init), (gst_gconf_video_sink_finalize), (do_toggle_element): * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init), (gst_gconf_video_src_class_init), (gst_gconf_video_src_dispose), (gst_gconf_video_src_finalize), (do_toggle_element): * ext/gconf/gstswitchsink.c: (gst_switch_sink_class_init), (gst_switch_sink_reset), (gst_switch_sink_set_child): * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init): * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init): * ext/shout2/gstshout2.c: (gst_shout2send_class_init), (gst_shout2send_init), (gst_shout2send_finalize): * gst/debug/testplugin.c: (gst_test_class_init), (gst_test_finalize): * gst/flx/gstflxdec.c: (gst_flxdec_class_init), (gst_flxdec_dispose): * gst/multipart/multipartmux.c: (gst_multipart_mux_finalize): * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_finalize): * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), (gst_rtspsrc_finalize): * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_free_context): * gst/rtsp/rtspextwms.h: * gst/smpte/gstsmpte.c: (gst_smpte_class_init), (gst_smpte_finalize): * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_finalize): * gst/udp/gstudpsink.c: (gst_udpsink_class_init), (gst_udpsink_finalize): * gst/wavparse/gstwavparse.c: (gst_wavparse_dispose), (gst_wavparse_sink_activate): * sys/oss/gstosssink.c: (gst_oss_sink_finalise): * sys/oss/gstosssrc.c: (gst_oss_src_class_init), (gst_oss_src_finalize): * sys/v4l2/gstv4l2object.c: (gst_v4l2_object_destroy): * sys/v4l2/gstv4l2object.h: * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), (gst_v4l2src_finalize): * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get): Fix a bunch of leaks shown by the newly-added states test.
2007-03-04 13:52:03 +00:00
static void gst_flxdec_dispose (GstFlxDec * flxdec);
2012-04-13 14:54:46 +00:00
static GstFlowReturn gst_flxdec_chain (GstPad * pad, GstObject * parent,
GstBuffer * buf);
static gboolean gst_flxdec_sink_event_handler (GstPad * pad,
GstObject * parent, GstEvent * event);
static GstStateChangeReturn gst_flxdec_change_state (GstElement * element,
GstStateChange transition);
2012-04-13 14:54:46 +00:00
static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
GstQuery * query);
static gboolean flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
GstByteWriter * writer, gint scale);
static gboolean flx_decode_brun (GstFlxDec * flxdec,
GstByteReader * reader, GstByteWriter * writer);
static gboolean flx_decode_delta_fli (GstFlxDec * flxdec,
GstByteReader * reader, GstByteWriter * writer);
static gboolean flx_decode_delta_flc (GstFlxDec * flxdec,
GstByteReader * reader, GstByteWriter * writer);
#define rndalign(off) ((off) + ((off) & 1))
2012-04-13 14:54:46 +00:00
#define gst_flxdec_parent_class parent_class
G_DEFINE_TYPE (GstFlxDec, gst_flxdec, GST_TYPE_ELEMENT);
GST_ELEMENT_REGISTER_DEFINE (flxdec, "flxdec",
GST_RANK_PRIMARY, GST_TYPE_FLXDEC);
static void
gst_flxdec_class_init (GstFlxDecClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent) Original commit message from CVS: * ext/aalib/gstaasink.c: (gst_aasink_class_init): * ext/esd/esdsink.c: (gst_esdsink_class_init): * ext/flac/gstflactag.c: (gst_flac_tag_class_init): * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_class_init): * ext/jpeg/gstjpegenc.c: (gst_jpegenc_class_init): * ext/jpeg/gstsmokedec.c: (gst_smokedec_class_init): * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_class_init): * ext/libcaca/gstcacasink.c: (gst_cacasink_class_init): * ext/libmng/gstmngdec.c: (gst_mngdec_class_init): * ext/libmng/gstmngenc.c: (gst_mngenc_class_init): * ext/libpng/gstpngdec.c: (gst_pngdec_class_init): * ext/libpng/gstpngenc.c: (gst_pngenc_class_init): * ext/mikmod/gstmikmod.c: (gst_mikmod_class_init): * ext/shout2/gstshout2.c: (gst_shout2send_class_init): * ext/speex/gstspeexenc.c: (gst_speexenc_class_init): * gst/alpha/gstalpha.c: (gst_alpha_class_init): * gst/avi/gstavimux.c: (gst_avimux_class_init): * gst/debug/efence.c: (gst_efence_class_init): * gst/debug/negotiation.c: (gst_negotiation_class_init): * gst/flx/gstflxdec.c: (gst_flxdec_class_init): * gst/goom/gstgoom.c: (gst_goom_class_init): * gst/id3demux/gstid3demux.c: (gst_id3demux_class_init): * gst/interleave/deinterleave.c: (deinterleave_class_init): * gst/interleave/interleave.c: (interleave_class_init): * gst/law/alaw-decode.c: (gst_alawdec_class_init): * gst/law/alaw-encode.c: (gst_alawenc_class_init): * gst/law/mulaw-encode.c: (gst_mulawenc_class_init): * gst/median/gstmedian.c: (gst_median_class_init): * gst/monoscope/gstmonoscope.c: (gst_monoscope_class_init): * gst/multipart/multipartmux.c: (gst_multipart_mux_class_init): * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_class_init): * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16depay_class_init): * gst/rtp/gstrtpL16pay.c: (gst_rtpL16pay_class_init): * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_class_init): * gst/rtp/gstrtpamrpay.c: (gst_rtp_amr_pay_class_init): * gst/rtp/gstrtpdepay.c: (gst_rtp_depay_class_init): * gst/rtp/gstrtpgsmdepay.c: (gst_rtp_gsm_depay_class_init): * gst/rtp/gstrtpgsmpay.c: (gst_rtp_gsm_pay_class_init): * gst/rtp/gstrtph263pay.c: (gst_rtp_h263_pay_class_init): * gst/rtp/gstrtph263pdepay.c: (gst_rtp_h263p_depay_class_init): * gst/rtp/gstrtph263ppay.c: (gst_rtp_h263p_pay_class_init): * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_class_init): * gst/rtp/gstrtpmp4vdepay.c: (gst_rtp_mp4v_depay_class_init): * gst/rtp/gstrtpmp4vpay.c: (gst_rtp_mp4v_pay_class_init): * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_class_init): * gst/rtp/gstrtpmpapay.c: (gst_rtp_mpa_pay_class_init): * gst/rtp/gstrtppcmadepay.c: (gst_rtp_pcma_depay_class_init): * gst/rtp/gstrtppcmapay.c: (gst_rtp_pcma_pay_class_init): * gst/rtp/gstrtppcmudepay.c: (gst_rtp_pcmu_depay_class_init): * gst/rtp/gstrtppcmupay.c: (gst_rtp_pcmu_pay_class_init): * gst/rtp/gstrtpspeexdepay.c: (gst_rtp_speex_depay_class_init): * gst/rtp/gstrtpspeexpay.c: (gst_rtp_speex_pay_class_init): * gst/rtsp/gstrtpdec.c: (gst_rtpdec_class_init): * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_class_init): * gst/smpte/gstsmpte.c: (gst_smpte_class_init): * gst/udp/gstdynudpsink.c: (gst_dynudpsink_class_init): * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_class_init): * gst/udp/gstudpsink.c: (gst_udpsink_class_init): * gst/videomixer/videomixer.c: (gst_videomixer_class_init): * gst/wavenc/gstwavenc.c: (gst_wavenc_class_init): * sys/oss/gstossdmabuffer.c: (gst_ossdmabuffer_class_init): * sys/oss/gstosssink.c: (gst_oss_sink_class_init): * sys/osxaudio/gstosxaudioelement.c: (gst_osxaudioelement_class_init): * sys/osxaudio/gstosxaudiosink.c: (gst_osxaudiosink_class_init): * sys/osxaudio/gstosxaudiosrc.c: (gst_osxaudiosrc_class_init): * sys/sunaudio/gstsunaudiosink.c: (gst_sunaudiosink_class_init): Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
2006-04-08 21:21:45 +00:00
parent_class = g_type_class_peek_parent (klass);
Fix a bunch of leaks shown by the newly-added states test. Original commit message from CVS: * ext/flac/gstflacenc.c: (gst_flac_enc_finalize): * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_class_init), (gst_gconf_audio_sink_dispose), (gst_gconf_audio_sink_finalize): * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init), (gst_gconf_audio_src_class_init), (gst_gconf_audio_src_dispose), (gst_gconf_audio_src_finalize), (do_toggle_element): * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init), (gst_gconf_video_sink_class_init), (gst_gconf_video_sink_finalize), (do_toggle_element): * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init), (gst_gconf_video_src_class_init), (gst_gconf_video_src_dispose), (gst_gconf_video_src_finalize), (do_toggle_element): * ext/gconf/gstswitchsink.c: (gst_switch_sink_class_init), (gst_switch_sink_reset), (gst_switch_sink_set_child): * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init): * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init): * ext/shout2/gstshout2.c: (gst_shout2send_class_init), (gst_shout2send_init), (gst_shout2send_finalize): * gst/debug/testplugin.c: (gst_test_class_init), (gst_test_finalize): * gst/flx/gstflxdec.c: (gst_flxdec_class_init), (gst_flxdec_dispose): * gst/multipart/multipartmux.c: (gst_multipart_mux_finalize): * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_finalize): * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), (gst_rtspsrc_finalize): * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_free_context): * gst/rtsp/rtspextwms.h: * gst/smpte/gstsmpte.c: (gst_smpte_class_init), (gst_smpte_finalize): * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_finalize): * gst/udp/gstudpsink.c: (gst_udpsink_class_init), (gst_udpsink_finalize): * gst/wavparse/gstwavparse.c: (gst_wavparse_dispose), (gst_wavparse_sink_activate): * sys/oss/gstosssink.c: (gst_oss_sink_finalise): * sys/oss/gstosssrc.c: (gst_oss_src_class_init), (gst_oss_src_finalize): * sys/v4l2/gstv4l2object.c: (gst_v4l2_object_destroy): * sys/v4l2/gstv4l2object.h: * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), (gst_v4l2src_finalize): * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get): Fix a bunch of leaks shown by the newly-added states test.
2007-03-04 13:52:03 +00:00
gobject_class->dispose = (GObjectFinalizeFunc) gst_flxdec_dispose;
ext/flac/gstflacdec.c: Only return true if we actually filled something in. Prevents player applications from showing... Original commit message from CVS: * ext/flac/gstflacdec.c: (gst_flacdec_src_query): Only return true if we actually filled something in. Prevents player applications from showing a random length for flac files. * gst-libs/gst/riff/riff-read.c: (gst_riff_read_class_init), (gst_riff_read_use_event), (gst_riff_read_handle_event), (gst_riff_read_seek), (gst_riff_read_skip), (gst_riff_read_strh), (gst_riff_read_strf_vids_with_data), (gst_riff_read_strf_auds_with_data), (gst_riff_read_strf_iavs): OK, ok, so I implemented event handling. Apparently it's normal that we receive random events at random points without asking for it. * gst/avi/gstavidemux.c: (gst_avi_demux_reset), (gst_avi_demux_src_convert), (gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event), (gst_avi_demux_stream_index), (gst_avi_demux_sync), (gst_avi_demux_stream_scan), (gst_avi_demux_massage_index), (gst_avi_demux_stream_header), (gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data), (gst_avi_demux_loop): * gst/avi/gstavidemux.h: Implement non-lineair chunk handling and subchunk processing. The first solves playback of AVI files where the audio and video data of individual buffers that we read are not synchronized. This should not happen according to the wonderful AVI specs, but of course it does happen in reality. It is also a prerequisite for the second. Subchunk processing allows us to cut chunks in small pieces and process each of these pieces separately. This is required because I've seen several AVI files with incredibly large audio chunks, even some files with only one audio chunk for the whole file. This allows for proper playback including seeking. This patch is supposed to fix all AVI A/V sync issues. * gst/flx/gstflxdec.c: (gst_flxdec_class_init), (flx_decode_chunks), (flx_decode_color), (gst_flxdec_loop): Work. * gst/modplug/gstmodplug.cc: Proper return value setting for the query() function. * gst/playback/gstplaybasebin.c: (setup_source): Being in non-playing state (after, e.g., EOS) is not necessarily a bad thing. Allow for that. This fixes playback of short files. They don't actually playback fully now, because the clock already runs. This means that small files (<500kB) with a small length (<2sec) will still not or barely play. Other files, such as mod or flx, will work correctly, however.
2004-09-29 09:45:40 +00:00
GST_DEBUG_CATEGORY_INIT (flxdec_debug, "flxdec", 0, "FLX video decoder");
2012-04-13 14:54:46 +00:00
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_flxdec_change_state);
gst_element_class_set_static_metadata (gstelement_class, "FLX video decoder",
"Codec/Decoder/Video",
"FLC/FLI/FLX video decoder",
"Sepp Wijnands <mrrazz@garbage-coderz.net>, Zeeshan Ali <zeenix@gmail.com>");
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_video_factory));
}
static void
gst_flxdec_init (GstFlxDec * flxdec)
{
Fix memleak with gst_static_pad_template_get(). Original commit message from CVS: * ext/cairo/gsttextoverlay.c: (gst_text_overlay_init): * ext/dv/gstdvdemux.c: (gst_dvdemux_init), (gst_dvdemux_add_pads): * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_init): * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_setcaps): * ext/jpeg/gstjpegenc.c: (gst_jpegenc_init): * ext/jpeg/gstsmokedec.c: (gst_smokedec_init): * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_init): * ext/libmng/gstmngdec.c: (gst_mngdec_init), (gst_mngdec_src_getcaps): * ext/libpng/gstpngdec.c: (gst_pngdec_init), (gst_pngdec_caps_create_and_set): * ext/libpng/gstpngenc.c: (gst_pngenc_init): * ext/mikmod/gstmikmod.c: (gst_mikmod_init): * ext/speex/gstspeexdec.c: (gst_speex_dec_init): * gst/alpha/gstalpha.c: (gst_alpha_init): * gst/auparse/gstauparse.c: (gst_au_parse_init): * gst/avi/gstavidemux.c: (gst_avi_demux_init), (gst_avi_demux_handle_src_event), (gst_avi_demux_parse_stream): * gst/cutter/gstcutter.c: (gst_cutter_init): * gst/debug/efence.c: (gst_efence_init), (gst_efence_getrange), (gst_efence_checkgetrange): * gst/debug/negotiation.c: (gst_negotiation_init): * gst/flx/gstflxdec.c: (gst_flxdec_init): * gst/goom/gstgoom.c: (gst_goom_init): * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_init): * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16depay_init): * gst/rtp/gstrtpL16pay.c: (gst_rtpL16pay_init): * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_init): * gst/rtp/gstrtpdepay.c: (gst_rtp_depay_init): * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_init): * gst/rtsp/gstrtpdec.c: (gst_rtpdec_init): * gst/smpte/gstsmpte.c: (gst_smpte_init): * gst/wavparse/gstwavparse.c: (gst_wavparse_init), (gst_wavparse_create_sourcepad): Fix memleak with gst_static_pad_template_get(). This uses gst_pad_new_from_static_template() instead. Fixes #333512
2006-03-15 16:17:12 +00:00
flxdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->sinkpad);
2012-04-13 14:54:46 +00:00
gst_pad_set_chain_function (flxdec->sinkpad,
GST_DEBUG_FUNCPTR (gst_flxdec_chain));
gst_pad_set_event_function (flxdec->sinkpad,
GST_DEBUG_FUNCPTR (gst_flxdec_sink_event_handler));
Fix memleak with gst_static_pad_template_get(). Original commit message from CVS: * ext/cairo/gsttextoverlay.c: (gst_text_overlay_init): * ext/dv/gstdvdemux.c: (gst_dvdemux_init), (gst_dvdemux_add_pads): * ext/gdk_pixbuf/gstgdkpixbuf.c: (gst_gdk_pixbuf_init): * ext/jpeg/gstjpegdec.c: (gst_jpeg_dec_init), (gst_jpeg_dec_setcaps): * ext/jpeg/gstjpegenc.c: (gst_jpegenc_init): * ext/jpeg/gstsmokedec.c: (gst_smokedec_init): * ext/jpeg/gstsmokeenc.c: (gst_smokeenc_init): * ext/libmng/gstmngdec.c: (gst_mngdec_init), (gst_mngdec_src_getcaps): * ext/libpng/gstpngdec.c: (gst_pngdec_init), (gst_pngdec_caps_create_and_set): * ext/libpng/gstpngenc.c: (gst_pngenc_init): * ext/mikmod/gstmikmod.c: (gst_mikmod_init): * ext/speex/gstspeexdec.c: (gst_speex_dec_init): * gst/alpha/gstalpha.c: (gst_alpha_init): * gst/auparse/gstauparse.c: (gst_au_parse_init): * gst/avi/gstavidemux.c: (gst_avi_demux_init), (gst_avi_demux_handle_src_event), (gst_avi_demux_parse_stream): * gst/cutter/gstcutter.c: (gst_cutter_init): * gst/debug/efence.c: (gst_efence_init), (gst_efence_getrange), (gst_efence_checkgetrange): * gst/debug/negotiation.c: (gst_negotiation_init): * gst/flx/gstflxdec.c: (gst_flxdec_init): * gst/goom/gstgoom.c: (gst_goom_init): * gst/rtp/gstasteriskh263.c: (gst_asteriskh263_init): * gst/rtp/gstrtpL16depay.c: (gst_rtp_L16depay_init): * gst/rtp/gstrtpL16pay.c: (gst_rtpL16pay_init): * gst/rtp/gstrtpamrdepay.c: (gst_rtp_amr_depay_init): * gst/rtp/gstrtpdepay.c: (gst_rtp_depay_init): * gst/rtp/gstrtpmpadepay.c: (gst_rtp_mpa_depay_init): * gst/rtsp/gstrtpdec.c: (gst_rtpdec_init): * gst/smpte/gstsmpte.c: (gst_smpte_init): * gst/wavparse/gstwavparse.c: (gst_wavparse_init), (gst_wavparse_create_sourcepad): Fix memleak with gst_static_pad_template_get(). This uses gst_pad_new_from_static_template() instead. Fixes #333512
2006-03-15 16:17:12 +00:00
flxdec->srcpad = gst_pad_new_from_static_template (&src_video_factory, "src");
gst_element_add_pad (GST_ELEMENT (flxdec), flxdec->srcpad);
2012-04-13 14:54:46 +00:00
gst_pad_set_query_function (flxdec->srcpad,
GST_DEBUG_FUNCPTR (gst_flxdec_src_query_handler));
gst_pad_use_fixed_caps (flxdec->srcpad);
flxdec->adapter = gst_adapter_new ();
}
Fix a bunch of leaks shown by the newly-added states test. Original commit message from CVS: * ext/flac/gstflacenc.c: (gst_flac_enc_finalize): * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_class_init), (gst_gconf_audio_sink_dispose), (gst_gconf_audio_sink_finalize): * ext/gconf/gstgconfaudiosrc.c: (gst_gconf_audio_src_base_init), (gst_gconf_audio_src_class_init), (gst_gconf_audio_src_dispose), (gst_gconf_audio_src_finalize), (do_toggle_element): * ext/gconf/gstgconfvideosink.c: (gst_gconf_video_sink_base_init), (gst_gconf_video_sink_class_init), (gst_gconf_video_sink_finalize), (do_toggle_element): * ext/gconf/gstgconfvideosrc.c: (gst_gconf_video_src_base_init), (gst_gconf_video_src_class_init), (gst_gconf_video_src_dispose), (gst_gconf_video_src_finalize), (do_toggle_element): * ext/gconf/gstswitchsink.c: (gst_switch_sink_class_init), (gst_switch_sink_reset), (gst_switch_sink_set_child): * ext/hal/gsthalaudiosink.c: (gst_hal_audio_sink_base_init): * ext/hal/gsthalaudiosrc.c: (gst_hal_audio_src_base_init): * ext/shout2/gstshout2.c: (gst_shout2send_class_init), (gst_shout2send_init), (gst_shout2send_finalize): * gst/debug/testplugin.c: (gst_test_class_init), (gst_test_finalize): * gst/flx/gstflxdec.c: (gst_flxdec_class_init), (gst_flxdec_dispose): * gst/multipart/multipartmux.c: (gst_multipart_mux_finalize): * gst/rtp/gstrtpmp4gpay.c: (gst_rtp_mp4g_pay_finalize): * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), (gst_rtspsrc_finalize): * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_free_context): * gst/rtsp/rtspextwms.h: * gst/smpte/gstsmpte.c: (gst_smpte_class_init), (gst_smpte_finalize): * gst/udp/gstmultiudpsink.c: (gst_multiudpsink_finalize): * gst/udp/gstudpsink.c: (gst_udpsink_class_init), (gst_udpsink_finalize): * gst/wavparse/gstwavparse.c: (gst_wavparse_dispose), (gst_wavparse_sink_activate): * sys/oss/gstosssink.c: (gst_oss_sink_finalise): * sys/oss/gstosssrc.c: (gst_oss_src_class_init), (gst_oss_src_finalize): * sys/v4l2/gstv4l2object.c: (gst_v4l2_object_destroy): * sys/v4l2/gstv4l2object.h: * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), (gst_v4l2src_finalize): * sys/ximage/gstximagesrc.c: (gst_ximage_src_ximage_get): Fix a bunch of leaks shown by the newly-added states test.
2007-03-04 13:52:03 +00:00
static void
gst_flxdec_dispose (GstFlxDec * flxdec)
{
if (flxdec->adapter) {
g_object_unref (flxdec->adapter);
flxdec->adapter = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose ((GObject *) flxdec);
}
static gboolean
2012-04-13 14:54:46 +00:00
gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
GstQuery * query)
{
2012-04-13 14:54:46 +00:00
GstFlxDec *flxdec = (GstFlxDec *) parent;
gboolean ret = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:
{
GstFormat format;
gst_query_parse_duration (query, &format, NULL);
if (format != GST_FORMAT_TIME)
goto done;
gst_query_set_duration (query, format, flxdec->duration);
ret = TRUE;
}
default:
break;
}
done:
2012-04-13 14:54:46 +00:00
if (!ret)
ret = gst_pad_query_default (pad, parent, query);
return ret;
}
static gboolean
gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
GstEvent * event)
{
GstFlxDec *flxdec;
gboolean ret;
flxdec = GST_FLXDEC (parent);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEGMENT:
{
gst_event_copy_segment (event, &flxdec->segment);
if (flxdec->segment.format != GST_FORMAT_TIME) {
GST_DEBUG_OBJECT (flxdec, "generating TIME segment");
gst_segment_init (&flxdec->segment, GST_FORMAT_TIME);
gst_event_unref (event);
event = gst_event_new_segment (&flxdec->segment);
}
if (gst_pad_has_current_caps (flxdec->srcpad)) {
ret = gst_pad_event_default (pad, parent, event);
} else {
flxdec->need_segment = TRUE;
gst_event_unref (event);
ret = TRUE;
}
break;
}
case GST_EVENT_FLUSH_STOP:
gst_segment_init (&flxdec->segment, GST_FORMAT_UNDEFINED);
ret = gst_pad_event_default (pad, parent, event);
break;
default:
ret = gst_pad_event_default (pad, parent, event);
break;
}
return ret;
}
static gboolean
flx_decode_chunks (GstFlxDec * flxdec, gulong n_chunks, GstByteReader * reader,
GstByteWriter * writer)
{
gboolean ret = TRUE;
while (n_chunks--) {
GstByteReader chunk;
guint32 size;
guint16 type;
if (!gst_byte_reader_get_uint32_le (reader, &size))
goto parse_error;
if (!gst_byte_reader_get_uint16_le (reader, &type))
goto parse_error;
GST_LOG_OBJECT (flxdec, "chunk has type 0x%02x size %d", type, size);
if (!gst_byte_reader_get_sub_reader (reader, &chunk,
size - FlxFrameChunkSize)) {
GST_ERROR_OBJECT (flxdec, "Incorrect size in the chunk header");
goto error;
}
switch (type) {
case FLX_COLOR64:
ret = flx_decode_color (flxdec, &chunk, writer, 2);
break;
case FLX_COLOR256:
ret = flx_decode_color (flxdec, &chunk, writer, 0);
break;
case FLX_BRUN:
ret = flx_decode_brun (flxdec, &chunk, writer);
break;
case FLX_LC:
ret = flx_decode_delta_fli (flxdec, &chunk, writer);
break;
case FLX_SS2:
ret = flx_decode_delta_flc (flxdec, &chunk, writer);
break;
case FLX_BLACK:
ret = gst_byte_writer_fill (writer, 0, flxdec->size);
break;
case FLX_MINI:
break;
default:
GST_WARNING ("Unimplemented chunk type: 0x%02x size: %d - skipping",
type, size);
break;
}
if (!ret)
break;
}
return ret;
parse_error:
GST_ERROR_OBJECT (flxdec, "Failed to decode chunk");
error:
return FALSE;
}
static gboolean
flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
GstByteWriter * writer, gint scale)
{
guint8 count, indx;
guint16 packs;
if (!gst_byte_reader_get_uint16_le (reader, &packs))
goto error;
indx = 0;
GST_LOG ("GstFlxDec: cmap packs: %d", (guint) packs);
while (packs--) {
const guint8 *data;
guint16 actual_count;
/* color map index + skip count */
if (!gst_byte_reader_get_uint8 (reader, &indx))
goto error;
/* number of rgb triplets */
if (!gst_byte_reader_get_uint8 (reader, &count))
goto error;
actual_count = count == 0 ? 256 : count;
if (!gst_byte_reader_get_data (reader, count * 3, &data))
goto error;
GST_LOG_OBJECT (flxdec, "cmap count: %d (indx: %d)", actual_count, indx);
flx_set_palette_vector (flxdec->converter, indx, actual_count,
(guchar *) data, scale);
}
return TRUE;
error:
GST_ERROR_OBJECT (flxdec, "Error decoding color palette");
return FALSE;
}
static gboolean
flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader,
GstByteWriter * writer)
{
gulong lines, row;
g_return_val_if_fail (flxdec != NULL, FALSE);
lines = flxdec->hdr.height;
while (lines--) {
/* packet count.
* should not be used anymore, since the flc format can
* contain more then 255 RLE packets. we use the frame
* width instead.
*/
if (!gst_byte_reader_skip (reader, 1))
goto error;
row = flxdec->hdr.width;
while (row) {
gint8 count;
if (!gst_byte_reader_get_int8 (reader, &count))
goto error;
if (count <= 0) {
const guint8 *data;
/* literal run */
count = ABS (count);
GST_LOG_OBJECT (flxdec, "have literal run of size %d", count);
if (count > row) {
GST_ERROR_OBJECT (flxdec, "Invalid BRUN line detected. "
"bytes to write exceeds the end of the row");
return FALSE;
}
row -= count;
if (!gst_byte_reader_get_data (reader, count, &data))
goto error;
if (!gst_byte_writer_put_data (writer, data, count))
goto error;
} else {
guint8 x;
GST_LOG_OBJECT (flxdec, "have replicate run of size %d", count);
if (count > row) {
GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."
"bytes to write exceeds the end of the row");
return FALSE;
}
/* replicate run */
row -= count;
if (!gst_byte_reader_get_uint8 (reader, &x))
goto error;
if (!gst_byte_writer_fill (writer, x, count))
goto error;
}
}
}
return TRUE;
error:
GST_ERROR_OBJECT (flxdec, "Failed to decode BRUN packet");
return FALSE;
}
static gboolean
flx_decode_delta_fli (GstFlxDec * flxdec, GstByteReader * reader,
GstByteWriter * writer)
{
guint16 start_line, lines;
guint line_start_i;
g_return_val_if_fail (flxdec != NULL, FALSE);
g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
/* use last frame for delta */
if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &start_line))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &lines))
goto error;
GST_LOG_OBJECT (flxdec, "height %d start line %d line count %d",
flxdec->hdr.height, start_line, lines);
if (start_line + lines > flxdec->hdr.height) {
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
return FALSE;
}
line_start_i = flxdec->hdr.width * start_line;
if (!gst_byte_writer_set_pos (writer, line_start_i))
goto error;
while (lines--) {
guint8 packets;
/* packet count */
if (!gst_byte_reader_get_uint8 (reader, &packets))
goto error;
GST_LOG_OBJECT (flxdec, "have %d packets", packets);
while (packets--) {
/* skip count */
guint8 skip;
gint8 count;
if (!gst_byte_reader_get_uint8 (reader, &skip))
goto error;
/* skip bytes */
if (!gst_byte_writer_set_pos (writer,
gst_byte_writer_get_pos (writer) + skip))
goto error;
/* RLE count */
if (!gst_byte_reader_get_int8 (reader, &count))
goto error;
if (count < 0) {
guint8 x;
/* literal run */
count = ABS (count);
GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
count, skip);
if (skip + count > flxdec->hdr.width) {
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
"line too long.");
return FALSE;
}
if (!gst_byte_reader_get_uint8 (reader, &x))
goto error;
if (!gst_byte_writer_fill (writer, x, count))
goto error;
} else {
const guint8 *data;
GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
count, skip);
if (skip + count > flxdec->hdr.width) {
GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
"line too long.");
return FALSE;
}
/* replicate run */
if (!gst_byte_reader_get_data (reader, count, &data))
goto error;
if (!gst_byte_writer_put_data (writer, data, count))
goto error;
}
}
line_start_i += flxdec->hdr.width;
if (!gst_byte_writer_set_pos (writer, line_start_i))
goto error;
}
return TRUE;
error:
GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
return FALSE;
}
static gboolean
flx_decode_delta_flc (GstFlxDec * flxdec, GstByteReader * reader,
GstByteWriter * writer)
{
guint16 lines, start_l;
g_return_val_if_fail (flxdec != NULL, FALSE);
g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
/* use last frame for delta */
if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &lines))
goto error;
if (lines > flxdec->hdr.height) {
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
return FALSE;
}
start_l = lines;
while (lines) {
guint16 opcode;
if (!gst_byte_writer_set_pos (writer,
flxdec->hdr.width * (start_l - lines)))
goto error;
/* process opcode(s) */
while (TRUE) {
if (!gst_byte_reader_get_uint16_le (reader, &opcode))
goto error;
if ((opcode & 0xc000) == 0)
break;
if ((opcode & 0xc000) == 0xc000) {
/* line skip count */
gulong skip = (0x10000 - opcode);
if (skip > flxdec->hdr.height) {
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
"skip line count too big.");
return FALSE;
}
start_l += skip;
if (!gst_byte_writer_set_pos (writer,
gst_byte_writer_get_pos (writer) + flxdec->hdr.width * skip))
goto error;
} else {
/* last pixel */
if (!gst_byte_writer_set_pos (writer,
gst_byte_writer_get_pos (writer) + flxdec->hdr.width))
goto error;
if (!gst_byte_writer_put_uint8 (writer, opcode & 0xff))
goto error;
}
}
/* last opcode is the packet count */
GST_LOG_OBJECT (flxdec, "have %d packets", opcode);
while (opcode--) {
/* skip count */
guint8 skip;
gint8 count;
if (!gst_byte_reader_get_uint8 (reader, &skip))
goto error;
if (!gst_byte_writer_set_pos (writer,
gst_byte_writer_get_pos (writer) + skip))
goto error;
/* RLE count */
if (!gst_byte_reader_get_int8 (reader, &count))
goto error;
if (count < 0) {
guint16 x;
/* replicate word run */
count = ABS (count);
GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
count, skip);
if (skip + count > flxdec->hdr.width) {
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
"line too long.");
return FALSE;
}
if (!gst_byte_reader_get_uint16_le (reader, &x))
goto error;
while (count--) {
if (!gst_byte_writer_put_uint16_le (writer, x)) {
goto error;
}
}
} else {
GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
count, skip);
if (skip + count > flxdec->hdr.width) {
GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
"line too long.");
return FALSE;
}
while (count--) {
guint16 x;
if (!gst_byte_reader_get_uint16_le (reader, &x))
goto error;
if (!gst_byte_writer_put_uint16_le (writer, x))
goto error;
}
}
}
lines--;
}
return TRUE;
error:
GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
return FALSE;
}
static gboolean
_read_flx_header (GstFlxDec * flxdec, GstByteReader * reader, FlxHeader * flxh)
{
memset (flxh, 0, sizeof (*flxh));
if (!gst_byte_reader_get_uint32_le (reader, &flxh->size))
goto error;
if (flxh->size < FlxHeaderSize) {
GST_ERROR_OBJECT (flxdec, "Invalid file size in the header");
return FALSE;
}
if (!gst_byte_reader_get_uint16_le (reader, &flxh->type))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->frames))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->width))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->height))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->depth))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->flags))
goto error;
if (!gst_byte_reader_get_uint32_le (reader, &flxh->speed))
goto error;
if (!gst_byte_reader_skip (reader, 2)) /* reserved */
goto error;
/* FLC */
if (!gst_byte_reader_get_uint32_le (reader, &flxh->created))
goto error;
if (!gst_byte_reader_get_uint32_le (reader, &flxh->creator))
goto error;
if (!gst_byte_reader_get_uint32_le (reader, &flxh->updated))
goto error;
if (!gst_byte_reader_get_uint32_le (reader, &flxh->updater))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dx))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dy))
goto error;
/* EGI */
if (!gst_byte_reader_get_uint16_le (reader, &flxh->ext_flags))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->keyframes))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->totalframes))
goto error;
if (!gst_byte_reader_get_uint32_le (reader, &flxh->req_memory))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->max_regions))
goto error;
if (!gst_byte_reader_get_uint16_le (reader, &flxh->transp_num))
goto error;
if (!gst_byte_reader_skip (reader, 24)) /* reserved */
goto error;
/* FLC */
if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe1))
goto error;
if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe2))
goto error;
if (!gst_byte_reader_skip (reader, 40)) /* reserved */
goto error;
return TRUE;
error:
GST_ERROR_OBJECT (flxdec, "Error reading file header");
return FALSE;
}
static GstFlowReturn
2012-04-13 14:54:46 +00:00
gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
GstByteReader reader;
GstBuffer *input;
GstMapInfo map_info;
GstCaps *caps;
guint available;
GstFlowReturn res = GST_FLOW_OK;
GstFlxDec *flxdec;
FlxHeader *flxh;
g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
2012-04-13 14:54:46 +00:00
flxdec = (GstFlxDec *) parent;
g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
gst_adapter_push (flxdec->adapter, buf);
available = gst_adapter_available (flxdec->adapter);
input = gst_adapter_get_buffer (flxdec->adapter, available);
if (!gst_buffer_map (input, &map_info, GST_MAP_READ)) {
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Failed to map buffer"), (NULL));
goto error;
}
gst_byte_reader_init (&reader, map_info.data, map_info.size);
if (flxdec->state == GST_FLXDEC_READ_HEADER) {
if (available >= FlxHeaderSize) {
GstByteReader header;
2012-04-13 14:54:46 +00:00
GstCaps *templ;
if (!gst_byte_reader_get_sub_reader (&reader, &header, FlxHeaderSize)) {
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Could not read header"), (NULL));
goto unmap_input_error;
}
gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
available -= FlxHeaderSize;
if (!_read_flx_header (flxdec, &header, &flxdec->hdr)) {
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Failed to parse header"), (NULL));
goto unmap_input_error;
}
flxh = &flxdec->hdr;
/* check header */
if (flxh->type != FLX_MAGICHDR_FLI &&
flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
("not a flx file (type %x)", flxh->type));
goto unmap_input_error;
}
GST_INFO_OBJECT (flxdec, "size : %d", flxh->size);
GST_INFO_OBJECT (flxdec, "frames : %d", flxh->frames);
GST_INFO_OBJECT (flxdec, "width : %d", flxh->width);
GST_INFO_OBJECT (flxdec, "height : %d", flxh->height);
GST_INFO_OBJECT (flxdec, "depth : %d", flxh->depth);
GST_INFO_OBJECT (flxdec, "speed : %d", flxh->speed);
flxdec->next_time = 0;
if (flxh->type == FLX_MAGICHDR_FLI) {
flxdec->frame_time = JIFFIE * flxh->speed;
} else if (flxh->speed == 0) {
flxdec->frame_time = GST_SECOND / 70;
} else {
flxdec->frame_time = flxh->speed * GST_MSECOND;
}
flxdec->duration = flxh->frames * flxdec->frame_time;
GST_LOG ("duration : %" GST_TIME_FORMAT,
GST_TIME_ARGS (flxdec->duration));
2012-04-13 14:54:46 +00:00
templ = gst_pad_get_pad_template_caps (flxdec->srcpad);
caps = gst_caps_copy (templ);
gst_caps_unref (templ);
gst_caps_set_simple (caps,
"width", G_TYPE_INT, flxh->width,
"height", G_TYPE_INT, flxh->height,
"framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND,
(gint) flxdec->frame_time / 1000, NULL);
gst_pad_set_caps (flxdec->srcpad, caps);
gst_caps_unref (caps);
if (flxdec->need_segment) {
gst_pad_push_event (flxdec->srcpad,
gst_event_new_segment (&flxdec->segment));
flxdec->need_segment = FALSE;
}
/* zero means 8 */
if (flxh->depth == 0)
flxh->depth = 8;
if (flxh->depth != 8) {
GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE,
("%s", "Don't know how to decode non 8 bit depth streams"), (NULL));
goto unmap_input_error;
}
flxdec->converter =
flx_colorspace_converter_new (flxh->width, flxh->height);
if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx : %d", flxh->aspect_dx);
GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy : %d", flxh->aspect_dy);
GST_INFO_OBJECT (flxdec, "(FLC) oframe1 : 0x%08x", flxh->oframe1);
GST_INFO_OBJECT (flxdec, "(FLC) oframe2 : 0x%08x", flxh->oframe2);
}
flxdec->size = ((guint) flxh->width * (guint) flxh->height);
if (flxdec->size >= G_MAXSIZE / 4) {
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Cannot allocate required memory"), (NULL));
goto unmap_input_error;
}
/* create delta and output frame */
flxdec->frame_data = g_malloc0 (flxdec->size);
flxdec->delta_data = g_malloc0 (flxdec->size);
flxdec->state = GST_FLXDEC_PLAYING;
}
} else if (flxdec->state == GST_FLXDEC_PLAYING) {
GstBuffer *out;
/* while we have enough data in the adapter */
while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) {
guint32 size;
guint16 type;
if (!gst_byte_reader_get_uint32_le (&reader, &size))
goto parse_error;
if (available < size)
goto need_more_data;
2012-04-13 14:54:46 +00:00
available -= size;
gst_adapter_flush (flxdec->adapter, size);
if (!gst_byte_reader_get_uint16_le (&reader, &type))
goto parse_error;
switch (type) {
case FLX_FRAME_TYPE:{
GstByteReader chunks;
GstByteWriter writer;
guint16 n_chunks;
GstMapInfo map;
GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type,
size);
if (!gst_byte_reader_get_sub_reader (&reader, &chunks,
size - FlxFrameChunkSize))
goto parse_error;
if (!gst_byte_reader_get_uint16_le (&chunks, &n_chunks))
goto parse_error;
GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks);
if (n_chunks == 0)
break;
if (!gst_byte_reader_skip (&chunks, 8)) /* reserved */
goto parse_error;
gst_byte_writer_init_with_data (&writer, flxdec->frame_data,
flxdec->size, TRUE);
/* decode chunks */
if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer)) {
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Could not decode chunk"), NULL);
goto unmap_input_error;
}
gst_byte_writer_reset (&writer);
/* save copy of the current frame for possible delta. */
2012-04-13 14:54:46 +00:00
memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
out = gst_buffer_new_and_alloc (flxdec->size * 4);
if (!gst_buffer_map (out, &map, GST_MAP_WRITE)) {
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Could not map output buffer"), NULL);
gst_buffer_unref (out);
goto unmap_input_error;
}
/* convert current frame. */
2012-04-13 14:54:46 +00:00
flx_colorspace_convert (flxdec->converter, flxdec->frame_data,
map.data);
gst_buffer_unmap (out, &map);
GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
flxdec->next_time += flxdec->frame_time;
2012-04-13 14:54:46 +00:00
res = gst_pad_push (flxdec->srcpad, out);
break;
}
2013-05-24 17:34:05 +00:00
default:
GST_DEBUG_OBJECT (flxdec, "Unknown frame type 0x%02x, skipping %d",
type, size);
if (!gst_byte_reader_skip (&reader, size - FlxFrameChunkSize))
goto parse_error;
2013-05-24 17:34:05 +00:00
break;
}
}
}
need_more_data:
gst_buffer_unmap (input, &map_info);
gst_buffer_unref (input);
return res;
/* ERRORS */
parse_error:
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Failed to parse stream"), (NULL));
unmap_input_error:
gst_buffer_unmap (input, &map_info);
error:
gst_buffer_unref (input);
return GST_FLOW_ERROR;
}
static GstStateChangeReturn
gst_flxdec_change_state (GstElement * element, GstStateChange transition)
{
GstFlxDec *flxdec;
GstStateChangeReturn ret;
flxdec = GST_FLXDEC (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_adapter_clear (flxdec->adapter);
flxdec->state = GST_FLXDEC_READ_HEADER;
gst_segment_init (&flxdec->segment, GST_FORMAT_UNDEFINED);
flxdec->need_segment = TRUE;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
2012-04-13 14:54:46 +00:00
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
2012-04-13 14:54:46 +00:00
if (flxdec->frame_data) {
g_free (flxdec->frame_data);
flxdec->frame_data = NULL;
}
if (flxdec->delta_data) {
g_free (flxdec->delta_data);
flxdec->delta_data = NULL;
}
2012-04-13 14:54:46 +00:00
if (flxdec->converter) {
flx_colorspace_converter_destroy (flxdec->converter);
flxdec->converter = NULL;
}
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
default:
break;
}
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return GST_ELEMENT_REGISTER (flxdec, plugin);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
flxdec,
"FLC/FLI/FLX video decoder",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)