EBC Exercise 21 Running Audio and Video

From eLinux.org
Revision as of 12:45, 9 September 2011 by Yoder (Talk | contribs) (Part b - Audio and Video - same process: Initial page)

Jump to: navigation, search

Welcome to Audio and Video labs Parts a and b. In Part a, you will combine the audio loop-thru application with the video loop-thru application by running them from the Linux Bash terminal.

In Part b, you’ll programmatically combine these two applications, along with the video OSD application into a single (multi-threaded) application that handles all three data streams – audio, video, and OSD.

Part a – Run Audio and Video in Separate Processes

Build Audio Executable

  • Change to the lab06c_audio_loopthru directory from before.
  • Build the application using “make debug”.

This will build the debug version. Note, if you have problems building at this step, try cleaning, then building:

$ make clean
$ make debug
  • Use the Linux “mv” command to change the name of the app_DEBUG.Beagle application to app_AUDIO.

Build Video Executable

  • Change to the lab07d_video_loopthru directory then build the application.
$ make install

Run Audio and Video in Separate Processes

  • Execute the app_AUDIO application using the following command:
$ ./app_AUDIO &

Note, the trailing ampersand (&) in this command indicates that the application is to be run as a separate process. (In this case, our audio app will run in the terminal background, meaning that the terminal will remain open to new commands even while the application is executing.)

  • Execute the videoThru_DEBUG.Beagle application (the video loop-thru application) using the following command:
$ ./app_DEBUG.xv5T

You should now have both audio loop-thru and video loop-thru running concurrently on the board. They are running as concurrent, but separate, processes. In Part b we will use pthreads to run the audio and video loop-thru in parallel threads within the same process or application.

  • Halt the video loop-thru (running in the terminal foreground) by pressing Ctrl-C.
  • Use the following command to determine the process jobs number of the audio loop-thru, which is running in the terminal background:
$ jobs
  • Halt the audio loop-thru using the kill command and job number from the last step.
$ kill %1

Part a Question

  • Which scheduling policy is being used by each of the audio and video program processes(i.e. how is the thread within each process being scheduled)?

Part b - Audio and Video - same process

In this lab, we will combine lab06c_audio_loopthru, and lab07d_video_loopthru into a single, multi-threaded application.

File Management

  • Change to the VideoThru directory.
$ cd ..
  • List the lab08b_audio_video directory.

Two previously unused files have been provided for you (make sure they’re #included):

$ ls lab08b_audio_video
  • Examine thread.c in gedit or similar editor.

This file contains one function, launch_pthread(), which is a “wrapper” function that implements thread creation procedure which was reviewed in the Chapter 8 discussion. (That is, rather than making you write all this code from scratch, we chose to wrap it up for you into a single call to launch a pthread.)

Our pthread launch function takes five parameters:

pthread_t *hThread_byref
This is a pointer to a handle (i.e. a handle passed by reference) which is used as a return value. The memory location pointed to by hThread_byref will be updated with a pthread handle.
int type
Integer specifying that the created thread will either be REALTIME or

TIMESLICE as per #define in thread.h

int priority
The priority assigned to the thread. (It’s only used for thread type = REALTIME)
void *(*thread_fxn)(void *env)
A pointer to the function that is the entry point for the created thread. This function takes a single pointer as an argument (although the pointer may be a pointer to a structure, effectively allowing multiple arguments.)
void *env
The pointer which will be passed as the argument to thread_fxn() as per the above

Hint: It is important to do the following three steps in this exact order. Otherwise, some of the following directions (i.e. editing main.c) will be incorrect!

Don’t worry about overwriting any files.

  • Copy the full contents of lab07a_osd_setup into lab08b_audio_video.
$ cp –R –f lab07a_osd_setup/* lab08b_audio_video
  • Copy the full contents of lab06c_audio_loop-thru into lab08b_audio_video.
$ cp –R –f lab06c_audio_loopthru/* lab08b_audio_video
  • Copy the full contents of lab07d_video_loopthru into lab08b_audio_video.
$ cp –R –f lab07d_video_loopthru/* lab08b_audio_video

Edit main.c

  • Open lab08b_audio_video/main.c in a text editor.
  • Fill in the missing .h files, as well as the missing _env variables for the audio and osd threads to main.c.

Your main.c file should contain the following:

video_env (which is the video_thread_env variable)

You need to add the following to main.c. (Refer to lab06c for this code.)

audio_env (which is the audio_thread_env variable)

as well as (Refer to lab07a for this code.)

osd_env (which is the audio_thread_env variable)
  • Make sure that video, audio and osd while loops exit when Ctrl-C is pressed.

Recall that the signal_handler function is run whenever Ctrl-C is pressed. This signal handler sets the quit field in both of these global structures to true, signaling to the thread that it should proceed to its cleanup phase and then exit.

How do the threads know where to look for these variables? These environment structures are passed as the argument to the thread. Within the thread function, the main while loop tests on the appropriate quit variable. When the quit variable becomes true, execution drops out of the while loop and into the final (cleanup) phase of the function.

Currently the signal_handler() function sets video_env.quit to one (true). We need to add similar statements for the audio_env.quit and osd_env.quit to the signal handler below.

void signal_handler( int sig )
DBG( "Ctrl-C pressed, cleaning up and exiting..\n" );
video_env.quit = 1;
  • To make debugging easier, put a one-second delay in between *.quit=1 statements. Since we’re exiting three pthreads back-to-back, you might find that their debug messages become interleaved – which can make debugging more difficult. To this end, when building with our “debug” profile, we could delay the start of the second quit by using a Linux time function.

Insert the following code between each *.quit=1 call to cause Linux to sleep for one second. This should make debugging easier.

#ifdef _DEBUG_

Don’t forget to include the proper header file for the sleep() function: unistd.h

  • Include the <pthread.h> header file that prototypes the launch_pthread() function.

This is the header file for the code you examined a few steps above.

  • Declare three pthread handles and three return pointers needed to manage our new threads (audio, video, osd).

At the top of main(), add three pthread handles (of type pthread_t) named audioThread, osdThread and videoThread. Handles are used to refer to instantiated objects; the handle value will be set during pthread_create() in step 22, then used again later to refer to that pthread instance.

Also, we want to add three void pointers: one named audioThreadReturn, one named osdThreadReturn and one named videoThreadReturn. The return pointers will be used when “joining” (i.e. exiting) each thread in step 25; they will allow you to interrogate the status after an exit.

It should end up looking like:

pthread_t audioThread, osdThread, videoThread;
void *audioThreadReturn, *osdThreadReturn, *videoThreadReturn;