Files
recycled-ni-neutrino/src/driver/screenshot.cpp
Thilo Graf 11b3307251 CMsgBox: rework msgbox classes with Window class implementation
Replacing messagebox, hintbox_ext and some derivated parts with
basic class hintbox and derivated class CMsgBox. This should unify
window handling and avoids maintain of multiple classes with quasi
same purpose and adds more functionality.

TODO: fix and optimize details


Origin commit data
------------------
Commit: dde298b1b7
Author: Thilo Graf <dbt@novatux.de>
Date: 2016-04-04 (Mon, 04 Apr 2016)
2016-10-24 10:31:24 +02:00

405 lines
10 KiB
C++

/*
Neutrino-GUI - DBoxII-Project
Copyright (C) 2011 CoolStream International Ltd
parts based on AiO Screengrabber (C) Seddi seddi@ihad.tv
License: GPLv2
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <png.h>
#include <zlib.h>
#include <global.h>
#include <neutrino.h>
#include <gui/filebrowser.h>
#include <gui/widget/hintbox.h>
#include <gui/widget/msgbox.h>
#include <daemonc/remotecontrol.h>
#include <zapit/debug.h>
#include <zapit/getservices.h>
#include <eitd/sectionsd.h>
#include <video.h>
#include <cs_api.h>
#include <driver/screenshot.h>
extern "C" {
#include <jpeglib.h>
}
extern cVideo *videoDecoder;
/* constructor, defaults is empty fname and CScreenShot::FORMAT_JPG format */
CScreenShot::CScreenShot(const std::string fname, screenshot_format_t fmt)
{
format = fmt;
filename = fname;
pixel_data = NULL;
fd = NULL;
xres = 0;
yres = 0;
get_video = g_settings.screenshot_video;
get_osd = g_settings.screenshot_mode;
scale_to_video = g_settings.screenshot_scale;
}
CScreenShot::~CScreenShot()
{
}
/* try to get video frame data in ARGB format, restore GXA state */
bool CScreenShot::GetData()
{
static OpenThreads::Mutex mutex;
bool res = false;
mutex.lock();
#ifdef USE_NEVIS_GXA
CFrameBuffer::getInstance()->setActive(false);
#endif
if (videoDecoder->getBlank())
get_video = false;
#if 1 // to enable after libcs/drivers update
res = videoDecoder->GetScreenImage(pixel_data, xres, yres, get_video, get_osd, scale_to_video);
#endif
#ifdef USE_NEVIS_GXA
/* sort of hack. GXA used to transfer/convert live image to RGB,
* so setup GXA back */
CFrameBuffer::getInstance()->setupGXA();
CFrameBuffer::getInstance()->add_gxa_sync_marker();
CFrameBuffer::getInstance()->setActive(true);
#endif
mutex.unlock();
if (!res) {
printf("CScreenShot::Start: GetScreenImage failed\n");
return false;
}
printf("CScreenShot::GetData: data: %p %d x %d\n", pixel_data, xres, yres);
return true;
}
/* start ::run in new thread to save file in selected format */
bool CScreenShot::Start()
{
bool ret = false;
if(GetData())
ret = (start() == 0);
else
delete this;
return ret;
}
/* thread function to save data asynchroniosly. delete itself after saving */
void CScreenShot::run()
{
printf("CScreenShot::run save to %s format %d\n", filename.c_str(), format);
detach();
setCancelModeDisable();
setSchedulePriority(THREAD_PRIORITY_MIN);
bool ret = SaveFile();
printf("CScreenShot::run: %s finished: %d\n", filename.c_str(), ret);
delete this;
}
/* save file in sync mode, return true if save ok, or false */
bool CScreenShot::StartSync()
{
bool ret = false;
printf("CScreenShot::StartSync save to %s format %d\n", filename.c_str(), format);
if(GetData())
ret = SaveFile();
printf("CScreenShot::StartSync: %s finished: %d\n", filename.c_str(), ret);
return ret;
}
/* save file in selected format, free data received from video decoder */
bool CScreenShot::SaveFile()
{
bool ret = true;
switch (format) {
case FORMAT_PNG:
ret = SavePng();
break;
default:
printf("CScreenShot::SaveFile unsupported format %d, using jpeg\n", format);
case FORMAT_JPG:
ret = SaveJpg();
break;
case FORMAT_BMP:
ret = SaveBmp();
break;
}
cs_free_uncached((void *) pixel_data);
return ret;
}
/* try to open file, return true if success, or false */
bool CScreenShot::OpenFile()
{
fd = fopen(filename.c_str(), "w");
if (!fd) {
printf("CScreenShot::OpenFile: failed to open %s\n", filename.c_str());
return false;
}
return true;
}
/* save screenshot in png format, return true if success, or false */
bool CScreenShot::SavePng()
{
png_bytep *row_pointers;
png_structp png_ptr;
png_infop info_ptr;
TIMER_START();
if(!OpenFile())
return false;
row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * yres);
if (!row_pointers) {
printf("CScreenShot::SavePng: malloc error\n");
fclose(fd);
return false;
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
info_ptr = png_create_info_struct(png_ptr);
#if (PNG_LIBPNG_VER < 10500)
if (setjmp(png_ptr->jmpbuf))
#else
if (setjmp(png_jmpbuf(png_ptr)))
#endif
{
printf("CScreenShot::SavePng: %s save error\n", filename.c_str());
png_destroy_write_struct(&png_ptr, &info_ptr);
free(row_pointers);
fclose(fd);
return false;
}
png_init_io(png_ptr, fd);
int y;
for (y=0; y<yres; y++) {
row_pointers[y] = pixel_data + (y*xres*4);
}
png_set_IHDR(png_ptr, info_ptr, xres, yres, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
//png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
png_set_compression_level(png_ptr, Z_BEST_SPEED);
png_set_bgr(png_ptr);
#ifdef BOXMODEL_APOLLO
png_set_invert_alpha(png_ptr);
#endif
png_write_info(png_ptr, info_ptr);
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(row_pointers);
fclose(fd);
TIMER_STOP(filename.c_str());
return true;
}
#define SWAP(x,y) { x ^= y; y ^= x; x ^= y; }
/* from libjpg example.c */
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
void my_error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
/* save screenshot in jpg format, return true if success, or false */
bool CScreenShot::SaveJpg()
{
int quality = 90;
TIMER_START();
if(!OpenFile())
return false;
for (int y = 0; y < yres; y++) {
int xres1 = y*xres*3;
int xres2 = xres1+2;
for (int x = 0; x < xres; x++) {
int x2 = x*3;
memcpy(pixel_data + x2 + xres1, pixel_data + x*4 + y*xres*4, 3);
SWAP(pixel_data[x2 + xres1], pixel_data[x2 + xres2]);
}
}
struct jpeg_compress_struct cinfo;
struct my_error_mgr jerr;
JSAMPROW row_pointer[1];
unsigned int row_stride;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
printf("CScreenShot::SaveJpg: %s save error\n", filename.c_str());
jpeg_destroy_compress(&cinfo);
fclose(fd);
return false;
}
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fd);
cinfo.image_width = xres;
cinfo.image_height = yres;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
cinfo.dct_method = JDCT_IFAST;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
row_stride = xres * 3;
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = & pixel_data[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(fd);
TIMER_STOP(filename.c_str());
return true;
}
/* save screenshot in bmp format, return true if success, or false */
bool CScreenShot::SaveBmp()
{
TIMER_START();
if(!OpenFile())
return false;
unsigned char hdr[14 + 40];
unsigned int i = 0;
#define PUT32(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF); hdr[i++] = (((x)>>16)&0xFF); hdr[i++] = (((x)>>24)&0xFF);
#define PUT16(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF);
#define PUT8(x) hdr[i++] = ((x)&0xFF);
PUT8('B'); PUT8('M');
PUT32((((xres * yres) * 3 + 3) &~ 3) + 14 + 40);
PUT16(0); PUT16(0); PUT32(14 + 40);
PUT32(40); PUT32(xres); PUT32(yres);
PUT16(1);
PUT16(4*8); // bits
PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0);
#undef PUT32
#undef PUT16
#undef PUT8
fwrite(hdr, 1, i, fd);
int y;
for (y=yres-1; y>=0 ; y-=1) {
fwrite(pixel_data+(y*xres*4),xres*4,1,fd);
}
fclose(fd);
TIMER_STOP(filename.c_str());
return true;
}
/*
* create filename member from channel name and its current EPG data,
* with added date and time including msecs and suffix for selected format
*/
void CScreenShot::MakeFileName(const t_channel_id channel_id)
{
char fname[512]; // UTF-8
std::string channel_name;
CEPGData epgData;
unsigned int pos = 0;
snprintf(fname, sizeof(fname), "%s/", g_settings.screenshot_dir.c_str());
pos = strlen(fname);
channel_name = CServiceManager::getInstance()->GetServiceName(channel_id);
if (!(channel_name.empty())) {
strcpy(&(fname[pos]), UTF8_TO_FILESYSTEM_ENCODING(channel_name.c_str()));
ZapitTools::replace_char(&fname[pos]);
strcat(fname, "_");
}
pos = strlen(fname);
if(CEitManager::getInstance()->getActualEPGServiceKey(channel_id, &epgData)) {
CShortEPGData epgdata;
if(CEitManager::getInstance()->getEPGidShort(epgData.eventID, &epgdata)) {
if (!(epgdata.title.empty())) {
strcpy(&(fname[pos]), epgdata.title.c_str());
ZapitTools::replace_char(&fname[pos]);
}
}
}
pos = strlen(fname);
struct timeval tv;
gettimeofday(&tv, NULL);
strftime(&(fname[pos]), sizeof(fname) - pos - 1, "_%Y%m%d_%H%M%S", localtime(&tv.tv_sec));
pos = strlen(fname);
snprintf(&(fname[pos]), sizeof(fname) - pos - 1, "_%03d", (int) tv.tv_usec/1000);
switch (format) {
case FORMAT_PNG:
strcat(fname, ".png");
break;
default:
printf("CScreenShot::MakeFileName unsupported format %d, using jpeg\n", format);
case FORMAT_JPG:
strcat(fname, ".jpg");
break;
case FORMAT_BMP:
strcat(fname, ".bmp");
break;
}
printf("CScreenShot::MakeFileName: [%s]\n", fname);
filename = std::string(fname);
}