DirectFB data from memory buffer

9.1k views Asked by At

I need a very fast way of displaying a data buffer to screen. I first tried accessing the linux framebuffer and that proved to be quite good. Then I learned about directFB and I liked the extra features it provides (like fast memcpy, resizing the images on the fly, no need for extra code etc.). But then I hit a snag - all examples are for images that are loaded from files. As far as I can tell there are no examples/tutorials for its 'DataBuffer' type. After peering through the documentation and source code I've managed to compile something that goes like this:

DFBSurfaceDescription sdsc;
DFBDataBufferDescription ddsc;
DFBDataBufferDescriptionFlags ddscf = (DFBDataBufferDescriptionFlags)DBDESC_MEMORY;
IDirectFBDataBuffer *dbuffer;
IDirectFBImageProvider *provider;

ddsc.flags = ddscf;
ddsc.file = NULL;
ddsc.memory.data = m_z;
ddsc.memory.length = 640*480;

DFBCHECK (DirectFBInit (&argc, &argv));
DFBCHECK (DirectFBCreate (&dfb));
DFBCHECK (dfb->SetCooperativeLevel (dfb, DFSCL_FULLSCREEN));
sdsc.flags = DSDESC_CAPS;
sdsc.caps  = (DFBSurfaceCapabilities)(DSCAPS_PRIMARY | DSCAPS_FLIPPING);
DFBCHECK (dfb->CreateSurface( dfb, &sdsc, &primary ));
DFBCHECK (primary->GetSize (primary, &screen_width, &screen_height));

DFBCHECK (dfb->CreateDataBuffer(dfb, &ddsc, &dbuffer));
DFBCHECK (dbuffer->CreateImageProvider(dbuffer, &provider));
DFBCHECK (provider->GetSurfaceDescription (provider, &sdsc));

DFBCHECK (dfb->CreateSurface( dfb, &sdsc, &fbwindow ));
DFBCHECK (provider->RenderTo (provider, fbwindow, NULL));
provider->Release (provider);

So basically I'm creating a DataBuffer from the DFB, then an ImageProvider from the DataBuffer and set it to render on a surface. When I run it however, it throws the error:

(#) DirectFBError [dbuffer->CreateImageProvider(dbuffer, &provider)]: No (suitable) implementation found!

Is the method really not implemented? I'm currently using DirectFB 1.4, from the API documentation the function should be there. That being said, does anyone know how to get a buffer (char*640*480*4 RGBA) from memory to render to the framebuffer using DirectFB?

Thanks.

2

There are 2 answers

0
MartinP On BEST ANSWER

Maybe a bit late to help you, but for the benefit of anyone else trying this, here is an answer.

It is actually more simple than you think (with one gotcha) - I am doing exactly what you want, using DirectFb 1.4.11.

Once you have the primary suface, don't bother with the DataBuffer. Create another surface, using the DSDESC_PREALLOCATED flasg and your buffer as the preallocated data. Then Blit() the data from your new surface onto the primary surface and Flip() the primary surface onto the screen. The one gotcha is that your data needs to be in a format that DirectFB understands: 32 bit RGBA is not one of them, but 32 bit ARGB is - I had to parse my buffer to swap the bytes around.

Example code:

  dsc.width = screen_width;
  dsc.height = screen_height;
  dsc.flags = DSDESC_HEIGHT | DSDESC_WIDTH | DSDESC_PREALLOCATED | DSDESC_PIXELFORMAT;
  dsc.caps = DSCAPS_NONE;
  dsc.pixelformat = DSPF_ARGB;
  dsc.preallocated[0].data = buffer;      // Buffer is your data
  dsc.preallocated[0].pitch = dsc.width*4;
  dsc.preallocated[1].data = NULL;
  dsc.preallocated[1].pitch = 0;

  DFBCHECK (dfb->CreateSurface( dfb, &dsc, &imageSurface ));
  DFBCHECK (primary->Blit(primary, imageSurface, NULL, 0, 0));
  DFBCHECK (primary->Flip(primary, NULL, DSFLIP_ONSYNC));

If your buffer is not the same size/shape as your screen, you can use StretchBlit() instead to resize it.

I hope this helps.

2
stacksake On

The answer above from MartinP is good, but only works if the image is not compressed. I found this topic because I wanted to load and decode/uncompress a png/jpeg image directly from memory.

There is hardly any useful info on this and I have been struggling with it myself but found out how to do it. Although this is an old question, it might help others who try to accomplish the same:

// Variables
DFBDataBufferDescription ddsc;
DFBSurfaceDescription sdsc;
IDirectFBDataBuffer *buffer;
IDirectFBImageProvider *image_provider;

// The surface that will contain the rendered image
IDirectFBSurface *surface;                      

// create a data buffer for memory
ddsc.flags = DBDESC_MEMORY;
ddsc.memory.data = data;
ddsc.memory.length = dataLength;
DFBCHECK(directFB->CreateDataBuffer(directFB, &ddsc, &buffer));

// Create the image provider, surface description and surface itself
DFBCHECK(buffer->CreateImageProvider(buffer, &image_provider));
DFBCHECK(image_provider->GetSurfaceDescription(image_provider, &sdsc));
DFBCHECK(directFB->CreateSurface(directFB, &sdsc, &surface ));

// Now render the image onto the surface
DFBCHECK(image_provider->RenderTo(image_provider, surface, NULL));

// Release 
image_provider->Release(image_provider);
buffer->Release(buffer);

The data variable is a pointer to an array of unsigned char containing the image (hint: you can create such an array with 'xxd -i image.jpg > image.h'). datalength is an unsigned int with the size of the array. The created surface can be blit to the screen, or perhaps you can 'renderto' the display-surface at once.