diff options
-rw-r--r-- | HISTORY | 3 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | audio.cpp | 18 | ||||
-rw-r--r-- | audio.h | 5 | ||||
-rw-r--r-- | decoder.cpp | 158 | ||||
-rw-r--r-- | decoder.h | 7 | ||||
-rw-r--r-- | demux.cpp | 12 | ||||
-rw-r--r-- | demux.h | 2 | ||||
-rw-r--r-- | global.h | 16 | ||||
-rw-r--r-- | markad-standalone.cpp | 144 | ||||
-rw-r--r-- | markad-standalone.h | 12 | ||||
-rw-r--r-- | pes2es.h | 2 | ||||
-rw-r--r-- | queue.cpp (renamed from tools.cpp) | 161 | ||||
-rw-r--r-- | queue.h (renamed from tools.h) | 28 | ||||
-rw-r--r-- | recv.cpp | 201 | ||||
-rw-r--r-- | recv.h | 7 | ||||
-rw-r--r-- | status.cpp | 4 | ||||
-rw-r--r-- | streaminfo.cpp | 569 | ||||
-rw-r--r-- | streaminfo.h | 11 | ||||
-rw-r--r-- | ts2pkt.cpp | 16 | ||||
-rw-r--r-- | ts2pkt.h | 3 | ||||
-rw-r--r-- | vdr2pkt.h | 2 | ||||
-rw-r--r-- | version.h | 2 | ||||
-rw-r--r-- | video.cpp | 345 | ||||
-rw-r--r-- | video.h | 44 |
25 files changed, 1074 insertions, 704 deletions
@@ -1,5 +1,8 @@ VDR Plugin 'markad' Revision History ---------------------------------- +2010-03-06: Version 0.0.5 + +- Updated H264 handling 2009-09-27: Version 0.0.4 @@ -18,7 +18,7 @@ VERSION = $(shell grep 'static const char \*VERSION *=' version.h | awk '{ print ### The C++ compiler and options: CXX ?= g++ -CXXFLAGS ?= -fPIC -g -O0 -Wall -Woverloaded-virtual -Wno-parentheses +CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses PKG-CONFIG ?= pkg-config ### The directory environment: @@ -56,8 +56,8 @@ LIBS-CMD += $(shell $(PKG-CONFIG) --libs $(PKG-LIBS)) ### The object files (add further files here): OBJS-CMD = markad-standalone.o decoder.o -OBJS-COMMON = common.o video.o audio.o demux.o tools.o vdr2pkt.o ts2pkt.o pes2es.o -OBJS = $(PLUGIN).o recv.o status.o streaminfo.o $(OBJS-COMMON) +OBJS-COMMON = streaminfo.o video.o audio.o demux.o queue.o vdr2pkt.o ts2pkt.o pes2es.o +OBJS = $(PLUGIN).o recv.o status.o $(OBJS-COMMON) ### The main target: @@ -65,19 +65,15 @@ MarkAdMark *cMarkAdAudio::Process(int LastIFrame) ResetMark(); if (!LastIFrame) return NULL; - - if (macontext->State.ContentStarted) + if (ChannelChange(macontext->Audio.Info.Channels,channels)) { - if (ChannelChange(macontext->Audio.Info.Channels,channels)) + char *buf=NULL; + if (asprintf(&buf,"audio channel change from %i to %i (%i)", channels, + macontext->Audio.Info.Channels,LastIFrame)!=-1) { - char *buf=NULL; - if (asprintf(&buf,"audio channel change from %i to %i (%i)", channels, - macontext->Audio.Info.Channels,LastIFrame)!=-1) - { - isyslog("markad [%i]: %s",recvnumber, buf); - AddMark(LastIFrame,buf); - free(buf); - } + isyslog("markad [%i]: %s",recvnumber, buf); + AddMark(LastIFrame,buf); + free(buf); } } @@ -10,6 +10,8 @@ #define __audio_h_ #include <vdr/tools.h> // needed for (d/e/i)syslog +#include <netinet/in.h> // for htonl + #include "global.h" class cMarkAdAudio @@ -24,10 +26,7 @@ private: bool AddMark(int Position, const char *Comment); int channels; - -private: bool ChannelChange(int a, int b); - public: cMarkAdAudio(int RecvNumber,MarkAdContext *maContext); ~cMarkAdAudio(); diff --git a/decoder.cpp b/decoder.cpp index 27c4bf2..15d72de 100644 --- a/decoder.cpp +++ b/decoder.cpp @@ -8,12 +8,14 @@ #include "decoder.h" -cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) +cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool useMP2, bool hasAC3) { recvnumber=RecvNumber; avcodec_init(); avcodec_register_all(); + last_qscale_table=NULL; + cpu_set_t cpumask; uint len = sizeof(cpumask); int cpucount; @@ -29,29 +31,36 @@ cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) isyslog("markad [%i]: using libavcodec.so.%s with %i threads",recvnumber, AV_STRINGIFY(LIBAVCODEC_VERSION),cpucount); - CodecID mp2_codecid=CODEC_ID_MP2; - AVCodec *mp2_codec= avcodec_find_decoder(mp2_codecid); - if (mp2_codec) + if (useMP2) { - mp2_context = avcodec_alloc_context(); - if (mp2_context) + CodecID mp2_codecid=CODEC_ID_MP2; + AVCodec *mp2_codec= avcodec_find_decoder(mp2_codecid); + if (mp2_codec) { - mp2_context->thread_count=cpucount; - if (avcodec_open(mp2_context, mp2_codec) < 0) + mp2_context = avcodec_alloc_context(); + if (mp2_context) + { + mp2_context->thread_count=cpucount; + if (avcodec_open(mp2_context, mp2_codec) < 0) + { + esyslog("markad [%i]: could not open codec 0x%05x",recvnumber,mp2_codecid); + av_free(mp2_context); + mp2_context=NULL; + } + } + else { - esyslog("markad [%i]: could not open codec 0x%05x",recvnumber,mp2_codecid); - av_free(mp2_context); - mp2_context=NULL; + esyslog("markad [%i]: could not allocate mp2 context",recvnumber); } } else { - esyslog("markad [%i]: could not allocate mp2 context",recvnumber); + esyslog("markad [%i]: codec 0x%05x not found",recvnumber,mp2_codecid); + mp2_context=NULL; } } else { - esyslog("markad [%i]: codec 0x%05x not found",recvnumber,mp2_codecid); mp2_context=NULL; } @@ -97,10 +106,17 @@ cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) } else { - video_codecid=CODEC_ID_MPEG2VIDEO; + video_codecid=CODEC_ID_MPEG2VIDEO_XVMC; } video_codec = avcodec_find_decoder(video_codecid); + if ((!video_codec) && (video_codecid==CODEC_ID_MPEG2VIDEO_XVMC)) + { + // fallback to MPEG2VIDEO + video_codecid=CODEC_ID_MPEG2VIDEO; + video_codec=avcodec_find_decoder(video_codecid); + } + if (video_codec) { video_context = avcodec_alloc_context(); @@ -109,11 +125,45 @@ cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) video_context->thread_count=cpucount; if (video_codec->capabilities & CODEC_CAP_TRUNCATED) video_context->flags|=CODEC_FLAG_TRUNCATED; // we do not send complete frames + video_context->flags|=CODEC_FLAG_EMU_EDGE; // now linesize should be the same as width - video_context->flags2|=CODEC_FLAG2_CHUNKS; // needed for H264! + + video_context->flags|=CODEC_FLAG_GRAY; // only decode grayscale video_context->flags2|=CODEC_FLAG2_FAST; // really? - if (avcodec_open(video_context, video_codec) < 0) + video_context->skip_idct=AVDISCARD_ALL; + + if (video_codecid==CODEC_ID_H264) + { + video_context->flags2|=CODEC_FLAG2_CHUNKS; // needed for H264! + video_context->skip_loop_filter=AVDISCARD_ALL; // skip deblocking + video_context->skip_frame=AVDISCARD_NONREF; // P/I-frames + } + else + { + video_context->skip_frame=AVDISCARD_NONKEY; // I-frames + } + + int ret=avcodec_open(video_context, video_codec); + if ((ret < 0) && (video_codecid==CODEC_ID_MPEG2VIDEO_XVMC)) + { + // fallback to MPEG2VIDEO + video_codecid=CODEC_ID_MPEG2VIDEO; + video_codec=avcodec_find_decoder(video_codecid); + if (video_codec) + { + video_context->codec_type=CODEC_TYPE_UNKNOWN; + video_context->codec_id=CODEC_ID_NONE; + video_context->codec_tag=0; + memset(video_context->codec_name,0,sizeof(video_context->codec_name)); + ret=avcodec_open(video_context, video_codec); + } + else + { + ret=-1; + } + } + if (ret < 0) { esyslog("markad [%i]: could not open codec 0x%05x",recvnumber,video_codecid); av_free(video_context); @@ -141,6 +191,16 @@ cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) esyslog("markad [%i]: codec 0x%05x not found",recvnumber,video_codecid); video_context=NULL; } + + if ((ac3_context) || (mp2_context)) + { + audiobuf=(int16_t*) malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); + } + else + { + audiobuf=NULL; + } + } cMarkAdDecoder::~cMarkAdDecoder() @@ -163,6 +223,7 @@ cMarkAdDecoder::~cMarkAdDecoder() avcodec_close(mp2_context); av_free(mp2_context); } + if (audiobuf) free(audiobuf); SetVideoInfos(NULL,NULL,NULL,NULL); } @@ -180,24 +241,25 @@ bool cMarkAdDecoder::DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen avpkt.data=espkt; avpkt.size=eslen; - DECLARE_ALIGNED(16,char,outbuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]); - int outbuf_size=AVCODEC_MAX_AUDIO_FRAME_SIZE; + audiobufsize=AVCODEC_MAX_AUDIO_FRAME_SIZE; int ret=false; + int16_t Taudiobuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]; while (avpkt.size>0) { #if LIBAVCODEC_VERSION_INT < ((52<<16)+(25<<8)+0) - int len=avcodec_decode_audio2(mp2_context,(short *) &outbuf,&outbuf_size, + int len=avcodec_decode_audio2(mp2_context,Taudiobuf,&audiobufsize, avpkt.data,avpkt.size); #else - int len=avcodec_decode_audio3(mp2_context,(short *) &outbuf,&outbuf_size,&avpkt); + int len=avcodec_decode_audio3(mp2_context,Taudiobuf,&audiobufsize,&avpkt); #endif if (len<0) { esyslog("markad [%i]: error decoding mp2",recvnumber); break; } - else + if (audiobufsize>0) { + memcpy(audiobuf,Taudiobuf,audiobufsize); SetAudioInfos(maContext,ac3_context); ret=true; avpkt.size-=len; @@ -212,6 +274,9 @@ bool cMarkAdDecoder::SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Aud if ((!maContext) || (!Audio_Context)) return false; maContext->Audio.Info.Channels = Audio_Context->channels; + maContext->Audio.Data.SampleBuf=audiobuf; + maContext->Audio.Data.SampleBufLen=audiobufsize; + maContext->Audio.Data.Valid=true; return true; } @@ -229,24 +294,25 @@ bool cMarkAdDecoder::DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen avpkt.data=espkt; avpkt.size=eslen; - DECLARE_ALIGNED(16,char,outbuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]); - int outbuf_size=AVCODEC_MAX_AUDIO_FRAME_SIZE; int ret=false; + int16_t Taudiobuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]; while (avpkt.size>0) { + audiobufsize=AVCODEC_MAX_AUDIO_FRAME_SIZE; #if LIBAVCODEC_VERSION_INT < ((52<<16)+(25<<8)+0) - int len=avcodec_decode_audio2(ac3_context,(short *) &outbuf,&outbuf_size, + int len=avcodec_decode_audio2(ac3_context,Taudiobuf,&audiobufsize, avpkt.data,avpkt.size); #else - int len=avcodec_decode_audio3(ac3_context,(short *) &outbuf,&outbuf_size,&avpkt); + int len=avcodec_decode_audio3(ac3_context,Taudiobuf,&audiobufsize,&avpkt); #endif if (len<0) { esyslog("markad [%i]: error decoding ac3",recvnumber); break; } - else + if (audiobufsize>0) { + memcpy(audiobuf,Taudiobuf,audiobufsize); SetAudioInfos(maContext,ac3_context); ret=true; avpkt.size-=len; @@ -277,32 +343,7 @@ bool cMarkAdDecoder::SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Vide maContext->Video.Info.Height=Video_Context->height; maContext->Video.Info.Width=Video_Context->width; - switch (Video_Frame->pict_type) - { - case FF_I_TYPE: - maContext->Video.Info.Pict_Type=MA_I_TYPE; - break; - case FF_P_TYPE: - maContext->Video.Info.Pict_Type=MA_P_TYPE; - break; - case FF_B_TYPE: - maContext->Video.Info.Pict_Type=MA_B_TYPE; - break; - case FF_S_TYPE: - maContext->Video.Info.Pict_Type=MA_S_TYPE; - break; - case FF_SI_TYPE: - maContext->Video.Info.Pict_Type=MA_SI_TYPE; - break; - case FF_SP_TYPE: - maContext->Video.Info.Pict_Type=MA_SP_TYPE; - break; - case FF_BI_TYPE: - maContext->Video.Info.Pict_Type=MA_BI_TYPE; - break; - default: - maContext->Video.Info.Pict_Type=0; - } + maContext->Video.Info.Pict_Type=Video_Context->coded_frame->pict_type; if (DAR) { @@ -316,6 +357,8 @@ bool cMarkAdDecoder::SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Vide bool cMarkAdDecoder::DecodeVideo(MarkAdContext *maContext,uchar *pkt, int plen) { + if (!video_context) return false; + AVPacket avpkt; #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(25<<8)+0) av_init_packet(&avpkt); @@ -330,6 +373,7 @@ bool cMarkAdDecoder::DecodeVideo(MarkAdContext *maContext,uchar *pkt, int plen) // decode video int video_frame_ready=0; int len,ret=false; + while (avpkt.size>0) { #if LIBAVCODEC_VERSION_INT < ((52<<16)+(25<<8)+0) @@ -351,9 +395,13 @@ bool cMarkAdDecoder::DecodeVideo(MarkAdContext *maContext,uchar *pkt, int plen) } if (video_frame_ready) { - AVRational dar; - PAR2DAR(video_context->sample_aspect_ratio,&dar); - if (SetVideoInfos(maContext,video_context,video_frame,&dar)) ret=true; + if (last_qscale_table!=video_frame->qscale_table) + { + AVRational dar; + PAR2DAR(video_context->sample_aspect_ratio,&dar); + if (SetVideoInfos(maContext,video_context,video_frame,&dar)) ret=true; + last_qscale_table=video_frame->qscale_table; + } } } return ret; @@ -42,11 +42,16 @@ class cMarkAdDecoder { private: int recvnumber; + int16_t *audiobuf; + int audiobufsize; + AVCodecContext *ac3_context; AVCodecContext *mp2_context; AVCodecContext *video_context; AVFrame *video_frame; + int8_t *last_qscale_table; + bool SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Audio_Context); void PAR2DAR(AVRational a, AVRational *erg); @@ -56,7 +61,7 @@ public: bool DecodeVideo(MarkAdContext *maContext, uchar *pkt, int plen); bool DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen); bool DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen); - cMarkAdDecoder(int recvnumber, bool useH264, bool hasAC3); + cMarkAdDecoder(int recvnumber, bool useH264, bool useMP2, bool hasAC3); ~cMarkAdDecoder(); }; @@ -69,7 +69,17 @@ void cMarkAdDemux::ProcessTS(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, uchar *pkt; int pktlen; - if (!ts2pkt) ts2pkt=new cMarkAdTS2Pkt(recvnumber,"TS2PES",262144); + if (!ts2pkt) + { + if (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264) + { + ts2pkt=new cMarkAdTS2Pkt(recvnumber,"TS2H264",393216); + } + else + { + ts2pkt=new cMarkAdTS2Pkt(recvnumber,"TS2PKT",262144); + } + } if (!ts2pkt) return; ts2pkt->Process(Pid,Data,Count,&pkt,&pktlen); @@ -18,7 +18,7 @@ #endif #include "global.h" -#include "tools.h" +#include "queue.h" #include "vdr2pkt.h" #include "ts2pkt.h" #include "pes2es.h" @@ -51,20 +51,11 @@ typedef struct MarkAdContext { struct General { - time_t StartTime; - time_t EndTime; - bool ManualRecording; MarkAdPid VPid; MarkAdPid APid; MarkAdPid DPid; } General; - struct State - { - int ContentStarted; - int ContentStopped; - } State; - struct Video { struct Info @@ -73,6 +64,7 @@ typedef struct MarkAdContext int Height; // height of pic int Pict_Type; // picture type (I,P,B,S,SI,SP,BI) MarkAdAspectRatio AspectRatio; + double FramesPerSecond; } Info; struct Data @@ -92,10 +84,8 @@ typedef struct MarkAdContext struct Data { bool Valid; - uchar *SampleBufAC3; - int SampleBufLenAC3; - uchar *SampleBufMP2; - int SampleBufLenMP2; + short *SampleBuf; + int SampleBufLen; } Data; } Audio; diff --git a/markad-standalone.cpp b/markad-standalone.cpp index 2b47d33..3537ecb 100644 --- a/markad-standalone.cpp +++ b/markad-standalone.cpp @@ -9,6 +9,8 @@ #include "markad-standalone.h" cMarkAdStandalone *cmasta=NULL; +int SysLogLevel=2; +char markFileName[1024]=""; void syslog_with_tid(int priority, const char *format, ...) { @@ -27,9 +29,59 @@ void syslog_with_tid(int priority, const char *format, ...) #endif } +char *cMarkAdStandalone::IndexToHMSF(int Index) +{ + if (macontext.Video.Info.FramesPerSecond==0.0) return NULL; + char *buf; + double Seconds; + int f = int(modf((Index+0.5)/macontext.Video.Info.FramesPerSecond,&Seconds)* + macontext.Video.Info.FramesPerSecond+1); + int s = int(Seconds); + int m = s / 60 % 60; + int h = s / 3600; + s %= 60; + if (asprintf(&buf,"%d:%02d:%02d.%02d",h,m,s,f)==-1) return NULL; + return buf; +} + void cMarkAdStandalone::AddMark(MarkAdMark *Mark) { -// TODO: Implement this! + if (!Mark) return; + + if (Mark->Comment) + { + char *buf=IndexToHMSF(Mark->Position); + if (buf) + { + fprintf(stderr,"%s %s\n",buf,Mark->Comment); + free(buf); + } + } +// TODO: Implement creating marks/marks.vdr! + +} + +void cMarkAdStandalone::SaveFrame(int frame) +{ + if (!macontext.Video.Info.Width) return; + if (!macontext.Video.Data.Valid) return; + + FILE *pFile; + char szFilename[32]; + + // Open file + sprintf(szFilename, "frame%06d.pgm", frame); + pFile=fopen(szFilename, "wb"); + if (pFile==NULL) + return; + + // Write header + fprintf(pFile, "P5\n%d %d\n255\n", macontext.Video.Info.Width,macontext.Video.Info.Height); + + // Write pixel data + fwrite(macontext.Video.Data.Plane[0],1,macontext.Video.Info.Width*macontext.Video.Info.Height,pFile); + // Close file + fclose(pFile); } bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) @@ -60,15 +112,9 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) while ((dataread=read(f,data,datalen))>0) { if (abort) break; - MarkAdMark *mark; - - if (common) - { - mark=common->Process(lastiframe); - AddMark(mark); - } + MarkAdMark *mark=NULL; - if ((video_demux) && (decoder) && (video)) + if ((video_demux) && (video) && (decoder) && (streaminfo)) { uchar *pkt; int pktlen; @@ -91,11 +137,13 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) { if (macontext.Video.Info.Pict_Type==MA_I_TYPE) { - lastiframe=framecnt; + lastiframe=framecnt-1; + mark=video->Process(lastiframe); + AddMark(mark); } - mark=video->Process(framecnt); - AddMark(mark); - + } + if (streaminfo->FindVideoInfos(&macontext,pkt,pktlen)) + { framecnt++; } } @@ -105,7 +153,7 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) } } - if ((mp2_demux) && (decoder) && (audio)) + if ((ac3_demux) && (streaminfo) && (audio)) { uchar *pkt; int pktlen; @@ -115,7 +163,7 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) while (tslen>0) { - int len=mp2_demux->Process(macontext.General.APid,tspkt,tslen,&pkt,&pktlen); + int len=ac3_demux->Process(macontext.General.DPid,tspkt,tslen,&pkt,&pktlen); if (len<0) { break; @@ -124,8 +172,18 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) { if (pkt) { - if (decoder->DecodeMP2(&macontext,pkt,pktlen)) + if (streaminfo->FindAC3AudioInfos(&macontext,pkt,pktlen)) { + if ((!isTS) && (!noticeVDR_AC3)) + { + dsyslog("markad [%i]: found AC3",recvnumber); + if (mp2_demux) + { + delete mp2_demux; + mp2_demux=NULL; + } + noticeVDR_AC3=true; + } mark=audio->Process(lastiframe); AddMark(mark); } @@ -136,7 +194,7 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) } } - if ((ac3_demux) && (decoder) && (audio)) + if ((mp2_demux) && (decoder) && (audio)) { uchar *pkt; int pktlen; @@ -146,7 +204,7 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) while (tslen>0) { - int len=ac3_demux->Process(macontext.General.DPid,tspkt,tslen,&pkt,&pktlen); + int len=mp2_demux->Process(macontext.General.APid,tspkt,tslen,&pkt,&pktlen); if (len<0) { break; @@ -155,8 +213,13 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) { if (pkt) { - if (decoder->DecodeAC3(&macontext,pkt,pktlen)) + if (decoder->DecodeMP2(&macontext,pkt,pktlen)) { + if ((!isTS) && (!noticeVDR_MP2)) + { + dsyslog("markad [%i]: found MP2",recvnumber); + noticeVDR_MP2=true; + } mark=audio->Process(lastiframe); AddMark(mark); } @@ -166,6 +229,7 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) } } } + } close(f); return true; @@ -337,9 +401,10 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) recvnumber=255; abort=false; + noticeVDR_MP2=false; + noticeVDR_AC3=false; + memset(&macontext,0,sizeof(macontext)); - macontext.General.StartTime=0; - macontext.General.EndTime=time(NULL)+(7*86400); macontext.General.DPid.Type=MARKAD_PIDTYPE_AUDIO_AC3; macontext.General.APid.Type=MARKAD_PIDTYPE_AUDIO_MP2; @@ -351,7 +416,6 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) decoder=NULL; video=NULL; audio=NULL; - common=NULL; return; } @@ -363,18 +427,28 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) abort=true; } macontext.General.APid.Num=0; + if (!markFileName[0]) strcpy(markFileName,"marks"); } else { macontext.General.DPid.Num=-1; macontext.General.VPid.Num=-1; macontext.General.VPid.Type=MARKAD_PIDTYPE_VIDEO_H262; + if (!markFileName[0]) strcpy(markFileName,"marks.vdr"); } if (macontext.General.VPid.Num) { - dsyslog("markad [%i]: using %s-video (0x%04x)",recvnumber,macontext.General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264 ? "H264": "H262", - macontext.General.VPid.Num); + if (isTS) + { + dsyslog("markad [%i]: using %s-video (0x%04x)",recvnumber,macontext.General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264 ? "H264": "H262", + macontext.General.VPid.Num); + } + else + { + dsyslog("markad [%i]: using %s-video", + recvnumber,macontext.General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264 ? "H264": "H262"); + } video_demux = new cMarkAdDemux(recvnumber); } else @@ -384,7 +458,8 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) if (macontext.General.APid.Num) { - dsyslog("markad [%i]: using MP2 (0x%04x)",recvnumber,macontext.General.APid.Num); + if (macontext.General.APid.Num!=-1) + dsyslog("markad [%i]: using MP2 (0x%04x)",recvnumber,macontext.General.APid.Num); mp2_demux = new cMarkAdDemux(recvnumber); } else @@ -394,7 +469,8 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) if (macontext.General.DPid.Num) { - dsyslog("markad [%i]: using AC3 (0x%04x)",recvnumber,macontext.General.DPid.Num); + if (macontext.General.DPid.Num!=-1) + dsyslog("markad [%i]: using AC3 (0x%04x)",recvnumber,macontext.General.DPid.Num); ac3_demux = new cMarkAdDemux(recvnumber); } else @@ -405,17 +481,17 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) if (!abort) { decoder = new cMarkAdDecoder(recvnumber,macontext.General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264, - macontext.General.DPid.Num!=0); + macontext.General.APid.Num!=0,macontext.General.DPid.Num!=0); video = new cMarkAdVideo(recvnumber,&macontext); audio = new cMarkAdAudio(recvnumber,&macontext); - common = new cMarkAdCommon(recvnumber,&macontext); + streaminfo = new cMarkAdStreamInfo; } else { decoder=NULL; video=NULL; audio=NULL; - common=NULL; + streaminfo=NULL; } framecnt=0; @@ -429,7 +505,7 @@ cMarkAdStandalone::~cMarkAdStandalone() if (decoder) delete decoder; if (video) delete video; if (audio) delete audio; - if (common) delete common; + if (streaminfo) delete streaminfo; } bool isnumber(const char *s) @@ -557,6 +633,10 @@ int main(int argc, char *argv[]) bNice = true; break; + case 'B': + // backupmarks + break; + case 'O': // --OSD break; @@ -571,7 +651,6 @@ int main(int argc, char *argv[]) case 'j': case 'a': case 'S': - case 'B': case 'n': case 'C': break; @@ -592,7 +671,8 @@ int main(int argc, char *argv[]) break; case 1: // --markfile - //setMarkfileName(optarg); // TODO: implement this + strncpy(markFileName,optarg,1024); + markFileName[1023]=0; break; case 2: // --loglevel diff --git a/markad-standalone.h b/markad-standalone.h index 145a9ea..fcde1fa 100644 --- a/markad-standalone.h +++ b/markad-standalone.h @@ -23,11 +23,9 @@ #include "decoder.h" #include "video.h" #include "audio.h" -#include "common.h" +#include "streaminfo.h" #include "version.h" -int SysLogLevel=2; - class cMarkAdStandalone { private: @@ -142,14 +140,13 @@ unsigned Descriptor_Length: 8; }; - cMarkAdDemux *video_demux; cMarkAdDemux *ac3_demux; cMarkAdDemux *mp2_demux; cMarkAdDecoder *decoder; cMarkAdVideo *video; cMarkAdAudio *audio; - cMarkAdCommon *common; + cMarkAdStreamInfo *streaminfo; MarkAdContext macontext; int recvnumber; @@ -159,6 +156,11 @@ unsigned Descriptor_Length: int framecnt; bool abort; + bool noticeVDR_MP2; + bool noticeVDR_AC3; + + void SaveFrame(int Frame); + char *IndexToHMSF(int Index); void AddMark(MarkAdMark *Mark); bool CheckPATPMT(const char *Directory); bool CheckTS(const char *Directory); @@ -18,7 +18,7 @@ typedef unsigned char uchar; #include <string.h> #include "global.h" -#include "tools.h" +#include "queue.h" class cMarkAdPES2ES { @@ -6,18 +6,22 @@ * $Id$ */ -#include "tools.h" +#include "queue.h" cMarkAdPaketQueue::cMarkAdPaketQueue(int RecvNumber, const char *Name, int Size) { recvnumber=RecvNumber; inptr=0; outptr=0; + memset(&pktinfo,0,sizeof(pktinfo)); pktinfo.pkthdr=-1; maxqueue=Size; name=strdup(Name); buffer=(uchar *) malloc(Size+1); if (!buffer) maxqueue=0; + scanner=0xFFFFFFFF; + scannerstart=-1; + percent=-1; } cMarkAdPaketQueue::~cMarkAdPaketQueue() @@ -70,10 +74,13 @@ bool cMarkAdPaketQueue::Put(uchar *Data, int Size) memcpy(&buffer[inptr],Data,Size); inptr+=Size; - if ((inptr>(0.9*maxqueue)) && (name)) + int npercent=((double) inptr/(double) maxqueue)*100; + + if ((npercent>90) && (name) && (npercent!=percent)) { - dsyslog("markad [%i]: buffer %s usage: %3.f%%",recvnumber, - name,((double) inptr/(double) maxqueue)*100); + dsyslog("markad [%i]: buffer %s usage: %3i%%",recvnumber, + name,npercent); + percent=npercent; } return true; @@ -93,28 +100,45 @@ uchar *cMarkAdPaketQueue::Get(int *Size) return ret; } -int cMarkAdPaketQueue::FindPktHeader(int Start, int *StreamSize,int *HeaderSize) +int cMarkAdPaketQueue::FindPktHeader(int Start, int *StreamSize,int *HeaderSize, bool LongStartCode) { if ((!StreamSize) || (!HeaderSize)) return -1; if (!Start) Start=outptr; - if (Start>inptr) return -1; + if (Start>=inptr) return -1; *StreamSize=0; - *HeaderSize=4; // 0x0 0x0 0x1 0xNN - unsigned long scanner=0xFFFFFFFF; + if (LongStartCode) + { + *HeaderSize=4; // 0x0 0x0 0x0 0x1 + } + else + { + *HeaderSize=3; // 0x0 0x0 0x1 + } int i; - for (i=Start; i<inptr; i++) + if (scanner!=0xFFFFFFFF) { scanner<<=8; - if (scanner==0x00000100L) + scanner|=buffer[Start++]; + } + + for (i=Start; i<inptr; i++) + { + if (LongStartCode) { - break; + if (scanner==1L) break; + if ((scanner & 0xFFFFFFF0)==0x1E0L) break; + } + else + { + if ((scanner & 0x00FFFFFF)==1L) break; } + scanner<<=8; scanner|=buffer[i]; } if (i==inptr) return -1; - + if (LongStartCode) i--; if (buffer[i]>=0xBC)// do we have a PES packet? { #define PESHDRSIZE 6 @@ -125,44 +149,63 @@ int cMarkAdPaketQueue::FindPktHeader(int Start, int *StreamSize,int *HeaderSize) *StreamSize=(buffer[i+1]<<8)+buffer[i+2]; if (*StreamSize) (*StreamSize)+=PESHDRSIZE; // 6 Byte PES-Header - - struct PESHDROPT *peshdropt=(struct PESHDROPT *) &buffer[i+3]; - if (peshdropt->MarkerBits==0x2) - { - *HeaderSize=PESHDRSIZE+sizeof(struct PESHDROPT)+ - peshdropt->Length; - } - else + if (LongStartCode) { - *HeaderSize=PESHDRSIZE; + struct PESHDROPT *peshdropt=(struct PESHDROPT *) &buffer[i+3]; + if (peshdropt->MarkerBits==0x2) + { + *HeaderSize=PESHDRSIZE+sizeof(struct PESHDROPT)+ + peshdropt->Length; + } + else + { + *HeaderSize=PESHDRSIZE; + } } } + return i-3; } int cMarkAdPaketQueue::FindAudioHeader(int Start, int *FrameSize, int *HeaderSize, bool AC3) { + if ((!FrameSize) || (!HeaderSize)) return -1; if (!Start) Start=outptr; - if (Start>inptr) return -1; - if (FrameSize) (*FrameSize)=0; - if (HeaderSize) (*HeaderSize)=4; - unsigned short scanner=0x0; + if (Start>=inptr) return -1; + (*FrameSize)=0; + if (AC3) + { + (*HeaderSize)=2; + } + else + { + (*HeaderSize)=3; + } int i; + + if (scanner!=0xFFFFFFFF) + { + scanner<<=8; + scanner|=buffer[Start++]; + } + for (i=Start; i<inptr; i++) { - scanner|=buffer[i]; + if (AC3) { - if (scanner==0x0B77) break; + if ((scanner & 0x0000FFFF)==0xB77L) break; } else { - if ((scanner & 0xFFE0)==0xFFE0) break; + if ((scanner & 0x00000FFE)==0xFFEL) break; } + scanner<<=8; + scanner|=buffer[i]; } if (i==inptr) return -1; - i--; + i-=2; if (AC3) { @@ -170,7 +213,6 @@ int cMarkAdPaketQueue::FindAudioHeader(int Start, int *FrameSize, int *HeaderSiz if (ac3hdr->SampleRateIndex==3) return -1; // reserved if (ac3hdr->FrameSizeIndex>=38) return -1; // reserved - if (HeaderSize) (*HeaderSize)=sizeof(struct AC3HDR); if (FrameSize) { @@ -202,8 +244,6 @@ int cMarkAdPaketQueue::FindAudioHeader(int Start, int *FrameSize, int *HeaderSiz if (mp2hdr->SampleRateIndex==3) return -1; //reserved if (mp2hdr->Emphasis==2) return -1; // reserved - if (HeaderSize) (*HeaderSize)=sizeof(struct MP2HDR); - if (FrameSize) { int bitRates[3][3][16] = // all values are specified as kbits/s @@ -279,30 +319,48 @@ uchar *cMarkAdPaketQueue::GetPacket(int *Size, int Type) { if (!Size) return NULL; *Size=0; - if (!Length()) return NULL; + if (Length()<4) return NULL; - if (pktinfo.pkthdr==-1) + if ((Type==MA_PACKET_H264) && (pktinfo.pktsyncsize>5) && (pktinfo.pkthdr!=-1)) { + // ignore PES paket + pktinfo.pkthdr=-1; + outptr+=pktinfo.pktsyncsize; + } + if (pktinfo.pkthdr==-1) + { + scanner=0xFFFFFFFF; switch (Type) { case MA_PACKET_AC3: - pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pkthdrsize, true); + pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize, true); break; case MA_PACKET_MP2: - pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pkthdrsize, false); + pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize, false); + break; + case MA_PACKET_H264: + pktinfo.pkthdr=FindPktHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,true); + if (pktinfo.pktsyncsize>5) + { + // ignore PES paket + pktinfo.pkthdr=-1; + outptr+=pktinfo.pktsyncsize; + } break; default: - pktinfo.pkthdr=FindPktHeader(0,&pktinfo.streamsize,&pktinfo.pkthdrsize); + pktinfo.pkthdr=FindPktHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,false); + break; } if (pktinfo.pkthdr==-1) { return NULL; } + scannerstart=pktinfo.pkthdr+pktinfo.pktsyncsize; } - int start,streamsize,pkthdrsize,pkthdr=-1; + int streamsize,pktsyncsize,pkthdr=-1; if (pktinfo.streamsize) { @@ -312,27 +370,33 @@ uchar *cMarkAdPaketQueue::GetPacket(int *Size, int Type) } else { - start=pktinfo.pkthdr+pktinfo.streamsize; + scannerstart=pktinfo.pkthdr+pktinfo.streamsize; + scanner=0xFFFFFFFF; } } - else - { - start=pktinfo.pkthdr+pktinfo.pkthdrsize; - } switch (Type) { case MA_PACKET_AC3: - pkthdr=FindAudioHeader(start,&streamsize,&pkthdrsize, true); + pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize, true); break; case MA_PACKET_MP2: - pkthdr=FindAudioHeader(start,&streamsize,&pkthdrsize, false); + pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize, false); + break; + case MA_PACKET_H264: + pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize, true); break; default: - pkthdr=FindPktHeader(start,&streamsize,&pkthdrsize); + pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize, false); + break; } - if (pkthdr==-1) return NULL; + if (pkthdr==-1) + { + scannerstart=inptr; + return NULL; + } + scannerstart=pkthdr+pktsyncsize; uchar *ptr=&buffer[pktinfo.pkthdr]; @@ -350,6 +414,7 @@ uchar *cMarkAdPaketQueue::GetPacket(int *Size, int Type) if (pktinfo.pkthdr>(4096+bytesleft)) { memcpy(buffer,&buffer[pkthdr],bytesleft); + scannerstart-=outptr; inptr=bytesleft; outptr=0; pkthdr=0; @@ -357,7 +422,7 @@ uchar *cMarkAdPaketQueue::GetPacket(int *Size, int Type) pktinfo.pkthdr=pkthdr; pktinfo.streamsize=streamsize; - pktinfo.pkthdrsize=pkthdrsize; + pktinfo.pktsyncsize=pktsyncsize; return ptr; } @@ -1,13 +1,13 @@ /* - * tools.h: A plugin for the Video Disk Recorder + * queue.h: A plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * * $Id$ */ -#ifndef __tools_h_ -#define __tools_h_ +#ifndef __queue_h_ +#define __queue_h_ #include <vdr/tools.h> // needed for (d/e/i)syslog @@ -109,16 +109,23 @@ private: struct pktinfo { int pkthdr; - int pkthdrsize; + int pktsyncsize; int streamsize; + bool ispes; } pktinfo; + int percent; + uchar *buffer; int maxqueue; int inptr; int outptr; - int FindPktHeader(int Start, int *StreamSize,int *HeaderSize); - int FindAudioHeader(int Start, int *FrameSize, int *HeaderSize, bool AC3); + + unsigned long scanner; + int scannerstart; + + int FindPktHeader(int Start, int *StreamSize,int *SyncSize, bool LongStartCode); + int FindAudioHeader(int Start, int *FrameSize, int *SyncSize, bool AC3); public: cMarkAdPaketQueue(int RecvNumber, const char *Name, int Size=32768); ~cMarkAdPaketQueue(); @@ -130,14 +137,17 @@ public: { inptr=outptr=0; pktinfo.pkthdr=-1; + scanner=0xFFFFFFFF; + scannerstart=-1; } bool Inject(uchar *Data, int Size); bool Put(uchar *Data, int Size); uchar *Get(int *Size); -#define MA_PACKET_PKT 1 -#define MA_PACKET_AC3 2 -#define MA_PACKET_MP2 3 +#define MA_PACKET_PKT 0x10 // 0x00 0x00 0x01 (PES / H262) +#define MA_PACKET_H264 0x11 // 0x00 0x00 0x00 0x01 (H264) +#define MA_PACKET_AC3 0x20 +#define MA_PACKET_MP2 0x30 uchar *GetPacket(int *Size, int Type); }; @@ -8,12 +8,20 @@ #include "recv.h" +#if APIVERSNUM > 10711 +cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *Timer) + : + cReceiver(Timer->Channel()->GetChannelID(), -1), + cThread("markad"), + buffer(MEGATS(3)), running(false) // 3MB Buffer +#else cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *Timer) : cReceiver(Timer->Channel()->GetChannelID(), -1, Timer->Channel()->Vpid(),Timer->Channel()->Dpids()), - cThread("markad"), + cThread("markad"), buffer(MEGATS(3)), running(false) // 3MB Buffer +#endif { if ((!Filename) || (!Timer)) return; @@ -23,46 +31,37 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *T // 10 ms timeout on getting TS frames buffer.SetTimeouts(0, 10); - bool useH264=false; -#if APIVERSNUM >= 10700 -#ifdef DVBFE_DELSYS_DVBS2 - if (Timer->Channel()->System()==DVBFE_DELSYS_DVBS2) useH264=true; -#else - if (Timer->Channel()->System()==SYS_DVBS2) useH264=true; -#endif -#endif memset(&macontext,0,sizeof(macontext)); - if (Timer->Event()) - { - macontext.General.StartTime=Timer->Event()->StartTime(); - macontext.General.EndTime=Timer->Event()->EndTime(); - } - else - { - macontext.General.StartTime=Timer->StartTime(); - macontext.General.EndTime=Timer->StopTime(); - macontext.General.ManualRecording=true; - } - macontext.General.VPid.Num=Timer->Channel()->Vpid(); - if (useH264) - { - macontext.General.VPid.Type=MARKAD_PIDTYPE_VIDEO_H264; - } - else + +#if APIVERSNUM == 10700 +#error "VDR-1.7.0 is not supported" +#endif +#if APIVERSNUM > 10700 + switch Timer->Channel()->Vtype() { + case 0x2: macontext.General.VPid.Type=MARKAD_PIDTYPE_VIDEO_H262; + break; + case 0x1b: + macontext.General.VPid.Type=MARKAD_PIDTYPE_VIDEO_H264; + break; + default: + macontext.General.VPid.Num=0; + macontext.General.VPid.Type=0; + break; } +#else + macontext.General.VPid.Type=MARKAD_PIDTYPE_VIDEO_H262; +#endif -// macontext.General.APid.Pid=Timer->Channel()->Apid(0); // TODO ... better solution? -// macontext.General.APid.Type=MARKAD_PIDTYPE_AUDIO_MP2; - - macontext.General.DPid.Num=Timer->Channel()->Dpid(0); // TODO ... better solution? + macontext.General.DPid.Num=Timer->Channel()->Dpid(0); // ... better solution? macontext.General.DPid.Type=MARKAD_PIDTYPE_AUDIO_AC3; if (macontext.General.VPid.Num) { - dsyslog("markad [%i]: using %s-video",recvnumber,useH264 ? "H264": "H262"); + dsyslog("markad [%i]: using %s-video",recvnumber, + (macontext.General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264) ? "H264": "H262"); video=new cMarkAdVideo(RecvNumber,&macontext); video_demux = new cMarkAdDemux(RecvNumber); } @@ -92,12 +91,31 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *T } streaminfo=new cMarkAdStreamInfo; - common=new cMarkAdCommon(RecvNumber,&macontext); marks.Load(Filename); + Index=NULL; lastiframe=0; framecnt=-1; + marksfound=false; + + if (!marks.Count()) + { + MarkAdMark tempmark; + char *buf; + tempmark.Position=0; + if (asprintf(&buf,"start of recording (0)")!=-1) + { + tempmark.Comment=buf; + AddMark(&tempmark,0); + isyslog("markad [%i]: %s",recvnumber,buf); + free(buf); + } + } + else + { + marksfound=true; + } } cMarkAdReceiver::~cMarkAdReceiver() @@ -111,12 +129,27 @@ cMarkAdReceiver::~cMarkAdReceiver() } buffer.Clear(); + if (lastiframe) + { + MarkAdMark tempmark; + tempmark.Position=lastiframe; + char *buf; + + if (asprintf(&buf,"stop of recording (%i)",lastiframe)!=-1) + { + tempmark.Comment=buf; + AddMark(&tempmark,0); + isyslog("markad [%i]: %s",recvnumber,buf); + free(buf); + } + } + + if (Index) delete Index; if (video_demux) delete video_demux; if (ac3_demux) delete ac3_demux; if (streaminfo) delete streaminfo; if (video) delete video; if (audio) delete audio; - if (common) delete common; if (filename) free(filename); } @@ -181,22 +214,6 @@ void cMarkAdReceiver::Activate(bool On) } else if (running) { - if ((!macontext.State.ContentStopped) && (lastiframe)) - { - MarkAdMark tempmark; - tempmark.Position=lastiframe; - - char *buf; - if (asprintf(&buf,"stop of user content (%i)",lastiframe)!=-1) - { - tempmark.Comment=buf; - AddMark(&tempmark,0); - isyslog("markad [%i]: %s",recvnumber,buf); - free(buf); - } - } - - if (Index) delete Index; running = false; buffer.Signal(); Cancel(2); @@ -228,8 +245,9 @@ void cMarkAdReceiver::Receive(uchar *Data, int Length) void cMarkAdReceiver::AddMark(MarkAdMark *mark, int Priority) { if (!mark) return; - if (!mark->Position) return; if (!mark->Comment) return; + if (mark->Position<0) return; + cMark *newmark=marks.Add(mark->Position); if (newmark) { @@ -242,35 +260,28 @@ void cMarkAdReceiver::AddMark(MarkAdMark *mark, int Priority) } marks.Save(); -#define MAXPOSDIFF (25*60*9) // = 9 min - - cMark *prevmark=marks.GetPrev(mark->Position); - if (!prevmark) return; - if (!prevmark->comment) return; - if (abs(mark->Position-prevmark->position)>MAXPOSDIFF) return; - - int prevPriority=atoi(prevmark->comment+1); - if (prevPriority==Priority) return; - - if (prevPriority>Priority) + if (!marksfound) { - // add text from mark to prevmark - prevmark->comment=strcatrealloc(prevmark->comment," "); - prevmark->comment=strcatrealloc(prevmark->comment,mark->Comment); - - dsyslog("markad [%i]: delete mark %i",recvnumber,newmark->position); - marks.Del(newmark,true); - } - else - { - // add text from prevmark to mark - mark->Comment=strcatrealloc(mark->Comment," "); - mark->Comment=strcatrealloc(mark->Comment,prevmark->comment); - - dsyslog("markad [%i]: delete previous mark %i",recvnumber,prevmark->position); - marks.Del(prevmark,true); + cMark *prevmark=marks.GetPrev(mark->Position); + if (!prevmark) return; + if (!prevmark->comment) return; + if (prevmark->position==0) return; +#define MAXPOSDIFF (25*60*13) // = 13 min + if (abs(mark->Position-prevmark->position)>MAXPOSDIFF) + { + cMark *firstmark=marks.Get(0); + if (firstmark) + { + marks.Del(firstmark,true); + marks.Save(); + marksfound=true; + } + } + else + { + marksfound=true; + } } - marks.Save(); } void cMarkAdReceiver::Action() @@ -283,12 +294,6 @@ void cMarkAdReceiver::Action() lastiframe=LastIFrame(); MarkAdMark *mark; - if (common) - { - mark=common->Process(lastiframe); - AddMark(mark,0); - } - if ((video_demux) && (streaminfo) && (video)) { cTimeMs t; @@ -309,20 +314,22 @@ void cMarkAdReceiver::Action() { if (pkt) { - streaminfo->FindVideoInfos(&macontext,pkt,pktlen); - if (macontext.Video.Info.Pict_Type==MA_I_TYPE) + if (streaminfo->FindVideoInfos(&macontext,pkt,pktlen)) { - if (framecnt==-1) + if (macontext.Video.Info.Pict_Type==MA_I_TYPE) { - framecnt=0; - } - else - { - mark=video->Process(lastiframe); - AddMark(mark,3); + if (framecnt==-1) + { + framecnt=0; + } + else + { + mark=video->Process(lastiframe); + AddMark(mark,3); + } } + if (framecnt!=-1) framecnt++; } - if (framecnt!=-1) framecnt++; } tspkt+=len; tslen-=len; @@ -354,9 +361,11 @@ void cMarkAdReceiver::Action() { if (pkt) { - streaminfo->FindAC3AudioInfos(&macontext,pkt,pktlen); - mark=audio->Process(lastiframe); - AddMark(mark,2); + if (streaminfo->FindAC3AudioInfos(&macontext,pkt,pktlen)) + { + mark=audio->Process(lastiframe); + AddMark(mark,2); + } } tspkt+=len; tslen-=len; @@ -19,7 +19,6 @@ #include "streaminfo.h" #include "audio.h" #include "video.h" -#include "common.h" #if (APIVERSNUM >= 10700) #include <linux/dvb/frontend.h> @@ -58,6 +57,7 @@ private: char *filename; int lastiframe; int framecnt; + bool marksfound; char *strcatrealloc(char *dest, const char *src); cMarks marks; @@ -67,7 +67,6 @@ private: MarkAdContext macontext; cMarkAdStreamInfo *streaminfo; - cMarkAdCommon *common; cMarkAdAudio *audio; cMarkAdVideo *video; @@ -83,6 +82,10 @@ protected: bool running; public: cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *Timer); + bool FoundMarks() + { + return marksfound; + } const char *FileName() { return (const char *) filename; @@ -72,6 +72,10 @@ void cStatusMarkAd::Recording(const cDevice *Device, const char *Name, const cha dsyslog("markad [%i]: stop recording %s ",recvnumber,FileName); ((cDevice *) Device)->Detach(recv[recvnumber]); + if (!recv[recvnumber]->FoundMarks()) + { + // TODO: start standalone markad with logo detection + } delete recv[recvnumber]; recv[recvnumber]=NULL; } diff --git a/streaminfo.cpp b/streaminfo.cpp index 2c0b6a3..e3692d6 100644 --- a/streaminfo.cpp +++ b/streaminfo.cpp @@ -8,9 +8,9 @@ #include "streaminfo.h" -void cMarkAdStreamInfo::FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen) +bool cMarkAdStreamInfo::FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen) { - if ((!maContext) || (!espkt)) return; + if ((!maContext) || (!espkt)) return false; #pragma pack(1) struct AC3HDR @@ -43,8 +43,8 @@ unsigned AcMod: if ((ac3hdr->Sync1==0x0b) && (ac3hdr->Sync2==0x77)) { // some extra checks - if (ac3hdr->SampleRateIndex==3) return; // reserved - if (ac3hdr->FrameSizeIndex>=38) return; // reserved + if (ac3hdr->SampleRateIndex==3) return false; // reserved + if (ac3hdr->FrameSizeIndex>=38) return false; // reserved maContext->Audio.Info.Channels=0; int lfe_bitmask = 0x0; @@ -87,34 +87,37 @@ unsigned AcMod: if ((ac3hdr->LFE_Mix_VarField & lfe_bitmask)==lfe_bitmask) maContext->Audio.Info.Channels++; - } + return true; + } + return false; } -void cMarkAdStreamInfo::FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len) +bool cMarkAdStreamInfo::FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len) { - if ((!maContext) || (!pkt) || (!len)) return; - if (!maContext->General.VPid.Type) return; + if ((!maContext) || (!pkt) || (!len)) return false; + if (!maContext->General.VPid.Type) return false; - if (maContext->General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264) - { - FindH264VideoInfos(maContext, pkt, len); - } - else + switch (maContext->General.VPid.Type) { - FindH262VideoInfos(maContext, pkt, len); + case MARKAD_PIDTYPE_VIDEO_H264: + return FindH264VideoInfos(maContext, pkt, len); + break; + case MARKAD_PIDTYPE_VIDEO_H262: + return FindH262VideoInfos(maContext, pkt, len); + break; } + return false; } -void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) +bool cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) { - if ((!maContext) || (!pkt) || (!len)) return; - - maContext->Video.Info.Pict_Type=0; + if ((!maContext) || (!pkt) || (!len)) return false; - if ((pkt[3] & 0x1F)==NAL_AUD) + if ((pkt[4] & 0x1F)==NAL_AUD) { - switch (pkt[4] >> 5) + + switch (pkt[5] >> 5) { case 0: case 3: @@ -127,262 +130,37 @@ void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, maContext->Video.Info.Pict_Type=MA_P_TYPE; break; case 2: - case 7: // B_FRAME; + case 7: // B_FRAME; maContext->Video.Info.Pict_Type=MA_B_TYPE; break; default: // NO_PICTURE; - maContext->Video.Info.Pict_Type=0; + return false; break; } + return true; } - if ((pkt[3] & 0x1F)==NAL_SPS) + if ((pkt[4] & 0x1F)==NAL_SPS) { uint8_t nal_data[len]; - const uint8_t *end = pkt + len; - int nal_len = nalUnescape(nal_data, pkt + 4, int(end - pkt - 4)); - - int profile_idc, level_idc, constraint_set3_flag, pic_order_cnt_type, i, j; + int nal_len = nalUnescape(nal_data, pkt + 5, len - 5); cBitStream bs(nal_data, nal_len); + int profile_idc, pic_order_cnt_type, i, j; + uint32_t width=0; uint32_t height=0; uint32_t aspect_ratio_idc=0; - uint32_t video_format=0; double frame_rate=0; - double bit_rate=0; - bool cpb_dpb_delays_present_flag=false; - bool pic_struct_present_flag=false; bool frame_mbs_only_flag=false; - bool mb_adaptive_frame_field_flag=false; - uint32_t time_offset_length=0; profile_idc = bs.getU8(); // profile_idc - bs.skipBit(); // constraint_set0_flag - bs.skipBit(); // constraint_set1_flag - bs.skipBit(); // constraint_set2_flag - constraint_set3_flag = bs.getBit(); // constraint_set3_flag - bs.skipBits(4); // reserved_zero_4bits - level_idc = bs.getU8(); // level_idc + bs.skipBits(8); // constraint_setN_flags and reserved_zero_Nbits + bs.skipBits(8); // level_idc bs.skipUeGolomb(); // seq_parameter_set_id - switch (profile_idc) - { - case 66: // baseline profile - case 77: // main profile - case 88: // extended profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 64000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 128000 : 192000; - break; - case 12: // level 1.2 - bit_rate = 384000; - break; - case 13: // level 1.3 - bit_rate = 768000; - break; - case 20: // level 2.0 - bit_rate = 2000000; - break; - case 21: // level 2.1 - bit_rate = 4000000; - break; - case 22: // level 2.2 - bit_rate = 4000000; - break; - case 30: // level 3.0 - bit_rate = 10000000; - break; - case 31: // level 3.1 - bit_rate = 14000000; - break; - case 32: // level 3.2 - bit_rate = 20000000; - break; - case 40: // level 4.0 - bit_rate = 20000000; - break; - case 41: // level 4.1 - bit_rate = 50000000; - break; - case 42: // level 4.2 - bit_rate = 50000000; - break; - case 50: // level 5.0 - bit_rate = 135000000; - break; - case 51: // level 5.1 - bit_rate = 240000000; - break; - default: - break; - } - break; - case 100: // high profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 80000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 160000 : 240000; - break; - case 12: // level 1.2 - bit_rate = 480000; - break; - case 13: // level 1.3 - bit_rate = 960000; - break; - case 20: // level 2.0 - bit_rate = 2500000; - break; - case 21: // level 2.1 - bit_rate = 5000000; - break; - case 22: // level 2.2 - bit_rate = 5000000; - break; - case 30: // level 3.0 - bit_rate = 12500000; - break; - case 31: // level 3.1 - bit_rate = 17500000; - break; - case 32: // level 3.2 - bit_rate = 25000000; - break; - case 40: // level 4.0 - bit_rate = 25000000; - break; - case 41: // level 4.1 - bit_rate = 62500000; - break; - case 42: // level 4.2 - bit_rate = 62500000; - break; - case 50: // level 5.0 - bit_rate = 168750000; - break; - case 51: // level 5.1 - bit_rate = 300000000; - break; - default: - break; - } - break; - case 110: // high 10 profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 192000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 384000 : 576000; - break; - case 12: // level 1.2 - bit_rate = 115200; - break; - case 13: // level 1.3 - bit_rate = 2304000; - break; - case 20: // level 2.0 - bit_rate = 6000000; - break; - case 21: // level 2.1 - bit_rate = 12000000; - break; - case 22: // level 2.2 - bit_rate = 12000000; - break; - case 30: // level 3.0 - bit_rate = 30000000; - break; - case 31: // level 3.1 - bit_rate = 42000000; - break; - case 32: // level 3.2 - bit_rate = 60000000; - break; - case 40: // level 4.0 - bit_rate = 60000000; - break; - case 41: // level 4.1 - bit_rate = 150000000; - break; - case 42: // level 4.2 - bit_rate = 150000000; - break; - case 50: // level 5.0 - bit_rate = 405000000; - break; - case 51: // level 5.1 - bit_rate = 720000000; - break; - default: - break; - } - break; - case 122: // high 4:2:2 profile - case 144: // high 4:4:4 profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 256000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 512000 : 768000; - break; - case 12: // level 1.2 - bit_rate = 1536000; - break; - case 13: // level 1.3 - bit_rate = 3072000; - break; - case 20: // level 2.0 - bit_rate = 8000000; - break; - case 21: // level 2.1 - bit_rate = 16000000; - break; - case 22: // level 2.2 - bit_rate = 16000000; - break; - case 30: // level 3.0 - bit_rate = 40000000; - break; - case 31: // level 3.1 - bit_rate = 56000000; - break; - case 32: // level 3.2 - bit_rate = 80000000; - break; - case 40: // level 4.0 - bit_rate = 80000000; - break; - case 41: // level 4.1 - bit_rate = 200000000; - break; - case 42: // level 4.2 - bit_rate = 200000000; - break; - case 50: // level 5.0 - bit_rate = 540000000; - break; - case 51: // level 5.1 - bit_rate = 960000000; - break; - default: - break; - } - break; - default: - break; - } - if ((profile_idc == 100) || (profile_idc == 110) || (profile_idc == 122) || (profile_idc == 144)) + if ((profile_idc == 100) || (profile_idc == 110) || (profile_idc == 122) || (profile_idc == 244) || + (profile_idc==44) || (profile_idc==83) || (profile_idc==86)) { if (bs.getUeGolomb() == 3) // chroma_format_idc bs.skipBit(); // residual_colour_transform_flag @@ -419,7 +197,7 @@ void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, for (i = 0; i < j; ++i) bs.skipSeGolomb(); // offset_for_ref_frame[i] } - bs.skipUeGolomb(); // num_ref_frames + bs.skipUeGolomb(); // max num_ref_frames bs.skipBit(); // gaps_in_frame_num_value_allowed_flag width = bs.getUeGolomb() + 1; // pic_width_in_mbs_minus1 height = bs.getUeGolomb() + 1; // pic_height_in_mbs_minus1 @@ -427,7 +205,7 @@ void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, width *= 16; height *= 16 * (frame_mbs_only_flag ? 1 : 2); if (!frame_mbs_only_flag) - mb_adaptive_frame_field_flag = bs.getBit(); // mb_adaptive_frame_field_flag + bs.skipBit(); // mb_adaptive_frame_field_flag bs.skipBit(); // direct_8x8_inference_flag if (bs.getBit()) // frame_cropping_flag { @@ -458,7 +236,7 @@ void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, bs.skipBit(); // overscan_approriate_flag if (bs.getBit()) // video_signal_type_present_flag { - video_format = bs.getBits(3); // video_format + bs.skipBits(3); // video_format bs.skipBit(); // video_full_range_flag if (bs.getBit()) // colour_description_present_flag { @@ -478,64 +256,68 @@ void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, num_units_in_tick = bs.getU32(); // num_units_in_tick time_scale = bs.getU32(); // time_scale if (num_units_in_tick > 0) - frame_rate = time_scale / num_units_in_tick; - bs.skipBit(); // fixed_frame_rate_flag - } - int nal_hrd_parameters_present_flag = bs.getBit(); // nal_hrd_parameters_present_flag - if (nal_hrd_parameters_present_flag) - { - int cpb_cnt_minus1; - cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 - bs.skipBits(4); // bit_rate_scale - bs.skipBits(4); // cpb_size_scale - for (int i = 0; i < cpb_cnt_minus1; ++i) - { - bs.skipUeGolomb(); // bit_rate_value_minus1[i] - bs.skipUeGolomb(); // cpb_size_value_minus1[i] - bs.skipBit(); // cbr_flag[i] - } - bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 - bs.skipBits(5); // cpb_removal_delay_length_minus1 - bs.skipBits(5); // dpb_output_delay_length_minus1 - time_offset_length = bs.getBits(5); // time_offset_length - } - int vlc_hrd_parameters_present_flag = bs.getBit(); // vlc_hrd_parameters_present_flag - if (vlc_hrd_parameters_present_flag) - { - int cpb_cnt_minus1; - cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 - bs.skipBits(4); // bit_rate_scale - bs.skipBits(4); // cpb_size_scale - for (int i = 0; i < cpb_cnt_minus1; ++i) - { - bs.skipUeGolomb(); // bit_rate_value_minus1[i] - bs.skipUeGolomb(); // cpb_size_value_minus1[i] - bs.skipBit(); // cbr_flag[i] - } - bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 - bs.skipBits(5); // cpb_removal_delay_length_minus1 - bs.skipBits(5); // dpb_output_delay_length_minus1 - time_offset_length = bs.getBits(5);// time_offset_length - } - cpb_dpb_delays_present_flag = (nal_hrd_parameters_present_flag | vlc_hrd_parameters_present_flag); - if (cpb_dpb_delays_present_flag) - bs.skipBit(); // low_delay_hrd_flag - pic_struct_present_flag = bs.getBit(); // pic_struct_present_flag - if (bs.getBit()) // bitstream_restriction_flag - { - bs.skipBit(); // motion_vectors_over_pic_boundaries_flag - bs.skipUeGolomb(); // max_bytes_per_pic_denom - bs.skipUeGolomb(); // max_bits_per_mb_denom - bs.skipUeGolomb(); // log2_max_mv_length_horizontal - bs.skipUeGolomb(); // log2_max_mv_length_vertical - bs.skipUeGolomb(); // num_reorder_frames - bs.skipUeGolomb(); // max_dec_frame_buffering + frame_rate = time_scale / (2*num_units_in_tick); + + //bs.skipBit(); // fixed_frame_rate_flag } + /* + int nal_hrd_parameters_present_flag = bs.getBit(); // nal_hrd_parameters_present_flag + if (nal_hrd_parameters_present_flag) + { + int cpb_cnt_minus1; + cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 + bs.skipBits(4); // bit_rate_scale + bs.skipBits(4); // cpb_size_scale + for (int i = 0; i <= cpb_cnt_minus1; i++) + { + bs.skipUeGolomb(); // bit_rate_value_minus1[i] + bs.skipUeGolomb(); // cpb_size_value_minus1[i] + bs.skipBit(); // cbr_flag[i] + } + bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 + bs.skipBits(5); // cpb_removal_delay_length_minus1 + bs.skipBits(5); // dpb_output_delay_length_minus1 + bs.skipBits(5); // time_offset_length + } + int vlc_hrd_parameters_present_flag = bs.getBit(); // vlc_hrd_parameters_present_flag + if (vlc_hrd_parameters_present_flag) + { + int cpb_cnt_minus1; + cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 + bs.skipBits(4); // bit_rate_scale + bs.skipBits(4); // cpb_size_scale + for (int i = 0; i <= cpb_cnt_minus1; i++) + { + bs.skipUeGolomb(); // bit_rate_value_minus1[i] + bs.skipUeGolomb(); // cpb_size_value_minus1[i] + bs.skipBit(); // cbr_flag[i] + } + bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 + bs.skipBits(5); // cpb_removal_delay_length_minus1 + bs.skipBits(5); // dpb_output_delay_length_minus1 + bs.skipBits(5); // time_offset_length + } + cpb_dpb_delays_present_flag = (nal_hrd_parameters_present_flag | vlc_hrd_parameters_present_flag); + if (cpb_dpb_delays_present_flag) + bs.skipBit(); // low_delay_hrd_flag + bs.skipBit(); // pic_struct_present_flag + if (bs.getBit()) // bitstream_restriction_flag + { + bs.skipBit(); // motion_vectors_over_pic_boundaries_flag + bs.skipUeGolomb(); // max_bytes_per_pic_denom + bs.skipUeGolomb(); // max_bits_per_mb_denom + bs.skipUeGolomb(); // log2_max_mv_length_horizontal + bs.skipUeGolomb(); // log2_max_mv_length_vertical + bs.skipUeGolomb(); // num_reorder_frames + bs.skipUeGolomb(); // max_dec_frame_buffering + } + */ } if ((bs.getIndex() / 8)>0) { // set values + maContext->Video.Info.FramesPerSecond=frame_rate; maContext->Video.Info.Width=width; maContext->Video.Info.Height=height; @@ -544,6 +326,30 @@ void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, case 1: maContext->Video.Info.AspectRatio.Num=1; maContext->Video.Info.AspectRatio.Den=1; + + if (height==1080) + { + if (width==1920) + { + maContext->Video.Info.AspectRatio.Num=16; + maContext->Video.Info.AspectRatio.Den=9; + } + } + + if (height==720) + { + if (width==960) + { + maContext->Video.Info.AspectRatio.Num=4; + maContext->Video.Info.AspectRatio.Den=3; + } + + if (width==1280) + { + maContext->Video.Info.AspectRatio.Num=16; + maContext->Video.Info.AspectRatio.Den=9; + } + } break; case 2: maContext->Video.Info.AspectRatio.Num=12; @@ -608,13 +414,22 @@ void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, } } } + return false; } -void cMarkAdStreamInfo::FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) +const uint8_t *cMarkAdStreamInfo::nextStartCode(const uint8_t *start, const uint8_t *end) { - if ((!maContext) || (!pkt) || (!len)) return; + for (end -= 4; start < end; ++start) + { + if ((start[0] == 0x00) && (start[1] == 0x00) && (start[2] == 0x00) && (start[3] == 0x01)) + return start; + } + return (end + 4); +} - maContext->Video.Info.Pict_Type=0; +bool cMarkAdStreamInfo::FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) +{ + if ((!maContext) || (!pkt) || (!len)) return false; struct H262_SequenceHdr { @@ -665,7 +480,7 @@ unsigned TemporalReferenceL: if (pichdr->Sync1==0 && pichdr->Sync2==0 && pichdr->Sync3==1 && pichdr->Sync4==0) { - if (maContext->Video.Info.Height==0) return; + if (maContext->Video.Info.Height==0) return false; switch (pichdr->CodingType) { @@ -682,9 +497,10 @@ unsigned TemporalReferenceL: maContext->Video.Info.Pict_Type=MA_D_TYPE; break; default: - maContext->Video.Info.Pict_Type=0; + return false; break; } + return true; } if (seqhdr->Sync1==0 && seqhdr->Sync2==0 && seqhdr->Sync3==1 && seqhdr->Sync4==0xb3) @@ -714,9 +530,127 @@ unsigned TemporalReferenceL: default: break; } + + switch (seqhdr->FrameRateIndex) + { + case 1: + maContext->Video.Info.FramesPerSecond=24000/1001; // 23.976 fps NTSC encapsulated + break; + case 2: + maContext->Video.Info.FramesPerSecond=24.0; // Standard international cinema film rate + break; + case 3: + maContext->Video.Info.FramesPerSecond=25.0; // PAL (625/50) video frame rate + break; + + case 4: + maContext->Video.Info.FramesPerSecond=30000/1001; // 29.97 NTSC video frame rate + break; + + case 5: + maContext->Video.Info.FramesPerSecond=30.0; // NTSC drop frame (525/60) video frame rate + break; + + case 6: + maContext->Video.Info.FramesPerSecond=50.0; // double frame rate/progressive PAL + break; + + case 7: + maContext->Video.Info.FramesPerSecond=60000/1001; // double frame rate NTSC + break; + + case 8: + maContext->Video.Info.FramesPerSecond=60.0; // double frame rate drop-frame NTSC + break; + + default: + break; + } + + } + return false; +} + +/* +// taken from ffmpeg +int cMarkAdStreamInfo::nalUnescape(uint8_t *dst, const uint8_t *src, int length) +{ + int i; + +#if HAVE_FAST_UNALIGNED +# if HAVE_FAST_64BIT +# define RS 7 + for (i=0; i+1<length; i+=9) + { + if (!((~*(const uint64_t*)(src+i) & (*(const uint64_t*)(src+i) - 0x0100010001000101ULL)) & 0x8000800080008080ULL)) +# else +# define RS 3 + for (i=0; i+1<length; i+=5) + { + if (!((~*(const uint32_t*)(src+i) & (*(const uint32_t*)(src+i) - 0x01000101U)) & 0x80008080U)) +# endif + continue; + if (i>0 && !src[i]) i--; + while (src[i]) i++; +#else +# define RS 0 + for (i=0; i+1<length; i+=2) + { + if (src[i]) continue; + if (i>0 && src[i-1]==0) i--; +#endif + if (i+2<length && src[i+1]==0 && src[i+2]<=3) + { + if (src[i+2]!=3) + { + // startcode, so we must be past the end + length=i; + } + break; + } + i-= RS; + } + + memcpy(dst,src,i); + + if (i>=length-1) //no escaped 0 + { + return length; + } + + int si,di; + si=di=i; + while (si+2<length) + { + //remove escapes (very rare 1:2^22) + if (src[si+2]>3) + { + dst[di++]= src[si++]; + dst[di++]= src[si++]; + } + else if (src[si]==0 && src[si+1]==0) + { + if (src[si+2]==3) //escape + { + dst[di++]= 0; + dst[di++]= 0; + si+=3; + continue; + } + else //next start code + goto nsc; + } + + dst[di++]= src[si++]; } + while (si<length) + dst[di++]= src[si++]; +nsc: + return di; } +*/ + // taken from femon int cMarkAdStreamInfo::nalUnescape(uint8_t *dst, const uint8_t *src, int len) @@ -744,9 +678,10 @@ int cMarkAdStreamInfo::nalUnescape(uint8_t *dst, const uint8_t *src, int len) return d; } + cBitStream::cBitStream(const uint8_t *buf, const int len) : data(buf), - count(len), + count(len*8), index(0) { } diff --git a/streaminfo.h b/streaminfo.h index 5c74b0c..7b94e21 100644 --- a/streaminfo.h +++ b/streaminfo.h @@ -10,6 +10,7 @@ #define __streaminfo_h_ #include <stdint.h> +#include <string.h> #include "global.h" @@ -25,12 +26,12 @@ private: NAL_END_SEQ = 0x0A // End of Sequence }; int nalUnescape(uint8_t *dst, const uint8_t *src, int len); - - void FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); - void FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); + const uint8_t *nextStartCode(const uint8_t *start, const uint8_t *end); + bool FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); + bool FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); public: - void FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len); - void FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen); + bool FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len); + bool FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen); }; @@ -22,6 +22,7 @@ cMarkAdTS2Pkt::~cMarkAdTS2Pkt() void cMarkAdTS2Pkt::Reset(int ErrIndex) { + sync=false; switch (ErrIndex) { case MA_ERR_TSSIZE: @@ -113,6 +114,12 @@ void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **Pk return; // not for us } + if (tshdr->PayloadStart) sync=true; + if (!sync) + { + return; // not synced + } + if ((counter!=-1) && (((counter+1) & 0xF)!=tshdr->Counter)) { if (counter==tshdr->Counter) @@ -177,6 +184,13 @@ void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **Pk queue->Put(buf,buflen); } - *PktData=queue->GetPacket(PktSize,MA_PACKET_PKT); + if (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264) + { + *PktData=queue->GetPacket(PktSize,MA_PACKET_H264); + } + else + { + *PktData=queue->GetPacket(PktSize,MA_PACKET_PKT); + } return; } @@ -23,7 +23,7 @@ typedef unsigned char uchar; #include <string.h> #include "global.h" -#include "tools.h" +#include "queue.h" class cMarkAdTS2Pkt { @@ -104,6 +104,7 @@ unsigned Length: int recvnumber; int counter; + bool sync; cMarkAdPaketQueue *queue; @@ -14,7 +14,7 @@ typedef unsigned char uchar; #endif #include "global.h" -#include "tools.h" +#include "queue.h" class cMarkAdVDR2Pkt { @@ -9,6 +9,6 @@ #ifndef __version_h_ #define __version_h_ -static const char *VERSION = "0.0.4"; +static const char *VERSION = "0.0.5"; #endif @@ -16,86 +16,124 @@ cMarkAdLogo::cMarkAdLogo(int RecvNumber, MarkAdContext *maContext) GX[0][0] = -1; GX[0][1] = 0; GX[0][2] = 1; - GX[1][0] = -2; // 2 + GX[1][0] = -2; GX[1][1] = 0; - GX[1][2] = 2; // 2 + GX[1][2] = 2; GX[2][0] = -1; GX[2][1] = 0; GX[2][2] = 1; // 3x3 GY Sobel mask GY[0][0] = 1; - GY[0][1] = 2; // 2 + GY[0][1] = 2; GY[0][2] = 1; GY[1][0] = 0; GY[1][1] = 0; GY[1][2] = 0; GY[2][0] = -1; - GY[2][1] = -2; //2 + GY[2][1] = -2; GY[2][2] = -1; - plane=NULL; - first=true; + memset(&area,0,sizeof(area)); + + area[TOP_LEFT].init=true; + area[TOP_RIGHT].init=true; + area[BOTTOM_LEFT].init=true; + area[BOTTOM_RIGHT].init=true; + + LOGOHEIGHT=100; + LOGOWIDTH=192; + + framecnt=0; + savedlastiframe=-1; + logostart=-1; + logostate=-1; + counter=0; } cMarkAdLogo::~cMarkAdLogo() { - if (plane) free(plane); } -void cMarkAdLogo::SaveFrame(int LastIFrame) +void cMarkAdLogo::SaveLogo(int corner, int lastiframe) { if (!macontext) return; if (!macontext->Video.Info.Width) return; - if (!plane) return; FILE *pFile; char szFilename[32]; // Open file - sprintf(szFilename, "frame%06d.pgm", LastIFrame); + sprintf(szFilename, "%iframe%06d.pgm", corner,lastiframe); pFile=fopen(szFilename, "wb"); if (pFile==NULL) return; // Write header - fprintf(pFile, "P5\n%d %d\n255\n", macontext->Video.Info.Width,LOGOHEIGHT); + fprintf(pFile, "P5\n%d %d\n255\n", LOGOWIDTH,LOGOHEIGHT); // Write pixel data - fwrite(plane,1,macontext->Video.Info.Width*LOGOHEIGHT,pFile); + fwrite(area[corner].plane,1,LOGOWIDTH*LOGOHEIGHT,pFile); // Close file fclose(pFile); - - dsyslog("markad saved frame %i",LastIFrame); - if (LastIFrame>750) abort(); } -int cMarkAdLogo::Process(int LastIFrame) +void cMarkAdLogo::CheckCorner(int corner) { - if (!macontext) return 0; - if (!macontext->Video.Info.Width) return 0; - if (!macontext->Video.Data.Valid) return 0; + if (!macontext) return; + if (!macontext->Video.Info.Width) return; + if (!macontext->Video.Info.Height) return; + if (!macontext->Video.Data.Valid) return; + + if (corner>BOTTOM_RIGHT) return; + if (corner<TOP_LEFT) return; - if (!plane) + int xstart,xend,ystart,yend; + + switch (corner) { - plane=(uchar *) malloc(LOGOHEIGHT*macontext->Video.Info.Width); - if (!plane) return 0; + case TOP_LEFT: + xstart=0; + xend=LOGOWIDTH; + ystart=0; + yend=LOGOHEIGHT; + break; + case TOP_RIGHT: + xstart=macontext->Video.Info.Width-LOGOWIDTH; + xend=macontext->Video.Info.Width; + ystart=0; + yend=LOGOHEIGHT; + break; + case BOTTOM_LEFT: + xstart=0; + xend=LOGOWIDTH; + ystart=macontext->Video.Info.Height-LOGOHEIGHT; + yend=macontext->Video.Info.Height; + break; + case BOTTOM_RIGHT: + xstart=macontext->Video.Info.Width-LOGOWIDTH; + xend=macontext->Video.Info.Width; + ystart=macontext->Video.Info.Height-LOGOHEIGHT; + yend=macontext->Video.Info.Height; + break; + default: + return; } int SUM; int sumX,sumY; - - for (int Y=0; Y<=LOGOHEIGHT-1; Y++) + area[corner].blackpixel=0; + for (int Y=ystart; Y<=yend-1; Y++) { - for (int X=0; X<=macontext->Video.Info.Width-1; X++) + for (int X=xstart; X<=xend-1; X++) { sumX=0; sumY=0; // image boundaries - if (Y==0 || Y==LOGOHEIGHT-1) + if (Y<(ystart+15) || Y>(yend-15)) SUM=0; - else if (X==0 || X==macontext->Video.Info.Width-1) + else if (X<(xstart+15) || X>(xend-15)) SUM=0; // convolution starts here else @@ -127,12 +165,151 @@ int cMarkAdLogo::Process(int LastIFrame) if (SUM>=127) SUM=255; if (SUM<127) SUM=0; - plane[X+Y*macontext->Video.Info.Width]=255-(uchar) (SUM); + int val = 255-(uchar) SUM; + + if (area[corner].init) + { + area[corner].plane[(X-xstart)+(Y-ystart)*LOGOWIDTH]=val; + } + else + { + if (area[corner].plane[(X-xstart)+(Y-ystart)*LOGOWIDTH]!=val) + { + area[corner].plane[(X-xstart)+(Y-ystart)*LOGOWIDTH]=255; + } + } + + if (area[corner].plane[(X-xstart)+(Y-ystart)*LOGOWIDTH]!=255) + area[corner].blackpixel++; } + } - //SaveFrame(LastIFrame); + area[corner].init=false; + if (area[corner].blackpixel<100) area[corner].blackpixel=0; +} - return 0; +void cMarkAdLogo::CheckCorners(int lastiframe) +{ + for (int i=TOP_LEFT; i<=BOTTOM_RIGHT; i++) + { + CheckCorner(i); +// printf("%i ",area[i].blackpixel); +// SaveLogo(i,lastiframe); + } +// printf("\n"); +} + +void cMarkAdLogo::RestartLogoDetection() +{ + for (int i=TOP_LEFT; i<=BOTTOM_RIGHT; i++) + { + area[i].init=true; +// area[i].cntfound=1; + } + framecnt=0; + counter++; +} + +bool cMarkAdLogo::LogoVisible() +{ + int sum=0; + for (int i=TOP_LEFT; i<=BOTTOM_RIGHT; i++) + { + sum+=area[i].blackpixel; + } + return (sum!=0); +} + +/* +void cMarkAdLogo::ResetLogoDetection() +{ + for (int i=TOP_LEFT; i<=BOTTOM_RIGHT; i++) + { + area[i].init=true; + area[i].cntfound=0; + } + framecnt=0; + counter=0; +} + +bool cMarkAdLogo::LogoFound() +{ + for (int i=TOP_LEFT; i<=BOTTOM_RIGHT; i++) + { + printf("%i ",area[i].cntfound); + } + printf("\n"); + return false; +} +*/ + +int cMarkAdLogo::Process(int LastIFrame) +{ + if (!macontext) return 0; + if (!macontext->Video.Info.Width) return 0; + if (!macontext->Video.Data.Valid) return 0; + + if ((macontext->Video.Info.Width>720) && (LOGOWIDTH==192)) + { + LOGOWIDTH=288; + } + + int ret=0; + CheckCorners(LastIFrame); +// if (framecnt>=250) abort(); + /* + if (framecnt>=MAXFRAMES) + { + if (logostate==-1) + { + if (LogoVisible()) + { + logostate=1; + } + else + { + logostate=0; + } + printf("Initial logo state %i\n",logostate); + abort(); + } + else + { + if (!LogoVisible() && logostate==1) + { + if (logostart==-1) logostart=LastIFrame; + RestartLogoDetection(); + printf("%i\n",counter); + if (counter>=2) + { + printf("%i Logo gone\n",logostart); + logostart=-1; + counter=0; + logostate=0; + ret=-1; + } + } + if (LogoVisible() && logostate==0) + { + if (logostart==-1) logostart=LastIFrame; + RestartLogoDetection(); + printf("%i\n",counter); + if (counter>=2) + { + printf("%i Logo start\n",logostart); + logostart=-1; + counter=0; + logostate=1; + ret=1; + } + } + } + } + */ + if (savedlastiframe!=-1) framecnt+=(LastIFrame-savedlastiframe); + savedlastiframe=LastIFrame; + + return ret; } cMarkAdBlackBordersHoriz::cMarkAdBlackBordersHoriz(int RecvNumber, MarkAdContext *maContext) @@ -177,62 +354,25 @@ int cMarkAdBlackBordersHoriz::Process(int LastIFrame, int *BorderIFrame) #define BRIGHTNESS 20 if (!macontext) return 0; if (!macontext->Video.Data.Valid) return 0; - return 0; + if (macontext->Video.Data.PlaneLinesize[0]!=macontext->Video.Info.Width) return 0; *BorderIFrame=borderiframe; - int x,y; + int x; bool ftop=true,fbottom=true; - if (macontext->Video.Data.PlaneLinesize[0]!=macontext->Video.Info.Width) + // "fast" method + for (x=(macontext->Video.Info.Height-CHECKHEIGHT)*macontext->Video.Info.Width; + x<macontext->Video.Info.Height*macontext->Video.Info.Width; x++) { - // slow (?) method - for (y=(macontext->Video.Info.Height-CHECKHEIGHT); y<macontext->Video.Info.Height; y++) - { - for (x=0; x<macontext->Video.Info.Width; x++) - { - if (macontext->Video.Data.Plane[0][y*macontext->Video.Data.PlaneLinesize[0]+x]> - BRIGHTNESS) - { - fbottom=false; - y=macontext->Video.Info.Height; - break; - } - } - } - - if (fbottom) - { - for (y=0; y<CHECKHEIGHT; y++) - { - for (x=0; x<macontext->Video.Info.Width; x++) - { - if (macontext->Video.Data.Plane[0][y*macontext->Video.Data.PlaneLinesize[0]+x] - >BRIGHTNESS) - { - ftop=false; - y=CHECKHEIGHT; - break; - } - } - } - } + if (macontext->Video.Data.Plane[0][x]>BRIGHTNESS) fbottom=false; } - else - { - // "fast" method - for (x=(macontext->Video.Info.Height-CHECKHEIGHT)*macontext->Video.Info.Width; - x<macontext->Video.Info.Height*macontext->Video.Info.Width; x++) - { - if (macontext->Video.Data.Plane[0][x]>BRIGHTNESS) fbottom=false; - } - if (fbottom) + if (fbottom) + { + for (x=0; x<(macontext->Video.Info.Width*CHECKHEIGHT); x++) { - for (x=0; x<(macontext->Video.Info.Width*CHECKHEIGHT); x++) - { - if (macontext->Video.Data.Plane[0][x]>BRIGHTNESS) ftop=false; - } + if (macontext->Video.Data.Plane[0][x]>BRIGHTNESS) ftop=false; } } @@ -338,42 +478,61 @@ bool cMarkAdVideo::AspectRatioChange(MarkAdAspectRatio *a, MarkAdAspectRatio *b) } - MarkAdMark *cMarkAdVideo::Process(int LastIFrame) { ResetMark(); if (!LastIFrame) return NULL; - logo->Process(LastIFrame); - - if (macontext->State.ContentStarted) + int lret=logo->Process(LastIFrame); + if (lret!=0) { - int borderiframe; - int hret=hborder->Process(LastIFrame,&borderiframe); - - if ((hret>0) && (borderiframe)) + char *buf=NULL; + if (lret>0) { - char *buf=NULL; - if (asprintf(&buf,"detected start of horiz. borders (%i)",borderiframe)!=-1) + if (asprintf(&buf,"detected logo start (%i)",LastIFrame)!=-1) { isyslog("markad [%i]: %s",recvnumber,buf); - AddMark(borderiframe,buf); + AddMark(LastIFrame,buf); free(buf); } } - - if ((hret<0) && (borderiframe)) + else { - char *buf=NULL; - if (asprintf(&buf,"detected stop of horiz. borders (%i)",borderiframe)!=-1) + if (asprintf(&buf,"detected logo stop (%i)",LastIFrame)!=-1) { isyslog("markad [%i]: %s",recvnumber,buf); - AddMark(borderiframe,buf); + AddMark(LastIFrame,buf); free(buf); } } } + + int borderiframe; + int hret=hborder->Process(LastIFrame,&borderiframe); + + if ((hret>0) && (borderiframe)) + { + char *buf=NULL; + if (asprintf(&buf,"detected start of horiz. borders (%i)",borderiframe)!=-1) + { + isyslog("markad [%i]: %s",recvnumber,buf); + AddMark(borderiframe,buf); + free(buf); + } + } + + if ((hret<0) && (borderiframe)) + { + char *buf=NULL; + if (asprintf(&buf,"detected stop of horiz. borders (%i)",borderiframe)!=-1) + { + isyslog("markad [%i]: %s",recvnumber,buf); + AddMark(borderiframe,buf); + free(buf); + } + } + if (AspectRatioChange(&macontext->Video.Info.AspectRatio,&aspectratio)) { char *buf=NULL; @@ -24,16 +24,52 @@ class cMarkAdLogo { private: -#define LOGOHEIGHT 100 +#define MAXFRAMES 25 + + enum + { + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT + }; + + int LOGOHEIGHT; // max. 100 + int LOGOWIDTH; // max. 288 + + struct area + { + uchar plane[28800]; + bool init; + int blackpixel; +// int cntfound; + } area[4]; + + int savedlastiframe; + int framecnt; + + int logostart; + int GX[3][3]; int GY[3][3]; - uchar *plane; - bool first; + + int counter; + + int logostate; MarkAdContext *macontext; + void CheckCorner(int corner); + void CheckCorners(int lastiframe); + void RestartLogoDetection(); + bool LogoVisible(); + + /* + void ResetLogoDetection(); + bool LogoFound(); + */ + void SaveLogo(int corner, int lastiframe); public: cMarkAdLogo(int RecvNumber, MarkAdContext *maContext); ~cMarkAdLogo(); - void SaveFrame(int LastIFrame); int Process(int LastIFrame); }; |