mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Implemented image grabbing
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										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 | ||||
|   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. | ||||
|   | ||||
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								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 | ||||
|   | ||||
							
								
								
									
										109
									
								
								dvbapi.c
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								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 | ||||
|   | ||||
							
								
								
									
										6
									
								
								dvbapi.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								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: | ||||
|   | ||||
							
								
								
									
										68
									
								
								svdrp.c
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								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); | ||||
|   | ||||
							
								
								
									
										3
									
								
								svdrp.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user