<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Apr 29, 2014 at 3:15 PM, Felix Abecassis <span dir="ltr"><<a href="mailto:felix.abecassis@gmail.com" target="_blank">felix.abecassis@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
I only have a few style remarks.<br>
<br>
2014-04-29 5:28 GMT+02:00 Vikram Fugro <<a href="mailto:vikram.fugro@gmail.com">vikram.fugro@gmail.com</a>>:<br>
<div><div class="h5">> GStreamer is a cross-platform multimedia processing<br>
> framework for audio/video postprocess/capture/<br>
> encode/decode/render.<br>
><br>
> This module is intended for Audio/Video decoding using<br>
> the available GStreamer plugins present in the system.<br>
> Currently this module supports only video decoding<br>
> and can be extended to audio decoding as well.<br>
> ZeroCopy is currently not supported and must be added.<br>
><br>
> Codecs currently supported are h264, mpeg4, vp8, mpeg2,<br>
> flashvideo, wmv1/2/3, vc1.<br>
><br>
> Signed-off-by: Vikram Fugro <<a href="mailto:vikram.fugro@gmail.com">vikram.fugro@gmail.com</a>><br>
> ---<br>
> NEWS | 1 +<br>
> <a href="http://configure.ac" target="_blank">configure.ac</a> | 20 +<br>
> modules/MODULES_LIST | 1 +<br>
> modules/codec/Makefile.am | 7 +<br>
> modules/codec/gstdecode.c | 881 +++++++++++++++++++++++++++++++++++++++++++++<br>
> po/POTFILES.in | 1 +<br>
> 6 files changed, 911 insertions(+)<br>
> create mode 100644 modules/codec/gstdecode.c<br>
><br>
> diff --git a/NEWS b/NEWS<br>
> index 67f2819..7722152 100644<br>
> --- a/NEWS<br>
> +++ b/NEWS<br>
> @@ -27,6 +27,7 @@ Decoder:<br>
> * New jpeg image decoder<br>
> * Add tx3g subtitles decoder<br>
> * Add Media Foundation Transform decoder<br>
> + * Add decoder module based on GStreamer. Currently supports only video decode.<br>
><br>
> Encoder:<br>
> * Support for MPEG-2 encoding using x262<br>
> diff --git a/<a href="http://configure.ac" target="_blank">configure.ac</a> b/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
> index 2f28385..a9a1626 100644<br>
> --- a/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
> +++ b/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
> @@ -2256,6 +2256,26 @@ PKG_CHECK_EXISTS([libavutil], [<br>
> AC_MSG_RESULT([${avfork}])<br>
><br>
> dnl<br>
> +dnl gstreamer stuff<br>
> +dnl<br>
> +AC_ARG_ENABLE(gst-decode,<br>
> + [ --enable-gst-decode GStreamer based decoding support (currently supports only video decoding) (default auto)])<br>
> +<br>
> +have_gst_decode="no"<br>
> +AS_IF([test "${enable_gst_decode}" != "no"], [<br>
> + PKG_CHECK_MODULES([GST_APP], [gstreamer-app-1.0], [<br>
> + PKG_CHECK_MODULES([GST_VIDEO], [gstreamer-video-1.0], [<br>
> + have_gst_decode="yes"<br>
> + ], [<br>
> + AC_MSG_WARN([${GST_VIDEO_PKG_ERRORS}. GStreamer Decode module will not be built.])<br>
> + ])<br>
> + ], [<br>
> + AC_MSG_WARN([${GST_APP_PKG_ERRORS}. GStreamer modules will not be built.])<br>
> + ])<br>
> +])<br>
> +AM_CONDITIONAL([HAVE_GST_DECODE], [test "${have_gst_decode}" = "yes"])<br>
> +<br>
> +dnl<br>
> dnl avcodec decoder/encoder plugin<br>
> dnl<br>
> AC_ARG_ENABLE(avcodec,<br>
> diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST<br>
> index effd694..a307635 100644<br>
> --- a/modules/MODULES_LIST<br>
> +++ b/modules/MODULES_LIST<br>
> @@ -151,6 +151,7 @@ $Id$<br>
> * grain: Grain Video filter<br>
> * grey_yuv: grayscale to others conversion module<br>
> * growl: announce currently playing stream to growl<br>
> + * gstdecode: GStreamer based decoder module.<br>
> * h264: H264 decoder<br>
> * headphone_channel_mixer: headphone channel mixer with virtual spatialization effect<br>
> * hevc: HEVC demuxer<br>
> diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am<br>
> index 14500c6..d6027fb 100644<br>
> --- a/modules/codec/Makefile.am<br>
> +++ b/modules/codec/Makefile.am<br>
> @@ -470,3 +470,10 @@ libquicktime_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'<br>
> libquicktime_plugin_la_LIBADD = $(LIBM)<br>
> EXTRA_LTLIBRARIES += <a href="http://libquicktime_plugin.la" target="_blank">libquicktime_plugin.la</a><br>
> codec_LTLIBRARIES += $(LTLIBquicktime)<br>
> +<br>
> +libgstdecode_plugin_la_SOURCES = codec/gstdecode.c<br>
> +libgstdecode_plugin_la_CFLAGS = $(AM_CFLAGS) $(GST_VIDEO_CFLAGS) $(GST_APP_CFLAGS)<br>
> +libgstdecode_plugin_la_LIBADD = $(GST_VIDEO_LIBS) $(GST_APP_LIBS)<br>
> +if HAVE_GST_DECODE<br>
> +codec_LTLIBRARIES += <a href="http://libgstdecode_plugin.la" target="_blank">libgstdecode_plugin.la</a><br>
> +endif<br>
> diff --git a/modules/codec/gstdecode.c b/modules/codec/gstdecode.c<br>
> new file mode 100644<br>
> index 0000000..555475b<br>
> --- /dev/null<br>
> +++ b/modules/codec/gstdecode.c<br>
> @@ -0,0 +1,881 @@<br>
> +/*****************************************************************************<br>
> + * gstdecode.c: Decoder module making use of gstreamer<br>
> + *****************************************************************************<br>
> + * Copyright (C) 2014 VLC authors and VideoLAN<br>
> + * $Id:<br>
> + *<br>
> + * Author: Vikram Fugro <<a href="mailto:vikram.fugro@gmail.com">vikram.fugro@gmail.com</a>><br>
> + *<br>
> + * This library is free software; you can redistribute it and/or<br>
> + * modify it under the terms of the GNU Library General Public<br>
> + * License as published by the Free Software Foundation; either<br>
> + * version 2.1 of the License, or (at your option) any later version.<br>
> + *<br>
> + * This library is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU<br>
> + * Lesser General Public License for more details.<br>
> + *<br>
> + * You should have received a copy of the GNU Library General Public<br>
> + * License along with this library; if not, write to the Free Software<br>
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA <a href="tel:02110-1301" value="+35821101301">02110-1301</a> USA<br>
> + *****************************************************************************/<br>
> +<br>
> +/*****************************************************************************<br>
> + * Preamble<br>
> + *****************************************************************************/<br>
> +#ifdef HAVE_CONFIG_H<br>
> +# include "config.h"<br>
> +#endif<br>
> +<br>
> +#include <vlc_common.h><br>
> +#include <vlc_plugin.h><br>
> +#include <vlc_codec.h><br>
> +#include <vlc_input.h><br>
> +<br>
> +#include <assert.h><br>
> +#include <limits.h><br>
> +<br>
> +#include <gst/gst.h><br>
> +#include <gst/video/video.h><br>
> +#include <gst/video/gstvideometa.h><br>
> +#include <gst/app/gstappsrc.h><br>
> +#include <gst/gstatomicqueue.h><br>
> +<br>
> +struct decoder_sys_t<br>
> +{<br>
> + GstElement* p_decoder;<br>
> + GstElement* p_decode_src;<br>
> + GstElement* p_decode_in;<br>
> + GstElement* p_decode_out;<br>
> +<br>
> + GstBus* p_bus;<br>
> +<br>
> + GstVideoInfo vinfo;<br>
> + GstAtomicQueue *p_que;<br>
</div></div>Your file is inconsistent regarding type declaration, you use both:<br>
type *var;<br>
and<br>
type* var;<br>
Same remark for casts.<br></blockquote><div style> Vikram: Yeah, will fix that. I am sorry, I normally tend to be inconsistent with that.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> + bool b_prerolled;<br>
> + bool b_running;<br>
> +};<br>
> +<br>
> +typedef struct<br>
> +{<br>
> + GstCaps* p_sinkcaps;<br>
> + GstCaps* p_srccaps;<br>
> +} sink_src_caps_t;<br>
> +<br>
> +/*****************************************************************************<br>
> + * Local prototypes<br>
> + *****************************************************************************/<br>
> +static int OpenDecoder( vlc_object_t * );<br>
> +static void CloseDecoder( vlc_object_t * );<br>
> +static picture_t *DecodeBlock( decoder_t *, block_t ** );<br>
> +<br>
> +#define MODULE_DESCRIPTION N_( "Uses GStreamer framework's plugins " \<br>
> + "to decode the media codecs " )<br>
> +<br>
> +#define USEDECODEBIN_TEXT N_("Use DecodeBin")<br>
> +#define USEDECODEBIN_LONGTEXT N_( \<br>
> + "DecodeBin is a container element, that can add and " \<br>
> + "manage multiple elements. Apart from adding the decoders, " \<br>
> + "decodebin also adds elementary stream parsers which can provide " \<br>
> + "more info such codec profile, level and other attributes, " \<br>
</div></div>Such "as"?<br></blockquote><div style> Vikram: OK. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class=""><br>
> + "in the form of GstCaps (Stream Capabilities) to decoder. " )<br>
> +<br>
> +vlc_module_begin ()<br>
> + set_shortname( "GstDecode")<br>
</div>Space missing.<br></blockquote><div style> Vikram: OK, My coding style is normally func (int a, int b) .... getting used to VLC coding style :-)</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class=""><br>
> + add_shortcut( "gstdecode" )<br>
> + set_category( CAT_INPUT )<br>
> + set_subcategory( SUBCAT_INPUT_VCODEC )<br>
> + /* decoder main module */<br>
> + set_description( N_( "GStreamer Based Decoder" ) )<br>
> + set_help( MODULE_DESCRIPTION )<br>
> + set_capability( "decoder", 50 )<br>
> + set_section( N_( "Decoding" ) , NULL )<br>
> + set_callbacks( OpenDecoder, CloseDecoder )<br>
> + add_bool( "use-decodebin", false, USEDECODEBIN_TEXT,<br>
> + USEDECODEBIN_LONGTEXT, false)<br>
</div>Space missing.<br>
<div><div class="h5"><br>
> +vlc_module_end ()<br>
> +<br>
> +/* gst_init() is not thread-safe, hence a thread-safe wrapper */<br>
> +static void vlc_gst_init( void )<br>
> +{<br>
> + static vlc_mutex_t init_lock = VLC_STATIC_MUTEX;<br>
> +<br>
> + vlc_mutex_lock( &init_lock );<br>
> + gst_init( NULL, NULL );<br>
> + vlc_mutex_unlock( &init_lock );<br>
> +}<br>
> +<br>
> +static GstStructure* vlc_to_gst_fmt( const es_format_t* p_fmt )<br>
> +{<br>
> + const video_format_t* p_vfmt = &p_fmt->video;<br>
> + GstStructure* p_str = NULL;<br>
> +<br>
> + switch( p_fmt->i_codec ){<br>
> + case VLC_CODEC_H264:<br>
> + p_str = gst_structure_new_empty( "video/x-h264" );<br>
> + gst_structure_set( p_str, "alignment", G_TYPE_STRING, "au", NULL );<br>
> + break;<br>
> + case VLC_CODEC_MP4V:<br>
> + p_str = gst_structure_new_empty( "video/mpeg" );<br>
> + gst_structure_set( p_str, "mpegversion", G_TYPE_INT, 4,<br>
> + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL );<br>
> + break;<br>
> + case VLC_CODEC_VP8:<br>
> + p_str = gst_structure_new_empty( "video/x-vp8" );<br>
> + break;<br>
> + case VLC_CODEC_MPGV:<br>
> + p_str = gst_structure_new_empty( "video/mpeg" );<br>
> + gst_structure_set( p_str, "mpegversion", G_TYPE_INT, 2,<br>
> + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL );<br>
> + break;<br>
> + case VLC_CODEC_FLV1:<br>
> + p_str = gst_structure_new_empty( "video/x-flash-video" );<br>
> + gst_structure_set( p_str, "flvversion", G_TYPE_INT, 1, NULL );<br>
> + break;<br>
> + case VLC_CODEC_WMV1:<br>
> + p_str = gst_structure_new_empty( "video/x-wmv" );<br>
> + gst_structure_set( p_str, "wmvversion", G_TYPE_INT, 1,<br>
> + "format", G_TYPE_STRING, "WMV1", NULL );<br>
> + break;<br>
> + case VLC_CODEC_WMV2:<br>
> + p_str = gst_structure_new_empty( "video/x-wmv" );<br>
> + gst_structure_set( p_str, "wmvversion", G_TYPE_INT, 2,<br>
> + "format", G_TYPE_STRING, "WMV2", NULL );<br>
> + break;<br>
> + case VLC_CODEC_WMV3:<br>
> + p_str = gst_structure_new_empty( "video/x-wmv" );<br>
> + gst_structure_set( p_str, "wmvversion", G_TYPE_INT, 3,<br>
> + "format", G_TYPE_STRING, "WMV3", NULL );<br>
> + break;<br>
> + case VLC_CODEC_VC1:<br>
> + p_str = gst_structure_new_empty( "video/x-wmv" );<br>
> + gst_structure_set( p_str, "wmvversion", G_TYPE_INT, 3,<br>
> + "format", G_TYPE_STRING, "WVC1", NULL );<br>
> + break;<br>
> + default:<br>
> + /* unsupported codec */<br>
> + goto done;<br>
> + }<br>
</div></div>I'm not sure, what happen afterwards if type not found?<br></blockquote><div style> Vikram: Nothing, VLC will not use this module :-) </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +<br>
> + if( p_vfmt->i_width && p_vfmt->i_height )<br>
> + gst_structure_set( p_str,<br>
> + "width", G_TYPE_INT, p_vfmt->i_width,<br>
> + "height", G_TYPE_INT, p_vfmt->i_height, NULL );<br>
> +<br>
> + if( p_vfmt->i_frame_rate && p_vfmt->i_frame_rate_base )<br>
> + gst_structure_set( p_str, "framerate", GST_TYPE_FRACTION,<br>
> + p_vfmt->i_frame_rate,<br>
> + p_vfmt->i_frame_rate_base, NULL );<br>
> +<br>
> + if( p_vfmt->i_sar_num && p_vfmt->i_sar_den )<br>
> + gst_structure_set( p_str, "pixel-aspect-ratio", GST_TYPE_FRACTION,<br>
> + p_vfmt->i_sar_num,<br>
> + p_vfmt->i_sar_den, NULL );<br>
> +<br>
> + if( p_fmt->i_extra )<br>
> + {<br>
> + GstBuffer* p_buf;<br>
> +<br>
> + p_buf = gst_buffer_new_wrapped_full( GST_MEMORY_FLAG_READONLY,<br>
> + p_fmt->p_extra, p_fmt->i_extra, 0,<br>
> + p_fmt->i_extra, NULL, NULL );<br>
> + if( p_buf == NULL )<br>
> + {<br>
> + gst_structure_free( p_str );<br>
> + p_str = NULL;<br>
> + goto done;<br>
> + }<br>
> +<br>
> + gst_structure_set( p_str, "codec_data", GST_TYPE_BUFFER, p_buf, NULL );<br>
> + gst_buffer_unref( p_buf );<br>
> + }<br>
> +<br>
> +done:<br>
> + return p_str;<br>
> +}<br>
> +<br>
> +/* Emitted by appsrc when serving a seek request.<br>
> + * Seek over here is only used for flushing the buffers.<br>
> + * Returns TRUE always, as the 'real' seek will be<br>
> + * done by VLC framework */<br>
> +static gboolean seek_data_cb( GstAppSrc* p_src, guint64 l_offset,<br>
> + gpointer p_data )<br>
> +{<br>
> + decoder_t* p_dec = ( decoder_t* )p_data;<br>
> + msg_Dbg( p_dec, "appsrc seeking to %"G_GUINT64_FORMAT, l_offset );<br>
> + return TRUE;<br>
> +}<br>
> +<br>
> +/* Emitted by decodebin when there are no more<br>
> + * outputs. In this case it will mostly and<br>
> + * should be one */<br>
</div></div>Sorry but I don't understand the second sentence.<br></blockquote><div style> Vikram: OK, I meant 'It cannot be more than one", will re-factor that explanation.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +static void no_more_pads_cb( GstElement* p_ele, gpointer p_data )<br>
> +{<br>
> + decoder_t* p_dec = ( decoder_t* )p_data;<br>
> + decoder_sys_t* p_sys = p_dec->p_sys;<br>
> + GstPad* p_pad;<br>
> +<br>
> + msg_Dbg( p_dec, "no more pads" );<br>
> +<br>
> + p_pad = gst_element_get_static_pad( p_sys->p_decode_out,<br>
> + "sink" );<br>
> + if( !gst_pad_is_linked( p_pad ) )<br>
> + {<br>
> + msg_Err( p_dec, "failed to link decode out pad" );<br>
> + GST_ELEMENT_ERROR (p_sys->p_decoder, STREAM, FAILED,<br>
> + ("vlc stream error"), NULL);<br>
> + }<br>
> +<br>
> + gst_object_unref( p_pad );<br>
> +}<br>
> +<br>
> +/* Sets the video output format */<br>
> +static void set_vout_format( GstStructure* p_str,<br>
> + const es_format_t* p_infmt, es_format_t* p_outfmt )<br>
> +{<br>
> + video_format_t *p_voutfmt = &p_outfmt->video;<br>
> + const video_format_t *p_vinfmt = &p_infmt->video;<br>
> + gboolean b_ret;<br>
> +<br>
> + /* We are interested in sytem memory raw buffers for now,<br>
> + * but support for opaque data formats can also be added.<br>
> + * For eg. when using HW decoders for zero-copy */<br>
> + p_outfmt->i_codec = vlc_fourcc_GetCodecFromString(<br>
> + VIDEO_ES,<br>
> + gst_structure_get_string ( p_str, "format" ) );<br>
> +<br>
> + if( !p_outfmt->i_codec )<br>
> + return;<br>
> +<br>
> + gst_structure_get_int( p_str, "width", &p_voutfmt->i_width );<br>
> + gst_structure_get_int( p_str, "height", &p_voutfmt->i_height );<br>
> +<br>
> + b_ret = gst_structure_get_fraction( p_str,<br>
> + "pixel-aspect-ratio",<br>
> + &p_voutfmt->i_sar_num,<br>
> + &p_voutfmt->i_sar_den );<br>
> +<br>
> + if( !b_ret || !p_voutfmt->i_sar_num ||<br>
> + !p_voutfmt->i_sar_den )<br>
> + {<br>
> + p_voutfmt->i_sar_num = 1;<br>
> + p_voutfmt->i_sar_den = 1;<br>
> + }<br>
> +<br>
> + b_ret = gst_structure_get_fraction ( p_str, "framerate",<br>
> + &p_voutfmt->i_frame_rate,<br>
> + &p_voutfmt->i_frame_rate_base );<br>
> +<br>
> + if( !b_ret || !p_voutfmt->i_frame_rate ||<br>
> + !p_voutfmt->i_frame_rate_base )<br>
> + {<br>
> + p_voutfmt->i_frame_rate = p_vinfmt->i_frame_rate;<br>
> + p_voutfmt->i_frame_rate_base = p_vinfmt->i_frame_rate_base;<br>
> + }<br>
> +}<br>
> +<br>
> +static bool set_out_fmt( decoder_t* p_dec, GstPad* p_pad )<br>
> +{<br>
> + GstCaps* p_caps = gst_pad_get_current_caps( p_pad );<br>
> + decoder_sys_t* p_sys = p_dec->p_sys;<br>
> + GstStructure* p_str;<br>
> +<br>
> + if( !gst_video_info_from_caps( &p_sys->vinfo,<br>
> + p_caps ) )<br>
> + {<br>
> + msg_Err( p_dec, "failed to get video info from caps" );<br>
> + gst_caps_unref( p_caps );<br>
> + GST_ELEMENT_ERROR (p_sys->p_decoder, STREAM, FAILED,<br>
> + ("vlc stream error"), NULL);<br>
</div></div>Change of coding style? Other occurences below.</blockquote><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="">
> + return false;<br>
> + }<br>
> +<br>
> + p_str = gst_caps_get_structure( p_caps, 0 );<br>
> + set_vout_format( p_str, &p_dec->fmt_in, &p_dec->fmt_out );<br>
> +<br>
> + if( p_dec->fmt_out.i_codec == 0 )<br>
> + {<br>
> + msg_Err( p_dec, "failed to set out format" );<br>
> + gst_caps_unref( p_caps );<br>
> + GST_ELEMENT_ERROR (p_sys->p_decoder, STREAM, FAILED,<br>
> + ("vlc stream error"), NULL);<br>
> + return false;<br>
> + }<br>
> +<br>
> + gst_caps_unref( p_caps );<br>
> + return true;<br>
> +}<br>
> +<br>
> +/* Emitted by decodebin and links decodebin to fakesink.<br>
> + * Since only one elementary codec stream is fed to decodebin,<br>
> + * this signal can be emitted atmost only once */<br>
</div>"at most"<br></blockquote><div style> Vikram: OK </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +static void pad_added_cb( GstElement* p_ele, GstPad* p_pad, gpointer p_data )<br>
> +{<br>
> + decoder_t* p_dec = ( decoder_t* )p_data;<br>
> + decoder_sys_t* p_sys = p_dec->p_sys;<br>
> +<br>
> + if( likely( gst_pad_has_current_caps( p_pad ) ) )<br>
> + {<br>
> + GstPad* p_sinkpad;<br>
> +<br>
> + if( !set_out_fmt( p_dec, p_pad ) )<br>
> + return;<br>
> +<br>
> + p_sinkpad = gst_element_get_static_pad(<br>
> + p_sys->p_decode_out, "sink" );<br>
> + gst_pad_link( p_pad, p_sinkpad );<br>
> + gst_object_unref( p_sinkpad );<br>
> + }<br>
> + else<br>
> + {<br>
> + msg_Err( p_dec, "decodebin src pad has no caps");<br>
> + GST_ELEMENT_ERROR (p_sys->p_decoder, STREAM, FAILED,<br>
> + ("vlc stream error"), NULL);<br>
> + }<br>
> +}<br>
> +<br>
> +/* Emitted by fakesink for every buffer and sets the<br>
> + * output format in VLC context for out for the first<br>
> + * buffer. Adds the buffer to the queue */<br>
> +static void frame_handoff_cb( GstElement* p_ele, GstBuffer* p_buf,<br>
> + GstPad* p_pad, gpointer p_data )<br>
> +{<br>
> + decoder_t* p_dec = ( decoder_t* )p_data;<br>
> + decoder_sys_t* p_sys = p_dec->p_sys;<br>
> +<br>
> + if( unlikely( p_dec->fmt_out.i_codec == 0 ) )<br>
> + {<br>
> + if( !gst_pad_has_current_caps( p_pad ) )<br>
> + {<br>
> + msg_Err( p_dec, "fakesink pad has no caps");<br>
> + GST_ELEMENT_ERROR (p_sys->p_decoder, STREAM, FAILED,<br>
> + ("vlc stream error"), NULL);<br>
> + return;<br>
> + }<br>
> +<br>
> + if( !set_out_fmt( p_dec, p_pad ) )<br>
> + return;<br>
> + }<br>
> +<br>
> + /* Push the buffer to the queue */<br>
> + gst_atomic_queue_push( p_sys->p_que, gst_buffer_ref( p_buf ) );<br>
> +}<br>
> +<br>
> +/* Copy the frame data from the GstBuffer (from decoder)<br>
> + * to the picture obtained from downstream in VLC.<br>
> + * TODO(Zero-Copy): This function should be avoided as much<br>
> + * as possible, since it involves a complete frame copy. */<br>
> +static void gst_CopyPicture( picture_t *p_pic, GstVideoFrame *frame )<br>
> +{<br>
> + int i_plane, i_planes, i_line, i_dst_stride, i_src_stride;<br>
> + uint8_t *p_dst, *p_src;<br>
> + int i_w, i_h;<br>
> +<br>
> + i_planes = p_pic->i_planes;<br>
> + for( i_plane = 0; i_plane < i_planes; i_plane++ )<br>
> + {<br>
> + p_dst = p_pic->p[i_plane].p_pixels;<br>
> + p_src = GST_VIDEO_FRAME_PLANE_DATA( frame, i_plane );<br>
> + i_dst_stride = p_pic->p[i_plane].i_pitch;<br>
> + i_src_stride = GST_VIDEO_FRAME_PLANE_STRIDE( frame, i_plane );<br>
> +<br>
> + i_w = GST_VIDEO_FRAME_COMP_WIDTH( frame,<br>
> + i_plane ) * GST_VIDEO_FRAME_COMP_PSTRIDE( frame, i_plane );<br>
> + i_h = GST_VIDEO_FRAME_COMP_HEIGHT( frame, i_plane );<br>
> +<br>
> + for( i_line = 0;<br>
> + i_line < __MIN( p_pic->p[i_plane].i_lines, i_h );<br>
> + i_line++ )<br>
> + {<br>
> + memcpy( p_dst, p_src, i_w );<br>
> + p_src += i_src_stride;<br>
> + p_dst += i_dst_stride;<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +/* Check if the element can use this caps */<br>
> +static gint find_decoder_func( gconstpointer p_p1, gconstpointer p_p2 )<br>
> +{<br>
> + GstElementFactory *p_factory;<br>
> + sink_src_caps_t* p_caps;<br>
> +<br>
> + p_factory = ( GstElementFactory* )p_p1;<br>
> + p_caps = ( sink_src_caps_t* )p_p2;<br>
> +<br>
> + return( !(gst_element_factory_can_sink_any_caps( p_factory,<br>
> + p_caps->p_sinkcaps ) &&<br>
> + gst_element_factory_can_src_any_caps( p_factory,<br>
> + p_caps->p_srccaps ) ) );<br>
> +}<br>
</div></div>Why parentheses for return suddenly?<br></blockquote><div style> Vikram: OK, will remove them. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +<br>
> +static bool default_msg_handler( decoder_t* p_dec, GstMessage* p_msg )<br>
> +{<br>
> + bool err = false;<br>
> +<br>
> + switch( GST_MESSAGE_TYPE( p_msg ) ){<br>
> + case GST_MESSAGE_ERROR:<br>
> + {<br>
> + gchar *psz_debug;<br>
> + GError *p_error;<br>
> +<br>
> + gst_message_parse_error ( p_msg, &p_error, &psz_debug );<br>
> + g_free( psz_debug );<br>
> +<br>
> + msg_Err( p_dec, "Error from %s: %s",<br>
> + GST_ELEMENT_NAME( GST_MESSAGE_SRC( p_msg ) ),<br>
> + p_error->message );<br>
> + g_error_free( p_error );<br>
> + err = true;<br>
> + }<br>
> + break;<br>
> + case GST_MESSAGE_WARNING:<br>
> + {<br>
> + gchar *psz_debug;<br>
> + GError *p_error;<br>
> +<br>
> + gst_message_parse_warning ( p_msg, &p_error, &psz_debug );<br>
> + g_free( psz_debug );<br>
> +<br>
> + msg_Warn( p_dec, "Warning from %s: %s",<br>
> + GST_ELEMENT_NAME( GST_MESSAGE_SRC( p_msg ) ),<br>
> + p_error->message );<br>
> + g_error_free( p_error );<br>
> + }<br>
> + break;<br>
> + case GST_MESSAGE_INFO:<br>
> + {<br>
> + gchar *psz_debug;<br>
> + GError *p_error;<br>
> +<br>
> + gst_message_parse_info ( p_msg, &p_error, &psz_debug );<br>
> + g_free( psz_debug );<br>
> +<br>
> + msg_Info( p_dec, "Info from %s: %s",<br>
> + GST_ELEMENT_NAME( GST_MESSAGE_SRC( p_msg ) ),<br>
> + p_error->message );<br>
> + g_error_free( p_error );<br>
> + }<br>
> + break;<br>
> + default:<br>
> + break;<br>
> + }<br>
> +<br>
> + return err;<br>
> +}<br>
> +<br>
> +/*****************************************************************************<br>
> + * OpenDecoder: probe the decoder and return score<br>
> + *****************************************************************************/<br>
> +static int OpenDecoder( vlc_object_t *p_this )<br>
> +{<br>
> + decoder_t *p_dec = ( decoder_t* )p_this;<br>
> + decoder_sys_t *p_sys;<br>
> + GstStateChangeReturn i_ret;<br>
> + gboolean b_ret;<br>
> + sink_src_caps_t caps = { NULL, NULL };<br>
> + GstStructure* p_str;<br>
> + GstAppSrcCallbacks cb;<br>
> + int i_rval = VLC_SUCCESS;<br>
> + GList* p_list;<br>
> + bool dbin;<br>
> +<br>
> +#define VLC_GST_CHECK(r, v, s, t) \<br>
> + { if(r == v) { msg_Err(p_dec, s); i_rval = t; goto fail; } }<br>
> +<br>
> + vlc_gst_init ( );<br>
</div></div>Space before "(" ?<br>
<div class=""><br>
> +<br>
> + p_str = vlc_to_gst_fmt( &p_dec->fmt_in );<br>
> + if( !p_str ) {<br>
</div>Brace at end of line here, most of the "ifs" seems to have the brace<br>
on its own line.<br></blockquote><div style> Vikram: OK, same as I said earlier, I normally code </div><div style> if (blah) {</div><div style> } else {</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"> }<br></div></div></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
> + return VLC_EGENERIC;<br>
> + }<br>
> +<br>
> + /* Allocate the memory needed to store the decoder's structure */<br>
> + if( ( p_dec->p_sys = p_sys = calloc( 1, sizeof( *p_sys ) ) ) == NULL )<br>
> + {<br>
> + gst_structure_free( p_str );<br>
> + return VLC_ENOMEM;<br>
> + }<br>
> +<br>
> + dbin = var_CreateGetBool( p_dec, "use-decodebin" );<br>
> + msg_Dbg( p_dec, "Using decodebin? %s", dbin ? "yes ":"no" );<br>
> +<br>
> + caps.p_sinkcaps = gst_caps_new_empty( );<br>
> + gst_caps_append_structure( caps.p_sinkcaps, p_str );<br>
> + /* Currently supports only system memory raw output format */<br>
> + caps.p_srccaps = gst_caps_new_empty_simple( "video/x-raw" );<br>
> +<br>
> + /* Get the list of all the available gstreamer decoders */<br>
> + p_list = gst_element_factory_list_get_elements(<br>
> + GST_ELEMENT_FACTORY_TYPE_DECODER, GST_RANK_MARGINAL );<br>
> + VLC_GST_CHECK( p_list, NULL, "no decoder list found", VLC_ENOMOD );<br>
> + if( !dbin )<br>
> + {<br>
> + GList* p_l;<br>
> + /* Sort them as per ranks */<br>
> + p_list = g_list_sort( p_list, gst_plugin_feature_rank_compare_func );<br>
> + VLC_GST_CHECK( p_list, NULL, "failed to sort decoders list",<br>
> + VLC_ENOMOD );<br>
> + p_l = g_list_find_custom( p_list, &caps, find_decoder_func );<br>
> + VLC_GST_CHECK( p_l, NULL, "no suitable decoder found",<br>
> + VLC_ENOMOD );<br>
> + /* create the decoder with highest rank */<br>
> + p_sys->p_decode_in = gst_element_factory_create(<br>
> + (GstElementFactory*)p_l->data, NULL );<br>
> + VLC_GST_CHECK( p_sys->p_decode_in, NULL,<br>
> + "failed to create decoder", VLC_ENOMOD );<br>
> + }<br>
> + else<br>
> + {<br>
> + GList* p_l;<br>
> + /* Just check if any suitable decoder exists, rest will be<br>
> + * handled by decodebin */<br>
> + p_l = g_list_find_custom( p_list, &caps, find_decoder_func );<br>
> + VLC_GST_CHECK( p_l, NULL, "no suitable decoder found",<br>
> + VLC_ENOMOD );<br>
> + }<br>
> + gst_plugin_feature_list_free( p_list );<br>
> + p_list = NULL;<br>
> + gst_caps_unref( caps.p_srccaps );<br>
> + caps.p_srccaps = NULL;<br>
> +<br>
> + p_sys->b_prerolled = false;<br>
> + p_sys->b_running = false;<br>
> +<br>
> + /* Queue: GStreamer thread will dump buffers into this queue,<br>
> + * DecodeBlock() will pop out the buffers from the queue */<br>
> + p_sys->p_que = gst_atomic_queue_new( 0 );<br>
> + VLC_GST_CHECK ( p_sys->p_que, NULL, "failed to create queue",<br>
> + VLC_ENOMEM );<br>
> +<br>
> + p_sys->p_decode_src = gst_element_factory_make( "appsrc", NULL );<br>
> + VLC_GST_CHECK( p_sys->p_decode_src, NULL, "appsrc not found",<br>
> + VLC_ENOMOD );<br>
> + g_object_set( G_OBJECT( p_sys->p_decode_src ), "caps", caps.p_sinkcaps,<br>
> + "block", FALSE, "emit-signals", TRUE, "format", GST_FORMAT_BYTES,<br>
> + "stream-type", GST_APP_STREAM_TYPE_SEEKABLE,<br>
> + /* Making the appsrc to block. This will make the push_buffer()<br>
> + * tightly coupled with the buffer flow from appsrc -> decoder.<br>
> + * push_buffer() will only return when the same buffer it just<br>
> + * fed to appsrc has also been fed to the decoder element as well */<br>
> + "block", TRUE, "max-bytes", ( guint64 )1, NULL );<br>
> + gst_caps_unref( caps.p_sinkcaps );<br>
> + caps.p_sinkcaps = NULL;<br>
> + cb.enough_data = cb.need_data = NULL;<br>
> + cb.seek_data = seek_data_cb;<br>
> + gst_app_src_set_callbacks( GST_APP_SRC( p_sys->p_decode_src ),<br>
> + &cb, p_dec, NULL );<br>
> +<br>
> + if( dbin )<br>
> + {<br>
> + p_sys->p_decode_in = gst_element_factory_make( "decodebin", NULL );<br>
> + VLC_GST_CHECK( p_sys->p_decode_in, NULL, "decodebin not found",<br>
> + VLC_ENOMOD );<br>
> + //g_object_set( G_OBJECT (p_sys->p_decode_in),<br>
> + //"max-size-buffers", 2, NULL );<br>
> + g_signal_connect( G_OBJECT( p_sys->p_decode_in ), "pad-added",<br>
> + G_CALLBACK( pad_added_cb ), p_dec );<br>
> + g_signal_connect (G_OBJECT( p_sys->p_decode_in ), "no-more-pads",<br>
> + G_CALLBACK( no_more_pads_cb ), p_dec );<br>
> + }<br>
> +<br>
> + /* fakesink: will emit signal for every available buffer */<br>
> + p_sys->p_decode_out = gst_element_factory_make( "fakesink", NULL );<br>
> + VLC_GST_CHECK( p_sys->p_decode_out, NULL, "fakesink not found",<br>
> + VLC_ENOMOD );<br>
> + /* connect to the signal with the callback */<br>
> + g_object_set( G_OBJECT( p_sys->p_decode_out ), "sync", FALSE,<br>
> + "enable-last-sample", FALSE, "signal-handoffs", TRUE, NULL );<br>
> + g_signal_connect( G_OBJECT( p_sys->p_decode_out ), "handoff",<br>
> + G_CALLBACK( frame_handoff_cb ), p_dec );<br>
> +<br>
> + p_sys->p_decoder = GST_ELEMENT( gst_bin_new( "decoder" ) );<br>
> + VLC_GST_CHECK( p_sys->p_decoder, NULL, "bin not found", VLC_ENOMOD );<br>
> + p_sys->p_bus = gst_bus_new( );<br>
> + VLC_GST_CHECK( p_sys->p_bus, NULL, "failed to create bus",<br>
> + VLC_ENOMOD );<br>
> + gst_element_set_bus( p_sys->p_decoder, p_sys->p_bus );<br>
> +<br>
> + gst_bin_add_many( GST_BIN( p_sys->p_decoder ),<br>
> + p_sys->p_decode_src, p_sys->p_decode_in,<br>
> + p_sys->p_decode_out, NULL );<br>
> + gst_object_ref( p_sys->p_decode_src );<br>
> + gst_object_ref( p_sys->p_decode_in );<br>
> + gst_object_ref( p_sys->p_decode_out );<br>
> +<br>
> + b_ret = gst_element_link( p_sys->p_decode_src, p_sys->p_decode_in );<br>
> + VLC_GST_CHECK ( b_ret, FALSE, "failed to link src <-> in",<br>
> + VLC_EGENERIC );<br>
> +<br>
> + if( !dbin )<br>
> + {<br>
> + b_ret = gst_element_link( p_sys->p_decode_in, p_sys->p_decode_out );<br>
> + VLC_GST_CHECK (b_ret, FALSE, "failed to link in <-> out",<br>
> + VLC_EGENERIC );<br>
> + }<br>
> +<br>
> + p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;<br>
> +<br>
> + /* set the pipeline to playing */<br>
> + i_ret = gst_element_set_state( p_sys->p_decoder, GST_STATE_PLAYING );<br>
> + VLC_GST_CHECK( i_ret, GST_STATE_CHANGE_FAILURE,<br>
> + "set state failure", VLC_EGENERIC );<br>
> + p_sys->b_running = true;<br>
> +<br>
> + /* Force packetized for now */<br>
> + p_dec->b_need_packetized = true;<br>
> + /* Set callbacks */<br>
> + p_dec->pf_decode_video = DecodeBlock;<br>
> +<br>
> + return VLC_SUCCESS;<br>
> +<br>
> +fail:<br>
> + if( caps.p_sinkcaps )<br>
> + gst_caps_unref( caps.p_sinkcaps );<br>
> + if( caps.p_srccaps )<br>
> + gst_caps_unref( caps.p_srccaps );<br>
> + if( p_list )<br>
> + gst_plugin_feature_list_free( p_list );<br>
> + CloseDecoder( ( vlc_object_t* )p_dec );<br>
> + return i_rval;<br>
> +}<br>
> +<br>
> +/* Decode */<br>
> +static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )<br>
> +{<br>
> + block_t *p_block;<br>
> + picture_t *p_pic = NULL;<br>
> + decoder_sys_t *p_sys = p_dec->p_sys;<br>
> + GstMessage* p_msg;<br>
> + gboolean b_ret;<br>
> + GstBuffer* p_buf;<br>
> +<br>
> + if( !pp_block )<br>
> + return NULL;<br>
> +<br>
> + p_block = *pp_block;<br>
> +<br>
> + if( p_block )<br>
> + {<br>
> + if( unlikely( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY |<br>
> + BLOCK_FLAG_CORRUPTED ) ) )<br>
> + {<br>
> + if ( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )<br>
> + {<br>
> + GstBuffer* p_buffer;<br>
> + /* Send a new segment event. Seeking position is<br>
> + * irrelavant in this case, as the main motive for a<br>
</div></div>"irrelevant"<br></blockquote><div style> Vikram: OK </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> + * seek here, is to tell the elements to start flushing<br>
> + * and start accepting buffers from a new time segment */<br>
> + b_ret = gst_element_seek_simple( p_sys->p_decoder,<br>
> + GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH, 0 );<br>
> + msg_Dbg( p_dec, "new segment event : %d", b_ret );<br>
> +<br>
> + /* flush the output buffers from the queue */<br>
> + while( ( p_buffer = gst_atomic_queue_pop( p_sys->p_que ) ) )<br>
> + gst_buffer_unref ( p_buffer );<br>
> +<br>
> + p_sys->b_prerolled = false;<br>
> + }<br>
> +<br>
> + block_Release( p_block );<br>
> + goto done;<br>
> + }<br>
> +<br>
> + if( likely( p_block->i_buffer ) )<br>
> + {<br>
> + p_buf = gst_buffer_new_wrapped_full( GST_MEMORY_FLAG_READONLY,<br>
> + p_block->p_start, p_block->i_size,<br>
> + p_block->p_buffer - p_block->p_start, p_block->i_buffer,<br>
> + p_block, ( GDestroyNotify )block_Release );<br>
> + if( unlikely( p_buf == NULL ) )<br>
> + {<br>
> + msg_Err( p_dec, "failed to create input gstbuffer" );<br>
> + p_dec->b_error = true;<br>
> + block_Release( p_block );<br>
> + goto done;<br>
> + }<br>
> +<br>
> + if( p_block->i_dts > VLC_TS_INVALID )<br>
> + GST_BUFFER_DTS( p_buf ) = gst_util_uint64_scale( p_block->i_dts,<br>
> + GST_SECOND, GST_MSECOND );<br>
> +<br>
> + if( p_block->i_pts <= VLC_TS_INVALID )<br>
> + GST_BUFFER_PTS( p_buf ) = GST_BUFFER_DTS( p_buf );<br>
> + else<br>
> + GST_BUFFER_PTS( p_buf ) = gst_util_uint64_scale( p_block->i_pts,<br>
> + GST_SECOND, GST_MSECOND );<br>
> +<br>
> + if( p_block->i_length > VLC_TS_INVALID )<br>
> + GST_BUFFER_DURATION( p_buf ) = gst_util_uint64_scale(<br>
> + p_block->i_length, GST_SECOND, GST_MSECOND );<br>
> +<br>
> + if( p_dec->fmt_in.video.i_frame_rate &&<br>
> + p_dec->fmt_in.video.i_frame_rate_base )<br>
> + GST_BUFFER_DURATION( p_buf ) = gst_util_uint64_scale( GST_SECOND,<br>
> + p_dec->fmt_in.video.i_frame_rate_base,<br>
> + p_dec->fmt_in.video.i_frame_rate );<br>
> +<br>
> + /* Give the input buffer to GStreamer Bin.<br>
> + *<br>
> + * libvlc libvlc<br>
> + * \ (i/p) (o/p) ^<br>
> + * \ /<br>
> + * ___v____GSTREAMER BIN_____/____<br>
> + * | |<br>
> + * | appsrc-->decode-->fakesink |<br>
> + * |_______________________________|<br>
> + *<br>
> + * * * * * * * * * * * * * * * * * * * * */<br>
> + if( unlikely( gst_app_src_push_buffer(<br>
> + GST_APP_SRC_CAST( p_sys->p_decode_src ), p_buf )<br>
> + != GST_FLOW_OK ) )<br>
> + {<br>
> + /* block will be released internally,<br>
> + * when gst_buffer_unref() is called */<br>
> + p_dec->b_error = true;<br>
> + msg_Err( p_dec, "failed to push buffer" );<br>
> + goto done;<br>
> + }<br>
> + }<br>
> + else<br>
> + block_Release( p_block );<br>
> + }<br>
> +<br>
> + /* Poll for any messages, errors */<br>
> + p_msg = gst_bus_pop_filtered( p_sys->p_bus,<br>
> + GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR |<br>
> + GST_MESSAGE_EOS | GST_MESSAGE_WARNING |<br>
> + GST_MESSAGE_INFO );<br>
> + if( p_msg )<br>
> + {<br>
> + switch( GST_MESSAGE_TYPE( p_msg ) ){<br>
> + case GST_MESSAGE_EOS:<br>
> + /* for debugging purpose */<br>
> + msg_Warn( p_dec, "got unexpected eos" );<br>
> + break;<br>
> + /* First buffer received */<br>
> + case GST_MESSAGE_ASYNC_DONE:<br>
> + /* for debugging purpose */<br>
> + p_sys->b_prerolled = true;<br>
> + msg_Dbg( p_dec, "Pipeline is prerolled" );<br>
> + break;<br>
> + default:<br>
> + if( ( p_dec->b_error = default_msg_handler( p_dec, p_msg ) ) )<br>
> + {<br>
> + gst_message_unref( p_msg );<br>
> + goto done;<br>
> + }<br>
> + break;<br>
> + }<br>
> + gst_message_unref( p_msg );<br>
> + }<br>
> +<br>
> + /* Look for any output buffers in the queue */<br>
> + if( gst_atomic_queue_peek( p_sys->p_que ) ) {<br>
> + /* Get a new picture */<br>
> + p_pic = decoder_NewPicture( p_dec );<br>
> +<br>
> + if( p_pic )<br>
> + {<br>
</div></div>You could return NULL directly if !p_pic and avoid another block.<br></blockquote><div style> Vikram: OK </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> + p_buf = GST_BUFFER_CAST(<br>
> + gst_atomic_queue_pop( p_sys->p_que ) );<br>
> + GstVideoFrame frame;<br>
> +<br>
> + if( likely( GST_BUFFER_PTS_IS_VALID( p_buf ) ) )<br>
> + {<br>
> + p_pic->date = gst_util_uint64_scale(<br>
> + GST_BUFFER_PTS( p_buf ), GST_MSECOND, GST_SECOND );<br>
> + }<br>
> + else<br>
> + msg_Warn( p_dec, "Gst Buffer has no timestamp" );<br>
> +<br>
> + if( unlikely( !gst_video_frame_map( &frame,<br>
> + &p_sys->vinfo, p_buf, GST_MAP_READ ) ) )<br>
> + {<br>
> + msg_Err( p_dec, "failed to map gst video frame" );<br>
> + gst_buffer_unref( p_buf );<br>
> + p_dec->b_error = true;<br>
> + goto done;<br>
> + }<br>
> +<br>
> + gst_CopyPicture( p_pic, &frame );<br>
> + gst_video_frame_unmap( &frame );<br>
> + gst_buffer_unref( p_buf );<br>
> + }<br>
> + }<br>
> +<br>
> +done:<br>
> + *pp_block = NULL;<br>
> + return p_pic;<br>
> +}<br>
> +<br>
> +/* Close the decoder instance */<br>
> +static void CloseDecoder( vlc_object_t *p_this )<br>
> +{<br>
> + decoder_t *p_dec = ( decoder_t *)p_this;<br>
> + decoder_sys_t *p_sys = p_dec->p_sys;<br>
> +<br>
> + if( p_sys->b_running )<br>
> + {<br>
> + GstMessage* p_msg;<br>
> + GstFlowReturn i_ret;<br>
> +<br>
> + /* Send EOS to the pipeline */<br>
> + i_ret = gst_app_src_end_of_stream(<br>
> + GST_APP_SRC_CAST( p_sys->p_decode_src ) );<br>
> + msg_Dbg( p_dec, "app src eos: %s", gst_flow_get_name( i_ret ) );<br>
> +<br>
> + /* and catch it on the bus with a timeout */<br>
> + p_msg = gst_bus_timed_pop_filtered( p_sys->p_bus,<br>
> + 2000000000ULL, GST_MESSAGE_EOS | GST_MESSAGE_ERROR );<br>
> +<br>
> + if( p_msg )<br>
> + {<br>
> + switch( GST_MESSAGE_TYPE( p_msg ) ){<br>
> + case GST_MESSAGE_EOS:<br>
> + msg_Dbg( p_dec, "got eos" );<br>
> + break;<br>
> + default:<br>
> + if( ( p_dec->b_error = default_msg_handler( p_dec, p_msg ) ) )<br>
> + msg_Warn( p_dec, "pipeline may not close gracefully" );<br>
> + break;<br>
> + }<br>
> +<br>
> + gst_message_unref( p_msg );<br>
> + }<br>
> + else<br>
> + msg_Warn( p_dec,<br>
> + "no message, pipeline may not close gracefully" );<br>
> + }<br>
> +<br>
> + /* Remove any left-over buffers from the queue */<br>
> + if( p_sys->p_que )<br>
> + {<br>
> + GstBuffer* p_buf;<br>
> + while( ( p_buf = gst_atomic_queue_pop( p_sys->p_que ) ) )<br>
> + gst_buffer_unref( p_buf );<br>
> + gst_atomic_queue_unref( p_sys->p_que );<br>
> + }<br>
> +<br>
> + if( p_sys->b_running &&<br>
> + gst_element_set_state( p_sys->p_decoder, GST_STATE_NULL )<br>
> + != GST_STATE_CHANGE_SUCCESS )<br>
> + msg_Warn( p_dec,<br>
> + "failed to change the state to NULL" \<br>
> + "pipeline may not close gracefully" );<br>
> +<br>
> + if( p_sys->p_bus )<br>
> + gst_object_unref( p_sys->p_bus );<br>
> + if( p_sys->p_decode_src )<br>
> + gst_object_unref( p_sys->p_decode_src );<br>
> + if( p_sys->p_decode_in )<br>
> + gst_object_unref( p_sys->p_decode_in );<br>
> + if( p_sys->p_decode_out )<br>
> + gst_object_unref( p_sys->p_decode_out );<br>
> + if( p_sys->p_decoder )<br>
> + gst_object_unref( p_sys->p_decoder);<br>
> +<br>
> + free( p_sys );<br>
> +}<br>
> diff --git a/po/POTFILES.in b/po/POTFILES.in<br>
> index 0a86072..49c997d 100644<br>
> --- a/po/POTFILES.in<br>
> +++ b/po/POTFILES.in<br>
> @@ -372,6 +372,7 @@ modules/codec/fdkaac.c<br>
> modules/codec/flac.c<br>
> modules/codec/fluidsynth.c<br>
> modules/codec/g711.c<br>
> +modules/codec/gstdecode.c<br>
> modules/codec/jpeg.c<br>
> modules/codec/kate.c<br>
> modules/codec/libass.c<br>
> --<br>
> 1.7.9.5<br>
><br>
</div></div>> _______________________________________________<br>
> vlc-devel mailing list<br>
> To unsubscribe or modify your subscription options:<br>
> <a href="https://mailman.videolan.org/listinfo/vlc-devel" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a><br>
<span class="HOEnZb"><font color="#888888"><br>
<br>
<br>
--<br>
Félix Abecassis<br>
<a href="http://felix.abecassis.me" target="_blank">http://felix.abecassis.me</a><br>
<br>
_______________________________________________<br>
vlc-devel mailing list<br>
To unsubscribe or modify your subscription options:<br>
<a href="https://mailman.videolan.org/listinfo/vlc-devel" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a><br>
</font></span></blockquote></div><br></div></div>