world leader in high performance signal processing
Trace: » jpegview

ADSP-BF548 EZ-KIT Quick Start: Peripheral Demos: jpegview

www.analog.com_static_imported-files_images_product_descriptions_680755565image1a.jpg

What is jpegview

An application that uses SDL_image to load a jpeg, resizes it to fit the LCD and then displays it on the LCD until the program is terminated.

Download jpegview

The demo comes with the customised Ubuntu ISO and can be found in the folder /home/Blackfin/demos. Alternatively it is already installed on the demo uClinux image (demo-uclinux.img) that you can get on ADSP-BF548 EZ-KIT Quick Start: Booting uClinux.

If you just want to download the demos on their own and get their source code you can download the compressed archive (demos-R1.tar.gz) here bf548-quick-start .

How to run the jpegview program

  • Change directory to /demos/lcd

    root:/> cd /demos/lcd
  • Make sure SDL knows that there is no mouse available otherwise it won't run

    root:/> export SDL_NOMOUSE=1

    Note: You only need to do this once per uClinux boot. If you want your program to make use of the touch screen, do not run this environment variable and instead run the commands found in the touchscreen demos.

  • Run jpegview with provided beach jpeg file (beach.jpg)

    root:/> ./jpegview beach.jpg
    Loading beach.jpg...
    Displayed. Interrupt to exit
  • Exit (Ctrl + C)

How the jpegview demo works

Required header files

#include <stdio.h>
#include <SDL.h>
#include <SDL_rotozoom.h>
#include <SDL_image.h>
#include <SDL_syswm.h>

These libraries as you can see are for SDL_image to load and display images. SDL_rotozoom is actually a part of SDL_gfx and is used for resizing SDL surfaces (in this case, resizing the jpeg). stdio is just for loading the jpeg file itself.

Input argument check

// Check for program arguments
if (argc <= 1) 
{
  printf("Please specify an image file.\nUsage: jpegview [image_file]\n");
  exit(0);
}

This section of code will look at the command line arguments invoked and make sure that an argument was provided to indicate the jpeg file to open.

Initializing the video subsystem

if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
  fprintf(stderr, "Error: Unable to init SDL: %s\n", SDL_GetError());
  exit(1);
}
atexit(SDL_Quit);

screen = SDL_SetVideoMode(width, height, depth, SDL_DOUBLEBUF);
if (screen == NULL)
{
  fprintf(stderr, "Error: Unable to grab screen\n");
  SDL_Quit();
  exit(1);
}

This section of code will initialise the video subsystem of SDL so that SDL knows it will have a graphics buffer to write to. If it fails, it will abort the program. The atexit call is added so that when the program closes, SDL will clean itself up.

It also grabs the screen to write to by making a call to SDL_SetVideoMode and provides the screen details, note that width, height and depth are provided at the start of this program and are set to the LCD screens actual dimensions so this creates a full screen window. If this fails, the program will abort.

This section will be quite common for any SDL program using the LCD and the SDL_Init call might have to OR other subsystems as well if you're using things like audio.

Initializing the JPEG image support library

if (IMG_Init(IMG_INIT_JPG) < 0)
{
  fprintf(stderr, "Error: Failed to initiate IMG_INIT_JPG support! %s\n", IMG_GetError());
  SDL_Quit();
  exit(1);
}
atexit(IMG_Quit);
SDL_ShowCursor (SDL_DISABLE);

This section will get the SDL_image library to initiate its jpeg support. If it fails, it will abort the program. The atexit call is added so that when the program closes, SDL_image will clean itself up.

The SDL_ShowCursor call will hide the mouse cursor from displaying in the program. Simply remove this call and a mouse cursor will appear, if you are making a touch screen program then this cursor can be moved via touch controls. You could also add the mice drivers into uClinux and add a usb mouse to use it.

Loading an image onto a surface

file_buffer = SDL_RWFromFile(argv[1], "rb");
if (file_buffer == NULL)
{
  fprintf(stderr, "Error: SDL_RWFromFile failed! Check if file accessible.\n");
  IMG_Quit();
  SDL_Quit();
  exit(1);
}

image_surface = IMG_LoadJPG_RW(file_buffer);

if (!image_surface)
{
  fprintf(stderr, "Error: IMG_LoadJPG_RW reports %s\n", IMG_GetError());
  IMG_Quit();
  SDL_Quit();
  exit(1);
}

This section will open the image file designated in the command line argument and write it to an SDL buffer using SDL_RWFromFile. If it fails, the program aborts.

If the file buffer is loaded, then SDL_image will convert that to a generic image surface for use in SDL. If that fails, it will abort the program.

