diff -uNr ticodecplugin/configure.ac ticodecplugin.new/configure.ac --- ticodecplugin/configure.ac 2010-08-24 15:08:58.609410984 -0500 +++ ticodecplugin.new/configure.ac 2010-09-03 13:54:11.909410298 -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/gstticodecplugin.c ticodecplugin.new/src/gstticodecplugin.c --- ticodecplugin/src/gstticodecplugin.c 2010-08-24 15:08:58.609410984 -0500 +++ ticodecplugin.new/src/gstticodecplugin.c 2010-09-03 13:54:11.929409696 -0500 @@ -42,6 +42,7 @@ #include "gsttiaudenc1.h" #include "gsttividresize.h" #include "gsttidmaiperf.h" +#include "omapfb.h" #ifdef HAVE_C6ACCEL #include "gsttic6xcolorspace.h" @@ -134,6 +135,13 @@ return FALSE; #endif + env_value = getenv("GST_omapdmaifbsink_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/Makefile.am ticodecplugin.new/src/Makefile.am --- ticodecplugin/src/Makefile.am 2010-08-24 22:01:30.989165985 -0500 +++ ticodecplugin.new/src/Makefile.am 2010-09-03 13:53:41.037663172 -0500 @@ -12,16 +12,16 @@ # sources used to compile this plug-in -libgstticodecplugin_la_SOURCES = gstticodecplugin.c gsttiauddec1.c gsttividdec2.c gsttiimgenc1.c gsttiimgdec1.c gsttidmaibuffertransport.c gsttidmaibuftab.c gstticircbuffer.c gsttidmaivideosink.c gstticodecs.c gstticodecs_platform.c gsttiquicktime_aac.c gsttiquicktime_h264.c gsttividenc1.c gsttiaudenc1.c gstticommonutils.c gsttividresize.c gsttidmaiperf.c gsttiquicktime_mpeg4.c $(C6ACCEL_SRC) +libgstticodecplugin_la_SOURCES = gstticodecplugin.c gsttiauddec1.c gsttividdec2.c gsttiimgenc1.c gsttiimgdec1.c gsttidmaibuffertransport.c gsttidmaibuftab.c gstticircbuffer.c gsttidmaivideosink.c gstticodecs.c gstticodecs_platform.c gsttiquicktime_aac.c gsttiquicktime_h264.c gsttividenc1.c gsttiaudenc1.c gstticommonutils.c gsttividresize.c gsttidmaiperf.c gsttiquicktime_mpeg4.c $(C6ACCEL_SRC) 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 -Wl,$(C6ACCEL_LIB) # headers we need but don't want installed -noinst_HEADERS = gsttiauddec1.h gsttividdec2.h gsttiimgenc1.h gsttiimgdec1.h gsttidmaibuffertransport.h gsttidmaibuftab.h gstticircbuffer.h gsttidmaivideosink.h gsttithreadprops.h gstticodecs.h gsttiquicktime_aac.h gsttiquicktime_h264.h gsttividenc1.h gsttiaudenc1.h gstticommonutils.h gsttividresize.h gsttiquicktime_mpeg4.h $(C6ACCEL_HEAD) +noinst_HEADERS = gsttiauddec1.h gsttividdec2.h gsttiimgenc1.h gsttiimgdec1.h gsttidmaibuffertransport.h gsttidmaibuftab.h gstticircbuffer.h gsttidmaivideosink.h gsttithreadprops.h gstticodecs.h gsttiquicktime_aac.h gsttiquicktime_h264.h gsttividenc1.h gsttiaudenc1.h gstticommonutils.h gsttividresize.h gsttiquicktime_mpeg4.h $(C6ACCEL_HEAD) omapfb.h # XDC Configuration CONFIGURO = $(XDC_INSTALL_DIR)/xs xdc.tools.configuro 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 2010-09-03 13:54:11.929409696 -0500 @@ -0,0 +1,1005 @@ +/* + * Copyright (C) 2008 Felipe Contreras + * Copyright (C) 2009 Tim Yamin + * Copyright (C) 2009 Brijesh Singh + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "omapfb.h" +#include + +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 = 0xff0; + + omapfbsink->plane_info.enabled = 0; + omapfbsink->row_skip = FALSE; + + omapfbsink->buffer = NULL; + omapfbsink->buffer_size = 0; + omapfbsink->hFc = NULL; +} + +GType +gst_omapfbsink_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + GTypeInfo *type_info; + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) gst_omapfbsink_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo overlay_info = { + (GInterfaceInitFunc) gst_omapfbsink_xoverlay_init, + NULL, + NULL, + }; + type_info = g_new0 (GTypeInfo, 1); + type_info->class_size = sizeof (GstOmapFbSinkClass); + type_info->base_init = type_base_init; + type_info->class_init = type_class_init; + type_info->instance_size = sizeof (GstOmapFbSink); + type_info->instance_init = (GInstanceInitFunc) gst_omapfbsink_init; + + type = g_type_register_static (GST_TYPE_BASE_SINK, "GstOmapFbSink", type_info, 0); + g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info); + g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info); + + g_free (type_info); + } + + return type; +} diff -uNr ticodecplugin/src/omapfb.h ticodecplugin.new/src/omapfb.h --- ticodecplugin/src/omapfb.h 1969-12-31 18:00:00.000000000 -0600 +++ ticodecplugin.new/src/omapfb.h 2010-09-03 13:54:11.929409696 -0500 @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2008 Felipe Contreras + * + * 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 + */ + +#ifndef GST_OMAPFB_H +#define GST_OMAPFB_H + +#include +#include + +#include "gsttidmaibuffertransport.h" +#include +#include +#include + +#include +#include + +#include +#include + + +G_BEGIN_DECLS + +#define GST_OMAPFB_SINK_TYPE (gst_omapfbsink_get_type ()) +#define GST_OMAPFB_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_OMAPFB_SINK_TYPE, GstOmapFbSink)) + +typedef struct GstXContext GstXContext; +typedef struct GstXWindow GstXWindow; +typedef struct GstOmapFbSink GstOmapFbSink; +typedef struct GstOmapFbSinkClass GstOmapFbSinkClass; + +/** + * GstXWindow: + * @win: the Window ID of this X11 window + * @width: the width in pixels of Window @win + * @height: the height in pixels of Window @win + * @internal: used to remember if Window @win was created internally or passed + * through the #GstXOverlay interface + * @gc: the Graphical Context of Window @win + * + * Structure used to store informations about a Window. + */ +struct GstXWindow { + Window win; + gint width, height; + gboolean internal; + GC gc; + + gint wx, wy; +}; + +/** + * GstXContext: + * @disp: the X11 Display of this context + * @screen: the default Screen of Display @disp + * @screen_num: the Screen number of @screen + * @visual: the default Visual of Screen @screen + * @root: the root Window of Display @disp + * @white: the value of a white pixel on Screen @screen + * @black: the value of a black pixel on Screen @screen + * @depth: the color depth of Display @disp + * @bpp: the number of bits per pixel on Display @disp + * @endianness: the endianness of image bytes on Display @disp + * @width: the width in pixels of Display @disp + * @height: the height in pixels of Display @disp + * + * Structure used to store various informations collected/calculated for a + * Display. + */ +struct GstXContext { + Display *disp; + Screen *screen; + gint screen_num; + + Visual *visual; + Window root; + + gint depth; + gint bpp; + + gint width, height; +}; + +struct GstOmapFbSink +{ + GstVideoSink videosink; + + struct fb_fix_screeninfo fixinfo; + struct fb_var_screeninfo varinfo; + struct fb_var_screeninfo overlay_info; + struct omapfb_mem_info mem_info; + struct omapfb_plane_info plane_info; + + int overlay_fd; + unsigned char *framebuffer; + gboolean enabled; + + GMutex *x_lock; + GMutex *flow_lock; + + GstXContext *xcontext; + GstXWindow *xwindow; + + gulong colorKey; + char *display_name; + GThread *event_thread; + + void *buffer; + guint buffer_size; + guint image_format; + + gboolean row_skip; + gboolean handle_events; + gboolean running; + Framecopy_Handle hFc; +}; + +struct GstOmapFbSinkClass +{ + GstBaseSinkClass parent_class; +}; + +GType gst_omapfbsink_get_type (void); + +G_END_DECLS + +#endif /* GST_OMAPFB_H */ diff -uNr ticodecplugin/src/yuv.S ticodecplugin.new/src/yuv.S --- ticodecplugin/src/yuv.S 1969-12-31 18:00:00.000000000 -0600 +++ ticodecplugin.new/src/yuv.S 2010-09-03 13:54:11.929409696 -0500 @@ -0,0 +1,117 @@ +/* + Copyright (C) 2008 Mans Rullgard + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + + .fpu neon + .text + +@ 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) + +#define yuv r0 +#define y r1 +#define u r2 +#define v r3 +#define w r4 +#define h r5 +#define yw r6 +#define cw r7 +#define dw r8 + +#define tyuv r9 +#define ty r10 +#define tu r11 +#define tv r12 +#define i lr + + .global yuv420_to_yuv422 + .func yuv420_to_yuv422 +yuv420_to_yuv422: + push {r4-r11,lr} + add r4, sp, #36 + ldm r4, {r4-r8} +1: + mov tu, u + mov tv, v + vld1.64 {d2}, [u,:64], cw @ u0 + vld1.64 {d3}, [v,:64], cw @ v0 + mov tyuv, yuv + mov ty, y + vzip.8 d2, d3 @ u0v0 + mov i, #16 +2: + pld [y, #64] + vld1.64 {d0, d1}, [y,:128], yw @ y0 + pld [u, #64] + subs i, i, #4 + vld1.64 {d6}, [u,:64], cw @ u2 + pld [y, #64] + vld1.64 {d4, d5}, [y,:128], yw @ y1 + pld [v, #64] + vld1.64 {d7}, [v,:64], cw @ v2 + pld [y, #64] + vld1.64 {d16,d17}, [y,:128], yw @ y2 + vzip.8 d6, d7 @ u2v2 + pld [u, #64] + vld1.64 {d22}, [u,:64], cw @ u4 + pld [v, #64] + vld1.64 {d23}, [v,:64], cw @ v4 + pld [y, #64] + vld1.64 {d20,d21}, [y,:128], yw @ y3 + vmov q9, q3 @ u2v2 + vzip.8 d22, d23 @ u4v4 + vrhadd.u8 q3, q1, q3 @ u1v1 + vzip.8 q0, q1 @ y0u0y0v0 + vmov q12, q11 @ u4v4 + vzip.8 q2, q3 @ y1u1y1v1 + vrhadd.u8 q11, q9, q11 @ u3v3 + vst1.64 {d0-d3}, [yuv,:128], dw @ y0u0y0v0 + vzip.8 q8, q9 @ y2u2y2v2 + vst1.64 {d4-d7}, [yuv,:128], dw @ y1u1y1v1 + vzip.8 q10, q11 @ y3u3y3v3 + vst1.64 {d16-d19}, [yuv,:128], dw @ y2u2y2v2 + vmov q1, q12 + vst1.64 {d20-d23}, [yuv,:128], dw @ y3u3y3v3 + bgt 2b + subs w, w, #16 + add yuv, tyuv, #32 + add y, ty, #16 + add u, tu, #8 + add v, tv, #8 + bgt 1b + + ldr w, [sp, #36] + subs h, h, #16 + add yuv, yuv, dw, lsl #4 + sub yuv, yuv, w, lsl #1 + add y, y, yw, lsl #4 + sub y, y, w + add u, u, cw, lsl #3 + sub u, u, w, asr #1 + add v, v, cw, lsl #3 + sub v, v, w, asr #1 + bgt 1b + + pop {r4-r11,pc} + .endfunc +