Add BGR24 saving mode.

This commit is contained in:
Themaister 2013-01-19 02:13:02 +01:00
parent 26e0c3b06d
commit 291a0360a2
6 changed files with 77 additions and 95 deletions

View File

@ -278,11 +278,6 @@ ifeq ($(HAVE_ZLIB), 1)
DEFINES += $(ZLIB_CFLAGS)
endif
ifeq ($(HAVE_LIBPNG), 1)
LIBS += $(LIBPNG_LIBS)
DEFINES += $(LIBPNG_CFLAGS)
endif
ifeq ($(HAVE_FFMPEG), 1)
OBJ += record/ffemu.o
LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS)

View File

@ -3,7 +3,7 @@ TARGET := rpng
SOURCES := $(wildcard *.c)
OBJS := $(SOURCES:.c=.o)
CFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB
CFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB -DHAVE_ZLIB_DEFLATE
all: $(TARGET)

View File

@ -500,7 +500,7 @@ static bool png_write_iend(FILE *file)
return true;
}
static void copy_rgba_line(uint8_t *dst, const uint32_t *src, unsigned width)
static void copy_argb_line(uint8_t *dst, const uint32_t *src, unsigned width)
{
for (unsigned i = 0; i < width; i++)
{
@ -512,6 +512,16 @@ static void copy_rgba_line(uint8_t *dst, const uint32_t *src, unsigned width)
}
}
static void copy_bgr24_line(uint8_t *dst, const uint8_t *src, unsigned width)
{
for (unsigned i = 0; i < width; i++, dst += 3, src += 3)
{
dst[2] = src[0];
dst[1] = src[1];
dst[0] = src[2];
}
}
static unsigned count_zeroes(const uint8_t *data, size_t size)
{
unsigned cnt = 0;
@ -566,8 +576,8 @@ static unsigned filter_paeth(uint8_t *target, const uint8_t *line, const uint8_t
return count_zeroes(target, width);
}
bool rpng_save_image_argb(const char *path, const uint32_t *data,
unsigned width, unsigned height, unsigned pitch)
static bool rpng_save_image(const char *path, const uint8_t *data,
unsigned width, unsigned height, unsigned pitch, unsigned bpp)
{
bool ret = true;
struct png_ihdr ihdr = {0};
@ -582,7 +592,6 @@ bool rpng_save_image_argb(const char *path, const uint32_t *data,
uint8_t *paeth_filtered = NULL;
uint8_t *prev_encoded = NULL;
uint8_t *encode_target = NULL;
unsigned bpp = sizeof(uint32_t);
z_stream stream = {0};
@ -596,11 +605,11 @@ bool rpng_save_image_argb(const char *path, const uint32_t *data,
ihdr.width = width;
ihdr.height = height;
ihdr.depth = 8;
ihdr.color_type = 6; // RGBA
ihdr.color_type = bpp == sizeof(uint32_t) ? 6 : 2; // RGBA or RGB
if (!png_write_ihdr(file, &ihdr))
GOTO_END_ERROR();
encode_buf_size = (width * sizeof(uint32_t) + 1) * height;
encode_buf_size = (width * bpp + 1) * height;
encode_buf = (uint8_t*)malloc(encode_buf_size);
if (!encode_buf)
GOTO_END_ERROR();
@ -619,9 +628,12 @@ bool rpng_save_image_argb(const char *path, const uint32_t *data,
encode_target = encode_buf;
for (unsigned h = 0; h < height;
h++, encode_target += width * bpp, data += pitch >> 2)
h++, encode_target += width * bpp, data += pitch)
{
copy_rgba_line(rgba_line, data, width);
if (bpp == sizeof(uint32_t))
copy_argb_line(rgba_line, (const uint32_t*)data, width);
else
copy_bgr24_line(rgba_line, data, width);
// Try every filtering method, and choose the method
// which has most entries as zero.
@ -706,5 +718,18 @@ end:
free(paeth_filtered);
return ret;
}
bool rpng_save_image_argb(const char *path, const uint32_t *data,
unsigned width, unsigned height, unsigned pitch)
{
return rpng_save_image(path, (const uint8_t*)data, width, height, pitch, sizeof(uint32_t));
}
bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
unsigned width, unsigned height, unsigned pitch)
{
return rpng_save_image(path, (const uint8_t*)data, width, height, pitch, 3);
}
#endif

View File

@ -28,6 +28,8 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, unsigned *width, un
#ifdef HAVE_ZLIB_DEFLATE
bool rpng_save_image_argb(const char *path, const uint32_t *data,
unsigned width, unsigned height, unsigned pitch);
bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
unsigned width, unsigned height, unsigned pitch);
#endif
#endif

View File

@ -132,7 +132,6 @@ if [ "$HAVE_SDL" = "no" ]; then
fi
check_pkgconf SDL_IMAGE SDL_image
check_pkgconf LIBPNG libpng 1.5
check_pkgconf ZLIB zlib
if [ "$HAVE_THREADS" != 'no' ]; then
@ -206,6 +205,6 @@ check_macro NEON __ARM_NEON__
add_define_make OS "$OS"
# Creates config.mk and config.h.
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL GLES VG EGL KMS GBM DRM DYLIB GETOPT_LONG THREADS CG LIBXML2 SDL_IMAGE LIBPNG ZLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE FREETYPE XVIDEO X11 XEXT XF86VM XINERAMA NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 SINC BSV_MOVIE VIDEOCORE NEON"
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL OPENGL GLES VG EGL KMS GBM DRM DYLIB GETOPT_LONG THREADS CG LIBXML2 SDL_IMAGE ZLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE FREETYPE XVIDEO X11 XEXT XF86VM XINERAMA NETPLAY NETWORK_CMD STDIN_CMD COMMAND SOCKET_LEGACY FBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM FFMPEG_AVCODEC_ENCODE_AUDIO2 FFMPEG_AVCODEC_ENCODE_VIDEO2 SINC BSV_MOVIE VIDEOCORE NEON"
create_config_make config.mk $VARS
create_config_header config.h $VARS

View File

@ -22,80 +22,15 @@
#include <string.h>
#include "general.h"
#include "file.h"
#include "gfx/scaler/scaler.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_LIBPNG
#include <png.h>
#endif
#ifdef HAVE_LIBPNG
static png_structp png_ptr;
static png_infop png_info_ptr;
static void destroy_png(void)
{
if (png_ptr)
png_destroy_write_struct(&png_ptr, &png_info_ptr);
}
static bool write_header_png(FILE *file, unsigned width, unsigned height)
{
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
return false;
if (setjmp(png_jmpbuf(png_ptr)))
goto error;
png_info_ptr = png_create_info_struct(png_ptr);
if (!png_info_ptr)
goto error;
png_init_io(png_ptr, file);
png_set_IHDR(png_ptr, png_info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, png_info_ptr);
png_set_compression_level(png_ptr, 2);
return true;
error:
destroy_png();
return false;
}
static void dump_lines_png(uint8_t **lines, int height)
{
if (setjmp(png_jmpbuf(png_ptr)))
{
RARCH_ERR("PNG: dump_lines_png() failed!\n");
goto end;
}
// PNG is top-down, BMP is bottom-up.
for (int i = 0, j = height - 1; i < j; i++, j--)
{
uint8_t *tmp = lines[i];
lines[i] = lines[j];
lines[j] = tmp;
}
png_set_rows(png_ptr, png_info_ptr, lines);
png_write_png(png_ptr, png_info_ptr, PNG_TRANSFORM_BGR, NULL);
png_write_end(png_ptr, NULL);
end:
destroy_png();
}
#ifdef HAVE_ZLIB_DEFLATE
#include "gfx/rpng/rpng.h"
#else
static bool write_header_bmp(FILE *file, unsigned width, unsigned height)
{
unsigned line_size = (width * 3 + 3) & ~3;
@ -130,8 +65,6 @@ static void dump_lines_file(FILE *file, uint8_t **lines, size_t line_size, unsig
fwrite(lines[i], 1, line_size, file);
}
#endif
static void dump_line_bgr(uint8_t *line, const uint8_t *src, unsigned width)
{
memcpy(line, src, width * 3);
@ -202,24 +135,21 @@ static void dump_content(FILE *file, const void *frame,
dump_line_16(lines[j], u.u16, width);
}
#ifdef HAVE_LIBPNG
dump_lines_png(lines, height);
#else
dump_lines_file(file, lines, line_size, height);
#endif
end:
for (int i = 0; i < height; i++)
free(lines[i]);
free(lines);
}
#endif
void screenshot_generate_filename(char *filename, size_t size)
{
time_t cur_time;
time(&cur_time);
#ifdef HAVE_LIBPNG
#ifdef HAVE_ZLIB_DEFLATE
#define IMG_EXT "png"
#else
#define IMG_EXT "bmp"
@ -228,6 +158,7 @@ void screenshot_generate_filename(char *filename, size_t size)
strftime(filename, size, "RetroArch-%m%d-%H%M%S." IMG_EXT, localtime(&cur_time));
}
// Take frame bottom-up.
bool screenshot_dump(const char *folder, const void *frame,
unsigned width, unsigned height, int pitch, bool bgr24)
{
@ -237,6 +168,39 @@ bool screenshot_dump(const char *folder, const void *frame,
screenshot_generate_filename(shotname, sizeof(shotname));
fill_pathname_join(filename, folder, shotname, sizeof(filename));
#ifdef HAVE_ZLIB_DEFLATE
uint8_t *out_buffer = (uint8_t*)malloc(width * height * 3);
if (!out_buffer)
return false;
struct scaler_ctx scaler = {0};
scaler.in_width = width;
scaler.in_height = height;
scaler.out_width = width;
scaler.out_height = height;
scaler.in_stride = -pitch;
scaler.out_stride = width * 3;
scaler.out_fmt = SCALER_FMT_BGR24;
scaler.scaler_type = SCALER_TYPE_POINT;
if (bgr24)
scaler.in_fmt = SCALER_FMT_BGR24;
else if (g_extern.system.pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888)
scaler.in_fmt = SCALER_FMT_ARGB8888;
else
scaler.in_fmt = SCALER_FMT_RGB565;
scaler_ctx_gen_filter(&scaler);
scaler_ctx_scale(&scaler, out_buffer, (const uint8_t*)frame + ((int)height - 1) * pitch);
scaler_ctx_gen_reset(&scaler);
RARCH_LOG("Using RPNG for PNG screenshots.\n");
bool ret = rpng_save_image_bgr24(filename, out_buffer, width, height, width * 3);
if (!ret)
RARCH_ERR("Failed to take screenshot.\n");
free(out_buffer);
return ret;
#else
FILE *file = fopen(filename, "wb");
if (!file)
{
@ -244,11 +208,7 @@ bool screenshot_dump(const char *folder, const void *frame,
return false;
}
#ifdef HAVE_LIBPNG
bool ret = write_header_png(file, width, height);
#else
bool ret = write_header_bmp(file, width, height);
#endif
if (ret)
dump_content(file, frame, width, height, pitch, bgr24);
@ -257,5 +217,6 @@ bool screenshot_dump(const char *folder, const void *frame,
fclose(file);
return ret;
#endif
}