summaryrefslogtreecommitdiff
path: root/gr-video-sdl/src
diff options
context:
space:
mode:
authorjcorgan2006-08-03 04:51:51 +0000
committerjcorgan2006-08-03 04:51:51 +0000
commit5d69a524f81f234b3fbc41d49ba18d6f6886baba (patch)
treeb71312bf7f1e8d10fef0f3ac6f28784065e73e72 /gr-video-sdl/src
downloadgnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.gz
gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.bz2
gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.zip
Houston, we have a trunk.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3122 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gr-video-sdl/src')
-rw-r--r--gr-video-sdl/src/Makefile.am86
-rwxr-xr-xgr-video-sdl/src/qa_video_sdl.py40
-rw-r--r--gr-video-sdl/src/run_tests.in47
-rw-r--r--gr-video-sdl/src/video_sdl.i67
-rw-r--r--gr-video-sdl/src/video_sdl_sink_s.cc301
-rw-r--r--gr-video-sdl/src/video_sdl_sink_s.h90
-rw-r--r--gr-video-sdl/src/video_sdl_sink_uc.cc291
-rw-r--r--gr-video-sdl/src/video_sdl_sink_uc.h90
8 files changed, 1012 insertions, 0 deletions
diff --git a/gr-video-sdl/src/Makefile.am b/gr-video-sdl/src/Makefile.am
new file mode 100644
index 000000000..0a28e0cef
--- /dev/null
+++ b/gr-video-sdl/src/Makefile.am
@@ -0,0 +1,86 @@
+#
+# Copyright 2004,2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+# Install this stuff so that it ends up as the gnuradio.video_sdl module
+# This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio
+
+ourpythondir = $(grpythondir)
+ourlibdir = $(grpyexecdir)
+
+EXTRA_DIST = run_tests.in
+TESTS = run_tests
+
+LOCAL_IFILES = \
+ video_sdl.i
+
+NON_LOCAL_IFILES = \
+ $(top_srcdir)/gnuradio-core/src/lib/swig/gnuradio.i
+
+ALL_IFILES = \
+ $(LOCAL_IFILES) \
+ $(NON_LOCAL_IFILES)
+
+BUILT_SOURCES = \
+ video_sdl.cc \
+ video_sdl.py
+
+ourpython_PYTHON = \
+ video_sdl.py
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(SDL_CFLAGS)
+
+SWIGCPPPYTHONARGS = -fvirtual -python -modern $(PYTHON_CPPFLAGS) $(STD_DEFINES_AND_INCLUDES)
+
+ourlib_LTLIBRARIES = _video_sdl.la
+
+_video_sdl_la_SOURCES = \
+ video_sdl.cc \
+ video_sdl_sink_uc.cc \
+ video_sdl_sink_s.cc
+
+
+grinclude_HEADERS = \
+ video_sdl_sink_uc.h \
+ video_sdl_sink_s.h
+
+swiginclude_HEADERS = \
+ $(LOCAL_IFILES)
+
+_video_sdl_la_LIBADD = \
+ $(PYTHON_LDFLAGS) \
+ $(GNURADIO_CORE_LIBS) \
+ $(SDL_LIBS) \
+ -lstdc++
+
+_video_sdl_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+video_sdl.cc video_sdl.py: video_sdl.i
+ $(SWIG) $(SWIGCPPPYTHONARGS) -module video_sdl -o video_sdl.cc $<
+
+
+noinst_PYTHON = qa_video_sdl.py
+
+MOSTLYCLEANFILES = \
+ $(BUILT_SOURCES) *~ *.pyc
+
diff --git a/gr-video-sdl/src/qa_video_sdl.py b/gr-video-sdl/src/qa_video_sdl.py
new file mode 100755
index 000000000..905b28715
--- /dev/null
+++ b/gr-video-sdl/src/qa_video_sdl.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# Copyright 2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import video_sdl
+
+class qa_video_sdl (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.fg = gr.flow_graph ()
+
+ def tearDown (self):
+ self.fg = None
+
+ def test_000_nop (self):
+ """Just see if we can import the module...
+ They may not have video drivers, etc. Don't try to run anything"""
+ pass
+
+if __name__ == '__main__':
+ gr_unittest.main ()
diff --git a/gr-video-sdl/src/run_tests.in b/gr-video-sdl/src/run_tests.in
new file mode 100644
index 000000000..2f84c3786
--- /dev/null
+++ b/gr-video-sdl/src/run_tests.in
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# All this strange PYTHONPATH manipulation is required to run our
+# tests using our just built shared library and swig-generated python
+# code prior to installation.
+
+# build tree == src tree unless you're doing a VPATH build.
+# If you don't know what a VPATH build is, you're not doing one. Relax...
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Where to look in the build tree for our shared library
+libbld=@abs_top_builddir@/gr-video-sdl/src
+# Where to look in the src tree for swig generated python code
+libsrc=@abs_top_srcdir@/gr-video-sdl/src
+# Where to look in the src tree for hand written python code
+py=@abs_top_srcdir@/gr-video-sdl/src
+
+# Where to look for GNU Radio python modules in current build tree
+# FIXME this is wrong on a distcheck. We really need to ask gnuradio-core
+# where it put its python files.
+grpythonbld=@abs_top_builddir@/gnuradio-core/src/python/:@abs_top_builddir@/gnuradio-core/src/lib/swig/:@abs_top_builddir@/gnuradio-core/src/lib/swig/.libs
+
+PYTHONPATH="$grpythonbld:$libbld:$libbld/.libs:$libsrc:$py:$PYTHONPATH"
+export PYTHONPATH
+
+#
+# This is the simple part...
+# Run everything that matches qa_*.py and return the final result.
+#
+
+ok=yes
+for file in @srcdir@/qa_*.py
+do
+ if ! $file
+ then
+ ok=no
+ fi
+done
+
+if [ $ok = yes ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/gr-video-sdl/src/video_sdl.i b/gr-video-sdl/src/video_sdl.i
new file mode 100644
index 000000000..e70d12356
--- /dev/null
+++ b/gr-video-sdl/src/video_sdl.i
@@ -0,0 +1,67 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+%feature("autodoc","1");
+
+%include "exception.i"
+%import "gnuradio.i" // the common stuff
+
+%{
+#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix
+#include "video_sdl_sink_uc.h"
+#include "video_sdl_sink_s.h"
+#include <stdexcept>
+%}
+
+// ----------------------------------------------------------------
+
+GR_SWIG_BLOCK_MAGIC(video_sdl,sink_uc)
+
+video_sdl_sink_uc_sptr
+video_sdl_make_sink_uc ( double framerate,int width=640, int height=480,unsigned int format=0,int dst_width=-1,int dst_height=-1
+ ) throw (std::runtime_error);
+
+
+class video_sdl_sink_uc : public gr_sync_block {
+ protected:
+ video_sdl_sink_uc (double framerate,int width, int height,gr_uint32 format,int dst_width,int dst_height);
+
+ public:
+ ~video_sdl_sink_uc ();
+};
+
+// ----------------------------------------------------------------
+
+GR_SWIG_BLOCK_MAGIC(video_sdl,sink_s)
+
+video_sdl_sink_s_sptr
+video_sdl_make_sink_s ( double framerate,int width=640, int height=480,unsigned int format=0,int dst_width=-1,int dst_height=-1
+ ) throw (std::runtime_error);
+
+
+class video_sdl_sink_s : public gr_sync_block {
+ protected:
+ video_sdl_sink_s (double framerate,int width, int height,gr_uint32 format,int dst_width,int dst_height);
+
+ public:
+ ~video_sdl_sink_s ();
+};
diff --git a/gr-video-sdl/src/video_sdl_sink_s.cc b/gr-video-sdl/src/video_sdl_sink_s.cc
new file mode 100644
index 000000000..50e730dbc
--- /dev/null
+++ b/gr-video-sdl/src/video_sdl_sink_s.cc
@@ -0,0 +1,301 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <SDL.h>
+
+#include <video_sdl_sink_s.h>
+#include <gr_io_signature.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <iostream>
+#include <stdexcept>
+
+
+
+video_sdl_sink_s::video_sdl_sink_s (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height)
+ : gr_sync_block ("video_sdl_sink_s",
+ gr_make_io_signature (1, 3, sizeof (short)),
+ gr_make_io_signature (0, 0, 0)),
+ d_chunk_size (width*height),
+ d_framerate(framerate),
+ d_wanted_frametime_ms(0),
+ d_width(width),
+ d_height (height),
+ d_dst_width(dst_width),
+ d_dst_height(dst_height),
+ d_format(format),
+ d_current_line(0),
+ d_screen(NULL),
+ d_image(NULL),
+ d_avg_delay(0.0),
+ d_wanted_ticks(0)
+{
+ if(framerate<=0.0)
+ d_wanted_frametime_ms=0;//Go as fast as possible
+ else
+ d_wanted_frametime_ms=(int)(1000.0/framerate);
+ if(dst_width<0) d_dst_width=d_width;
+ if(dst_height<0) d_dst_height=d_height;
+ if(0==format) d_format=IMGFMT_YV12;
+
+ atexit(SDL_Quit);//check if this is the way to do this
+ if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
+ std::cerr << "video_sdl_sink_s: Couldn't initialize SDL:" << SDL_GetError() << " \n SDL_Init(SDL_INIT_VIDEO) failed\n";
+ throw std::runtime_error ("video_sdl_sink_s");
+ };
+
+ /* accept any depth */
+ d_screen = SDL_SetVideoMode(dst_width, dst_height, 0, SDL_SWSURFACE|SDL_RESIZABLE|SDL_ANYFORMAT);//SDL_DOUBLEBUF |SDL_SWSURFACE| SDL_HWSURFACE||SDL_FULLSCREEN
+ if ( d_screen == NULL ) {
+ std::cerr << "Unable to set SDL video mode: " << SDL_GetError() <<"\n SDL_SetVideoMode() Failed \n";
+ exit(1);
+ }
+ if ( d_image ) {
+ SDL_FreeYUVOverlay(d_image);
+ }
+ /* Initialize and create the YUV Overlay used for video out */
+ if (!(d_image = SDL_CreateYUVOverlay (d_width, d_height, SDL_YV12_OVERLAY, d_screen))) {
+ std::cerr << "SDL: Couldn't create a YUV overlay: \n"<< SDL_GetError() <<"\n";
+ throw std::runtime_error ("video_sdl_sink_s");
+ }
+
+ printf("SDL screen_mode %d bits-per-pixel\n",
+ d_screen->format->BitsPerPixel);
+ printf("SDL overlay_mode %i \n",
+ d_image->format);
+ d_chunk_size = std::min(1,16384/width); //width*16;
+ d_chunk_size = d_chunk_size*width;
+ //d_chunk_size = (int) (width);
+ set_output_multiple (d_chunk_size);
+ /* Set the default playback area */
+ d_dst_rect.x = 0;
+ d_dst_rect.y = 0;
+ d_dst_rect.w = d_dst_width;
+ d_dst_rect.h = d_dst_height;
+ //clear the surface to grey
+ if ( SDL_LockYUVOverlay( d_image ) ) {
+ std::cerr << "SDL: Couldn't lock YUV overlay: \n"<< SDL_GetError() <<"\n";
+ throw std::runtime_error ("video_sdl_sink_s");
+ }
+ memset(d_image->pixels[0], 128, d_image->pitches[0]*d_height);
+ memset(d_image->pixels[1], 128, d_image->pitches[1]*d_height/2);
+ memset(d_image->pixels[2], 128, d_image->pitches[2]*d_height/2);
+ SDL_UnlockYUVOverlay( d_image );
+}
+
+video_sdl_sink_s::~video_sdl_sink_s ()
+{
+ SDL_Quit();
+}
+
+video_sdl_sink_s_sptr
+video_sdl_make_sink_s (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height)
+{
+ return video_sdl_sink_s_sptr (new video_sdl_sink_s (framerate, width, height,format,dst_width,dst_height));
+}
+
+void
+video_sdl_sink_s::copy_line_pixel_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,const short * src_pixels,int src_width)
+{
+ for(int i=0;i<src_width;i++)
+ {
+ dst_pixels_u[i]=(unsigned char)src_pixels[i*2];
+ dst_pixels_v[i]=(unsigned char)src_pixels[i*2+1];
+ }
+ return;
+}
+
+void
+video_sdl_sink_s::copy_line_line_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,const short * src_pixels,int src_width)
+{
+ for(int i=0;i<src_width;i++)
+ {
+ dst_pixels_u[i]=(unsigned char)src_pixels[i];
+ dst_pixels_v[i]=(unsigned char)src_pixels[i+src_width];
+ }
+ for(int i=src_width;i<src_width*2;i++)
+ {
+ dst_pixels_v[i]=(unsigned char)src_pixels[i];
+ }
+ return;
+}
+void
+video_sdl_sink_s::copy_line_single_plane(unsigned char *dst_pixels,const short * src_pixels,int src_width)
+{
+ for(int i=0;i<src_width;i++)
+ {
+ dst_pixels[i]=(unsigned char)src_pixels[i];
+ }
+ return;
+}
+
+void
+video_sdl_sink_s::copy_line_single_plane_dec2(unsigned char *dst_pixels,const short * src_pixels,int src_width)
+{
+ for(int i=0,j=0;i<src_width;i+=2,j++)
+ {
+ dst_pixels[j]=(unsigned char)src_pixels[i];
+ }
+ return;
+}
+
+int
+video_sdl_sink_s::copy_plane_to_surface (int plane,int noutput_items,
+ const short * src_pixels)
+{
+ const int first_dst_plane=(12==plane ||1122==plane)?1:plane;
+ const int second_dst_plane=(12==plane ||1122==plane)?2:plane;
+ int current_line=(0==plane)?d_current_line:d_current_line/2;
+ unsigned char * dst_pixels = (unsigned char *)d_image->pixels[first_dst_plane];
+ dst_pixels=&dst_pixels[current_line*d_image->pitches[first_dst_plane]];
+ unsigned char * dst_pixels_2 = (unsigned char *)d_image->pixels[second_dst_plane];
+ dst_pixels_2=&dst_pixels_2[current_line*d_image->pitches[second_dst_plane]];
+ int src_width=(0==plane || 12==plane || 1122==plane)?d_width:d_width/2;
+ int noutput_items_produced=0;
+ int max_height=(0==plane)?d_height-1:d_height/2-1;
+ for (int i = 0; i < noutput_items; i += src_width){
+ //output one line at a time
+ if(12==plane)
+ {
+ copy_line_pixel_interleaved(dst_pixels,dst_pixels_2,src_pixels,src_width);
+ dst_pixels_2 += d_image->pitches[second_dst_plane];
+ }
+ else if (1122==plane)
+ {
+ copy_line_line_interleaved(dst_pixels,dst_pixels_2,src_pixels,src_width);
+ dst_pixels_2 += d_image->pitches[second_dst_plane];
+ src_pixels += src_width;
+ }
+ else if (0==plane)
+ copy_line_single_plane(dst_pixels,src_pixels,src_width);
+ else /* 1==plane || 2==plane*/
+ copy_line_single_plane_dec2(dst_pixels,src_pixels,src_width);//decimate by two horizontally
+
+ src_pixels += src_width;
+ dst_pixels += d_image->pitches[first_dst_plane];
+ noutput_items_produced+=src_width;
+ current_line++;
+ if (current_line>max_height)
+ {
+ //Start new frame
+ //TODO, do this all in a seperate thread
+ current_line=0;
+ dst_pixels=d_image->pixels[first_dst_plane];
+ dst_pixels_2=d_image->pixels[second_dst_plane];
+ if(0==plane)
+ {
+ SDL_DisplayYUVOverlay(d_image, &d_dst_rect);
+ //SDL_Flip(d_screen);
+ unsigned int ticks=SDL_GetTicks();//milliseconds
+ d_wanted_ticks+=d_wanted_frametime_ms;
+ float avg_alpha=0.1;
+ int time_diff=d_wanted_ticks-ticks;
+ d_avg_delay=time_diff*avg_alpha +d_avg_delay*(1.0-avg_alpha);
+ }
+ }
+ }
+ if(0==plane) d_current_line=current_line;
+ return noutput_items_produced;
+}
+
+int
+video_sdl_sink_s::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ short *src_pixels_0,*src_pixels_1,*src_pixels_2;
+ int noutput_items_produced=0;
+ int plane;
+ int delay=(int)d_avg_delay;
+ if(0==d_wanted_ticks)
+ d_wanted_ticks=SDL_GetTicks();
+ if(delay>0)
+ SDL_Delay((unsigned int)delay);//compensate if running too fast
+
+ if ( SDL_LockYUVOverlay( d_image ) ) {
+ return 0;
+ }
+ switch (input_items.size ()){
+ case 3: // first channel=Y, second channel is U , third channel is V
+ src_pixels_0 = (short *) input_items[0];
+ src_pixels_1 = (short *) input_items[1];
+ src_pixels_2 = (short *) input_items[2];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ copy_plane_to_surface (1,d_chunk_size, src_pixels_1);
+ copy_plane_to_surface (2,d_chunk_size, src_pixels_2);
+ noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ src_pixels_1 += d_chunk_size;
+ src_pixels_2 += d_chunk_size;
+ }
+ break;
+ case 2:
+ if(1) //if(pixel_interleaved_uv)
+ {
+ // first channel=Y, second channel is alternating pixels U and V
+ src_pixels_0 = (short *) input_items[0];
+ src_pixels_1 = (short *) input_items[1];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ copy_plane_to_surface (12,d_chunk_size/2, src_pixels_1);
+ noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ src_pixels_1 += d_chunk_size;
+ }
+ } else
+ {
+ // first channel=Y, second channel is alternating lines U and V
+ src_pixels_0 = (short *) input_items[0];
+ src_pixels_1 = (short *) input_items[1];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ copy_plane_to_surface (1222,d_chunk_size/2, src_pixels_1);
+ noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ src_pixels_1 += d_chunk_size;
+ }
+ }
+ break;
+ case 1: // grey (Y) input
+ /* Y component */
+ plane=0;
+ src_pixels_0 = (short *) input_items[plane];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ noutput_items_produced+=copy_plane_to_surface (plane,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ }
+ break;
+ default: //0 or more then 3 channels
+ std::cerr << "video_sdl_sink_s: Wrong number of channels: ";
+ std::cerr <<"1, 2 or 3 channels are supported.\n Requested number of channels is "<< input_items.size () <<"\n";
+ throw std::runtime_error ("video_sdl_sink_s");
+ }
+
+ SDL_UnlockYUVOverlay( d_image );
+ return noutput_items_produced;
+}
diff --git a/gr-video-sdl/src/video_sdl_sink_s.h b/gr-video-sdl/src/video_sdl_sink_s.h
new file mode 100644
index 000000000..662c52b93
--- /dev/null
+++ b/gr-video-sdl/src/video_sdl_sink_s.h
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_VIDEO_SDL_SINK_S_H
+#define INCLUDED_VIDEO_SDL_SINK_S_H
+
+#include <gr_sync_block.h>
+#include <string>
+#include <SDL.h>
+
+/* fourcc (four character code) */
+#define vid_fourcc(a,b,c,d) (((unsigned)(a)<<0) | ((unsigned)(b)<<8) | ((unsigned)(c)<<16) | ((unsigned)(d)<<24))
+#define IMGFMT_YV12 vid_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */
+
+class video_sdl_sink_s;
+typedef boost::shared_ptr<video_sdl_sink_s> video_sdl_sink_s_sptr;
+
+video_sdl_sink_s_sptr
+video_sdl_make_sink_s (double framerate,int width=640, int height=480,unsigned int format=IMGFMT_YV12,int dst_width=-1,int dst_height=-1);
+
+/*!
+ * \brief video sink using SDL
+ *
+ * input signature is one, two or three streams of signed short.
+ * One stream: stream is grey (Y)
+ * two streems: first is grey (Y), second is alternating U and V
+ * Three streams: first is grey (Y), second is U, third is V
+ * Input samples must be in the range [0,255].
+ */
+
+class video_sdl_sink_s : public gr_sync_block {
+ friend video_sdl_sink_s_sptr
+ video_sdl_make_sink_s (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height);
+
+ int d_chunk_size;
+
+ protected:
+ video_sdl_sink_s (double framerate,int width, int height,unsigned int format,
+ int dst_width,int dst_height);
+ void copy_line_pixel_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,
+ const short * src_pixels,int src_width);
+ void copy_line_line_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,
+ const short * src_pixels,int src_width);
+ void copy_line_single_plane(unsigned char *dst_pixels,const short * src_pixels,int src_width);
+ void copy_line_single_plane_dec2(unsigned char *dst_pixels,const short * src_pixels,int src_width);
+ int copy_plane_to_surface (int plane,int noutput_items,
+ const short * src_pixels);
+ float d_framerate;
+ int d_wanted_frametime_ms;
+ int d_width;
+ int d_height;
+ int d_dst_width;
+ int d_dst_height;
+ int d_format;
+ int d_current_line;
+ SDL_Surface *d_screen;
+ SDL_Overlay *d_image;
+ SDL_Rect d_dst_rect;
+ float d_avg_delay;
+ unsigned int d_wanted_ticks;
+
+
+ public:
+ ~video_sdl_sink_s ();
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_VIDEO_SDL_SINK_S_H */
diff --git a/gr-video-sdl/src/video_sdl_sink_uc.cc b/gr-video-sdl/src/video_sdl_sink_uc.cc
new file mode 100644
index 000000000..1462d7287
--- /dev/null
+++ b/gr-video-sdl/src/video_sdl_sink_uc.cc
@@ -0,0 +1,291 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <SDL.h>
+
+#include <video_sdl_sink_uc.h>
+#include <gr_io_signature.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <iostream>
+#include <stdexcept>
+
+
+
+video_sdl_sink_uc::video_sdl_sink_uc (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height)
+ : gr_sync_block ("video_sdl_sink_uc",
+ gr_make_io_signature (1, 3, sizeof (unsigned char)),
+ gr_make_io_signature (0, 0, 0)),
+ d_chunk_size (width*height),
+ d_framerate(framerate),
+ d_wanted_frametime_ms(0),
+ d_width(width),
+ d_height (height),
+ d_dst_width(dst_width),
+ d_dst_height(dst_height),
+ d_format(format),
+ d_current_line(0),
+ d_screen(NULL),
+ d_image(NULL),
+ d_avg_delay(0.0),
+ d_wanted_ticks(0)
+{
+ if(framerate<=0.0)
+ d_wanted_frametime_ms=0;//Go as fast as possible
+ else
+ d_wanted_frametime_ms=(int)(1000.0/framerate);
+ if(dst_width<0) d_dst_width=d_width;
+ if(dst_height<0) d_dst_height=d_height;
+ if(0==format) d_format=IMGFMT_YV12;
+
+ atexit(SDL_Quit);//check if this is the way to do this
+ if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
+ std::cerr << "video_sdl_sink_uc: Couldn't initialize SDL:" << SDL_GetError() << " \n SDL_Init(SDL_INIT_VIDEO) failed\n";
+ throw std::runtime_error ("video_sdl_sink_uc");
+ };
+
+ /* accept any depth */
+ d_screen = SDL_SetVideoMode(dst_width, dst_height, 0, SDL_SWSURFACE|SDL_RESIZABLE|SDL_ANYFORMAT);//SDL_DOUBLEBUF |SDL_SWSURFACE| SDL_HWSURFACE||SDL_FULLSCREEN
+ if ( d_screen == NULL ) {
+ std::cerr << "Unable to set SDL video mode: " << SDL_GetError() <<"\n SDL_SetVideoMode() Failed \n";
+ exit(1);
+ }
+ if ( d_image ) {
+ SDL_FreeYUVOverlay(d_image);
+ }
+ /* Initialize and create the YUV Overlay used for video out */
+ if (!(d_image = SDL_CreateYUVOverlay (d_width, d_height, SDL_YV12_OVERLAY, d_screen))) {
+ std::cerr << "SDL: Couldn't create a YUV overlay: \n"<< SDL_GetError() <<"\n";
+ throw std::runtime_error ("video_sdl_sink_uc");
+ }
+
+ printf("SDL screen_mode %d bits-per-pixel\n",
+ d_screen->format->BitsPerPixel);
+ printf("SDL overlay_mode %i \n",
+ d_image->format);
+ d_chunk_size = std::min(1,16384/width); //width*16;
+ d_chunk_size = d_chunk_size*width;
+ //d_chunk_size = (int) (width);
+ set_output_multiple (d_chunk_size);
+ /* Set the default playback area */
+ d_dst_rect.x = 0;
+ d_dst_rect.y = 0;
+ d_dst_rect.w = d_dst_width;
+ d_dst_rect.h = d_dst_height;
+ //clear the surface to grey
+ if ( SDL_LockYUVOverlay( d_image ) ) {
+ std::cerr << "SDL: Couldn't lock YUV overlay: \n"<< SDL_GetError() <<"\n";
+ throw std::runtime_error ("video_sdl_sink_uc");
+ }
+ memset(d_image->pixels[0], 128, d_image->pitches[0]*d_height);
+ memset(d_image->pixels[1], 128, d_image->pitches[1]*d_height/2);
+ memset(d_image->pixels[2], 128, d_image->pitches[2]*d_height/2);
+ SDL_UnlockYUVOverlay( d_image );
+}
+
+video_sdl_sink_uc::~video_sdl_sink_uc ()
+{
+ SDL_Quit();
+}
+
+video_sdl_sink_uc_sptr
+video_sdl_make_sink_uc (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height)
+{
+ return video_sdl_sink_uc_sptr (new video_sdl_sink_uc (framerate, width, height,format,dst_width,dst_height));
+}
+
+void
+video_sdl_sink_uc::copy_line_pixel_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,const unsigned char * src_pixels,int src_width)
+{
+ for(int i=0;i<src_width;i++)
+ {
+ dst_pixels_u[i]=src_pixels[i*2];
+ dst_pixels_v[i]=src_pixels[i*2+1];
+ }
+ return;
+}
+
+void
+video_sdl_sink_uc::copy_line_line_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,const unsigned char * src_pixels,int src_width)
+{
+ memcpy(dst_pixels_u, src_pixels, src_width);
+ memcpy(dst_pixels_v, src_pixels+src_width, src_width);
+ return;
+}
+
+void
+video_sdl_sink_uc::copy_line_single_plane(unsigned char *dst_pixels,const unsigned char * src_pixels,int src_width)
+{
+ memcpy(dst_pixels, src_pixels, src_width);
+ return;
+}
+
+void
+video_sdl_sink_uc::copy_line_single_plane_dec2(unsigned char *dst_pixels,const unsigned char * src_pixels,int src_width)
+{
+ for(int i=0,j=0;i<src_width;i+=2,j++)
+ {
+ dst_pixels[j]=(unsigned char)src_pixels[i];
+ }
+ return;
+}
+
+int
+video_sdl_sink_uc::copy_plane_to_surface (int plane,int noutput_items,
+ const unsigned char * src_pixels)
+{
+ const int first_dst_plane=(12==plane ||1122==plane)?1:plane;
+ const int second_dst_plane=(12==plane ||1122==plane)?2:plane;
+ int current_line=(0==plane)?d_current_line:d_current_line/2;
+ unsigned char * dst_pixels = (unsigned char *)d_image->pixels[first_dst_plane];
+ dst_pixels=&dst_pixels[current_line*d_image->pitches[first_dst_plane]];
+ unsigned char * dst_pixels_2 = (unsigned char *)d_image->pixels[second_dst_plane];
+ dst_pixels_2=&dst_pixels_2[current_line*d_image->pitches[second_dst_plane]];
+ int src_width=(0==plane || 12==plane || 1122==plane)?d_width:d_width/2;
+ int noutput_items_produced=0;
+ int max_height=(0==plane)?d_height-1:d_height/2-1;
+ for (int i = 0; i < noutput_items; i += src_width){
+ //output one line at a time
+ if(12==plane)
+ {
+ copy_line_pixel_interleaved(dst_pixels,dst_pixels_2,src_pixels,src_width);
+ dst_pixels_2 += d_image->pitches[second_dst_plane];
+ }
+ else if (1122==plane)
+ {
+ copy_line_line_interleaved(dst_pixels,dst_pixels_2,src_pixels,src_width);
+ dst_pixels_2 += d_image->pitches[second_dst_plane];
+ src_pixels += src_width;
+ }
+ else if (0==plane)
+ copy_line_single_plane(dst_pixels,src_pixels,src_width);
+ else /* 1==plane || 2==plane*/
+ copy_line_single_plane_dec2(dst_pixels,src_pixels,src_width);//decimate by two horizontally
+ src_pixels += src_width;
+ dst_pixels += d_image->pitches[first_dst_plane];
+ noutput_items_produced+=src_width;
+ current_line++;
+ if (current_line>max_height)
+ {
+ //Start new frame
+ //TODO, do this all in a seperate thread
+ current_line=0;
+ dst_pixels=d_image->pixels[first_dst_plane];
+ dst_pixels_2=d_image->pixels[second_dst_plane];
+ if(0==plane)
+ {
+ SDL_DisplayYUVOverlay(d_image, &d_dst_rect);
+ //SDL_Flip(d_screen);
+ unsigned int ticks=SDL_GetTicks();//milliseconds
+ d_wanted_ticks+=d_wanted_frametime_ms;
+ float avg_alpha=0.1;
+ int time_diff=d_wanted_ticks-ticks;
+ d_avg_delay=time_diff*avg_alpha +d_avg_delay*(1.0-avg_alpha);
+ }
+ }
+ }
+ if(0==plane) d_current_line=current_line;
+ return noutput_items_produced;
+}
+
+int
+video_sdl_sink_uc::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ unsigned char *src_pixels_0,*src_pixels_1,*src_pixels_2;
+ int noutput_items_produced=0;
+ int plane;
+ int delay=(int)d_avg_delay;
+ if(0==d_wanted_ticks)
+ d_wanted_ticks=SDL_GetTicks();
+ if(delay>0)
+ SDL_Delay((unsigned int)delay);//compensate if running too fast
+
+ if ( SDL_LockYUVOverlay( d_image ) ) {
+ return 0;
+ }
+ switch (input_items.size ()){
+ case 3: // first channel=Y, second channel is U , third channel is V
+ src_pixels_0 = (unsigned char *) input_items[0];
+ src_pixels_1 = (unsigned char *) input_items[1];
+ src_pixels_2 = (unsigned char *) input_items[2];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ copy_plane_to_surface (1,d_chunk_size, src_pixels_1);
+ copy_plane_to_surface (2,d_chunk_size, src_pixels_2);
+ noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ src_pixels_1 += d_chunk_size;
+ src_pixels_2 += d_chunk_size;
+ }
+ break;
+ case 2:
+ if(1) //if(pixel_interleaved_uv)
+ {
+ // first channel=Y, second channel is alternating pixels U and V
+ src_pixels_0 = (unsigned char *) input_items[0];
+ src_pixels_1 = (unsigned char *) input_items[1];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ copy_plane_to_surface (12,d_chunk_size/2, src_pixels_1);
+ noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ src_pixels_1 += d_chunk_size;
+ }
+ } else
+ {
+ // first channel=Y, second channel is alternating lines U and V
+ src_pixels_0 = (unsigned char *) input_items[0];
+ src_pixels_1 = (unsigned char *) input_items[1];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ copy_plane_to_surface (1222,d_chunk_size/2, src_pixels_1);
+ noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ src_pixels_1 += d_chunk_size;
+ }
+ }
+ break;
+ case 1: // grey (Y) input
+ /* Y component */
+ plane=0;
+ src_pixels_0 = (unsigned char *) input_items[plane];
+ for (int i = 0; i < noutput_items; i += d_chunk_size){
+ noutput_items_produced+=copy_plane_to_surface (plane,d_chunk_size, src_pixels_0);
+ src_pixels_0 += d_chunk_size;
+ }
+ break;
+ default: //0 or more then 3 channels
+ std::cerr << "video_sdl_sink_uc: Wrong number of channels: ";
+ std::cerr <<"1, 2 or 3 channels are supported.\n Requested number of channels is "<< input_items.size () <<"\n";
+ throw std::runtime_error ("video_sdl_sink_uc");
+ }
+
+ SDL_UnlockYUVOverlay( d_image );
+ return noutput_items_produced;
+}
diff --git a/gr-video-sdl/src/video_sdl_sink_uc.h b/gr-video-sdl/src/video_sdl_sink_uc.h
new file mode 100644
index 000000000..3f380f3c4
--- /dev/null
+++ b/gr-video-sdl/src/video_sdl_sink_uc.h
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_VIDEO_SDL_SINK_UC_H
+#define INCLUDED_VIDEO_SDL_SINK_UC_H
+
+#include <gr_sync_block.h>
+#include <string>
+#include <SDL.h>
+
+/* fourcc (four character code) */
+#define vid_fourcc(a,b,c,d) (((unsigned)(a)<<0) | ((unsigned)(b)<<8) | ((unsigned)(c)<<16) | ((unsigned)(d)<<24))
+#define IMGFMT_YV12 vid_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */
+
+class video_sdl_sink_uc;
+typedef boost::shared_ptr<video_sdl_sink_uc> video_sdl_sink_uc_sptr;
+
+video_sdl_sink_uc_sptr
+video_sdl_make_sink_uc (double framerate,int width=640, int height=480,unsigned int format=IMGFMT_YV12,int dst_width=-1,int dst_height=-1);
+
+/*!
+ * \brief video sink using SDL
+ *
+ * input signature is one, two or three streams of uchar.
+ * One stream: stream is grey (Y)
+ * two streems: first is grey (Y), second is alternating U and V
+ * Three streams: first is grey (Y), second is U, third is V
+ * Input samples must be in the range [0,255].
+ */
+
+class video_sdl_sink_uc : public gr_sync_block {
+ friend video_sdl_sink_uc_sptr
+ video_sdl_make_sink_uc (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height);
+
+ int d_chunk_size;
+
+ protected:
+ video_sdl_sink_uc (double framerate,int width, int height,unsigned int format,
+ int dst_width,int dst_height);
+ void copy_line_pixel_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,
+ const unsigned char * src_pixels,int src_width);
+ void copy_line_line_interleaved(unsigned char *dst_pixels_u,unsigned char *dst_pixels_v,
+ const unsigned char * src_pixels,int src_width);
+ void copy_line_single_plane(unsigned char *dst_pixels,const unsigned char * src_pixels,int src_width);
+ void copy_line_single_plane_dec2(unsigned char *dst_pixels,const unsigned char * src_pixels,int src_width);
+ int copy_plane_to_surface (int plane,int noutput_items,
+ const unsigned char * src_pixels);
+ float d_framerate;
+ int d_wanted_frametime_ms;
+ int d_width;
+ int d_height;
+ int d_dst_width;
+ int d_dst_height;
+ int d_format;
+ int d_current_line;
+ SDL_Surface *d_screen;
+ SDL_Overlay *d_image;
+ SDL_Rect d_dst_rect;
+ float d_avg_delay;
+ unsigned int d_wanted_ticks;
+
+
+ public:
+ ~video_sdl_sink_uc ();
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_VIDEO_SDL_SINK_UC_H */