Load Screenshots from FlightGear
WORK IN PROGRESS
This page describes the steps required to obtain screenshots from FlightGear into the memory of PaparazziUAV. First the required functions are presented and described. Than the exact details about running the applications are mentioned. This has been tested with PaparazziUAV v5.10 and FlightGear 2017.1.2.
Required modules
FlightGear can be run with an HTTP server which can be used to obtain screenshots of the current scenery in FlightGear. There is a limit to the rate at which these screenshots (I only tested this with approximately 1 fps) can be obtained thus it cannot be used to simulate high frame rate vision. One requires the libcurl library to download the image from the HTTP server into memory. Following this, the jpeg image data needs to be decompressed to obtain the pixel values using libjpeg. All of this code have been obtained from the reference material of the corresponding libraries and required modifications made for the specific implementation.
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
/* Helper function for curl2mem. Handles the writing of the data from
* the source HTTP into the memory. Needs to follow format provided by
* libcurl.
*/
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
if(mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
void curl2mem(struct MemoryStruct *chunk)
{
/* Uses libcurl functions to load the screenshot from the FlightGear HTTP
* server into the programs memory
*/
CURL *curl_handle;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://localhost:1234/screenshot");
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
// curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)chunk);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
/* get it! */
res = curl_easy_perform(curl_handle);
/* check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
}
uint8_t get_bmp(unsigned char *jpg_buffer, unsigned long jpg_size, struct BmpStruct *bmp)
{
// // INTIALIZE
uint8_t rc;
// Variables for the decompressor itself
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
// Variables for the output buffer, and how long each row is
unsigned long bmp_size;
unsigned char *bmp_buffer;
uint16_t row_stride, width, height, pixel_size;
// holds the output bmp and its metadata
// // SETUP AND CHECK
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo, jpg_buffer, jpg_size);
// skipping error check for now. file should be JPEG
rc = jpeg_read_header(&cinfo, TRUE);
if (rc != 1) {
printf("File to get_bmp() not JPEG");
return 1;
}
jpeg_start_decompress(&cinfo);
width = cinfo.output_width;
height = cinfo.output_height;
pixel_size = cinfo.output_components;
bmp_size = width * height * pixel_size;
bmp_buffer = (unsigned char*) malloc(bmp_size);
// The row_stride is the total number of bytes it takes to store an
// entire scanline (row).
row_stride = width * pixel_size;
// // READ THE LINES
while (cinfo.output_scanline < cinfo.output_height) {
unsigned char *buffer_array[1];
buffer_array[0] = bmp_buffer + (cinfo.output_scanline) * row_stride;
jpeg_read_scanlines(&cinfo, buffer_array, 1);
}
bmp->buffer = bmp_buffer;
bmp->size = bmp_size;
bmp->width = width;
bmp->height = height;
bmp->pixel_size = pixel_size;
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return 0;
}