mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented image grabbing
This commit is contained in:
parent
27046cf8a9
commit
b3c78919d5
@ -19,6 +19,7 @@ Heino Goldenstein <heino.goldenstein@microplex.de>
|
|||||||
Guido Fiala <gfiala@s.netic.de>
|
Guido Fiala <gfiala@s.netic.de>
|
||||||
for implementing slow forward/back
|
for implementing slow forward/back
|
||||||
for implementing the SVDRP command 'HITK'
|
for implementing the SVDRP command 'HITK'
|
||||||
|
for implementing image grabbing
|
||||||
|
|
||||||
Robert Schneider <Robert.Schneider@lotus.com>
|
Robert Schneider <Robert.Schneider@lotus.com>
|
||||||
for implementing EIT support for displaying the current/next info
|
for implementing EIT support for displaying the current/next info
|
||||||
|
9
HISTORY
9
HISTORY
@ -182,7 +182,8 @@ Video Disk Recorder Revision History
|
|||||||
response time on user actions. As a consequence the EIT data may sometimes
|
response time on user actions. As a consequence the EIT data may sometimes
|
||||||
not be displayed, but this will change later when cEIT runs as a separate
|
not be displayed, but this will change later when cEIT runs as a separate
|
||||||
thread.
|
thread.
|
||||||
- The new SVDRP command 'HITK' can be used to 'hit' a remote control key.
|
- The new SVDRP command 'HITK' (thanks to Guido Fiala!) can be used to 'hit'
|
||||||
Establish an SVDRP connection and enter HITK without a parameter for a list
|
a remote control key. Establish an SVDRP connection and enter HITK without
|
||||||
of all valid key names.
|
a parameter for a list of all valid key names.
|
||||||
|
- The new SVDRP command 'GRAB' (thanks to Guido Fiala!) can be used to grab
|
||||||
|
the current frame and save it to a file.
|
||||||
|
4
Makefile
4
Makefile
@ -4,7 +4,7 @@
|
|||||||
# See the main source file 'vdr.c' for copyright information and
|
# See the main source file 'vdr.c' for copyright information and
|
||||||
# how to reach the author.
|
# how to reach the author.
|
||||||
#
|
#
|
||||||
# $Id: Makefile 1.9 2000/09/10 08:55:45 kls Exp $
|
# $Id: Makefile 1.10 2000/09/17 10:19:44 kls Exp $
|
||||||
|
|
||||||
DVBDIR = ../DVB
|
DVBDIR = ../DVB
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ tools.o : tools.c tools.h
|
|||||||
videodir.o : videodir.c tools.h videodir.h
|
videodir.o : videodir.c tools.h videodir.h
|
||||||
|
|
||||||
vdr: $(OBJS)
|
vdr: $(OBJS)
|
||||||
g++ -g -O2 $(OBJS) -lncurses -o vdr
|
g++ -g -O2 $(OBJS) -lncurses -ljpeg -o vdr
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm $(OBJS) vdr
|
-rm $(OBJS) vdr
|
||||||
|
109
dvbapi.c
109
dvbapi.c
@ -4,14 +4,18 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: dvbapi.c 1.25 2000/09/15 13:23:00 kls Exp $
|
* $Id: dvbapi.c 1.26 2000/09/17 11:53:35 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbapi.h"
|
#include "dvbapi.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
extern "C" {
|
||||||
|
#include <jpeglib.h>
|
||||||
|
}
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -315,8 +319,8 @@ char *cIndexFile::Str(int Index, bool WithFrame)
|
|||||||
static char buffer[16];
|
static char buffer[16];
|
||||||
int f = (Index % FRAMESPERSEC) + 1;
|
int f = (Index % FRAMESPERSEC) + 1;
|
||||||
int s = (Index / FRAMESPERSEC);
|
int s = (Index / FRAMESPERSEC);
|
||||||
int m = s / 60 % 60;
|
int m = s / 60 % 60;
|
||||||
int h = s / 3600;
|
int h = s / 3600;
|
||||||
s %= 60;
|
s %= 60;
|
||||||
snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f);
|
snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f);
|
||||||
return buffer;
|
return buffer;
|
||||||
@ -511,7 +515,7 @@ protected:
|
|||||||
char *fileName, *pFileNumber;
|
char *fileName, *pFileNumber;
|
||||||
bool stop;
|
bool stop;
|
||||||
int GetAvPesLength(void)
|
int GetAvPesLength(void)
|
||||||
{
|
{
|
||||||
if (Byte(0) == 'A' && Byte(1) == 'V' && Byte(4) == 'U')
|
if (Byte(0) == 'A' && Byte(1) == 'V' && Byte(4) == 'U')
|
||||||
return (Byte(6) << 8) + Byte(7) + AV_PES_HEADER_LEN;
|
return (Byte(6) << 8) + Byte(7) + AV_PES_HEADER_LEN;
|
||||||
return 0;
|
return 0;
|
||||||
@ -751,7 +755,7 @@ int cRecordBuffer::Write(int Max)
|
|||||||
if (n) {
|
if (n) {
|
||||||
if (stop && pictureType == I_FRAME) {
|
if (stop && pictureType == I_FRAME) {
|
||||||
ok = false;
|
ok = false;
|
||||||
return -1; // finish the recording before the next 'I' frame
|
return -1; // finish the recording before the next 'I' frame
|
||||||
}
|
}
|
||||||
if (NextFile()) {
|
if (NextFile()) {
|
||||||
if (index && pictureType != NO_PICTURE)
|
if (index && pictureType != NO_PICTURE)
|
||||||
@ -801,7 +805,7 @@ private:
|
|||||||
void Close(void);
|
void Close(void);
|
||||||
public:
|
public:
|
||||||
cReplayBuffer(int *OutFile, const char *FileName);
|
cReplayBuffer(int *OutFile, const char *FileName);
|
||||||
virtual ~cReplayBuffer();
|
virtual ~cReplayBuffer();
|
||||||
virtual int Read(int Max = -1);
|
virtual int Read(int Max = -1);
|
||||||
virtual int Write(int Max = -1);
|
virtual int Write(int Max = -1);
|
||||||
void SetMode(eReplayMode Mode);
|
void SetMode(eReplayMode Mode);
|
||||||
@ -1067,7 +1071,7 @@ cDvbApi::cDvbApi(const char *FileName)
|
|||||||
cols = rows = 0;
|
cols = rows = 0;
|
||||||
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
|
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
|
||||||
initscr();
|
initscr();
|
||||||
keypad(stdscr, TRUE);
|
keypad(stdscr, true);
|
||||||
nonl();
|
nonl();
|
||||||
cbreak();
|
cbreak();
|
||||||
noecho();
|
noecho();
|
||||||
@ -1076,7 +1080,7 @@ cDvbApi::cDvbApi(const char *FileName)
|
|||||||
#if defined(DEBUG_OSD)
|
#if defined(DEBUG_OSD)
|
||||||
memset(&colorPairs, 0, sizeof(colorPairs));
|
memset(&colorPairs, 0, sizeof(colorPairs));
|
||||||
start_color();
|
start_color();
|
||||||
leaveok(stdscr, TRUE);
|
leaveok(stdscr, true);
|
||||||
window = NULL;
|
window = NULL;
|
||||||
#endif
|
#endif
|
||||||
lastProgress = lastTotal = -1;
|
lastProgress = lastTotal = -1;
|
||||||
@ -1187,6 +1191,93 @@ void cDvbApi::Cleanup(void)
|
|||||||
PrimaryDvbApi = NULL;
|
PrimaryDvbApi = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
// just do this once?
|
||||||
|
struct video_mbuf mbuf;
|
||||||
|
result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
|
||||||
|
int msize = mbuf.size;
|
||||||
|
// gf: this needs to be a protected member of cDvbApi! //XXX kls: WHY???
|
||||||
|
unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
|
||||||
|
if (!mem || mem == (unsigned char *)-1)
|
||||||
|
return false;
|
||||||
|
// set up the size and RGB
|
||||||
|
struct video_capability vc;
|
||||||
|
result |= ioctl(videoDev, VIDIOCGCAP, &vc);
|
||||||
|
struct video_mmap vm;
|
||||||
|
vm.frame = 0;
|
||||||
|
if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
|
||||||
|
(SizeY > 0) && (SizeY <= vc.maxheight)) {
|
||||||
|
vm.width = SizeX;
|
||||||
|
vm.height = SizeY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm.width = vc.maxwidth;
|
||||||
|
vm.height = vc.maxheight;
|
||||||
|
}
|
||||||
|
vm.format = VIDEO_PALETTE_RGB24;
|
||||||
|
// this needs to be done every time:
|
||||||
|
result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
|
||||||
|
result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
|
||||||
|
// make RGB out of BGR:
|
||||||
|
int memsize = vm.width * vm.height;
|
||||||
|
unsigned char *mem1 = mem;
|
||||||
|
for (int i = 0; i < memsize; i++) {
|
||||||
|
unsigned char tmp = mem1[2];
|
||||||
|
mem1[2] = mem1[0];
|
||||||
|
mem1[0] = tmp;
|
||||||
|
mem1 += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Quality < 0)
|
||||||
|
Quality = 255; //XXX is this 'best'???
|
||||||
|
|
||||||
|
isyslog(LOG_INFO, "grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
|
||||||
|
FILE *f = fopen(FileName, "wb");
|
||||||
|
if (f) {
|
||||||
|
if (Jpeg) {
|
||||||
|
// write JPEG file:
|
||||||
|
struct jpeg_compress_struct cinfo;
|
||||||
|
struct jpeg_error_mgr jerr;
|
||||||
|
cinfo.err = jpeg_std_error(&jerr);
|
||||||
|
jpeg_create_compress(&cinfo);
|
||||||
|
jpeg_stdio_dest(&cinfo, f);
|
||||||
|
cinfo.image_width = vm.width;
|
||||||
|
cinfo.image_height = vm.height;
|
||||||
|
cinfo.input_components = 3;
|
||||||
|
cinfo.in_color_space = JCS_RGB;
|
||||||
|
|
||||||
|
jpeg_set_defaults(&cinfo);
|
||||||
|
jpeg_set_quality(&cinfo, Quality, true);
|
||||||
|
jpeg_start_compress(&cinfo, true);
|
||||||
|
|
||||||
|
int rs = vm.width * 3;
|
||||||
|
JSAMPROW rp[vm.height];
|
||||||
|
for (int k = 0; k < vm.height; k++)
|
||||||
|
rp[k] = &mem[rs * k];
|
||||||
|
jpeg_write_scanlines(&cinfo, rp, vm.height);
|
||||||
|
jpeg_finish_compress(&cinfo);
|
||||||
|
jpeg_destroy_compress(&cinfo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// write PNM file:
|
||||||
|
if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
|
||||||
|
fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
|
||||||
|
LOG_ERROR_STR(FileName);
|
||||||
|
result |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG_ERROR_STR(FileName);
|
||||||
|
result |= 1;
|
||||||
|
}
|
||||||
|
munmap(mem, msize);
|
||||||
|
return result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_OSD
|
#ifdef DEBUG_OSD
|
||||||
void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg)
|
void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg)
|
||||||
{
|
{
|
||||||
@ -1233,7 +1324,7 @@ void cDvbApi::Open(int w, int h)
|
|||||||
rows = h;
|
rows = h;
|
||||||
#ifdef DEBUG_OSD
|
#ifdef DEBUG_OSD
|
||||||
window = subwin(stdscr, h, w, d, 0);
|
window = subwin(stdscr, h, w, d, 0);
|
||||||
syncok(window, TRUE);
|
syncok(window, true);
|
||||||
#define B2C(b) (((b) * 1000) / 255)
|
#define B2C(b) (((b) * 1000) / 255)
|
||||||
#define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
|
#define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
|
||||||
#else
|
#else
|
||||||
|
6
dvbapi.h
6
dvbapi.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: dvbapi.h 1.14 2000/09/10 10:03:29 kls Exp $
|
* $Id: dvbapi.h 1.15 2000/09/17 11:43:10 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DVBAPI_H
|
#ifndef __DVBAPI_H
|
||||||
@ -70,6 +70,10 @@ public:
|
|||||||
// Closes down all DVB devices.
|
// Closes down all DVB devices.
|
||||||
// Must be called at the end of the program.
|
// Must be called at the end of the program.
|
||||||
|
|
||||||
|
// Image Grab facilities
|
||||||
|
|
||||||
|
bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
|
||||||
|
|
||||||
// On Screen Display facilities
|
// On Screen Display facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
68
svdrp.c
68
svdrp.c
@ -10,7 +10,7 @@
|
|||||||
* and interact with the Video Disk Recorder - or write a full featured
|
* and interact with the Video Disk Recorder - or write a full featured
|
||||||
* graphical interface that sits on top of an SVDRP connection.
|
* graphical interface that sits on top of an SVDRP connection.
|
||||||
*
|
*
|
||||||
* $Id: svdrp.c 1.8 2000/09/17 09:24:52 kls Exp $
|
* $Id: svdrp.c 1.9 2000/09/17 11:29:33 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
@ -120,6 +120,10 @@ const char *HelpPages[] = {
|
|||||||
" Delete channel.",
|
" Delete channel.",
|
||||||
"DELT <number>\n"
|
"DELT <number>\n"
|
||||||
" Delete timer.",
|
" Delete timer.",
|
||||||
|
"GRAB <filename> [ jpeg | pnm [ <quality> [ <sizex> <sizey> ] ] ]\n"
|
||||||
|
" Grab the current frame and save it to the given file. Images can\n"
|
||||||
|
" be stored as JPEG (default) or PNM, at the given quality (default\n"
|
||||||
|
" is 'maximum', only applies to JPEG) and size (default is full screen).",
|
||||||
"HELP [ <topic> ]\n"
|
"HELP [ <topic> ]\n"
|
||||||
" The HELP command gives help info.",
|
" The HELP command gives help info.",
|
||||||
"HITK [ <key> ]\n"
|
"HITK [ <key> ]\n"
|
||||||
@ -363,6 +367,67 @@ void cSVDRP::CmdDELT(const char *Option)
|
|||||||
Reply(501, "Missing timer number");
|
Reply(501, "Missing timer number");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cSVDRP::CmdGRAB(const char *Option)
|
||||||
|
{
|
||||||
|
char *FileName = NULL;
|
||||||
|
bool Jpeg = true;
|
||||||
|
int Quality = -1, SizeX = -1, SizeY = -1;
|
||||||
|
if (*Option) {
|
||||||
|
char buf[strlen(Option) + 1];
|
||||||
|
char *p = strcpy(buf, Option);
|
||||||
|
const char *delim = " \t";
|
||||||
|
FileName = strtok(p, delim);
|
||||||
|
if ((p = strtok(NULL, delim)) != NULL) {
|
||||||
|
if (strcasecmp(p, "JPEG") == 0)
|
||||||
|
Jpeg = true;
|
||||||
|
else if (strcasecmp(p, "PNM") == 0)
|
||||||
|
Jpeg = false;
|
||||||
|
else {
|
||||||
|
Reply(501, "Unknown image type \"%s\"", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((p = strtok(NULL, delim)) != NULL) {
|
||||||
|
if (isnumber(p))
|
||||||
|
Quality = atoi(p);
|
||||||
|
else {
|
||||||
|
Reply(501, "Illegal quality \"%s\"", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((p = strtok(NULL, delim)) != NULL) {
|
||||||
|
if (isnumber(p))
|
||||||
|
SizeX = atoi(p);
|
||||||
|
else {
|
||||||
|
Reply(501, "Illegal sizex \"%s\"", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((p = strtok(NULL, delim)) != NULL) {
|
||||||
|
if (isnumber(p))
|
||||||
|
SizeY = atoi(p);
|
||||||
|
else {
|
||||||
|
Reply(501, "Illegal sizey \"%s\"", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Reply(501, "Missing sizey");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((p = strtok(NULL, delim)) != NULL) {
|
||||||
|
Reply(501, "Unexpected parameter \"%s\"", p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cDvbApi::PrimaryDvbApi->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY))
|
||||||
|
Reply(250, "Grabbed image %s", Option);
|
||||||
|
else
|
||||||
|
Reply(451, "Grab image failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Reply(501, "Missing filename");
|
||||||
|
}
|
||||||
|
|
||||||
void cSVDRP::CmdHELP(const char *Option)
|
void cSVDRP::CmdHELP(const char *Option)
|
||||||
{
|
{
|
||||||
if (*Option) {
|
if (*Option) {
|
||||||
@ -636,6 +701,7 @@ void cSVDRP::Execute(char *Cmd)
|
|||||||
if (CMD("CHAN")) CmdCHAN(s);
|
if (CMD("CHAN")) CmdCHAN(s);
|
||||||
else if (CMD("DELC")) CmdDELC(s);
|
else if (CMD("DELC")) CmdDELC(s);
|
||||||
else if (CMD("DELT")) CmdDELT(s);
|
else if (CMD("DELT")) CmdDELT(s);
|
||||||
|
else if (CMD("GRAB")) CmdGRAB(s);
|
||||||
else if (CMD("HELP")) CmdHELP(s);
|
else if (CMD("HELP")) CmdHELP(s);
|
||||||
else if (CMD("HITK")) CmdHITK(s);
|
else if (CMD("HITK")) CmdHITK(s);
|
||||||
else if (CMD("LSTC")) CmdLSTC(s);
|
else if (CMD("LSTC")) CmdLSTC(s);
|
||||||
|
3
svdrp.h
3
svdrp.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: svdrp.h 1.4 2000/09/17 08:52:51 kls Exp $
|
* $Id: svdrp.h 1.5 2000/09/17 10:22:49 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __SVDRP_H
|
#ifndef __SVDRP_H
|
||||||
@ -35,6 +35,7 @@ private:
|
|||||||
void CmdCHAN(const char *Option);
|
void CmdCHAN(const char *Option);
|
||||||
void CmdDELC(const char *Option);
|
void CmdDELC(const char *Option);
|
||||||
void CmdDELT(const char *Option);
|
void CmdDELT(const char *Option);
|
||||||
|
void CmdGRAB(const char *Option);
|
||||||
void CmdHELP(const char *Option);
|
void CmdHELP(const char *Option);
|
||||||
void CmdHITK(const char *Option);
|
void CmdHITK(const char *Option);
|
||||||
void CmdLSTC(const char *Option);
|
void CmdLSTC(const char *Option);
|
||||||
|
Loading…
Reference in New Issue
Block a user