Pi Firmware: Switched screen capture to LodePNG

Change-Id: I622da201a530fc14d827f1357ba7924609a3f51c
pull/45/head^2
David Banks 2019-03-11 13:00:36 +00:00
rodzic 563e199967
commit 562fcf8f4d
4 zmienionych plików z 8052 dodań i 50 usunięć

Wyświetl plik

@ -105,6 +105,9 @@ file( GLOB core_files
# File system functions
filesystem.c
filesystem.h
# LodePNG Library
lodepng.c
lodepng.h
# Tiny PNG Output Library
tiny_png_out.c
tiny_png_out.h

Wyświetl plik

@ -3,19 +3,140 @@
#include <string.h>
#include "logging.h"
#include "fatfs/ff.h"
#include "tiny_png_out.h"
#include "filesystem.h"
#define USE_LODEPNG
#ifdef USE_LODEPNG
#include "lodepng.h"
#else
#include "tiny_png_out.h"
#endif
#define CAPTURE_BASE "capture"
static FATFS fsObject;
static int capture_id = -1;
#ifdef USE_LODEPNG
// TODO: Using LCT_PALETTE colour type we can almost point LodePNG directly
// at the frame buffer. The only thing stopping us is the pitch != width.
// Would be interesting to experiment using this.
static uint8_t rgb8_buffer[8 * 1024 * 1024] __attribute__((aligned(0x4000)));
static int generate_png(capture_info_t *capinfo, uint8_t **png, unsigned int *png_len ) {
// TODO: Take account of current palette
uint8_t *pp = rgb8_buffer;
for (int y = 0; y < capinfo->height; y++) {
uint8_t *fp = capinfo->fb + capinfo->pitch * y;
if (capinfo->bpp == 8) {
for (int x = 0; x < capinfo->width; x++) {
uint8_t single_pixel = *fp++;
*pp++ = (single_pixel & 0x01) ? 255 : 0;
*pp++ = (single_pixel & 0x02) ? 255 : 0;
*pp++ = (single_pixel & 0x04) ? 255 : 0;
}
} else {
for (int x = 0; x < capinfo->width << 1; x++) {
uint8_t double_pixel = *fp++;
*pp++ = (double_pixel & 0x10) ? 255 : 0;
*pp++ = (double_pixel & 0x20) ? 255 : 0;
*pp++ = (double_pixel & 0x40) ? 255 : 0;
*pp++ = (double_pixel & 0x01) ? 255 : 0;
*pp++ = (double_pixel & 0x02) ? 255 : 0;
*pp++ = (double_pixel & 0x04) ? 255 : 0;
}
}
}
unsigned result = lodepng_encode_memory(png, png_len, rgb8_buffer, capinfo->width, capinfo->height, LCT_RGB, 8);
if (result) {
log_warn("lodepng_encode32 failed (result = %d)", result);
return 1;
}
return 0;
}
static void free_png(uint8_t *png) {
if (png) {
free(png);
}
}
#else
// TODO: Fix hard-coded max H resolution of 4096
static uint8_t pixels[3 * 4096];
// TODO: Fix hard-coded buffer size if 8MB
static uint8_t png_buffer[8 * 1024 * 1024] __attribute__((aligned(32)));
static uint8_t png_buffer[8 * 1024 * 1024] __attribute__((aligned(0x4000)));
static int generate_png(capture_info_t *capinfo, uint8_t **png, unsigned int *png_len ) {
enum TinyPngOut_Status result;
struct TinyPngOut state;
*png = NULL;
*png_len = 0;
result = TinyPngOut_init(&state, capinfo->width, capinfo->height, png_buffer);
if (result != TINYPNGOUT_OK) {
log_warn("TinyPngOut_init failed (result = %d)", result);
return 1;
} else {
// TODO: Take account of current palette
for (int y = 0; y < capinfo->height; y++) {
uint8_t *fp = capinfo->fb + capinfo->pitch * y;
uint8_t *pp = pixels;
if (capinfo->bpp == 8) {
for (int x = 0; x < capinfo->width; x++) {
uint8_t single_pixel = *fp++;
*pp++ = (single_pixel & 0x01) ? 255 : 0;
*pp++ = (single_pixel & 0x02) ? 255 : 0;
*pp++ = (single_pixel & 0x04) ? 255 : 0;
}
} else {
for (int x = 0; x < capinfo->width << 1; x++) {
uint8_t double_pixel = *fp++;
*pp++ = (double_pixel & 0x10) ? 255 : 0;
*pp++ = (double_pixel & 0x20) ? 255 : 0;
*pp++ = (double_pixel & 0x40) ? 255 : 0;
*pp++ = (double_pixel & 0x01) ? 255 : 0;
*pp++ = (double_pixel & 0x02) ? 255 : 0;
*pp++ = (double_pixel & 0x04) ? 255 : 0;
}
}
result = TinyPngOut_write(&state, pixels, capinfo->width);
if (result != TINYPNGOUT_OK) {
log_warn("TinyPngOut_write failed (result = %d)", result);
return 1;
}
}
}
*png = png_buffer;
*png_len = state.output_len;
return 0;
}
static void free_png(uint8_t *png) {
}
#endif
static FATFS fsObject;
static int capture_id = -1;
static void initialize_capture_id() {
FRESULT result;
@ -89,10 +210,10 @@ void close_filesystem() {
void capture_screenshot(capture_info_t *capinfo) {
FRESULT result;
enum TinyPngOut_Status tiny_result;
struct TinyPngOut tiny_state;
char path[100];
FIL file;
uint8_t *png;
unsigned int png_len;
init_filesystem();
@ -109,57 +230,24 @@ void capture_screenshot(capture_info_t *capinfo) {
}
capture_id++;
tiny_result = TinyPngOut_init(&tiny_state, capinfo->width, capinfo->height, png_buffer);
if (generate_png(capinfo, &png, &png_len)) {
if (tiny_result != TINYPNGOUT_OK) {
log_warn("TinyPngOut_init failed (result = %d)", tiny_result);
log_warn("generate_png failed, not writing data");
} else {
// TODO: Take account of current palette
log_info("Screen capture PNG length = %d, writing data...", png_len);
for (int y = 0; y < capinfo->height; y++) {
uint8_t *fp = capinfo->fb + capinfo->pitch * y;
uint8_t *pp = pixels;
if (capinfo->bpp == 8) {
for (int x = 0; x < capinfo->width; x++) {
uint8_t single_pixel = *fp++;
*pp++ = (single_pixel & 0x01) ? 255 : 0;
*pp++ = (single_pixel & 0x02) ? 255 : 0;
*pp++ = (single_pixel & 0x04) ? 255 : 0;
}
} else {
for (int x = 0; x < capinfo->width << 1; x++) {
uint8_t double_pixel = *fp++;
*pp++ = (double_pixel & 0x10) ? 255 : 0;
*pp++ = (double_pixel & 0x20) ? 255 : 0;
*pp++ = (double_pixel & 0x40) ? 255 : 0;
*pp++ = (double_pixel & 0x01) ? 255 : 0;
*pp++ = (double_pixel & 0x02) ? 255 : 0;
*pp++ = (double_pixel & 0x04) ? 255 : 0;
}
}
tiny_result = TinyPngOut_write(&tiny_state, pixels, capinfo->width);
if (tiny_result != TINYPNGOUT_OK) {
log_warn("TinyPngOut_write failed (result = %d)", tiny_result);
break;
}
UINT num_written = 0;
result = f_write(&file, png, png_len, &num_written);
if (result != FR_OK) {
log_warn("Failed to write capture file %s (result = %d)", path, result);
} else if (num_written != png_len) {
log_warn("Capture file %s incomplete (%d < %d bytes)", path, num_written, png_len);
}
}
int png_len = tiny_state.output_len;
log_info("Screen capture PNG length = %d, writing data...", png_len);
UINT num_written = 0;
result = f_write(&file, png_buffer, png_len, &num_written);
if (result != FR_OK) {
log_warn("Failed to write capture file %s (result = %d)", path, result);
} else if (num_written != png_len) {
log_warn("Capture file %s incomplete (%d < %d bytes)", path, num_written, png_len);
}
free_png(png);
result = f_close(&file);
if (result != FR_OK) {

5992
src/lodepng.c 100644

Plik diff jest za duży Load Diff

1919
src/lodepng.h 100644

Plik diff jest za duży Load Diff