summaryrefslogtreecommitdiff
path: root/command/video.cpp
diff options
context:
space:
mode:
authorJochen Dolze <vdr@dolze.de>2010-10-03 23:30:02 +0200
committerJochen Dolze <vdr@dolze.de>2010-10-03 23:30:02 +0200
commit711def8f20707e2816c957d5d4edb8952b0876e6 (patch)
tree6b20a3570be535aabaae870d0104b0b165731429 /command/video.cpp
parent190b1e31a688117783b09a6edbbb15257655b9c2 (diff)
downloadvdr-plugin-markad-711def8f20707e2816c957d5d4edb8952b0876e6.tar.gz
vdr-plugin-markad-711def8f20707e2816c957d5d4edb8952b0876e6.tar.bz2
Added better detection for transparent logos, new logo filename scheme!
Diffstat (limited to 'command/video.cpp')
-rw-r--r--command/video.cpp431
1 files changed, 238 insertions, 193 deletions
diff --git a/command/video.cpp b/command/video.cpp
index 06a9bf3..95c48b4 100644
--- a/command/video.cpp
+++ b/command/video.cpp
@@ -55,6 +55,7 @@ cMarkAdLogo::cMarkAdLogo(MarkAdContext *maContext)
LOGOWIDTH=LOGO_DEFWIDTH;
}
+ pixfmt_info=false;
Clear();
}
@@ -64,92 +65,115 @@ void cMarkAdLogo::Clear()
area.status=UNINITIALIZED;
}
-int cMarkAdLogo::Load(char *directory, char *file)
+int cMarkAdLogo::Load(char *directory, char *file, int plane)
{
+ if ((plane<0) || (plane>3)) return -3;
+
char *path;
- if (asprintf(&path,"%s/%s.pgm",directory,file)==-1) return -3;
+ if (asprintf(&path,"%s/%s-P%i.pgm",directory,file,plane)==-1) return -3;
// Load mask
FILE *pFile;
- area.valid=false;
- area.corner=-1;
+ area.valid[plane]=false;
pFile=fopen(path, "rb");
free(path);
- if (!pFile) return -1;
+ if (!pFile)
+ {
+ if (plane>0) return 0; // only report for plane0
+ return -1;
+ }
- if (fscanf(pFile, "P5\n#C%i %i\n%d %d\n255\n#", &area.corner,&area.mpixel,&LOGOWIDTH,&LOGOHEIGHT)) {};
+ int width,height;
+ if (fscanf(pFile, "P5\n#C%i %i\n%d %d\n255\n#", &area.corner,&area.mpixel[plane],&width,&height)!=4)
+ {
+ fclose(pFile);
+ return -2;
+ }
- if (LOGOHEIGHT==255)
+ if (height==255)
{
- LOGOHEIGHT=LOGOWIDTH;
- LOGOWIDTH=area.mpixel;
- area.mpixel=0;
+ height=width;
+ width=area.mpixel[plane];
+ area.mpixel[plane]=0;
}
- if ((LOGOWIDTH<=0) || (LOGOHEIGHT<=0) || (LOGOWIDTH>LOGO_MAXWIDTH) || (LOGOHEIGHT>LOGO_MAXHEIGHT) ||
+ if ((width<=0) || (height<=0) || (width>LOGO_MAXWIDTH) || (height>LOGO_MAXHEIGHT) ||
(area.corner<TOP_LEFT) || (area.corner>BOTTOM_RIGHT))
{
fclose(pFile);
return -2;
}
- if (fread(&area.mask,1,LOGOWIDTH*LOGOHEIGHT,pFile)!=(size_t) (LOGOWIDTH*LOGOHEIGHT)) return -2;
+ if (fread(&area.mask[plane],1,width*height,pFile)!=(size_t) (width*height)) return -2;
- if (!area.mpixel)
+ if (!area.mpixel[plane])
{
- for (int i=0; i<LOGOWIDTH*LOGOHEIGHT; i++)
+ for (int i=0; i<width*height; i++)
{
- if (!area.mask[i]) area.mpixel++;
+ if (!area.mask[plane][i]) area.mpixel[plane]++;
}
}
+ if (!plane)
+ {
+ // plane 0 is the largest -> use this values
+ LOGOWIDTH=width;
+ LOGOHEIGHT=height;
+ }
+
fclose(pFile);
- area.valid=true;
+ area.valid[plane]=true;
return 0;
}
-void cMarkAdLogo::Save(int framenumber, uchar *picture)
+void cMarkAdLogo::Save(int framenumber, uchar picture[4][MAXPIXEL], int plane)
{
if (!macontext) return;
-
+ if ((plane<0) || (plane>3)) return;
+ if (!macontext->Info.ChannelName) return;
+ if (!macontext->Video.Info.Width) return;
+ if (!macontext->Video.Info.Height) return;
+ if (!macontext->Video.Data.Valid) return;
+ if (!macontext->Video.Data.PlaneLinesize[plane]) return;
char *buf=NULL;
- if (asprintf(&buf,"%s/%06d-%s-A%i_%i.pgm","/tmp/",framenumber,
- macontext->Info.ChannelID,
- area.aspectratio.Num,area.aspectratio.Den)!=-1)
+ if (asprintf(&buf,"%s/%06d-%s-A%i_%i-P%i.pgm","/tmp/",framenumber,
+ macontext->Info.ChannelName,
+ area.aspectratio.Num,area.aspectratio.Den,plane)==-1) return;
+
+ // Open file
+ FILE *pFile=fopen(buf, "wb");
+ if (pFile==NULL)
{
- // Open file
- FILE *pFile=fopen(buf, "wb");
- if (pFile==NULL)
- {
- free(buf);
- return;
- }
+ free(buf);
+ return;
+ }
- // Write header
- fprintf(pFile, "P5\n#C%i\n%d %d\n255\n", area.corner, LOGOWIDTH,LOGOHEIGHT);
+ int width=LOGOWIDTH;
+ int height=LOGOHEIGHT;
- // Write pixel data
- if (fwrite(picture,1,LOGOWIDTH*LOGOHEIGHT,pFile)) {};
- // Close file
- fclose(pFile);
- free(buf);
+ if (plane>0)
+ {
+ width/=2;
+ height/=2;
}
-}
-int cMarkAdLogo::Detect(int framenumber, int *logoframenumber)
-{
- // Detection is made with Sobel-Operator
+ // Write header
+ fprintf(pFile, "P5\n#C%i\n%d %d\n255\n", area.corner,width,height);
- if (!macontext) return 0;
- if (!macontext->Video.Info.Width) return 0;
- if (!macontext->Video.Info.Height) return 0;
- if (!macontext->Video.Data.Valid) return 0;
+ // Write pixel data
+ if (fwrite(picture[plane],1,width*height,pFile)) {};
+ // Close file
+ fclose(pFile);
+ free(buf);
+}
- if (area.corner>BOTTOM_RIGHT) return 0;
- if (area.corner<TOP_LEFT) return 0;
+int cMarkAdLogo::SobelPlane(int plane)
+{
+ if ((plane<0) || (plane>3)) return 0;
+ if (!macontext->Video.Data.PlaneLinesize[plane]) return 0;
int xstart,xend,ystart,yend;
@@ -183,177 +207,196 @@ int cMarkAdLogo::Detect(int framenumber, int *logoframenumber)
return 0;
}
- int SUMA=0;
- for (int Y=ystart; Y<=yend-1; Y++)
+ if (macontext->Video.Info.Pix_Fmt!=0)
{
- for (int X=xstart; X<=xend-1; X++)
+ if (!pixfmt_info)
{
- int val=macontext->Video.Data.Plane[0][X+(Y*macontext->Video.Data.PlaneLinesize[0])];
- area.source[(X-xstart)+(Y-ystart)*LOGOWIDTH]=val;
- SUMA+=val;
+ esyslog("unknown pix_fmt %i, please report!",macontext->Video.Info.Pix_Fmt);
+ pixfmt_info=true;
}
+ return 0;
}
- SUMA/=(LOGOWIDTH*LOGOHEIGHT);
-#if 0
- if (SUMA>=100)
+ int boundary=15;
+ int cutval=127;
+ int width=LOGOWIDTH;
+
+ if (plane>0)
{
- int maxval=(int) SUMA;
- SUMA=0;
- for (int Y=ystart; Y<=yend-1; Y++)
- {
- for (int X=xstart; X<=xend-1; X++)
- {
- int val=macontext->Video.Data.Plane[0][X+(Y*macontext->Video.Data.PlaneLinesize[0])];
- val=(int) (((double) val- (double) maxval/1.4)*1.4);
- if (val>maxval) val=maxval;
- if (val<0) val=0;
- area.source[(X-xstart)+(Y-ystart)*LOGOWIDTH]=val;
- SUMA+=val;
- }
- }
- SUMA/=(LOGOWIDTH*LOGOHEIGHT);
+ xstart/=2;
+ xend/=2;
+ ystart/=2;
+ yend/=2;
+ boundary/=2;
+ cutval/=2;
+ width/=2;
}
-#endif
- int ret=NOCHANGE;
- if ((SUMA<100) || ((area.status==LOGO) && (SUMA<180)))
+ int SUM;
+ int sumX,sumY;
+ area.rpixel[plane]=0;
+ if (!plane) area.intensity=0;
+ for (int Y=ystart; Y<=yend-1; Y++)
{
-
- int SUM;
- int sumX,sumY;
- area.rpixel=0;
- for (int Y=ystart; Y<=yend-1; Y++)
+ for (int X=xstart; X<=xend-1; X++)
{
- for (int X=xstart; X<=xend-1; X++)
+ if (!plane)
{
- sumX=0;
- sumY=0;
-
- // image boundaries
- if (Y<(ystart+15) || Y>(yend-15))
- SUM=0;
- else if (X<(xstart+15) || X>(xend-15))
- SUM=0;
- // convolution starts here
- else
+ area.intensity+=macontext->Video.Data.Plane[plane][X+(Y*macontext->Video.Data.PlaneLinesize[plane])];
+ }
+ sumX=0;
+ sumY=0;
+
+ // image boundaries
+ if (Y<(ystart+boundary) || Y>(yend-boundary))
+ SUM=0;
+ else if (X<(xstart+boundary) || X>(xend-boundary))
+ SUM=0;
+ // convolution starts here
+ else
+ {
+ // X Gradient approximation
+ for (int I=-1; I<=1; I++)
{
- // X Gradient approximation
- for (int I=-1; I<=1; I++)
+ for (int J=-1; J<=1; J++)
{
- for (int J=-1; J<=1; J++)
- {
- sumX=sumX+ (int) ((*(macontext->Video.Data.Plane[0]+X+I+
- (Y+J)*macontext->Video.Data.PlaneLinesize[0]))
- *GX[I+1][J+1]);
- }
+ sumX=sumX+ (int) ((*(macontext->Video.Data.Plane[plane]+X+I+
+ (Y+J)*macontext->Video.Data.PlaneLinesize[plane]))
+ *GX[I+1][J+1]);
}
+ }
- // Y Gradient approximation
- for (int I=-1; I<=1; I++)
+ // Y Gradient approximation
+ for (int I=-1; I<=1; I++)
+ {
+ for (int J=-1; J<=1; J++)
{
- for (int J=-1; J<=1; J++)
- {
- sumY=sumY+ (int) ((*(macontext->Video.Data.Plane[0]+X+I+
- (Y+J)*macontext->Video.Data.PlaneLinesize[0]))*
- GY[I+1][J+1]);
- }
+ sumY=sumY+ (int) ((*(macontext->Video.Data.Plane[plane]+X+I+
+ (Y+J)*macontext->Video.Data.PlaneLinesize[plane]))*
+ GY[I+1][J+1]);
}
-
- // Gradient Magnitude approximation
- SUM = abs(sumX) + abs(sumY);
}
- if (SUM>=127) SUM=255;
- if (SUM<127) SUM=0;
+ // Gradient Magnitude approximation
+ SUM = abs(sumX) + abs(sumY);
+ }
- int val = 255-(uchar) SUM;
+ if (SUM>=cutval) SUM=255;
+ if (SUM<cutval) SUM=0;
- area.sobel[(X-xstart)+(Y-ystart)*LOGOWIDTH]=val;
+ int val = 255-(uchar) SUM;
- area.result[(X-xstart)+(Y-ystart)*LOGOWIDTH]=
- (area.mask[(X-xstart)+(Y-ystart)*LOGOWIDTH] + val) & 255;
+ area.sobel[plane][(X-xstart)+(Y-ystart)*width]=val;
- if (!area.result[(X-xstart)+(Y-ystart)*LOGOWIDTH]) area.rpixel++;
+ area.result[plane][(X-xstart)+(Y-ystart)*width]=
+ (area.mask[plane][(X-xstart)+(Y-ystart)*width] + val) & 255;
+
+ if (!area.result[plane][(X-xstart)+(Y-ystart)*width]) area.rpixel[plane]++;
+#ifdef VDRDEBUG
+ val=macontext->Video.Data.Plane[plane][X+(Y*macontext->Video.Data.PlaneLinesize[plane])];
+ area.source[plane][(X-xstart)+(Y-ystart)*width]=val;
+#endif
- }
}
- if (macontext->Options.LogoExtraction==-1)
+ }
+ if (!plane) area.intensity/=(LOGOHEIGHT*width);
+
+ return 1;
+}
+
+int cMarkAdLogo::Detect(int framenumber, int *logoframenumber)
+{
+ bool extract=(macontext->Options.LogoExtraction!=-1);
+
+ int rpixel=0,mpixel=0;
+ int processed=0;
+ for (int plane=0; plane<4; plane++)
+ {
+ if ((area.valid[plane]) || (extract))
{
- if (area.status==UNINITIALIZED)
- {
- // Initialize
- if (area.rpixel>(area.mpixel*LOGO_VMARK))
- {
- area.status=LOGO;
- }
- else
- {
- area.status=NOLOGO;
- }
- }
+ if (SobelPlane(plane)) processed++;
+ }
+ if (extract)
+ {
+ Save(framenumber,area.sobel,plane);
+ }
+ else
+ {
+ rpixel+=area.rpixel[plane];
+ mpixel+=area.mpixel[plane];
+ }
+ }
+ if (extract) return NOCHANGE;
+ if (!processed) return ERROR;
+
+ if (processed==1)
+ {
+ if ((area.intensity>100) || (area.status!=LOGO) &&
+ (area.intensity>180)) return NOCHANGE;
+ }
+
+ int ret=NOCHANGE;
+ if (area.status==UNINITIALIZED)
+ {
+ // Initialize
+ if (rpixel>(mpixel*LOGO_VMARK))
+ {
+ area.status=LOGO;
+ }
+ else
+ {
+ area.status=NOLOGO;
+ }
+ }
- if (area.rpixel>=(area.mpixel*LOGO_VMARK))
+ if (rpixel>=(mpixel*LOGO_VMARK))
+ {
+ if (area.status==NOLOGO)
+ {
+ if (area.counter>=LOGO_VMAXCOUNT)
{
- if (area.status==NOLOGO)
- {
- if (area.counter>=LOGO_VMAXCOUNT)
- {
- area.status=ret=LOGO;
- *logoframenumber=area.framenumber;
- area.counter=0;
- }
- else
- {
- if (!area.counter) area.framenumber=framenumber;
- area.counter++;
- }
- }
- else
- {
- area.framenumber=framenumber;
- area.counter=0;
- }
+ area.status=ret=LOGO;
+ *logoframenumber=area.framenumber;
+ area.counter=0;
}
-
- if (area.rpixel<(area.mpixel*LOGO_IMARK))
+ else
{
- if (area.status==LOGO)
- {
- if (area.counter>=LOGO_IMAXCOUNT)
- {
- area.status=ret=NOLOGO;
- *logoframenumber=area.framenumber;
- area.counter=0;
- }
- else
- {
- area.counter++;
- }
- }
- else
- {
- area.counter=0;
- }
+ if (!area.counter) area.framenumber=framenumber;
+ area.counter++;
}
+ }
+ else
+ {
+ area.framenumber=framenumber;
+ area.counter=0;
+ }
+ }
- if ((area.rpixel<(area.mpixel*LOGO_VMARK)) && (area.rpixel>(area.mpixel*LOGO_IMARK)))
+ if (rpixel<(mpixel*LOGO_IMARK))
+ {
+ if (area.status==LOGO)
+ {
+ if (area.counter>=LOGO_IMAXCOUNT)
{
+ area.status=ret=NOLOGO;
+ *logoframenumber=area.framenumber;
area.counter=0;
}
-
-#if 0
- printf("%5i %3i %4i %4i %i %i %i\n",framenumber,SUMA,area.rpixel,area.mpixel,
- (area.rpixel>=(area.mpixel*LOGO_VMARK)),(area.rpixel<(area.mpixel*LOGO_IMARK)),
- area.counter );
- Save(framenumber,area.sobel); // TODO: JUST FOR DEBUGGING!
-#endif
+ else
+ {
+ area.counter++;
+ }
}
else
{
- Save(framenumber,area.sobel);
+ area.counter=0;
}
}
+
+ if ((rpixel<(mpixel*LOGO_VMARK)) && (rpixel>(mpixel*LOGO_IMARK)))
+ {
+ area.counter=0;
+ }
return ret;
}
@@ -362,32 +405,35 @@ int cMarkAdLogo::Process(int FrameNumber, int *LogoFrameNumber)
if (!macontext) return ERROR;
if (!macontext->Video.Data.Valid) return ERROR;
if (!macontext->Video.Info.Width) return ERROR;
+ if (!macontext->Video.Info.Height) return ERROR;
if (!macontext->LogoDir) return ERROR;
- if (!macontext->Info.ChannelID) return ERROR;
+ if (!macontext->Info.ChannelName) return ERROR;
if (macontext->Options.LogoExtraction==-1)
{
-
if ((area.aspectratio.Num!=macontext->Video.Info.AspectRatio.Num) ||
(area.aspectratio.Den!=macontext->Video.Info.AspectRatio.Den))
{
- area.valid=false; // just to be sure!
char *buf=NULL;
- if (asprintf(&buf,"%s-A%i_%i",macontext->Info.ChannelID,
+ if (asprintf(&buf,"%s-A%i_%i",macontext->Info.ChannelName,
macontext->Video.Info.AspectRatio.Num,macontext->Video.Info.AspectRatio.Den)!=-1)
{
- int ret=Load(macontext->LogoDir,buf);
- switch (ret)
+ area.corner=-1;
+ for (int plane=0; plane<4; plane++)
{
- case -1:
- isyslog("no logo for %s",buf);
- break;
- case -2:
- esyslog("format error in %s",buf);
- break;
- case -3:
- esyslog("cannot load %s",buf);
- break;
+ int ret=Load(macontext->LogoDir,buf,plane);
+ switch (ret)
+ {
+ case -1:
+ isyslog("no logo for %s",buf);
+ break;
+ case -2:
+ esyslog("format error in %s",buf);
+ break;
+ case -3:
+ esyslog("cannot load %s",buf);
+ break;
+ }
}
free(buf);
}
@@ -408,10 +454,9 @@ int cMarkAdLogo::Process(int FrameNumber, int *LogoFrameNumber)
{
LOGOHEIGHT=macontext->Options.LogoHeight;
}
- area.valid=true;
}
- if (!area.valid) return ERROR;
+ //if (!area.valid) return ERROR;
return Detect(FrameNumber,LogoFrameNumber);
}