diff --git a/CONTRIBUTORS b/CONTRIBUTORS index fd220b16..03fd4bc0 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -20,6 +20,7 @@ Guido Fiala for implementing slow forward/back for implementing the SVDRP command 'HITK' for implementing image grabbing + for implementing overlay capabilities (see his 'kvdr' tool at http://www.s.netic.de/gfiala) Robert Schneider for implementing EIT support for displaying the current/next info diff --git a/HISTORY b/HISTORY index 6fade416..a54c3dcd 100644 --- a/HISTORY +++ b/HISTORY @@ -187,3 +187,6 @@ Video Disk Recorder Revision History 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. +- The new SVDRP commands 'OVL*' can be used to control video overlays (thanks + to Guido Fiala!). This is mainly for use in the 'kvdr' tool (see the 'kvdr' + page at http://www.s.netic.de/gfiala). diff --git a/dvbapi.c b/dvbapi.c index 2c8a6ba1..1468de60 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.26 2000/09/17 11:53:35 kls Exp $ + * $Id: dvbapi.c 1.27 2000/09/17 12:45:55 kls Exp $ */ #include "dvbapi.h" @@ -1069,6 +1069,11 @@ cDvbApi::cDvbApi(const char *FileName) if (videoDev < 0) LOG_ERROR; cols = rows = 0; + + ovlGeoSet = ovlStat = ovlFbSet = false; + ovlBrightness = ovlColour = ovlHue = ovlContrast = 32768; + ovlClipCount = 0; + #if defined(DEBUG_OSD) || defined(REMOTE_KBD) initscr(); keypad(stdscr, true); @@ -1093,6 +1098,7 @@ cDvbApi::~cDvbApi() Close(); Stop(); StopRecord(); + OvlO(false); //Overlay off! close(videoDev); } #if defined(DEBUG_OSD) || defined(REMOTE_KBD) @@ -1274,10 +1280,159 @@ bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, LOG_ERROR_STR(FileName); result |= 1; } + + if (ovlStat && ovlGeoSet) { + // switch the Overlay on again (gf: why have i to do anything again?) + OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY); + } + if (ovlFbSet) + OvlP(ovlBrightness, ovlColour, ovlHue, ovlContrast); + munmap(mem, msize); return result == 0; } +bool cDvbApi::OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette) +{ + int result = 0; + // get the actual X-Server settings??? + // plausibility-check problem: can't be verified w/o X-server!!! + if (SizeX <= 0 || SizeY <= 0 || FbAddr == 0 || Bpp / 8 > 4 || + Bpp / 8 <= 0 || Palette <= 0 || Palette > 13 || ovlClipCount < 0 || + SizeX > 4096 || SizeY > 4096) { + ovlFbSet = ovlGeoSet = false; + OvlO(false); + return false; + } + else { + dsyslog(LOG_INFO, "OvlF: %d %d %x %d %d", SizeX, SizeY, FbAddr, Bpp, Palette); + // this is the problematic part! + struct video_buffer vb; + result |= ioctl(videoDev, VIDIOCGFBUF, &vb); + vb.base = (void*)FbAddr; + vb.depth = Bpp; + vb.height = SizeY; + vb.width = SizeX; + vb.bytesperline = ((vb.depth + 1) / 8) * vb.width; + //now the real thing: setting the framebuffer + result |= ioctl(videoDev, VIDIOCSFBUF, &vb); + if (result) { + ovlFbSet = ovlGeoSet = false; + ovlClipCount = 0; + OvlO(false); + return false; + } + else { + ovlFbSizeX = SizeX; + ovlFbSizeY = SizeY; + ovlBpp = Bpp; + ovlPalette = Palette; + ovlFbSet = true; + return true; + } + } +} + +bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY) +{ + int result = 0; + // get the actual X-Server settings??? + struct video_capability vc; + result |= ioctl(videoDev, VIDIOCGCAP, &vc); + if (!ovlFbSet) + return false; + if (SizeX < vc.minwidth || SizeY < vc.minheight || + SizeX > vc.maxwidth || SizeY>vc.maxheight +// || PosX > FbSizeX || PosY > FbSizeY +// PosX < -SizeX || PosY < -SizeY || + ) { + ovlGeoSet = false; + OvlO(false); + return false; + } + else { + struct video_window vw; + result |= ioctl(videoDev, VIDIOCGWIN, &vw); + vw.x = PosX; + vw.y = PosY; + vw.width = SizeX; + vw.height = SizeY; + vw.chromakey = ovlPalette; + vw.flags = VIDEO_WINDOW_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP; + vw.clips = ovlClipRects; + vw.clipcount = ovlClipCount; + result |= ioctl(videoDev, VIDIOCSWIN, &vw); + if (result) { + ovlGeoSet = false; + ovlClipCount = 0; + return false; + } + else { + ovlSizeX = SizeX; + ovlSizeY = SizeY; + ovlPosX = PosX; + ovlPosY = PosY; + ovlGeoSet = true; + ovlStat = true; + return true; + } + } +} + +bool cDvbApi::OvlC(int ClipCount, CRect *cr) +{ + if (ovlGeoSet && ovlFbSet) { + for (int i = 0; i < ClipCount; i++) { + ovlClipRects[i].x = cr[i].x; + ovlClipRects[i].y = cr[i].y; + ovlClipRects[i].width = cr[i].width; + ovlClipRects[i].height = cr[i].height; + ovlClipRects[i].next = &(ovlClipRects[i + 1]); + } + ovlClipCount = ClipCount; + //use it: + return OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY); + } + return false; +} + +bool cDvbApi::OvlP(__u16 Brightness, __u16 Colour, __u16 Hue, __u16 Contrast) +{ + int result = 0; + ovlBrightness = Brightness; + ovlColour = Colour; + ovlHue = Hue; + ovlContrast = Contrast; + struct video_picture vp; + if (!ovlFbSet) + return false; + result |= ioctl(videoDev, VIDIOCGPICT, &vp); + vp.brightness = Brightness; + vp.colour = Colour; + vp.hue = Hue; + vp.contrast = Contrast; + vp.depth = ovlBpp; + vp.palette = ovlPalette; // gf: is this always ok? VIDEO_PALETTE_RGB565; + result |= ioctl(videoDev, VIDIOCSPICT, &vp); + return result == 0; +} + +bool cDvbApi::OvlO(bool Value) +{ + int result = 0; + if (!ovlGeoSet && Value) + return false; + int one = 1; + int zero = 0; + result |= ioctl(videoDev, VIDIOCCAPTURE, Value ? &one : &zero); + ovlStat = Value; + if (result) { + ovlStat = false; + return false; + } + return true; +} + #ifdef DEBUG_OSD void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) { diff --git a/dvbapi.h b/dvbapi.h index 5ae3a513..08ba4bfc 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.15 2000/09/17 11:43:10 kls Exp $ + * $Id: dvbapi.h 1.16 2000/09/17 12:15:05 kls Exp $ */ #ifndef __DVBAPI_H @@ -21,6 +21,12 @@ typedef unsigned char __u8; #include #include +// Overlay facilities +#define MAXCLIPRECTS 100 +typedef struct CRect { + signed short x, y, width, height; + }; + #define MenuLines 15 #define MenuColumns 40 @@ -74,6 +80,21 @@ public: bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + // Overlay facilities + +private: + bool ovlStat, ovlGeoSet, ovlFbSet; + int ovlSizeX, ovlSizeY, ovlPosX, ovlPosY, ovlBpp, ovlPalette, ovlClips, ovlClipCount; + int ovlFbSizeX, ovlFbSizeY; + __u16 ovlBrightness, ovlColour, ovlHue, ovlContrast; + struct video_clip ovlClipRects[MAXCLIPRECTS]; +public: + bool OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette); + bool OvlG(int SizeX, int SizeY, int PosX, int PosY); + bool OvlC(int ClipCount, CRect *Cr); + bool OvlP(__u16 Brightness, __u16 Color, __u16 Hue, __u16 Contrast); + bool OvlO(bool Value); + // On Screen Display facilities private: diff --git a/svdrp.c b/svdrp.c index 09cffe3d..c9ea7c38 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.9 2000/09/17 11:29:33 kls Exp $ + * $Id: svdrp.c 1.10 2000/09/17 13:39:37 kls Exp $ */ #define _GNU_SOURCE @@ -154,6 +154,16 @@ const char *HelpPages[] = { " Create a new timer. Settings must be in the same format as returned\n" " by the LSTT command. It is an error if a timer with the same channel,\n" " day, start and stop time already exists.", + "OVLF \n" + " Set the size, address depth and palette of the overlay.", + "OVLG \n" + " Set the size and position of the overlay.", + "OVLC \n" + " Set the overlay clipping rectangles.", + "OVLP \n" + " Set the picture parameters for the overlay.", + "OVLO 0 | 1\n" + " Switch the overlay on or off.", "UPDT \n" " Updates a timer. Settings must be in the same format as returned\n" " by the LSTT command. If a timer with the same channel, day, start\n" @@ -240,8 +250,11 @@ bool cSVDRP::Send(const char *s, int length) int wbytes = write(file, s, length); if (wbytes == length) return true; - if (wbytes < 0) + if (wbytes < 0) { LOG_ERROR; + file.Close(); + cDvbApi::PrimaryDvbApi->OvlO(false); + } else //XXX while...??? esyslog(LOG_ERR, "Wrote %d bytes to client while expecting %d\n", wbytes, length); return false; @@ -659,6 +672,106 @@ void cSVDRP::CmdNEWT(const char *Option) Reply(501, "Missing timer settings"); } +void cSVDRP::CmdOVLF(const char *Option) +{ + if (*Option) { + int SizeX = 0, SizeY = 0, Bpp = 0, Palette = 0, FbAddr = 0; + if (5 == sscanf(Option, "%d %d %x %d %d", &SizeX, &SizeY, &FbAddr, &Bpp, &Palette)) { + //somehow_set_overlay_geometry; + if (cDvbApi::PrimaryDvbApi->OvlF(SizeX, SizeY, FbAddr, Bpp, Palette)) + Reply(250, "Overlay framebuffer set"); + else + Reply(451, "Illegal overlay framebuffer settings"); + } + else + Reply(501, "Could not parse overlay framebuffer settings"); + } + else + Reply(501, "Missing overlay framebuffer settings"); +} + +void cSVDRP::CmdOVLG(const char *Option) +{ + if (*Option) { + int SizeX = 0, SizeY = 0, PosX = 0, PosY = 0; + if (4 == sscanf(Option, "%d %d %d %d", &SizeX, &SizeY, &PosX, &PosY)) { + //somehow_set_overlay_geometry; + if (cDvbApi::PrimaryDvbApi->OvlG(SizeX, SizeY, PosX, PosY)) + Reply(250, "Overlay geometry set"); + else + Reply(451, "Illegal overlay geometry settings"); + } + else + Reply(501, "Could not parse overlay geometry settings"); + } + else + Reply(501, "Missing overlay geometry settings"); +} + +void cSVDRP::CmdOVLC(const char *Option) +{ + if (*Option) { + int ClipCount = 0; + unsigned char s[2 * MAXCLIPRECTS * sizeof(CRect) + 2]; + if (2 == sscanf(Option, "%d %s", &ClipCount, s)) { + // Base16-decoding of CRect-array: + unsigned char *p = (unsigned char*)ovlClipRects; + int i = 0, size = sizeof(CRect)*ClipCount; + for (int j = 0; i < size; i++) { + p[i] = (s[j++] - 65); + p[i] += (s[j++] - 65) << 4; + } + if (((unsigned)ClipCount == (i / sizeof(CRect))) && (ClipCount >= 0)) { + // apply it: + if (cDvbApi::PrimaryDvbApi->OvlC(ClipCount, ovlClipRects)) + Reply(250, "Overlay-Clipping set"); + else + Reply(451, "Illegal overlay clipping settings"); + return; + } + } + Reply(501, "Error parsing Overlay-Clipping settings"); + } + else + Reply(501, "Missing Clipping settings"); +} + +void cSVDRP::CmdOVLP(const char *Option) +{ + if (*Option) { + int Brightness = 0, Colour = 0, Hue = 0, Contrast = 0; + if (4 == sscanf(Option, "%d %d %d %d", &Brightness, &Colour, &Hue, &Contrast)) { + //somehow_set_overlay_picture_settings; + if (cDvbApi::PrimaryDvbApi->OvlP(Brightness, Colour, Hue, Contrast)) + Reply(250, "Overlay picture settings set"); + else + Reply(451, "Illegal overlay picture settings"); + } + else + Reply(501, "Could not parse overlay picture settings"); + } + else + Reply(501, "Missing overlay picture settings"); +} + +void cSVDRP::CmdOVLO(const char *Option) +{ + if (*Option) { + int Value; + if (1 == sscanf(Option, "%d", &Value)) { + //somehow_set_overlay_picture_settings; + if (cDvbApi::PrimaryDvbApi->OvlO(Value)) + Reply(250, "Overlay capture set"); + else + Reply(451, "Error setting overlay capture"); + } + else + Reply(501, "Could not parse status"); + } + else + Reply(501, "Missing overlay capture status"); +} + void cSVDRP::CmdUPDT(const char *Option) { if (*Option) { @@ -712,6 +825,11 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("MOVT")) CmdMOVT(s); else if (CMD("NEWC")) CmdNEWC(s); else if (CMD("NEWT")) CmdNEWT(s); + else if (CMD("OVLF")) CmdOVLF(s); + else if (CMD("OVLG")) CmdOVLG(s); + else if (CMD("OVLC")) CmdOVLC(s); + else if (CMD("OVLP")) CmdOVLP(s); + else if (CMD("OVLO")) CmdOVLO(s); else if (CMD("UPDT")) CmdUPDT(s); else if (CMD("QUIT") || CMD("\x04")) Close(); diff --git a/svdrp.h b/svdrp.h index 134332a0..12eb11e3 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 1.5 2000/09/17 10:22:49 kls Exp $ + * $Id: svdrp.h 1.6 2000/09/17 13:22:04 kls Exp $ */ #ifndef __SVDRP_H #define __SVDRP_H +#include "dvbapi.h" #include "tools.h" class cSocket { @@ -29,6 +30,7 @@ class cSVDRP { private: cSocket socket; cFile file; + CRect ovlClipRects[MAXCLIPRECTS]; void Close(void); bool Send(const char *s, int length = -1); void Reply(int Code, const char *fmt, ...); @@ -46,6 +48,11 @@ private: void CmdMOVT(const char *Option); void CmdNEWC(const char *Option); void CmdNEWT(const char *Option); + void CmdOVLF(const char *Option); + void CmdOVLG(const char *Option); + void CmdOVLC(const char *Option); + void CmdOVLP(const char *Option); + void CmdOVLO(const char *Option); void CmdUPDT(const char *Option); void Execute(char *Cmd); public: