diff --git a/configure b/configure index e279b96203e..ab5434a9c56 100755 --- a/configure +++ b/configure @@ -2290,9 +2290,11 @@ Some influential environment variables: C compiler flags for libpulse, overriding pkg-config PULSE_LIBS Linker flags for libpulse, overriding pkg-config GSTREAMER_CFLAGS - C compiler flags for gstreamer-app-0.10, overriding pkg-config + C compiler flags for gstreamer-1.0 gstreamer-video-1.0 + gstreamer-audio-1.0, overriding pkg-config GSTREAMER_LIBS - Linker flags for gstreamer-app-0.10, overriding pkg-config + Linker flags for gstreamer-1.0 gstreamer-video-1.0 + gstreamer-audio-1.0, overriding pkg-config CAPI20_CFLAGS C compiler flags for capi20, overriding pkg-config CAPI20_LIBS Linker flags for capi20, overriding pkg-config @@ -12591,19 +12593,19 @@ if test "x$with_gstreamer" != "xno" then if ${GSTREAMER_CFLAGS:+false} :; then : if ${PKG_CONFIG+:} false; then : - GSTREAMER_CFLAGS=`$PKG_CONFIG --cflags gstreamer-app-0.10 2>/dev/null` + GSTREAMER_CFLAGS=`$PKG_CONFIG --cflags gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 2>/dev/null` fi fi if ${GSTREAMER_LIBS:+false} :; then : if ${PKG_CONFIG+:} false; then : - GSTREAMER_LIBS=`$PKG_CONFIG --libs gstreamer-app-0.10 2>/dev/null` + GSTREAMER_LIBS=`$PKG_CONFIG --libs gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 2>/dev/null` fi fi -$as_echo "$as_me:${as_lineno-$LINENO}: gstreamer-app-0.10 cflags: $GSTREAMER_CFLAGS" >&5 -$as_echo "$as_me:${as_lineno-$LINENO}: gstreamer-app-0.10 libs: $GSTREAMER_LIBS" >&5 +$as_echo "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 cflags: $GSTREAMER_CFLAGS" >&5 +$as_echo "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 libs: $GSTREAMER_LIBS" >&5 ac_save_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS $GSTREAMER_CFLAGS" ac_gst_incl="" @@ -12617,13 +12619,13 @@ ac_gst_incl="" CPPFLAGS="$ac_save_CPPFLAGS $GSTREAMER_CFLAGS" ac_fn_c_check_header_mongrel "$LINENO" "gst/gstpad.h" "ac_cv_header_gst_gstpad_h" "$ac_includes_default" if test "x$ac_cv_header_gst_gstpad_h" = xyes; then : - ac_fn_c_check_header_mongrel "$LINENO" "gst/app/gstappsink.h" "ac_cv_header_gst_app_gstappsink_h" "$ac_includes_default" -if test "x$ac_cv_header_gst_app_gstappsink_h" = xyes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gint64 defined by gst/app/gstappsink.h is indeed 64-bit" >&5 -$as_echo_n "checking whether gint64 defined by gst/app/gstappsink.h is indeed 64-bit... " >&6; } + ac_fn_c_check_header_mongrel "$LINENO" "gst/gst.h" "ac_cv_header_gst_gst_h" "$ac_includes_default" +if test "x$ac_cv_header_gst_gst_h" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gint64 defined by gst/gst.h is indeed 64-bit" >&5 +$as_echo_n "checking whether gint64 defined by gst/gst.h is indeed 64-bit... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include +#include int main () { @@ -12635,13 +12637,13 @@ _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gst_pad_get_caps_reffed in -lgstreamer-0.10" >&5 -$as_echo_n "checking for gst_pad_get_caps_reffed in -lgstreamer-0.10... " >&6; } -if ${ac_cv_lib_gstreamer_0_10_gst_pad_get_caps_reffed+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gst_pad_new in -lgstreamer-1.0" >&5 +$as_echo_n "checking for gst_pad_new in -lgstreamer-1.0... " >&6; } +if ${ac_cv_lib_gstreamer_1_0_gst_pad_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lgstreamer-0.10 $LIBS" +LIBS="-lgstreamer-1.0 $GSTREAMER_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -12651,69 +12653,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char gst_pad_get_caps_reffed (); +char gst_pad_new (); int main () { -return gst_pad_get_caps_reffed (); +return gst_pad_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_gstreamer_0_10_gst_pad_get_caps_reffed=yes + ac_cv_lib_gstreamer_1_0_gst_pad_new=yes else - ac_cv_lib_gstreamer_0_10_gst_pad_get_caps_reffed=no + ac_cv_lib_gstreamer_1_0_gst_pad_new=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gstreamer_0_10_gst_pad_get_caps_reffed" >&5 -$as_echo "$ac_cv_lib_gstreamer_0_10_gst_pad_get_caps_reffed" >&6; } -if test "x$ac_cv_lib_gstreamer_0_10_gst_pad_get_caps_reffed" = xyes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gst_app_buffer_new in -lgstapp-0.10" >&5 -$as_echo_n "checking for gst_app_buffer_new in -lgstapp-0.10... " >&6; } -if ${ac_cv_lib_gstapp_0_10_gst_app_buffer_new+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgstapp-0.10 $GSTREAMER_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char gst_app_buffer_new (); -int -main () -{ -return gst_app_buffer_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_gstapp_0_10_gst_app_buffer_new=yes -else - ac_cv_lib_gstapp_0_10_gst_app_buffer_new=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gstapp_0_10_gst_app_buffer_new" >&5 -$as_echo "$ac_cv_lib_gstapp_0_10_gst_app_buffer_new" >&6; } -if test "x$ac_cv_lib_gstapp_0_10_gst_app_buffer_new" = xyes; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gstreamer_1_0_gst_pad_new" >&5 +$as_echo "$ac_cv_lib_gstreamer_1_0_gst_pad_new" >&6; } +if test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" = xyes; then : : fi -fi - else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } @@ -12732,15 +12695,15 @@ test -z "$GSTREAMER_CFLAGS" || GSTREAMER_CFLAGS=`echo " $GSTREAMER_CFLAGS" | sed test -z "$GSTREAMER_LIBS" || GSTREAMER_LIBS=`echo " $GSTREAMER_LIBS" | sed 's/ -L\([^/]\)/ -L\$(top_builddir)\/\1/g'` fi -if test "x$ac_cv_lib_gstapp_0_10_gst_app_buffer_new" != xyes -a "x$ac_cv_header_QuickTime_ImageCompression_h" != xyes; then : +if test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" != xyes -a "x$ac_cv_header_QuickTime_ImageCompression_h" != xyes; then : case "x$with_gstreamer" in - x) as_fn_append wine_notices "|gstreamer-0.10 base plugins ${notice_platform}development files not found, gstreamer support disabled" ;; + x) as_fn_append wine_notices "|gstreamer-1.0 base plugins ${notice_platform}development files not found, gstreamer support disabled" ;; xno) ;; - *) as_fn_error $? "gstreamer-0.10 base plugins ${notice_platform}development files not found, gstreamer support disabled + *) as_fn_error $? "gstreamer-1.0 base plugins ${notice_platform}development files not found, gstreamer support disabled This is an error since --with-gstreamer was requested." "$LINENO" 5 ;; esac fi -test "x$ac_cv_lib_gstapp_0_10_gst_app_buffer_new" = xyes || enable_winegstreamer=${enable_winegstreamer:-no} +test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" = xyes || enable_winegstreamer=${enable_winegstreamer:-no} ALSA_LIBS="" diff --git a/configure.ac b/configure.ac index 6eac75204e8..0766edf7ab6 100644 --- a/configure.ac +++ b/configure.ac @@ -1460,7 +1460,7 @@ test -n "$PULSE_LIBS" || enable_winepulse_drv=${enable_winepulse_drv:-no} dnl **** Check for gstreamer **** if test "x$with_gstreamer" != "xno" then - WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-app-0.10],,,, + WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0],,,, [ac_gst_incl="" for i in $GSTREAMER_CFLAGS do @@ -1471,19 +1471,18 @@ then GSTREAMER_CFLAGS=$ac_gst_incl CPPFLAGS="$ac_save_CPPFLAGS $GSTREAMER_CFLAGS" AC_CHECK_HEADER([gst/gstpad.h], - [AC_CHECK_HEADER([gst/app/gstappsink.h], - [AC_MSG_CHECKING([whether gint64 defined by gst/app/gstappsink.h is indeed 64-bit]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [AC_CHECK_HEADER([gst/gst.h], + [AC_MSG_CHECKING([whether gint64 defined by gst/gst.h is indeed 64-bit]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[static int a[sizeof(gint64) > 4 ? 1 : -1]; if (a[0]) return 0;]])], [AC_MSG_RESULT([yes]) - AC_CHECK_LIB(gstreamer-0.10,gst_pad_get_caps_reffed, - [AC_CHECK_LIB(gstapp-0.10,gst_app_buffer_new,[:],,[$GSTREAMER_LIBS])])], + AC_CHECK_LIB(gstreamer-1.0,gst_pad_new,[:],,[$GSTREAMER_LIBS])], [AC_MSG_RESULT([no])])])], [GSTREAMER_CFLAGS=""])]) fi -WINE_NOTICE_WITH(gstreamer,[test "x$ac_cv_lib_gstapp_0_10_gst_app_buffer_new" != xyes -a "x$ac_cv_header_QuickTime_ImageCompression_h" != xyes], - [gstreamer-0.10 base plugins ${notice_platform}development files not found, gstreamer support disabled]) -test "x$ac_cv_lib_gstapp_0_10_gst_app_buffer_new" = xyes || enable_winegstreamer=${enable_winegstreamer:-no} +WINE_NOTICE_WITH(gstreamer,[test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" != xyes -a "x$ac_cv_header_QuickTime_ImageCompression_h" != xyes], + [gstreamer-1.0 base plugins ${notice_platform}development files not found, gstreamer support disabled]) +test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" = xyes || enable_winegstreamer=${enable_winegstreamer:-no} dnl **** Check for ALSA 1.x **** AC_SUBST(ALSA_LIBS,"") diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c index 9202630f45e..c851798b6d3 100644 --- a/dlls/winegstreamer/gst_cbs.c +++ b/dlls/winegstreamer/gst_cbs.c @@ -18,10 +18,7 @@ #include "config.h" -#include -#include -#include -#include +#include #include "wine/list.h" @@ -88,35 +85,23 @@ GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user) return cbdata.u.watch_bus_data.ret; } -void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gboolean last, - gpointer user) +void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) { struct cb_data cbdata = { EXISTING_NEW_PAD }; cbdata.u.existing_new_pad_data.bin = bin; cbdata.u.existing_new_pad_data.pad = pad; - cbdata.u.existing_new_pad_data.last = last; cbdata.u.existing_new_pad_data.user = user; call_cb(&cbdata); } -gboolean check_get_range_wrapper(GstPad *pad) -{ - struct cb_data cbdata = { CHECK_GET_RANGE }; - - cbdata.u.check_get_range_data.pad = pad; - - call_cb(&cbdata); - - return cbdata.u.check_get_range_data.ret; -} - -gboolean query_function_wrapper(GstPad *pad, GstQuery *query) +gboolean query_function_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) { struct cb_data cbdata = { QUERY_FUNCTION }; cbdata.u.query_function_data.pad = pad; + cbdata.u.query_function_data.parent = parent; cbdata.u.query_function_data.query = query; call_cb(&cbdata); @@ -124,16 +109,18 @@ gboolean query_function_wrapper(GstPad *pad, GstQuery *query) return cbdata.u.query_function_data.ret; } -gboolean activate_push_wrapper(GstPad *pad, gboolean activate) +gboolean activate_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) { - struct cb_data cbdata = { ACTIVATE_PUSH }; + struct cb_data cbdata = { ACTIVATE_MODE }; - cbdata.u.activate_push_data.pad = pad; - cbdata.u.activate_push_data.activate = activate; + cbdata.u.activate_mode_data.pad = pad; + cbdata.u.activate_mode_data.parent = parent; + cbdata.u.activate_mode_data.mode = mode; + cbdata.u.activate_mode_data.activate = activate; call_cb(&cbdata); - return cbdata.u.activate_push_data.ret; + return cbdata.u.activate_mode_data.ret; } void no_more_pads_wrapper(GstElement *decodebin, gpointer user) @@ -146,12 +133,13 @@ void no_more_pads_wrapper(GstElement *decodebin, gpointer user) call_cb(&cbdata); } -GstFlowReturn request_buffer_src_wrapper(GstPad *pad, guint64 ofs, guint len, +GstFlowReturn request_buffer_src_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len, GstBuffer **buf) { struct cb_data cbdata = { REQUEST_BUFFER_SRC }; cbdata.u.request_buffer_src_data.pad = pad; + cbdata.u.request_buffer_src_data.parent = parent; cbdata.u.request_buffer_src_data.ofs = ofs; cbdata.u.request_buffer_src_data.len = len; cbdata.u.request_buffer_src_data.buf = buf; @@ -161,11 +149,12 @@ GstFlowReturn request_buffer_src_wrapper(GstPad *pad, guint64 ofs, guint len, return cbdata.u.request_buffer_src_data.ret; } -gboolean event_src_wrapper(GstPad *pad, GstEvent *event) +gboolean event_src_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) { struct cb_data cbdata = { EVENT_SRC }; cbdata.u.event_src_data.pad = pad; + cbdata.u.event_src_data.parent = parent; cbdata.u.event_src_data.event = event; call_cb(&cbdata); @@ -173,11 +162,12 @@ gboolean event_src_wrapper(GstPad *pad, GstEvent *event) return cbdata.u.event_src_data.ret; } -gboolean event_sink_wrapper(GstPad *pad, GstEvent *event) +gboolean event_sink_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) { struct cb_data cbdata = { EVENT_SINK }; cbdata.u.event_sink_data.pad = pad; + cbdata.u.event_sink_data.parent = parent; cbdata.u.event_sink_data.event = event; call_cb(&cbdata); @@ -185,22 +175,6 @@ gboolean event_sink_wrapper(GstPad *pad, GstEvent *event) return cbdata.u.event_sink_data.ret; } -GstFlowReturn request_buffer_sink_wrapper(GstPad *pad, guint64 ofs, guint size, - GstCaps *caps, GstBuffer **buf) -{ - struct cb_data cbdata = { REQUEST_BUFFER_SINK }; - - cbdata.u.request_buffer_sink_data.pad = pad; - cbdata.u.request_buffer_sink_data.ofs = ofs; - cbdata.u.request_buffer_sink_data.size = size; - cbdata.u.request_buffer_sink_data.caps = caps; - cbdata.u.request_buffer_sink_data.buf = buf; - - call_cb(&cbdata); - - return cbdata.u.request_buffer_sink_data.ret; -} - gboolean accept_caps_sink_wrapper(GstPad *pad, GstCaps *caps) { struct cb_data cbdata = { ACCEPT_CAPS_SINK }; @@ -225,11 +199,12 @@ gboolean setcaps_sink_wrapper(GstPad *pad, GstCaps *caps) return cbdata.u.setcaps_sink_data.ret; } -GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstBuffer *buf) +GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf) { struct cb_data cbdata = { GOT_DATA_SINK }; cbdata.u.got_data_sink_data.pad = pad; + cbdata.u.got_data_sink_data.parent = parent; cbdata.u.got_data_sink_data.buf = buf; call_cb(&cbdata); @@ -237,11 +212,12 @@ GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstBuffer *buf) return cbdata.u.got_data_sink_data.ret; } -GstFlowReturn got_data_wrapper(GstPad *pad, GstBuffer *buf) +GstFlowReturn got_data_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf) { struct cb_data cbdata = { GOT_DATA }; cbdata.u.got_data_data.pad = pad; + cbdata.u.got_data_data.parent = parent; cbdata.u.got_data_data.buf = buf; call_cb(&cbdata); @@ -249,22 +225,6 @@ GstFlowReturn got_data_wrapper(GstPad *pad, GstBuffer *buf) return cbdata.u.got_data_data.ret; } -GstFlowReturn request_buffer_wrapper(GstPad *pad, guint64 ofs, guint size, - GstCaps *caps, GstBuffer **buf) -{ - struct cb_data cbdata = { REQUEST_BUFFER }; - - cbdata.u.request_buffer_data.pad = pad; - cbdata.u.request_buffer_data.ofs = ofs; - cbdata.u.request_buffer_data.size = size; - cbdata.u.request_buffer_data.caps = caps; - cbdata.u.request_buffer_data.buf = buf; - - call_cb(&cbdata); - - return cbdata.u.request_buffer_data.ret; -} - void removed_decoded_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) { struct cb_data cbdata = { REMOVED_DECODED_PAD }; @@ -323,3 +283,14 @@ void Gstreamer_transform_pad_added_wrapper(GstElement *filter, GstPad *pad, gpoi call_cb(&cbdata); } + +gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) +{ + struct cb_data cbdata = { QUERY_SINK, + { .query_sink_data = {pad, parent, query} } + }; + + call_cb(&cbdata); + + return cbdata.u.query_sink_data.ret; +} diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h index adb99a163de..e52d1bae8a2 100644 --- a/dlls/winegstreamer/gst_cbs.h +++ b/dlls/winegstreamer/gst_cbs.h @@ -32,24 +32,22 @@ typedef enum { enum CB_TYPE { WATCH_BUS, EXISTING_NEW_PAD, - CHECK_GET_RANGE, QUERY_FUNCTION, - ACTIVATE_PUSH, + ACTIVATE_MODE, NO_MORE_PADS, REQUEST_BUFFER_SRC, EVENT_SRC, EVENT_SINK, - REQUEST_BUFFER_SINK, ACCEPT_CAPS_SINK, SETCAPS_SINK, GOT_DATA_SINK, GOT_DATA, - REQUEST_BUFFER, REMOVED_DECODED_PAD, AUTOPLUG_BLACKLIST, UNKNOWN_TYPE, RELEASE_SAMPLE, - TRANSFORM_PAD_ADDED + TRANSFORM_PAD_ADDED, + QUERY_SINK }; struct cb_data { @@ -64,29 +62,28 @@ struct cb_data { struct existing_new_pad_data { GstElement *bin; GstPad *pad; - gboolean last; gpointer user; } existing_new_pad_data; - struct check_get_range_data { - GstPad *pad; - gboolean ret; - } check_get_range_data; struct query_function_data { GstPad *pad; + GstObject *parent; GstQuery *query; gboolean ret; } query_function_data; - struct activate_push_data { + struct activate_mode_data { GstPad *pad; + GstObject *parent; + GstPadMode mode; gboolean activate; gboolean ret; - } activate_push_data; + } activate_mode_data; struct no_more_pads_data { GstElement *decodebin; gpointer user; } no_more_pads_data; struct request_buffer_src_data { GstPad *pad; + GstObject *parent; guint64 ofs; guint len; GstBuffer **buf; @@ -94,22 +91,16 @@ struct cb_data { } request_buffer_src_data; struct event_src_data { GstPad *pad; + GstObject *parent; GstEvent *event; gboolean ret; } event_src_data; struct event_sink_data { GstPad *pad; + GstObject *parent; GstEvent *event; gboolean ret; } event_sink_data; - struct request_buffer_sink_data { - GstPad *pad; - guint64 ofs; - guint size; - GstCaps *caps; - GstBuffer **buf; - GstFlowReturn ret; - } request_buffer_sink_data; struct accept_caps_sink_data { GstPad *pad; GstCaps *caps; @@ -122,22 +113,16 @@ struct cb_data { } setcaps_sink_data; struct got_data_sink_data { GstPad *pad; + GstObject *parent; GstBuffer *buf; GstFlowReturn ret; } got_data_sink_data; struct got_data_data { GstPad *pad; + GstObject *parent; GstBuffer *buf; GstFlowReturn ret; } got_data_data; - struct request_buffer_data { - GstPad *pad; - guint64 ofs; - guint size; - GstCaps *caps; - GstBuffer **buf; - GstFlowReturn ret; - } request_buffer_data; struct removed_decoded_pad_data { GstElement *bin; GstPad *pad; @@ -165,6 +150,12 @@ struct cb_data { GstPad *pad; gpointer user; } transform_pad_added_data; + struct query_sink_data { + GstPad *pad; + GstObject *parent; + GstQuery *query; + gboolean ret; + } query_sink_data; } u; int finished; @@ -181,24 +172,22 @@ BOOL is_wine_thread(void) DECLSPEC_HIDDEN; void mark_wine_thread(void) DECLSPEC_HIDDEN; GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user) DECLSPEC_HIDDEN; -void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gboolean last, gpointer user) DECLSPEC_HIDDEN; -gboolean check_get_range_wrapper(GstPad *pad) DECLSPEC_HIDDEN; -gboolean query_function_wrapper(GstPad *pad, GstQuery *query) DECLSPEC_HIDDEN; -gboolean activate_push_wrapper(GstPad *pad, gboolean activate) DECLSPEC_HIDDEN; +void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN; +gboolean query_function_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN; +gboolean activate_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN; void no_more_pads_wrapper(GstElement *decodebin, gpointer user) DECLSPEC_HIDDEN; -GstFlowReturn request_buffer_src_wrapper(GstPad *pad, guint64 ofs, guint len, GstBuffer **buf) DECLSPEC_HIDDEN; -gboolean event_src_wrapper(GstPad *pad, GstEvent *event) DECLSPEC_HIDDEN; -gboolean event_sink_wrapper(GstPad *pad, GstEvent *event) DECLSPEC_HIDDEN; -GstFlowReturn request_buffer_sink_wrapper(GstPad *pad, guint64 ofs, guint size, GstCaps *caps, GstBuffer **buf) DECLSPEC_HIDDEN; +GstFlowReturn request_buffer_src_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len, GstBuffer **buf) DECLSPEC_HIDDEN; +gboolean event_src_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN; +gboolean event_sink_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN; gboolean accept_caps_sink_wrapper(GstPad *pad, GstCaps *caps) DECLSPEC_HIDDEN; gboolean setcaps_sink_wrapper(GstPad *pad, GstCaps *caps) DECLSPEC_HIDDEN; -GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstBuffer *buf) DECLSPEC_HIDDEN; -GstFlowReturn got_data_wrapper(GstPad *pad, GstBuffer *buf) DECLSPEC_HIDDEN; -GstFlowReturn request_buffer_wrapper(GstPad *pad, guint64 ofs, guint size, GstCaps *caps, GstBuffer **buf) DECLSPEC_HIDDEN; +GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf) DECLSPEC_HIDDEN; +GstFlowReturn got_data_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf) DECLSPEC_HIDDEN; void removed_decoded_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN; GstAutoplugSelectResult autoplug_blacklist_wrapper(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user) DECLSPEC_HIDDEN; void unknown_type_wrapper(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user) DECLSPEC_HIDDEN; void release_sample_wrapper(gpointer data) DECLSPEC_HIDDEN; void Gstreamer_transform_pad_added_wrapper(GstElement *filter, GstPad *pad, gpointer user) DECLSPEC_HIDDEN; +gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN; #endif diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 2f145ed6823..4b29f21a298 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -44,10 +44,12 @@ IUnknown * CALLBACK Gstreamer_Splitter_create(IUnknown *pUnkOuter, HRESULT *phr) DWORD Gstreamer_init(void); -GstFlowReturn got_data(GstPad *pad, GstBuffer *buf) DECLSPEC_HIDDEN; +GstFlowReturn got_data(GstPad *pad, GstObject *parent, GstBuffer *buf) DECLSPEC_HIDDEN; GstFlowReturn request_buffer(GstPad *pad, guint64 ofs, guint size, GstCaps *caps, GstBuffer **buf) DECLSPEC_HIDDEN; void Gstreamer_transform_pad_added(GstElement *filter, GstPad *pad, gpointer user) DECLSPEC_HIDDEN; void start_dispatch_thread(void) DECLSPEC_HIDDEN; +extern const char *media_quark_string DECLSPEC_HIDDEN; + #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c index 3063cfd4097..58b187b34f9 100644 --- a/dlls/winegstreamer/gstdemux.c +++ b/dlls/winegstreamer/gstdemux.c @@ -20,10 +20,10 @@ */ #include "config.h" -#include -#include -#include -#include + +#include +#include +#include #include "gst_private.h" #include "gst_guids.h" @@ -63,7 +63,7 @@ typedef struct GSTImpl { LONGLONG filesize; - BOOL discont, initial; + BOOL discont, initial, ignore_flush; GstElement *gstfilter; GstPad *my_src, *their_sink; GstBus *bus; @@ -80,6 +80,7 @@ struct GSTOutPin { GstPad *their_src; GstPad *my_sink; + GstBufferPool *gstpool; int isaud, isvid; AM_MEDIA_TYPE * pmt; HANDLE caps_event; @@ -87,6 +88,8 @@ struct GSTOutPin { SourceSeeking seek; }; +const char* media_quark_string = "media-sample"; + static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; static const IMediaSeekingVtbl GST_Seeking_Vtbl; static const IPinVtbl GST_OutputPin_Vtbl; @@ -115,13 +118,10 @@ static gboolean amt_from_gst_caps_audio(GstCaps *caps, AM_MEDIA_TYPE *amt) { WAVEFORMATEXTENSIBLE *wfe; WAVEFORMATEX *wfx; - GstStructure *arg; gint32 depth = 0, bpp = 0; - const char *typename; + GstAudioInfo ainfo; - arg = gst_caps_get_structure(caps, 0); - typename = gst_structure_get_name(arg); - if (!typename) + if (!gst_audio_info_from_caps (&ainfo, caps)) return FALSE; wfe = CoTaskMemAlloc(sizeof(*wfe)); @@ -137,12 +137,12 @@ static gboolean amt_from_gst_caps_audio(GstCaps *caps, AM_MEDIA_TYPE *amt) amt->pUnk = NULL; wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE; - if (!gst_structure_get_int(arg, "channels", (INT*)&wfx->nChannels)) - return FALSE; - if (!gst_structure_get_int(arg, "rate", (INT*)&wfx->nSamplesPerSec)) - return FALSE; - gst_structure_get_int(arg, "width", &depth); - gst_structure_get_int(arg, "depth", &bpp); + + wfx->nChannels = ainfo.channels; + wfx->nSamplesPerSec = ainfo.rate; + depth = GST_AUDIO_INFO_WIDTH(&ainfo); + bpp = GST_AUDIO_INFO_DEPTH(&ainfo); + if (!depth || depth > 32 || depth % 8) depth = bpp; else if (!bpp) @@ -160,7 +160,7 @@ static gboolean amt_from_gst_caps_audio(GstCaps *caps, AM_MEDIA_TYPE *amt) default: wfe->dwChannelMask = 0; } - if (!strcmp(typename, "audio/x-raw-float")) { + if (GST_AUDIO_INFO_IS_FLOAT(&ainfo)) { wfe->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; wfx->wBitsPerSample = wfe->Samples.wValidBitsPerSample = 32; } else { @@ -179,19 +179,15 @@ static gboolean amt_from_gst_caps_video(GstCaps *caps, AM_MEDIA_TYPE *amt) { VIDEOINFOHEADER *vih = CoTaskMemAlloc(sizeof(*vih)); BITMAPINFOHEADER *bih = &vih->bmiHeader; - GstStructure *arg; gint32 width = 0, height = 0, nom = 0, denom = 0; - const char *typename; + GstVideoInfo vinfo; - arg = gst_caps_get_structure(caps, 0); - typename = gst_structure_get_name(arg); - if (!typename) - return FALSE; - - if (!gst_structure_get_int(arg, "width", &width) || - !gst_structure_get_int(arg, "height", &height) || - !gst_structure_get_fraction(arg, "framerate", &nom, &denom)) + if (!gst_video_info_from_caps (&vinfo, caps)) return FALSE; + width = vinfo.width; + height = vinfo.height; + nom = vinfo.fps_n; + denom = vinfo.fps_d; amt->formattype = FORMAT_VideoInfo; amt->pbFormat = (BYTE*)vih; @@ -201,9 +197,8 @@ static gboolean amt_from_gst_caps_video(GstCaps *caps, AM_MEDIA_TYPE *amt) amt->pUnk = NULL; ZeroMemory(vih, sizeof(*vih)); amt->majortype = MEDIATYPE_Video; - if (!strcmp(typename, "video/x-raw-rgb")) { - if (!gst_structure_get_int(arg, "bpp", (INT*)&bih->biBitCount)) - return FALSE; + if (GST_VIDEO_INFO_IS_RGB(&vinfo)) { + bih->biBitCount = GST_VIDEO_FORMAT_INFO_BITS(vinfo.finfo); switch (bih->biBitCount) { case 16: amt->subtype = MEDIASUBTYPE_RGB555; break; case 24: amt->subtype = MEDIASUBTYPE_RGB24; break; @@ -215,7 +210,7 @@ static gboolean amt_from_gst_caps_video(GstCaps *caps, AM_MEDIA_TYPE *amt) bih->biCompression = BI_RGB; } else { amt->subtype = MEDIATYPE_Video; - if (!gst_structure_get_fourcc(arg, "format", &amt->subtype.Data1)) + if (!(amt->subtype.Data1 = gst_video_format_to_fourcc(vinfo.finfo->format))) return FALSE; switch (amt->subtype.Data1) { case mmioFOURCC('I','4','2','0'): @@ -257,8 +252,7 @@ static gboolean accept_caps_sink(GstPad *pad, GstCaps *caps) arg = gst_caps_get_structure(caps, 0); typename = gst_structure_get_name(arg); - if (!strcmp(typename, "audio/x-raw-int") || - !strcmp(typename, "audio/x-raw-float")) { + if (!strcmp(typename, "audio/x-raw")) { if (!pin->isaud) { ERR("Setting audio caps on non-audio pad?\n"); return FALSE; @@ -267,8 +261,7 @@ static gboolean accept_caps_sink(GstPad *pad, GstCaps *caps) FreeMediaType(&amt); TRACE("+%i\n", ret); return ret; - } else if (!strcmp(typename, "video/x-raw-rgb") - || !strcmp(typename, "video/x-raw-yuv")) { + } else if (!strcmp(typename, "video/x-raw")) { if (!pin->isvid) { ERR("Setting video caps on non-video pad?\n"); return FALSE; @@ -296,15 +289,13 @@ static gboolean setcaps_sink(GstPad *pad, GstCaps *caps) arg = gst_caps_get_structure(caps, 0); typename = gst_structure_get_name(arg); - if (!strcmp(typename, "audio/x-raw-int") || - !strcmp(typename, "audio/x-raw-float")) { + if (!strcmp(typename, "audio/x-raw")) { if (!pin->isaud) { ERR("Setting audio caps on non-audio pad?\n"); return FALSE; } ret = amt_from_gst_caps_audio(caps, &amt); - } else if (!strcmp(typename, "video/x-raw-rgb") - || !strcmp(typename, "video/x-raw-yuv")) { + } else if (!strcmp(typename, "video/x-raw")) { if (!pin->isvid) { ERR("Setting video caps on non-video pad?\n"); return FALSE; @@ -324,6 +315,23 @@ static gboolean setcaps_sink(GstPad *pad, GstCaps *caps) return TRUE; } +static gboolean query_sink(GstPad *pad, GstObject *parent, GstQuery *query) +{ + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_ACCEPT_CAPS: + { + GstCaps *caps; + gboolean res; + gst_query_parse_accept_caps(query, &caps); + res = accept_caps_sink(pad, caps); + gst_query_set_accept_caps_result(query, res); + return TRUE; /* FIXME */ + } + default: + return gst_pad_query_default (pad, parent, query); + } +} + static gboolean gst_base_src_perform_seek(GSTImpl *This, GstEvent *event) { gboolean res = TRUE; @@ -358,26 +366,26 @@ static gboolean gst_base_src_perform_seek(GSTImpl *This, GstEvent *event) if (This->pInputPin.pReader) IAsyncReader_BeginFlush(This->pInputPin.pReader); if (thread) - gst_pad_activate_push(This->my_src, 0); + gst_pad_set_active(This->my_src, 1); } This->nextofs = This->start = cur; /* and prepare to continue streaming */ if (flush) { - tevent = gst_event_new_flush_stop(); + tevent = gst_event_new_flush_stop(TRUE); gst_event_set_seqnum(tevent, seqnum); gst_pad_push_event(This->my_src, tevent); if (This->pInputPin.pReader) IAsyncReader_EndFlush(This->pInputPin.pReader); if (thread) - gst_pad_activate_push(This->my_src, 1); + gst_pad_set_active(This->my_src, 1); } return res; } -static gboolean event_src(GstPad *pad, GstEvent *event) +static gboolean event_src(GstPad *pad, GstObject *parent, GstEvent *event) { GSTImpl *This = gst_pad_get_element_private(pad); @@ -402,34 +410,45 @@ static gboolean event_src(GstPad *pad, GstEvent *event) FIXME("%p (%u) stub\n", event, event->type); case GST_EVENT_TAG: case GST_EVENT_QOS: - return gst_pad_event_default(pad, event); + return gst_pad_event_default(pad, parent, event); } return TRUE; } -static gboolean event_sink(GstPad *pad, GstEvent *event) +static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event) { GSTOutPin *pin = gst_pad_get_element_private(pad); TRACE("%p %p\n", pad, event); switch (event->type) { - case GST_EVENT_NEWSEGMENT: { - gboolean update; + case GST_EVENT_SEGMENT: { gdouble rate, applied_rate; - GstFormat format; - gint64 start, stop, pos; - gst_event_parse_new_segment_full(event, &update, &rate, &applied_rate, &format, &start, &stop, &pos); - if (format != GST_FORMAT_TIME) { - FIXME("Ignoring new segment because of format %i\n", format); + gint64 stop, pos; + const GstSegment *segment; + + gst_event_parse_segment(event, &segment); + + pos = segment->position; + stop = segment->stop; + rate = segment->rate; + applied_rate = segment->applied_rate; + + if (segment->format != GST_FORMAT_TIME) { + FIXME("Ignoring new segment because of format %i\n", segment->format); return TRUE; } - gst_segment_set_newsegment_full(pin->segment, update, rate, applied_rate, format, start, stop, pos); + + gst_segment_copy_into(segment, pin->segment); + pos /= 100; + if (stop > 0) stop /= 100; + if (pin->pin.pin.pConnectedTo) IPin_NewSegment(pin->pin.pin.pConnectedTo, pos, stop, rate*applied_rate); + return TRUE; } case GST_EVENT_EOS: @@ -437,6 +456,17 @@ static gboolean event_sink(GstPad *pad, GstEvent *event) IPin_EndOfStream(pin->pin.pin.pConnectedTo); return TRUE; case GST_EVENT_FLUSH_START: + if (((GSTImpl *)pin->pin.pin.pinInfo.pFilter)->ignore_flush) { + /* gst-plugins-base prior to 1.7 contains a bug which causes + * our sink pins to receive a flush-start event when the + * decodebin changes from PAUSED to READY (including + * PLAYING->PAUSED->READY), but no matching flush-stop event is + * sent. See pin.pin.pConnectedTo) IPin_BeginFlush(pin->pin.pin.pConnectedTo); return TRUE; @@ -445,9 +475,14 @@ static gboolean event_sink(GstPad *pad, GstEvent *event) if (pin->pin.pin.pConnectedTo) IPin_EndFlush(pin->pin.pin.pConnectedTo); return TRUE; + case GST_EVENT_CAPS: { + GstCaps *caps; + gst_event_parse_caps(event, &caps); + return setcaps_sink(pad, caps); + } default: - FIXME("%p stub %s\n", event, gst_event_type_get_name(event->type)); - return gst_pad_event_default(pad, event); + TRACE("%p stub %s\n", event, gst_event_type_get_name(event->type)); + return gst_pad_event_default(pad, parent, event); } } @@ -471,14 +506,20 @@ static DWORD CALLBACK push_data(LPVOID iface) else maxlen = This->stop; + TRACE("Waiting..\n"); + + WaitForSingleObject(This->event, INFINITE); + TRACE("Starting..\n"); for (;;) { REFERENCE_TIME tStart, tStop; ULONG len; GstBuffer *gstbuf; + gsize bufsize; BYTE *data; int ret; + TRACE("pAlloc: %p\n", This->pInputPin.pAlloc); hr = IMemAllocator_GetBuffer(This->pInputPin.pAlloc, &buf, NULL, NULL, 0); if (FAILED(hr)) break; @@ -507,12 +548,15 @@ static DWORD CALLBACK push_data(LPVOID iface) } IMediaSample_GetPointer(buf, &data); - gstbuf = gst_app_buffer_new(data, IMediaSample_GetActualDataLength(buf), release_sample_wrapper, buf); + bufsize = IMediaSample_GetActualDataLength(buf); + gstbuf = gst_buffer_new_wrapped_full(0, data, bufsize, 0, bufsize, buf, release_sample_wrapper); + IMediaSample_AddRef(buf); + gst_mini_object_set_qdata(GST_MINI_OBJECT(gstbuf), g_quark_from_static_string(media_quark_string), buf, release_sample_wrapper); if (!gstbuf) { IMediaSample_Release(buf); break; } - gstbuf->duration = gstbuf->timestamp = -1; + gstbuf->duration = gstbuf->pts = -1; ret = gst_pad_push(This->my_src, gstbuf); if (ret >= 0) hr = S_OK; @@ -520,10 +564,8 @@ static DWORD CALLBACK push_data(LPVOID iface) ERR("Sending returned: %i\n", ret); if (ret == GST_FLOW_ERROR) hr = E_FAIL; - else if (ret == GST_FLOW_WRONG_STATE) + else if (ret == GST_FLOW_FLUSHING) hr = VFW_E_WRONG_STATE; - else if (ret == GST_FLOW_RESEND) - hr = S_FALSE; if (hr != S_OK) break; } @@ -548,13 +590,14 @@ static HRESULT WINAPI GST_OutPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *p return S_OK; } -static GstFlowReturn got_data_sink(GstPad *pad, GstBuffer *buf) +static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *buf) { GSTOutPin *pin = gst_pad_get_element_private(pad); GSTImpl *This = (GSTImpl *)pin->pin.pin.pinInfo.pFilter; - IMediaSample *sample; HRESULT hr; - BOOL freeSamp = FALSE; + BYTE *ptr = NULL; + IMediaSample *sample; + GstMapInfo info; TRACE("%p %p\n", pad, buf); @@ -562,44 +605,46 @@ static GstFlowReturn got_data_sink(GstPad *pad, GstBuffer *buf) gst_buffer_unref(buf); TRACE("Triggering %p %p\n", pad, pin->caps_event); SetEvent(pin->caps_event); + return GST_FLOW_OK; + } + + hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0); + + if (hr == VFW_E_NOT_CONNECTED) { + gst_buffer_unref(buf); return GST_FLOW_NOT_LINKED; } - if (GST_IS_APP_BUFFER(buf)) { - sample = GST_APP_BUFFER(buf)->priv; - TRACE("Pushing buffer\n"); - } else if (buf->parent && GST_IS_APP_BUFFER(buf->parent)) { - sample = GST_APP_BUFFER(buf->parent)->priv; - TRACE("Pushing sub-buffer\n"); - } else { - BYTE *ptr = NULL; - hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0); - freeSamp = TRUE; - if (hr == VFW_E_NOT_CONNECTED) { - gst_buffer_unref(buf); - return GST_FLOW_NOT_LINKED; - } - if (FAILED(hr)) { - gst_buffer_unref(buf); - ERR("Didn't get a GST_APP_BUFFER, and could not get a delivery buffer (%x), returning GST_FLOW_WRONG_STATE\n", hr); - return GST_FLOW_WRONG_STATE; - } - TRACE("Did not get a GST_APP_BUFFER, creating a sample\n"); - IMediaSample_GetPointer(sample, &ptr); - memcpy(ptr, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf)); + if (FAILED(hr)) { + gst_buffer_unref(buf); + ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr); + return GST_FLOW_FLUSHING; } - IMediaSample_SetActualDataLength(sample, GST_BUFFER_SIZE(buf)); - if (GST_BUFFER_TIMESTAMP_IS_VALID(buf)) { - REFERENCE_TIME rtStart = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->timestamp); + gst_buffer_map(buf, &info, GST_MAP_READ); + + hr = IMediaSample_SetActualDataLength(sample, info.size); + if(FAILED(hr)){ + WARN("SetActualDataLength failed: %08x\n", hr); + return GST_FLOW_FLUSHING; + } + + IMediaSample_GetPointer(sample, &ptr); + + memcpy(ptr, info.data, info.size); + + gst_buffer_unmap(buf, &info); + + if (GST_BUFFER_PTS_IS_VALID(buf)) { + REFERENCE_TIME rtStart = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->pts); if (rtStart >= 0) rtStart /= 100; if (GST_BUFFER_DURATION_IS_VALID(buf)) { - REFERENCE_TIME tStart = buf->timestamp / 100; - REFERENCE_TIME tStop = (buf->timestamp + buf->duration) / 100; + REFERENCE_TIME tStart = buf->pts / 100; + REFERENCE_TIME tStop = (buf->pts + buf->duration) / 100; REFERENCE_TIME rtStop; - rtStop = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->timestamp + buf->duration); + rtStop = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->pts + buf->duration); if (rtStop >= 0) rtStop /= 100; TRACE("Current time on %p: %i to %i ms\n", pin, (int)(rtStart / 10000), (int)(rtStop / 10000)); @@ -615,73 +660,33 @@ static GstFlowReturn got_data_sink(GstPad *pad, GstBuffer *buf) } IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT)); - IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_PREROLL)); + IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LIVE)); IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)); if (!pin->pin.pin.pConnectedTo) hr = VFW_E_NOT_CONNECTED; else hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample); - TRACE("sending sample: %08x\n", hr); + + TRACE("sending sample returned: %08x\n", hr); + gst_buffer_unref(buf); - if (freeSamp) - IMediaSample_Release(sample); + IMediaSample_Release(sample); + if (hr == VFW_E_NOT_CONNECTED) return GST_FLOW_NOT_LINKED; - else if (FAILED(hr)) - return GST_FLOW_WRONG_STATE; - if (hr != S_OK) - return GST_FLOW_RESEND; + + if (FAILED(hr)) + return GST_FLOW_FLUSHING; + return GST_FLOW_OK; } -static GstFlowReturn request_buffer_sink(GstPad *pad, guint64 ofs, guint size, GstCaps *caps, GstBuffer **buf) -{ - GSTOutPin *pin = gst_pad_get_element_private(pad); - GSTImpl *This = (GSTImpl *)pin->pin.pin.pinInfo.pFilter; - IMediaSample *sample; - BYTE *ptr; - HRESULT hr; - - TRACE("%p %s %i %p %p\n", pad, wine_dbgstr_longlong(ofs), size, caps, buf); - - if (This->initial) { - int ret; - ret = setcaps_sink(pad, caps); - if (!ret) - return GST_FLOW_NOT_NEGOTIATED; - *buf = gst_buffer_new_and_alloc(size); - return GST_FLOW_OK; - } - - if (caps && caps != GST_PAD_CAPS(pad)) - if (!setcaps_sink(pad, caps)) - return GST_FLOW_NOT_NEGOTIATED; - - hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0); - if (hr == VFW_E_NOT_CONNECTED) - return GST_FLOW_NOT_LINKED; - if (FAILED(hr)) { - ERR("Could not get output buffer: %08x\n", hr); - *buf = NULL; - return GST_FLOW_WRONG_STATE; - } - IMediaSample_SetActualDataLength(sample, size); - IMediaSample_GetPointer(sample, &ptr); - *buf = gst_app_buffer_new(ptr, size, release_sample_wrapper, sample); - if (!*buf) { - IMediaSample_Release(sample); - ERR("Out of memory\n"); - return GST_FLOW_ERROR; - } - gst_buffer_set_caps(*buf, caps); - return GST_FLOW_OK; -} - -static GstFlowReturn request_buffer_src(GstPad *pad, guint64 ofs, guint len, GstBuffer **buf) +static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 ofs, guint len, GstBuffer **buf) { GSTImpl *This = gst_pad_get_element_private(pad); - int ret; + HRESULT hr; + GstMapInfo info; TRACE("%p %s %i %p\n", pad, wine_dbgstr_longlong(ofs), len, buf); @@ -690,22 +695,21 @@ static GstFlowReturn request_buffer_src(GstPad *pad, guint64 ofs, guint len, Gst ofs = This->nextpullofs; if (ofs >= This->filesize) { WARN("Reading past eof: %s, %u\n", wine_dbgstr_longlong(ofs), len); - return GST_FLOW_UNEXPECTED; + return GST_FLOW_EOS; } if (len + ofs > This->filesize) len = This->filesize - ofs; This->nextpullofs = ofs + len; - ret = gst_pad_alloc_buffer(This->my_src, ofs, len, NULL, buf); - if (ret >= 0) { - HRESULT hr; - hr = IAsyncReader_SyncRead(This->pInputPin.pReader, ofs, len, GST_BUFFER_DATA(*buf)); - if (FAILED(hr)) { - ERR("Returned %08x\n", hr); - return GST_FLOW_ERROR; - } + *buf = gst_buffer_new_and_alloc(len); + gst_buffer_map(*buf, &info, GST_MAP_WRITE); + hr = IAsyncReader_SyncRead(This->pInputPin.pReader, ofs, len, info.data); + gst_buffer_unmap(*buf, &info); + if (FAILED(hr)) { + ERR("Returned %08x\n", hr); + return GST_FLOW_ERROR; } - return ret; + return GST_FLOW_OK; } static DWORD CALLBACK push_data_init(LPVOID iface) @@ -716,7 +720,7 @@ static DWORD CALLBACK push_data_init(LPVOID iface) TRACE("Starting..\n"); for (;;) { GstBuffer *buf; - GstFlowReturn ret = request_buffer_src(This->my_src, ofs, 4096, &buf); + GstFlowReturn ret = request_buffer_src(This->my_src, NULL, ofs, 4096, &buf); if (ret < 0) { ERR("Obtaining buffer returned: %i\n", ret); break; @@ -756,7 +760,7 @@ out: LeaveCriticalSection(&This->filter.csFilter); } -static void init_new_decoded_pad(GstElement *bin, GstPad *pad, gboolean last, GSTImpl *This) +static void init_new_decoded_pad(GstElement *bin, GstPad *pad, GSTImpl *This) { HRESULT hr; PIN_INFO piOutput; @@ -769,44 +773,45 @@ static void init_new_decoded_pad(GstElement *bin, GstPad *pad, gboolean last, GS GSTOutPin *pin; int ret; int isvid = 0, isaud = 0; + gchar my_name[1024]; - TRACE("%p %p %p %u\n", This, bin, pad, last); + TRACE("%p %p %p\n", This, bin, pad); piOutput.dir = PINDIR_OUTPUT; piOutput.pFilter = (IBaseFilter *)This; name = gst_pad_get_name(pad); MultiByteToWideChar(CP_UNIXCP, 0, name, -1, piOutput.achName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]) - 1); TRACE("Name: %s\n", name); + strcpy(my_name, "qz_sink_"); + strcat(my_name, name); g_free(name); piOutput.achName[sizeof(piOutput.achName) / sizeof(piOutput.achName[0]) - 1] = 0; - caps = gst_pad_get_caps_reffed(pad); + caps = gst_pad_query_caps(pad, NULL); + caps = gst_caps_make_writable(caps); arg = gst_caps_get_structure(caps, 0); typename = gst_structure_get_name(arg); - mypad = gst_pad_new(NULL, GST_PAD_SINK); + mypad = gst_pad_new(my_name, GST_PAD_SINK); gst_pad_set_chain_function(mypad, got_data_sink_wrapper); gst_pad_set_event_function(mypad, event_sink_wrapper); - gst_pad_set_bufferalloc_function(mypad, request_buffer_sink_wrapper); - gst_pad_set_acceptcaps_function(mypad, accept_caps_sink_wrapper); - gst_pad_set_setcaps_function(mypad, setcaps_sink_wrapper); + gst_pad_set_query_function(mypad, query_sink_wrapper); - if (!strcmp(typename, "audio/x-raw-int") || - !strcmp(typename, "audio/x-raw-float")) { + if (!strcmp(typename, "audio/x-raw")) { isaud = 1; - } else if (!strcmp(typename, "video/x-raw-rgb") - || !strcmp(typename, "video/x-raw-yuv")) { + } else if (!strcmp(typename, "video/x-raw")) { isvid = 1; } else { FIXME("Unknown type \'%s\'\n", typename); return; } - GST_PAD_CAPS(mypad) = GST_CAPS_ANY; + hr = GST_AddPin(This, &piOutput, &amt); if (FAILED(hr)) { ERR("%08x\n", hr); return; } + pin = This->ppPins[This->cStreams - 1]; gst_pad_set_element_private(mypad, pin); pin->my_sink = mypad; @@ -815,27 +820,30 @@ static void init_new_decoded_pad(GstElement *bin, GstPad *pad, gboolean last, GS gst_segment_init(pin->segment, GST_FORMAT_TIME); ret = gst_pad_link(pad, mypad); - gst_pad_activate_push(mypad, 1); + + gst_pad_set_active(mypad, 1); + TRACE("Linking: %i\n", ret); + if (ret >= 0) { pin->their_src = pad; gst_object_ref(pin->their_src); } } -static void existing_new_pad(GstElement *bin, GstPad *pad, gboolean last, gpointer user) +static void existing_new_pad(GstElement *bin, GstPad *pad, gpointer user) { GSTImpl *This = (GSTImpl*)user; int x; - TRACE("%p %p %p %u\n", This, bin, pad, last); + TRACE("%p %p %p\n", This, bin, pad); if (gst_pad_is_linked(pad)) return; /* Still holding our own lock */ if (This->initial) { - init_new_decoded_pad(bin, pad, last, This); + init_new_decoded_pad(bin, pad, This); return; } @@ -853,17 +861,11 @@ static void existing_new_pad(GstElement *bin, GstPad *pad, gboolean last, gpoint } } } - init_new_decoded_pad(bin, pad, last, This); + init_new_decoded_pad(bin, pad, This); LeaveCriticalSection(&This->filter.csFilter); } -static gboolean check_get_range(GstPad *pad) -{ - TRACE("%p\n", pad); - return TRUE; -} - -static gboolean query_function(GstPad *pad, GstQuery *query) +static gboolean query_function(GstPad *pad, GstObject *parent, GstQuery *query) { GSTImpl *This = gst_pad_get_element_private(pad); GstFormat format; @@ -879,7 +881,7 @@ static gboolean query_function(GstPad *pad, GstQuery *query) gst_query_set_duration (query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX); return TRUE; } - ret = gst_pad_query_convert (pad, GST_FORMAT_BYTES, This->filesize, &format, &duration); + ret = gst_pad_query_convert (pad, GST_FORMAT_BYTES, This->filesize, format, &duration); gst_query_set_duration(query, format, duration); return ret; case GST_QUERY_SEEKING: @@ -889,10 +891,13 @@ static gboolean query_function(GstPad *pad, GstQuery *query) return FALSE; gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, This->filesize); return TRUE; + case GST_QUERY_SCHEDULING: + gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); + return TRUE; default: - FIXME("Unhandled query type %i\n", GST_QUERY_TYPE(query)); - case GST_QUERY_URI: - case GST_QUERY_CONVERT: + TRACE("Unhandled query type: %s\n", GST_QUERY_TYPE_NAME(query)); return FALSE; } } @@ -928,6 +933,20 @@ static gboolean activate_push(GstPad *pad, gboolean activate) return TRUE; } +static gboolean activate_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) +{ + TRACE("%p %p 0x%x %u\n", pad, parent, mode, activate); + switch (mode) { + case GST_PAD_MODE_PULL: + return TRUE; + case GST_PAD_MODE_PUSH: + return activate_push(pad, activate); + default: + return FALSE; + } + return FALSE; +} + static void no_more_pads(GstElement *decodebin, gpointer user) { GSTImpl *This = (GSTImpl*)user; @@ -988,7 +1007,6 @@ static HRESULT GST_Connect(GSTInPin *pPin, IPin *pConnectPin, ALLOCATOR_PROPERTI HRESULT hr; int ret, i; LONGLONG avail, duration; - GstFormat format = GST_FORMAT_TIME; GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE( "quartz_src", GST_PAD_SRC, @@ -1002,33 +1020,31 @@ static HRESULT GST_Connect(GSTInPin *pPin, IPin *pConnectPin, ALLOCATOR_PROPERTI if (!This->bus) { This->bus = gst_bus_new(); - gst_bus_set_sync_handler(This->bus, watch_bus_wrapper, This); + gst_bus_set_sync_handler(This->bus, watch_bus_wrapper, This, NULL); } - This->gstfilter = gst_element_factory_make("decodebin2", NULL); + This->gstfilter = gst_element_factory_make("decodebin", NULL); if (!This->gstfilter) { FIXME("Could not make source filter, are gstreamer-plugins-* installed for %u bits?\n", 8 * (int)sizeof(void*)); return E_FAIL; } gst_element_set_bus(This->gstfilter, This->bus); - g_signal_connect(This->gstfilter, "new-decoded-pad", G_CALLBACK(existing_new_pad_wrapper), This); + g_signal_connect(This->gstfilter, "pad-added", G_CALLBACK(existing_new_pad_wrapper), This); g_signal_connect(This->gstfilter, "pad-removed", G_CALLBACK(removed_decoded_pad_wrapper), This); g_signal_connect(This->gstfilter, "autoplug-select", G_CALLBACK(autoplug_blacklist_wrapper), This); g_signal_connect(This->gstfilter, "unknown-type", G_CALLBACK(unknown_type_wrapper), This); This->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); gst_pad_set_getrange_function(This->my_src, request_buffer_src_wrapper); - gst_pad_set_checkgetrange_function(This->my_src, check_get_range_wrapper); gst_pad_set_query_function(This->my_src, query_function_wrapper); - gst_pad_set_activatepush_function(This->my_src, activate_push_wrapper); + gst_pad_set_activatemode_function(This->my_src, activate_mode_wrapper); gst_pad_set_event_function(This->my_src, event_src_wrapper); gst_pad_set_element_private (This->my_src, This); This->their_sink = gst_element_get_static_pad(This->gstfilter, "sink"); g_signal_connect(This->gstfilter, "no-more-pads", G_CALLBACK(no_more_pads_wrapper), This); ret = gst_pad_link(This->my_src, This->their_sink); - gst_object_unref(This->their_sink); if (ret < 0) { ERR("Returns: %i\n", ret); return E_FAIL; @@ -1039,7 +1055,6 @@ static HRESULT GST_Connect(GSTInPin *pPin, IPin *pConnectPin, ALLOCATOR_PROPERTI This->initial = This->discont = TRUE; ResetEvent(This->event); gst_element_set_state(This->gstfilter, GST_STATE_PLAYING); - gst_pad_set_active(This->my_src, 1); WaitForSingleObject(This->event, -1); gst_element_get_state(This->gstfilter, NULL, NULL, -1); @@ -1050,7 +1065,7 @@ static HRESULT GST_Connect(GSTInPin *pPin, IPin *pConnectPin, ALLOCATOR_PROPERTI FIXME("GStreamer could not find any streams\n"); hr = E_FAIL; } else { - gst_pad_query_duration(This->ppPins[0]->their_src, &format, &duration); + gst_pad_query_duration(This->ppPins[0]->their_src, GST_FORMAT_TIME, &duration); for (i = 0; i < This->cStreams; ++i) { This->ppPins[i]->seek.llDuration = This->ppPins[i]->seek.llStop = duration / 100; This->ppPins[i]->seek.llCurrent = 0; @@ -1061,12 +1076,18 @@ static HRESULT GST_Connect(GSTInPin *pPin, IPin *pConnectPin, ALLOCATOR_PROPERTI hr = S_OK; } *props = This->props; + + This->ignore_flush = TRUE; gst_element_set_state(This->gstfilter, GST_STATE_READY); gst_element_get_state(This->gstfilter, NULL, NULL, -1); - if (This->push_thread) - gst_pad_activate_push(This->my_src, 0); + This->ignore_flush = FALSE; This->initial = FALSE; + + /* don't set active during test-play, as we don't want to push/pull data + * from the source yet */ + gst_pad_set_active(This->my_src, 1); + This->nextofs = This->nextpullofs = 0; return hr; } @@ -1184,7 +1205,7 @@ static void GST_Destroy(GSTImpl *This) pinref = IPin_Release((IPin *)&This->pInputPin); } if (This->bus) { - gst_bus_set_sync_handler(This->bus, NULL, NULL); + gst_bus_set_sync_handler(This->bus, NULL, NULL, NULL); gst_object_unref(This->bus); } BaseFilter_Destroy(&This->filter); @@ -1241,8 +1262,12 @@ static HRESULT WINAPI GST_Stop(IBaseFilter *iface) mark_wine_thread(); - if (This->gstfilter) + if (This->gstfilter) { + This->ignore_flush = TRUE; gst_element_set_state(This->gstfilter, GST_STATE_READY); + gst_element_get_state(This->gstfilter, NULL, NULL, -1); + This->ignore_flush = FALSE; + } return S_OK; } @@ -1304,23 +1329,16 @@ static HRESULT WINAPI GST_Run(IBaseFilter *iface, REFERENCE_TIME tStart) } EnterCriticalSection(&This->filter.csFilter); - gst_pad_set_blocked(This->my_src, 0); - gst_pad_set_blocked(This->their_sink, 0); gst_element_set_state(This->gstfilter, GST_STATE_PLAYING); This->filter.rtStreamStart = tStart; for (i = 0; i < This->cStreams; i++) { hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[i]); if (SUCCEEDED(hr)) { - gst_pad_set_blocked(This->ppPins[i]->my_sink, 0); - if (This->ppPins[i]->their_src) - gst_pad_set_blocked(This->ppPins[i]->their_src, 0); hr_any = hr; } } hr = hr_any; - if (SUCCEEDED(hr)) - gst_pad_set_active(This->my_src, 1); LeaveCriticalSection(&This->filter.csFilter); return hr; @@ -1425,7 +1443,6 @@ static ULONG WINAPI GST_Seeking_Release(IMediaSeeking *iface) static HRESULT WINAPI GST_Seeking_GetCurrentPosition(IMediaSeeking *iface, REFERENCE_TIME *pos) { GSTOutPin *This = impl_from_IMediaSeeking(iface); - GstFormat format = GST_FORMAT_TIME; TRACE("(%p)->(%p)\n", This, pos); @@ -1443,7 +1460,7 @@ static HRESULT WINAPI GST_Seeking_GetCurrentPosition(IMediaSeeking *iface, REFER return E_NOTIMPL; } - if (!gst_pad_query_position(This->their_src, &format, pos)) { + if (!gst_pad_query_position(This->their_src, GST_FORMAT_TIME, pos)) { WARN("Could not query position\n"); return E_NOTIMPL; } @@ -1455,10 +1472,13 @@ static HRESULT WINAPI GST_Seeking_GetCurrentPosition(IMediaSeeking *iface, REFER static GstSeekType type_from_flags(DWORD flags) { switch (flags & AM_SEEKING_PositioningBitsMask) { - case AM_SEEKING_NoPositioning: return GST_SEEK_TYPE_NONE; - case AM_SEEKING_AbsolutePositioning: return GST_SEEK_TYPE_SET; - case AM_SEEKING_RelativePositioning: return GST_SEEK_TYPE_CUR; - case AM_SEEKING_IncrementalPositioning: return GST_SEEK_TYPE_END; + case AM_SEEKING_NoPositioning: + return GST_SEEK_TYPE_NONE; + case AM_SEEKING_AbsolutePositioning: + case AM_SEEKING_RelativePositioning: + return GST_SEEK_TYPE_SET; + case AM_SEEKING_IncrementalPositioning: + return GST_SEEK_TYPE_END; } return GST_SEEK_TYPE_NONE; } @@ -1472,6 +1492,7 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface, GstSeekFlags f = 0; GstSeekType curtype, stoptype; GstEvent *e; + gint64 stop_pos = 0, curr_pos = 0; TRACE("(%p)->(%p, 0x%x, %p, 0x%x)\n", This, pCur, curflags, pStop, stopflags); @@ -1493,7 +1514,17 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface, if (!(curflags & AM_SEEKING_NoFlush)) f |= GST_SEEK_FLAG_FLUSH; - e = gst_event_new_seek(This->seek.dRate, GST_FORMAT_TIME, f, curtype, pCur ? *pCur * 100 : -1, stoptype, pStop ? *pStop * 100 : -1); + if (((curflags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_RelativePositioning) || + ((stopflags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_RelativePositioning)) { + gint64 tmp_pos; + gst_pad_query_position (This->my_sink, GST_FORMAT_TIME, &tmp_pos); + if ((curflags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_RelativePositioning) + curr_pos = tmp_pos; + if ((stopflags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_RelativePositioning) + stop_pos = tmp_pos; + } + + e = gst_event_new_seek(This->seek.dRate, GST_FORMAT_TIME, f, curtype, pCur ? curr_pos + *pCur * 100 : -1, stoptype, pStop ? stop_pos + *pStop * 100 : -1); if (gst_pad_push_event(This->my_sink, e)) return S_OK; else @@ -1555,7 +1586,7 @@ static HRESULT WINAPI GST_QualityControl_Notify(IQualityControl *iface, IBaseFil mark_wine_thread(); if (qm.Late < 0 && -qm.Late > qm.TimeStamp) late = -qm.TimeStamp; - gst_pad_push_event(pin->my_sink, gst_event_new_qos(1000./qm.Proportion, late*100, qm.TimeStamp*100)); + gst_pad_push_event(pin->my_sink, gst_event_new_qos(late <= 0 ? GST_QOS_TYPE_OVERFLOW : GST_QOS_TYPE_UNDERFLOW, 1000./qm.Proportion, late*100, qm.TimeStamp*100)); return S_OK; } @@ -1610,13 +1641,17 @@ static ULONG WINAPI GSTOutPin_Release(IPin *iface) mark_wine_thread(); if (!refCount) { - if (This->their_src) + if (This->their_src) { gst_pad_unlink(This->their_src, This->my_sink); + gst_object_unref(This->their_src); + } gst_object_unref(This->my_sink); CloseHandle(This->caps_event); DeleteMediaType(This->pmt); FreeMediaType(&This->pin.pin.mtCurrent); gst_segment_free(This->segment); + if(This->gstpool) + gst_object_unref(This->gstpool); if (This->pin.pAllocator) IMemAllocator_Release(This->pin.pAllocator); CoTaskMemFree(This); @@ -1734,6 +1769,7 @@ static HRESULT GST_AddPin(GSTImpl *This, const PIN_INFO *piOutput, const AM_MEDI hr = BaseOutputPin_Construct(&GST_OutputPin_Vtbl, sizeof(GSTOutPin), piOutput, &output_BaseOutputFuncTable, &This->filter.csFilter, (IPin**)(This->ppPins + This->cStreams)); if (SUCCEEDED(hr)) { GSTOutPin *pin = This->ppPins[This->cStreams]; + memset((char*)pin + sizeof(pin->pin), 0, sizeof(GSTOutPin) - sizeof(pin->pin)); pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); CopyMediaType(pin->pmt, amt); pin->pin.pin.pinInfo.pFilter = (LPVOID)This; @@ -1762,9 +1798,8 @@ static HRESULT GST_RemoveOutputPins(GSTImpl *This) gst_element_set_bus(This->gstfilter, NULL); gst_element_set_state(This->gstfilter, GST_STATE_NULL); gst_pad_unlink(This->my_src, This->their_sink); - if (This->push_thread) - gst_pad_activate_push(This->my_src, 0); gst_object_unref(This->my_src); + gst_object_unref(This->their_sink); This->my_src = This->their_sink = NULL; for (i = 0; i < This->cStreams; i++) { @@ -1841,6 +1876,7 @@ static HRESULT WINAPI GSTInPin_ReceiveConnection(IPin *iface, IPin *pReceivePin, This->pin.pConnectedTo = pReceivePin; IPin_AddRef(pReceivePin); hr = IMemAllocator_Commit(This->pAlloc); + SetEvent(((GSTImpl*)This->pin.pinInfo.pFilter)->event); } else { GST_RemoveOutputPins((GSTImpl *)This->pin.pinInfo.pFilter); if (This->pReader) @@ -2013,25 +2049,19 @@ void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user) case EXISTING_NEW_PAD: { struct existing_new_pad_data *data = &cbdata->u.existing_new_pad_data; - existing_new_pad(data->bin, data->pad, data->last, data->user); - break; - } - case CHECK_GET_RANGE: - { - struct check_get_range_data *data = &cbdata->u.check_get_range_data; - cbdata->u.check_get_range_data.ret = check_get_range(data->pad); + existing_new_pad(data->bin, data->pad, data->user); break; } case QUERY_FUNCTION: { struct query_function_data *data = &cbdata->u.query_function_data; - cbdata->u.query_function_data.ret = query_function(data->pad, data->query); + cbdata->u.query_function_data.ret = query_function(data->pad, data->parent, data->query); break; } - case ACTIVATE_PUSH: + case ACTIVATE_MODE: { - struct activate_push_data *data = &cbdata->u.activate_push_data; - cbdata->u.activate_push_data.ret = activate_push(data->pad, data->activate); + struct activate_mode_data *data = &cbdata->u.activate_mode_data; + cbdata->u.activate_mode_data.ret = activate_mode(data->pad, data->parent, data->mode, data->activate); break; } case NO_MORE_PADS: @@ -2043,27 +2073,20 @@ void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user) case REQUEST_BUFFER_SRC: { struct request_buffer_src_data *data = &cbdata->u.request_buffer_src_data; - cbdata->u.request_buffer_src_data.ret = request_buffer_src(data->pad, + cbdata->u.request_buffer_src_data.ret = request_buffer_src(data->pad, data->parent, data->ofs, data->len, data->buf); break; } case EVENT_SRC: { struct event_src_data *data = &cbdata->u.event_src_data; - cbdata->u.event_src_data.ret = event_src(data->pad, data->event); + cbdata->u.event_src_data.ret = event_src(data->pad, data->parent, data->event); break; } case EVENT_SINK: { struct event_sink_data *data = &cbdata->u.event_sink_data; - cbdata->u.event_sink_data.ret = event_sink(data->pad, data->event); - break; - } - case REQUEST_BUFFER_SINK: - { - struct request_buffer_sink_data *data = &cbdata->u.request_buffer_sink_data; - cbdata->u.request_buffer_sink_data.ret = request_buffer_sink(data->pad, - data->ofs, data->size, data->caps, data->buf); + cbdata->u.event_sink_data.ret = event_sink(data->pad, data->parent, data->event); break; } case ACCEPT_CAPS_SINK: @@ -2081,20 +2104,13 @@ void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user) case GOT_DATA_SINK: { struct got_data_sink_data *data = &cbdata->u.got_data_sink_data; - cbdata->u.got_data_sink_data.ret = got_data_sink(data->pad, data->buf); + cbdata->u.got_data_sink_data.ret = got_data_sink(data->pad, data->parent, data->buf); break; } case GOT_DATA: { struct got_data_data *data = &cbdata->u.got_data_data; - cbdata->u.got_data_data.ret = got_data(data->pad, data->buf); - break; - } - case REQUEST_BUFFER: - { - struct request_buffer_data *data = &cbdata->u.request_buffer_data; - cbdata->u.request_buffer_data.ret = request_buffer(data->pad, - data->ofs, data->size, data->caps, data->buf); + cbdata->u.got_data_data.ret = got_data(data->pad, data->parent, data->buf); break; } case REMOVED_DECODED_PAD: @@ -2128,6 +2144,13 @@ void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user) Gstreamer_transform_pad_added(data->filter, data->pad, data->user); break; } + case QUERY_SINK: + { + struct query_sink_data *data = &cbdata->u.query_sink_data; + cbdata->u.query_sink_data.ret = query_sink(data->pad, data->parent, + data->query); + break; + } } pthread_mutex_lock(&cbdata->lock); diff --git a/dlls/winegstreamer/gsttffilter.c b/dlls/winegstreamer/gsttffilter.c index d57aac1f18c..b8435bad1bb 100644 --- a/dlls/winegstreamer/gsttffilter.c +++ b/dlls/winegstreamer/gsttffilter.c @@ -22,9 +22,9 @@ #include "config.h" -#include -#include -#include +#include +#include +#include #include "gst_private.h" #include "gst_guids.h" @@ -97,7 +97,7 @@ static const char *Gstreamer_FindMatch(const char *strcaps) data.caps = caps; data.type = "Decoder"; - copy = gst_default_registry_feature_filter(match_element, 0, &data); + copy = gst_registry_feature_filter(gst_registry_get(), match_element, 0, &data); for (list = copy; list; list = list->next) { GstElementFactory *factory = (GstElementFactory*)list->data; guint rank; @@ -155,18 +155,39 @@ static HRESULT WINAPI Gstreamer_transform_DecideBufferSize(TransformFilter *tf, return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual); } -GstFlowReturn got_data(GstPad *pad, GstBuffer *buf) +GstFlowReturn got_data(GstPad *pad, GstObject *parent, GstBuffer *buf) { GstTfImpl *This = gst_pad_get_element_private(pad); - IMediaSample *sample = GST_APP_BUFFER(buf)->priv; + IMediaSample *sample = (IMediaSample *) gst_mini_object_get_qdata(GST_MINI_OBJECT(buf), g_quark_from_static_string(media_quark_string)); REFERENCE_TIME tStart, tStop; HRESULT hr; TRACE("%p, %p\n", pad, buf); - if (GST_BUFFER_TIMESTAMP_IS_VALID(buf) && + if(!sample){ + GstMapInfo info; + BYTE *ptr; + + gst_buffer_map(buf, &info, GST_MAP_READ); + + hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &sample, NULL, NULL, 0); + if (FAILED(hr)) { + ERR("Could not get output buffer: %08x\n", hr); + return GST_FLOW_FLUSHING; + } + + IMediaSample_SetActualDataLength(sample, info.size); + + IMediaSample_GetPointer(sample, &ptr); + + memcpy(ptr, info.data, info.size); + + gst_buffer_unmap(buf, &info); + } + + if (GST_BUFFER_PTS_IS_VALID(buf) && GST_BUFFER_DURATION_IS_VALID(buf)) { - tStart = buf->timestamp / 100; + tStart = buf->pts / 100; tStop = tStart + buf->duration / 100; IMediaSample_SetTime(sample, &tStart, &tStop); } @@ -182,45 +203,15 @@ GstFlowReturn got_data(GstPad *pad, GstBuffer *buf) IMediaSample_SetMediaTime(sample, NULL, NULL); IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT)); - IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_PREROLL)); + IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LIVE)); IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)); - IMediaSample_SetActualDataLength(sample, GST_BUFFER_SIZE(buf)); + IMediaSample_SetActualDataLength(sample, gst_buffer_get_size(buf)); hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], sample); + IMediaSample_Release(sample); gst_buffer_unref(buf); if (FAILED(hr)) - return GST_FLOW_WRONG_STATE; - if (hr != S_OK) - return GST_FLOW_RESEND; - return GST_FLOW_OK; -} - -GstFlowReturn request_buffer(GstPad *pad, guint64 ofs, guint size, GstCaps *caps, GstBuffer **buf) -{ - GstTfImpl *This = gst_pad_get_element_private(pad); - IMediaSample *sample; - BYTE *ptr; - HRESULT hr; - - TRACE("%p %s %u %p %p\n", pad, wine_dbgstr_longlong(ofs), size, caps, buf); - - hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &sample, NULL, NULL, 0); - if (FAILED(hr)) { - ERR("Could not get output buffer: %08x\n", hr); - return GST_FLOW_WRONG_STATE; - } - IMediaSample_SetActualDataLength(sample, size); - IMediaSample_GetPointer(sample, &ptr); - *buf = gst_app_buffer_new(ptr, size, release_sample_wrapper, sample); - - if (!*buf) { - IMediaSample_Release(sample); - ERR("Out of memory\n"); - return GST_FLOW_ERROR; - } - if (!caps) - caps = gst_pad_get_caps_reffed(This->my_sink); - gst_buffer_set_caps(*buf, caps); + return GST_FLOW_FLUSHING; return GST_FLOW_OK; } @@ -231,6 +222,7 @@ static HRESULT WINAPI Gstreamer_transform_ProcessData(TransformFilter *iface, IM BYTE *data; GstBuffer *buf; HRESULT hr; + DWORD bufsize; int ret; TRACE("%p, %p\n", This, sample); @@ -239,17 +231,23 @@ static HRESULT WINAPI Gstreamer_transform_ProcessData(TransformFilter *iface, IM EnterCriticalSection(&This->tf.csReceive); IMediaSample_GetPointer(sample, &data); - buf = gst_app_buffer_new(data, IMediaSample_GetActualDataLength(sample), release_sample_wrapper, sample); + + IMediaSample_AddRef(sample); + bufsize = IMediaSample_GetActualDataLength(sample); + buf = gst_buffer_new_wrapped_full(0, data, bufsize, 0, bufsize, sample, release_sample_wrapper); if (!buf) { + IMediaSample_Release(sample); LeaveCriticalSection(&This->tf.csReceive); return S_OK; } - gst_buffer_set_caps(buf, gst_pad_get_caps_reffed(This->my_src)); + IMediaSample_AddRef(sample); - buf->duration = buf->timestamp = -1; + gst_mini_object_set_qdata(GST_MINI_OBJECT(buf), g_quark_from_static_string(media_quark_string), sample, release_sample_wrapper); + + buf->duration = buf->pts = -1; hr = IMediaSample_GetTime(sample, &tStart, &tStop); if (SUCCEEDED(hr)) { - buf->timestamp = tStart * 100; + buf->pts = tStart * 100; if (hr == S_OK) buf->duration = (tStop - tStart)*100; } @@ -260,19 +258,15 @@ static HRESULT WINAPI Gstreamer_transform_ProcessData(TransformFilter *iface, IM if (IMediaSample_IsDiscontinuity(sample) == S_OK) GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DISCONT); if (IMediaSample_IsPreroll(sample) == S_OK) - GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_PREROLL); + GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_LIVE); if (IMediaSample_IsSyncPoint(sample) != S_OK) GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT); LeaveCriticalSection(&This->tf.csReceive); ret = gst_pad_push(This->my_src, buf); if (ret) WARN("Sending returned: %i\n", ret); - if (ret == GST_FLOW_ERROR) - return E_FAIL; - if (ret == GST_FLOW_WRONG_STATE) + if (ret == GST_FLOW_FLUSHING) return VFW_E_WRONG_STATE; - if (ret == GST_FLOW_RESEND) - return S_FALSE; return S_OK; } @@ -304,9 +298,6 @@ void Gstreamer_transform_pad_added(GstElement *filter, GstPad *pad, gpointer use if (ret < 0) WARN("Failed to link with %i\n", ret); This->their_src = pad; - - gst_pad_set_active(pad, TRUE); - gst_pad_set_active(This->my_sink, TRUE); } static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_TYPE *amt, GstCaps *capsin, GstCaps *capsout) @@ -324,36 +315,27 @@ static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_ FIXME("Could not make %s filter\n", This->gstreamer_name); return E_FAIL; } - This->my_src = gst_pad_new(NULL, GST_PAD_SRC); + This->my_src = gst_pad_new("yuvsrc", GST_PAD_SRC); gst_pad_set_element_private (This->my_src, This); + gst_pad_set_active(This->my_src, 1); - This->my_sink = gst_pad_new(NULL, GST_PAD_SINK); + This->my_sink = gst_pad_new("yuvsink", GST_PAD_SINK); gst_pad_set_chain_function(This->my_sink, got_data_wrapper); - gst_pad_set_bufferalloc_function(This->my_sink, request_buffer_wrapper); gst_pad_set_element_private (This->my_sink, This); - - ret = gst_pad_set_caps(This->my_src, capsin); - if (ret < 0) { - WARN("Failed to set caps on own source with %i\n", ret); - return E_FAIL; - } - - ret = gst_pad_set_caps(This->my_sink, capsout); - if (ret < 0) { - WARN("Failed to set caps on own sink with %i\n", ret); - return E_FAIL; - } + gst_pad_set_active(This->my_sink, 1); it = gst_element_iterate_sink_pads(This->filter); while (!done) { - gpointer item; + GValue item = {0}; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: - This->their_sink = item; + This->their_sink = g_value_get_object(&item); + gst_object_ref(This->their_sink); + g_value_reset(&item); case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; @@ -370,14 +352,16 @@ static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_ gst_iterator_resync(it); done = FALSE; while (!done) { - gpointer item; + GValue item = {0}; switch (gst_iterator_next(it, &item)) { case GST_ITERATOR_RESYNC: gst_iterator_resync (it); break; case GST_ITERATOR_OK: - This->their_src = item; + This->their_src = g_value_get_object(&item); + gst_object_ref(This->their_src); + g_value_reset(&item); case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; @@ -394,12 +378,24 @@ static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_ return E_FAIL; } + ret = gst_pad_set_caps(This->my_src, capsin); + if (ret < 0) { + WARN("Failed to set caps on own source with %i\n", ret); + return E_FAIL; + } + if (found) Gstreamer_transform_pad_added(This->filter, This->their_src, This); if (!gst_pad_is_linked(This->my_sink)) return E_FAIL; + ret = gst_pad_set_caps(This->my_sink, capsout); + if (ret < 0) { + WARN("Failed to set caps on own sink with %i\n", ret); + return E_FAIL; + } + TRACE("Connected\n"); return S_OK; } @@ -422,10 +418,12 @@ static HRESULT WINAPI Gstreamer_transform_Cleanup(TransformFilter *tf, PIN_DIREC if (This->my_src) { gst_pad_unlink(This->my_src, This->their_sink); gst_object_unref(This->my_src); + gst_object_unref(This->their_sink); } if (This->my_sink) { gst_pad_unlink(This->their_src, This->my_sink); gst_object_unref(This->my_sink); + gst_object_unref(This->their_src); } This->my_sink = This->my_src = This->their_sink = This->their_src = NULL; } @@ -458,18 +456,20 @@ static HRESULT WINAPI Gstreamer_transform_EndFlush(TransformFilter *iface) TRACE("%p\n", This); mark_wine_thread(); - gst_pad_push_event(This->my_src, gst_event_new_flush_stop()); + gst_pad_push_event(This->my_src, gst_event_new_flush_stop(TRUE)); return S_OK; } static HRESULT WINAPI Gstreamer_transform_NewSegment(TransformFilter *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) { GstTfImpl *This = (GstTfImpl*)iface; + const GstSegment segment = { GST_SEGMENT_FLAG_NONE, 1.0, dRate, GST_FORMAT_TIME, 0, 0, 0, tStop <= tStart ? -1 : tStop * 100, 0, tStart*100, -1 }; + TRACE("%p\n", This); mark_wine_thread(); - gst_pad_push_event(This->my_src, gst_event_new_new_segment_full(1, - 1.0, dRate, GST_FORMAT_TIME, 0, tStop <= tStart ? -1 : tStop * 100, tStart*100)); + gst_pad_push_event(This->my_src, gst_event_new_segment(&segment)); + return S_OK; } @@ -484,7 +484,7 @@ static HRESULT WINAPI Gstreamer_transform_QOS(TransformFilter *iface, IBaseFilte if (qm.Late < 0 && -qm.Late > qm.TimeStamp) late = -qm.TimeStamp; - gst_pad_push_event(This->my_sink, gst_event_new_qos(1000. / qm.Proportion, late * 100, qm.TimeStamp * 100)); + gst_pad_push_event(This->my_sink, gst_event_new_qos(late <= 0 ? GST_QOS_TYPE_OVERFLOW : GST_QOS_TYPE_UNDERFLOW, 1000. / qm.Proportion, late * 100, qm.TimeStamp * 100)); return TransformFilterImpl_Notify(iface, sender, qm); } @@ -515,8 +515,9 @@ static HRESULT WINAPI Gstreamer_Mp3_QueryConnect(TransformFilter *iface, const A !IsEqualGUID(&amt->majortype, &MEDIATYPE_Stream)) || (!IsEqualGUID(&amt->subtype, &MEDIASUBTYPE_MPEG1AudioPayload) && !IsEqualGUID(&amt->subtype, &WMMEDIASUBTYPE_MP3)) - || !IsEqualGUID(&amt->formattype, &FORMAT_WaveFormatEx)) + || !IsEqualGUID(&amt->formattype, &FORMAT_WaveFormatEx)){ return S_FALSE; + } return S_OK; } @@ -578,11 +579,8 @@ static HRESULT WINAPI Gstreamer_Mp3_SetMediaType(TransformFilter *tf, PIN_DIRECT "rate", G_TYPE_INT, wfx->nSamplesPerSec, "channels", G_TYPE_INT, wfx->nChannels, NULL); - capsout = gst_caps_new_simple("audio/x-raw-int", - "endianness", G_TYPE_INT, 1234, - "signed", G_TYPE_BOOLEAN, 1, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, + capsout = gst_caps_new_simple("audio/x-raw", + "format", G_TYPE_STRING, "S16LE" "rate", G_TYPE_INT, wfx->nSamplesPerSec, "channels", G_TYPE_INT, wfx->nChannels, NULL); @@ -727,22 +725,19 @@ static HRESULT WINAPI Gstreamer_YUV_SetMediaType(TransformFilter *tf, PIN_DIRECT outpmt->subtype = MEDIASUBTYPE_RGB24; - capsin = gst_caps_new_simple("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, amt->subtype.Data1, + capsin = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, + gst_video_format_to_string( + gst_video_format_from_fourcc(amt->subtype.Data1)), "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, 10000000, avgtime, NULL); - capsout = gst_caps_new_simple("video/x-raw-rgb", - "endianness", G_TYPE_INT, 4321, + capsout = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, "BGR", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, 10000000, avgtime, - "bpp", G_TYPE_INT, 24, - "depth", G_TYPE_INT, 24, - "red_mask", G_TYPE_INT, 0xff, - "green_mask", G_TYPE_INT, 0xff00, - "blue_mask", G_TYPE_INT, 0xff0000, NULL); hr = Gstreamer_transform_ConnectInput(This, amt, capsin, capsout); @@ -781,7 +776,7 @@ IUnknown * CALLBACK Gstreamer_YUV_create(IUnknown *punkouter, HRESULT *phr) return NULL; } - *phr = Gstreamer_transform_create(punkouter, &CLSID_Gstreamer_YUV, "ffmpegcolorspace", &Gstreamer_YUV_vtbl, (LPVOID*)&obj); + *phr = Gstreamer_transform_create(punkouter, &CLSID_Gstreamer_YUV, "videoconvert", &Gstreamer_YUV_vtbl, (LPVOID*)&obj); TRACE("returning %p\n", obj); @@ -815,6 +810,7 @@ static HRESULT WINAPI Gstreamer_AudioConvert_SetMediaType(TransformFilter *tf, P WAVEFORMATEX *inwfe; WAVEFORMATEX *outwfe; WAVEFORMATEXTENSIBLE *outwfx; + GstAudioFormat format; HRESULT hr; BOOL inisfloat = FALSE; int indepth; @@ -844,10 +840,12 @@ static HRESULT WINAPI Gstreamer_AudioConvert_SetMediaType(TransformFilter *tf, P indepth = inwfx->Samples.wValidBitsPerSample; } - capsin = gst_caps_new_simple(inisfloat ? "audio/x-raw-float" : "audio/x-raw-int", - "endianness", G_TYPE_INT, 1234, - "width", G_TYPE_INT, inwfe->wBitsPerSample, - "depth", G_TYPE_INT, indepth, + format = inisfloat ? (inwfe->wBitsPerSample == 64 ? GST_AUDIO_FORMAT_F64LE : GST_AUDIO_FORMAT_F32LE) + : gst_audio_format_build_integer(inwfe->wBitsPerSample == 8 ? FALSE : TRUE, + inwfe->wBitsPerSample, + indepth, G_LITTLE_ENDIAN); + capsin = gst_caps_new_simple("audio/x-raw", + "format", G_TYPE_STRING, gst_audio_format_to_string(format), "channels", G_TYPE_INT, inwfe->nChannels, "rate", G_TYPE_INT, inwfe->nSamplesPerSec, NULL); @@ -865,14 +863,13 @@ static HRESULT WINAPI Gstreamer_AudioConvert_SetMediaType(TransformFilter *tf, P outwfx->dwChannelMask = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT; outwfx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - capsout = gst_caps_new_simple("audio/x-raw-int", - "endianness", G_TYPE_INT, 1234, - "width", G_TYPE_INT, outwfe->wBitsPerSample, - "depth", G_TYPE_INT, outwfx->Samples.wValidBitsPerSample, + capsout = gst_caps_new_simple("audio/x-raw", + "format", G_TYPE_STRING, "S16LE", "channels", G_TYPE_INT, outwfe->nChannels, "rate", G_TYPE_INT, outwfe->nSamplesPerSec, NULL); + hr = Gstreamer_transform_ConnectInput(This, amt, capsin, capsout); gst_caps_unref(capsin); gst_caps_unref(capsout); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index b3f90e9dbb3..7b9cd319596 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -22,9 +22,7 @@ #include #include -#include -#include -#include +#include #include "windef.h" #include "winbase.h"