Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
@@ -0,0 +1,47 @@
# -*- cmake -*-
project(media_plugin_gstreamer010)
include(00-Common)
include(LLCommon)
include(LLImage)
include(LLMath)
include(LLWindow)
include(Linking)
include(PluginAPI)
include(OpenGL)
include(MediaPluginBase) # <FS:Zi> Linux volume catcher
include(GStreamer010Plugin)
### media_plugin_gstreamer010
if(NOT ADDRESS_SIZE EQUAL 32)
if(WINDOWS)
##add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)
endif(NOT ADDRESS_SIZE EQUAL 32)
set(media_plugin_gstreamer010_SOURCE_FILES
media_plugin_gstreamer010.cpp
llmediaimplgstreamer_syms.cpp
llmediaimplgstreamervidplug.cpp
)
set(media_plugin_gstreamer010_HEADER_FILES
llmediaimplgstreamervidplug.h
llmediaimplgstreamer_syms.h
llmediaimplgstreamertriviallogging.h
)
add_library(media_plugin_gstreamer010
SHARED
${media_plugin_gstreamer010_SOURCE_FILES}
)
target_link_libraries(media_plugin_gstreamer010
media_plugin_base
ll::gstreamer
)
@@ -0,0 +1,53 @@
/**
* @file llmediaimplgstreamer.h
* @author Tofu Linden
* @brief implementation that supports media playback via GStreamer.
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
*/
// header guard
#ifndef llmediaimplgstreamer_h
#define llmediaimplgstreamer_h
#if LL_GSTREAMER010_ENABLED
extern "C" {
#include <stdio.h>
#include <gst/gst.h>
#include "apr_pools.h"
#include "apr_dso.h"
}
extern "C" {
gboolean llmediaimplgstreamer_bus_callback (GstBus *bus,
GstMessage *message,
gpointer data);
}
#endif // LL_GSTREAMER010_ENABLED
#endif // llmediaimplgstreamer_h
@@ -0,0 +1,167 @@
/**
* @file llmediaimplgstreamer_syms.cpp
* @brief dynamic GStreamer symbol-grabbing code
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
*/
#if LL_GSTREAMER010_ENABLED
#include <string>
extern "C" {
#include <gst/gst.h>
#include "apr_pools.h"
#include "apr_dso.h"
}
#include "llmediaimplgstreamertriviallogging.h"
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL
#include "llmediaimplgstreamer_syms_raw.inc"
#include "llmediaimplgstreamer_syms_rawv.inc"
#undef LL_GST_SYM
// a couple of stubs for disgusting reasons
GstDebugCategory*
ll_gst_debug_category_new(gchar *name, guint color, gchar *description)
{
static GstDebugCategory dummy;
return &dummy;
}
void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)
{
}
static bool sSymsGrabbed = false;
static apr_pool_t *sSymGSTDSOMemoryPool = NULL;
static apr_dso_handle_t *sSymGSTDSOHandleG = NULL;
static apr_dso_handle_t *sSymGSTDSOHandleV = NULL;
bool grab_gst_syms(std::string gst_dso_name,
std::string gst_dso_name_vid)
{
if (sSymsGrabbed)
{
// already have grabbed good syms
return TRUE;
}
bool sym_error = false;
bool rtn = false;
apr_status_t rv;
apr_dso_handle_t *sSymGSTDSOHandle = NULL;
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0)
//attempt to load the shared libraries
apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle,
gst_dso_name.c_str(),
sSymGSTDSOMemoryPool) ))
{
INFOMSG("Found DSO: %s", gst_dso_name.c_str());
#include "llmediaimplgstreamer_syms_raw.inc"
if ( sSymGSTDSOHandle )
{
sSymGSTDSOHandleG = sSymGSTDSOHandle;
sSymGSTDSOHandle = NULL;
}
if ( APR_SUCCESS ==
(rv = apr_dso_load(&sSymGSTDSOHandle,
gst_dso_name_vid.c_str(),
sSymGSTDSOMemoryPool) ))
{
INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str());
#include "llmediaimplgstreamer_syms_rawv.inc"
rtn = !sym_error;
}
else
{
INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str());
rtn = false; // failure
}
}
else
{
INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str());
rtn = false; // failure
}
if (sym_error)
{
WARNMSG("Failed to find necessary symbols in GStreamer libraries.");
}
if ( sSymGSTDSOHandle )
{
sSymGSTDSOHandleV = sSymGSTDSOHandle;
sSymGSTDSOHandle = NULL;
}
#undef LL_GST_SYM
sSymsGrabbed = !!rtn;
return rtn;
}
void ungrab_gst_syms()
{
// should be safe to call regardless of whether we've
// actually grabbed syms.
if ( sSymGSTDSOHandleG )
{
apr_dso_unload(sSymGSTDSOHandleG);
sSymGSTDSOHandleG = NULL;
}
if ( sSymGSTDSOHandleV )
{
apr_dso_unload(sSymGSTDSOHandleV);
sSymGSTDSOHandleV = NULL;
}
if ( sSymGSTDSOMemoryPool )
{
apr_pool_destroy(sSymGSTDSOMemoryPool);
sSymGSTDSOMemoryPool = NULL;
}
// NULL-out all of the symbols we'd grabbed
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0)
#include "llmediaimplgstreamer_syms_raw.inc"
#include "llmediaimplgstreamer_syms_rawv.inc"
#undef LL_GST_SYM
sSymsGrabbed = false;
}
#endif // LL_GSTREAMER010_ENABLED
@@ -0,0 +1,74 @@
/**
* @file llmediaimplgstreamer_syms.h
* @brief dynamic GStreamer symbol-grabbing code
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
*/
#include "linden_common.h"
#if LL_GSTREAMER010_ENABLED
extern "C" {
#include <gst/gst.h>
}
bool grab_gst_syms(std::string gst_dso_name,
std::string gst_dso_name_vid);
void ungrab_gst_syms();
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__)
#include "llmediaimplgstreamer_syms_raw.inc"
#include "llmediaimplgstreamer_syms_rawv.inc"
#undef LL_GST_SYM
// regrettable hacks to give us better runtime compatibility with older systems
#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0)
// regrettable hacks because GStreamer was not designed for runtime loading
#undef GST_TYPE_MESSAGE
#define GST_TYPE_MESSAGE (llgst_message_get_type())
#undef GST_TYPE_OBJECT
#define GST_TYPE_OBJECT (llgst_object_get_type())
#undef GST_TYPE_PIPELINE
#define GST_TYPE_PIPELINE (llgst_pipeline_get_type())
#undef GST_TYPE_ELEMENT
#define GST_TYPE_ELEMENT (llgst_element_get_type())
#undef GST_TYPE_VIDEO_SINK
#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type())
// more regrettable hacks to stub-out these .h-exposed GStreamer internals
void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname);
#undef _gst_debug_register_funcptr
#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr
GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description);
#undef _gst_debug_category_new
#define _gst_debug_category_new ll_gst_debug_category_new
#undef __gst_debug_enabled
#define __gst_debug_enabled (0)
// more hacks
#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M)))
#endif // LL_GSTREAMER010_ENABLED
@@ -0,0 +1,59 @@
// required symbols to grab
LL_GST_SYM(true, gst_pad_peer_accept_caps, gboolean, GstPad *pad, GstCaps *caps);
LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void);
LL_GST_SYM(true, gst_buffer_set_caps, void, GstBuffer*, GstCaps *);
LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*);
LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err);
LL_GST_SYM(true, gst_message_get_type, GType, void);
LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type);
LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug);
LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug);
LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending);
LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state);
LL_GST_SYM(true, gst_object_unref, void, gpointer object);
LL_GST_SYM(true, gst_object_get_type, GType, void);
LL_GST_SYM(true, gst_pipeline_get_type, GType, void);
LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline);
LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data);
LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name);
LL_GST_SYM(true, gst_element_get_type, GType, void);
LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template);
LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp);
LL_GST_SYM(true, gst_element_class_set_details, void, GstElementClass *klass, const GstElementDetails *details);
LL_GST_SYM(true, gst_caps_unref, void, GstCaps* caps);
LL_GST_SYM(true, gst_caps_ref, GstCaps *, GstCaps* caps);
//LL_GST_SYM(true, gst_caps_is_empty, gboolean, const GstCaps *caps);
LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string);
LL_GST_SYM(true, gst_caps_replace, void, GstCaps **caps, GstCaps *newcaps);
LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index);
LL_GST_SYM(true, gst_caps_copy, GstCaps *, const GstCaps * caps);
//LL_GST_SYM(true, gst_caps_intersect, GstCaps *, const GstCaps *caps1, const GstCaps *caps2);
LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type);
LL_GST_SYM(true, _gst_plugin_register_static, void, GstPluginDesc *desc);
LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value);
LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname);
LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value);
LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value);
LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure);
LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64);
// optional symbols to grab
LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled);
LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled);
LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent);
LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug);
LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur);
LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano);
// GStreamer 'internal' symbols which may not be visible in some runtimes but are still used in expanded GStreamer header macros - yuck! We'll substitute our own stubs for these.
//LL_GST_SYM(true, _gst_debug_register_funcptr, void, GstDebugFuncPtr func, gchar* ptrname);
//LL_GST_SYM(true, _gst_debug_category_new, GstDebugCategory *, gchar *name, guint color, gchar *description);
// [ML] Symbols needed to make "Now playing" work in standard builds
LL_GST_SYM(true, gst_message_parse_tag, void, GstMessage *, GstTagList **);
LL_GST_SYM(true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer);
LL_GST_SYM(true, gst_tag_list_free, void, GstTagList *);
LL_GST_SYM(true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *);
LL_GST_SYM(true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint);
// [/ML]
@@ -0,0 +1,5 @@
// required symbols to grab
LL_GST_SYM(true, gst_video_sink_get_type, GType, void);
// optional symbols to grab
@@ -0,0 +1,55 @@
/**
* @file llmediaimplgstreamertriviallogging.h
* @brief minimal logging utilities.
*
* @cond
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
*/
#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__
#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__
#include <cstdio>
extern "C" {
#include <sys/types.h>
#include <unistd.h>
}
/////////////////////////////////////////////////////////////////////////
// Debug/Info/Warning macros.
#define MSGMODULEFOO "(media plugin)"
#define STDERRMSG(...) do{\
fprintf(stderr, " pid:%d: ", (int)getpid());\
fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\
fprintf(stderr, __VA_ARGS__);\
fputc('\n',stderr);\
}while(0)
#define NULLMSG(...) do{}while(0)
#define DEBUGMSG NULLMSG
#define INFOMSG STDERRMSG
#define WARNMSG STDERRMSG
/////////////////////////////////////////////////////////////////////////
#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */
@@ -0,0 +1,526 @@
/**
* @file llmediaimplgstreamervidplug.h
* @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
*/
#if LL_GSTREAMER010_ENABLED
#include "linden_common.h"
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideosink.h>
#include "llmediaimplgstreamer_syms.h"
#include "llmediaimplgstreamertriviallogging.h"
#include "llmediaimplgstreamervidplug.h"
GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug);
#define GST_CAT_DEFAULT gst_slvideo_debug
#define SLV_SIZECAPS ", width=(int)[1,2048], height=(int)[1,2048] "
#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE (
(gchar*)"sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (SLV_ALLCAPS)
);
GST_BOILERPLATE (GstSLVideo, gst_slvideo, GstVideoSink,
GST_TYPE_VIDEO_SINK);
static void gst_slvideo_set_property (GObject * object, guint prop_id,
const GValue * value,
GParamSpec * pspec);
static void gst_slvideo_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void
gst_slvideo_base_init (gpointer gclass)
{
static GstElementDetails element_details = {
(gchar*)"PluginTemplate",
(gchar*)"Generic/PluginTemplate",
(gchar*)"Generic Template Element",
(gchar*)"Linden Lab"
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
llgst_element_class_add_pad_template (element_class,
llgst_static_pad_template_get (&sink_factory));
llgst_element_class_set_details (element_class, &element_details);
}
static void
gst_slvideo_finalize (GObject * object)
{
GstSLVideo *slvideo;
slvideo = GST_SLVIDEO (object);
if (slvideo->caps)
{
llgst_caps_unref(slvideo->caps);
}
G_OBJECT_CLASS(parent_class)->finalize (object);
}
static GstFlowReturn
gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf)
{
GstSLVideo *slvideo;
llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
slvideo = GST_SLVIDEO(bsink);
DEBUGMSG("transferring a frame of %dx%d <- %p (%d)",
slvideo->width, slvideo->height, GST_BUFFER_DATA(buf),
slvideo->format);
if (GST_BUFFER_DATA(buf))
{
// copy frame and frame info into neutral territory
GST_OBJECT_LOCK(slvideo);
slvideo->retained_frame_ready = TRUE;
slvideo->retained_frame_width = slvideo->width;
slvideo->retained_frame_height = slvideo->height;
slvideo->retained_frame_format = slvideo->format;
int rowbytes =
SLVPixelFormatBytes[slvideo->retained_frame_format] *
slvideo->retained_frame_width;
int needbytes = rowbytes * slvideo->retained_frame_width;
// resize retained frame hunk only if necessary
if (needbytes != slvideo->retained_frame_allocbytes)
{
delete[] slvideo->retained_frame_data;
slvideo->retained_frame_data = new unsigned char[needbytes];
slvideo->retained_frame_allocbytes = needbytes;
}
// copy the actual frame data to neutral territory -
// flipped, for GL reasons
for (int ypos=0; ypos<slvideo->height; ++ypos)
{
memcpy(&slvideo->retained_frame_data[(slvideo->height-1-ypos)*rowbytes],
&(((unsigned char*)GST_BUFFER_DATA(buf))[ypos*rowbytes]),
rowbytes);
}
// done with the shared data
GST_OBJECT_UNLOCK(slvideo);
}
return GST_FLOW_OK;
}
static GstStateChangeReturn
gst_slvideo_change_state(GstElement * element, GstStateChange transition)
{
GstSLVideo *slvideo;
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
slvideo = GST_SLVIDEO (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
slvideo->fps_n = 0;
slvideo->fps_d = 1;
GST_VIDEO_SINK_WIDTH(slvideo) = 0;
GST_VIDEO_SINK_HEIGHT(slvideo) = 0;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
default:
break;
}
return ret;
}
static GstCaps *
gst_slvideo_get_caps (GstBaseSink * bsink)
{
GstSLVideo *slvideo;
slvideo = GST_SLVIDEO(bsink);
return llgst_caps_ref (slvideo->caps);
}
/* this function handles the link with other elements */
static gboolean
gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
GstSLVideo *filter;
GstStructure *structure;
GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
filter = GST_SLVIDEO(bsink);
int width, height;
gboolean ret;
const GValue *fps;
const GValue *par;
structure = llgst_caps_get_structure (caps, 0);
ret = llgst_structure_get_int (structure, "width", &width);
ret = ret && llgst_structure_get_int (structure, "height", &height);
fps = llgst_structure_get_value (structure, "framerate");
ret = ret && (fps != NULL);
par = llgst_structure_get_value (structure, "pixel-aspect-ratio");
if (!ret)
return FALSE;
INFOMSG("** filter caps set with width=%d, height=%d", width, height);
GST_OBJECT_LOCK(filter);
filter->width = width;
filter->height = height;
filter->fps_n = llgst_value_get_fraction_numerator(fps);
filter->fps_d = llgst_value_get_fraction_denominator(fps);
if (par)
{
filter->par_n = llgst_value_get_fraction_numerator(par);
filter->par_d = llgst_value_get_fraction_denominator(par);
}
else
{
filter->par_n = 1;
filter->par_d = 1;
}
GST_VIDEO_SINK_WIDTH(filter) = width;
GST_VIDEO_SINK_HEIGHT(filter) = height;
// crufty lump - we *always* accept *only* RGBX now.
/*
filter->format = SLV_PF_UNKNOWN;
if (0 == strcmp(llgst_structure_get_name(structure),
"video/x-raw-rgb"))
{
int red_mask;
int green_mask;
int blue_mask;
llgst_structure_get_int(structure, "red_mask", &red_mask);
llgst_structure_get_int(structure, "green_mask", &green_mask);
llgst_structure_get_int(structure, "blue_mask", &blue_mask);
if ((unsigned int)red_mask == 0xFF000000 &&
(unsigned int)green_mask == 0x00FF0000 &&
(unsigned int)blue_mask == 0x0000FF00)
{
filter->format = SLV_PF_RGBX;
//fprintf(stderr, "\n\nPIXEL FORMAT RGB\n\n");
} else if ((unsigned int)red_mask == 0x0000FF00 &&
(unsigned int)green_mask == 0x00FF0000 &&
(unsigned int)blue_mask == 0xFF000000)
{
filter->format = SLV_PF_BGRX;
//fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n");
}
}*/
filter->format = SLV_PF_RGBX;
GST_OBJECT_UNLOCK(filter);
return TRUE;
}
static gboolean
gst_slvideo_start (GstBaseSink * bsink)
{
gboolean ret = TRUE;
GST_SLVIDEO(bsink);
return ret;
}
static gboolean
gst_slvideo_stop (GstBaseSink * bsink)
{
GstSLVideo *slvideo;
slvideo = GST_SLVIDEO(bsink);
// free-up retained frame buffer
GST_OBJECT_LOCK(slvideo);
slvideo->retained_frame_ready = FALSE;
delete[] slvideo->retained_frame_data;
slvideo->retained_frame_data = NULL;
slvideo->retained_frame_allocbytes = 0;
GST_OBJECT_UNLOCK(slvideo);
return TRUE;
}
static GstFlowReturn
gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
GstCaps * caps, GstBuffer ** buf)
{
gint width, height;
GstStructure *structure = NULL;
GstSLVideo *slvideo;
slvideo = GST_SLVIDEO(bsink);
// caps == requested caps
// we can ignore these and reverse-negotiate our preferred dimensions with
// the peer if we like - we need to do this to obey dynamic resize requests
// flowing in from the app.
structure = llgst_caps_get_structure (caps, 0);
if (!llgst_structure_get_int(structure, "width", &width) ||
!llgst_structure_get_int(structure, "height", &height))
{
GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps);
return GST_FLOW_NOT_NEGOTIATED;
}
GstBuffer *newbuf = llgst_buffer_new();
bool made_bufferdata_ptr = false;
#define MAXDEPTHHACK 4
GST_OBJECT_LOCK(slvideo);
if (slvideo->resize_forced_always) // app is giving us a fixed size to work with
{
gint slwantwidth, slwantheight;
slwantwidth = slvideo->resize_try_width;
slwantheight = slvideo->resize_try_height;
if (slwantwidth != width ||
slwantheight != height)
{
// don't like requested caps, we will issue our own suggestion - copy
// the requested caps but substitute our own width and height and see
// if our peer is happy with that.
GstCaps *desired_caps;
GstStructure *desired_struct;
desired_caps = llgst_caps_copy (caps);
desired_struct = llgst_caps_get_structure (desired_caps, 0);
GValue value = {0};
g_value_init(&value, G_TYPE_INT);
g_value_set_int(&value, slwantwidth);
llgst_structure_set_value (desired_struct, "width", &value);
g_value_unset(&value);
g_value_init(&value, G_TYPE_INT);
g_value_set_int(&value, slwantheight);
llgst_structure_set_value (desired_struct, "height", &value);
if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo),
desired_caps))
{
// todo: re-use buffers from a pool?
// todo: set MALLOCDATA to null, set DATA to point straight to shm?
// peer likes our cap suggestion
DEBUGMSG("peer loves us :)");
GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK;
GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps);
made_bufferdata_ptr = true;
} else {
// peer hates our cap suggestion
INFOMSG("peer hates us :(");
llgst_caps_unref(desired_caps);
}
}
}
GST_OBJECT_UNLOCK(slvideo);
if (!made_bufferdata_ptr) // need to fallback to malloc at original size
{
GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK;
GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps);
}
*buf = GST_BUFFER_CAST(newbuf);
return GST_FLOW_OK;
}
/* initialize the plugin's class */
static void
gst_slvideo_class_init (GstSLVideoClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gobject_class->finalize = gst_slvideo_finalize;
gobject_class->set_property = gst_slvideo_set_property;
gobject_class->get_property = gst_slvideo_get_property;
gstelement_class->change_state = gst_slvideo_change_state;
#define LLGST_DEBUG_FUNCPTR(p) (p)
gstbasesink_class->get_caps = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_caps);
gstbasesink_class->set_caps = LLGST_DEBUG_FUNCPTR( gst_slvideo_set_caps);
gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc);
//gstbasesink_class->get_times = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_times);
gstbasesink_class->preroll = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
gstbasesink_class->render = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
gstbasesink_class->start = LLGST_DEBUG_FUNCPTR (gst_slvideo_start);
gstbasesink_class->stop = LLGST_DEBUG_FUNCPTR (gst_slvideo_stop);
// gstbasesink_class->unlock = LLGST_DEBUG_FUNCPTR (gst_slvideo_unlock);
#undef LLGST_DEBUG_FUNCPTR
}
/* initialize the new element
* instantiate pads and add them to element
* set functions
* initialize structure
*/
static void
gst_slvideo_init (GstSLVideo * filter,
GstSLVideoClass * gclass)
{
filter->caps = NULL;
filter->width = -1;
filter->height = -1;
// this is the info we share with the client app
GST_OBJECT_LOCK(filter);
filter->retained_frame_ready = FALSE;
filter->retained_frame_data = NULL;
filter->retained_frame_allocbytes = 0;
filter->retained_frame_width = filter->width;
filter->retained_frame_height = filter->height;
filter->retained_frame_format = SLV_PF_UNKNOWN;
GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS);
llgst_caps_replace (&filter->caps, caps);
filter->resize_forced_always = false;
filter->resize_try_width = -1;
filter->resize_try_height = -1;
GST_OBJECT_UNLOCK(filter);
}
static void
gst_slvideo_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
llg_return_if_fail (GST_IS_SLVIDEO (object));
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_slvideo_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
llg_return_if_fail (GST_IS_SLVIDEO (object));
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* entry point to initialize the plug-in
* initialize the plug-in itself
* register the element factories and pad templates
* register the features
*/
static gboolean
plugin_init (GstPlugin * plugin)
{
DEBUGMSG("PLUGIN INIT");
GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin",
0, (gchar*)"Second Life Video Sink");
return llgst_element_register (plugin, "private-slvideo",
GST_RANK_NONE, GST_TYPE_SLVIDEO);
}
/* this is the structure that gstreamer looks for to register plugins
*/
/* NOTE: Can't rely upon GST_PLUGIN_DEFINE_STATIC to self-register, since
some g++ versions buggily avoid __attribute__((constructor)) functions -
so we provide an explicit plugin init function.
*/
#define PACKAGE (gchar*)"packagehack"
// this macro quietly refers to PACKAGE internally
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
(gchar*)"private-slvideoplugin",
(gchar*)"SL Video sink plugin",
plugin_init, (gchar*)"1.0", (gchar*)"LGPL",
(gchar*)"Firestorm",
(gchar*)"http://www.firestormviewer.org");
#undef PACKAGE
void gst_slvideo_init_class (void)
{
ll_gst_plugin_register_static (&gst_plugin_desc);
DEBUGMSG("CLASS INIT");
}
#endif // LL_GSTREAMER010_ENABLED
@@ -0,0 +1,105 @@
/**
* @file llmediaimplgstreamervidplug.h
* @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
*/
#ifndef __GST_SLVIDEO_H__
#define __GST_SLVIDEO_H__
#if LL_GSTREAMER010_ENABLED
extern "C" {
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideosink.h>
}
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_SLVIDEO \
(gst_slvideo_get_type())
#define GST_SLVIDEO(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SLVIDEO,GstSLVideo))
#define GST_SLVIDEO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SLVIDEO,GstSLVideoClass))
#define GST_IS_SLVIDEO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SLVIDEO))
#define GST_IS_SLVIDEO_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SLVIDEO))
typedef struct _GstSLVideo GstSLVideo;
typedef struct _GstSLVideoClass GstSLVideoClass;
typedef enum {
SLV_PF_UNKNOWN = 0,
SLV_PF_RGBX = 1,
SLV_PF_BGRX = 2,
SLV__END = 3
} SLVPixelFormat;
const int SLVPixelFormatBytes[SLV__END] = {1, 4, 4};
struct _GstSLVideo
{
GstVideoSink video_sink;
GstCaps *caps;
int fps_n, fps_d;
int par_n, par_d;
int height, width;
SLVPixelFormat format;
// SHARED WITH APPLICATION:
// Access to the following should be protected by GST_OBJECT_LOCK() on
// the GstSLVideo object, and should be totally consistent upon UNLOCK
// (i.e. all written at once to reflect the current retained frame info
// when the retained frame is updated.)
bool retained_frame_ready; // new frame ready since flag last reset. (*TODO: could get the writer to wait on a semaphore instead of having the reader poll, potentially making dropped frames somewhat cheaper.)
unsigned char* retained_frame_data;
int retained_frame_allocbytes;
int retained_frame_width, retained_frame_height;
SLVPixelFormat retained_frame_format;
// sticky resize info
bool resize_forced_always;
int resize_try_width;
int resize_try_height;
};
struct _GstSLVideoClass
{
GstVideoSinkClass parent_class;
};
GType gst_slvideo_get_type (void);
void gst_slvideo_init_class (void);
G_END_DECLS
#endif // LL_GSTREAMER010_ENABLED
#endif /* __GST_SLVIDEO_H__ */
File diff suppressed because it is too large Load Diff