summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2000-09-17 11:53:35 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2000-09-17 11:53:35 +0200
commitb3c78919d5e8dcfcf8f5eb635bbb86efa98a3fa4 (patch)
tree9f7fdf1aa3461c1c743b338e018d304e7569be45
parent27046cf8a9f1047e39724ddb1702957f4b395f36 (diff)
downloadvdr-b3c78919d5e8dcfcf8f5eb635bbb86efa98a3fa4.tar.gz
vdr-b3c78919d5e8dcfcf8f5eb635bbb86efa98a3fa4.tar.bz2
Implemented image grabbing
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY9
-rw-r--r--Makefile4
-rw-r--r--dvbapi.c109
-rw-r--r--dvbapi.h6
-rw-r--r--svdrp.c68
-rw-r--r--svdrp.h3
7 files changed, 182 insertions, 18 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 0627c37b..fd220b16 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -19,6 +19,7 @@ Heino Goldenstein <heino.goldenstein@microplex.de>
Guido Fiala <gfiala@s.netic.de>
for implementing slow forward/back
for implementing the SVDRP command 'HITK'
+ for implementing image grabbing
Robert Schneider <Robert.Schneider@lotus.com>
for implementing EIT support for displaying the current/next info
diff --git a/HISTORY b/HISTORY
index eb7f7009..6fade416 100644
--- a/HISTORY
+++ b/HISTORY
@@ -182,7 +182,8 @@ Video Disk Recorder Revision History
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
thread.
-- The new SVDRP command 'HITK' can be used to 'hit' a remote control key.
- Establish an SVDRP connection and enter HITK without a parameter for a list
- of all valid key names.
-
+- The new SVDRP command 'HITK' (thanks to Guido Fiala!) can be used to 'hit'
+ a remote control key. Establish an SVDRP connection and enter HITK without
+ 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.
diff --git a/Makefile b/Makefile
index 2f00459b..583a3f84 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# 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
@@ -40,7 +40,7 @@ tools.o : tools.c tools.h
videodir.o : videodir.c tools.h videodir.h
vdr: $(OBJS)
- g++ -g -O2 $(OBJS) -lncurses -o vdr
+ g++ -g -O2 $(OBJS) -lncurses -ljpeg -o vdr
clean:
-rm $(OBJS) vdr
diff --git a/dvbapi.c b/dvbapi.c
index 6c08e065..2c8a6ba1 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -4,14 +4,18 @@
* See the main source file 'vdr.c' for copyright information and
* 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 <errno.h>
#include <fcntl.h>
+extern "C" {
+#include <jpeglib.h>
+}
#include <stdlib.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
@@ -315,8 +319,8 @@ char *cIndexFile::Str(int Index, bool WithFrame)
static char buffer[16];
int f = (Index % FRAMESPERSEC) + 1;
int s = (Index / FRAMESPERSEC);
- int m = s / 60 % 60;
- int h = s / 3600;
+ int m = s / 60 % 60;
+ int h = s / 3600;
s %= 60;
snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f);
return buffer;
@@ -511,7 +515,7 @@ protected:
char *fileName, *pFileNumber;
bool stop;
int GetAvPesLength(void)
- {
+ {
if (Byte(0) == 'A' && Byte(1) == 'V' && Byte(4) == 'U')
return (Byte(6) << 8) + Byte(7) + AV_PES_HEADER_LEN;
return 0;
@@ -751,7 +755,7 @@ int cRecordBuffer::Write(int Max)
if (n) {
if (stop && pictureType == I_FRAME) {
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 (index && pictureType != NO_PICTURE)
@@ -801,7 +805,7 @@ private:
void Close(void);
public:
cReplayBuffer(int *OutFile, const char *FileName);
- virtual ~cReplayBuffer();
+ virtual ~cReplayBuffer();
virtual int Read(int Max = -1);
virtual int Write(int Max = -1);
void SetMode(eReplayMode Mode);
@@ -1067,7 +1071,7 @@ cDvbApi::cDvbApi(const char *FileName)
cols = rows = 0;
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
initscr();
- keypad(stdscr, TRUE);
+ keypad(stdscr, true);
nonl();
cbreak();
noecho();
@@ -1076,7 +1080,7 @@ cDvbApi::cDvbApi(const char *FileName)
#if defined(DEBUG_OSD)
memset(&colorPairs, 0, sizeof(colorPairs));
start_color();
- leaveok(stdscr, TRUE);
+ leaveok(stdscr, true);
window = NULL;
#endif
lastProgress = lastTotal = -1;
@@ -1187,6 +1191,93 @@ void cDvbApi::Cleanup(void)
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
void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg)
{
@@ -1233,7 +1324,7 @@ void cDvbApi::Open(int w, int h)
rows = h;
#ifdef DEBUG_OSD
window = subwin(stdscr, h, w, d, 0);
- syncok(window, TRUE);
+ syncok(window, true);
#define B2C(b) (((b) * 1000) / 255)
#define SETCOLOR(n, r, g, b, o) init_color(n, B2C(r), B2C(g), B2C(b))
#else
diff --git a/dvbapi.h b/dvbapi.h
index a43e7075..5ae3a513 100644
--- a/dvbapi.h
+++ b/dvbapi.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -70,6 +70,10 @@ public:
// Closes down all DVB devices.
// 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
private:
diff --git a/svdrp.c b/svdrp.c
index fe25c8bf..09cffe3d 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* 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
@@ -120,6 +120,10 @@ const char *HelpPages[] = {
" Delete channel.",
"DELT <number>\n"
" 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"
" The HELP command gives help info.",
"HITK [ <key> ]\n"
@@ -363,6 +367,67 @@ void cSVDRP::CmdDELT(const char *Option)
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)
{
if (*Option) {
@@ -636,6 +701,7 @@ void cSVDRP::Execute(char *Cmd)
if (CMD("CHAN")) CmdCHAN(s);
else if (CMD("DELC")) CmdDELC(s);
else if (CMD("DELT")) CmdDELT(s);
+ else if (CMD("GRAB")) CmdGRAB(s);
else if (CMD("HELP")) CmdHELP(s);
else if (CMD("HITK")) CmdHITK(s);
else if (CMD("LSTC")) CmdLSTC(s);
diff --git a/svdrp.h b/svdrp.h
index 6c1fbb29..134332a0 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* 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
@@ -35,6 +35,7 @@ private:
void CmdCHAN(const char *Option);
void CmdDELC(const char *Option);
void CmdDELT(const char *Option);
+ void CmdGRAB(const char *Option);
void CmdHELP(const char *Option);
void CmdHITK(const char *Option);
void CmdLSTC(const char *Option);