From 34dcb85ace76c59cbec38e33dcbaccbb2663cd0f Mon Sep 17 00:00:00 2001 From: Fabian Orccon Date: Fri, 18 Oct 2024 11:54:22 +0200 Subject: [PATCH] Add webdownload element --- .../gst-libs/gst/web/gstwebutils.cpp | 73 +++++++ .../gst-libs/gst/web/gstwebutils.h | 5 +- .../gst-libs/gst/web/gstwebvideoframe.cpp | 99 ++++++++- .../gst-plugins-web/gst/web/gstweb.c | 4 + .../gst-plugins-web/gst/web/gstwebdownload.c | 197 ++++++++++++++++++ .../gst-plugins-web/gst/web/gstwebdownload.h | 27 +++ .../gst-plugins-web/gst/web/meson.build | 1 + .../subprojects/samples/ci/static/index.html | 3 + gst.wasm/subprojects/samples/meson.build | 1 + gst.wasm/subprojects/samples/template.html | 4 +- .../samples/webdownload/meson.build | 58 ++++++ .../webdownload/webdownload-example-page.html | 14 ++ .../samples/webdownload/webdownload-example.c | 79 +++++++ 13 files changed, 558 insertions(+), 7 deletions(-) create mode 100644 gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.c create mode 100644 gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.h create mode 100644 gst.wasm/subprojects/samples/webdownload/meson.build create mode 100644 gst.wasm/subprojects/samples/webdownload/webdownload-example-page.html create mode 100644 gst.wasm/subprojects/samples/webdownload/webdownload-example.c diff --git a/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.cpp b/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.cpp index 29d02ce..b7d8809 100644 --- a/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.cpp +++ b/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.cpp @@ -546,3 +546,76 @@ EMSCRIPTEN_BINDINGS (gst_web_transport_src) function ("gst_web_utils_js_worker_transfer_object", &gst_web_utils_js_worker_transfer_object); } + +GstVideoFormat +gst_web_utils_video_format_from_web_format (const char *vf_format) +{ + GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; + + // TODO: gst_video_format_from_string? + + if (!g_strcmp0 (vf_format, "I420")) { + format = GST_VIDEO_FORMAT_I420; + } else if (!g_strcmp0 (vf_format, "I420A")) { + format = GST_VIDEO_FORMAT_A420; + } else if (!g_strcmp0 (vf_format, "I422")) { + format = GST_VIDEO_FORMAT_Y42B; + } else if (!g_strcmp0 (vf_format, "I444")) { + format = GST_VIDEO_FORMAT_Y444; + } else if (!g_strcmp0 (vf_format, "NV12")) { + format = GST_VIDEO_FORMAT_NV12; + } else if (!g_strcmp0 (vf_format, "RGBA")) { + format = GST_VIDEO_FORMAT_RGBA; + } else if (!g_strcmp0 (vf_format, "RGBX")) { + format = GST_VIDEO_FORMAT_RGBx; + } else if (!g_strcmp0 (vf_format, "BGRA")) { + format = GST_VIDEO_FORMAT_BGRA; + } else if (!g_strcmp0 (vf_format, "BGRX")) { + format = GST_VIDEO_FORMAT_BGRx; + } else { + GST_ERROR ("Unsupported format %s", vf_format); + } + + return format; +} + +const char * +gst_web_utils_convert_video_format (GstVideoFormat format) +{ + const char *vf_format = NULL; + + switch (format) { + case GST_VIDEO_FORMAT_I420: + vf_format = "I420"; + break; + case GST_VIDEO_FORMAT_A420: + vf_format = "I420A"; + break; + case GST_VIDEO_FORMAT_Y42B: + vf_format = "I422"; + break; + case GST_VIDEO_FORMAT_Y444: + vf_format = "I444"; + break; + case GST_VIDEO_FORMAT_NV12: + vf_format = "NV12"; + break; + case GST_VIDEO_FORMAT_RGBA: + vf_format = "RGBA"; + break; + case GST_VIDEO_FORMAT_RGBx: + vf_format = "RGBX"; + break; + case GST_VIDEO_FORMAT_BGRA: + vf_format = "BGRA"; + break; + case GST_VIDEO_FORMAT_BGRx: + vf_format = "BGRX"; + break; + default: + GST_ERROR ("Unsupported GstVideoFormat: %d", format); + break; + } + + return vf_format; +} diff --git a/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.h b/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.h index 5d7bf60..08a8f73 100644 --- a/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.h +++ b/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebutils.h @@ -21,6 +21,7 @@ #ifndef __GST_WEB_UTILS_H__ #define __GST_WEB_UTILS_H__ +#include #include "gstwebcanvas.h" #define GST_WEB_UTILS_MESSAGE_PROPOSE_OBJECT_NAME "GstWebProposeObjectMessage" @@ -44,9 +45,11 @@ void gst_web_utils_js_register_on_message (void); void gst_web_utils_js_unregister_on_message (void); void gst_web_utils_element_process_request_object ( GstElement *e, GstMessage *msg, guintptr object); - GstMessage *gst_web_utils_message_new_request_object (GstElement *src, const gchar *cb_name, const gchar *object_name, gpointer user_data); +GstVideoFormat gst_web_utils_video_format_from_web_format ( + const char *vf_format); +const char *gst_web_utils_convert_video_format (GstVideoFormat format); G_END_DECLS diff --git a/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebvideoframe.cpp b/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebvideoframe.cpp index 30abdfb..9ddf47b 100644 --- a/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebvideoframe.cpp +++ b/gst.wasm/subprojects/gst-plugins-web/gst-libs/gst/web/gstwebvideoframe.cpp @@ -30,7 +30,10 @@ #endif #include +#include #include +#include +#include #include "gstwebrunner.h" #include "gstwebvideoframe.h" @@ -77,6 +80,15 @@ typedef struct _GstWebVideoFrameAllocatorClass GstAllocatorClass parent_class; } GstWebVideoFrameAllocatorClass; +typedef struct _GstWebVideoFrameAllocatorMapCpuData +{ + GstWebVideoFrame *self; + guint8 *data; + gsize size; + GstVideoInfo *info; + gboolean result; +} GstWebVideoFrameAllocatorMapCpuData; + typedef struct _GstWebVideoFrameAllocationSizeData { val video_frame; @@ -109,20 +121,99 @@ GST_DEFINE_MINI_OBJECT_TYPE (GstWebVideoFrame, gst_web_video_frame); G_DEFINE_TYPE (GstWebVideoFrameAllocator, gst_web_video_frame_allocator, GST_TYPE_ALLOCATOR); +static gboolean +gst_web_video_frame_map_internal ( + GstWebVideoFrame *self, GstVideoInfo *info, gpointer data, gsize size) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail ( + info == NULL || (info != NULL && info->finfo != NULL), FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + val video_frame = gst_web_video_frame_get_handle (self); + val data_view = + val (typed_memory_view (size, static_cast (data))); + val options = val::object (); + + if (info != NULL) { + const char *format; + + format = gst_web_utils_convert_video_format ( + GST_VIDEO_FORMAT_INFO_FORMAT (info->finfo)); + if (format == NULL) { + GST_ERROR ("Format %s is not supported.", + GST_VIDEO_FORMAT_INFO_NAME (info->finfo)); + return FALSE; + } + options.set ("format", format); + } else { + GST_DEBUG ("No format specified. Use default format."); + } + + video_frame.call ("copyTo", data_view, options).await (); + + return TRUE; +} + +static void +gst_web_video_frame_allocator_map_cpu_access (gpointer data) +{ + GstWebVideoFrameAllocatorMapCpuData *cdata = + (GstWebVideoFrameAllocatorMapCpuData *) data; + GstWebVideoFrame *self = cdata->self; + + cdata->result = gst_web_video_frame_map_internal ( + self, cdata->info, cdata->data, cdata->size); +} + +gboolean +gst_web_video_frame_copy_to ( + GstWebVideoFrame *self, GstVideoInfo *info, guint8 *data, gsize size) +{ + GstWebVideoFrameAllocatorMapCpuData cdata = { .self = self, + .data = data, + .size = info->size, + .info = info, + .result = FALSE }; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (info != NULL, FALSE); + + gst_web_runner_send_message (self->priv->runner, + gst_web_video_frame_allocator_map_cpu_access, &cdata); + + return cdata.result; +} + static gpointer gst_web_video_frame_allocator_map_full ( - GstWebVideoFrame *mem, GstMapInfo *info, gsize size) + GstWebVideoFrame *self, GstMapInfo *info, gsize size) { - GST_FIXME ("Trying to map"); + GstWebVideoFrameAllocatorMapCpuData data = { + .self = self, .data = NULL, .size = size, .info = NULL, .result = FALSE + }; - return NULL; + if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE) { + GST_DEBUG ("Write flags not supported"); + } + + data.data = (guint8 *) g_malloc (data.size); + + gst_web_runner_send_message ( + self->priv->runner, gst_web_video_frame_allocator_map_cpu_access, &data); + + if (!data.result) { + return NULL; + } + + return data.data; } static void gst_web_video_frame_allocator_unmap_full ( GstWebVideoFrame *mem, GstMapInfo *info) { - GST_FIXME ("Trying to unmap"); + g_free (info->data); } static GstMemory * diff --git a/gst.wasm/subprojects/gst-plugins-web/gst/web/gstweb.c b/gst.wasm/subprojects/gst-plugins-web/gst/web/gstweb.c index c4835c9..c880612 100644 --- a/gst.wasm/subprojects/gst-plugins-web/gst/web/gstweb.c +++ b/gst.wasm/subprojects/gst-plugins-web/gst/web/gstweb.c @@ -32,6 +32,8 @@ #include "gstwebstreamsrc.h" #include "gstwebcanvassink.h" #include "gstwebcanvassrc.h" +#include "gstwebdownload.h" + #include "codecs/gstwebcodecs.h" #include "transport/gstwebtransportsrc.h" @@ -47,6 +49,8 @@ plugin_init (GstPlugin *plugin) gst_element_register_web_fetch_src (plugin); gst_element_register_web_stream_src (plugin); gst_element_register_web_transport_src (plugin); + gst_element_register_web_download (plugin); + return TRUE; } diff --git a/gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.c b/gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.c new file mode 100644 index 0000000..a1c9e50 --- /dev/null +++ b/gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.c @@ -0,0 +1,197 @@ +/* + * gst.wasm - gstwebdownload + * + * Copyright 2024 Fluendo S.A. + * @author: Cesar Fabian Orccon Chipana + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "gstweb.h" + +#define GST_TYPE_WEB_DOWNLOAD (gst_web_download_get_type ()) +#define GST_CAT_DEFAULT web_download_debug +#define parent_class gst_web_download_parent_class + +#define DEFAULT_STATIC_CAPS \ + GST_VIDEO_CAPS_MAKE (GST_WEB_MEMORY_VIDEO_FORMATS_STR) \ + ";" GST_VIDEO_CAPS_MAKE_WITH_FEATURES ( \ + GST_CAPS_FEATURE_MEMORY_WEB_VIDEO_FRAME, \ + GST_WEB_MEMORY_VIDEO_FORMATS_STR) + +struct _GstWebDownload +{ + GstBaseTransform element; + + /*< private >*/ + GstVideoInfo vinfo; +}; + +G_DECLARE_FINAL_TYPE ( + GstWebDownload, gst_web_download, GST, WEB_DOWNLOAD, GstBaseTransform) +G_DEFINE_TYPE (GstWebDownload, gst_web_download, GST_TYPE_BASE_TRANSFORM); +GST_ELEMENT_REGISTER_DEFINE ( + web_download, "webdownload", GST_RANK_NONE, GST_TYPE_WEB_DOWNLOAD); +GST_DEBUG_CATEGORY_STATIC (web_download_debug); + +static GstStaticPadTemplate gst_web_download_sink_pad_template = + GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS (DEFAULT_STATIC_CAPS)); + +static GstStaticPadTemplate gst_web_download_src_pad_template = + GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS (DEFAULT_STATIC_CAPS)); + +static GstCaps * +gst_web_download_transform_caps (GstBaseTransform *bt, + GstPadDirection direction, GstCaps *caps, GstCaps *filter) +{ + GstWebDownload *self = GST_WEB_DOWNLOAD (bt); + + GstCaps *tmp, *res; + + GST_DEBUG_OBJECT (self, "caps: %" GST_PTR_FORMAT, caps); + GST_DEBUG_OBJECT (self, "filter: %" GST_PTR_FORMAT, filter); + GST_DEBUG_OBJECT (self, "direction: %d", (int) direction); + + if (direction == GST_PAD_SRC) { + tmp = gst_caps_copy (caps); + gst_caps_set_features_simple ( + tmp, gst_caps_features_from_string ( + GST_CAPS_FEATURE_MEMORY_WEB_VIDEO_FRAME)); + tmp = gst_caps_merge (gst_caps_ref (caps), tmp); + } else { + tmp = gst_caps_copy (caps); + gst_caps_set_features_simple (tmp, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)); + tmp = gst_caps_merge (gst_caps_ref (caps), tmp); + } + + if (filter) { + res = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (tmp); + } else { + res = tmp; + } + + GST_DEBUG_OBJECT (self, "Transformed caps to %" GST_PTR_FORMAT, caps); + + return res; +} + +static GstFlowReturn +gst_web_download_prepare_output_buffer ( + GstBaseTransform *bt, GstBuffer *inbuf, GstBuffer **outbuf) +{ + GstWebDownload *self = GST_WEB_DOWNLOAD (bt); + GstMapInfo out_map, in_map; + GstFlowReturn ret = GST_FLOW_ERROR; + + if (gst_base_transform_is_passthrough (bt)) { + *outbuf = inbuf; + return GST_FLOW_OK; + } + + if (!gst_buffer_map (inbuf, &in_map, GST_MAP_READ)) { + GST_ERROR_OBJECT (self, "Failed to map inpput buffer."); + goto beach; + } + + g_warn_if_fail (self->vinfo.size == in_map.size); + *outbuf = gst_buffer_new_allocate (NULL, self->vinfo.size, NULL); + + if (!gst_buffer_map (*outbuf, &out_map, GST_MAP_WRITE)) { + GST_ERROR_OBJECT (self, "Failed to map output buffer."); + g_clear_pointer (outbuf, gst_buffer_unref); + goto unmap_inbuf; + } + + memcpy (out_map.data, in_map.data, in_map.size); + + ret = GST_FLOW_OK; + + gst_buffer_unmap (*outbuf, &out_map); + +unmap_inbuf: + gst_buffer_unmap (inbuf, &in_map); + +beach: + return ret; +} + +static gboolean +gst_web_download_set_caps ( + GstBaseTransform *bt, GstCaps *in_caps, GstCaps *out_caps) +{ + GstWebDownload *self = GST_WEB_DOWNLOAD (bt); + + gst_video_info_from_caps (&self->vinfo, out_caps); + + return TRUE; +} + +static GstFlowReturn +gst_web_download_transform ( + GstBaseTransform *bt, GstBuffer *inbuf, GstBuffer *outbuf) +{ + return GST_FLOW_OK; +} + +static void +gst_web_download_init (GstWebDownload *self) +{ + gst_base_transform_set_prefer_passthrough (GST_BASE_TRANSFORM (self), TRUE); +} + +static void +gst_web_download_class_init (GstWebDownloadClass *klass) +{ + GstBaseTransformClass *gstbasetransform_class; + GstElementClass *gstelement_class; + + gstbasetransform_class = (GstBaseTransformClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gstbasetransform_class->transform_caps = gst_web_download_transform_caps; + gstbasetransform_class->set_caps = gst_web_download_set_caps; + gstbasetransform_class->passthrough_on_same_caps = TRUE; + gstbasetransform_class->transform = gst_web_download_transform; + gstbasetransform_class->prepare_output_buffer = + gst_web_download_prepare_output_buffer; + + gst_element_class_set_static_metadata (gstelement_class, + "Web Canvas Download", "Filter/Video", + "Converts VideoFrame (memory) to raw pixel data", GST_WEB_AUTHOR); + + gst_element_class_add_static_pad_template ( + gstelement_class, &gst_web_download_src_pad_template); + gst_element_class_add_static_pad_template ( + gstelement_class, &gst_web_download_sink_pad_template); + + GST_DEBUG_CATEGORY_INIT ( + web_download_debug, "webdownload", 0, "WebCodecs Video Decoder"); +} diff --git a/gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.h b/gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.h new file mode 100644 index 0000000..282ff0f --- /dev/null +++ b/gst.wasm/subprojects/gst-plugins-web/gst/web/gstwebdownload.h @@ -0,0 +1,27 @@ +/* + * GStreamer - GStreamer WebCanvasSrc source + * + * Copyright 2024 Fluendo S.A. + * @author: Cesar Fabian Orccon Chipana + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +GST_ELEMENT_REGISTER_DECLARE (web_download) diff --git a/gst.wasm/subprojects/gst-plugins-web/gst/web/meson.build b/gst.wasm/subprojects/gst-plugins-web/gst/web/meson.build index e4ff0a4..a4390a9 100644 --- a/gst.wasm/subprojects/gst-plugins-web/gst/web/meson.build +++ b/gst.wasm/subprojects/gst-plugins-web/gst/web/meson.build @@ -2,6 +2,7 @@ sources = [ 'gstweb.c', 'gstwebcanvassink.cpp', 'gstwebcanvassrc.cpp', + 'gstwebdownload.c', 'gstwebfetchsrc.c', 'gstwebstreamsrc.cpp', 'codecs/gstwebcodecs.cpp', diff --git a/gst.wasm/subprojects/samples/ci/static/index.html b/gst.wasm/subprojects/samples/ci/static/index.html index 21106b2..1afa8e0 100644 --- a/gst.wasm/subprojects/samples/ci/static/index.html +++ b/gst.wasm/subprojects/samples/ci/static/index.html @@ -52,6 +52,9 @@

gst.wasm

  • webcodecs
  • +
  • + webcodecs +
  • OpenGL
  • diff --git a/gst.wasm/subprojects/samples/meson.build b/gst.wasm/subprojects/samples/meson.build index 30a8293..4681234 100644 --- a/gst.wasm/subprojects/samples/meson.build +++ b/gst.wasm/subprojects/samples/meson.build @@ -32,6 +32,7 @@ examples = [ 'openal', 'videotestsrc', 'webcanvassrc', + 'webdownload', 'webfetchsrc', 'webstreamsrc', 'webtransportsrc', diff --git a/gst.wasm/subprojects/samples/template.html b/gst.wasm/subprojects/samples/template.html index 5676094..b7c8ade 100644 --- a/gst.wasm/subprojects/samples/template.html +++ b/gst.wasm/subprojects/samples/template.html @@ -14,6 +14,8 @@ font-size: 12px; background: black; color: white; + min-width: 640px; + min-height: 480px; } iframe { border: none; @@ -41,8 +43,6 @@ onload="onPageLoad()" title="Page" scrolling="no" - width="640px" - height="480px" >
           
    diff --git a/gst.wasm/subprojects/samples/webdownload/meson.build b/gst.wasm/subprojects/samples/webdownload/meson.build
    new file mode 100644
    index 0000000..5a1b44b
    --- /dev/null
    +++ b/gst.wasm/subprojects/samples/webdownload/meson.build
    @@ -0,0 +1,58 @@
    +fs = import('fs')
    +
    +c_code = executable_name + '.c'
    +html_code = executable_name + '-page.html'
    +
    +executable(executable_name,
    +    'webdownload-example.c',
    +    dependencies: [
    +      common_deps,
    +      gstisomp4_dep,
    +      dependency('gstreamer-emscripten-1.0'),
    +      dependency('gstdebugutilsbad'),
    +    ],
    +    link_with: [
    +      gstweb_dep,
    +    ],
    +    link_args: common_link_args + [
    +      '-lembind',
    +      '-sASYNCIFY',
    +      # This is giving problems when running the WebRunner at set_format
    +      '-sPROXY_TO_PTHREAD',
    +      # Required by webfetchsrc, this should be brought directly by the dep
    +      '-sFETCH=1',
    +      '-g3',
    +      '-lhtml5',
    +    ],
    +    c_args: [
    +      '-g3',
    +      '-O0',
    +    ],
    +    name_suffix: 'js',
    +    install: true,
    +    install_dir: install_dir
    +)
    +
    +install_data(html_code, install_dir: install_dir)
    +
    +custom_target('js',
    +  input: html_code,
    +  output: html_code,
    +  command: ['cp', '@INPUT@', '@OUTPUT@'],
    +  install: true,
    +  install_dir: install_dir)
    +
    +# This should be changed to something that works at compile time
    +html_data = configuration_data()
    +html_data.set('PAGE_NAME', html_code)
    +html_data.set('PAGE_CODE', fs.read(html_code).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace('\'', ''').strip())
    +html_data.set('EXECUTABLE_NAME', executable_name + '.js')
    +html_data.set('CODE', fs.read(c_code).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace('\'', ''').strip())
    +
    +configure_file(
    +  input: '../template.html',
    +  output: executable_name + '.html',
    +  configuration: html_data,
    +  install: true,
    +  install_dir: install_dir
    +)
    diff --git a/gst.wasm/subprojects/samples/webdownload/webdownload-example-page.html b/gst.wasm/subprojects/samples/webdownload/webdownload-example-page.html
    new file mode 100644
    index 0000000..8ec2e6f
    --- /dev/null
    +++ b/gst.wasm/subprojects/samples/webdownload/webdownload-example-page.html
    @@ -0,0 +1,14 @@
    +
    +
    +   
    +  
    +    
    +    
    +    

    Open the inspector to see output

    + + diff --git a/gst.wasm/subprojects/samples/webdownload/webdownload-example.c b/gst.wasm/subprojects/samples/webdownload/webdownload-example.c new file mode 100644 index 0000000..c12ecce --- /dev/null +++ b/gst.wasm/subprojects/samples/webdownload/webdownload-example.c @@ -0,0 +1,79 @@ +/* + * Gst.WASM + * Copyright 2024 Fluendo S.A. + * @author: Jorge Zapata + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#define DEFAULT_URL \ + "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/" \ + "BigBuckBunny.mp4" + +#define GST_CAT_DEFAULT example_dbg +GST_DEBUG_CATEGORY_STATIC (example_dbg); + +static GstElement *pipeline; + +static void +register_elements () +{ + GST_PLUGIN_STATIC_DECLARE (coreelements); + GST_PLUGIN_STATIC_DECLARE (web); + GST_PLUGIN_STATIC_DECLARE (isomp4); + GST_PLUGIN_STATIC_DECLARE (debugutilsbad); + + GST_PLUGIN_STATIC_REGISTER (coreelements); + GST_PLUGIN_STATIC_REGISTER (web); + GST_PLUGIN_STATIC_REGISTER (isomp4); + GST_PLUGIN_STATIC_REGISTER (debugutilsbad); +} + +static void +init_pipeline () +{ + pipeline = + gst_parse_launch ("webstreamsrc location=" DEFAULT_URL " ! " + "qtdemux ! webcodecsviddech264sw ! webdownload ! " + "video/x-raw ! checksumsink", + NULL); + + g_signal_connect (pipeline, "deep-notify", + G_CALLBACK (gst_object_default_deep_notify), NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); +} + +int +main (int argc, char **argv) +{ + gst_debug_set_default_threshold (1); + gst_init (NULL, NULL); + gst_emscripten_init (); + + GST_DEBUG_CATEGORY_INIT (example_dbg, "example", 0, "webcodecs example"); + gst_debug_set_threshold_from_string ("example:5,webdownload:5", FALSE); + + GST_INFO ("Registering elements"); + register_elements (); + + GST_INFO ("Initializing pipeline"); + init_pipeline (); + + return 0; +}