<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Apr 27, 2014 at 2:15 AM, Rémi Denis-Courmont <span dir="ltr"><<a href="mailto:remi@remlab.net" target="_blank">remi@remlab.net</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Le samedi 26 avril 2014, 17:35:26 Vikram Fugro a écrit :<br>
<div class="">>  dnl<br>
> +dnl gstreamer decode plugins<br>
> +dnl<br>
> +AC_ARG_ENABLE(gstreamer-decode,<br>
> +[  --enable-gstreamer-decode        gstreamer decode plugins support,<br>
> currently supports only video decoders (default enabled)])<br>
<br>
</div>I think it should default to auto, not enabled.<br>
<div class=""><br>
> +<br>
> +dnl<br>
> +dnl gstreamer core libs, will be mandatory for all types of gstreamer based<br>
> modules<br>
> +dnl<br>
> +AS_IF([test "${enable_gstreamer_decode}" != "no"], [<br>
> +  PKG_CHECK_MODULES(GSTREAMER_APP,[gstreamer-app-1.0], [<br>
> +  ],[<br>
> +    AC_MSG_ERROR([${GSTREAMER_APP_PKG_ERRORS}. Please disable all the<br>
> gstreamer based modules to ignore this error.])<br>
> +  ])<br>
> +],[<br>
<br>
</div>Same here.<br>
<div class=""><br>
> +])<br>
> +<br>
> +dnl<br>
> +dnl gstreamer plugins for decoder codec module.<br>
> +dnl<br>
> +AS_IF([test "${enable_gstreamer_decode}" != "no"], [<br>
> +  dnl<br>
> +  dnl Currently supports only video decoders<br>
> +  dnl<br>
> +  PKG_CHECK_MODULES(GSTREAMER_VIDEO,[gstreamer-basevideo-1.0<br>
> gstreamer-video-1.0], [<br>
<br>
</div>AFAIK, gstreamer-basevideo no longer exists.<br>
<div class=""><br>
> +    VLC_SAVE_FLAGS<br>
> +    CPPFLAGS="${CPPFLAGS} ${GSTREAMER_VIDEO_CFLAGS}<br>
> ${GSTREAMER_APP_CFLAGS}"<br>
> +    CFLAGS="${CFLAGS} ${GSTREAMER_VIDEO_CFLAGS}<br>
> ${GSTREAMER_APP_CFLAGS}"<br>
<br>
</div>Why? you're not compiling any code here...<br>
<br>
> +    VLC_ADD_PLUGIN([gstdecode])<br>
<br>
No. This is redundant with the automake conditional below.<br>
<div class=""><br>
> +    VLC_ADD_LIBS([gstdecode],[$GSTREAMER_VIDEO_LIBS])<br>
> +    VLC_ADD_LIBS([gstdecode],[$GSTREAMER_APP_LIBS])<br>
<br>
</div>No. This is redundant since you already have LIBADD in the Makefile.<br>
<div class=""><br>
> +    VLC_RESTORE_FLAGS<br>
> +  ],[<br>
> +    AC_MSG_ERROR([${GSTREAMER_VIDEO_PKG_ERRORS}. Pass<br>
> --disable-gstreamer-decode to ignore this error.])<br>
> +  ])<br>
<br>
</div>Not everybody has gstreamer. We don't want to fail by default.<br>
<div class=""><br>
> +],[<br>
> +])<br>
> +AM_CONDITIONAL([HAVE_GSTREAMER_DECODE], [test "${have_gstreamer_decode}" !=<br>
> "no"])<br>
<br>
</div>HAVE_GSTREAMER. And I don't see where ${have_gstreamer_decode} is computed.<br>
<div><div class="h5"><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<br>
> spatialization effect * hevc: HEVC demuxer<br>
> diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am<br>
> index 14500c6..dc8664f 100644<br>
> --- a/modules/codec/Makefile.am<br>
> +++ b/modules/codec/Makefile.am<br>
> @@ -470,3 +470,12 @@ libquicktime_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath<br>
> '$(codecdir)' 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) $(GSTREAMER_VIDEO_CFLAGS)<br>
> $(GSTREAMER_APP_CFLAGS)<br>
<br>
> +libgstdecode_plugin_la_LDFLAGS = $(AM_LDFLAGS)<br>
> -rpath '$(codecdir)'<br>
<br>
</div></div>Not needed.<br>
<div class=""><br>
> +libgstdecode_plugin_la_LIBADD =<br>
> $(GSTREAMER_VIDEO_LIBS) $(GSTREAMER_APP_LIBS)<br>
<br>
> +EXTRA_LTLIBRARIES += <a href="http://libgstdecode_plugin.la" target="_blank">libgstdecode_plugin.la</a><br>
<br>
</div>Not needed.<br>
<div class=""><br>
> +if HAVE_GSTREAMER_DECODE<br>
> +codec_LTLIBRARIES += $(LTLIBgstdecode)<br>
<br>
</div>codec_LTLIBRARIES += <a href="http://libgstdecode_plugin.la" target="_blank">libgstdecode_plugin.la</a><br>
<div class=""><br></div></blockquote><div>    Sorry I'm not really an expert in autotools/configure stuff . For all the comments above, Would it be ok if I move it back to <br>    PKG_ENABLE_MODULES_VLC([GSTREAMER_DECODE], [gstdecode], [gstreamer-app-1.0 gstreamer-video-1.0], [gstreamer blah blah ], [auto]) <br>
</div><div>    That'd actually simplify a lot and make it much shorter, as also suggested by Jean.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="">
> +endif<br>
> diff --git a/modules/codec/gstdecode.c b/modules/codec/gstdecode.c<br>
> new file mode 100644<br>
> index 0000000..565f284<br>
> --- /dev/null<br>
> +++ b/modules/codec/gstdecode.c<br>
> @@ -0,0 +1,889 @@<br>
> +/**************************************************************************<br>
</div>> *** + * gstdecode.c: Decoder module making use of gstreamer<br>
> +<br>
> ***************************************************************************<br>
> ** + * Copyright (C) 2014 the VideoLAN team<br>
<div class="">> + * $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<br>
> <a href="tel:02110-1301" value="+35821101301">02110-1301</a> USA +<br>
> ***************************************************************************<br>
> **/ +<br>
> +/**************************************************************************<br>
> *** + * Preamble<br>
> +<br>
> ***************************************************************************<br>
</div>> **/ +#ifdef HAVE_CONFIG_H<br>
<div><div class="h5">> +# 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>
> +    bool b_prerolled;<br>
> +    bool b_running;<br>
> +<br>
> +    bool b_out_fmt_set;<br>
> +};<br>
> +<br>
> +/**************************************************************************<br>
</div></div>> *** + * Local prototypes<br>
> +<br>
> ***************************************************************************<br>
> **/ +static int  OpenDecoder( vlc_object_t * );<br>
<div><div class="h5">> +static void CloseDecoder( vlc_object_t * );<br>
> +static picture_t *DecodeBlock( decoder_t *, block_t ** );<br>
> +<br>
> +#define MODULE_DESCRIPTION N_( "Decoders' plugins " \<br>
> +        "delivered by the GStreamer library. " \<br>
> +        "Currently supports only video decoders such as " \<br>
> +        "h264, mpeg4, wmv, mpeg2, vp8, etc. " )<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>
> +    "in the form of GstCaps (Stream Capabilities) to decoder. " )<br>
> +<br>
> +vlc_module_begin ()<br>
> +    set_shortname( "GstDecode")<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>
> +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( es_format_t* p_fmt )<br>
<br>
</div></div>Missing const.<br>
<div><div class="h5">OK.<br></div></div></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="h5">
> +{<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>
> +        break;<br>
> +    }<br>
> +<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 %llu", (unsigned long long)l_offset<br>
> );<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>
> +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>
> +    /* check if atleast one pad was linked by now */<br>
> +    if( p_pad )<br>
> +    {<br>
> +        if( !gst_pad_is_linked( p_pad ) )<br>
> +        {<br>
> +            p_dec->b_error = true;<br>
<br>
</div></div>Dubious for thread-safety...<br>
<div><div class="h5">OK. Will have it set in DecodeBlock().<br></div></div></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5">
> +            msg_Err( p_dec, "failed to link decode out pad" );<br>
> +        }<br>
> +<br>
> +        gst_object_unref( p_pad );<br>
> +    }<br>
> +}<br>
> +<br>
> +/* Emitted by decodebin and links decodebin to fakesink */<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>
> +    GstPad* p_sinkpad;<br>
> +<br>
> +    p_sinkpad = gst_element_get_static_pad(<br>
> +            p_sys->p_decode_out, "sink" );<br>
> +<br>
> +    if( p_sinkpad && !gst_pad_is_linked( p_sinkpad ) &&<br>
> +            gst_pad_has_current_caps( p_pad ) )<br>
> +    {<br>
> +        GstCaps* p_caps;<br>
> +        GstStructure* p_str;<br>
> +<br>
> +        p_caps = gst_pad_get_current_caps( p_pad );<br>
> +        p_str = gst_caps_get_structure( p_caps, 0 );<br>
> +<br>
> +        /* We want raw caps only. More formats can also be added like<br>
> +         * opaque data structures in case of HW decoder */<br>
> +        if( p_str && gst_structure_has_name( p_str, "video/x-raw" ) )<br>
> +        {<br>
> +            if( !gst_video_info_from_caps( &p_sys->vinfo,<br>
> +                        p_caps ) )<br>
> +                msg_Warn( p_dec, "failed to get video info from caps" );<br>
> +            else<br>
> +                gst_pad_link( p_pad, p_sinkpad );<br>
> +        }<br>
> +<br>
> +        gst_caps_unref( p_caps );<br>
> +    }<br>
> +<br>
> +    if( p_sinkpad )<br>
> +        gst_object_unref( p_sinkpad );<br>
> +}<br>
> +<br>
> +static bool set_out_format( GstStructure* p_str,<br>
> +        const es_format_t* p_infmt, es_format_t* p_outfmt )<br>
> +{<br>
> +    video_format_t *p_voutfmt, *p_vinfmt;<br>
> +<br>
> +    if ( !p_str || !p_infmt || !p_outfmt)<br>
> +        return false;<br>
<br>
</div></div>Please don't handle impossible errors.<br>
<div class="">OK.<br></div></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="">
> +<br>
> +    p_voutfmt = &p_outfmt->video;<br>
> +    p_vinfmt = &p_infmt->video;<br>
> +<br>
> +    /* We are interested in raw buffers for now, but support<br>
> +     * for opaque data formats can also be added. For eg. when<br>
> +     * using HW  decoders for zero-copy */<br>
> +    if( gst_structure_has_name( p_str, "video/x-raw" ) )<br>
> +    {<br>
> +        gboolean b_ret = FALSE;<br>
> +<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 false;<br>
> +<br>
> +        b_ret = gst_structure_get_fraction( p_str,<br>
> +                "pixel-aspect-ratio",<br>
> +                ( gint* )&p_voutfmt->i_sar_num,<br>
> +                ( gint* )&p_voutfmt->i_sar_den );<br>
<br>
</div>Either those casts are not needed, or they violate aliasing rules. Same below.<br></blockquote><div>   One is int and the other is unsigned int! I put them to avoid the compiler warnings.<br></div><div>    <br></div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Also I am not sure why this is under "video/x-raw". Surely opaque video data<br>
can have an aspect ratio too. Same with the dimensions and frame rate.<br>
<div class=""><br></div></blockquote><div>   Surely, but opaque data would still be raw data, right? Did you mean that opaque data would have <br></div><div>   different mime-type? In GStreamer 1.0, it is now a "GstCapsFeature" for memory-type in opaque <br>
   data types in such cases, whilst keeping the mime-type to "video/x-raw" only.<br><br></div><div>   Currently it only supports "video/x-raw(memory:system)" under raw video formats. As and when,<br></div>
<div>   more formats are added like opaque video data, the "if" check can be ORed with them.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="">
> +<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_int( p_str, "width",<br>
> +                ( gint* )&p_voutfmt->i_width ) &&<br>
> +            gst_structure_get_int ( p_str, "height",<br>
> +                    ( gint* )&p_voutfmt->i_height );<br>
> +<br>
> +        if( !b_ret || !p_voutfmt->i_width ||<br>
> +                !p_voutfmt->i_height )<br>
> +        {<br>
> +            p_voutfmt->i_width = p_vinfmt->i_width;<br>
> +            p_voutfmt->i_height = p_vinfmt->i_height;<br>
> +        }<br>
<br>
</div>Is this actually possible? Shouldn't gstreamer always provide a width and<br>
height?<br>
<div><div class="h5">It does really. I'll remove the check. Was just being unnecessarily over-cautious! <br></div></div></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div><div class="h5"></div><div class="h5">
> +<br>
> +        b_ret = gst_structure_get_fraction ( p_str, "framerate",<br>
> +                ( gint* )&p_voutfmt->i_frame_rate,<br>
> +                ( gint* )&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>
> +        return true;<br>
> +    }<br>
> +<br>
> +    return false;<br>
> +}<br>
> +<br>
> +/* Emitted by fakesink for every buffer and sets the<br>
> + * output format in VLC context for vout 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_sys->b_out_fmt_set == false ) )<br>
<br>
</div></div>That should be !p_sys->b_out_fmt_set<br>
</div>OK.<br></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
But depending on the case, you can use either<br>
i_codec == 0 or video.i_format == 0 without a new boolean.<br>
<div class="">OK. I'll check for i_codec == 0, since audio support can also be added .<br></div></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div class="">
> +    {<br>
> +        if( gst_pad_has_current_caps( p_pad ) )<br>
> +        {<br>
> +            GstCaps* p_caps;<br>
> +            GstStructure* p_str;<br>
> +<br>
> +            p_caps = gst_pad_get_current_caps( p_pad );<br>
> +<br>
> +            if ( !gst_video_info_from_caps( &p_sys->vinfo,<br>
> +                        p_caps ) )<br>
> +                msg_Warn( p_dec, "failed to get video info from caps" );<br>
<br>
</div>Is this really a recoverable error?<br></blockquote><div>   No. Thanks, Will change it to msg_Errr and quit from there.. This code will need a little reorg.<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<div><div class="h5"><br>
> +<br>
> +            p_str = gst_caps_get_structure( p_caps, 0 );<br>
> +            p_sys->b_out_fmt_set = set_out_format( p_str, &p_dec->fmt_in,<br>
> +                    &p_dec->fmt_out );<br>
> +<br>
> +            gst_caps_unref( p_caps );<br>
> +        }<br>
> +<br>
> +        if( !p_sys->b_out_fmt_set )<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 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 < 3 ? p_pic->i_planes : 3;<br>
<br>
</div></div>Why is this capped to 3? If the gstreamer output format is unsupported, we<br>
should hopefully not reach this code at all<br></blockquote><div>   OK, will remove this part.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> +    for( i_plane = 0; i_plane < i_planes; i_plane++ )<br><div><div class="h5">
> +    {<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>
> +    GstCaps* p_caps;<br>
> +<br>
> +    p_factory = ( GstElementFactory* )p_p1;<br>
> +    p_caps = ( GstCaps * )p_p2;<br>
> +<br>
> +    return( !gst_element_factory_can_sink_any_caps( p_factory, p_caps ) );<br>
> +}<br>
> +<br>
> +/**************************************************************************<br>
</div></div>> *** + * OpenDecoder: probe the decoder and return score<br>
> +<br>
> ***************************************************************************<br>
> **/ +static int OpenDecoder( vlc_object_t *p_this )<br>
<div><div class="h5">> +{<br>
> +    decoder_t *p_dec = ( decoder_t* )p_this;<br>
> +    decoder_sys_t *p_sys;<br>
> +    GstStateChangeReturn i_ret;<br>
> +    gboolean b_ret;<br>
> +    GstCaps* p_caps = NULL;<br>
> +    GstStructure* p_str = NULL;<br>
> +    GstAppSrcCallbacks cb;<br>
> +    int i_rval = VLC_SUCCESS;<br>
> +    GList* p_list = NULL;<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>
> +<br>
> +    p_str = vlc_to_gst_fmt( &p_dec->fmt_in );<br>
> +    if( !p_str ) {<br>
> +        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>
> +        return VLC_ENOMEM;<br>
<br>
</div></div>Leaking p_str.<br></blockquote><div>   Thanks, will fix that. <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><br>
> +<br>
> +    dbin = var_CreateGetBool( p_dec, "use-decodebin" );<br>
> +    msg_Info( p_dec, "Using decodebin? %s", dbin ? "yes ":"no" );<br>
> +<br>
> +    /* Force packetized for now */<br>
> +    p_dec->b_need_packetized = true;<br>
> +<br>
<br>
> +    if( p_dec->fmt_in.video.i_width &&<br>
> +            p_dec->fmt_in.video.i_height )<br>
> +    {<br>
> +        gst_structure_set( p_str,<br>
> +                "width", G_TYPE_INT, p_dec->fmt_in.video.i_width,<br>
> +                "height", G_TYPE_INT, p_dec->fmt_in.video.i_height, NULL );<br>
> +    }<br>
> +<br>
> +    if( p_dec->fmt_in.video.i_frame_rate &&<br>
> +            p_dec->fmt_in.video.i_frame_rate_base )<br>
> +    {<br>
> +        gst_structure_set( p_str, "framerate", GST_TYPE_FRACTION,<br>
> +                p_dec->fmt_in.video.i_frame_rate,<br>
> +                p_dec->fmt_in.video.i_frame_rate_base, NULL );<br>
> +    }<br>
> +<br>
> +    if( p_dec->fmt_in.video.i_sar_num &&<br>
> +            p_dec->fmt_in.video.i_sar_den )<br>
> +    {<br>
> +        gst_structure_set( p_str, "pixel-aspect-ratio", GST_TYPE_FRACTION,<br>
> +                p_dec->fmt_in.video.i_sar_num,<br>
> +                p_dec->fmt_in.video.i_sar_den, NULL );<br>
> +    }<br>
> +<br>
> +    if( p_dec->fmt_in.i_extra )<br>
> +    {<br>
> +        GstBuffer* p_buf;<br>
> +<br>
> +        p_buf = gst_buffer_new_wrapped_full( GST_MEMORY_FLAG_READONLY,<br>
> +                p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra, 0,<br>
> +                p_dec->fmt_in.i_extra, NULL, NULL );<br>
> +        VLC_GST_CHECK( p_buf, NULL, "failed to create codec data<br>
> gstbuffer", +                VLC_ENOMEM );<br>
> +<br>
> +        gst_structure_set( p_str, "codec_data", GST_TYPE_BUFFER, p_buf,<br>
> NULL );<br>
> +        gst_buffer_unref( p_buf );<br>
> +    }<br>
<br>
</div></div>Why is that block not part of vlc_to_gst_fmt() ?</blockquote><div>   Correct, will have it in vlc_to_gst_fmt(). But there is no need currently for it be parsed, Nevertheless, I'll move it there.<br><br></div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="h5">
> +<br>
> +    p_caps = gst_caps_new_empty( );<br>
> +    gst_caps_append_structure( p_caps, p_str );<br>
> +    p_str = NULL;<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, p_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, p_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>
> +<br>
> +    p_dec->fmt_out.i_cat = VIDEO_ES;<br>
> +<br>
> +    p_sys->b_prerolled = false;<br>
> +    p_sys->b_running = false;<br>
> +    p_sys->b_out_fmt_set = 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", p_caps,<br>
> +            "block", FALSE, "emit-signals", TRUE, "format",<br>
> GST_FORMAT_BYTES, +            "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 -><br>
> decoder. +             * push_buffer() will only return when the buffer has<br>
> been fed +             * to the decoder element */<br>
> +            "block", TRUE, "max-bytes", ( guint64 )1, NULL );<br>
> +    gst_caps_unref( p_caps );<br>
> +    p_caps = 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>
> +    /* 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>
> +<br>
> +    p_sys->b_running = true;<br>
> +<br>
> +    /* Set callbacks */<br>
> +    p_dec->pf_decode_video = DecodeBlock;<br>
> +<br>
> +    return VLC_SUCCESS;<br>
> +<br>
> +fail:<br>
> +    if( p_caps )<br>
> +    {<br>
> +        gst_caps_unref( p_caps );<br>
> +        p_str = NULL;<br>
> +    }<br>
> +    if( p_str )<br>
> +        gst_structure_free( p_str );<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>
> +                 * 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,<br>
> p_block->i_buffer,<br>
> +                    p_block, ( GDestroyNotify )block_Release );<br>
<br>
</div></div>Is that a valid function pointer cast?<br></blockquote><div>   Yes, to avoid compiler warnings. is there anything wrong you see here?<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<div><div class="h5"><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(<br>
> p_block->i_dts, +                        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(<br>
> p_block->i_pts, +                        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(<br>
> GST_SECOND, +                        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>
> +                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>
<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_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>
> +                p_dec->b_error = true;<br>
> +<br>
> +            }<br>
> +            goto done;<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>
> +        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>
> +        case GST_MESSAGE_WARNING:<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_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>
> +        default:<br>
> +            break;<br>
> +        }<br>
> +        gst_message_unref( p_msg );<br>
> +    }<br>
<br>
</div></div>This block seems like it could be split to a separate function and reused in<br>
CloseDecoder().<br></blockquote><div>   ok. <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><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>
> +            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>
> +<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>
> +            else<br>
> +            {<br>
> +                gst_CopyPicture( p_pic, &frame );<br>
> +                gst_video_frame_unmap( &frame );<br>
> +            }<br>
> +<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 == NULL )<br>
> +        return;<br>
<br>
</div></div>That should be impossible.<br>
<div class=""><div class="h5">ok.<br></div></div></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class=""><div class="h5">
</div><div class="h5">
> +<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_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 when shutting down, from %s:<br>
> %s", +                            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_EOS:<br>
> +                msg_Dbg( p_dec, "got eos" );<br>
> +                break;<br>
> +            default:<br>
> +                break;<br>
> +            }<br>
> +<br>
> +            gst_message_unref( p_msg );<br>
> +        }<br>
> +        else<br>
> +        {<br>
> +            msg_Warn( p_dec,<br>
> +                    "no message, pipeline may not close gracefully" );<br>
> +        }<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>
--<br>
</div></div><span class=""><font color="#888888">Rémi Denis-Courmont<br>
<a href="http://www.remlab.net/" target="_blank">http://www.remlab.net/</a><br>
<br>
</font></span></blockquote></div><br></div></div>