SDL: Unable to flip multiple surfaces - c

I've been trying to flip surfaces and have been successful if I'm only flipping a single surface (the same surface I got back from SDL_SetVideoMode). If I try to flip the surface I get back from SDL_DisplayFormat, nothing happens. I've attached demo code that demonstrates my problem:
#include <stdio.h>
#include <stdlib.h>
#include "SDL/SDL.h"
void main()
{
int i;
SDL_Surface *mysurface1;
SDL_Surface *mysurface2;
char *pxl;
SDL_Init( SDL_INIT_EVERYTHING );
mysurface1 = SDL_SetVideoMode( 640, 480, 8, SDL_DOUBLEBUF|SDL_HWSURFACE );
for (i = 0; i < 20; i++)
{
pxl = (char *)mysurface1->pixels + i*mysurface1->pitch + i;
*pxl = 100; // Red Line
}
SDL_Flip(mysurface1); // Works, we see a red line
sleep(5);
printf("Sleeping for 5...\n");
mysurface2 = SDL_DisplayFormat(mysurface1);
for (i = 0; i < 20; i++)
{
pxl = (char *)mysurface2->pixels + i*mysurface2->pitch + i;
*pxl = 255; // White line
}
SDL_Flip(mysurface2); // White line doesnt appear
printf("Done... No white line\n");
sleep(10);
}
Has anyone ever seen this before? Again, I think I tracked it down to surfaces that wont display if its a surface I got back from SDL_DisplayFormat. If I do it on the surface I get back from SDL_SetVideoMode, then I see the red line and everything works fine.

You can only flip the main display surface (the one created with SDL_SetVideoMode). In order to make your other surface visible, you need to blit it onto the main surface. Lookup SDL_BlitSurface for details on how to do that.

Pass the screen to the SDL_Flip function. The flip function modifies the value of screen->pixels so that it points to the surface that isn't visible on the screen.
However, this is only applicable to video devices such as SVGA and DGA. On X11, calling SDL_Flip(screen) is equivalent to calling SDL_UpdateRect(screen, 0, 0, 0, 0).
#include <stdio.h>
#include <stdlib.h>
#include "SDL/SDL.h"
void main()
{
int i;
SDL_Surface *screen;
char *pxl;
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 640, 480, 8, SDL_DOUBLEBUF|SDL_HWSURFACE );
printf("Drawing the red line ...\n");
printf("screen->pixels = %p\n", screen->pixels);
for (i = 0; i < 100; i++)
{
pxl = (char *)screen->pixels + i*screen->pitch + i;
*pxl = 100; // Red Line
}
printf("Flip screens\n");
SDL_Flip(screen); // Display the red line
printf("Drawing the white line ...\n");
printf("screen->pixels = %p\n", screen->pixels);
for (i = 0; i < 100; i++)
{
pxl = (char *)screen->pixels + i*screen->pitch + i;
*pxl = 255; // White line
}
sleep(3);
printf("Flip screens\n");
SDL_Flip(screen); // Display the white line
sleep(10);
}
On my Linux notebook, this prints:
Drawing the red line ...
screen->pixels = 0xb6c8c008
Flip screens
Drawing the white line ...
screen->pixels = 0xb6c8c008
Flip screens
The value of screen->pixels is the same, but this is only because on X11 the flip operation is a no-operation. On a video device such as SVGA or DGA, the two values would be different.

First, it seems SDL_Flip() only works on surfaces that correspond to the screen or a window, like those created by SDL_SetVideoMode(). Your other surface is off-screen; it doesn't make much sense to double-buffer it (or flip it), and it most likely isn't double-buffered anyway. Being an off screen surface, it won't appear until you blit it to your display surface with SDL_BlitSurface() or a similar function -- then, the changes will be visible next time you flip the display surface.
Essentially, mysurface2 isn't actually on your display until you put it there, by blitting it onto a surface that is on your display. If you replace the following:
SDL_Flip(mysurface2); // White line doesnt appear
With this:
SDL_BlitSurface(mysurface2,NULL,mysurface1,NULL);
SDL_Flip(mysurface1);
...then your code will probably work as you expect.

