0,0 → 1,201 |
/* |
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org> |
* |
* 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 <http://www.gnu.org/licenses/>. |
*/ |
|
#include <gst/gst.h> |
|
#include "content/content_factory.h" |
#include "content/content_protected.h" |
#include "image/video.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 = calloc(1, sizeof(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) { |
free(video); |
return error; |
} |
|
error = llcache_handle_force_stream(llcache); |
if (error != NSERROR_OK) { |
free(video); |
return error; |
} |
|
video->playbin = gst_element_factory_make("playbin2", NULL); |
if (video->playbin == NULL) { |
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); |
|