3 * Copyright 2006 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
29 #include <video_sdl_sink_uc.h>
30 #include <gr_io_signature.h>
31 #include <sys/types.h>
41 video_sdl_sink_uc::video_sdl_sink_uc (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height)
42 : gr_sync_block ("video_sdl_sink_uc",
43 gr_make_io_signature (1, 3, sizeof (unsigned char)),
44 gr_make_io_signature (0, 0, 0)),
45 d_chunk_size (width*height),
46 d_framerate(framerate),
47 d_wanted_frametime_ms(0),
50 d_dst_width(dst_width),
51 d_dst_height(dst_height),
60 d_wanted_frametime_ms=0;//Go as fast as possible
62 d_wanted_frametime_ms=(int)(1000.0/framerate);
63 if(dst_width<0) d_dst_width=d_width;
64 if(dst_height<0) d_dst_height=d_height;
65 if(0==format) d_format=IMGFMT_YV12;
67 atexit(SDL_Quit);//check if this is the way to do this
68 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
69 std::cerr << "video_sdl_sink_uc: Couldn't initialize SDL:" << SDL_GetError() << " \n SDL_Init(SDL_INIT_VIDEO) failed\n";
70 throw std::runtime_error ("video_sdl_sink_uc");
73 /* accept any depth */
74 d_screen = SDL_SetVideoMode(dst_width, dst_height, 0, SDL_SWSURFACE|SDL_RESIZABLE|SDL_ANYFORMAT);//SDL_DOUBLEBUF |SDL_SWSURFACE| SDL_HWSURFACE||SDL_FULLSCREEN
75 if ( d_screen == NULL ) {
76 std::cerr << "Unable to set SDL video mode: " << SDL_GetError() <<"\n SDL_SetVideoMode() Failed \n";
80 SDL_FreeYUVOverlay(d_image);
82 /* Initialize and create the YUV Overlay used for video out */
83 if (!(d_image = SDL_CreateYUVOverlay (d_width, d_height, SDL_YV12_OVERLAY, d_screen))) {
84 std::cerr << "SDL: Couldn't create a YUV overlay: \n"<< SDL_GetError() <<"\n";
85 throw std::runtime_error ("video_sdl_sink_uc");
88 printf("SDL screen_mode %d bits-per-pixel\n",
89 d_screen->format->BitsPerPixel);
90 printf("SDL overlay_mode %i \n",
92 d_chunk_size = std::min(1,16384/width); //width*16;
93 d_chunk_size = d_chunk_size*width;
94 //d_chunk_size = (int) (width);
95 set_output_multiple (d_chunk_size);
96 /* Set the default playback area */
99 d_dst_rect.w = d_dst_width;
100 d_dst_rect.h = d_dst_height;
101 //clear the surface to grey
102 if ( SDL_LockYUVOverlay( d_image ) ) {
103 std::cerr << "SDL: Couldn't lock YUV overlay: \n"<< SDL_GetError() <<"\n";
104 throw std::runtime_error ("video_sdl_sink_uc");
106 memset(d_image->pixels[0], 128, d_image->pitches[0]*d_height);
107 memset(d_image->pixels[1], 128, d_image->pitches[1]*d_height/2);
108 memset(d_image->pixels[2], 128, d_image->pitches[2]*d_height/2);
109 SDL_UnlockYUVOverlay( d_image );
112 video_sdl_sink_uc::~video_sdl_sink_uc ()
117 video_sdl_sink_uc_sptr
118 video_sdl_make_sink_uc (double framerate,int width, int height,unsigned int format,int dst_width,int dst_height)
120 return video_sdl_sink_uc_sptr (new video_sdl_sink_uc (framerate, width, height,format,dst_width,dst_height));
124 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)
126 for(int i=0;i<src_width;i++)
128 dst_pixels_u[i]=src_pixels[i*2];
129 dst_pixels_v[i]=src_pixels[i*2+1];
135 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)
137 memcpy(dst_pixels_u, src_pixels, src_width);
138 memcpy(dst_pixels_v, src_pixels+src_width, src_width);
143 video_sdl_sink_uc::copy_line_single_plane(unsigned char *dst_pixels,const unsigned char * src_pixels,int src_width)
145 memcpy(dst_pixels, src_pixels, src_width);
150 video_sdl_sink_uc::copy_line_single_plane_dec2(unsigned char *dst_pixels,const unsigned char * src_pixels,int src_width)
152 for(int i=0,j=0;i<src_width;i+=2,j++)
154 dst_pixels[j]=(unsigned char)src_pixels[i];
160 video_sdl_sink_uc::copy_plane_to_surface (int plane,int noutput_items,
161 const unsigned char * src_pixels)
163 const int first_dst_plane=(12==plane ||1122==plane)?1:plane;
164 const int second_dst_plane=(12==plane ||1122==plane)?2:plane;
165 int current_line=(0==plane)?d_current_line:d_current_line/2;
166 unsigned char * dst_pixels = (unsigned char *)d_image->pixels[first_dst_plane];
167 dst_pixels=&dst_pixels[current_line*d_image->pitches[first_dst_plane]];
168 unsigned char * dst_pixels_2 = (unsigned char *)d_image->pixels[second_dst_plane];
169 dst_pixels_2=&dst_pixels_2[current_line*d_image->pitches[second_dst_plane]];
170 int src_width=(0==plane || 12==plane || 1122==plane)?d_width:d_width/2;
171 int noutput_items_produced=0;
172 int max_height=(0==plane)?d_height-1:d_height/2-1;
173 for (int i = 0; i < noutput_items; i += src_width){
174 //output one line at a time
177 copy_line_pixel_interleaved(dst_pixels,dst_pixels_2,src_pixels,src_width);
178 dst_pixels_2 += d_image->pitches[second_dst_plane];
180 else if (1122==plane)
182 copy_line_line_interleaved(dst_pixels,dst_pixels_2,src_pixels,src_width);
183 dst_pixels_2 += d_image->pitches[second_dst_plane];
184 src_pixels += src_width;
187 copy_line_single_plane(dst_pixels,src_pixels,src_width);
188 else /* 1==plane || 2==plane*/
189 copy_line_single_plane_dec2(dst_pixels,src_pixels,src_width);//decimate by two horizontally
190 src_pixels += src_width;
191 dst_pixels += d_image->pitches[first_dst_plane];
192 noutput_items_produced+=src_width;
194 if (current_line>max_height)
197 //TODO, do this all in a seperate thread
199 dst_pixels=d_image->pixels[first_dst_plane];
200 dst_pixels_2=d_image->pixels[second_dst_plane];
203 SDL_DisplayYUVOverlay(d_image, &d_dst_rect);
204 //SDL_Flip(d_screen);
205 unsigned int ticks=SDL_GetTicks();//milliseconds
206 d_wanted_ticks+=d_wanted_frametime_ms;
208 int time_diff=d_wanted_ticks-ticks;
209 d_avg_delay=time_diff*avg_alpha +d_avg_delay*(1.0-avg_alpha);
213 if(0==plane) d_current_line=current_line;
214 return noutput_items_produced;
218 video_sdl_sink_uc::work (int noutput_items,
219 gr_vector_const_void_star &input_items,
220 gr_vector_void_star &output_items)
222 unsigned char *src_pixels_0,*src_pixels_1,*src_pixels_2;
223 int noutput_items_produced=0;
225 int delay=(int)d_avg_delay;
226 if(0==d_wanted_ticks)
227 d_wanted_ticks=SDL_GetTicks();
229 SDL_Delay((unsigned int)delay);//compensate if running too fast
231 if ( SDL_LockYUVOverlay( d_image ) ) {
234 switch (input_items.size ()){
235 case 3: // first channel=Y, second channel is U , third channel is V
236 src_pixels_0 = (unsigned char *) input_items[0];
237 src_pixels_1 = (unsigned char *) input_items[1];
238 src_pixels_2 = (unsigned char *) input_items[2];
239 for (int i = 0; i < noutput_items; i += d_chunk_size){
240 copy_plane_to_surface (1,d_chunk_size, src_pixels_1);
241 copy_plane_to_surface (2,d_chunk_size, src_pixels_2);
242 noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
243 src_pixels_0 += d_chunk_size;
244 src_pixels_1 += d_chunk_size;
245 src_pixels_2 += d_chunk_size;
249 if(1) //if(pixel_interleaved_uv)
251 // first channel=Y, second channel is alternating pixels U and V
252 src_pixels_0 = (unsigned char *) input_items[0];
253 src_pixels_1 = (unsigned char *) input_items[1];
254 for (int i = 0; i < noutput_items; i += d_chunk_size){
255 copy_plane_to_surface (12,d_chunk_size/2, src_pixels_1);
256 noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
257 src_pixels_0 += d_chunk_size;
258 src_pixels_1 += d_chunk_size;
262 // first channel=Y, second channel is alternating lines U and V
263 src_pixels_0 = (unsigned char *) input_items[0];
264 src_pixels_1 = (unsigned char *) input_items[1];
265 for (int i = 0; i < noutput_items; i += d_chunk_size){
266 copy_plane_to_surface (1222,d_chunk_size/2, src_pixels_1);
267 noutput_items_produced+=copy_plane_to_surface (0,d_chunk_size, src_pixels_0);
268 src_pixels_0 += d_chunk_size;
269 src_pixels_1 += d_chunk_size;
273 case 1: // grey (Y) input
276 src_pixels_0 = (unsigned char *) input_items[plane];
277 for (int i = 0; i < noutput_items; i += d_chunk_size){
278 noutput_items_produced+=copy_plane_to_surface (plane,d_chunk_size, src_pixels_0);
279 src_pixels_0 += d_chunk_size;
282 default: //0 or more then 3 channels
283 std::cerr << "video_sdl_sink_uc: Wrong number of channels: ";
284 std::cerr <<"1, 2 or 3 channels are supported.\n Requested number of channels is "<< input_items.size () <<"\n";
285 throw std::runtime_error ("video_sdl_sink_uc");
288 SDL_UnlockYUVOverlay( d_image );
289 return noutput_items_produced;