Related

Xlib image grab fails in XGetImage

Cookie cuttered (from supposedly working code) a trivial C program to perform a Xlib image grab using XGetImage(). At this point I'm not trying to process the image, this is just a proof-of-concept to see if the image grab works - and it doesn't. The XGetImage() call fails like:
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 73 (X_GetImage)
Serial number of failed request: 21
Current serial number in output stream: 21
I spent a fair amount of time researching this and apparently this problem has plagued other developers and no definitive answer was ever arrived at. Does someone know how I could go about resolving this? I can tell from the printf that the window of interest was correctly identified. The XMapRaised() is a suggestion from a prior thread on this problem, but doesn't seem to help. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "/usr/include/X11/Xlib.h"
Window findScidWindow(Display *display )
{
Bool found = False;
Window rootWindow = RootWindow(display, DefaultScreen(display));
Atom atom = XInternAtom(display, "_NET_CLIENT_LIST", True);
Atom actualType;
int format;
unsigned long numItems;
unsigned long bytesAfter;
unsigned char *data = '\0';
Window *list;
char *windowName;
int status = XGetWindowProperty(display, rootWindow, atom, 0L, (~0L), False,
AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, &data);
list = (Window *)data;
if (status >= Success && numItems)
{
for (int i = 0; i < numItems; ++i)
{
status = XFetchName(display, list[i], &windowName);
if (status >= Success)
{
if(strstr(windowName, "Scid vs. PC") != NULL)
{
XFree(windowName);
XFree(data);
return list[i];
}
}
}
}
}
void
main( int argc, char*argv )
{
Display* d = XOpenDisplay(":0.0");
XImage *image;
Window root = (Window)0x0560003b; /* obtained via 'wmctrl -l -G' */
Window ScidWindow = findScidWindow(d);
XWindowAttributes attrib;
XGetWindowAttributes(d, ScidWindow, &attrib);
int width = attrib.width;
int height = attrib.height;
printf("width: %d height: %d\n",width,height);
XMapRaised(d, root);
/* coordinates 438,110 obtained via 'wmctrl -l -G' */
image = XGetImage( d, ScidWindow, 438, 110, width, height, AllPlanes, ZPixmap);
}
The issue is
image = XGetImage( d, ScidWindow, 438, 110, width, height, AllPlanes, ZPixmap);
uses x = 438 and y = 110 that is particular a problem if x + width is actually bigger as the window width (same for the height)
So here I have to assume you're not attempting to crop the window image but rather want to take a plain raw screenshot, then you just need to pass 0 for x and y:
image = XGetImage( d, ScidWindow, 0, 0, width, height, AllPlanes, ZPixmap);
The explanation is that the coordination system is not the full display or screen but the one of the window you are grabbing. Means the window starts at (0, 0).
This took me also some time to figure out.

How can i add line breaks when rendering Text using X11,

I am making an application that renders texts according to style mentioned on screen using X Windows System and Xft. My code is working fine as shown below.
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
char * nowShowing()
{
return strdup("This is a sample text This is rendered with new Driver installed This is a sample text his is rendered with new Driver installed");
}
int main()
{
XftFont *font;
XftDraw *draw;
XRenderColor render_color;
XftColor xft_color;
char *str;
str = nowShowing();
int x = 70;
int y = 150;
Display *dis = XOpenDisplay (0);
int screen = DefaultScreen (dis);
Window w = XCreateSimpleWindow (dis, RootWindow (dis, screen),
0, 0, 1200, 300, 1,
BlackPixel (dis, screen),
WhitePixel (dis, screen));
XEvent ev;
render_color.red = 0;
render_color.green =0;
render_color.blue = 0;
render_color.alpha = 0xffff;
XftColorAllocValue (dis,
DefaultVisual(dis, screen),
DefaultColormap(dis, screen),
&render_color,
&xft_color);
//font = XftFontOpen(dis, screen,
// XFT_FAMILY, XftTypeString, "charter",
// XFT_SIZE, XftTypeDouble, 20.0,
// NULL);
font = XftFontOpenName(dis,screen,"URW Palladio L:style=Bold Italic"); //it takes a Fontconfig pattern string
draw = XftDrawCreate(dis, w,
DefaultVisual(dis, screen),
DefaultColormap(dis, screen));
XSelectInput (dis, w, ExposureMask);
XMapWindow (dis, w);
for (;;)
{
XNextEvent (dis, &ev);
if (ev.type == Expose)
XftDrawString8(draw, &xft_color, font, x, y, (XftChar8 *) str,
strlen(str));
}
return 0;
}
But i am wondering that how can i add line breaks in the text entered. I tried using "/n" and also tried to make array and used loops but it didn't work.
New line "\n" will not be rendered by Xft. You need to render each line separately with proper offset, depending on font size and desired spacing.
I have modified the ending block of your code with sample text rendered two times on separate lines.
if (ev.type == Expose)
{
int fonth = font->ascent + font->descent;
XftDrawString8(draw, &xft_color, font, x, y, (XftChar8 *) str,
strlen(str));
XftDrawString8(draw, &xft_color, font, x, y+fonth, (XftChar8 *) str,
strlen(str));
}