Resizing image to stretch onto BF548-EZKIT LCD

resized_surface = zoomSurface(image_surface, (width / (float) image_surface->w), (height / (float) image_surface->h), SMOOTHING_OFF);

SDL_FreeSurface(image_surface);

This next section uses SDL_gfx's rotozoom functions to resize an SDL surface. Since we have already loaded the image as a surface, we can resize that surface by a scaling factor to match the LCD dimensions. This involves basic ratios. When it is done, the original surface is freed up and the new surface is carried on.

Displaying surface on LCD

r.x = (Sint16) 0;
r.y = (Sint16) 0;
r.w = (Uint16) resized_surface->w;
r.h = (Uint16) resized_surface->h;
SDL_BlitSurface(resized_surface, NULL, screen, &r);
SDL_Flip(screen);

printf("Displayed. Interrupt to exit\n");

Finally, the resized surface is written to the screen.

Infinite user input loop

memset(&input_event, 0, sizeof(input_event));
while (running == 0)
{
  if (SDL_PollEvent(&input_event))
  {
    if (input_event.type == SDL_QUIT)
    {
      running = 1;
    }
    else if (input_event.type == SDL_KEYDOWN)
    {
      running = 1;
    }
  }
}

This section is common in all SDL programs and it is a loop that will continuously check for any program input. This one is looking for either an SDL_Quit call (from program termination) or any key presses (from the keypad or rotary) to perform an exit.

Exiting

IMG_Quit();
SDL_Quit();
return 0;

This section just does some basic clean up and exits the program.

Compiling jpegview

First make sure that your kernel has the libraries libSDL, SDL_image, SDL_gfx and tslib enabled.

Secondly, make sure your vendor staging install is complete (ADSP-BF548 EZ-KIT Quick Start: Compiling uClinux).

root:/> make vendor_staging_install

Run the following compile command in the same directory as the source code:

root:/> bfin-linux-uclibc-gcc -O2 \
$(~/Blackfin/blackfin-linux-dist/staging/usr/bin/sdl-config --cflags) \
$(~/Blackfin/blackfin-linux-dist/staging/usr/bin/sdl-config --libs) \ 
-lSDL_image -lSDL_gfx \ 
jpegview.c -o jpegview

What this compile command is doing is it is calling the uclibc cross compiler that is set up from the Blackfin toolchains to compile our application.

The calls to sdl-config are a special case for SDL because SDL places its header & library files in non-root locations so this will load them properly.

The parameters prefixed with -l are to indicate we need to load that library, so in this case the libraries SDL_image and SDL_gfx are loaded. Without these, our program would not have access to the required functions.

The final parameters match up to standard gcc compiling, jpegview.c is the source file while -o jpegview indicates the output file is jpegview.

A standard make file is accompanies this demo and you can run that by simply calling

root:/> make jpegview

Further Reading

SDL_image

SDL_image is a popular SDL image handling api, and its documentation is located at http://www.libsdl.org/projects/SDL_image/

There are other ways of performing basic image display and once again you can look at DirectFB or even writing directly to the frame buffer. They are more complex but if you're building an application that might for example take jpeg data from a camera and is performing some digital signal processing, be more efficient.

SDL_gfx

SDL_gfx is a popular SDL primitives drawing api, and its documentation is located at http://www.ferzkopp.net/joomla/content/view/19/14/

It contains many SDL support functions and in this case was used for its interpolating rotozoomer functions to resize the SDL surface displaying the jpeg. The components of SDL_gfx you can use include

  • Graphic Primitives (SDL_gfxPrimitves.h)
  • Rotozoomer (SDL_rotozoom.h)
  • Framerate control (SDL_framerate.h)
  • MMX image filters (SDL_imageFilter.h)
  • Custom Blit functions (SDL_gfxBlitFunc.h)

LCD Notes

The LCD on the BF548 EZ-KIT is a 24bit lcd (8bit blue, 8bit green, 8bit red). This means some programs hard coded for the frame buffer do not work, for example pngview. If you run pngview and it appears wonky on the BF548 that is because it was made for the BF537 and a 16bit LCD. Since it does not write enough data to fill a pixel and will encode for rgb and not bgr, it will be interpreted wrongly, so be aware of this when working with programs that write directly to the frame buffer.

If the colour on the LCD screen appears wonky, this may be due to the LCD screen settings defined by SW17. These switches can set the bitrate of the LCD and if set differently than to what the program expecs will lead to a bit of mayham. Check the development environment page of this guide to make sure it is set to the default 24bit.

Information on the LCD driver for the BF548 EZ-KIT can be found here Linux framebuffer driver for ADSP-BF54x