/* * Copyright 2011 John-Mark Bell * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * NetSurf 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "content/content_factory.h" #include "content/content_protected.h" #include "image/video.h" #include "utils/talloc.h" typedef struct nsvideo_content { struct content base; GstElement *playbin; GstElement *appsrc; } nsvideo_content; static gboolean nsvideo_bus_call(GstBus *bus, GstMessage *msg, nsvideo_content *video) { switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_ERROR: break; case GST_MESSAGE_EOS: break; default: break; } return TRUE; } static void nsvideo_need_data_event(GstElement *playbin, guint size, nsvideo_content *video) { } static void nsvideo_enough_data_event(GstElement *playbin, nsvideo_content *video) { } static void nsvideo_source_event(GObject *object, GObject *orig, GParamSpec *pspec, nsvideo_content *video) { g_object_get(orig, pspec->name, &video->appsrc, NULL); g_signal_connect(video->appsrc, "need-data", G_CALLBACK(nsvideo_need_data_event), video); g_signal_connect(video->appsrc, "enough-data", G_CALLBACK(nsvideo_enough_data_event), video); } static nserror nsvideo_create(const content_handler *handler, lwc_string *imime_type, const http_parameter *params, llcache_handle *llcache, const char *fallback_charset, bool quirks, struct content **c) { nsvideo_content *video; nserror error; GstBus *bus; video = talloc_zero(0, nsvideo_content); if (video == NULL) return NSERROR_NOMEM; error = content__init(&video->base, handler, imime_type, params, llcache, fallback_charset, quirks); if (error != NSERROR_OK) { talloc_free(video); return error; } error = llcache_handle_force_stream(llcache); if (error != NSERROR_OK) { talloc_free(video); return error; } video->playbin = gst_element_factory_make("playbin2", NULL); if (video->playbin == NULL) { talloc_free(video); return NSERROR_NOMEM; } bus = gst_pipeline_get_bus(GST_PIPELINE(video->playbin)); gst_bus_add_watch(bus, (GstBusFunc) nsvideo_bus_call, video); gst_object_unref(bus); g_object_set(video->playbin, "uri", "appsrc://", NULL); g_signal_connect(video->playbin, "deep-notify::source", G_CALLBACK(nsvideo_source_event), video); /** \todo Create appsink & register with playbin */ gst_element_set_state(video->playbin, GST_STATE_PLAYING); *c = (struct content *) video; return NSERROR_OK; } static bool nsvideo_process_data(struct content *c, const char *data, unsigned int size) { nsvideo_content *video = (nsvideo_content *) c; GstBuffer *buffer; GstFlowReturn ret; buffer = gst_buffer_new(); GST_BUFFER_DATA(buffer) = (guint8 *) data; GST_BUFFER_SIZE(buffer) = (gsize) size; /* Send data to appsrc */ g_signal_emit_by_name(video->appsrc, "push-buffer", buffer, &ret); return ret == GST_FLOW_OK; } static bool nsvideo_convert(struct content *c) { nsvideo_content *video = (nsvideo_content *) c; GstFlowReturn ret; /* Tell appsrc we're done */ g_signal_emit_by_name(video->appsrc, "end-of-stream", &ret); /* Appsink will flag DONE on receipt of first frame */ return ret == GST_FLOW_OK; } static void nsvideo_destroy(struct content *c) { nsvideo_content *video = (nsvideo_content *) c; gst_element_set_state(video->playbin, GST_STATE_NULL); gst_object_unref(video->playbin); } static bool nsvideo_redraw(struct content *c, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx) { /** \todo Implement */ return true; } static nserror nsvideo_clone(const struct content *old, struct content **newc) { /** \todo Implement */ return NSERROR_CLONE_FAILED; } static content_type nsvideo_type(void) { /** \todo Lies */ return CONTENT_IMAGE; } static void *nsvideo_get_internal(const struct content *c, void *context) { /** \todo Return pointer to bitmap containing current frame, if any? */ return NULL; } static const content_handler nsvideo_content_handler = { .create = nsvideo_create, .process_data = nsvideo_process_data, .data_complete = nsvideo_convert, .destroy = nsvideo_destroy, .redraw = nsvideo_redraw, .clone = nsvideo_clone, .type = nsvideo_type, .get_internal = nsvideo_get_internal, /* Can't share videos because we stream them */ .no_share = true }; static const char *nsvideo_types[] = { "video/mp4", "video/webm" }; CONTENT_FACTORY_REGISTER_TYPES(nsvideo, nsvideo_types, nsvideo_content_handler);