Pixel manipulation using sdl

I am trying to manipulate pixel using sdl and manage to read them up now. Below is my sample code. When I print I this printf("\npixelvalue is is : %d",MyPixel); I get values like this
11275780
11275776
etc
I know these are not in hex form but how to manipulate say I want to filter just the blue colors out? Secondly after manipulation how to generate the new image?
#include "SDL.h"
int main( int argc, char* argv[] )
{
SDL_Surface *screen, *image;
SDL_Event event;
Uint8 *keys;
int done = 0;
if (SDL_Init(SDL_INIT_VIDEO) == -1)
{
printf("Can't init SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
SDL_WM_SetCaption("sample1", "app.ico");
/* obtain the SDL surfance of the video card */
screen = SDL_SetVideoMode(640, 480, 24, SDL_HWSURFACE);
if (screen == NULL)
{
printf("Can't set video mode: %s\n", SDL_GetError());
exit(1);
}
printf("Loading here");
/* load BMP file */
image = SDL_LoadBMP("testa.bmp");
Uint32* pixels = (Uint32*)image->pixels;
int width = image->w;
int height = image->h;
printf("Widts is : %d",image->w);
for(int iH = 1; iH<=height; iH++)
for(int iW = 1; iW<=width; iW++)
{
printf("\nIh is : %d",iH);
printf("\nIw is : %d",iW);
Uint32* MyPixel = pixels + ( (iH-1) + image->w ) + iW;
printf("\npixelvalue is is : %d",MyPixel);
}
if (image == NULL) {
printf("Can't load image of tux: %s\n", SDL_GetError());
exit(1);
}
/* Blit image to the video surface */
SDL_BlitSurface(image, NULL, screen, NULL);
SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
/* free the image if it is no longer needed */
SDL_FreeSurface(image);
/* process the keyboard event */
while (!done)
{
// Poll input queue, run keyboard loop
while ( SDL_PollEvent(&event) )
{
if ( event.type == SDL_QUIT )
{
done = 1;
break;
}
}
keys = SDL_GetKeyState(NULL);
if (keys[SDLK_q])
{
done = 1;
}
// Release CPU for others
SDL_Delay(100);
}
// Release memeory and Quit SDL
SDL_FreeSurface(screen);
SDL_Quit();
return 0;
}
Use SDL_MapRGB and SDL_MapRGBA to sort colors out. SDL will filter it out for you, based on surface format.
Just like this:
Uint32 rawpixel = getpixel(surface, x, y);
Uint8 red, green, blue;
SDL_GetRGB(rawpixel, surface->format, &red, &green, &blue);
You are printing the value of the pointer MyPixel. To get the value you have to dereference the pointer to the pixel value like this: *MyPixel
Then the printf would look like this:
printf("\npixelvalue is : %d and the address of that pixel is: %p\n",*MyPixel , MyPixel);
Other errors:
Your for loops are incorrect. You should loop from 0 to less than width or height, or else you will read uninitialized memory.
You didn't lock the surface. Although you are only reading the pixels and nothing should go wrong it is still not correct.
Test for correctness if the image pointer comes after you are already using the pointer. Put the test right after the initialization.
If I recall correctly I used sdl_gfx for pixel manipulation.
It also contains function like drawing a circle, oval etc.

How to directly query the camera about image luminance/ Skip compentation in OpenCV

I am developing a program in VS 2010 using OpenCV. I want to measure the luminance of every frame that the computer's camera captures. However, the camera's software stabilizes the luminance after 2-3 frames. Eg, if i put my thumb in front of the camera the first frame's luminance is 2 (scale from 0 to 255), but then while keeping my thumb in front of the camera the luminance becomes 7 and the 20 - it is stabilized there for the next frames. So the camera tries to make too dark pictures brighter and too bright pictures darker.
How can i measure the actual luminance without the camera's interference?
My code is:
#ifdef _CH_
#pragma package <opencv>
#endif
#include "stdafx.h"
#include <highgui.h>
#include "cv.h"
#include <stdio.h>
#include <stdlib.h>
#include "..\utilities.h"
int _tmain(int argc, _TCHAR* argv[])
{
FILE *file;
IplImage *img;
IplImage* grayscale_image;
int c, i, j, Luminance = 0, Pixel_Num = 0;
int Avg_Luminance;
int width_step;
int pixel_step;
// allocate memory for an image
// capture from video device #1
CvCapture* capture;
// create a window to display the images
cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
// position the window
cvMoveWindow("mainWin", 5, 5);
while(1)
{
if(file = fopen("luminance_value.txt", "w+"))
{
// retrieve the captured frame
capture= cvCaptureFromCAM(1);
img=cvQueryFrame(capture);
grayscale_image = cvCreateImage( cvGetSize(img), 8, 1 );
cvConvertImage( img, grayscale_image );
width_step= grayscale_image->widthStep;
pixel_step= grayscale_image->widthStep/grayscale_image->width;
Pixel_Num = grayscale_image->width * grayscale_image->height;
for(i = 0; i < grayscale_image->height; i++)
{
for(j = 0; j < grayscale_image->width; j++)
{
unsigned char* point = GETPIXELPTRMACRO( grayscale_image, j, i, width_step, pixel_step);
Luminance += point[0];
}
}
Avg_Luminance = Luminance / Pixel_Num;
//Avg_Luminance = cvGetCaptureProperty(capture,CV_CAP_PROP_BRIGHTNESS);
//file = fopen("luminance_value.txt", "w+");
fprintf(file, "%d", Avg_Luminance);
fclose(file);
printf("Avg_Luminance = %d\n", Avg_Luminance);
Luminance = 0;
Pixel_Num = 0;
// show the image in the window
cvShowImage("mainWin", grayscale_image );
cvReleaseCapture(&capture);
// wait 10 ms for a key to be pressed
c=cvWaitKey(10000);
// escape key terminates program
if(c == 27)
break;
}
else
{
continue;
}
}
return 0;
}

Writing AVI files in OpenCV

There example on the net and code given in Learn OpenCv,Orielly.
After many attempts the out.avi file is written with 0 bytes.
I wonder where i went wrong.
The following are the code i used...
int main(int argc, char* argv[]) {
CvCapture* input = cvCaptureFromFile(argv[1]);
IplImage* image = cvRetrieveFrame(input);
if (!image) {
printf("Unable to read input");
return 0;
}
CvSize imgSize;
imgSize.width = image->width;
imgSize.height = image->height;
double fps = cvGetCaptureProperty(
input,
CV_CAP_PROP_FPS
);
CvVideoWriter *writer = cvCreateVideoWriter(
"out.avi",
CV_FOURCC('M', 'J', 'P', 'G'),
fps,
imgSize
);
IplImage* colourImage;
//Keep processing frames...
for (;;) {
//Get a frame from the input video.
colourImage = cvQueryFrame(input);
cvWriteFrame(writer, colourImage);
}
cvReleaseVideoWriter(&writer);
cvReleaseCapture(&input);
}
My bet is that cvCreateVideoWriter returns NULL. Just step through it to see if it's true. In that case, the problem is probably with CV_FOURCC(..) which doesnt find the codec and force a return 0;
you can try using -1 instead of CV_FOURCC. There is gonna be a prompt during runtime for you to chose the appropriate codec
When i google this problem i meet an answer: "OpenCV on mac os x don`t support avi write until it will be compiled with a ffmpeg"
For me seem to wrok this solution
http://article.gmane.org/gmane.comp.lib.opencv/16005
You need to provide the full path to
the file with the movie in
cvCreateVideoWriter. I don't know
whether it's only an Mac OS X port
issue, but might be, since
QTNewDataReferenceFromFullPathCFString
from the QT backend is used.
hey This code works in DevC++ try it:
#include<cv.h>
#include<highgui.h>
#include<cvaux.h>
#include<cvcam.h>
#include<cxcore.h>
int main()
{
CvVideoWriter *writer = 0;
int isColor = 1;
int fps = 5; // or 30
int frameW = 1600; //640; // 744 for firewire cameras
int frameH = 1200; //480; // 480 for firewire cameras
//writer=cvCreateVideoWriter("out.avi",CV_FOURCC('P','I','M','1'),
// fps,cvSize(frameW,frameH),isColor);
writer=cvCreateVideoWriter("out.avi",-1,
fps,cvSize(frameW,frameH),isColor);
IplImage* img = 0;
img=cvLoadImage("CapturedFrame_0.jpg");
cvWriteFrame(writer,img); // add the frame to the file
img=cvLoadImage("CapturedFrame_1.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_2.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_3.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_4.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_5.jpg");
cvWriteFrame(writer,img);
cvReleaseVideoWriter(&writer);
return 0;
}
I compiled it and ran it, works fine.
(I did not see above whether you got your answer or not .. but for this particular thing I worked very hard earlier and suddenly I just did it, from some code snippets.)
It's a codec issue. Try out all the possible codecs (option -1 in cvCreateVideo). In my case Microsoft Video 1 worked well.
Maybe you could try inserting a printf("Frame found\n") inside the for(;;) to see if it is actually capturing frames. Or even better:
if(colourImage == NULL) {
printf("Warning - got NULL colourImage\n");
continue;
}
cvNamedWindow( "test", 1);
cvShowImage( "test", colourImage );
cvWaitKey( 0 );
cvDestroyWindow( "test" );
Then see if you get any windows, and if they contain the right contents.
This code worked fine:
cv.h
highgui.h
cvaux.h
cvcam.h
cxcore.h
int main(){
CvVideoWriter *writer = 0;
int isColor = 1;
int fps = 5; // or 30
IplImage* img = 0;
img=cvLoadImage("animTest_1.bmp");
int frameW = img->width; //640; // 744 for firewire cameras
int frameH = img->height; //480; // 480 for firewire cameras
writer=cvCreateVideoWriter("out.avi",-1,
fps,cvSize(frameW,frameH),1);
cvWriteFrame(writer, img); // add the frame to the file
char *FirstFile,fF[20]="",*fileNoStr,fns[4]="";
fileNoStr=fns;
for(int fileNo;fileNo<100;fileNo++){
FirstFile=fF;
itoa(fileNo,fileNoStr,10);
FirstFile=strcat ( FirstFile,"animTest_");
FirstFile=strcat ( FirstFile,fileNoStr);
FirstFile=strcat ( FirstFile,".bmp");
printf(" \n%s .",FirstFile);
img=cvLoadImage(FirstFile);
cvWriteFrame(writer, img);
}
cvReleaseVideoWriter(&writer);
return 0;
}
I think the problem you're encountering is that your "for" loop never ends; therefore, cvReleaseVideoWriter(&writer); and cvReleaseCapture(&input); never get called. Try something like for(int i=0; i<200; i++) and see if you end up with a working video.
Often video is written to a temporary files before being finalized on disk. If your file isn't finalized, there won't be anything to see.
Hope that helps.

Resources