summaryrefslogtreecommitdiff
path: root/markad-standalone.cpp
diff options
context:
space:
mode:
authorJochen Dolze <vdr@dolze.de>2010-03-30 18:49:58 +0200
committerJochen Dolze <vdr@dolze.de>2010-03-30 18:49:58 +0200
commit74cdd9ffa1d0e5f74942051e7e22e07542929c03 (patch)
treee59472547b1ed3543b8e2d1d0e2a7c52fcb24c04 /markad-standalone.cpp
parent6446f24dce1b30fa341b7de078ca4385d1378457 (diff)
downloadvdr-plugin-markad-74cdd9ffa1d0e5f74942051e7e22e07542929c03.tar.gz
vdr-plugin-markad-74cdd9ffa1d0e5f74942051e7e22e07542929c03.tar.bz2
Changed directory structure, added Makefiles
Diffstat (limited to 'markad-standalone.cpp')
-rw-r--r--markad-standalone.cpp1632
1 files changed, 0 insertions, 1632 deletions
diff --git a/markad-standalone.cpp b/markad-standalone.cpp
deleted file mode 100644
index 9d4cb82..0000000
--- a/markad-standalone.cpp
+++ /dev/null
@@ -1,1632 +0,0 @@
-/*
- * markad-standalone.cpp: A program for the Video Disk Recorder
- *
- * See the README file for copyright information and how to reach the author.
- *
- */
-
-#include "markad-standalone.h"
-
-bool SYSLOG=false;
-cMarkAdStandalone *cmasta=NULL;
-int SysLogLevel=2;
-
-void syslog_with_tid(int priority, const char *format, ...)
-{
- va_list ap;
- if (SYSLOG)
- {
- char fmt[255];
- snprintf(fmt, sizeof(fmt), "[%d] %s", getpid(), format);
- va_start(ap, format);
- vsyslog(priority, fmt, ap);
- va_end(ap);
- }
- else
- {
- char fmt[255];
- snprintf(fmt, sizeof(fmt), "markad: [%d] %s", getpid(), format);
- va_start(ap, format);
- vprintf(fmt,ap);
- va_end(ap);
- printf("\n");
- fflush(stdout);
- }
-}
-
-void cMarkAdStandalone::AddStartMark()
-{
- char *buf;
- if (asprintf(&buf,"start of recording (0)")!=-1)
- {
- marks.Add(MT_COMMON,0,buf);
- isyslog(buf);
- free(buf);
- }
-}
-
-bool cMarkAdStandalone::CheckFirstMark()
-{
- if (marksAligned) return true;
-
- // Check the second mark
- clMark *second=marks.GetNext(0);
- if (!second) return false;
-
- if ((second->type==MT_LOGOSTART) || (second->type==MT_BORDERSTART) ||
- (second->type==MT_CHANNELSTART))
- {
- clMark *first=marks.Get(0);
- if (first) marks.Del(first);
- marksAligned=true;
- }
-
- if ((second->type==MT_LOGOSTOP) || (second->type==MT_BORDERSTOP) ||
- (second->type==MT_CHANNELSTOP))
- {
- marksAligned=true;
- }
-
- // If we have an aspectchange, check the next aspectchange mark
- // and the difference between
- if ((second->type==MT_ASPECTCHANGE) && (macontext.Video.Info.FramesPerSecond>0))
- {
- clMark *next=marks.GetNext(second->position,MT_ASPECTCHANGE);
- if (next)
- {
- int MAXPOSDIFF=(int) (macontext.Video.Info.FramesPerSecond*60*13);
- if ((next->position-second->position)>MAXPOSDIFF)
- {
- clMark *first=marks.Get(0);
- if (first) marks.Del(first);
- marksAligned=true;
- }
- }
- }
- return marksAligned;
-}
-
-void cMarkAdStandalone::AddMark(MarkAdMark *Mark)
-{
- if (!Mark) return;
- if (!Mark->Type) return;
-
- if (Mark->Type==MT_LOGOSTART)
- {
- // check if last mark is an aspectratio change
- clMark *prev=marks.GetLast();
- if ((prev) && (prev->type==MT_ASPECTCHANGE))
- {
- if ((Mark->Position-prev->position)<20)
- {
- if (Mark->Comment) isyslog(Mark->Comment);
- isyslog("aspectratio change in short distance, moving mark (%i->%i)",Mark->Position,prev->position);
- marks.Add(MT_MOVED,prev->position,Mark->Comment);
- return;
- }
- }
- }
-
- if (((Mark->Type & 0xF0)==MT_LOGOCHANGE) && (macontext.Video.Info.FramesPerSecond>0))
- {
- // check if the distance to the last mark is large enough!
- clMark *prev=marks.GetLast();
- if ((prev) && ((prev->type & 0xF0)==MT_LOGOCHANGE))
- {
- int MINMARKDIFF=(int) (macontext.Video.Info.FramesPerSecond*60*2);
- if ((Mark->Position-prev->position)<MINMARKDIFF)
- {
- if (Mark->Comment) isyslog(Mark->Comment);
- isyslog("logo distance too short, deleting (%i,%i)",prev->position,Mark->Position);
- marks.Del(prev);
- return;
- }
- }
- }
-
- if (((Mark->Type & 0xF0)==MT_BORDERCHANGE) && (Mark->Position>25000) &&
- (!macontext.Video.Options.IgnoreLogoDetection))
- {
- isyslog("border change detected. logo detection disabled");
- macontext.Video.Options.IgnoreLogoDetection=true;
- marks.Del(MT_LOGOSTART);
- marks.Del(MT_LOGOSTOP);
- }
-
- if ((((Mark->Type & 0xF0)==MT_CHANNELCHANGE) || (Mark->Type==MT_ASPECTCHANGE)) &&
- (Mark->Position>25000) && (bDecodeVideo))
- {
- bool TurnOff=true;
- if (Mark->Type==MT_ASPECTCHANGE)
- {
- if (marks.Count(MT_ASPECTCHANGE)<3)
- {
- TurnOff=false;
- }
- }
-
- if (Mark->Type==MT_CHANNELCHANGE)
- {
- if ((marks.Count(MT_CHANNELSTART)+marks.Count(MT_CHANNELSTOP))<3)
- {
- TurnOff=false;
- }
- }
-
- if (TurnOff)
- {
- isyslog("%s change detected. logo/border detection disabled",
- Mark->Type==MT_ASPECTCHANGE ? "aspectratio" : "audio channel");
-
- bDecodeVideo=false;
- macontext.Video.Data.Valid=false;
- marks.Del(MT_LOGOSTART);
- marks.Del(MT_LOGOSTOP);
- marks.Del(MT_BORDERSTART);
- marks.Del(MT_BORDERSTOP);
- }
- }
- CheckFirstMark();
- clMark *old=marks.Get(Mark->Position);
- if (old)
- {
- // Aspect- / Channelchange wins over Logo/Border
- if (((old->type & 0xF0)!=MT_ASPECTCHANGE) && ((old->type & 0xF0)!=MT_CHANNELCHANGE))
- {
- if (Mark->Comment) isyslog(Mark->Comment);
- marks.Add(Mark->Type,Mark->Position,Mark->Comment);
- }
- }
- else
- {
- if (Mark->Comment) isyslog(Mark->Comment);
- marks.Add(Mark->Type,Mark->Position,Mark->Comment);
- }
-}
-
-void cMarkAdStandalone::RateMarks()
-{
- if (macontext.Info.Length)
- {
- if ((marks.Count()>3) && (macontext.Info.Length>30))
- {
- int logomarks=marks.Count(MT_LOGOSTART) + marks.Count(MT_LOGOSTOP);
- int audiomarks=marks.Count(MT_CHANNELSTART) + marks.Count(MT_CHANNELSTOP);
-
- // If we have logomarks or audiomarks get rid of the aspect changes,
- // cause if we have a recording with (>=3) aspect changes the
- // logomarks were already deleted in AddMark
- if ((logomarks) || (audiomarks))
- {
- marks.Del(MT_ASPECTCHANGE);
- }
- }
- }
-
- // Check the first mark again
- CheckFirstMark();
-
- // TODO: more checks
-}
-
-void cMarkAdStandalone::SaveFrame(int frame)
-{
- if (!macontext.Video.Info.Width) return;
- if (!macontext.Video.Data.Valid) return;
-
- FILE *pFile;
- char szFilename[256];
-
- // Open file
- sprintf(szFilename, "/tmp/frame%06d.pgm", frame);
- pFile=fopen(szFilename, "wb");
- if (pFile==NULL)
- return;
-
- // Write header
- fprintf(pFile, "P5\n%d %d\n255\n", macontext.Video.Data.PlaneLinesize[0],
- macontext.Video.Info.Height);
-
- // Write pixel data
- fwrite(macontext.Video.Data.Plane[0],1,
- macontext.Video.Data.PlaneLinesize[0]*macontext.Video.Info.Height,pFile);
- // Close file
- fclose(pFile);
-}
-
-void cMarkAdStandalone::CheckIndex(const char *Directory)
-{
- // Here we check if the index is more
- // advanced than our framecounter.
- // If not we wait. If we wait too much,
- // we discard this check...
-
-#define WAITTIME 10
-
- if (!indexFile) return;
- if (sleepcnt>=2) return; // we already slept too much
-
- bool notenough=true;
- do
- {
- struct stat statbuf;
- if (stat(indexFile,&statbuf)==-1) return;
-
- int maxframes=statbuf.st_size/8;
- if (maxframes<(framecnt+200))
- {
- if ((difftime(time(NULL),statbuf.st_mtime))>=10) return; // "old" file
- marks.Save(Directory,macontext.Video.Info.FramesPerSecond,isTS);
- sleep(WAITTIME); // now we sleep and hopefully the index will grow
- waittime+=WAITTIME;
- if (errno==EINTR) return;
- sleepcnt++;
- if (sleepcnt>=2)
- {
- esyslog("no new data after %i seconds, skipping wait!",
- sleepcnt*WAITTIME);
- notenough=false; // something went wrong?
- }
- }
- else
- {
- sleepcnt=0;
- notenough=false;
- }
- }
- while (notenough);
-}
-
-bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
-{
- if (!Directory) return false;
- if (!Number) return false;
-
- CheckIndex(Directory);
- if (abort) return false;
-
- const int datalen=385024;
- uchar data[datalen];
-
- char *fbuf;
- if (isTS)
- {
- if (asprintf(&fbuf,"%s/%05i.ts",Directory,Number)==-1) return false;
- }
- else
- {
- if (asprintf(&fbuf,"%s/%03i.vdr",Directory,Number)==-1) return false;
- }
-
- int f=open(fbuf,O_RDONLY);
- free(fbuf);
- if (f==-1) return false;
-
- int dataread;
- dsyslog("processing file %05i",Number);
-
- while ((dataread=read(f,data,datalen))>0)
- {
- if (abort) break;
- MarkAdMark *mark=NULL;
-
- if ((video_demux) && (video) && (streaminfo))
- {
- uchar *pkt;
- int pktlen;
-
- uchar *tspkt = data;
- int tslen = dataread;
-
- while (tslen>0)
- {
- int len=video_demux->Process(macontext.Info.VPid,tspkt,tslen,&pkt,&pktlen);
- if (len<0)
- {
- break;
- }
- else
- {
- if (pkt)
- {
- if (streaminfo->FindVideoInfos(&macontext,pkt,pktlen))
- {
- if (!framecnt)
- {
- isyslog("%s %i%c",(macontext.Video.Info.Height>576) ? "HDTV" : "SDTV",
- macontext.Video.Info.Height,
- macontext.Video.Info.Interlaced ? 'i' : 'p');
- AddStartMark();
- }
- //printf("%05i( %c )\n",framecnt,frametypes[macontext.Video.Info.Pict_Type]);
- framecnt++;
- if (macontext.Video.Info.Pict_Type==MA_I_TYPE)
- {
- lastiframe=iframe;
- iframe=framecnt-1;
- }
- }
-
- bool dRes=true;
- if ((decoder) && (bDecodeVideo)) dRes=decoder->DecodeVideo(&macontext,pkt,pktlen);
- if (dRes)
- {
- if ((framecnt-iframe)<=3)
- {
- mark=video->Process(lastiframe);
- AddMark(mark);
- //SaveFrame(lastiframe); // TODO: JUST FOR DEBUGGING!
- }
- }
- }
- tspkt+=len;
- tslen-=len;
- }
- }
- }
-
- if ((ac3_demux) && (streaminfo) && (audio))
- {
- uchar *pkt;
- int pktlen;
-
- uchar *tspkt = data;
- int tslen = dataread;
-
- while (tslen>0)
- {
- int len=ac3_demux->Process(macontext.Info.DPid,tspkt,tslen,&pkt,&pktlen);
- if (len<0)
- {
- break;
- }
- else
- {
- if (pkt)
- {
- if (streaminfo->FindAC3AudioInfos(&macontext,pkt,pktlen))
- {
- if ((!isTS) && (!noticeVDR_AC3))
- {
- dsyslog("found AC3");
- if (mp2_demux)
- {
- delete mp2_demux;
- mp2_demux=NULL;
- }
- noticeVDR_AC3=true;
- }
- mark=audio->Process(lastiframe);
- AddMark(mark);
- }
- }
- tspkt+=len;
- tslen-=len;
- }
- }
- }
-
- if ((mp2_demux) && (decoder) && (audio) && (bDecodeAudio))
- {
- uchar *pkt;
- int pktlen;
-
- uchar *tspkt = data;
- int tslen = dataread;
-
- while (tslen>0)
- {
- int len=mp2_demux->Process(macontext.Info.APid,tspkt,tslen,&pkt,&pktlen);
- if (len<0)
- {
- break;
- }
- else
- {
- if (pkt)
- {
- if (decoder->DecodeMP2(&macontext,pkt,pktlen))
- {
- if ((!isTS) && (!noticeVDR_MP2))
- {
- dsyslog("found MP2");
- noticeVDR_MP2=true;
- }
- mark=audio->Process(lastiframe);
- AddMark(mark);
- }
- }
- tspkt+=len;
- tslen-=len;
- }
- }
- }
-
- CheckIndex(Directory);
- if (abort)
- {
- if (f!=-1) close(f);
- return false;
- }
- }
- close(f);
- return true;
-}
-
-void cMarkAdStandalone::Process(const char *Directory)
-{
- if (abort) return;
-
- struct timeval tv1,tv2;
- struct timezone tz;
-
- gettimeofday(&tv1,&tz);
-
- if (bBackupMarks) marks.Backup(Directory,isTS);
-
- for (int i=1; i<=MaxFiles; i++)
- {
- if (abort) break;
- if (!ProcessFile(Directory,i))
- {
- break;
- }
- }
- if (abort)
- {
- isyslog("aborted");
- }
- else
- {
- if (lastiframe)
- {
- MarkAdMark tempmark;
- tempmark.Type=MT_COMMON;
- tempmark.Position=lastiframe;
- char *buf;
-
- if (asprintf(&buf,"stop of recording (%i)",lastiframe)!=-1)
- {
- tempmark.Comment=buf;
- AddMark(&tempmark);
- free(buf);
- }
- }
-
- gettimeofday(&tv2,&tz);
- time_t sec;
- suseconds_t usec;
- sec=tv2.tv_sec-tv1.tv_sec;
- usec=tv2.tv_usec-tv1.tv_usec;
- if (usec<0)
- {
- usec+=1000000;
- sec--;
- }
- RateMarks();
- if (marks.Save(Directory,macontext.Video.Info.FramesPerSecond,isTS))
- {
- bool bIndexError=false;
- if (marks.CheckIndex(Directory,isTS,&bIndexError))
- {
- if (bIndexError)
- {
- if ((macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264) && (!isTS))
- {
- esyslog("index doesn't match marks, sorry you're lost");
- }
- else
- {
- esyslog("index doesn't match marks%s",
- isTS ? ", please recreate it" : ", please run genindex");
- }
- }
- }
- }
-
- double etime,ftime=0,ptime=0;
- etime=sec+((double) usec/1000000)-waittime;
- if (etime>0) ftime=framecnt/etime;
- if (macontext.Video.Info.FramesPerSecond>0)
- ptime=ftime/macontext.Video.Info.FramesPerSecond;
- isyslog("processed time %.2fs, %i frames, %.1f fps, %.1f pps",
- etime,framecnt,ftime,ptime);
-
- }
-}
-
-bool cMarkAdStandalone::LoadInfo(const char *Directory)
-{
- char *buf;
- if (isTS)
- {
- if (asprintf(&buf,"%s/info",Directory)==-1) return false;
- }
- else
- {
- if (asprintf(&buf,"%s/info.vdr",Directory)==-1) return false;
- }
-
- FILE *f;
- f=fopen(buf,"r");
- if (!f)
- {
- free(buf);
- return false;
- }
-
- char *line=NULL;
- size_t length;
- while (getline(&line,&length,f)!=-1)
- {
- if (line[0]=='C')
- {
- int ntok=0;
- char *str=line,*tok;
- while ((tok=strtok(str," ")))
- {
- if (ntok==1) macontext.Info.ChannelID=strdup(tok);
- ntok++;
- str=NULL;
- }
- if (macontext.Info.ChannelID)
- {
- for (int i=0; i<(int) strlen(macontext.Info.ChannelID); i++)
- {
- if (macontext.Info.ChannelID[i]=='.') macontext.Info.ChannelID[i]='_';
- }
- }
- }
- if (line[0]=='E')
- {
- int result=sscanf(line,"%*c %*i %*i %i %*i %*x",&macontext.Info.Length);
- if (result==1)
- {
- macontext.Info.Length/=60;
- }
- else
- {
- macontext.Info.Length=0;
- }
- if ((bIgnoreAudioInfo) && (bIgnoreVideoInfo)) break;
- }
- if (line[0]=='X')
- {
- int stream=0,type=0;
- char descr[256]="";
- int result=sscanf(line,"%*c %i %i %250c",&stream,&type,(char *) &descr);
- if ((result!=0) && (result!=EOF))
- {
- if ((stream==1) && (!bIgnoreVideoInfo))
- {
- if ((type!=1) && (type!=5))
- {
- // we dont have 4:3, so ignore AspectRatio-Changes
- macontext.Video.Options.IgnoreAspectRatio=true;
- isyslog("broadcasts aspectratio is not 4:3, disabling aspect ratio");
- }
- }
-
- if ((stream==2) && (!bIgnoreAudioInfo))
- {
- if (type==5)
- {
- // if we have DolbyDigital 2.0 disable AC3
- if (strchr(descr,'2'))
- {
- macontext.Info.DPid.Num=0;
- isyslog("broadcast with DolbyDigital2.0, disabling AC3 decoding");
- }
- // if we have DolbyDigital 5.1 disable video decoding
- if (strchr(descr,'5'))
- {
- bDecodeVideo=false;
- isyslog("broadcast with DolbyDigital5.1, disabling video decoding");
- }
-
- }
- }
- }
- }
- }
- if (line) free(line);
-
- fclose(f);
- free(buf);
- if (!macontext.Info.ChannelID)
- {
- return false;
- }
- else
- {
- return true;
- }
-}
-
-bool cMarkAdStandalone::CheckTS(const char *Directory)
-{
- MaxFiles=0;
- isTS=false;
- if (!Directory) return false;
- char *buf;
- if (asprintf(&buf,"%s/00001.ts",Directory)==-1) return false;
- struct stat statbuf;
- if (stat(buf,&statbuf)==-1)
- {
- if (errno!=ENOENT)
- {
- free(buf);
- return false;
- }
- free(buf);
- if (asprintf(&buf,"%s/001.vdr",Directory)==-1) return false;
- if (stat(buf,&statbuf)==-1)
- {
- free(buf);
- return false;
- }
- free(buf);
- // .VDR detected
- isTS=false;
- MaxFiles=999;
- return true;
- }
- free(buf);
- // .TS detected
- isTS=true;
- MaxFiles=65535;
- return true;
-}
-
-bool cMarkAdStandalone::CheckVDRHD(const char *Directory)
-{
- char *buf;
- if (asprintf(&buf,"%s/001.vdr",Directory)==-1) return false;
-
- int fd=open(buf,O_RDONLY);
- free(buf);
- if (fd==-1) return false;
-
- uchar pes_buf[32];
- if (read(fd,pes_buf,sizeof(pes_buf))!=sizeof(pes_buf))
- {
- close(fd);
- return false;
- }
- close(fd);
-
- if ((pes_buf[0]==0) && (pes_buf[1]==0) && (pes_buf[2]==1) && ((pes_buf[3] & 0xF0)==0xE0))
- {
- int payloadstart=9+pes_buf[8];
- if (payloadstart>23) return false;
- uchar *start=&pes_buf[payloadstart];
- if ((start[0]==0) && (start[1]==0) && (start[2]==1) && (start[5]==0) && (start[6]==0)
- && (start[7]==0) && (start[8]==1))
- {
- return true;
- }
- }
- return false;
-}
-
-bool cMarkAdStandalone::CheckPATPMT(const char *Directory)
-{
- char *buf;
- if (asprintf(&buf,"%s/00001.ts",Directory)==-1) return false;
-
- int fd=open(buf,O_RDONLY);
- free(buf);
- if (fd==-1) return false;
-
- uchar patpmt_buf[564];
- uchar *patpmt;
-
- if (read(fd,patpmt_buf,sizeof(patpmt_buf))!=sizeof(patpmt_buf))
- {
- close(fd);
- return false;
- }
- close(fd);
- patpmt=patpmt_buf;
-
- if ((patpmt[0]==0x47) && ((patpmt[1] & 0x5F)==0x40) && (patpmt[2]==0x11) &&
- ((patpmt[3] & 0x10)==0x10)) patpmt+=188; // skip SDT
-
- // some checks
- if ((patpmt[0]!=0x47) || (patpmt[188]!=0x47)) return false; // no TS-Sync
- if (((patpmt[1] & 0x5F)!=0x40) && (patpmt[2]!=0)) return false; // no PAT
- if ((patpmt[3] & 0x10)!=0x10) return false; // PAT not without AFC
- if ((patpmt[191] & 0x10)!=0x10) return false; // PMT not without AFC
- struct PAT *pat = (struct PAT *) &patpmt[5];
-
- // more checks
- if (pat->reserved1!=3) return false; // is always 11
- if (pat->reserved3!=7) return false; // is always 111
-
- int pid=pat->pid_L+(pat->pid_H<<8);
- int pmtpid=((patpmt[189] & 0x1f)<<8)+patpmt[190];
- if (pid!=pmtpid) return false; // pid in PAT differs from pid in PMT
-
- struct PMT *pmt = (struct PMT *) &patpmt[193];
-
- // still more checks
- if (pmt->reserved1!=3) return false; // is always 11
- if (pmt->reserved2!=3) return false; // is always 11
- if (pmt->reserved3!=7) return false; // is always 111
- if (pmt->reserved4!=15) return false; // is always 1111
-
- if ((pmt->program_number_H!=pat->program_number_H) ||
- (pmt->program_number_L!=pat->program_number_L)) return false;
-
- int desc_len=(pmt->program_info_length_H<<8)+pmt->program_info_length_L;
- if (desc_len>166) return false; // beyond patpmt buffer
-
- int section_end = 196+(pmt->section_length_H<<8)+pmt->section_length_L;
- section_end-=4; // we don't care about the CRC32
- if (section_end>376) return false; //beyond patpmt buffer
-
- int i=205+desc_len;
-
- while (i<section_end)
- {
- struct ES_DESCRIPTOR *es=NULL;
- struct STREAMINFO *si = (struct STREAMINFO *) &patpmt[i];
- int esinfo_len=(si->ES_info_length_H<<8)+si->ES_info_length_L;
- if (esinfo_len)
- {
- es = (struct ES_DESCRIPTOR *) &patpmt[i+sizeof(struct STREAMINFO)];
- }
-
- // oh no -> more checks!
- if (si->reserved1!=7) return false;
- if (si->reserved2!=15) return false;
-
- int pid=(si->PID_H<<8)+si->PID_L;
-
- switch (si->stream_type)
- {
- case 0x1:
- case 0x2:
- macontext.Info.VPid.Type=MARKAD_PIDTYPE_VIDEO_H262;
- // just use the first pid
- if (!macontext.Info.VPid.Num) macontext.Info.VPid.Num=pid;
- break;
-
- case 0x3:
- case 0x4:
- // just use the first pid
- if (!macontext.Info.APid.Num) macontext.Info.APid.Num=pid;
- break;
-
- case 0x6:
- if (es)
- {
- if (es->Descriptor_Tag==0x6A) macontext.Info.DPid.Num=pid;
- }
- break;
-
- case 0x1b:
- macontext.Info.VPid.Type=MARKAD_PIDTYPE_VIDEO_H264;
- // just use the first pid
- if (!macontext.Info.VPid.Num) macontext.Info.VPid.Num=pid;
- break;
- }
-
- i+=(sizeof(struct STREAMINFO)+esinfo_len);
- }
-
- return true;
-}
-
-bool cMarkAdStandalone::CreatePidfile(const char *Directory)
-{
- char *buf;
- if (asprintf(&buf,"%s/markad.pid",Directory)==-1) return false;
-
- // check for other running markad process
- FILE *oldpid=fopen(buf,"r");
- if (oldpid)
- {
- // found old pidfile, check if it's still running
- int pid;
- if (fscanf(oldpid,"%i\n",&pid)==1)
- {
- char procname[256]="";
- snprintf(procname,sizeof(procname),"/proc/%i",pid);
- struct stat statbuf;
- if (stat(procname,&statbuf)!=-1)
- {
- // found another, running markad
- isyslog("another instance is running on this recording");
- abort=duplicate=true;
- }
- }
- fclose(oldpid);
- }
- if (duplicate) return false;
-
- FILE *pidfile=fopen(buf,"w+");
-
- if (getuid()==0 || geteuid()!=0)
- {
- // if we are root, set fileowner to owner of 001.vdr/00001.ts file
- char *spath=NULL;
- if (asprintf(&spath,"%s/%s",Directory,isTS ? "00001.ts" : "001.vdr")!=-1)
- {
- struct stat statbuf;
- if (!stat(spath,&statbuf))
- {
- chown(buf,statbuf.st_uid, statbuf.st_gid);
- }
- free(spath);
- }
- }
-
- free(buf);
- if (!pidfile) return false;
- fprintf(pidfile,"%i\n",(int) getpid());
- fflush(pidfile);
- fclose(pidfile);
- return true;
-}
-
-void cMarkAdStandalone::RemovePidfile(const char *Directory)
-{
- char *buf;
- if (asprintf(&buf,"%s/markad.pid",Directory)!=-1)
- {
- unlink(buf);
- free(buf);
- }
-}
-
-const char cMarkAdStandalone::frametypes[8]={'?','I','P','B','D','S','s','b'};
-
-cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, int LogoExtraction,
- int LogoWidth, int LogoHeight, bool DecodeVideo,
- bool DecodeAudio, bool IgnoreVideoInfo, bool IgnoreAudioInfo,
- const char *LogoDir, const char *MarkFileName, bool ASD,
- bool noPid)
-{
- directory=Directory;
- abort=false;
-
- noticeVDR_MP2=false;
- noticeVDR_AC3=false;
-
- sleepcnt=0;
- waittime=0;
- duplicate=false;
- marksAligned=false;
-
- memset(&macontext,0,sizeof(macontext));
- macontext.LogoDir=(char *) LogoDir;
- macontext.Options.LogoExtraction=LogoExtraction;
- macontext.Options.LogoWidth=LogoWidth;
- macontext.Options.LogoHeight=LogoHeight;
- macontext.Audio.Options.AudioSilenceDetection=ASD;
-
- bDecodeVideo=DecodeVideo;
- bDecodeAudio=DecodeAudio;
- bIgnoreAudioInfo=IgnoreAudioInfo;
- bIgnoreVideoInfo=IgnoreVideoInfo;
-
- bBackupMarks=BackupMarks;
-
- macontext.Info.DPid.Type=MARKAD_PIDTYPE_AUDIO_AC3;
- macontext.Info.APid.Type=MARKAD_PIDTYPE_AUDIO_MP2;
-
- isyslog("starting v%s",VERSION);
- isyslog("on %s",Directory);
-
- if (!bDecodeAudio)
- {
- isyslog("audio decoding disabled by user");
- }
- if (!bDecodeVideo)
- {
- isyslog("video decoding disabled by user");
- }
- if (bIgnoreAudioInfo)
- {
- isyslog("audio info usage disabled by user");
- }
- if (bIgnoreVideoInfo)
- {
- isyslog("video info usage disabled by user");
- }
-
- if (LogoExtraction!=-1)
- {
- // just to be sure extraction works
- bDecodeVideo=true;
- bIgnoreAudioInfo=true;
- bIgnoreVideoInfo=true;
- }
-
- if (!CheckTS(Directory))
- {
- video_demux=NULL;
- ac3_demux=NULL;
- mp2_demux=NULL;
- decoder=NULL;
- video=NULL;
- audio=NULL;
- return;
- }
-
- if (!noPid)
- {
- CreatePidfile(Directory);
- if (abort)
- {
- video_demux=NULL;
- ac3_demux=NULL;
- mp2_demux=NULL;
- decoder=NULL;
- video=NULL;
- audio=NULL;
- return;
- }
- }
-
- if (isTS)
- {
- if (!CheckPATPMT(Directory))
- {
- esyslog("no PAT/PMT found -> nothing to process");
- abort=true;
- }
- if (!macontext.Audio.Options.AudioSilenceDetection)
- {
- macontext.Info.APid.Num=0;
- }
- if (asprintf(&indexFile,"%s/index",Directory)==-1) indexFile=NULL;
- }
- else
- {
- if (macontext.Audio.Options.AudioSilenceDetection)
- {
- macontext.Info.APid.Num=-1;
- }
- macontext.Info.DPid.Num=-1;
- macontext.Info.VPid.Num=-1;
-
- if (CheckVDRHD(Directory))
- {
- macontext.Info.VPid.Type=MARKAD_PIDTYPE_VIDEO_H264;
- }
- else
- {
- macontext.Info.VPid.Type=MARKAD_PIDTYPE_VIDEO_H262;
- }
- if (asprintf(&indexFile,"%s/index.vdr",Directory)==-1) indexFile=NULL;
- }
-
- if (!LoadInfo(Directory))
- {
- if (bDecodeVideo)
- {
- esyslog("failed loading info - logo %s disabled",
- (LogoExtraction!=-1) ? "extraction" : "detection");
- }
- }
-
- if (MarkFileName[0]) marks.SetFileName(MarkFileName);
-
- if (macontext.Info.VPid.Num)
- {
- if (isTS)
- {
- dsyslog("using %s-video (0x%04x)",
- macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264 ? "H264": "H262",
- macontext.Info.VPid.Num);
- }
- else
- {
- dsyslog("using %s-video",
- macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264 ? "H264": "H262");
- }
- video_demux = new cMarkAdDemux();
- }
- else
- {
- video_demux=NULL;
- }
-
- if (macontext.Info.APid.Num)
- {
- if (macontext.Info.APid.Num!=-1)
- dsyslog("using MP2 (0x%04x)",macontext.Info.APid.Num);
- mp2_demux = new cMarkAdDemux();
- }
- else
- {
- mp2_demux=NULL;
- }
-
- if (macontext.Info.DPid.Num)
- {
- if (macontext.Info.DPid.Num!=-1)
- dsyslog("using AC3 (0x%04x)",macontext.Info.DPid.Num);
- ac3_demux = new cMarkAdDemux();
- }
- else
- {
- ac3_demux=NULL;
- }
-
- if (!abort)
- {
- decoder = new cMarkAdDecoder(macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264,
- macontext.Info.APid.Num!=0,macontext.Info.DPid.Num!=0);
- video = new cMarkAdVideo(&macontext);
- audio = new cMarkAdAudio(&macontext);
- streaminfo = new cMarkAdStreamInfo;
- if (macontext.Info.ChannelID)
- dsyslog("channel %s",macontext.Info.ChannelID);
- }
- else
- {
- decoder=NULL;
- video=NULL;
- audio=NULL;
- streaminfo=NULL;
- }
-
- framecnt=0;
- lastiframe=0;
- iframe=0;
-}
-
-cMarkAdStandalone::~cMarkAdStandalone()
-{
- if (macontext.Info.ChannelID) free(macontext.Info.ChannelID);
- if (indexFile) free(indexFile);
-
- if (video_demux) delete video_demux;
- if (ac3_demux) delete ac3_demux;
- if (mp2_demux) delete mp2_demux;
- if (decoder) delete decoder;
- if (video) delete video;
- if (audio) delete audio;
- if (streaminfo) delete streaminfo;
-
- if ((directory) && (!duplicate)) RemovePidfile(directory);
-}
-
-bool isnumber(const char *s)
-{
- while (*s)
- {
- if (!isdigit(*s))
- return false;
- s++;
- }
- return true;
-}
-
-int usage()
-{
- // nothing done, give the user some help
- printf("Usage: markad [options] cmd <record>\n"
- "options:\n"
- "-b --background\n"
- " markad runs as a background-process\n"
- " this will be automatically set if called with \"after\"\n"
- "-d --disable=<option>\n"
- " <option> 1 = disable video 2 = disable audio\n"
- " 3 = disable video and audio\n"
- "-i --ignoreinfo=<info>\n"
- " ignores hints from info(.vdr) file\n"
- " <info> 1 = ignore audio info 2 = ignore video info\n"
- " 3 = ignore video and audio info\n"
- "-l --logocachedir\n"
- " directory where logos stored, default /var/lib/markad\n"
- "-p, --priority level=<priority>\n"
- " priority-level of markad when running in background\n"
- " <-20...19> default 19\n"
- "-v, --verbose\n"
- " increments loglevel by one, can be given multiple times\n"
- "-B --backupmarks\n"
- " make a backup of existing marks\n"
- "-L --extractlogo=<direction>[,width[,height]]\n"
- " extracts logo to /tmp as pgm files (must be renamed)\n"
- " <direction> 0 = top left, 1 = top right\n"
- " 2 = bottom left, 3 = bottom right\n"
- " [width] range from 50 to %3i, default %3i (SD)\n"
- " default %3i (HD)\n"
- " [height] range from 20 to %3i, default %3i\n"
- "-O, --OSD\n"
- " markad sends an OSD-Message for start and end\n"
- "-V --version\n"
- " print version-info and exit\n"
- " --asd\n"
- " enable audio silence detecion\n"
- " --markfile=<markfilename>\n"
- " set a different markfile-name\n"
- " --online[=1|2] (default is 1)\n"
- " start markad immediately when called with \"before\" as cmd\n"
- " if online is 1, markad starts online for live-recordings\n"
- " only, online=2 starts markad online for every recording\n"
- " live-recordings are identified by having a '@' in the\n"
- " filename so the entry 'Mark instant recording' in the menu\n"
- " 'Setup - Recording' of the vdr should be set to 'yes'\n"
- "\ncmd: one of\n"
- "- dummy-parameter if called directly\n"
- "after markad starts to analyze the recording\n"
- "before markad exits immediately if called with \"before\"\n"
- "edited markad exits immediately if called with \"edited\"\n"
- "nice runs markad with nice(19)\n"
- "\n<record> is the name of the directory where the recording\n"
- " is stored\n\n",
- LOGO_MAXWIDTH,LOGO_DEFWIDTH,LOGO_DEFHDWIDTH,
- LOGO_MAXHEIGHT,LOGO_DEFHEIGHT
- );
- return -1;
-}
-
-void signal_handler(int sig)
-{
- if (sig==SIGUSR1)
- {
- // TODO: what we are supposed to do?
- }
- else
- {
- if (cmasta)
- {
- cmasta->SetAbort();
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- int c;
- bool bAfter=false,bBefore=false,bEdited=false;
- bool bFork=false,bNice=false,bImmediateCall=false;
- bool bASD=false;
- int niceLevel = 19;
- char *recDir=NULL;
- char *tok,*str;
- int ntok;
- int logoExtraction=-1;
- int logoWidth=-1;
- int logoHeight=-1;
- bool bBackupMarks=false,bNoPid=false;
- char markFileName[1024]="";
- char logoDirectory[1024]="";
- bool bDecodeVideo=true;
- bool bDecodeAudio=true;
- bool bIgnoreAudioInfo=false;
- bool bIgnoreVideoInfo=false;
- int online=1;
-
- strcpy(logoDirectory,"/var/lib/markad");
-
- while (1)
- {
- int option_index = 0;
- static struct option long_options[] =
- {
- {"ac3",0,0,'a'
- },
- {"background", 0, 0, 'b'},
- {"comments", 0, 0, 'c'},
- {"disable", 1, 0, 'd'},
- {"ignoreinfo", 1, 0, 'i' },
- {"jumplogo",0,0,'j'},
- {"logocachedir", 1, 0, 'l'},
- {"nelonen",0,0,'n'},
- {"overlap",0,0,'o' },
- {"priority",1,0,'p'},
- {"statisticfile",1,0,'s'},
- {"verbose", 0, 0, 'v'},
-
- {"asd",0,0,6},
- {"loglevel",1,0,2},
- {"markfile",1,0,1},
- {"nopid",0,0,5},
- {"online",2,0,4},
- {"pass3only",0,0,7},
- {"testmode",0,0,3},
-
- {"backupmarks", 0, 0, 'B'},
- {"scenechangedetection", 0, 0, 'C'},
- {"extractlogo", 1, 0, 'L'},
- {"OSD",0,0,'O' },
- {"savelogo", 0, 0, 'S'},
- {"version", 0, 0, 'V'},
-
- {0, 0, 0, 0}
- };
-
- c = getopt_long (argc, argv, "abcd:i:jl:nop:s:vBCL:O:SV",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c)
- {
-
- case 'a':
- // --ac3
- break;
-
- case 'b':
- // --background
- bFork = SYSLOG = true;
- break;
-
- case 'c':
- // --comments
- break;
-
- case 'd':
- // --disable
- switch (atoi(optarg))
- {
- case 1:
- bDecodeVideo=false;
- break;
- case 2:
- bDecodeAudio=false;
- break;
- case 3:
- bDecodeVideo=false;
- bDecodeAudio=false;
- break;
- default:
- fprintf(stderr, "markad: invalid disable option: %s\n", optarg);
- return 2;
- break;
- }
- break;
-
- case 'i':
- // --ignoreinfo
- switch (atoi(optarg))
- {
- case 1:
- bIgnoreAudioInfo=true;
- break;
- case 2:
- bIgnoreVideoInfo=true;
- break;
- case 3:
- bIgnoreVideoInfo=true;
- bIgnoreAudioInfo=true;
- break;
- default:
- fprintf(stderr, "markad: invalid ignoreinfo option: %s\n", optarg);
- return 2;
- break;
- }
- break;
-
- case 'j':
- // --jumplogo
- break;
-
- case 'l':
- strncpy(logoDirectory,optarg,1024);
- logoDirectory[1023]=0;
- break;
-
- case 'n':
- // --nelonen
- break;
-
- case 'o':
- // --overlap
- break;
-
- case 'p':
- // --priority
- if (isnumber(optarg) || *optarg=='-')
- niceLevel = atoi(optarg);
- else
- {
- fprintf(stderr, "markad: invalid priority level: %s\n", optarg);
- return 2;
- }
- bNice = true;
- break;
-
- case 's':
- // --statisticfile
- break;
-
- case 'v':
- // --verbose
- SysLogLevel++;
- if (SysLogLevel>10) SysLogLevel=10;
- break;
-
- case 'B':
- // --backupmarks
- bBackupMarks=true;
- break;
-
- case 'C':
- // --scenechangedetection
- break;
-
- case 'L':
- // --extractlogo
- str=optarg;
- ntok=0;
- while (tok=strtok(str,","))
- {
- switch (ntok)
- {
- case 0:
- logoExtraction=atoi(tok);
- if ((logoExtraction<0) || (logoExtraction>3))
- {
- fprintf(stderr, "markad: invalid extractlogo value: %s\n", tok);
- return 2;
- }
- break;
-
- case 1:
- logoWidth=atoi(tok);
- if ((logoWidth<50) || (logoWidth>LOGO_MAXWIDTH))
- {
- fprintf(stderr, "markad: invalid width value: %s\n", tok);
- return 2;
- }
- break;
-
- case 2:
- logoHeight=atoi(tok);
- if ((logoHeight<20) || (logoHeight>LOGO_MAXHEIGHT))
- {
- fprintf(stderr, "markad: invalid height value: %s\n", tok);
- return 2;
- }
- break;
-
- default:
- break;
- }
- str=NULL;
- ntok++;
- }
- break;
-
- case 'O':
- // --OSD
- break;
-
- case 'S':
- // --savelogo
- break;
-
- case 'V':
- printf("markad %s - marks advertisements in VDR recordings\n",VERSION);
- return 0;
-
- case '?':
- printf("unknow option ?\n");
- break;
-
- case 0:
- printf ("option %s", long_options[option_index].name);
- if (optarg)
- printf (" with arg %s", optarg);
- printf ("\n");
- break;
-
- case 1: // --markfile
- strncpy(markFileName,optarg,1024);
- markFileName[1023]=0;
- break;
-
- case 2: // --loglevel
- SysLogLevel=atoi(optarg);
- if (SysLogLevel>10) SysLogLevel=10;
- if (SysLogLevel<0) SysLogLevel=2;
- break;
-
- case 3: // --testmode
- break;
-
- case 4: // --online
- online=atoi(optarg);
- if ((online!=1) && (online!=2))
- {
- fprintf(stderr, "markad: invalid online value: %s\n", optarg);
- return 2;
- }
- break;
-
- case 5: // --nopid
- bNoPid=true;
- break;
-
- case 6: // --asd
- bASD=true;
- break;
-
- case 7: // --pass3only
- break;
-
- default:
- printf ("? getopt returned character code 0%o ? (option_index %d)\n", c,option_index);
- }
- }
-
- if (optind < argc)
- {
- while (optind < argc)
- {
- if (strcmp(argv[optind], "after" ) == 0 )
- {
- bAfter = bFork = bNice = SYSLOG = true;
- }
- else if (strcmp(argv[optind], "before" ) == 0 )
- {
- bBefore = bFork = bNice = SYSLOG = true;
- }
- else if (strcmp(argv[optind], "edited" ) == 0 )
- {
- bEdited = true;
- }
- else if (strcmp(argv[optind], "nice" ) == 0 )
- {
- bNice = true;
- }
- else if (strcmp(argv[optind], "-" ) == 0 )
- {
- bImmediateCall = true;
- }
- else
- {
- if ( strstr(argv[optind],".rec") != NULL )
- recDir = argv[optind];
- }
- optind++;
- }
- }
-
- // do nothing if called from vdr before/after the video is cutted
- if ((bAfter) && (online)) return 0;
- if (bBefore)
- {
- if (!online) return 0;
- if ((online==1) && (!strchr(recDir,'@'))) return 0;
- }
- if (bEdited) return 0;
-
- // we can run, if one of bImmediateCall, bAfter, bBefore or bNice is true
- // and recDir is given
- if ( (bImmediateCall || bBefore || bAfter || bNice) && recDir )
- {
- // if bFork is given go in background
- if ( bFork )
- {
- (void)umask((mode_t)0011);
- //close_files();
- pid_t pid = fork();
- if (pid < 0)
- {
- char *err=strerror(errno);
- fprintf(stderr, "%s\n",err);
- esyslog("fork ERROR: %s",err);
- return 2;
- }
- if (pid != 0)
- {
- isyslog("forked to pid %d",pid);
- return 0; // initial program immediately returns
- }
- }
- if ( bFork )
- {
- isyslog("(forked) pid %d", getpid());
- if (chdir("/")==-1)
- {
- perror("chdir");
- exit(EXIT_FAILURE);
- }
- if (setsid() == (pid_t)(-1))
- {
- perror("setsid");
- exit(EXIT_FAILURE);
- }
- if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
- {
- perror("signal(SIGHUP, SIG_IGN)");
- errno = 0;
- }
- int f;
-
- f = open("/dev/null", O_RDONLY);
- if (f == -1)
- {
- perror("/dev/null");
- errno = 0;
- }
- else
- {
- if (dup2(f, fileno(stdin)) == -1)
- {
- perror("dup2");
- errno = 0;
- }
- (void)close(f);
- }
-
- f = open("/dev/null", O_WRONLY);
- if (f == -1)
- {
- perror("/dev/null");
- errno = 0;
- }
- else
- {
- if (dup2(f, fileno(stdout)) == -1)
- {
- perror("dup2");
- errno = 0;
- }
- if (dup2(f, fileno(stderr)) == -1)
- {
- perror("dup2");
- errno = 0;
- }
- (void)close(f);
- }
- }
-
- int MaxPossibleFileDescriptors = getdtablesize();
- for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
- close(i); //close all dup'ed filedescriptors
-
- // should we renice ?
- if ( bNice )
- {
- if (setpriority(PRIO_PROCESS,0,niceLevel)==-1)
- {
- esyslog("failed to set nice to %d",niceLevel);
- }
- }
-
- if (bBefore) sleep(10);
-
- // now do the work...
- struct stat statbuf;
- if (stat(recDir,&statbuf)==-1)
- {
- fprintf(stderr,"%s not found\n",recDir);
- return -1;
- }
-
- if (!S_ISDIR(statbuf.st_mode))
- {
- fprintf(stderr,"%s is not a directory\n",recDir);
- return -1;
- }
-
- cmasta = new cMarkAdStandalone(recDir,bBackupMarks, logoExtraction, logoWidth, logoHeight,
- bDecodeVideo,bDecodeAudio,bIgnoreVideoInfo,bIgnoreAudioInfo,
- logoDirectory,markFileName,bASD,bNoPid);
- if (!cmasta) return -1;
-
- // ignore some signals
- signal(SIGHUP, SIG_IGN);
-
- // catch some signals
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
- signal(SIGUSR1, signal_handler);
-
- cmasta->Process(recDir);
- delete cmasta;
- return 0;
- }
-
- return usage();
-}