diff options
| -rw-r--r-- | recipes/ti/gstreamer-ti/gstreamer-ti-add-omapfb.patch | 1336 | ||||
| -rw-r--r-- | recipes/ti/gstreamer-ti_svn.bb | 11 |
2 files changed, 1345 insertions, 2 deletions
diff --git a/recipes/ti/gstreamer-ti/gstreamer-ti-add-omapfb.patch b/recipes/ti/gstreamer-ti/gstreamer-ti-add-omapfb.patch new file mode 100644 index 0000000000..e7b1dab300 --- /dev/null +++ b/recipes/ti/gstreamer-ti/gstreamer-ti-add-omapfb.patch @@ -0,0 +1,1336 @@ +diff -uNr ticodecplugin/configure.ac ticodecplugin.new/configure.ac +--- ticodecplugin/configure.ac 2009-09-05 00:04:51.000000000 -0500 ++++ ticodecplugin.new/configure.ac 2009-09-15 13:14:44.000000000 -0500 +@@ -25,6 +25,7 @@ + AC_SUBST(ACLOCAL_AMFLAGS, "-I m4") + + AM_CONFIG_HEADER(config.h) ++AM_PROG_AS + + dnl check for tools + AC_PROG_CC +diff -uNr ticodecplugin/src/Makefile.am ticodecplugin.new/src/Makefile.am +--- ticodecplugin/src/Makefile.am 2009-09-05 00:04:51.000000000 -0500 ++++ ticodecplugin.new/src/Makefile.am 2009-09-15 13:14:44.000000000 -0500 +@@ -4,16 +4,16 @@ + plugin_LTLIBRARIES = libgstticodecplugin.la + + # sources used to compile this plug-in +-libgstticodecplugin_la_SOURCES = gstticodecplugin.c gsttiauddec.c gsttiauddec1.c gsttividdec.c gsttividdec2.c gsttiimgenc1.c gsttiimgenc.c gsttiimgdec1.c gsttiimgdec.c gsttidmaibuffertransport.c gstticircbuffer.c gsttidmaivideosink.c gstticodecs.c gstticodecs_platform.c gsttiquicktime_aac.c gsttiquicktime_h264.c gsttividenc.c gsttividenc1.c gstticommonutils.c ++libgstticodecplugin_la_SOURCES = gstticodecplugin.c gsttiauddec.c gsttiauddec1.c gsttividdec.c gsttividdec2.c gsttiimgenc1.c gsttiimgenc.c gsttiimgdec1.c gsttiimgdec.c gsttidmaibuffertransport.c gstticircbuffer.c gsttidmaivideosink.c gstticodecs.c gstticodecs_platform.c gsttiquicktime_aac.c gsttiquicktime_h264.c gsttividenc.c gsttividenc1.c gstticommonutils.c omapfb.c yuv.S + + # flags used to compile this plugin + # add other _CFLAGS and _LIBS as needed +-libgstticodecplugin_la_CFLAGS = $(GST_CFLAGS) $(shell cat $(XDC_CONFIG_BASENAME)/compiler.opt) +-libgstticodecplugin_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstvideo-0.10 -lgstaudio-0.10 -lm ++libgstticodecplugin_la_CFLAGS = $(GST_CFLAGS) $(shell cat $(XDC_CONFIG_BASENAME)/compiler.opt) -I$(LINUXKERNEL_INSTALL_DIR)/include ++libgstticodecplugin_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstvideo-0.10 -lgstaudio-0.10 -lm -lX11 + libgstticodecplugin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,$(XDC_CONFIG_BASENAME)/linker.cmd + + # headers we need but don't want installed +-noinst_HEADERS = gsttiauddec.h gsttiauddec1.h gsttividdec.h gsttividdec2.h gsttiimgenc1.h gsttiimgenc.h gsttiimgdec1.h gsttiimgdec.h gsttidmaibuffertransport.h gstticircbuffer.h gsttidmaivideosink.h gsttithreadprops.h gstticodecs.h gsttiquicktime_aac.h gsttiquicktime_h264.h gsttividenc.h gsttividenc1.h gstticommonutils.h ++noinst_HEADERS = gsttiauddec.h gsttiauddec1.h gsttividdec.h gsttividdec2.h gsttiimgenc1.h gsttiimgenc.h gsttiimgdec1.h gsttiimgdec.h gsttidmaibuffertransport.h gstticircbuffer.h gsttidmaivideosink.h gsttithreadprops.h gstticodecs.h gsttiquicktime_aac.h gsttiquicktime_h264.h gsttividenc.h gsttividenc1.h gstticommonutils.h omapfb.h + + # XDC Configuration + CONFIGURO = $(XDC_INSTALL_DIR)/xs xdc.tools.configuro +diff -uNr ticodecplugin/src/gstticodecplugin.c ticodecplugin.new/src/gstticodecplugin.c +--- ticodecplugin/src/gstticodecplugin.c 2009-09-05 00:04:51.000000000 -0500 ++++ ticodecplugin.new/src/gstticodecplugin.c 2009-09-15 13:14:44.000000000 -0500 +@@ -44,6 +44,7 @@ + #include "gsttidmaivideosink.h" + #include "gsttividenc.h" + #include "gsttividenc1.h" ++#include "omapfb.h" + + /* entry point to initialize the plug-in + * initialize the plug-in itself +@@ -137,6 +138,13 @@ + GST_TYPE_TIDMAIVIDEOSINK)) + return FALSE; + ++ env_value = getenv("GST_Omapfbdmaisink_DISABLE"); ++ ++ if ((!env_value || strcmp(env_value,"1")) && !gst_element_register( ++ TICodecPlugin, "omapdmaifbsink", GST_RANK_PRIMARY, ++ GST_OMAPFB_SINK_TYPE)) ++ return FALSE; ++ + return TRUE; + } + +diff -uNr ticodecplugin/src/omapfb.c ticodecplugin.new/src/omapfb.c +--- ticodecplugin/src/omapfb.c 1969-12-31 18:00:00.000000000 -0600 ++++ ticodecplugin.new/src/omapfb.c 2009-09-15 13:16:03.000000000 -0500 +@@ -0,0 +1,1005 @@ ++/* ++ * Copyright (C) 2008 Felipe Contreras <felipe.contreras@gmail.com> ++ * Copyright (C) 2009 Tim Yamin <plasm@roo.me.uk> ++ * Copyright (C) 2009 Brijesh Singh <brijesh.ksingh@gmail.com> ++ * ++ * X code largely copied from ximagesink by Julien Moutte and ++ * vo_omapfb.c by Gregoire Gentil. ++ * ++ * Use DMAI hw framecopy module to copy the dmai transport buffers. ++ * ++ * 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. ++ * ++ * 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 General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA ++ */ ++ ++#include <fcntl.h> ++#include <sys/ioctl.h> ++#include <sys/mman.h> ++#include <unistd.h> ++#include <string.h> ++#include <sys/types.h> ++#include <malloc.h> ++#include <stdlib.h> ++ ++#include "omapfb.h" ++#include <gst/interfaces/xoverlay.h> ++ ++static GstVideoSinkClass *parent_class = NULL; ++ ++extern void yuv420_to_yuv422(__uint8_t *yuv, __uint8_t *y, __uint8_t *u, __uint8_t *v, ++ int w, int h, int yw, int cw, int dw); ++ ++static void x11_get_window_abs_position(Display *display, Window window, ++ int *wx, int *wy, int *ww, int *wh) ++{ ++ Window root, parent; ++ Window *child; ++ unsigned int n_children; ++ XWindowAttributes attribs; ++ ++ /* Get window attributes */ ++ XGetWindowAttributes(display, window, &attribs); ++ ++ /* Get relative position of given window */ ++ *wx = attribs.x; ++ *wy = attribs.y; ++ if (ww) ++ *ww = attribs.width; ++ if (wh) ++ *wh = attribs.height; ++ ++ /* Query window tree information */ ++ XQueryTree(display, window, &root, &parent, &child, &n_children); ++ if (parent) ++ { ++ int x, y; ++ ++ /* If we have a parent we must go there and discover his position */ ++ x11_get_window_abs_position(display, parent, &x, &y, NULL, NULL); ++ *wx += x; ++ *wy += y; ++ } ++ ++ /* If we had children, free them */ ++ if(n_children) ++ XFree(child); ++} ++ ++static GstXWindow * ++gst_omapfbsink_xwindow_new (GstOmapFbSink * omapfbsink, gint width, gint height) ++{ ++ GstXWindow *xwindow = NULL; ++ XGCValues values; ++ ++ if(!omapfbsink->xcontext) ++ return NULL; ++ ++ xwindow = g_new0 (GstXWindow, 1); ++ xwindow->width = width; ++ xwindow->height = height; ++ xwindow->internal = TRUE; ++ ++ g_mutex_lock (omapfbsink->x_lock); ++ xwindow->win = XCreateSimpleWindow (omapfbsink->xcontext->disp, ++ omapfbsink->xcontext->root, ++ 0, 0, xwindow->width, xwindow->height, ++ 0, 0, omapfbsink->colorKey); ++ ++ /* We have to do that to prevent X from redrawing the background on ++ ConfigureNotify. This takes away flickering of video when resizing. */ ++ XSetWindowBackgroundPixmap (omapfbsink->xcontext->disp, xwindow->win, None); ++ ++ if (omapfbsink->handle_events) { ++ Atom wm_delete; ++ ++ XSelectInput (omapfbsink->xcontext->disp, xwindow->win, ExposureMask | ++ StructureNotifyMask | PointerMotionMask | KeyPressMask | ++ KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); ++ ++ /* Tell the window manager we'd like delete client messages instead of ++ * being killed */ ++ wm_delete = XInternAtom (omapfbsink->xcontext->disp, ++ "WM_DELETE_WINDOW", False); ++ (void) XSetWMProtocols (omapfbsink->xcontext->disp, xwindow->win, ++ &wm_delete, 1); ++ } ++ ++ xwindow->gc = XCreateGC (omapfbsink->xcontext->disp, xwindow->win, ++ 0, &values); ++ ++ XMapRaised (omapfbsink->xcontext->disp, xwindow->win); ++ XSync (omapfbsink->xcontext->disp, FALSE); ++ ++ g_mutex_unlock (omapfbsink->x_lock); ++ gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (omapfbsink), xwindow->win); ++ ++ return xwindow; ++} ++ ++static gboolean gst_omapfbsink_update_plane (GstOmapFbSink *omapfbsink) ++{ ++ int wx, wy, ww, wh; ++ if (!omapfbsink->xcontext) ++ { ++ if (ioctl (omapfbsink->overlay_fd, OMAPFB_SETUP_PLANE, &omapfbsink->plane_info)) ++ return FALSE; ++ return TRUE; ++ } ++ ++ if (omapfbsink->plane_info.enabled != 1) ++ return FALSE; ++ ++ x11_get_window_abs_position(omapfbsink->xcontext->disp, ++ omapfbsink->xwindow->win, &wx, &wy, &ww, &wh); ++ ++ if (wx != omapfbsink->xwindow->wx || wy != omapfbsink->xwindow->wy || ++ wh != omapfbsink->xwindow->height || ww != omapfbsink->xwindow->width) { ++ omapfbsink->plane_info.out_width = omapfbsink->xwindow->width = ww; ++ omapfbsink->plane_info.out_height = omapfbsink->xwindow->height = wh; ++ omapfbsink->plane_info.pos_x = omapfbsink->xwindow->wx = wx; ++ omapfbsink->plane_info.pos_y = omapfbsink->xwindow->wy = wy; ++ ++ GST_DEBUG_OBJECT(omapfbsink, "updating geometry to: (%d,%d) %dx%d", wx, wy, ww, wh); ++ ++ XSetForeground (omapfbsink->xcontext->disp, omapfbsink->xwindow->gc, omapfbsink->colorKey); ++ XFillRectangle (omapfbsink->xcontext->disp, omapfbsink->xwindow->win, omapfbsink->xwindow->gc, 0, 0, ww, wh); ++ ++ if (ioctl (omapfbsink->overlay_fd, OMAPFB_SETUP_PLANE, &omapfbsink->plane_info)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static void ++gst_omapfbsink_expose (GstXOverlay * overlay) ++{ ++ gst_omapfbsink_update_plane(GST_OMAPFB_SINK (overlay)); ++} ++ ++static void ++gst_omapfbsink_xwindow_destroy (GstOmapFbSink * omapfbsink, ++ GstXWindow * xwindow) ++{ ++ g_return_if_fail (xwindow != NULL); ++ g_mutex_lock (omapfbsink->x_lock); ++ ++ /* If we did not create that window we just free the GC and let it live */ ++ if (xwindow->internal) ++ XDestroyWindow (omapfbsink->xcontext->disp, xwindow->win); ++ else ++ XSelectInput (omapfbsink->xcontext->disp, xwindow->win, 0); ++ ++ XFreeGC (omapfbsink->xcontext->disp, xwindow->gc); ++ XSync (omapfbsink->xcontext->disp, FALSE); ++ g_mutex_unlock (omapfbsink->x_lock); ++ g_free (xwindow); ++} ++ ++/* This function handles XEvents that might be in the queue. It generates ++ GstEvent that will be sent upstream in the pipeline to handle interactivity ++ and navigation.*/ ++static void ++gst_omapfbsink_handle_xevents (GstOmapFbSink * omapfbsink) ++{ ++ XEvent e; ++ g_mutex_lock (omapfbsink->flow_lock); ++ g_mutex_lock (omapfbsink->x_lock); ++ ++ while (XCheckWindowEvent (omapfbsink->xcontext->disp, ++ omapfbsink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { ++ switch (e.type) { ++ case Expose: ++ case ConfigureNotify: ++ gst_omapfbsink_update_plane (omapfbsink); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ /* Handle Display events */ ++ while (XPending (omapfbsink->xcontext->disp)) { ++ XNextEvent (omapfbsink->xcontext->disp, &e); ++ ++ switch (e.type) { ++ case ClientMessage:{ ++ Atom wm_delete; ++ ++ wm_delete = XInternAtom (omapfbsink->xcontext->disp, ++ "WM_DELETE_WINDOW", False); ++ if (wm_delete == (Atom) e.xclient.data.l[0]) { ++ /* Handle window deletion by posting an error on the bus */ ++ GST_ELEMENT_ERROR (omapfbsink, RESOURCE, NOT_FOUND, ++ ("Output window was closed"), (NULL)); ++ ++ g_mutex_unlock (omapfbsink->x_lock); ++ gst_omapfbsink_xwindow_destroy (omapfbsink, omapfbsink->xwindow); ++ omapfbsink->xwindow = NULL; ++ g_mutex_lock (omapfbsink->x_lock); ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ } ++ ++ g_mutex_unlock (omapfbsink->x_lock); ++ g_mutex_unlock (omapfbsink->flow_lock); ++} ++ ++static gpointer ++gst_omapfbsink_event_thread (GstOmapFbSink * omapfbsink) ++{ ++ GST_OBJECT_LOCK (omapfbsink); ++ while (omapfbsink->running) { ++ GST_OBJECT_UNLOCK (omapfbsink); ++ ++ if (omapfbsink->xwindow) ++ gst_omapfbsink_handle_xevents (omapfbsink); ++ g_usleep (100000); ++ ++ GST_OBJECT_LOCK (omapfbsink); ++ } ++ GST_OBJECT_UNLOCK (omapfbsink); ++ ++ return NULL; ++} ++ ++/* This function gets the X Display and global info about it. Everything is ++ stored in our object and will be cleaned when the object is disposed. */ ++static GstXContext * ++gst_omapfbsink_xcontext_get (GstOmapFbSink * omapfbsink) ++{ ++ GstXContext *xcontext = g_new0 (GstXContext, 1); ++ g_mutex_lock (omapfbsink->x_lock); ++ ++ xcontext->disp = XOpenDisplay (omapfbsink->display_name); ++ ++ if (!xcontext->disp) { ++ g_mutex_unlock (omapfbsink->x_lock); ++ g_free (xcontext); ++ GST_ELEMENT_WARNING (omapfbsink, RESOURCE, WRITE, ++ ("Could not initialise X output"), ++ ("Could not open display")); ++ return NULL; ++ } ++ ++ xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); ++ xcontext->screen_num = DefaultScreen (xcontext->disp); ++ xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); ++ xcontext->root = DefaultRootWindow (xcontext->disp); ++ ++ xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); ++ xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); ++ ++ g_mutex_unlock (omapfbsink->x_lock); ++ ++ /* Setup our event listening thread */ ++ GST_OBJECT_LOCK (omapfbsink); ++ omapfbsink->running = TRUE; ++ omapfbsink->event_thread = g_thread_create ( ++ (GThreadFunc) gst_omapfbsink_event_thread, omapfbsink, TRUE, NULL); ++ GST_OBJECT_UNLOCK (omapfbsink); ++ ++ return xcontext; ++} ++ ++static void ++gst_omapfbsink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) ++{ ++ GstOmapFbSink *omapfbsink = GST_OMAPFB_SINK (overlay); ++ GstXWindow *xwindow = NULL; ++ XWindowAttributes attr; ++ ++ /* If we already use that window, return */ ++ if (omapfbsink->xwindow && (xwindow_id == omapfbsink->xwindow->win)) ++ return; ++ ++ /* If the element has not initialized the X11 context try to do so */ ++ if (!omapfbsink->xcontext && ++ !(omapfbsink->xcontext = gst_omapfbsink_xcontext_get (omapfbsink))) { ++ g_mutex_unlock (omapfbsink->flow_lock); ++ return; ++ } ++ ++ /* If a window is there already we destroy it */ ++ if (omapfbsink->xwindow) { ++ gst_omapfbsink_xwindow_destroy (omapfbsink, omapfbsink->xwindow); ++ omapfbsink->xwindow = NULL; ++ } ++ ++ /* If the xid is 0 we go back to an internal window */ ++ if (xwindow_id == 0) { ++ /* If no width/height caps nego did not happen window will be created ++ during caps nego then */ ++ if (GST_VIDEO_SINK_WIDTH (omapfbsink) && GST_VIDEO_SINK_HEIGHT (omapfbsink)) { ++ xwindow = gst_omapfbsink_xwindow_new (omapfbsink, ++ GST_VIDEO_SINK_WIDTH (omapfbsink), ++ GST_VIDEO_SINK_HEIGHT (omapfbsink)); ++ } ++ } else { ++ xwindow = g_new0 (GstXWindow, 1); ++ xwindow->wx = xwindow->wy = -1; ++ xwindow->win = xwindow_id; ++ ++ /* We get window geometry, set the event we want to receive, ++ and create a GC */ ++ g_mutex_lock (omapfbsink->x_lock); ++ XGetWindowAttributes (omapfbsink->xcontext->disp, xwindow->win, &attr); ++ xwindow->width = attr.width; ++ xwindow->height = attr.height; ++ xwindow->internal = FALSE; ++ if (omapfbsink->handle_events) { ++ XSelectInput (omapfbsink->xcontext->disp, xwindow->win, ExposureMask | ++ StructureNotifyMask | PointerMotionMask | KeyPressMask | ++ KeyReleaseMask); ++ } ++ ++ xwindow->gc = XCreateGC (omapfbsink->xcontext->disp, xwindow->win, 0, NULL); ++ g_mutex_unlock (omapfbsink->x_lock); ++ } ++ ++ if (xwindow) { ++ omapfbsink->xwindow = xwindow; ++ ++ g_mutex_lock (omapfbsink->x_lock); ++ gst_omapfbsink_update_plane(omapfbsink); ++ g_mutex_unlock (omapfbsink->x_lock); ++ } ++} ++ ++static void ++gst_omapfbsink_xwindow_clear (GstOmapFbSink * omapfbsink, ++ GstXWindow * xwindow) ++{ ++ g_return_if_fail (xwindow != NULL); ++ g_mutex_lock (omapfbsink->x_lock); ++ ++ XSetForeground (omapfbsink->xcontext->disp, xwindow->gc, ++ XBlackPixel (omapfbsink->xcontext->disp, ++ omapfbsink->xcontext->screen_num)); ++ ++ XFillRectangle (omapfbsink->xcontext->disp, xwindow->win, xwindow->gc, ++ 0, 0, xwindow->width, xwindow->height); ++ ++ XSync (omapfbsink->xcontext->disp, FALSE); ++ g_mutex_unlock (omapfbsink->x_lock); ++} ++ ++static void ++gst_omapfbsink_set_event_handling (GstXOverlay * overlay, ++ gboolean handle_events) ++{ ++ GstOmapFbSink *omapfbsink = GST_OMAPFB_SINK (overlay); ++ omapfbsink->handle_events = handle_events; ++ ++ g_mutex_lock (omapfbsink->flow_lock); ++ ++ if (G_UNLIKELY (!omapfbsink->xwindow)) { ++ g_mutex_unlock (omapfbsink->flow_lock); ++ return; ++ } ++ ++ g_mutex_lock (omapfbsink->x_lock); ++ ++ if (handle_events) { ++ if (omapfbsink->xwindow->internal) { ++ XSelectInput (omapfbsink->xcontext->disp, omapfbsink->xwindow->win, ++ ExposureMask | StructureNotifyMask | PointerMotionMask | ++ KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); ++ } else { ++ XSelectInput (omapfbsink->xcontext->disp, omapfbsink->xwindow->win, ++ ExposureMask | StructureNotifyMask | PointerMotionMask | ++ KeyPressMask | KeyReleaseMask); ++ } ++ } else { ++ XSelectInput (omapfbsink->xcontext->disp, omapfbsink->xwindow->win, 0); ++ } ++ ++ g_mutex_unlock (omapfbsink->x_lock); ++ g_mutex_unlock (omapfbsink->flow_lock); ++} ++ ++static void ++gst_omapfbsink_xoverlay_init (GstXOverlayClass * iface) ++{ ++ iface->set_xwindow_id = gst_omapfbsink_set_xwindow_id; ++ iface->expose = gst_omapfbsink_expose; ++ iface->handle_events = gst_omapfbsink_set_event_handling; ++} ++ ++static GstCaps * ++generate_sink_template (void) ++{ ++ GstCaps *caps; ++ GstStructure *struc; ++ ++ caps = gst_caps_new_empty (); ++ ++ struc = gst_structure_new ("video/x-raw-yuv", ++ "width", GST_TYPE_INT_RANGE, 16, 4096, ++ "height", GST_TYPE_INT_RANGE, 16, 4096, ++ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30, 1, ++ NULL); ++ ++ { ++ GValue list; ++ GValue val; ++ ++ list.g_type = val.g_type = 0; ++ ++ g_value_init (&list, GST_TYPE_LIST); ++ g_value_init (&val, GST_TYPE_FOURCC); ++ ++#if 0 ++ gst_value_set_fourcc (&val, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2')); ++ gst_value_list_append_value (&list, &val); ++#else ++ gst_value_set_fourcc (&val, GST_MAKE_FOURCC ('I', '4', '2', '0')); ++ gst_value_list_append_value (&list, &val); ++ ++ gst_value_set_fourcc (&val, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y')); ++ gst_value_list_append_value (&list, &val); ++#endif ++ ++ gst_structure_set_value (struc, "format", &list); ++ ++ g_value_unset (&val); ++ g_value_unset (&list); ++ } ++ ++ gst_caps_append_structure (caps, struc); ++ ++ return caps; ++} ++ ++static GstFlowReturn ++buffer_alloc (GstBaseSink *bsink, ++ guint64 offset, ++ guint size, ++ GstCaps *caps, ++ GstBuffer **buf) ++{ ++ GstOmapFbSink *self; ++ GstBuffer *buffer = NULL; ++ GstFlowReturn ret = GST_FLOW_OK; ++ self = GST_OMAPFB_SINK (bsink); ++ ++ if(self->row_skip) { ++ buffer = gst_buffer_new (); ++ GST_BUFFER_DATA (buffer) = self->buffer = self->framebuffer; ++ GST_BUFFER_SIZE (buffer) = self->buffer_size = size; ++ gst_buffer_set_caps (buffer, caps); ++ } else { ++ if(self->buffer && size == self->buffer_size) { ++ buffer = gst_buffer_new (); ++ GST_BUFFER_DATA (buffer) = self->buffer; ++ GST_BUFFER_SIZE (buffer) = size; ++ gst_buffer_set_caps (buffer, caps); ++ } else { ++ if(self->buffer) ++ free(self->buffer); ++ if(posix_memalign(&self->buffer, 16, (size_t) size) == 0) { ++ buffer = gst_buffer_new (); ++ GST_BUFFER_DATA (buffer) = self->buffer; ++ GST_BUFFER_SIZE (buffer) = self->buffer_size = size; ++ gst_buffer_set_caps (buffer, caps); ++ } else { ++ GST_ELEMENT_ERROR (self, RESOURCE, WRITE, ("Could not allocate aligned buf!"), ++ ("Could not alloc aligned buf!")); ++ } ++ } ++ } ++ ++ *buf = buffer; ++ return ret; ++} ++ ++static void ++x_memcpy (GstOmapFbSink *omapfbsink, __uint8_t *outBuf, __uint8_t *inBuf) ++{ ++ BufferGfx_Attrs gfxAttrs = BufferGfx_Attrs_DEFAULT; ++ Buffer_Handle hInBuf = NULL, hOutBuf = NULL; ++ Framecopy_Attrs fcAttrs = Framecopy_Attrs_DEFAULT; ++ int size; ++ ++ if (omapfbsink->hFc == NULL) { ++ fcAttrs.accel = TRUE; ++ omapfbsink->hFc = Framecopy_create(&fcAttrs); ++ if (omapfbsink->hFc == NULL) { ++ GST_ELEMENT_ERROR(omapfbsink, RESOURCE, WRITE, ("failed to create dmai framecopy handle"), ("failed to create dmai framecopy handle")); ++ goto cleanup; ++ } ++ } ++ ++ gfxAttrs.bAttrs.reference = TRUE; ++ gfxAttrs.dim.width = GST_VIDEO_SINK_WIDTH (omapfbsink); ++ gfxAttrs.dim.height = GST_VIDEO_SINK_HEIGHT (omapfbsink); ++ gfxAttrs.colorSpace = ColorSpace_UYVY; ++ gfxAttrs.dim.lineLength = omapfbsink->fixinfo.line_length; ++ size = gfxAttrs.dim.height * gfxAttrs.dim.width * 2; ++ ++ hInBuf = Buffer_create(size, BufferGfx_getBufferAttrs(&gfxAttrs)); ++ if (hInBuf == NULL) { ++ GST_ELEMENT_ERROR(omapfbsink, RESOURCE, WRITE, ("Could not allocate refer dmai buffer"), ("Could not allocate refer dmai buffer")); ++ goto cleanup; ++ } ++ Buffer_setUserPtr(hInBuf, (Int8*) inBuf); ++ Buffer_setNumBytesUsed(hInBuf,Buffer_getSize(hInBuf)); ++ ++ hOutBuf = Buffer_create(size, BufferGfx_getBufferAttrs(&gfxAttrs)); ++ if (hOutBuf == NULL) { ++ GST_ELEMENT_ERROR(omapfbsink, RESOURCE, WRITE, ("Could not allocate refer dmai buffer"), ("Could not allocate refer dmai buffer")); ++ goto cleanup; ++ } ++ Buffer_setUserPtr(hOutBuf, (Int8*) outBuf); ++ Buffer_setNumBytesUsed(hOutBuf,Buffer_getSize(hOutBuf)); ++ ++ ++ if (Framecopy_config(omapfbsink->hFc, hInBuf, hOutBuf) < 0) { ++ GST_ELEMENT_ERROR(omapfbsink, RESOURCE, WRITE, ("failed to configure dmai framecopy handle"), ("failed to configure dmai framecopy handle")); ++ goto cleanup; ++ } ++ ++ if (Framecopy_execute(omapfbsink->hFc, hInBuf, hOutBuf) < 0) { ++ GST_ELEMENT_ERROR(omapfbsink, RESOURCE, WRITE, ("failed to execute dmai framecopy handle"), ("failed to configure dmai framecopy handle")); ++ goto cleanup; ++ } ++ cleanup: ++ ++ if (hInBuf) ++ Buffer_delete(hInBuf); ++ if (hOutBuf) ++ Buffer_delete(hOutBuf); ++} ++ ++static GstFlowReturn ++render (GstBaseSink * bsink, GstBuffer * buf) ++{ ++ int i, w, h; ++ GstOmapFbSink *omapfbsink = GST_OMAPFB_SINK(bsink); ++ __uint8_t *fb = omapfbsink->framebuffer, *data = GST_BUFFER_DATA(buf); ++ gboolean useXcopy = FALSE; ++ ++ if (GST_IS_TIDMAIBUFFERTRANSPORT(buf)) { ++ GST_LOG("found dmai transport buffer, enabling hw framecopy.\n"); ++ useXcopy = TRUE; ++ } ++ ++ if(omapfbsink->plane_info.enabled == 2) ++ { ++ omapfbsink->plane_info.enabled = 1; ++ ++ g_mutex_lock (omapfbsink->x_lock); ++ gst_omapfbsink_update_plane(omapfbsink); ++ g_mutex_unlock (omapfbsink->x_lock); ++ } ++ ++ /* If a buffer which wasn't supplied by us is given to us to render with, ++ we need to copy to our buffer first so that memory alignment constraints ++ are met. */ ++ if((data != omapfbsink->buffer && GST_BUFFER_SIZE(buf) <= omapfbsink->buffer_size) && !useXcopy) ++ { ++ memcpy(omapfbsink->buffer, data, GST_BUFFER_SIZE(buf)); ++ data = omapfbsink->buffer; ++ } ++ ++ /* buffer_alloc gave a direct buffer, so we have nothing to ++ do here... */ ++ if(omapfbsink->row_skip) ++ return GST_FLOW_OK; ++ ++ switch(omapfbsink->image_format) { ++ case GST_MAKE_FOURCC('I', '4', '2', '0'): ++ /* Convert to YUV422 and send to FB */ ++ ++ h = GST_VIDEO_SINK_HEIGHT (omapfbsink); ++ w = GST_VIDEO_SINK_WIDTH (omapfbsink); ++ ++ __uint8_t *y, *u, *v; ++ y = data; ++ u = y + w * h; ++ v = u + w / 2 * h / 2; ++ yuv420_to_yuv422(fb, y, u, v, w & ~15, h, w, w / 2, omapfbsink->fixinfo.line_length); ++ break; ++ ++ case GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'): ++ /* Send to FB, taking into account line_length */ ++ if (useXcopy) { ++ x_memcpy(omapfbsink, fb, data); ++ } ++ else { ++ ++ w = 2 * GST_VIDEO_SINK_WIDTH (omapfbsink); ++ for(i = 0; i < GST_VIDEO_SINK_HEIGHT (omapfbsink); i++) ++ { ++ memcpy(fb, data, w); ++ ++ fb += omapfbsink->fixinfo.line_length; ++ data += w; ++ } ++ } ++ break; ++ } ++ ++ return GST_FLOW_OK; ++} ++ ++static gboolean ++setcaps (GstBaseSink *bsink, ++ GstCaps *vscapslist) ++{ ++ GstOmapFbSink *self; ++ GstStructure *structure; ++ ++ gint width, height; ++ struct omapfb_color_key color_key; ++ ++ self = GST_OMAPFB_SINK (bsink); ++ ++ structure = gst_caps_get_structure (vscapslist, 0); ++ ++ gst_structure_get_int (structure, "width", &width); ++ gst_structure_get_int (structure, "height", &height); ++ ++ self->overlay_info.xres = MIN (self->varinfo.xres, width) & ~15; ++ self->overlay_info.yres = MIN (self->varinfo.yres, height) & ~15; ++ self->overlay_info.xres_virtual = self->overlay_info.xres; ++ self->overlay_info.yres_virtual = self->overlay_info.yres; ++ ++ self->overlay_info.xoffset = 0; ++ self->overlay_info.yoffset = 0; ++ ++ gst_structure_get_fourcc (structure, "format", &self->image_format); ++ switch(self->image_format) { ++ case GST_MAKE_FOURCC('I', '4', '2', '0'): ++ self->row_skip = FALSE; /* Colorspace conversion required */ ++ self->overlay_info.nonstd = OMAPFB_COLOR_YUY422; ++ break; ++ case GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'): ++ /* Can data be pushed straight to the FB or do we need to interleave? */ ++ if (self->fixinfo.line_length != 2 * width) ++ self->row_skip = FALSE; ++ else ++ self->row_skip = TRUE; ++ self->overlay_info.nonstd = OMAPFB_COLOR_YUV422; ++ break; ++ } ++ ++ if (ioctl (self->overlay_fd, FBIOPUT_VSCREENINFO, &self->overlay_info)) ++ return FALSE; ++ ++ GST_VIDEO_SINK_WIDTH (self) = width; ++ GST_VIDEO_SINK_HEIGHT (self) = height; ++ if (!self->xwindow) { ++ self->xwindow = gst_omapfbsink_xwindow_new (self, ++ GST_VIDEO_SINK_WIDTH (self), GST_VIDEO_SINK_HEIGHT (self)); ++ } ++ ++ color_key.channel_out = OMAPFB_CHANNEL_OUT_LCD; ++ color_key.background = 0x0; ++ color_key.trans_key = self->colorKey; ++ if (self->xwindow) ++ color_key.key_type = OMAPFB_COLOR_KEY_GFX_DST; ++ else ++ color_key.key_type = OMAPFB_COLOR_KEY_DISABLED; ++ ++ if (ioctl (self->overlay_fd, OMAPFB_SET_COLOR_KEY, &color_key)) ++ return FALSE; ++ ++ self->plane_info.pos_x = 0; ++ self->plane_info.pos_y = 0; ++ self->plane_info.out_width = self->overlay_info.xres; ++ self->plane_info.out_height = self->overlay_info.yres; ++ self->plane_info.enabled = 2; ++ ++ if (ioctl (self->overlay_fd, FBIOGET_FSCREENINFO, &self->fixinfo)) ++ return FALSE; ++ ++ self->enabled = TRUE; ++ return TRUE; ++} ++ ++static gboolean ++start (GstBaseSink *bsink) ++{ ++ GstOmapFbSink *self; ++ int fd; ++ ++ self = GST_OMAPFB_SINK (bsink); ++ ++ fd = open ("/dev/fb0", O_RDWR); ++ ++ if (fd == -1) ++ return FALSE; ++ ++ if (ioctl (fd, FBIOGET_VSCREENINFO, &self->varinfo)) ++ { ++ close (fd); ++ return FALSE; ++ } ++ ++ if (close (fd)) ++ return FALSE; ++ ++ self->overlay_fd = open ("/dev/fb1", O_RDWR); ++ ++ if (self->overlay_fd == -1) ++ return FALSE; ++ ++ if (ioctl (self->overlay_fd, FBIOGET_VSCREENINFO, &self->overlay_info)) ++ return FALSE; ++ ++ if (ioctl (self->overlay_fd, OMAPFB_QUERY_PLANE, &self->plane_info)) ++ return FALSE; ++ ++ if (ioctl (self->overlay_fd, OMAPFB_QUERY_MEM, &self->mem_info)) ++ return FALSE; ++ ++ self->framebuffer = mmap (NULL, self->mem_info.size, PROT_WRITE, MAP_SHARED, self->overlay_fd, 0); ++ if (self->framebuffer == MAP_FAILED) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++static gboolean ++stop (GstBaseSink *bsink) ++{ ++ GstOmapFbSink *self; ++ ++ self = GST_OMAPFB_SINK (bsink); ++ ++ if (self->enabled) ++ { ++ self->plane_info.enabled = 0; ++ ++ if (ioctl (self->overlay_fd, OMAPFB_SETUP_PLANE, &self->plane_info)) ++ return FALSE; ++ } ++ ++ if (munmap (self->framebuffer, self->mem_info.size)) ++ return FALSE; ++ ++ if (close (self->overlay_fd)) ++ return FALSE; ++ ++ if (self->hFc) ++ Framecopy_delete(self->hFc); ++ ++ return TRUE; ++} ++ ++/* This function cleans the X context. Closing the Display and unrefing the ++ caps for supported formats. */ ++static void ++gst_omapfbsink_xcontext_clear (GstOmapFbSink * omapfbsink) ++{ ++ GstXContext *xcontext; ++ GST_OBJECT_LOCK (omapfbsink); ++ if (omapfbsink->xcontext == NULL) { ++ GST_OBJECT_UNLOCK (omapfbsink); ++ return; ++ } ++ ++ xcontext = omapfbsink->xcontext; ++ omapfbsink->xcontext = NULL; ++ ++ GST_OBJECT_UNLOCK (omapfbsink); ++ g_mutex_lock (omapfbsink->x_lock); ++ ++ XCloseDisplay (xcontext->disp); ++ g_mutex_unlock (omapfbsink->x_lock); ++ g_free (xcontext); ++} ++ ++static void ++gst_omapfbsink_reset (GstOmapFbSink *omapfbsink) ++{ ++ GThread *thread; ++ ++ GST_OBJECT_LOCK (omapfbsink); ++ omapfbsink->running = FALSE; ++ /* grab thread and mark it as NULL */ ++ thread = omapfbsink->event_thread; ++ omapfbsink->event_thread = NULL; ++ GST_OBJECT_UNLOCK (omapfbsink); ++ ++ /* Wait for our event thread to finish before we clean up our stuff. */ ++ if (thread) ++ g_thread_join (thread); ++ ++ g_mutex_lock (omapfbsink->flow_lock); ++ if (omapfbsink->xwindow) { ++ gst_omapfbsink_xwindow_clear (omapfbsink, omapfbsink->xwindow); ++ gst_omapfbsink_xwindow_destroy (omapfbsink, omapfbsink->xwindow); ++ omapfbsink->xwindow = NULL; ++ } ++ g_mutex_unlock (omapfbsink->flow_lock); ++ gst_omapfbsink_xcontext_clear (omapfbsink); ++} ++ ++static GstStateChangeReturn ++gst_omapfbsink_change_state (GstElement * element, GstStateChange transition) ++{ ++ GstOmapFbSink *omapfbsink; ++ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; ++ GstXContext *xcontext = NULL; ++ ++ omapfbsink = GST_OMAPFB_SINK (element); ++ ++ switch (transition) { ++ case GST_STATE_CHANGE_NULL_TO_READY: ++ ++ /* Initializing the XContext */ ++ if (omapfbsink->xcontext == NULL) { ++ xcontext = gst_omapfbsink_xcontext_get (omapfbsink); ++ ++ GST_OBJECT_LOCK (omapfbsink); ++ omapfbsink->xcontext = xcontext; ++ GST_OBJECT_UNLOCK (omapfbsink); ++ } ++ break; ++ case GST_STATE_CHANGE_READY_TO_PAUSED: ++ g_mutex_lock (omapfbsink->flow_lock); ++ if (omapfbsink->xwindow) ++ gst_omapfbsink_xwindow_clear (omapfbsink, omapfbsink->xwindow); ++ g_mutex_unlock (omapfbsink->flow_lock); ++ break; ++ case GST_STATE_CHANGE_PAUSED_TO_PLAYING: ++ break; ++ default: ++ break; ++ } ++ ++ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); ++ ++ switch (transition) { ++ case GST_STATE_CHANGE_PLAYING_TO_PAUSED: ++ break; ++ case GST_STATE_CHANGE_PAUSED_TO_READY: ++ GST_VIDEO_SINK_WIDTH (omapfbsink) = 0; ++ GST_VIDEO_SINK_HEIGHT (omapfbsink) = 0; ++ break; ++ case GST_STATE_CHANGE_READY_TO_NULL: ++ gst_omapfbsink_reset (omapfbsink); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static void ++type_class_init (gpointer g_class, ++ gpointer class_data) ++{ ++ GstElementClass *element_class; ++ GstBaseSinkClass *base_sink_class; ++ ++ element_class = (GstElementClass *) g_class; ++ base_sink_class = (GstBaseSinkClass *) g_class; ++ ++ parent_class = g_type_class_peek_parent (g_class); ++ ++ base_sink_class->set_caps = GST_DEBUG_FUNCPTR (setcaps); ++ base_sink_class->buffer_alloc = GST_DEBUG_FUNCPTR (buffer_alloc); ++ base_sink_class->render = GST_DEBUG_FUNCPTR (render); ++ base_sink_class->start = GST_DEBUG_FUNCPTR (start); ++ base_sink_class->stop = GST_DEBUG_FUNCPTR (stop); ++ ++ element_class->change_state = gst_omapfbsink_change_state; ++} ++ ++static void ++type_base_init (gpointer g_class) ++{ ++ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); ++ ++ { ++ GstElementDetails details; ++ ++ details.longname = "Linux OMAP framebuffer sink"; ++ details.klass = "Sink/Video"; ++ details.description = "Renders video with omapfb"; ++ details.author = "Felipe Contreras"; ++ ++ gst_element_class_set_details (element_class, &details); ++ } ++ ++ { ++ GstPadTemplate *template; ++ ++ template = gst_pad_template_new ("sink", GST_PAD_SINK, ++ GST_PAD_ALWAYS, ++ generate_sink_template ()); ++ ++ gst_element_class_add_pad_template (element_class, template); ++ } ++} ++ ++static gboolean ++gst_omapfbsink_interface_supported (GstImplementsInterface * iface, GType type) ++{ ++ g_assert (type == GST_TYPE_X_OVERLAY); ++ return TRUE; ++} ++ ++static void ++gst_omapfbsink_interface_init (GstImplementsInterfaceClass * klass) ++{ ++ klass->supported = gst_omapfbsink_interface_supported; ++} ++ ++static void ++gst_omapfbsink_init (GstOmapFbSink * omapfbsink) ++{ ++ omapfbsink->display_name = NULL; ++ omapfbsink->xcontext = NULL; ++ omapfbsink->xwindow = NULL; ++ ++ omapfbsink->event_thread = NULL; ++ omapfbsink->running = FALSE; ++ ++ omapfbsink->x_lock = g_mutex_new (); ++ omapfbsink->flow_lock = g_mutex_new (); ++ ++ omapfbsink->handle_events = TRUE; ++ omapfbsink->colorKey |
