diff options
-rw-r--r-- | command/Makefile | 2 | ||||
-rw-r--r-- | command/audio.cpp | 120 | ||||
-rw-r--r-- | command/audio.h | 10 | ||||
-rw-r--r-- | command/audio_gain_analysis.cpp | 423 | ||||
-rw-r--r-- | command/audio_gain_analysis.h | 102 | ||||
-rw-r--r-- | command/demux.cpp | 1247 | ||||
-rw-r--r-- | command/demux.h | 331 | ||||
-rw-r--r-- | command/global.h | 30 | ||||
-rw-r--r-- | command/markad-standalone.cpp | 477 | ||||
-rw-r--r-- | command/markad-standalone.h | 11 | ||||
-rw-r--r-- | command/marks.cpp | 1 | ||||
-rw-r--r-- | command/pes2es.cpp | 102 | ||||
-rw-r--r-- | command/pes2es.h | 96 | ||||
-rw-r--r-- | command/queue.cpp | 504 | ||||
-rw-r--r-- | command/queue.h | 161 | ||||
-rw-r--r-- | command/ts2pkt.cpp | 224 | ||||
-rw-r--r-- | command/ts2pkt.h | 140 | ||||
-rw-r--r-- | command/video.cpp | 243 | ||||
-rw-r--r-- | command/video.h | 66 |
19 files changed, 1827 insertions, 2463 deletions
diff --git a/command/Makefile b/command/Makefile index 95d7da4..e1ab816 100644 --- a/command/Makefile +++ b/command/Makefile @@ -37,7 +37,7 @@ INCLUDES += -I.. ### The object files (add further files here): -OBJS = markad-standalone.o decoder.o marks.o streaminfo.o video.o audio.o audio_gain_analysis.o demux.o queue.o ts2pkt.o pes2es.o +OBJS = markad-standalone.o decoder.o marks.o streaminfo.o video.o audio.o demux.o ### The main target: diff --git a/command/audio.cpp b/command/audio.cpp index 46fa57a..082010f 100644 --- a/command/audio.cpp +++ b/command/audio.cpp @@ -11,11 +11,6 @@ #include <stdlib.h> #include <string.h> -extern "C" -{ -#include "debug.h" -} - #include "audio.h" cMarkAdAudio::cMarkAdAudio(MarkAdContext *maContext) @@ -31,12 +26,21 @@ cMarkAdAudio::cMarkAdAudio(MarkAdContext *maContext) cMarkAdAudio::~cMarkAdAudio() { - Clear(); ResetMark(); + Clear(); +} + +void cMarkAdAudio::Clear() +{ + channels=0; + if (result.CommentBefore) free(result.CommentBefore); + if (result.CommentAfter) free(result.CommentAfter); + memset(&result,0,sizeof(result)); } void cMarkAdAudio::ResetMark() { + if (!mark.Type) return; if (mark.Comment) free(mark.Comment); mark.Comment=NULL; mark.Position=0; @@ -68,55 +72,6 @@ bool cMarkAdAudio::AddMark(int Type, int Position, const char *Comment) return true; } -bool cMarkAdAudio::AnalyzeGain(int FrameNumber) -{ - if (!macontext->Audio.Data.Valid) return false; - - int samples=macontext->Audio.Data.SampleBufLen/ - sizeof(*macontext->Audio.Data.SampleBuf)/ - macontext->Audio.Info.Channels; - - double left[samples]; - double right[samples]; - - for (int i=0; i<samples; i++) - { - left[i]=macontext->Audio.Data.SampleBuf[0+(i*2)]; - right[i]=macontext->Audio.Data.SampleBuf[1+(i*2)]; - } - - if (FrameNumber!=lastframe_gain) - { - if ((lastframe_gain>0) && (audiogain.AnalyzedSamples()>=(3*samples))) - { - double gain = audiogain.GetGain(); - printf("%05i %+.2f db\n",lastframe_gain,gain); - } - audiogain.Init(macontext->Audio.Info.SampleRate); - lastframe_gain=-1; - } - - if (audiogain.AnalyzeSamples(left,right,samples,2)!=GAIN_ANALYSIS_OK) - { - lastframe_gain=-1; - return false; - } - else - { - lastframe_gain=FrameNumber; - } - return true; -} - -void cMarkAdAudio::Clear() -{ - channels=0; - lastframe_gain=-1; - if (result.CommentBefore) free(result.CommentBefore); - if (result.CommentAfter) free(result.CommentAfter); - memset(&result,0,sizeof(result)); -} - bool cMarkAdAudio::ChannelChange(int a, int b) { if ((a==0) || (b==0)) return false; @@ -124,24 +79,6 @@ bool cMarkAdAudio::ChannelChange(int a, int b) return false; } -MarkAdPos *cMarkAdAudio::Process2ndPass(int FrameNumber) -{ - if (!FrameNumber) return NULL; -#if 0 - if (AnalyzeGain(FrameNumber)) - { - if (result.CommentBefore) free(result.CommentBefore); - if (asprintf(&result.CommentBefore,"audio silence detection (%i)",FrameNumber)==-1) - { - result.CommentBefore=NULL; - } - result.FrameNumberBefore=FrameNumber; - return &result; - } -#endif - return NULL; -} - MarkAdMark *cMarkAdAudio::Process(int FrameNumber, int FrameNumberNext) { if ((!FrameNumber) || (!FrameNumberNext)) return NULL; @@ -155,38 +92,33 @@ MarkAdMark *cMarkAdAudio::Process(int FrameNumber, int FrameNumberNext) snprintf(buf,255,"audio channel change from %i to %i (", channels, macontext->Audio.Info.Channels); - if (macontext->Info.Channels) + if (macontext->Audio.Info.Channels>2) { - if (macontext->Info.Channels==macontext->Audio.Info.Channels) - { - char nbuf[20]; - snprintf(nbuf,sizeof(nbuf),"%i)*",FrameNumberNext); - nbuf[19]=0; - strcat(buf,nbuf); - AddMark(MT_CHANNELSTART,FrameNumberNext,buf); - } - else - { - char nbuf[20]; - snprintf(nbuf,sizeof(nbuf),"%i)",framelast); - nbuf[19]=0; - strcat(buf,nbuf); - AddMark(MT_CHANNELSTOP,framelast,buf); - } + char nbuf[20]; + snprintf(nbuf,sizeof(nbuf),"%i)*",FrameNumberNext); + nbuf[19]=0; + strcat(buf,nbuf); + AddMark(MT_CHANNELSTART,FrameNumberNext,buf); } else { char nbuf[20]; - snprintf(nbuf,sizeof(nbuf),"%i)?",FrameNumber); + snprintf(nbuf,sizeof(nbuf),"%i)",framelast); nbuf[19]=0; strcat(buf,nbuf); - AddMark(MT_CHANNELCHANGE,FrameNumber,buf); + AddMark(MT_CHANNELSTOP,framelast,buf); } free(buf); } channels=macontext->Audio.Info.Channels; framelast=FrameNumber; - return &mark; + if (mark.Position) + { + return &mark; + } + else + { + return NULL; + } } - diff --git a/command/audio.h b/command/audio.h index 651d056..6bb2b2e 100644 --- a/command/audio.h +++ b/command/audio.h @@ -10,23 +10,15 @@ #include "global.h" -#include "audio_gain_analysis.h" - class cMarkAdAudio { private: - //int framenumber; MarkAdContext *macontext; MarkAdMark mark; void ResetMark(); bool AddMark(int Type, int Position, const char *Comment); - int lastframe_gain; - double lastgain; - cMarkAdAudioGainAnalysis audiogain; - bool AnalyzeGain(int FrameNumber); - int channels; bool ChannelChange(int a, int b); int framelast; @@ -36,9 +28,7 @@ public: cMarkAdAudio(MarkAdContext *maContext); ~cMarkAdAudio(); MarkAdMark *Process(int FrameNumber, int FrameNumberBefore); - MarkAdPos *Process2ndPass(int FrameNumber); void Clear(); }; - #endif diff --git a/command/audio_gain_analysis.cpp b/command/audio_gain_analysis.cpp deleted file mode 100644 index b5abf9b..0000000 --- a/command/audio_gain_analysis.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - * ReplayGainAnalysis - analyzes input samples and give the recommended dB change - * Copyright (C) 2001-2009 David Robinson and Glen Sawyer - * Improvements and optimizations added by Frank Klemm, and by Marcel Müller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * concept and filter values by David Robinson (David@Robinson.org) - * -- blame him if you think the idea is flawed - * original coding by Glen Sawyer (mp3gain@hotmail.com) - * -- blame him if you think this runs too slowly, or the coding is otherwise flawed - * - * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) - * -- credit him for all the _good_ programming ;) - * - * - * For an explanation of the concepts and the basic algorithms involved, go to: - * http://www.replaygain.org/ - */ - -/* - * Here's the deal. Call - * - * InitGainAnalysis ( long samplefreq ); - * - * to initialize everything. Call - * - * AnalyzeSamples ( const Float_t* left_samples, - * const Float_t* right_samples, - * size_t num_samples, - * int num_channels ); - * - * as many times as you want, with as many or as few samples as you want. - * If mono, pass the sample buffer in through left_samples, leave - * right_samples NULL, and make sure num_channels = 1. - * - * GetGain() - * - * will return the recommended dB level change for all samples analyzed - * SINCE THE LAST TIME you called InitGainAnalysis(). - * - */ - -/* - * So here's the main source of potential code confusion: - * - * The filters applied to the incoming samples are IIR filters, - * meaning they rely on up to <filter order> number of previous samples - * AND up to <filter order> number of previous filtered samples. - * - * I set up the AnalyzeSamples routine to minimize memory usage and interface - * complexity. The speed isn't compromised too much (I don't think), but the - * internal complexity is higher than it should be for such a relatively - * simple routine. - * - * Optimization/clarity suggestions are welcome. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "audio_gain_analysis.h" - -const Float_t cMarkAdAudioGainAnalysis::ABYule[12][2*YULE_ORDER + 1] = -{ - {0.006471345933032, -7.22103125152679, -0.02567678242161, 24.7034187975904, 0.049805860704367, -52.6825833623896, -0.05823001743528, 77.4825736677539, 0.040611847441914, -82.0074753444205, -0.010912036887501, 63.1566097101925, -0.00901635868667, -34.889569769245, 0.012448886238123, 13.2126852760198, -0.007206683749426, -3.09445623301669, 0.002167156433951, 0.340344741393305, -0.000261819276949}, - {0.015415414474287, -7.19001570087017, -0.07691359399407, 24.4109412087159, 0.196677418516518, -51.6306373580801, -0.338855114128061, 75.3978476863163, 0.430094579594561, -79.4164552507386, -0.415015413747894, 61.0373661948115, 0.304942508151101, -33.7446462547014, -0.166191795926663, 12.8168791146274, 0.063198189938739, -3.01332198541437, -0.015003978694525, 0.223619893831468, 0.001748085184539}, - {0.021776466467053, -5.74819833657784, -0.062376961003801, 16.246507961894, 0.107731165328514, -29.9691822642542, -0.150994515142316, 40.027597579378, 0.170334807313632, -40.3209196052655, -0.157984942890531, 30.8542077487718, 0.121639833268721, -17.5965138737281, -0.074094040816409, 7.10690214103873, 0.031282852041061, -1.82175564515191, -0.00755421235941, 0.223619893831468, 0.00117925454213 }, - {0.03857599435200, -3.84664617118067, -0.02160367184185, 7.81501653005538, -0.00123395316851, -11.34170355132042, -0.00009291677959, 13.05504219327545, -0.01655260341619, -12.28759895145294, 0.02161526843274, 9.48293806319790, -0.02074045215285, -5.87257861775999, 0.00594298065125, 2.75465861874613, 0.00306428023191, -0.86984376593551, 0.00012025322027, 0.13919314567432, 0.00288463683916 }, - {0.05418656406430, -3.47845948550071, -0.02911007808948, 6.36317777566148, -0.00848709379851, -8.54751527471874, -0.00851165645469, 9.47693607801280, -0.00834990904936, -8.81498681370155, 0.02245293253339, 6.85401540936998, -0.02596338512915, -4.39470996079559, 0.01624864962975, 2.19611684890774, -0.00240879051584, -0.75104302451432, 0.00674613682247, 0.13149317958808, -0.00187763777362 }, - {0.15457299681924, -2.37898834973084, -0.09331049056315, 2.84868151156327, -0.06247880153653, -2.64577170229825, 0.02163541888798, 2.23697657451713, -0.05588393329856, -1.67148153367602, 0.04781476674921, 1.00595954808547, 0.00222312597743, -0.45953458054983, 0.03174092540049, 0.16378164858596, -0.01390589421898, -0.05032077717131, 0.00651420667831, 0.02347897407020, -0.00881362733839 }, - {0.30296907319327, -1.61273165137247, -0.22613988682123, 1.07977492259970, -0.08587323730772, -0.25656257754070, 0.03282930172664, -0.16276719120440, -0.00915702933434, -0.22638893773906, -0.02364141202522, 0.39120800788284, -0.00584456039913, -0.22138138954925, 0.06276101321749, 0.04500235387352, -0.00000828086748, 0.02005851806501, 0.00205861885564, 0.00302439095741, -0.02950134983287 }, - {0.33642304856132, -1.49858979367799, -0.25572241425570, 0.87350271418188, -0.11828570177555, 0.12205022308084, 0.11921148675203, -0.80774944671438, -0.07834489609479, 0.47854794562326, -0.00469977914380, -0.12453458140019, -0.00589500224440, -0.04067510197014, 0.05724228140351, 0.08333755284107, 0.00832043980773, -0.04237348025746, -0.01635381384540, 0.02977207319925, -0.01760176568150 }, - {0.44915256608450, -0.62820619233671, -0.14351757464547, 0.29661783706366, -0.22784394429749, -0.37256372942400, -0.01419140100551, 0.00213767857124, 0.04078262797139, -0.42029820170918, -0.12398163381748, 0.22199650564824, 0.04097565135648, 0.00613424350682, 0.10478503600251, 0.06747620744683, -0.01863887810927, 0.05784820375801, -0.03193428438915, 0.03222754072173, 0.00541907748707 }, - {0.56619470757641, -1.04800335126349, -0.75464456939302, 0.29156311971249, 0.16242137742230, -0.26806001042947, 0.16744243493672, 0.00819999645858, -0.18901604199609, 0.45054734505008, 0.30931782841830, -0.33032403314006, -0.27562961986224, 0.06739368333110, 0.00647310677246, -0.04784254229033, 0.08647503780351, 0.01639907836189, -0.03788984554840, 0.01807364323573, -0.00588215443421 }, - {0.58100494960553, -0.51035327095184, -0.53174909058578, -0.31863563325245, -0.14289799034253, -0.20256413484477, 0.17520704835522, 0.14728154134330, 0.02377945217615, 0.38952639978999, 0.15558449135573, -0.23313271880868, -0.25344790059353, -0.05246019024463, 0.01628462406333, -0.02505961724053, 0.06920467763959, 0.02442357316099, -0.03721611395801, 0.01818801111503, -0.00749618797172 }, - {0.53648789255105, -0.25049871956020, -0.42163034350696, -0.43193942311114, -0.00275953611929, -0.03424681017675, 0.04267842219415, -0.04678328784242, -0.10214864179676, 0.26408300200955, 0.14590772289388, 0.15113130533216, -0.02459864859345, -0.17556493366449, -0.11202315195388, -0.18823009262115, -0.04060034127000, 0.05477720428674, 0.04788665548180, 0.04704409688120, -0.02217936801134 } -}; - -const Float_t cMarkAdAudioGainAnalysis::ABButter[12][2*BUTTER_ORDER + 1] = -{ - {0.99308203517541, -1.98611621154089, -1.98616407035082, 0.986211929160751, 0.99308203517541 }, - {0.992472550461293,-1.98488843762334, -1.98494510092258, 0.979389350028798, 0.992472550461293}, - {0.989641019334721,-1.97917472731008, -1.97928203866944, 0.979389350028798, 0.989641019334721}, - {0.98621192462708, -1.97223372919527, -1.97242384925416, 0.97261396931306, 0.98621192462708 }, - {0.98500175787242, -1.96977855582618, -1.97000351574484, 0.97022847566350, 0.98500175787242 }, - {0.97938932735214, -1.95835380975398, -1.95877865470428, 0.95920349965459, 0.97938932735214 }, - {0.97531843204928, -1.95002759149878, -1.95063686409857, 0.95124613669835, 0.97531843204928 }, - {0.97316523498161, -1.94561023566527, -1.94633046996323, 0.94705070426118, 0.97316523498161 }, - {0.96454515552826, -1.92783286977036, -1.92909031105652, 0.93034775234268, 0.96454515552826 }, - {0.96009142950541, -1.91858953033784, -1.92018285901082, 0.92177618768381, 0.96009142950541 }, - {0.95856916599601, -1.91542108074780, -1.91713833199203, 0.91885558323625, 0.95856916599601 }, - {0.94597685600279, -1.88903307939452, -1.89195371200558, 0.89487434461664, 0.94597685600279 } -}; - -void cMarkAdAudioGainAnalysis::filterYule (const Float_t* input, Float_t* output, size_t nSamples, const Float_t* kernel) -{ - // for each filter: - // [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, - // [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz - - // When calling these filter procedures, make sure that ip[-order] and op[-order] point to real data! - - while (nSamples--) - { - *output = 1e-10 /* 1e-10 is a hack to avoid slowdown because of denormals */ - + input [0] * kernel[0] - - output[-1] * kernel[1] - + input [-1] * kernel[2] - - output[-2] * kernel[3] - + input [-2] * kernel[4] - - output[-3] * kernel[5] - + input [-3] * kernel[6] - - output[-4] * kernel[7] - + input [-4] * kernel[8] - - output[-5] * kernel[9] - + input [-5] * kernel[10] - - output[-6] * kernel[11] - + input [-6] * kernel[12] - - output[-7] * kernel[13] - + input [-7] * kernel[14] - - output[-8] * kernel[15] - + input [-8] * kernel[16] - - output[-9] * kernel[17] - + input [-9] * kernel[18] - - output[-10]* kernel[19] - + input [-10]* kernel[20]; - ++output; - ++input; - } -} - -void cMarkAdAudioGainAnalysis::filterButter (const Float_t* input, Float_t* output, size_t nSamples, const Float_t* kernel) -{ - - while (nSamples--) - { - *output = - input [0] * kernel[0] - - output[-1] * kernel[1] - + input [-1] * kernel[2] - - output[-2] * kernel[3] - + input [-2] * kernel[4]; - ++output; - ++input; - } -} - -int cMarkAdAudioGainAnalysis::ResetSampleFrequency ( long samplefreq ) -{ - // returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not - int i; - - // zero out initial values - for ( i = 0; i < MAX_ORDER; i++ ) - linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.; - - switch ( (int)(samplefreq) ) - { - case 96000: - freqindex = 0; - break; - case 88200: - freqindex = 1; - break; - case 64000: - freqindex = 2; - break; - case 48000: - freqindex = 3; - break; - case 44100: - freqindex = 4; - break; - case 32000: - freqindex = 5; - break; - case 24000: - freqindex = 6; - break; - case 22050: - freqindex = 7; - break; - case 16000: - freqindex = 8; - break; - case 12000: - freqindex = 9; - break; - case 11025: - freqindex = 10; - break; - case 8000: - freqindex = 11; - break; - default: - return INIT_GAIN_ANALYSIS_ERROR; - } - - sampleWindow = (int) ceil (samplefreq * RMS_WINDOW_TIME); - - lsum = 0.; - rsum = 0.; - totsamp = 0; - - memset ( A, 0, sizeof(A) ); - - return INIT_GAIN_ANALYSIS_OK; -} - -int cMarkAdAudioGainAnalysis::Init(long samplefreq) -{ - if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) - { - return INIT_GAIN_ANALYSIS_ERROR; - } - - linpre = linprebuf + MAX_ORDER; - rinpre = rinprebuf + MAX_ORDER; - lstep = lstepbuf + MAX_ORDER; - rstep = rstepbuf + MAX_ORDER; - lout = loutbuf + MAX_ORDER; - rout = routbuf + MAX_ORDER; - - memset ( B, 0, sizeof(B) ); - - gnum_samples=0; - - return INIT_GAIN_ANALYSIS_OK; -} - -static __inline double fsqr(const double d) -{ - return d*d; -} - -int cMarkAdAudioGainAnalysis::AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels ) -{ - // returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not - const Float_t* curleft; - const Float_t* curright; - long batchsamples; - long cursamples; - long cursamplepos; - int i; - - if ( num_samples == 0 ) - return GAIN_ANALYSIS_OK; - - gnum_samples+=num_samples; - - cursamplepos = 0; - batchsamples = (long)num_samples; - - switch ( num_channels) - { - case 1: - right_samples = left_samples; - case 2: - break; - default: - return GAIN_ANALYSIS_ERROR; - } - - if ( num_samples < MAX_ORDER ) - { - memcpy ( linprebuf + MAX_ORDER, left_samples , num_samples * sizeof(Float_t) ); - memcpy ( rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t) ); - } - else - { - memcpy ( linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t) ); - memcpy ( rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t) ); - } - - while ( batchsamples > 0 ) - { - cursamples = batchsamples > sampleWindow-totsamp ? sampleWindow - totsamp : batchsamples; - if ( cursamplepos < MAX_ORDER ) - { - curleft = linpre+cursamplepos; - curright = rinpre+cursamplepos; - if (cursamples > MAX_ORDER - cursamplepos ) - cursamples = MAX_ORDER - cursamplepos; - } - else - { - curleft = left_samples + cursamplepos; - curright = right_samples + cursamplepos; - } - - YULE_FILTER ( curleft , lstep + totsamp, cursamples, ABYule[freqindex]); - YULE_FILTER ( curright, rstep + totsamp, cursamples, ABYule[freqindex]); - - BUTTER_FILTER ( lstep + totsamp, lout + totsamp, cursamples, ABButter[freqindex]); - BUTTER_FILTER ( rstep + totsamp, rout + totsamp, cursamples, ABButter[freqindex]); - - curleft = lout + totsamp; // Get the squared values - curright = rout + totsamp; - - i = cursamples % 16; - while (i--) - { - lsum += fsqr(*curleft++); - rsum += fsqr(*curright++); - } - i = cursamples / 16; - while (i--) - { - lsum += fsqr(curleft[0]) - + fsqr(curleft[1]) - + fsqr(curleft[2]) - + fsqr(curleft[3]) - + fsqr(curleft[4]) - + fsqr(curleft[5]) - + fsqr(curleft[6]) - + fsqr(curleft[7]) - + fsqr(curleft[8]) - + fsqr(curleft[9]) - + fsqr(curleft[10]) - + fsqr(curleft[11]) - + fsqr(curleft[12]) - + fsqr(curleft[13]) - + fsqr(curleft[14]) - + fsqr(curleft[15]); - curleft += 16; - rsum += fsqr(curright[0]) - + fsqr(curright[1]) - + fsqr(curright[2]) - + fsqr(curright[3]) - + fsqr(curright[4]) - + fsqr(curright[5]) - + fsqr(curright[6]) - + fsqr(curright[7]) - + fsqr(curright[8]) - + fsqr(curright[9]) - + fsqr(curright[10]) - + fsqr(curright[11]) - + fsqr(curright[12]) - + fsqr(curright[13]) - + fsqr(curright[14]) - + fsqr(curright[15]); - curright += 16; - } - - batchsamples -= cursamples; - cursamplepos += cursamples; - totsamp += cursamples; - if ( totsamp == sampleWindow ) // Get the Root Mean Square (RMS) for this set of samples - { - double val = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 ); - int ival = (int) val; - if ( ival < 0 ) ival = 0; - if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = sizeof(A)/sizeof(*A) - 1; - A [ival]++; - lsum = rsum = 0.; - memmove ( loutbuf , loutbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - memmove ( routbuf , routbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - totsamp = 0; - } - if ( totsamp > sampleWindow ) - // somehow I really screwed up: Error in programming! - // Contact author about totsamp > sampleWindow - return GAIN_ANALYSIS_ERROR; - } - if ( num_samples < MAX_ORDER ) - { - memmove ( linprebuf,linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) ); - memmove ( rinprebuf,rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) ); - memcpy ( linprebuf + MAX_ORDER - num_samples, left_samples,num_samples * sizeof(Float_t) ); - memcpy ( rinprebuf + MAX_ORDER - num_samples, right_samples,num_samples * sizeof(Float_t) ); - } - else - { - memcpy ( linprebuf, left_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) ); - memcpy ( rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) ); - } - - return GAIN_ANALYSIS_OK; -} - -Float_t cMarkAdAudioGainAnalysis::analyzeResult ( Uint32_t* Array, size_t len ) -{ - Uint32_t elems; - Int32_t upper; - size_t i; - - elems = 0; - for ( i = 0; i < len; i++ ) - elems += Array[i]; - if ( elems == 0 ) - return GAIN_NOT_ENOUGH_SAMPLES; - - upper = (Int32_t) ceil (elems * (1. - RMS_PERCENTILE)); - for ( i = len; i-- > 0; ) - { - if ( (upper -= Array[i]) <= 0 ) - break; - } - - return (Float_t) ((Float_t)PINK_REF - (Float_t)i / (Float_t)STEPS_per_dB); -} - -Float_t cMarkAdAudioGainAnalysis::GetGain ( void ) -{ - return analyzeResult ( A, sizeof(A)/sizeof(*A) ); -} diff --git a/command/audio_gain_analysis.h b/command/audio_gain_analysis.h deleted file mode 100644 index abed123..0000000 --- a/command/audio_gain_analysis.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * ReplayGainAnalysis - analyzes input samples and give the recommended dB change - * Copyright (C) 2001-2009 David Robinson and Glen Sawyer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * concept and filter values by David Robinson (David@Robinson.org) - * -- blame him if you think the idea is flawed - * coding by Glen Sawyer (mp3gain@hotmail.com) 735 W 255 N, Orem, UT 84057-4505 USA - * -- blame him if you think this runs too slowly, or the coding is otherwise flawed - * - * For an explanation of the concepts and the basic algorithms involved, go to: - * http://www.replaygain.org/ - */ - -#ifndef GAIN_ANALYSIS_H -#define GAIN_ANALYSIS_H - -#include <stddef.h> - -#define GAIN_NOT_ENOUGH_SAMPLES -24601 -#define GAIN_ANALYSIS_ERROR 0 -#define GAIN_ANALYSIS_OK 1 - -#define INIT_GAIN_ANALYSIS_ERROR 0 -#define INIT_GAIN_ANALYSIS_OK 1 - -typedef double Float_t; // Type used for filtering - -class cMarkAdAudioGainAnalysis -{ -private: - typedef unsigned int Uint32_t; - typedef signed int Int32_t; - -#define YULE_ORDER 10 -#define BUTTER_ORDER 2 -#define YULE_FILTER filterYule -#define BUTTER_FILTER filterButter -#define RMS_PERCENTILE 0.95 // percentile which is louder than the proposed level -#define MAX_SAMP_FREQ 96000. // maximum allowed sample frequency [Hz] -#define RMS_WINDOW_TIME 0.050 // Time slice size [s] -#define STEPS_per_dB 100. // Table entries per dB -#define MAX_dB 120. // Table entries for 0...MAX_dB (normal max. values are 70...80 dB) - -#define MAX_ORDER (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) -#define MAX_SAMPLES_PER_WINDOW (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1) // max. Samples per Time slice -#define PINK_REF 64.82 //298640883795 // calibration value - - Float_t linprebuf [MAX_ORDER * 2]; - Float_t* linpre; // left input samples, with pre-buffer - Float_t lstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; - Float_t* lstep; // left "first step" (i.e. post first filter) samples - Float_t loutbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; - Float_t* lout; // left "out" (i.e. post second filter) samples - Float_t rinprebuf [MAX_ORDER * 2]; - Float_t* rinpre; // right input samples ... - Float_t rstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; - Float_t* rstep; - Float_t routbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; - Float_t* rout; - long sampleWindow; // number of samples required to reach number of milliseconds required for RMS window - long totsamp; - int gnum_samples; - double lsum; - double rsum; - int freqindex; - int first; - Uint32_t A [(size_t)(STEPS_per_dB * MAX_dB)]; - Uint32_t B [(size_t)(STEPS_per_dB * MAX_dB)]; - - static const Float_t ABButter[12][2*BUTTER_ORDER + 1]; - static const Float_t ABYule[12][2*YULE_ORDER + 1]; - - void filterButter (const Float_t* input, Float_t* output, size_t nSamples, const Float_t* kernel); - void filterYule (const Float_t* input, Float_t* output, size_t nSamples, const Float_t* kernel); - - int ResetSampleFrequency ( long samplefreq ); - Float_t analyzeResult ( Uint32_t* Array, size_t len ); -public: - int Init( long samplefreq ); - int AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels ); - int AnalyzedSamples() - { - return (int) gnum_samples; - }; - Float_t GetGain(void); -}; - -#endif /* GAIN_ANALYSIS_H */ diff --git a/command/demux.cpp b/command/demux.cpp index 6f58dde..9c9bcc8 100644 --- a/command/demux.cpp +++ b/command/demux.cpp @@ -5,282 +5,1201 @@ * */ +#include <string.h> #include "demux.h" +extern "C" +{ +#include "debug.h" +} -#include <string.h> +#include <stdlib.h> -cMarkAdDemux::cMarkAdDemux() +#ifndef TS_SIZE +#define TS_SIZE 188 +#endif + +cPaketQueue::cPaketQueue(const char *Name, int Size) { - ts2pkt=NULL; - pes2audioes=NULL; - pes2videoes=NULL; - pause=false; - pause_retval=0; - min_needed=0; - skip=0; - queue = new cMarkAdPaketQueue(NULL,2176); + maxqueue=Size; + if (Name) + { + name=strdup(Name); + } + else + { + name=NULL; + } + buffer=(uchar *) malloc(Size+8); + if (!buffer) maxqueue=0; + memset(&pktinfo,0,sizeof(pktinfo)); + percent=-1; + mpercent=0; + Clear(); } -cMarkAdDemux::~cMarkAdDemux() +void cPaketQueue::Clear() { - if (ts2pkt) delete ts2pkt; - if (pes2audioes) delete pes2audioes; - if (pes2videoes) delete pes2videoes; - if (queue) delete queue; + inptr=outptr=0; + pktinfo.pkthdr=-1; + scanner=0xFFFFFFFF; + scannerstart=-1; + skipped=0; } -void cMarkAdDemux::Clear() +cPaketQueue::~cPaketQueue() { - if (ts2pkt) ts2pkt->Clear(); - if (pes2audioes) pes2audioes->Clear(); - if (pes2videoes) pes2videoes->Clear(); - if (queue) queue->Clear(); - pause=false; - pause_retval=0; - min_needed=0; - skip=0; + if (name) + { + tsyslog("buffer usage : %-15s %3i%%",name,mpercent); + free((void *) name); + } + if (buffer) free(buffer); } -void cMarkAdDemux::ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *Pkt) +void cPaketQueue::Resize(int NewSize, const char *NewName) { - if (!Pkt) return; + if (NewName) + { + if (name) free((void *) name); + name=strdup(NewName); + } + if (inptr<NewSize) + { + buffer=(uchar *) realloc(buffer,NewSize+8); + if (buffer) + { + maxqueue=NewSize; + } + else + { + maxqueue=0; + Clear(); + } + } +} - if ((Pid.Type==MARKAD_PIDTYPE_AUDIO_AC3) || (Pid.Type==MARKAD_PIDTYPE_AUDIO_MP2)) +int cPaketQueue::findpktheader(int start, int *streamsize,int *headersize, bool longstartcode, bool pesonly=false) +{ + if ((!streamsize) || (!headersize)) return -1; + if (!start) start=outptr; + if (start>=inptr) return -1; + *streamsize=0; + if (longstartcode) + { + *headersize=4; // 0x0 0x0 0x0 0x1 + } + else + { + *headersize=3; // 0x0 0x0 0x1 + } + int i; + + if (scanner!=0xFFFFFFFF) + { + scanner<<=8; + scanner|=buffer[start++]; + } + + bool found=false; + for (i=start; i<inptr; i++) + { + if (longstartcode) + { + if (scanner==1L) + { + found=true; + break; + } + if ((scanner & 0xFFFFFFF0)==0x1E0L) + { + found=true; + break; + } + } + else + { + if ((scanner & 0x00FFFFFF)==1L) + { + if (pesonly) + { + if (buffer[i]>=0xBC) + { + found=true; + break; + } + } + else + { + found=true; + break; + } + } + } + scanner<<=8; + scanner|=buffer[i]; + } + if (!found) { - if (!pes2audioes) pes2audioes=new cMarkAdPES2ES((Pid.Type==MARKAD_PIDTYPE_AUDIO_AC3) ? - "PES2ES AC3" : "PES2ES MP2"); - if (!pes2audioes) return; - pes2audioes->Process(Pid,Data,Count,Pkt); + if (longstartcode) + { + if (scanner==1L) + { + found=true; + } + if ((scanner & 0xFFFFFFF0)==0x1E0L) + { + found=true; + } + } + else + { + if (((scanner & 0x00FFFFFF)==1L) && (!pesonly)) + { + found=true; + } + } } - if ((Pid.Type==MARKAD_PIDTYPE_VIDEO_H262) || (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264)) + if (i==inptr) { - if (!pes2videoes) + if (found) { - if (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264) + if (!start) { - pes2videoes=new cMarkAdPES2ES("PES2H264ES",425984); + scanner=0xFFFFFFFF; + return -1; + } + } + else + { + return -1; + } + } + if (longstartcode) i--; + if (buffer[i]>=0xBC) // do we have a PES packet? + { +#define PESHDRSIZE 6 + if ((i+PESHDRSIZE)>inptr) + { + return -1; // we need more data (for streamsize and headersize) + } + + *streamsize=(buffer[i+1]<<8)+buffer[i+2]; + if (*streamsize) (*streamsize)+=PESHDRSIZE; // 6 Byte PES-Header + if (longstartcode) + { + struct PESHDROPT *peshdropt=(struct PESHDROPT *) &buffer[i+3]; + if (peshdropt->MarkerBits==0x2) + { + *headersize=PESHDRSIZE+sizeof(struct PESHDROPT)+ + peshdropt->Length; } else { - pes2videoes=new cMarkAdPES2ES("PES2H262ES",65536); + *headersize=PESHDRSIZE; } } - if (!pes2videoes) return; - pes2videoes->Process(Pid,Data,Count,Pkt); } - return; + return i-3; } -void cMarkAdDemux::ProcessTS(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *Pkt) +int cPaketQueue::findaudioheader(int start, int *framesize, int *headersize, bool ac3) { - if (!Pkt) return; + if ((!framesize) || (!headersize)) return -1; + if (!start) start=outptr; + if (start>=inptr) return -1; + (*framesize)=0; + if (ac3) + { + (*headersize)=2; + } + else + { + (*headersize)=3; + } + int i; - MarkAdPacket pkt; - memset(&pkt,0,sizeof(pkt)); + if (scanner!=0xFFFFFFFF) + { + scanner<<=8; + scanner|=buffer[start++]; + } + else + { + scanner<<=8; + scanner|=buffer[start++]; + scanner<<=8; + scanner|=buffer[start++]; + } - if (!ts2pkt) + for (i=start; i<inptr; i++) { - switch (Pid.Type) + + if (ac3) { - case MARKAD_PIDTYPE_VIDEO_H264: - ts2pkt=new cMarkAdTS2Pkt("TS2H264",819200); - break; + if ((scanner & 0x0000FFFF)==0xB77L) break; + } + else + { + if ((scanner & 0x0000FFE0)==0xFFE0L) break; + } - case MARKAD_PIDTYPE_VIDEO_H262: - ts2pkt=new cMarkAdTS2Pkt("TS2H262",262144); - break; + scanner<<=8; + scanner|=buffer[i]; + } + if (i==inptr) return -1; - case MARKAD_PIDTYPE_AUDIO_AC3: - ts2pkt=new cMarkAdTS2Pkt("TS2PES AC3",32768); - break; + i-=2; + + if (ac3) + { + struct AC3HDR *ac3hdr = (struct AC3HDR *) &buffer[i]; + + if (ac3hdr->SampleRateIndex==3) return -1; // reserved + if (ac3hdr->FrameSizeIndex>=38) return -1; // reserved - case MARKAD_PIDTYPE_AUDIO_MP2: - ts2pkt=new cMarkAdTS2Pkt("TS2PES MP2",16384); + if (framesize) + { + int bitRatesAC3[3][38] = // all values are specified as kbits/s + { + { 64, 64, 80, 80, 96, 96, 112, 112, 128, 128, 160, 160, 192, 192, + 224, 224, 256, 256, 320, 320, 384, 384, 448, 448, 512, 512, + 640, 640, 768, 768, 896, 896, 1024, 1024, 1152, 1152, 1280, 1280 }, // 48kHz + + { 69, 70, 87, 88, 104, 105, 121, 122, 139, 140, 174, 175, 208, 209, + 243, 244, 278, 279, 348, 349, 417, 418, 487, 488, 557, 558, + 696, 697, 835, 836, 975, 976, 1114, 1115, 1253, 1254, 1393, 1394 }, // 44.1kHz + + { 96, 96, 120, 120, 144, 144, 168, 168, 192, 192, 240, 240, 288, + 288, 336, 336, 384, 384, 480, 480, 576, 576, 672, 672, 768, + 768, 960, 960, 1152, 1152, 1344, 1344, 1536, 1536, 1728, 1728, 1920,1920 } // 32kHz + }; + + *framesize=2*bitRatesAC3[ac3hdr->SampleRateIndex][ac3hdr->FrameSizeIndex]; + } + return i; + } + else + { + struct MP2HDR *mp2hdr = (struct MP2HDR *) &buffer[i]; + if (mp2hdr->MpegID==1) return -1; // reserved + if (mp2hdr->Layer==0) return -1; // reserved + if (mp2hdr->BitRateIndex==0xF) return -1; // forbidden + if (mp2hdr->SampleRateIndex==3) return -1; //reserved + if (mp2hdr->Emphasis==2) return -1; // reserved + + if (framesize) + { + int bitRates[3][3][16] = // all values are specified as kbits/s + { + { + { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, // M1, L1 + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, // M1, L2 + { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 } // M1, L3 + }, + { + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, // M2, L1 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, // M2, L2 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 } // M2, L3 + }, + { + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, // M2.5, L1 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, // M2.5, L2 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 } // M2.5, L3 + } + }; + + int samplingFrequencies[3][4] = // all values are specified in Hz + { + { 44100, 48000, 32000, -1 }, // MPEG 1 + { 22050, 24000, 16000, -1 }, // MPEG 2 + { 32000, 16000, 8000, -1 } // MPEG 2.5 + }; + + + int slots_per_frame[3][3] = + { + { 12, 144, 144 }, // MPEG 1, Layer I, II, III + { 12, 144, 72 }, // MPEG 2, Layer I, II, III + { 12, 144, 72 } // MPEG 2.5, Layer I, II, III + }; + + int mpegIndex; + switch (mp2hdr->MpegID) + { + case 0: + mpegIndex=2; + break; + case 2: + mpegIndex=1; + break; + case 3: + mpegIndex=0; + break; + default: + mpegIndex=0; // just to get rid of compiler warnings ;) + } + int layerIndex = 3 - mp2hdr->Layer; + + // Layer I (i. e., layerIndex == 0) has a larger slot size + int slotSize = (layerIndex == 0) ? 4 : 1; // bytes + int sf = samplingFrequencies[mpegIndex][mp2hdr->SampleRateIndex]; + + if (mp2hdr->BitRateIndex == 0) + *framesize = 0; // "free" Bitrate -> we don't support this! + else + { + int br = 1000 * bitRates[mpegIndex][layerIndex][mp2hdr->BitRateIndex]; // bits/s + int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots + + *framesize = (N + mp2hdr->Padding) * slotSize; // bytes + } + } + return i; + } +} + +int cPaketQueue::FindPesHeader(int Start) +{ + int start=outptr+Start; + int ssize,hsize; + int pos=findpktheader(start,&ssize,&hsize,false,true); + if (pos==-1) return -1; + pos-=outptr; + return pos; +} + +bool cPaketQueue::Put(uchar *Data, int Size) +{ + if (!buffer) return false; + if ((inptr) && (inptr==outptr)) inptr=outptr=0; + + if (outptr) + { + if (outptr>(inptr-outptr)) + { + memcpy(buffer,&buffer[outptr],inptr-outptr); + if (scannerstart==inptr) scannerstart-=outptr; + inptr-=outptr; + if (pktinfo.pkthdr==outptr) pktinfo.pkthdr=0; + outptr=0; + } + } + + if ((inptr+Size)>maxqueue) + { + if (name) + { + esyslog("buffer %s full",name); + } + else + { + esyslog("buffer full"); + } + mpercent=100; + Clear(); + return false; + } + + memcpy(&buffer[inptr],Data,Size); + inptr+=Size; + + int npercent=(int) ((inptr*100)/maxqueue); + if (npercent>mpercent) mpercent=npercent; + + if ((npercent>90) && (name) && (npercent!=percent)) + { + dsyslog("buffer %s usage: %3i%%", + name,npercent); + percent=npercent; + } + + return true; +} + +uchar *cPaketQueue::Get(int *Size) +{ + if (!buffer) return NULL; + if (!Size) return NULL; + if (Length()<*Size) + { + *Size=0; + return NULL; + } + uchar *ret=&buffer[outptr]; + outptr+=*Size; + return ret; +} + +uchar *cPaketQueue::Peek(int Size) +{ + if (!buffer) return NULL; + if (!Size) return NULL; + if (Length()<Size) return NULL; + uchar *ret=&buffer[outptr]; + return ret; +} + +uchar *cPaketQueue::GetPacket(int *Size, int Type) +{ + if (!Size) return NULL; + *Size=0; + if (Length()<4) return NULL; + + skipped=0; + if (pktinfo.pkthdr==-1) + { + scanner=0xFFFFFFFF; + scannerstart=outptr; + switch (Type) + { + case PACKET_AC3: + pktinfo.pkthdr=findaudioheader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,true); + break; + case PACKET_MP2: + pktinfo.pkthdr=findaudioheader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,false); break; + case PACKET_H264: + pktinfo.pkthdr=findpktheader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,true); + break; + default: + pktinfo.pkthdr=findpktheader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,false); + break; + } + + if (pktinfo.pkthdr==-1) + { + return NULL; + } + else + { + if (pktinfo.pkthdr!=outptr) + { + skipped=pktinfo.pkthdr-outptr; + } + } + scannerstart=pktinfo.pkthdr+pktinfo.pktsyncsize; + } + + int streamsize,pktsyncsize,pkthdr=-1; + + if (pktinfo.streamsize) + { + if ((pktinfo.pkthdr+pktinfo.streamsize)>inptr) + { + return NULL; // need more data + } + else + { + scannerstart=pktinfo.pkthdr+pktinfo.streamsize; + scanner=0xFFFFFFFF; + } + } + + switch (Type) + { + case PACKET_AC3: + pkthdr=findaudioheader(scannerstart,&streamsize,&pktsyncsize,true); + break; + case PACKET_MP2: + pkthdr=findaudioheader(scannerstart,&streamsize,&pktsyncsize,false); + break; + case PACKET_H264: + pkthdr=findpktheader(scannerstart,&streamsize,&pktsyncsize,true); + break; + default: + pkthdr=findpktheader(scannerstart,&streamsize,&pktsyncsize,false); + break; + } + + if (pkthdr==-1) + { + if ((pktinfo.streamsize) && ((inptr-outptr)>pktinfo.streamsize)) + { + // no startcode right after streamsize? + // output streamsize packet + scannerstart=pktinfo.pkthdr+pktinfo.streamsize; + streamsize=pktsyncsize=0; + pkthdr=-1; + } + else + { + scannerstart=inptr; + return NULL; } } - if (!ts2pkt) return; + else + { + scannerstart=pkthdr+pktsyncsize; + } + + uchar *ptr=&buffer[pktinfo.pkthdr]; + + if (pktinfo.streamsize) + { + *Size=pktinfo.streamsize; + } + else + { + *Size=pkthdr-pktinfo.pkthdr; + } + if (pkthdr==-1) + { + outptr=pktinfo.pkthdr+pktinfo.streamsize; + } + else + { + outptr=pkthdr; + } + + pktinfo.pkthdr=pkthdr; + pktinfo.streamsize=streamsize; + pktinfo.pktsyncsize=pktsyncsize; - if (!ts2pkt->Process(Pid,Data,Count,&pkt)) + return ptr; +} + +// ---------------------------------------------------------------------------- + +cTS2Pkt::cTS2Pkt(int Pid, const char *QueueName, int QueueSize, bool H264) +{ + queue=new cPaketQueue(QueueName,QueueSize); + pid=Pid; + h264=H264; + firstsync=false; + Clear(); +} + +cTS2Pkt::~cTS2Pkt() +{ + if (queue) { - if (pes2audioes) pes2audioes->Clear(); - return; + if (skipped) esyslog("buffer skipped: %-15s %i bytes",queue->Name(),skipped); + delete queue; } +} - if ((Pid.Type==MARKAD_PIDTYPE_AUDIO_AC3) || (Pid.Type==MARKAD_PIDTYPE_AUDIO_MP2)) +void cTS2Pkt::Clear() +{ + sync=false; + counter=-1; + skipped=0; + noticeFILLER=false; + noticeSEQUENCE=false; + noticeSTREAM=false; + if (queue) queue->Clear(); +} + +bool cTS2Pkt::Process(uchar *TSData, int TSSize, AvPacket *Pkt) +{ + if (!Pkt) return false; + if (TSData) { - if (!pes2audioes) pes2audioes=new cMarkAdPES2ES((Pid.Type==MARKAD_PIDTYPE_AUDIO_AC3) ? - "PES2ES AC3" : "PES2ES MP2"); - if (!pes2audioes) return; - pes2audioes->Process(Pid,pkt.Data,pkt.Length,Pkt); + if (TSSize!=TS_SIZE) return false; + + struct TSHDR *tshdr = (struct TSHDR *) TSData; + + int ppid=(tshdr->PidH << 8) | tshdr->PidL; + if (ppid!=pid) + { + return false; + } + + if ((counter!=-1) && (((counter+1) & 0xF)!=tshdr->Counter)) + { + if (counter==(int) tshdr->Counter) + { + skipped+=TS_SIZE; + return true; // duplicate paket -> just ignore + } + // sequence error + if (!noticeSEQUENCE) + { + noticeSEQUENCE=true; + isyslog("sequence error"); + } + if (queue) + { + skipped+=queue->Length(); + queue->Clear(); + } + counter=-1; + sync=false; + if (!tshdr->PayloadStart) return true; + } + counter=tshdr->Counter; + + if (tshdr->PayloadStart) + { + firstsync=sync=true; + } + if (!sync) + { + if (firstsync) skipped+=TS_SIZE; // only count skipped bytes after first sync + return true; // not synced + } + + // we just ignore the infos in the adaption field (e.g. OPCR/PCR) + if ((tshdr->AFC!=1) && (tshdr->AFC!=3)) + { + return true; + } + + int buflen=TS_SIZE+1; + uchar *buf=NULL; + + if (tshdr->AFC==1) + { + // payload only + buflen=TS_SIZE-sizeof(struct TSHDR); + buf=&TSData[sizeof(struct TSHDR)]; + } + + if (tshdr->AFC==3) + { + // adaption field + payload + int alen=TSData[4]+1; + if (alen>(TS_SIZE-(int) sizeof(struct TSHDR))) alen=TS_SIZE-(int) sizeof(struct TSHDR); + buflen=TS_SIZE-(sizeof(struct TSHDR)+alen); + buf=&TSData[sizeof(struct TSHDR)+alen]; + } + + if (!buflen) + { + // no data? -> impossible? + return false; + } + + if (tshdr->PayloadStart) + { + if ((buf[0]!=0) && (buf[1]!=0)) + { + if (!noticeSTREAM) + { + isyslog("stream error"); + noticeSTREAM=true; + } + skipped+=TS_SIZE; + sync=false; + if (buflen<7) return false; + // add a pseudo padding stream + buf[0]=0; + buf[1]=0; + buf[2]=1; + buf[3]=0xbe; + buf[4]=0; + buf[5]=buflen-6; + } + } + queue->Put(buf,buflen); } - if ((Pid.Type==MARKAD_PIDTYPE_VIDEO_H262) || (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264)) + Pkt->Data=queue->GetPacket(&Pkt->Length,h264 ? PACKET_H264 : PACKET_H262); + if (Pkt->Data) { - if ((pkt.Data) && ((pkt.Data[3] & 0xF0)==0xE0) && (pkt.Data[4]!=0) && (pkt.Data[5]!=0)) + Pkt->Type=h264 ? PACKET_H264 : PACKET_H262; + if ((h264) && ((Pkt->Data[4] & 0x1F)==0x0C)) { - ts2pkt->InjectVideoPES(pkt.Data,pkt.Length); - pkt.Data=NULL; - pkt.Length=0; + if (!noticeFILLER) + { + isyslog("H264 video stream with filler nalu"); + noticeFILLER=true; + } + skipped+=Pkt->Length; // thats not accurate! + Pkt->Data=NULL; + Pkt->Length=0; + Pkt->Type=0; } - Pkt->Data=pkt.Data; - Pkt->Length=pkt.Length; - Pkt->Skipped=pkt.Skipped; } - return; + else + { + Pkt->Length=0; + Pkt->Type=0; + } + return true; } -int cMarkAdDemux::GetMinNeeded(MarkAdPid Pid, uchar *Data, int Count, bool *Offcnt) +// ---------------------------------------------------------------------------- + +cPES2ES::cPES2ES(int PacketType, const char *QueueName, int QueueSize) { - if (Pid.Num>=0) return TS_SIZE; + queue = new cPaketQueue(QueueName,QueueSize); + ptype=PacketType; + Clear(); +} - uchar *qData=queue->Peek(PESHDRSIZE); - if (!qData) +cPES2ES::~cPES2ES() +{ + if (queue) { - int len=PESHDRSIZE-queue->Length(); - int cnt=(Count>len) ? len : Count; - queue->Put(Data,cnt); - return -cnt; + if (skipped) esyslog("buffer skipped: %-15s %i bytes",queue->Name(),skipped); + delete queue; } +} - int stream=qData[3]; +void cPES2ES::Clear() +{ + skipped=0; + if (queue) queue->Clear(); +} - if ((qData[0]==0) && (qData[1]==0) && (qData[2]==1) && (stream>0xBC)) +bool cPES2ES::Process(uchar *PESData, int PESSize, AvPacket *ESPkt) +{ + if (!ESPkt) return false; + if (PESData) { - int needed=qData[4]*256+qData[5]; + struct PESHDR *peshdr=(struct PESHDR *) PESData; + + // first check some simple things + if ((peshdr->Sync1!=0) && (peshdr->Sync2!=0) && (peshdr->Sync3!=1)) return false; + if (peshdr->StreamID<=0xBC) return false; - if (((Pid.Type==MARKAD_PIDTYPE_VIDEO_H262) || - (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264)) && ((stream & 0xF0)!=0xE0)) + int Length=(peshdr->LenH<<8)+peshdr->LenL; + if (Length) { - // ignore 6 header bytes from queue->Put above - queue->Clear(); - if (Offcnt) *Offcnt=true; - return -needed; + Length+=sizeof(PESHDR); + if (Length!=PESSize) + { + skipped+=Length; + return true; + } } - if ((Pid.Type==MARKAD_PIDTYPE_AUDIO_MP2) && ((stream & 0xF0)!=0xC0)) + + if (peshdr->StreamID==0xBE) { - // ignore 6 header bytes from queue->Put above queue->Clear(); - if (Offcnt) *Offcnt=true; - return -needed; + return true; } - if ((Pid.Type==MARKAD_PIDTYPE_AUDIO_AC3) && (stream!=0xBD)) + + switch (ptype) { - // ignore 6 header bytes from queue->Put above - queue->Clear(); - if (Offcnt) *Offcnt=true; - return -needed; + case PACKET_H262: + if (peshdr->StreamID!=0xE0) return true; // ignore packets not for us! + break; + case PACKET_H264: + if (peshdr->StreamID!=0xE0) return true; // ignore packets not for us! + break; + case PACKET_AC3: + if (peshdr->StreamID!=0xBD) return true; // ignore packets not for us! + break; + case PACKET_MP2: + if (peshdr->StreamID!=0xC0) return true; // ignore packets not for us! + break; + default: + break; + } + + struct PESHDROPT *peshdropt=(struct PESHDROPT *) &PESData[sizeof(struct PESHDR)]; + + uchar *buf; + int buflen; + + if (peshdropt->MarkerBits==0x2) + { + // we have an optional PES header + int bpos=sizeof(struct PESHDR)+sizeof(struct PESHDROPT)+ + peshdropt->Length; + buf=&PESData[bpos]; + buflen=PESSize-bpos; + } + else + { + int bpos=sizeof(struct PESHDR); + buf=&PESData[bpos]; + buflen=PESSize-bpos; } - return needed+PESHDRSIZE; + queue->Put(buf,buflen); + } + ESPkt->Data=queue->GetPacket(&ESPkt->Length,ptype); + if (ESPkt->Data) + { + ESPkt->Type=ptype; } else { - queue->Clear(); - if (Offcnt) *Offcnt=true; - return -1; // skip one byte (maybe we get another header!) + ESPkt->Type=0; + ESPkt->Length=0; } + skipped+=queue->Skipped(); + return true; } -void cMarkAdDemux::VDRTSAddPATPMT2Offset(MarkAdPid Pid, uchar *Data, int Count, bool *Offcnt) +// ---------------------------------------------------------------------------- + +cDemux::cDemux(int VPid, int DPid, int APid, bool H264, bool VDRCount) { - if (Pid.Num<0) return; - if (Count<2) return; - if ((Data[0]==0x47) && (Data[1]==0x40) && ((Data[2]==0) || (Data[2]==0x84))) *Offcnt=false; + vpid=(VPid!=0) ? VPid : -1; + dpid=(DPid!=0) ? DPid : -1; + apid=(APid!=0) ? APid : -1; + TS=false; + if ((vpid>0) || (dpid>0) || (apid>0)) TS=true; + pes2videoes=NULL; + pes2audioes_mp2=NULL; + pes2audioes_ac3=NULL; + ts2pkt_vpid=NULL; + ts2pkt_dpid=NULL; + ts2pkt_apid=NULL; + h264=H264; + vdrcount=VDRCount; + queue = new cPaketQueue("DEMUX",5640); + skipped=0; + Clear(); } -int cMarkAdDemux::Process(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *Pkt) +cDemux::~cDemux() { - if ((!Data) && (!Count) && (!Pkt)) return -1; + if (skipped) tsyslog("buffer skipped: %-15s %i bytes",queue->Name(),skipped); + if (queue) delete queue; + + if (ts2pkt_vpid) delete ts2pkt_vpid; + if (pes2videoes) delete pes2videoes; - uchar *in=NULL; - int inlen=0; - int retval=0; + if (ts2pkt_dpid) delete ts2pkt_dpid; + if (pes2audioes_ac3) delete pes2audioes_ac3; + + if (ts2pkt_apid) delete ts2pkt_apid; + if (pes2audioes_mp2) delete pes2audioes_mp2; + +} + +int cDemux::Skipped() +{ + int val=skipped; + if (pes2videoes) val+=pes2videoes->Skipped(); + if (pes2audioes_mp2) val+=pes2audioes_mp2->Skipped(); + if (pes2audioes_ac3) val+=pes2audioes_ac3->Skipped(); + if (ts2pkt_vpid) val+=ts2pkt_vpid->Skipped(); + if (ts2pkt_dpid) val+=ts2pkt_dpid->Skipped(); + if (ts2pkt_apid) val+=ts2pkt_apid->Skipped(); + return val; +} - if (!pause) +void cDemux::Clear() +{ + if (pes2videoes) pes2videoes->Clear(); + if (pes2audioes_mp2) pes2audioes_mp2->Clear(); + if (pes2audioes_ac3) pes2audioes_ac3->Clear(); + if (ts2pkt_vpid) ts2pkt_vpid->Clear(); + if (ts2pkt_dpid) ts2pkt_dpid->Clear(); + if (ts2pkt_apid) ts2pkt_apid->Clear(); + + if (queue) queue->Clear(); + offset=0; + vdroffset=0; + last_bplen=0; + from_oldfile=0; + stream_or_pid=0; +} + +bool cDemux::isvideopes(uchar *data, int count) +{ + if (!data) return false; + if (count<6) return false; + if ((data[0]==0) && (data[1]==0) && (data[2]==1) && + ((data[3] & 0xF0)==0xE0) && + ((data[4]!=0) || (data[5]!=0))) return true; + return false; +} + +int cDemux::checkts(uchar *data, int count, int &pid) +{ + if (count<(int) sizeof(struct TSHDR)) return -1; + if (data[0]!=0x47) return 1; + + struct TSHDR *tshdr = (struct TSHDR *) data; + if ((tshdr->AFC<=0) || (tshdr->AFC>3)) return 1; + + pid = (tshdr->PidH << 8) | tshdr->PidL; + return 0; +} + +int cDemux::fillqueue(uchar *data, int count, int &stream_or_pid, int &packetsize, int &readout) +{ +#define PEEKBUF 6 + stream_or_pid=packetsize=readout=0; + + uchar *qData=NULL; + + while (!(qData=queue->Peek(PEEKBUF))) { - Pkt->Data=NULL; - Pkt->Length=0; - Pkt->Skipped=0; - Pkt->Offcnt=false; + int len=PEEKBUF-queue->Length(); + int cnt=(count>len) ? len : count; + if (!queue->Put(data,cnt)) return -1; + readout+=cnt; + data+=cnt; + count-=cnt; + if (queue->Length()<PEEKBUF) return cnt; // we need more data! + } - if (!min_needed) + if (!TS) + { + if ((qData[0]==0) && (qData[1]==0) && (qData[2]==1) && (qData[3]>=0xBC)) { - if (skip) + stream_or_pid=qData[3]; + packetsize=PEEKBUF+(qData[4]*256+qData[5]); + } + else + { + skipped++; + stream_or_pid=0; + packetsize=1; + return 0; + } + } + else + { + int error_skipbytes=checkts(qData,PEEKBUF,stream_or_pid); + if (error_skipbytes==-1) return -1; + if (error_skipbytes) + { + skipped+=error_skipbytes; + stream_or_pid=0; + packetsize=1; + return error_skipbytes; // no useable data found, try next! + } + packetsize=TS_SIZE; + } + + int needed=packetsize+PEEKBUF; + while (!(qData=queue->Peek(needed))) + { + int len=needed-queue->Length(); + int cnt=(count>len) ? len : count; + if (!queue->Put(data,cnt)) return -1; + readout+=cnt; + data+=cnt; + count-=cnt; + if (queue->Length()<needed) return cnt; // we need more data! + } + if (!TS) + { + // check length of PES-paket + qData=queue->Peek(packetsize+PEEKBUF); + if (qData) + { + int start=packetsize; + if ((qData[start]!=0) || (qData[start+1]!=0) || (qData[start+2]!=1) || (qData[start+3]<0xBC)) { - int t_skip=skip; - skip=0; - Pkt->Offcnt=true; - return t_skip; + int start=queue->FindPesHeader(1); + if (start) + { + // broken PES in queue, skip it + packetsize=start; + skipped+=start; + stream_or_pid=0; + return 0; + } + else + { + return -1; + } } - - int t_min_needed=GetMinNeeded(Pid,Data,Count,&Pkt->Offcnt); - if (t_min_needed==0) + } + } + else + { + qData=queue->Peek(packetsize+PEEKBUF); + if (qData) + { + int start=packetsize; + int pid; + int ret=checkts(&qData[start],PEEKBUF,pid); + if (ret==-1) { return -1; } - if (t_min_needed<0) + if (ret) { - if (-t_min_needed>Count) - { - skip=-t_min_needed-Count; - return Count; - } - if (t_min_needed==-1) Pkt->Skipped++; - return -t_min_needed; + return -1; } - min_needed=t_min_needed; } + } + return 0; +} - int needed=min_needed-queue->Length(); +bool cDemux::needmoredata() +{ + if (!stream_or_pid) return true; - if (Count>needed) + if (!TS) + { + switch (stream_or_pid) { - queue->Put(Data,needed); - retval=needed; + case 0xE0: + if (pes2videoes) return pes2videoes->NeedMoreData(); + break; + case 0xC0: + if (pes2audioes_mp2) return pes2audioes_mp2->NeedMoreData(); + break; + case 0xBD: + if (pes2audioes_ac3) return pes2audioes_ac3->NeedMoreData(); + break; } - else + } + + if (TS) + { + if ((stream_or_pid==vpid) && (ts2pkt_vpid)) { - queue->Put(Data,Count); - retval=Count; + if (pes2videoes) return pes2videoes->NeedMoreData(); + return ts2pkt_vpid->NeedMoreData(); } - if (queue->Length()<min_needed) + if ((stream_or_pid==dpid) && (ts2pkt_dpid)) { - return Count; + if (pes2audioes_ac3) return pes2audioes_ac3->NeedMoreData(); + return ts2pkt_dpid->NeedMoreData(); + } + if ((stream_or_pid==apid) && (ts2pkt_apid)) + { + if (pes2audioes_mp2) return pes2audioes_mp2->NeedMoreData(); + return ts2pkt_apid->NeedMoreData(); } - inlen=min_needed; - in=queue->Get(&inlen); - min_needed=0; } + return false; +} - if (Pid.Num>=0) +bool cDemux::vdraddpatpmt(uchar *data, int count) +{ + // TS-VDR adds pat/pmt to the output, e.g. if + // a picture starts @376, vdr outputs 0 (!) + int pid; + if (checkts(data,count,pid)!=0) return false; + if ((!pid) || (pid==132)) { - ProcessTS(Pid, in, inlen, Pkt); + last_bplen=0; + vdroffset+=count; } else { - ProcessVDR(Pid, in, inlen, Pkt); + last_bplen=vdroffset+count; + vdroffset=0; } + return true; +} - if (Pkt->Data) +void cDemux::addoffset() +{ + offset+=last_bplen; + if (from_oldfile) { - if (!pause_retval) pause_retval=retval; - pause=true; - return 0; + from_oldfile-=last_bplen; + if (!from_oldfile) offset=0; } + last_bplen=0; +} + +void cDemux::NewFile() +{ + from_oldfile=queue->Length(); +} + +int cDemux::Process(uchar *Data, int Count, AvPacket *pkt) +{ + if (!pkt) return -1; + pkt->Data=NULL; + pkt->Length=0; + + bool add=needmoredata(); - if (pause) + int bplen=0,readout=0; + uchar *bpkt=NULL; + if (add) + { + addoffset(); + int advance=fillqueue(Data,Count,stream_or_pid,bplen,readout); + if (advance<0) return -1; + if (advance) return advance; + bpkt=queue->Get(&bplen); + if (!bpkt) return -1; + last_bplen=bplen; + if (vdrcount) vdraddpatpmt(bpkt,bplen); + } + + if (!TS) + { + switch (stream_or_pid) + { + case 0xE0: + if (!pes2videoes) + { + if (h264) + { + pes2videoes=new cPES2ES(PACKET_H264,"PES2H264ES",524288); + } + else + { + pes2videoes=new cPES2ES(PACKET_H262,"PES2H262ES",65536); + } + } + if (!pes2videoes->Process(bpkt,bplen,pkt)) return -1; + break; + case 0xC0: + if (!pes2audioes_mp2) pes2audioes_mp2=new cPES2ES(PACKET_MP2,"PES2MP2",16384); + if (!pes2audioes_mp2->Process(bpkt,bplen,pkt)) return -1; + break; + case 0xBD: + if (!pes2audioes_ac3) pes2audioes_ac3=new cPES2ES(PACKET_AC3,"PES2AC3"); + if (!pes2audioes_ac3->Process(bpkt,bplen,pkt)) return -1; + break; + default: + stream_or_pid=0; + break; + } + } + if (TS) { - if (pause_retval) + if (stream_or_pid==vpid) + { + if (!ts2pkt_vpid) + { + if (h264) + { + ts2pkt_vpid=new cTS2Pkt(vpid,"TS2H264",524288,true); + } + else + { + ts2pkt_vpid=new cTS2Pkt(vpid,"TS2H262",65536); + } + } + if (!ts2pkt_vpid->Process(bpkt,bplen,pkt)) return -1; + if (isvideopes(pkt->Data,pkt->Length) || pes2videoes) + { + AvPacket tpkt; + memcpy(&tpkt,pkt,sizeof(AvPacket)); + memset(pkt,0,sizeof(AvPacket)); + if (!pes2videoes) + { + ts2pkt_vpid->Resize(3*tpkt.Length,"TS2PES"); + if (h264) + { + pes2videoes=new cPES2ES(PACKET_H264,"PES2H264ES",524288); + } + else + { + pes2videoes=new cPES2ES(PACKET_H262,"PES2H262ES",65536); + } + } + if (!pes2videoes->Process(tpkt.Data,tpkt.Length,pkt)) return -1; + } + } + else if (stream_or_pid==dpid) { - retval=pause_retval; - pause_retval=0; + AvPacket tpkt={NULL,0,0}; + if (!ts2pkt_dpid) ts2pkt_dpid=new cTS2Pkt(dpid,"TS2PES AC3"); + if (!ts2pkt_dpid->Process(bpkt,bplen,&tpkt)) return -1; + if (!pes2audioes_ac3) pes2audioes_ac3=new cPES2ES(PACKET_AC3,"PES2AC3"); + if (!pes2audioes_ac3->Process(tpkt.Data,tpkt.Length,pkt)) return -1; } - pause=false; + else if (stream_or_pid==apid) + { + AvPacket tpkt={NULL,0,0}; + if (!ts2pkt_apid) ts2pkt_apid=new cTS2Pkt(apid,"TS2PES MP2",16384); + if (!ts2pkt_apid->Process(bpkt,bplen,&tpkt)) return -1; + if (!pes2audioes_mp2) pes2audioes_mp2=new cPES2ES(PACKET_MP2,"PES2MP2",16384); + if (!pes2audioes_mp2->Process(tpkt.Data,tpkt.Length,pkt)) return -1; + } + else stream_or_pid=0; } - - Pkt->Offcnt=true; - VDRTSAddPATPMT2Offset(Pid, in, inlen, &Pkt->Offcnt); - return retval; + return add ? readout : 0; } diff --git a/command/demux.h b/command/demux.h index 0c91c7a..4213479 100644 --- a/command/demux.h +++ b/command/demux.h @@ -8,39 +8,322 @@ #ifndef __demux_h_ #define __demux_h_ -#ifndef TS_SIZE -#define TS_SIZE 188 +#include <stdint.h> + +#ifndef uchar +typedef unsigned char uchar; #endif -#define PESHDRSIZE 6 +#define PACKET_MASK 0xF0 +#define PACKET_VIDEO 0x10 +#define PACKET_H262 0x10 // 0x00 0x00 0x01 (PES / H262) +#define PACKET_H264 0x11 // 0x00 0x00 0x00 0x01 (H264) +#define PACKET_AUDIO 0x20 +#define PACKET_AC3 0x20 +#define PACKET_MP2 0x21 + +typedef struct AvPacket +{ + uchar *Data; + int Length; + int Type; +} AvPacket; + +struct TSHDR +{ +unsigned Sync: + 8; +unsigned PidH: + 5; +unsigned Priority: + 1; +unsigned PayloadStart: + 1; +unsigned TError: + 1; +unsigned PidL: + 8; +unsigned Counter: + 4; +unsigned AFC: + 2; +unsigned TSC: + 2; +}; + +struct PESHDR +{ + uchar Sync1; + uchar Sync2; + uchar Sync3; + uchar StreamID; + uchar LenH; + uchar LenL; +}; + +#pragma pack(1) +struct PESHDROPT +{ +unsigned OOC: + 1; +unsigned CY: + 1; +unsigned DAI: + 1; +unsigned PESP: + 1; +unsigned PESSC: + 2; +unsigned MarkerBits: + 2; +unsigned EXT: + 1; +unsigned CRC: + 1; +unsigned ACI: + 1; +unsigned TM: + 1; +unsigned RATE: + 1; +unsigned ESCR: + 1; +unsigned PTSDTS: + 2; +unsigned Length: + 8; +}; +#pragma pack() + +// ---------------------------------------------------------------------------- + +class cPaketQueue +{ + struct MP2HDR + { +unsigned Sync1: + 8; +unsigned Protection: + 1; +unsigned Layer: + 2; +unsigned MpegID: + 2; +unsigned Sync2: + 3; +unsigned Private: + 1; +unsigned Padding: + 1; +unsigned SampleRateIndex: + 2; +unsigned BitRateIndex: + 4; +unsigned Emphasis: + 2; +unsigned Original: + 1; +unsigned Copyright: + 1; +unsigned ModeExt: + 2; +unsigned Mode: + 2; + }; + +#pragma pack(1) + struct AC3HDR + { +unsigned Sync1: + 8; +unsigned Sync2: + 8; +unsigned CRC1: + 8; +unsigned CRC2: + 8; +unsigned FrameSizeIndex: + 6; +unsigned SampleRateIndex: + 2; + }; +#pragma pack() + +private: + const char *name; + struct pktinfo + { + int pkthdr; + int pktsyncsize; + int streamsize; + bool ispes; + } pktinfo; + + int percent; + int mpercent; // max percentage use + + uchar *buffer; + int maxqueue; + int inptr; + int outptr; + + int skipped; -#include "queue.h" -#include "ts2pkt.h" -#include "pes2es.h" + uint32_t scanner; + int scannerstart; -class cMarkAdDemux + int findaudioheader(int start, int *framesize, int *headersize, bool ac3); + int findpktheader(int start, int *streamsize,int *headersize, bool longstartcode, bool pesonly); +public: + cPaketQueue(const char *Name, int Size=32768); + ~cPaketQueue(); + int Length() + { + return inptr-outptr; + } + const char *Name() + { + return name; + } + void Clear(); + int Skipped() + { + return skipped; + } + bool Put(uchar *Data, int Size); + uchar *Get(int *Size); + uchar *Peek(int Size); + uchar *GetPacket(int *Size, int Type); + void Resize(int NewSize, const char *NewName=NULL); + bool NeedMoreData() + { + if (scannerstart==-1) return true; + if (pktinfo.streamsize) + { + return (((inptr-pktinfo.pkthdr)-outptr)<=(pktinfo.streamsize+6)); + } + else + { + return ((scannerstart==inptr) || (scannerstart==outptr)); + } + } + int FindPesHeader(int Start); +}; + +// ---------------------------------------------------------------------------- + +class cTS2Pkt { +private: + cPaketQueue *queue; + int counter; + bool sync; + bool firstsync; + int skipped; + int pid; + bool h264; + bool noticeFILLER; + bool noticeSEQUENCE; + bool noticeSTREAM; +public: + cTS2Pkt(int Pid, const char *QueueName="TS2Pkt", int QueueSize=32768, bool H264=false); + ~cTS2Pkt(); + void Clear(); + int Skipped() + { + return skipped; + } + bool Process(uchar *TSData, int TSSize, AvPacket *Pkt); + void Resize(int NewQueueSize, const char *NewQueueName) + { + queue->Resize(NewQueueSize, NewQueueName); + } + bool NeedMoreData() + { + if (queue) + { + return queue->NeedMoreData(); + } + else + { + return false; + } + } +}; +// ---------------------------------------------------------------------------- + +class cPES2ES +{ private: - cMarkAdTS2Pkt *ts2pkt; - cMarkAdPES2ES *pes2audioes; - cMarkAdPES2ES *pes2videoes; - cMarkAdPaketQueue *queue; - - bool pause; - int pause_retval; - int min_needed; - int skip; - - int GetMinNeeded(MarkAdPid Pid, uchar *Data, int Count, bool *Offcnt); - void ProcessTS(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *pkt); - void ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *pkt); - void VDRTSAddPATPMT2Offset(MarkAdPid Pid, uchar *Data, int Count, bool *Offcnt); + cPaketQueue *queue; + int skipped; + int ptype; + bool h264; +public: + cPES2ES(int PacketType, const char *QueueName="PES2ES", int QueueSize=32768); + ~cPES2ES(); + void Clear(); + bool Process(uchar *PESData, int PESSize, AvPacket *ESPkt); + int Skipped() + { + return skipped; + } + bool NeedMoreData() + { + if (queue) + { + return queue->NeedMoreData(); + } + else + { + return false; + } + } +}; + +// ---------------------------------------------------------------------------- + +class cDemux +{ +private: + int vpid,dpid,apid; + int stream_or_pid; + int skipped; + bool h264; + bool TS; + uint64_t offset; + int from_oldfile; + int last_bplen; + + bool vdrcount; + int vdroffset; + bool vdraddpatpmt(uchar *data, int count); + + void addoffset(); + + cPaketQueue *queue; + cPES2ES *pes2videoes; + cPES2ES *pes2audioes_mp2; + cPES2ES *pes2audioes_ac3; + cTS2Pkt *ts2pkt_vpid; + cTS2Pkt *ts2pkt_dpid; + cTS2Pkt *ts2pkt_apid; + bool needmoredata(); + int checkts(uchar *data, int count, int &pid); + bool isvideopes(uchar *data, int count); + int fillqueue(uchar *data, int count, int &stream_or_pid, int &packetsize, int &readout); public: - cMarkAdDemux(); - ~cMarkAdDemux(); + cDemux(int VPid, int DPid, int APid, bool H264=false, bool VDRCount=false); + ~cDemux(); void Clear(); - int Process(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *pkt); + int Skipped(); + void NewFile(); + uint64_t Offset() + { + return offset; + } + int Process(uchar *Data, int Count, AvPacket *pkt); }; #endif diff --git a/command/global.h b/command/global.h index 52764ee..bfd4703 100644 --- a/command/global.h +++ b/command/global.h @@ -34,23 +34,21 @@ typedef unsigned char uchar; #define MT_ASSUMEDSTART 0x21 #define MT_ASSUMEDSTOP 0x22 -#define MT_ASPECTCHANGE 0x30 -#define MT_ASPECTSTART 0x31 -#define MT_ASPECTSTOP 0x32 +#define MT_LOGOCHANGE 0x30 +#define MT_LOGOSTART 0x31 +#define MT_LOGOSTOP 0x32 -#define MT_CHANNELCHANGE 0x40 -#define MT_CHANNELSTART 0x41 -#define MT_CHANNELSTOP 0x42 +#define MT_BORDERCHANGE 0x40 +#define MT_BORDERSTART 0x41 +#define MT_BORDERSTOP 0x42 -#define MT_LOGOCHANGE 0x50 -#define MT_LOGOSTART 0x51 -#define MT_LOGOSTOP 0x52 +#define MT_ASPECTCHANGE 0x50 +#define MT_ASPECTSTART 0x51 +#define MT_ASPECTSTOP 0x52 -#define MT_BORDERCHANGE 0x60 -#define MT_BORDERSTART 0x61 -#define MT_BORDERSTOP 0x62 - -#define MT_SILENCECHANGE 0x90 +#define MT_CHANNELCHANGE 0x60 +#define MT_CHANNELSTART 0x61 +#define MT_CHANNELSTOP 0x62 #define MT_MOVED 0xE0 #define MT_ALL 0xFF @@ -125,9 +123,11 @@ typedef struct MarkAdContext struct Info { + + MarkAdAspectRatio AspectRatio; int Channels; + char *ChannelName; - MarkAdAspectRatio AspectRatio; MarkAdPid VPid; MarkAdPid APid; MarkAdPid DPid; diff --git a/command/markad-standalone.cpp b/command/markad-standalone.cpp index 3d129a6..70d9aa7 100644 --- a/command/markad-standalone.cpp +++ b/command/markad-standalone.cpp @@ -179,6 +179,32 @@ int cOSDMessage::Send(const char *format, ...) return 0; } +void cMarkAdStandalone::AddStartMark() +{ +#if 0 + char *buf; + if (asprintf(&buf,"start of recording (0)")!=-1) + { + MarkAdMark Mark; + Mark.Position=0; + Mark.Type=MT_COMMONSTART; + Mark.Comment=buf; + AddMark(&Mark); + free(buf); + } +#endif + + if (tStart) + { + iStart=-(tStart*macontext.Video.Info.FramesPerSecond); + } + CalculateStopPosition(-iStart,macontext.Video.Info.FramesPerSecond*MAXRANGE); + if (tStart==1) + { + tStart=iStart=0; + } +} + void cMarkAdStandalone::CalculateStopPosition(int startframe, int delta) { if (!length) return; @@ -199,29 +225,7 @@ void cMarkAdStandalone::CalculateStopPosition(int startframe, int delta) } } -void cMarkAdStandalone::AddStartMark() -{ - if (tStart<2) - { - char *buf; - if (asprintf(&buf,"start of recording (0)")!=-1) - { - marks.Add(MT_COMMONSTART,0,buf); - isyslog("%s",buf); - free(buf); - } - } - if (tStart) - { - iStart=-(tStart*macontext.Video.Info.FramesPerSecond); - } - CalculateStopPosition(-iStart,macontext.Video.Info.FramesPerSecond*MAXRANGE); - if (tStart==1) - { - tStart=iStart=0; - } -} - +#if 0 void cMarkAdStandalone::CheckStartStop(int frame, bool checkend) { MarkAdMark mark; @@ -233,7 +237,7 @@ void cMarkAdStandalone::CheckStartStop(int frame, bool checkend) clMark *before_iStart=marks.GetPrev(iStart,MT_START,0xF); clMark *after_iStart=marks.GetNext(iStart,MT_START,0xF); - int MAXMARKDIFF=(int) (macontext.Video.Info.FramesPerSecond*MAXRANGE); + int MAXMARKDIFF=MAXRANGE*macontext.Video.Info.FramesPerSecond; int type=0; int newpos=0; int delta_before=MAXMARKDIFF; @@ -352,12 +356,11 @@ void cMarkAdStandalone::CheckStartStop(int frame, bool checkend) AddMark(&mark); free(buf); } - - int MARKDIFF=length/6; - if (MARKDIFF>MAXRANGE) MARKDIFF=MAXRANGE; - MARKDIFF=(int) (MARKDIFF*macontext.Video.Info.FramesPerSecond); - iStartCheck=iStart+MARKDIFF; - CalculateStopPosition(iStart,MARKDIFF); + int MAXMARKDIFF=(int) (macontext.Video.Info.FramesPerSecond*MAXRANGE); + iStartCheck=iStart+MAXMARKDIFF; + int CHECKPOINT=(int) ((length*macontext.Video.Info.FramesPerSecond)/18); + if (CHECKPOINT>MAXMARKDIFF) CHECKPOINT=MAXMARKDIFF; + CalculateStopPosition(iStart,CHECKPOINT); } if ((iStop<0) && (lastiframe>-iStop)) { @@ -597,7 +600,7 @@ void cMarkAdStandalone::AddMark(MarkAdMark *Mark) } if (prev->type==MT_ASPECTSTART) { - int MARKDIFF=(int) (macontext.Video.Info.FramesPerSecond*240); + int MARKDIFF=(int) macontext.Video.Info.FramesPerSecond; if ((Mark->Position-prev->position)<MARKDIFF) { if (Mark->Comment) isyslog("%s",Mark->Comment); @@ -793,12 +796,75 @@ void cMarkAdStandalone::AddMark(MarkAdMark *Mark) marks.Del((uchar) MT_BORDERSTOP); } } - if (Mark->Position>chkLEFT) CheckFirstMark(); + if ((iStart==0) && (!marksAligned)) CheckFirstMark(); if (marksAligned) CheckLogoMarks(marks.GetLast()); if ((Mark->Comment) && (!loggedAlready)) isyslog("%s",Mark->Comment); marks.Add(Mark->Type,Mark->Position,Mark->Comment); } +#endif + +void cMarkAdStandalone::AddMark(MarkAdMark *Mark) +{ + if (!Mark) return; + if (!Mark->Type) return; + + if ((Mark->Type & 0x0F)==MT_STOP) + { + clMark *prev=marks.GetPrev(Mark->Position,(Mark->Type & 0xF0)|MT_START); + if (prev) + { + int MARKDIFF; + if ((Mark->Type & 0xF0)==MT_LOGOCHANGE) + { + MARKDIFF=(int) (macontext.Video.Info.FramesPerSecond*240); + } + else + { + MARKDIFF=(int) (macontext.Video.Info.FramesPerSecond*10); + } + if ((Mark->Position-prev->position)<MARKDIFF) + { + if (Mark->Comment) isyslog("%s",Mark->Comment); + double distance=(Mark->Position-prev->position)/macontext.Video.Info.FramesPerSecond; + isyslog("mark distance too short (%.1fs), deleting %i,%i",distance, + prev->position,Mark->Position); + marks.Del(prev); + return; + } + } + } + + clMark *prev=marks.GetLast(); + if (prev) + { + if ((prev->type & 0x0F)==(Mark->Type & 0x0F)) + { + int MARKDIFF=(int) (macontext.Video.Info.FramesPerSecond*30); + int diff=abs(Mark->Position-prev->position); + if (diff<MARKDIFF) + { + if (Mark->Comment) isyslog("%s",Mark->Comment); + if (prev->type>Mark->Type) + { + isyslog("previous mark (%i) stronger than actual mark, deleting %i", + prev->position, Mark->Position); + return; + } + else + { + isyslog("actual mark stronger then previous mark, deleting %i",prev->position); + marks.Del(prev); + marks.Add(Mark->Type,Mark->Position,Mark->Comment); + return; + } + } + } + } + + isyslog("%s",Mark->Comment); + marks.Add(Mark->Type,Mark->Position,Mark->Comment); +} void cMarkAdStandalone::SaveFrame(int frame) { @@ -825,6 +891,7 @@ void cMarkAdStandalone::SaveFrame(int frame) fclose(pFile); } +#if 0 void cMarkAdStandalone::CheckBroadcastLength() { if (length) return; @@ -838,6 +905,7 @@ void cMarkAdStandalone::CheckBroadcastLength() isyslog("got broadcast length of %im from index",length/60); reprocess=true; } +#endif bool cMarkAdStandalone::CheckIndexGrowing() { @@ -950,12 +1018,12 @@ bool cMarkAdStandalone::ProcessFile2ndPass(clMark **Mark1, clMark **Mark2,int Nu if (Mark1 && Mark2) { if (!(*Mark1) || !(*Mark2)) return false; - if (*Mark1==*Mark2) pn=1; - if (*Mark1!=*Mark2) pn=3; + if (*Mark1==*Mark2) pn=mSTART; + if (*Mark1!=*Mark2) pn=mAFTER; } else { - pn=2; + pn=mBEFORE; } if (!Reset(false)) @@ -992,13 +1060,13 @@ bool cMarkAdStandalone::ProcessFile2ndPass(clMark **Mark1, clMark **Mark2,int Nu if (f==-1) return false; int dataread; - if (pn==1) + if (pn==mSTART) { dsyslog("processing file %05i (start mark)",Number); } else { - dsyslog("processing file %05i %s",Number,(pn==3) ? "(after mark)" : "(before mark)"); + dsyslog("processing file %05i %s",Number,(pn==mAFTER) ? "(after mark)" : "(before mark)"); } if (lseek(f,Offset,SEEK_SET)!=Offset) @@ -1007,32 +1075,30 @@ bool cMarkAdStandalone::ProcessFile2ndPass(clMark **Mark1, clMark **Mark2,int Nu return false; } - uint64_t offset=Offset; - int offset_add=0; while ((dataread=read(f,data,datalen))>0) { if (abort) break; - if ((video_demux) && (video) && (decoder) && (streaminfo)) + if ((demux) && (video) && (decoder) && (streaminfo)) { uchar *tspkt = data; int tslen = dataread; while (tslen>0) { - int len=video_demux->Process(macontext.Info.VPid,tspkt,tslen,&vpkt); + int len=demux->Process(tspkt,tslen,&pkt); if (len<0) { - esyslog("error demuxing video"); + esyslog("error demuxing file"); abort=true; break; } else { - if (vpkt.Data) + if ((pkt.Data) && ((pkt.Type & PACKET_MASK)==PACKET_VIDEO)) { bool dRes=false; - if (streaminfo->FindVideoInfos(&macontext,vpkt.Data,vpkt.Length)) + if (streaminfo->FindVideoInfos(&macontext,pkt.Data,pkt.Length)) { actframe++; framecnt2++; @@ -1051,16 +1117,16 @@ bool cMarkAdStandalone::ProcessFile2ndPass(clMark **Mark1, clMark **Mark2,int Nu dRes=true; } } - if (pn>1) dRes=decoder->DecodeVideo(&macontext,vpkt.Data,vpkt.Length); + if (pn>mSTART) dRes=decoder->DecodeVideo(&macontext,pkt.Data,pkt.Length); if (dRes) { if ((actframe-iframe)<=3) { - if (pn>1) pos=video->Process2ndPass(lastiframe,Frames,(pn==2)); + if (pn>mSTART) pos=video->Process2ndPass(lastiframe,Frames,(pn==mBEFORE)); //SaveFrame(lastiframe); framecounter++; } - if ((pos) && (pn==3)) + if ((pos) && (pn==mAFTER)) { // found overlap ChangeMarks(Mark1,Mark2,pos); @@ -1071,54 +1137,10 @@ bool cMarkAdStandalone::ProcessFile2ndPass(clMark **Mark1, clMark **Mark2,int Nu } tspkt+=len; tslen-=len; - if (!vpkt.Offcnt) - { - offset_add+=len; - } - else - { - offset+=offset_add; - offset+=len; - offset_add=0; - } } } } -#if 0 - if ((mp2_demux) && (audio) && (pn!=3)) - { - uchar *tspkt = data; - int tslen = dataread; - - while (tslen>0) - { - int len=mp2_demux->Process(macontext.Info.APid,tspkt,tslen,&apkt); - if (len<0) - { - esyslog("error demuxing mp2-audio"); - break; - } - else - { - if (apkt.Data) - { - if (apkt.Timestamp) audiotime=apkt.Timestamp; - if (abs(audiotime-lastiframetime)<DELTATIME) - { - if (decoder->DecodeMP2(&macontext,apkt.Data,apkt.length)) - { - pos=audio->Process2ndPass(iframe); - if (pos) ChangeMarks(Mark1,NULL,pos); - } - } - } - tspkt+=len; - tslen-=len; - } - } - } -#endif if (abort) { close(f); @@ -1161,24 +1183,7 @@ void cMarkAdStandalone::Process2ndPass() bool infoheader=false; clMark *p1=NULL,*p2=NULL; -#if 0 - p1=marks.GetFirst(); - if (!p1) return; - if (p1->position>0) - { - isyslog("2nd pass"); - infoheader=true; - off_t offset; - int number,frame,iframes; - int frange=macontext.Video.Info.FramesPerSecond*120; - - if (marks.ReadIndex(directory,isTS,p1->position-(frange/10),frange,&number,&offset,&frame,&iframes)) - { - ProcessFile2ndPass(&p1,&p1,number,offset,frame,iframes); - } - } -#endif - if (marks.Count()<4) return; // here we cannot do much + if (marks.Count()<4) return; // we cannot do much without marks p1=marks.GetFirst(); if (!p1) return; @@ -1232,7 +1237,7 @@ bool cMarkAdStandalone::ProcessFile(int Number) if (!directory) return false; if (!Number) return false; - if (!CheckIndexGrowing()) CheckBroadcastLength(); + CheckIndexGrowing(); if (abort) return false; @@ -1256,159 +1261,121 @@ bool cMarkAdStandalone::ProcessFile(int Number) int dataread; dsyslog("processing file %05i",Number); - uint64_t offset=0; - int offset_add=0; + demux->NewFile(); while ((dataread=read(f,data,datalen))>0) { if (abort) break; - - if ((video_demux) && (video) && (streaminfo)) + if ((demux) && (video) && (streaminfo)) { uchar *tspkt = data; int tslen = dataread; - while (tslen>0) { - int len=video_demux->Process(macontext.Info.VPid,tspkt,tslen,&vpkt); + int len=demux->Process(tspkt,tslen,&pkt); if (len<0) { - esyslog("error demuxing video"); + esyslog("error demuxing"); abort=true; break; } else { - if (vpkt.Data) + if (pkt.Data) { - if ((macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264) && (!noticeFILLER)) + if ((pkt.Type & PACKET_MASK)==PACKET_VIDEO) { - if ((vpkt.Data[4] & 0x1F)==0x0C) + bool dRes=false; + if (streaminfo->FindVideoInfos(&macontext,pkt.Data,pkt.Length)) { - isyslog("H264 video stream with filler nalu"); - noticeFILLER=true; - } - } + if ((macontext.Video.Info.Height) && (!noticeHEADER)) + { + isyslog("%s %ix%i%c%0.f",(macontext.Video.Info.Height>576) ? "HDTV" : "SDTV", + macontext.Video.Info.Width, + macontext.Video.Info.Height, + macontext.Video.Info.Interlaced ? 'i' : 'p', + macontext.Video.Info.FramesPerSecond); + noticeHEADER=true; + } - bool dRes=false; - if (streaminfo->FindVideoInfos(&macontext,vpkt.Data,vpkt.Length)) - { - if ((macontext.Video.Info.Height) && (!noticeHEADER)) - { - isyslog("%s %ix%i%c%0.f",(macontext.Video.Info.Height>576) ? "HDTV" : "SDTV", - macontext.Video.Info.Width, - macontext.Video.Info.Height, - macontext.Video.Info.Interlaced ? 'i' : 'p', - macontext.Video.Info.FramesPerSecond); - noticeHEADER=true; - } + if (!framecnt) + { + AddStartMark(); + } + if (macontext.Config->GenIndex) + { + marks.WriteIndex(directory,isTS,demux->Offset(),macontext.Video.Info.Pict_Type,Number); + } + framecnt++; - if (!framecnt) - { - AddStartMark(); + if (macontext.Video.Info.Pict_Type==MA_I_TYPE) + { + lastiframe=iframe; +#if 0 + CheckStartStop(lastiframe); + if (lastiframe>chkLEFT) CheckAspectRatio_and_AudioChannels(); +#endif + iframe=framecnt-1; + dRes=true; + } } - - if (macontext.Config->GenIndex) + if (macontext.Video.Info.FramesPerSecond<0) { - marks.WriteIndex(directory,isTS,offset,macontext.Video.Info.Pict_Type,Number); + macontext.Video.Info.FramesPerSecond*=-1; + isyslog("using framerate of %.f",macontext.Video.Info.FramesPerSecond); } - framecnt++; - if (macontext.Video.Info.Pict_Type==MA_I_TYPE) + if ((decoder) && (bDecodeVideo)) + dRes=decoder->DecodeVideo(&macontext,pkt.Data,pkt.Length); + if (dRes) { - lastiframe=iframe; - CheckStartStop(lastiframe); - if (lastiframe>chkLEFT) CheckAspectRatio_and_AudioChannels(); - iframe=framecnt-1; - dRes=true; + if ((framecnt-iframe)<=3) + { + MarkAdMarks *vmarks=video->Process(lastiframe,iframe); + if (vmarks) + { + for (int i=0; i<vmarks->Count; i++) + { + AddMark(&vmarks->Number[i]); + } + } + SaveFrame(lastiframe); // TODO: JUST FOR DEBUGGING! + } } } - if (macontext.Video.Info.FramesPerSecond<0) - { - macontext.Video.Info.FramesPerSecond*=-1; - isyslog("using framerate of %.f",macontext.Video.Info.FramesPerSecond); - } - if ((decoder) && (bDecodeVideo)) - dRes=decoder->DecodeVideo(&macontext,vpkt.Data,vpkt.Length); - if (dRes) + if ((pkt.Type & PACKET_MASK)==PACKET_AC3) { - if ((framecnt-iframe)<=3) + if (streaminfo->FindAC3AudioInfos(&macontext,pkt.Data,pkt.Length)) { - MarkAdMarks *vmarks; - vmarks=video->Process(lastiframe,iframe); - if (vmarks) + if ((!isTS) && (!noticeVDR_AC3)) { - for (int i=0; i<vmarks->Count; i++) + isyslog("found AC3%s",macontext.Config->AC3Always ? "*" : ""); + noticeVDR_AC3=true; + } + if ((framecnt-iframe)<=3) + { + MarkAdMark *amark=audio->Process(lastiframe,iframe); + if (amark) { - AddMark(&vmarks->Number[i]); + AddMark(amark); } } - //SaveFrame(lastiframe); // TODO: JUST FOR DEBUGGING! } } } - if (vpkt.Skipped) - { - errcnt+=vpkt.Skipped; - } - tspkt+=len; - tslen-=len; - if (!vpkt.Offcnt) - { - offset_add+=len; - } - else - { - offset+=offset_add; - offset+=len; - offset_add=0; - } - } - } - } - if ((ac3_demux) && (streaminfo) && (audio)) - { - uchar *tspkt = data; - int tslen = dataread; - - while (tslen>0) - { - int len=ac3_demux->Process(macontext.Info.DPid,tspkt,tslen,&apkt); - if (len<0) - { - esyslog("error demuxing ac3-audio"); - break; - } - else - { - if (apkt.Data) - { - if (streaminfo->FindAC3AudioInfos(&macontext,apkt.Data,apkt.Length)) - { - if ((!isTS) && (!noticeVDR_AC3)) - { - isyslog("found AC3%s",macontext.Config->AC3Always ? "*" : ""); - noticeVDR_AC3=true; - } - MarkAdMark *amark; - amark=audio->Process(lastiframe,iframe); - if (amark) AddMark(amark); - } - } tspkt+=len; tslen-=len; } } } - if (((gotendmark) && (!macontext.Config->GenIndex)) || (reprocess)) { if (f!=-1) close(f); return true; } - if (!CheckIndexGrowing()) CheckBroadcastLength(); + CheckIndexGrowing(); if (abort) { if (f!=-1) close(f); @@ -1429,8 +1396,7 @@ bool cMarkAdStandalone::Reset(bool FirstPass) gotendmark=false; - memset(&vpkt,0,sizeof(vpkt)); - memset(&apkt,0,sizeof(apkt)); + memset(&pkt,0,sizeof(pkt)); iStart=iStartCheck=iStop=iStopCheck=0; chkLEFT=INT_MAX; @@ -1453,9 +1419,7 @@ bool cMarkAdStandalone::Reset(bool FirstPass) ret=decoder->Clear(); } if (streaminfo) streaminfo->Clear(); - if (video_demux) video_demux->Clear(); - if (ac3_demux) ac3_demux->Clear(); - if (mp2_demux) mp2_demux->Clear(); + if (demux) demux->Clear(); if (video) video->Clear(); if (audio) audio->Clear(); return ret; @@ -1480,8 +1444,9 @@ void cMarkAdStandalone::ProcessFile() { if (lastiframe) { +#if 0 CheckStartStop(lastiframe,true); - +#endif if ((!gotendmark) && ((iStop<0) || (!tStart))) { char *buf; @@ -1497,10 +1462,12 @@ void cMarkAdStandalone::ProcessFile() } } } - +#if 0 CheckLastMark(); CheckLogoMarks(); +#endif } + skipped=demux->Skipped(); } void cMarkAdStandalone::Process() @@ -1559,7 +1526,7 @@ void cMarkAdStandalone::Process() } } } - SaveInfo(); + //SaveInfo(); } else { @@ -1671,7 +1638,6 @@ bool cMarkAdStandalone::SaveInfo() { if (fprintf(w,"X %i %02i %s 4:3 LetterBox\n",stream_content, component_type_43+component_type_add,lang)<=0) err=true; - setVideo43_done=true; setVideo43LB_done=true; } if (setVideo169) @@ -1899,6 +1865,7 @@ bool cMarkAdStandalone::LoadInfo() startTime=0; length=0; } + dsyslog("startTime=%s",ctime(&startTime)); } if (line[0]=='T') { @@ -1967,19 +1934,14 @@ bool cMarkAdStandalone::LoadInfo() macontext.Info.Channels=2; } } - else - // if we have DolbyDigital 5.1 disable video decoding - if (strchr(descr,'5')) - { - bDecodeVideo=false; - macontext.Info.Channels=6; - macontext.Video.Options.IgnoreAspectRatio=true; - isyslog("broadcast with DolbyDigital5.1, disabling video decoding"); - } - else - { - setAudio20=true; - } + // if we have DolbyDigital 5.1 disable video decoding + if (strchr(descr,'5')) + { + bDecodeVideo=false; + macontext.Info.Channels=6; + macontext.Video.Options.IgnoreAspectRatio=true; + isyslog("broadcast with DolbyDigital5.1, disabling video decoding"); + } } } } @@ -2342,16 +2304,13 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, const MarkAdConfig * indexFile=NULL; streaminfo=NULL; - video_demux=NULL; - ac3_demux=NULL; - mp2_demux=NULL; + demux=NULL; decoder=NULL; video=NULL; audio=NULL; osd=NULL; - memset(&vpkt,0,sizeof(vpkt)); - memset(&apkt,0,sizeof(apkt)); + memset(&pkt,0,sizeof(pkt)); setAudio51=false; setAudio20=false; @@ -2365,7 +2324,7 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, const MarkAdConfig * noticeHEADER=false; noticeFILLER=false; - errcnt=0; + skipped=0; sleepcnt=0; waittime=iwaittime=0; @@ -2479,6 +2438,7 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, const MarkAdConfig * } if (asprintf(&indexFile,"%s/index.vdr",Directory)==-1) indexFile=NULL; } + macontext.Info.APid.Num=0; // till now we do just nothing with stereo-sound if (!LoadInfo()) { @@ -2519,42 +2479,33 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, const MarkAdConfig * { if (isTS) { - dsyslog("using %s-video (0x%04x)", + dsyslog("found %s-video (0x%04x)", macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264 ? "H264": "H262", macontext.Info.VPid.Num); } else { - dsyslog("using %s-video", + dsyslog("found %s-video", macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264 ? "H264": "H262"); } - video_demux = new cMarkAdDemux(); + demux=new cDemux(macontext.Info.VPid.Num,macontext.Info.DPid.Num,macontext.Info.APid.Num, + macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264,true); } else { - video_demux=NULL; + 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; + dsyslog("found MP2 (0x%04x)",macontext.Info.APid.Num); } if (macontext.Info.DPid.Num) { if (macontext.Info.DPid.Num!=-1) - dsyslog("using AC3 (0x%04x)%s",macontext.Info.DPid.Num,macontext.Config->AC3Always ? "*" : ""); - ac3_demux = new cMarkAdDemux(); - } - else - { - ac3_demux=NULL; + dsyslog("found AC3 (0x%04x)%s",macontext.Info.DPid.Num,macontext.Config->AC3Always ? "*" : ""); } if (!abort) @@ -2581,9 +2532,9 @@ cMarkAdStandalone::~cMarkAdStandalone() { if ((!abort) && (!duplicate)) { - if (errcnt>20) + if (skipped) { - isyslog("skipped %i bytes in video stream",errcnt); + isyslog("skipped %i bytes",skipped); } gettimeofday(&tv2,&tz); @@ -2620,9 +2571,7 @@ cMarkAdStandalone::~cMarkAdStandalone() if (macontext.Info.ChannelName) free(macontext.Info.ChannelName); if (indexFile) free(indexFile); - if (video_demux) delete video_demux; - if (ac3_demux) delete ac3_demux; - if (mp2_demux) delete mp2_demux; + if (demux) delete demux; if (decoder) delete decoder; if (video) delete video; if (audio) delete audio; @@ -3328,7 +3277,7 @@ int main(int argc, char *argv[]) if (!cmasta) return -1; if (!bPass2Only) cmasta->Process(); - if (!bPass1Only) cmasta->Process2ndPass(); + //if (!bPass1Only) cmasta->Process2ndPass(); delete cmasta; return 0; } diff --git a/command/markad-standalone.h b/command/markad-standalone.h index 78f0ea9..6f7797d 100644 --- a/command/markad-standalone.h +++ b/command/markad-standalone.h @@ -26,7 +26,6 @@ #define MAXRANGE 420 /* range to search for start/stop marks in seconds */ - class cOSDMessage { private: @@ -156,19 +155,19 @@ unsigned Descriptor_Length: 8; }; + enum { mSTART=0x1, mBEFORE, mAFTER }; + static const char frametypes[8]; const char *directory; - cMarkAdDemux *video_demux; - cMarkAdDemux *ac3_demux; - cMarkAdDemux *mp2_demux; + cDemux *demux; cMarkAdDecoder *decoder; cMarkAdVideo *video; cMarkAdAudio *audio; cMarkAdStreamInfo *streaminfo; cOSDMessage *osd; - MarkAdPacket vpkt,apkt; + AvPacket pkt; MarkAdContext macontext; @@ -214,7 +213,7 @@ unsigned Descriptor_Length: int iStop; // posttimer as index value int iStopCheck; // check position for iStop - int errcnt; // Skipped bytes in stream + int skipped; // Skipped bytes in whole file bool setAudio51; // set audio to 5.1 in info bool setAudio20; // set audio to 2.0 in info diff --git a/command/marks.cpp b/command/marks.cpp index 130ff42..f06416d 100644 --- a/command/marks.cpp +++ b/command/marks.cpp @@ -485,7 +485,6 @@ void clMarks::WriteIndex(const char *Directory, bool isTS, uint64_t Offset, indexfd=open(ipath,O_WRONLY|O_CREAT|O_TRUNC,0644); free(ipath); if (indexfd==-1) return; - if (Offset>376) WriteIndex(isTS,0,1,Number); } WriteIndex(isTS,Offset,FrameType,Number); return; diff --git a/command/pes2es.cpp b/command/pes2es.cpp deleted file mode 100644 index c78afd6..0000000 --- a/command/pes2es.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * pes2es.cpp: A program for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - */ - -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> - -#include "pes2es.h" -#include <stdio.h> -cMarkAdPES2ES::cMarkAdPES2ES(const char *QueueName, int QueueSize) -{ - queue = new cMarkAdPaketQueue(QueueName,QueueSize); - type=0; -} - -cMarkAdPES2ES::~cMarkAdPES2ES() -{ - if (queue) delete queue; -} - -void cMarkAdPES2ES::Clear() -{ - if (queue) queue->Clear(); -} - -void cMarkAdPES2ES::Process(MarkAdPid Pid, uchar *PESData, int PESSize, MarkAdPacket *ESPkt) -{ - if (!ESPkt) return; - - if (PESData) - { - struct PESHDR *peshdr=(struct PESHDR *) PESData; - - // first check some simple things - if ((peshdr->Sync1!=0) && (peshdr->Sync2!=0) && (peshdr->Sync3!=1)) - { - Clear(); - return; - } - - if (peshdr->StreamID<=0xBC) return; - - int Length=(peshdr->LenH<<8)+peshdr->LenL; - if (Length) Length+=sizeof(PESHDR); - if (Length!=PESSize) - { - if ((peshdr->StreamID & 0xF0)==0xE0) return; - Clear(); - return; - } - - switch (Pid.Type) - { - case MARKAD_PIDTYPE_VIDEO_H262: - if ((peshdr->StreamID & 0xF0)!=0xE0) return; - type=MA_PACKET_PKT; - break; - case MARKAD_PIDTYPE_VIDEO_H264: - if ((peshdr->StreamID & 0xF0)!=0xE0) return; - type=MA_PACKET_H264; - break; - case MARKAD_PIDTYPE_AUDIO_AC3: - if (peshdr->StreamID!=0xBD) return; - type=MA_PACKET_AC3; - break; - case MARKAD_PIDTYPE_AUDIO_MP2: - if ((peshdr->StreamID<0xC0) || (peshdr->StreamID>0xDF)) return; - type=MA_PACKET_MP2; - break; - default: - Clear(); - return; - } - - struct PESHDROPT *peshdropt=(struct PESHDROPT *) &PESData[sizeof(struct PESHDR)]; - - uchar *buf; - int buflen; - - if (peshdropt->MarkerBits==0x2) - { - // we have an optional PES header - int bpos=sizeof(struct PESHDR)+sizeof(struct PESHDROPT)+ - peshdropt->Length; - buf=&PESData[bpos]; - buflen=PESSize-bpos; - } - else - { - int bpos=sizeof(struct PESHDR); - buf=&PESData[bpos]; - buflen=PESSize-bpos; - } - queue->Put(buf,buflen); - } - if (type) ESPkt->Data=queue->GetPacket(&ESPkt->Length,type); - return; -} diff --git a/command/pes2es.h b/command/pes2es.h deleted file mode 100644 index bfeaaaa..0000000 --- a/command/pes2es.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * pes2es.h: A program for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - */ - -#ifndef __pes2es_h_ -#define __pes2es_h_ - -#ifndef uchar -typedef unsigned char uchar; -#endif - -#include "global.h" -#include "queue.h" - -struct PESHDR -{ - uchar Sync1; - uchar Sync2; - uchar Sync3; - uchar StreamID; - uchar LenH; - uchar LenL; -}; - -#pragma pack(1) -struct PESHDROPT -{ -unsigned OOC: - 1; -unsigned CY: - 1; -unsigned DAI: - 1; -unsigned PESP: - 1; -unsigned PESSC: - 2; -unsigned MarkerBits: - 2; -unsigned EXT: - 1; -unsigned CRC: - 1; -unsigned ACI: - 1; -unsigned TM: - 1; -unsigned RATE: - 1; -unsigned ESCR: - 1; -unsigned PTSDTS: - 2; -unsigned Length: - 8; -}; - -struct PESHDROPTPTS -{ -unsigned Marker1: - 1; -unsigned PTS32_30: - 3; -unsigned Fixed: - 4; -unsigned PTS29_15_H: - 8; -unsigned Marker2: - 1; -unsigned PTS29_15_L: - 7; -unsigned PTS14_0_H: - 8; -unsigned Marker3: - 1; -unsigned PTS14_0_L: - 7; -}; -#pragma pack() - -class cMarkAdPES2ES -{ -private: - cMarkAdPaketQueue *queue; - int type; -public: - cMarkAdPES2ES(const char *QueueName="PES2ES", int QueueSize=32768); - ~cMarkAdPES2ES(); - void Clear(); - void Process(MarkAdPid Pid, uchar *PESData, int PESSize, MarkAdPacket *ESPkt); -}; - -#endif diff --git a/command/queue.cpp b/command/queue.cpp deleted file mode 100644 index 65188e4..0000000 --- a/command/queue.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* - * queue.cpp: A program for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - */ - -#include <stdlib.h> -#include <string.h> - -extern "C" -{ -#include "debug.h" -} - -#include "queue.h" - -cMarkAdPaketQueue::cMarkAdPaketQueue(const char *Name, int Size) -{ - inptr=0; - outptr=0; - memset(&pktinfo,0,sizeof(pktinfo)); - pktinfo.pkthdr=-1; - maxqueue=Size; - if (Name) - { - name=strdup(Name); - } - else - { - name=NULL; - } - buffer=(uchar *) malloc(Size+1); - if (!buffer) maxqueue=0; - scanner=0xFFFFFFFF; - scannerstart=-1; - percent=-1; - mpercent=0; -} - -cMarkAdPaketQueue::~cMarkAdPaketQueue() -{ - if (name) - { - tsyslog("buffer usage: %-15s %3i%%",name,mpercent); - free(name); - } - if (buffer) free(buffer); -} - -bool cMarkAdPaketQueue::Inject(uchar *Data, int Size) -{ - if (!buffer) return false; - isyslog("inject was called, please report this"); - - if (outptr>Size) - { - uchar *temp=(uchar *) alloca(Size+1); - if (!temp) return false; - memcpy(temp,Data,Size); - outptr-=Size; - memcpy(&buffer[outptr],temp,Size); - pktinfo.pkthdr=-1; - } - else - { - int oldSize=Length(); - uchar *tempold=(uchar *) alloca(oldSize+1); - if (!tempold) return false; - uchar *temp=(uchar *) alloca(Size+1); - if (!temp) return false; - - memcpy(tempold,&buffer[outptr],oldSize); - memcpy(temp,Data,Size); - memcpy(buffer,temp,Size); - memcpy(buffer+Size,tempold,oldSize); - - inptr=Size+oldSize; - outptr=0; - pktinfo.pkthdr=-1; - } - return true; -} - -bool cMarkAdPaketQueue::Put(uchar *Data, int Size) -{ - if (!buffer) return false; - if ((inptr) && (inptr==outptr)) inptr=outptr=0; - - if ((inptr+Size)>maxqueue) - { - if (name) - { - esyslog("buffer %s full",name); - } - else - { - esyslog("buffer full"); - } - mpercent=100; - Clear(); - return false; - } - - memcpy(&buffer[inptr],Data,Size); - inptr+=Size; - - int npercent=(int) ((inptr*100)/maxqueue); - if (npercent>mpercent) mpercent=npercent; - - if ((npercent>90) && (name) && (npercent!=percent)) - { - dsyslog("buffer %s usage: %3i%%", - name,npercent); - percent=npercent; - } - - return true; -} - -uchar *cMarkAdPaketQueue::Get(int *Size) -{ - if (!buffer) return NULL; - if (!Size) return NULL; - if (Length()<*Size) - { - *Size=0; - return NULL; - } - uchar *ret=&buffer[outptr]; - outptr+=*Size; - return ret; -} - -uchar *cMarkAdPaketQueue::Peek(int Size) -{ - if (!buffer) return NULL; - if (!Size) return NULL; - if (Length()<Size) return NULL; - uchar *ret=&buffer[outptr]; - return ret; -} - -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; - *StreamSize=0; - if (LongStartCode) - { - *HeaderSize=4; // 0x0 0x0 0x0 0x1 - } - else - { - *HeaderSize=3; // 0x0 0x0 0x1 - } - int i; - - if (scanner!=0xFFFFFFFF) - { - scanner<<=8; - scanner|=buffer[Start++]; - } - - bool found=false; - for (i=Start; i<inptr; i++) - { - if (LongStartCode) - { - if (scanner==1L) - { - found=true; - break; - } - if ((scanner & 0xFFFFFFF0)==0x1E0L) - { - found=true; - break; - } - } - else - { - if ((scanner & 0x00FFFFFF)==1L) - { - found=true; - break; - } - } - scanner<<=8; - scanner|=buffer[i]; - } - if (!found) - { - if (LongStartCode) - { - if (scanner==1L) - { - found=true; - } - if ((scanner & 0xFFFFFFF0)==0x1E0L) - { - found=true; - } - } - else - { - if ((scanner & 0x00FFFFFF)==1L) - { - found=true; - } - } - } - - if (i==inptr) - { - if (found) - { - if (!Start) - { - scanner=0xFFFFFFFF; - return -1; - } - } - else - { - return -1; - } - } - if (LongStartCode) i--; - if ((buffer[i]>=0xBC) && (!Start)) // do we have a PES packet? - { -#define PESHDRSIZE 6 - if ((i+PESHDRSIZE)>inptr) - { - return -1; // we need more data (for streamsize and headersize) - } - - *StreamSize=(buffer[i+1]<<8)+buffer[i+2]; - if (*StreamSize) (*StreamSize)+=PESHDRSIZE; // 6 Byte PES-Header - if (LongStartCode) - { - 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; - (*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++) - { - - if (AC3) - { - if ((scanner & 0x0000FFFF)==0xB77L) break; - } - else - { - if ((scanner & 0x00000FFE)==0xFFEL) break; - } - - scanner<<=8; - scanner|=buffer[i]; - } - if (i==inptr) return -1; - if (AC3) i-=2; - - if (AC3) - { - struct AC3HDR *ac3hdr = (struct AC3HDR *) &buffer[i]; - - if (ac3hdr->SampleRateIndex==3) return -1; // reserved - if (ac3hdr->FrameSizeIndex>=38) return -1; // reserved - - if (FrameSize) - { - int bitRatesAC3[3][38] = // all values are specified as kbits/s - { - { 64, 64, 80, 80, 96, 96, 112, 112, 128, 128, 160, 160, 192, 192, - 224, 224, 256, 256, 320, 320, 384, 384, 448, 448, 512, 512, - 640, 640, 768, 768, 896, 896, 1024, 1024, 1152, 1152, 1280, 1280 }, // 48kHz - - { 69, 70, 87, 88, 104, 105, 121, 122, 139, 140, 174, 175, 208, 209, - 243, 244, 278, 279, 348, 349, 417, 418, 487, 488, 557, 558, - 696, 697, 835, 836, 975, 976, 1114, 1115, 1253, 1254, 1393, 1394 }, // 44.1kHz - - { 96, 96, 120, 120, 144, 144, 168, 168, 192, 192, 240, 240, 288, - 288, 336, 336, 384, 384, 480, 480, 576, 576, 672, 672, 768, - 768, 960, 960, 1152, 1152, 1344, 1344, 1536, 1536, 1728, 1728, 1920,1920 } // 32kHz - }; - - *FrameSize=2*bitRatesAC3[ac3hdr->SampleRateIndex][ac3hdr->FrameSizeIndex]; - } - return i; - } - else - { - struct MP2HDR *mp2hdr = (struct MP2HDR *) &buffer[i]; - if (mp2hdr->MpegID==1) return -1; // reserved - if (mp2hdr->Layer==0) return -1; // reserved - if (mp2hdr->BitRateIndex==0xF) return -1; // forbidden - if (mp2hdr->SampleRateIndex==3) return -1; //reserved - if (mp2hdr->Emphasis==2) return -1; // reserved - - if (FrameSize) - { - int bitRates[3][3][16] = // all values are specified as kbits/s - { - { - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, // M1, L1 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, // M1, L2 - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 } // M1, L3 - }, - { - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, // M2, L1 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, // M2, L2 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 } // M2, L3 - }, - { - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, // M2.5, L1 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, // M2.5, L2 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 } // M2.5, L3 - } - }; - - int samplingFrequencies[3][4] = // all values are specified in Hz - { - { 44100, 48000, 32000, -1 }, // MPEG 1 - { 22050, 24000, 16000, -1 }, // MPEG 2 - { 32000, 16000, 8000, -1 } // MPEG 2.5 - }; - - - int slots_per_frame[3][3] = - { - { 12, 144, 144 }, // MPEG 1, Layer I, II, III - { 12, 144, 72 }, // MPEG 2, Layer I, II, III - { 12, 144, 72 } // MPEG 2.5, Layer I, II, III - }; - - int mpegIndex; - switch (mp2hdr->MpegID) - { - case 0: - mpegIndex=2; - break; - case 2: - mpegIndex=1; - break; - case 3: - mpegIndex=0; - break; - default: - mpegIndex=0; // just to get rid of compiler warnings ;) - } - int layerIndex = 3 - mp2hdr->Layer; - - // Layer I (i. e., layerIndex == 0) has a larger slot size - int slotSize = (layerIndex == 0) ? 4 : 1; // bytes - int sf = samplingFrequencies[mpegIndex][mp2hdr->SampleRateIndex]; - - if (mp2hdr->BitRateIndex == 0) - *FrameSize = 0; // "free" Bitrate -> we don't support this! - else - { - int br = 1000 * bitRates[mpegIndex][layerIndex][mp2hdr->BitRateIndex]; // bits/s - int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots - - *FrameSize = (N + mp2hdr->Padding) * slotSize; // bytes - } - } - return i; - } -} - -uchar *cMarkAdPaketQueue::GetPacket(int *Size, int Type) -{ - if (!Size) return NULL; - *Size=0; - if (Length()<4) return NULL; - - if (pktinfo.pkthdr==-1) - { - scanner=0xFFFFFFFF; - switch (Type) - { - case MA_PACKET_AC3: - pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,true); - break; - case MA_PACKET_MP2: - pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,false); - break; - case MA_PACKET_H264: - pktinfo.pkthdr=FindPktHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,true); - break; - default: - pktinfo.pkthdr=FindPktHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,false); - break; - } - - if (pktinfo.pkthdr==-1) - { - return NULL; - } - scannerstart=pktinfo.pkthdr+pktinfo.pktsyncsize; - } - - int streamsize,pktsyncsize,pkthdr=-1; - - if (pktinfo.streamsize) - { - if ((pktinfo.pkthdr+pktinfo.streamsize)>inptr) - { - return NULL; // need more data - } - else - { - scannerstart=pktinfo.pkthdr+pktinfo.streamsize; - scanner=0xFFFFFFFF; - } - } - - switch (Type) - { - case MA_PACKET_AC3: - pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize,true); - break; - case MA_PACKET_MP2: - pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize,false); - break; - case MA_PACKET_H264: - pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize,true); - break; - default: - pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize,false); - break; - } - - if (pkthdr==-1) - { - scannerstart=inptr; - return NULL; - } - scannerstart=pkthdr+pktsyncsize; - - uchar *ptr=&buffer[pktinfo.pkthdr]; - - if (pktinfo.streamsize) - { - *Size=pktinfo.streamsize; - } - else - { - *Size=pkthdr-pktinfo.pkthdr; - } - outptr=pkthdr; - - int bytesleft=inptr-outptr; - if (pktinfo.pkthdr>(4096+bytesleft)) - { - memcpy(buffer,&buffer[pkthdr],bytesleft); - scannerstart-=outptr; - inptr=bytesleft; - outptr=0; - pkthdr=0; - } - - pktinfo.pkthdr=pkthdr; - pktinfo.streamsize=streamsize; - pktinfo.pktsyncsize=pktsyncsize; - - return ptr; -} diff --git a/command/queue.h b/command/queue.h deleted file mode 100644 index 4efd197..0000000 --- a/command/queue.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * queue.h: A program for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - */ - -#ifndef __queue_h_ -#define __queue_h_ - -#include <stdint.h> - -#ifndef uchar -typedef unsigned char uchar; -#endif - -typedef struct MarkAdPacket -{ - uchar *Data; - int Length; - int Skipped; - bool Offcnt; -} MarkAdPacket; - -class cMarkAdPaketQueue -{ - struct MP2HDR - { -unsigned Sync1: - 8; -unsigned Protection: - 1; -unsigned Layer: - 2; -unsigned MpegID: - 2; -unsigned Sync2: - 3; -unsigned Private: - 1; -unsigned Padding: - 1; -unsigned SampleRateIndex: - 2; -unsigned BitRateIndex: - 4; -unsigned Emphasis: - 2; -unsigned Original: - 1; -unsigned Copyright: - 1; -unsigned ModeExt: - 2; -unsigned Mode: - 2; - }; - -#pragma pack(1) - struct AC3HDR - { -unsigned Sync1: - 8; -unsigned Sync2: - 8; -unsigned CRC1: - 8; -unsigned CRC2: - 8; -unsigned FrameSizeIndex: - 6; -unsigned SampleRateIndex: - 2; - }; -#pragma pack() - -#pragma pack(1) - struct PESHDROPT - { -unsigned OOC: - 1; -unsigned CY: - 1; -unsigned DAI: - 1; -unsigned PESP: - 1; -unsigned PESSC: - 2; -unsigned MarkerBits: - 2; -unsigned EXT: - 1; -unsigned CRC: - 1; -unsigned ACI: - 1; -unsigned TM: - 1; -unsigned RATE: - 1; -unsigned ESCR: - 1; -unsigned TSF: - 2; -unsigned Length: - 8; - }; -#pragma pack() - -private: - char *name; - struct pktinfo - { - int pkthdr; - int pktsyncsize; - int streamsize; - bool ispes; - } pktinfo; - - int percent; - int mpercent; // max percentage use - - uchar *buffer; - int maxqueue; - int inptr; - int outptr; - - uint32_t 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(const char *Name, int Size=32768); - ~cMarkAdPaketQueue(); - int Length() - { - return inptr-outptr; - } - void Clear() - { - 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); - uchar *Peek(int Size); - -#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); -}; - -#endif diff --git a/command/ts2pkt.cpp b/command/ts2pkt.cpp deleted file mode 100644 index c3bbd15..0000000 --- a/command/ts2pkt.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * ts2pkt.cpp: A program for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - */ - -#include <stdlib.h> -#include <string.h> - -extern "C" -{ -#include "debug.h" -} - -#include "ts2pkt.h" - -cMarkAdTS2Pkt::cMarkAdTS2Pkt(const char *QueueName, int QueueSize) -{ - queue=new cMarkAdPaketQueue(QueueName,QueueSize); - Reset(); -} - -cMarkAdTS2Pkt::~cMarkAdTS2Pkt() -{ - if (queue) delete queue; -} - -void cMarkAdTS2Pkt::Clear() -{ - Reset(); -} - -bool cMarkAdTS2Pkt::Reset(int ErrIndex) -{ - sync=false; - switch (ErrIndex) - { - case MA_ERR_TSSIZE: - dsyslog("inbuf not 188 bytes"); - break; - case MA_ERR_NOSYNC: - dsyslog("found no sync"); - break; - case MA_ERR_SEQ: - dsyslog("sequence error"); - break; - case MA_ERR_AFC: - dsyslog("wrong AFC value"); - break; - case MA_ERR_TOBIG: - dsyslog("buflen > 188 bytes"); - break; - case MA_ERR_NEG: - dsyslog("buflen negative"); - break; - } - counter=-1; - if (queue) queue->Clear(); - return false; -} - -bool cMarkAdTS2Pkt::InjectVideoPES(uchar *PESData, int PESSize) -{ - if ((!PESData) || (!PESSize)) return false; - - struct PESHDR *peshdr=(struct PESHDR *) PESData; - - // first check some simple things - if ((peshdr->Sync1!=0) && (peshdr->Sync2!=0) && (peshdr->Sync3!=1)) return false; - if ((peshdr->StreamID & 0xF0)!=0xE0) return false; - - int Length=(peshdr->LenH<<8)+peshdr->LenL; - if (Length) Length+=sizeof(PESHDR); - if (Length!=PESSize) return false; - - struct PESHDROPT *peshdropt=(struct PESHDROPT *) &PESData[sizeof(struct PESHDR)]; - - uchar *buf; - int buflen; - - if (peshdropt->MarkerBits==0x2) - { - // we have an optional PES header - int bpos=sizeof(struct PESHDR)+sizeof(struct PESHDROPT)+ - peshdropt->Length; - buf=&PESData[bpos]; - buflen=PESSize-bpos; - } - else - { - int bpos=sizeof(struct PESHDR); - buf=&PESData[bpos]; - buflen=PESSize-bpos; - } - queue->Inject(buf,buflen); - return true; -} - -bool cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, MarkAdPacket *Pkt) -{ - if ((!Pkt) || (!queue)) return false; - - bool ret=true; - - if (TSData) - { - if (TSSize!=TS_SIZE) - { - return Reset(MA_ERR_TSSIZE); // we need a full packet - } - - // check TS packet sync - if (TSData[0]!=0x47) - { - return Reset(MA_ERR_NOSYNC); // no sync - } - - struct TSHDR *tshdr = (struct TSHDR *) TSData; - - int pid = (tshdr->PidH << 8) | tshdr->PidL; - if (Pid.Num!=pid) - { - return true; // not for us, but this is ok - } - - if ((counter!=-1) && (((counter+1) & 0xF)!=tshdr->Counter)) - { - if (counter==(int) tshdr->Counter) - { - Pkt->Skipped+=TS_SIZE; - return true; // duplicate paket -> just ignore - } - // sequence error - ret=Reset(MA_ERR_SEQ); - if (!tshdr->PayloadStart) return ret; - } - counter=tshdr->Counter; - - if (tshdr->PayloadStart) - { - sync=true; - } - if (!sync) - { - Pkt->Skipped+=TS_SIZE; - return false; // not synced - } - - if ((tshdr->AFC<=0) || (tshdr->AFC>3)) - { - return Reset(MA_ERR_AFC); - } - - // we just ignore the infos in the adaption field (e.g. OPCR/PCR) - if ((tshdr->AFC!=1) && (tshdr->AFC!=3)) - { - return true; - } - - int buflen=TS_SIZE+1; - uchar *buf=NULL; - - if (tshdr->AFC==1) - { - // payload only - buflen=TS_SIZE-sizeof(struct TSHDR); - buf=&TSData[sizeof(struct TSHDR)]; - } - - if (tshdr->AFC==3) - { - // adaption field + payload - struct TSADAPT *tsadapt = (struct TSADAPT *) &TSData[4]; - int alen=tsadapt->Len+1; - buflen=TS_SIZE-(sizeof(struct TSHDR)+alen); - buf=&TSData[sizeof(struct TSHDR)+alen]; - } - - if (buflen>TS_SIZE) - { - // size to large - return Reset(MA_ERR_TOBIG); - } - if (buflen<0) - { - // error in size - return Reset(MA_ERR_NEG); - } - if (buflen==0) - { - // no data? - return false; - } - - if (tshdr->PayloadStart) - { - if ((buf[0]!=0) && (buf[1]!=0)) - { - Pkt->Skipped+=TS_SIZE; - sync=false; - if (buflen<7) return false; - // add a pseudo padding stream - buf[0]=0; - buf[1]=0; - buf[2]=1; - buf[3]=0xbe; - buf[4]=buflen-6; - buf[5]=0; - } - } - queue->Put(buf,buflen); - } - if (!ret) return ret; - if (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264) - { - Pkt->Data=queue->GetPacket(&Pkt->Length,MA_PACKET_H264); - } - else - { - Pkt->Data=queue->GetPacket(&Pkt->Length,MA_PACKET_PKT); - } - return ret; -} diff --git a/command/ts2pkt.h b/command/ts2pkt.h deleted file mode 100644 index 367a007..0000000 --- a/command/ts2pkt.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * ts2pkt.h: A program for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - */ - -#ifndef __ts2pkt_h_ -#define __ts2pkt_h_ - -#ifndef TS_SIZE -#define TS_SIZE 188 -#endif - -#ifndef uchar -typedef unsigned char uchar; -#endif - -#include "global.h" -#include "queue.h" - -class cMarkAdTS2Pkt -{ -private: - struct TSHDR - { -unsigned Sync: - 8; -unsigned PidH: - 5; -unsigned Priority: - 1; -unsigned PayloadStart: - 1; -unsigned TError: - 1; -unsigned PidL: - 8; -unsigned Counter: - 4; -unsigned AFC: - 2; -unsigned TSC: - 2; - }; - - struct TSADAPT - { -unsigned Len: - 8; -unsigned Discontinuity_indicator: - 1; -unsigned Random_access_indicator: - 1; -unsigned Elementary_stream_priority_indicator: - 1; -unsigned PCR_flag: - 1; -unsigned OPCR_flag: - 1; -unsigned Splicing_point_flag: - 1; -unsigned Transport_private_data_flag: - 1; -unsigned Adaption_field_extension_flag: - 1; -uint64_t PCR_base: - 33; -unsigned reserved: - 6; -unsigned PCR_ext: - 9; - }; - - struct PESHDR - { - uchar Sync1; - uchar Sync2; - uchar Sync3; - uchar StreamID; - uchar LenH; - uchar LenL; - }; - -#pragma pack(1) - struct PESHDROPT - { -unsigned OOC: - 1; -unsigned CY: - 1; -unsigned DAI: - 1; -unsigned PESP: - 1; -unsigned PESSC: - 2; -unsigned MarkerBits: - 2; -unsigned EXT: - 1; -unsigned CRC: - 1; -unsigned ACI: - 1; -unsigned TM: - 1; -unsigned RATE: - 1; -unsigned ESCR: - 1; -unsigned TSF: - 2; -unsigned Length: - 8; - }; -#pragma pack() - - int counter; - bool sync; - - cMarkAdPaketQueue *queue; - -#define MA_ERR_STARTUP 0 -#define MA_ERR_TSSIZE 1 -#define MA_ERR_NOSYNC 2 -#define MA_ERR_SEQ 3 -#define MA_ERR_AFC 4 -#define MA_ERR_TOBIG 5 -#define MA_ERR_NEG 6 - bool Reset(int ErrIndex=MA_ERR_STARTUP); -public: - cMarkAdTS2Pkt(const char *QueueName="TS2Pkt", int QueueSize=32768); - ~cMarkAdTS2Pkt(); - void Clear(); - bool Process(MarkAdPid Pid,uchar *TSData, int TSSize, MarkAdPacket *Pkt); - bool InjectVideoPES(uchar *PESData, int PESSize); -}; - -#endif diff --git a/command/video.cpp b/command/video.cpp index 77b77fa..d11d0cd 100644 --- a/command/video.cpp +++ b/command/video.cpp @@ -62,7 +62,7 @@ cMarkAdLogo::cMarkAdLogo(MarkAdContext *maContext) void cMarkAdLogo::Clear() { memset(&area,0,sizeof(area)); - area.status=UNINITIALIZED; + area.status=LOGO_UNINITIALIZED; } int cMarkAdLogo::Load(const char *directory, char *file, int plane) @@ -326,36 +326,36 @@ int cMarkAdLogo::Detect(int framenumber, int *logoframenumber) mpixel+=area.mpixel[plane]; } } - if (extract) return NOCHANGE; - if (!processed) return ERROR; + if (extract) return LOGO_NOCHANGE; + if (!processed) return LOGO_ERROR; if (processed==1) { - if ((area.intensity>100) || (area.status!=LOGO) && - (area.intensity>180)) return NOCHANGE; + if ((area.intensity>100) || (area.status!=LOGO_VISIBLE) && + (area.intensity>180)) return LOGO_NOCHANGE; } - int ret=NOCHANGE; - if (area.status==UNINITIALIZED) + int ret=LOGO_NOCHANGE; + if (area.status==LOGO_UNINITIALIZED) { // Initialize - if (rpixel>(mpixel*LOGO_VMARK)) + if (rpixel>=(mpixel*LOGO_VMARK)) { - area.status=LOGO; + area.status=ret=LOGO_VISIBLE; } else { - area.status=NOLOGO; + area.status=LOGO_INVISIBLE; } } if (rpixel>=(mpixel*LOGO_VMARK)) { - if (area.status==NOLOGO) + if (area.status==LOGO_INVISIBLE) { if (area.counter>=LOGO_VMAXCOUNT) { - area.status=ret=LOGO; + area.status=ret=LOGO_VISIBLE; *logoframenumber=area.framenumber; area.counter=0; } @@ -374,11 +374,11 @@ int cMarkAdLogo::Detect(int framenumber, int *logoframenumber) if (rpixel<(mpixel*LOGO_IMARK)) { - if (area.status==LOGO) + if (area.status==LOGO_VISIBLE) { if (area.counter>=LOGO_IMAXCOUNT) { - area.status=ret=NOLOGO; + area.status=ret=LOGO_INVISIBLE; *logoframenumber=area.framenumber; area.counter=0; } @@ -403,12 +403,12 @@ int cMarkAdLogo::Detect(int framenumber, int *logoframenumber) int cMarkAdLogo::Process(int FrameNumber, int *LogoFrameNumber) { - if (!macontext) return ERROR; - if (!macontext->Video.Data.Valid) return ERROR; - if (!macontext->Video.Info.Width) return ERROR; - if (!macontext->Video.Info.Height) return ERROR; - if (!macontext->Config->logoDirectory[0]) return ERROR; - if (!macontext->Info.ChannelName) return ERROR; + if (!macontext) return LOGO_ERROR; + if (!macontext->Video.Data.Valid) return LOGO_ERROR; + if (!macontext->Video.Info.Width) return LOGO_ERROR; + if (!macontext->Video.Info.Height) return LOGO_ERROR; + if (!macontext->Config->logoDirectory[0]) return LOGO_ERROR; + if (!macontext->Info.ChannelName) return LOGO_ERROR; if (macontext->Config->logoExtraction==-1) { @@ -468,7 +468,7 @@ cMarkAdBlackBordersHoriz::cMarkAdBlackBordersHoriz(MarkAdContext *maContext) void cMarkAdBlackBordersHoriz::Clear() { - borderstatus=UNINITIALIZED; + borderstatus=HBORDER_UNINITIALIZED; borderframenumber=-1; } @@ -536,23 +536,23 @@ int cMarkAdBlackBordersHoriz::Process(int FrameNumber, int *BorderIFrame) #define MINSECS 240 switch (borderstatus) { - case UNINITIALIZED: + case HBORDER_UNINITIALIZED: if (FrameNumber>(borderframenumber+macontext->Video.Info.FramesPerSecond*MINSECS)) { - borderstatus=BORDER; + borderstatus=HBORDER_VISIBLE; } break; - case NOBORDER: + case HBORDER_INVISIBLE: if (FrameNumber>(borderframenumber+macontext->Video.Info.FramesPerSecond*MINSECS)) { *BorderIFrame=borderframenumber; - borderstatus=BORDER; + borderstatus=HBORDER_VISIBLE; return 1; // detected start of black border } break; - case BORDER: + case HBORDER_VISIBLE: borderframenumber=FrameNumber; break; } @@ -562,10 +562,10 @@ int cMarkAdBlackBordersHoriz::Process(int FrameNumber, int *BorderIFrame) { if (borderframenumber!=-1) { - if (borderstatus==BORDER) + if (borderstatus==HBORDER_VISIBLE) { *BorderIFrame=borderframenumber; - borderstatus=NOBORDER; + borderstatus=HBORDER_INVISIBLE; borderframenumber=-1; return -1; // detected stop of black border } @@ -577,7 +577,7 @@ int cMarkAdBlackBordersHoriz::Process(int FrameNumber, int *BorderIFrame) else { borderframenumber=-1; - borderstatus=NOBORDER; + borderstatus=HBORDER_INVISIBLE; } } return 0; @@ -587,8 +587,8 @@ cMarkAdOverlap::cMarkAdOverlap(MarkAdContext *maContext) { macontext=maContext; - histbuf[BEFORE]=NULL; - histbuf[AFTER]=NULL; + histbuf[OV_BEFORE]=NULL; + histbuf[OV_AFTER]=NULL; result.CommentBefore=NULL; result.CommentAfter=NULL; Clear(); @@ -601,19 +601,19 @@ cMarkAdOverlap::~cMarkAdOverlap() void cMarkAdOverlap::Clear() { - histcnt[BEFORE]=0; - histcnt[AFTER]=0; - histframes[BEFORE]=0; - histframes[AFTER]=0; - if (histbuf[BEFORE]) + histcnt[OV_BEFORE]=0; + histcnt[OV_AFTER]=0; + histframes[OV_BEFORE]=0; + histframes[OV_AFTER]=0; + if (histbuf[OV_BEFORE]) { - delete[] histbuf[BEFORE]; - histbuf[BEFORE]=NULL; + delete[] histbuf[OV_BEFORE]; + histbuf[OV_BEFORE]=NULL; } - if (histbuf[AFTER]) + if (histbuf[OV_AFTER]) { - delete[] histbuf[AFTER]; - histbuf[AFTER]=NULL; + delete[] histbuf[OV_AFTER]; + histbuf[OV_AFTER]=NULL; } if (result.CommentBefore) free(result.CommentBefore); if (result.CommentAfter) free(result.CommentAfter); @@ -655,12 +655,12 @@ MarkAdPos *cMarkAdOverlap::Detect() int tmpA=0,tmpB=0; if (result.FrameNumberBefore==-1) return NULL; result.FrameNumberBefore=-1; - for (int B=0; B<histcnt[BEFORE]; B++) + for (int B=0; B<histcnt[OV_BEFORE]; B++) { - for (int A=start; A<histcnt[AFTER]; A++) + for (int A=start; A<histcnt[OV_AFTER]; A++) { //printf("%6i %6i ",histbuf[BEFORE][B].framenumber,histbuf[AFTER][A].framenumber); - bool simil=areSimilar(histbuf[BEFORE][B].histogram,histbuf[AFTER][A].histogram); + bool simil=areSimilar(histbuf[OV_BEFORE][B].histogram,histbuf[OV_AFTER][A].histogram); if (simil) { tmpA=A; @@ -675,8 +675,8 @@ MarkAdPos *cMarkAdOverlap::Detect() if (simcnt>similarMaxCnt) { - result.FrameNumberBefore=histbuf[BEFORE][tmpB].framenumber; - result.FrameNumberAfter=histbuf[AFTER][tmpA].framenumber; + result.FrameNumberBefore=histbuf[OV_BEFORE][tmpB].framenumber; + result.FrameNumberAfter=histbuf[OV_AFTER][tmpA].framenumber; } else { @@ -690,8 +690,8 @@ MarkAdPos *cMarkAdOverlap::Detect() { if (simcnt>similarMaxCnt) { - result.FrameNumberBefore=histbuf[BEFORE][tmpB].framenumber; - result.FrameNumberAfter=histbuf[AFTER][tmpA].framenumber; + result.FrameNumberBefore=histbuf[OV_BEFORE][tmpB].framenumber; + result.FrameNumberAfter=histbuf[OV_AFTER][tmpA].framenumber; } else { @@ -714,13 +714,13 @@ MarkAdPos *cMarkAdOverlap::Process(int FrameNumber, int Frames, bool BeforeAd) { if ((lastframenumber>0) && (!similarMaxCnt)) { - similarCutOff=60000; // lower is harder! - similarMaxCnt=4; + similarCutOff=50000; // lower is harder! + similarMaxCnt=6; } if (BeforeAd) { - if ((histframes[BEFORE]) && (histcnt[BEFORE]>=histframes[BEFORE])) + if ((histframes[OV_BEFORE]) && (histcnt[OV_BEFORE]>=histframes[OV_BEFORE])) { if (result.FrameNumberBefore) { @@ -731,31 +731,31 @@ MarkAdPos *cMarkAdOverlap::Process(int FrameNumber, int Frames, bool BeforeAd) return NULL; } } - if (!histbuf[BEFORE]) + if (!histbuf[OV_BEFORE]) { - histframes[BEFORE]=Frames; - histbuf[BEFORE]=new histbuffer[Frames+1]; + histframes[OV_BEFORE]=Frames; + histbuf[OV_BEFORE]=new histbuffer[Frames+1]; } - getHistogram(histbuf[BEFORE][histcnt[BEFORE]].histogram); - histbuf[BEFORE][histcnt[BEFORE]].framenumber=FrameNumber; - histcnt[BEFORE]++; + getHistogram(histbuf[OV_BEFORE][histcnt[OV_BEFORE]].histogram); + histbuf[OV_BEFORE][histcnt[OV_BEFORE]].framenumber=FrameNumber; + histcnt[OV_BEFORE]++; } else { - if (!histbuf[AFTER]) + if (!histbuf[OV_AFTER]) { - histframes[AFTER]=Frames; - histbuf[AFTER]=new histbuffer[Frames+1]; + histframes[OV_AFTER]=Frames; + histbuf[OV_AFTER]=new histbuffer[Frames+1]; } - if (histcnt[AFTER]>=histframes[AFTER]-1) + if (histcnt[OV_AFTER]>=histframes[OV_AFTER]-1) { if (result.FrameNumberBefore) return NULL; return Detect(); } - getHistogram(histbuf[AFTER][histcnt[AFTER]].histogram); - histbuf[AFTER][histcnt[AFTER]].framenumber=FrameNumber; - histcnt[AFTER]++; + getHistogram(histbuf[OV_AFTER][histcnt[OV_AFTER]].histogram); + histbuf[OV_AFTER][histcnt[OV_AFTER]].framenumber=FrameNumber; + histcnt[OV_AFTER]++; } lastframenumber=FrameNumber; return NULL; @@ -775,7 +775,7 @@ cMarkAdVideo::cMarkAdVideo(MarkAdContext *maContext) cMarkAdVideo::~cMarkAdVideo() { - ResetMarks(); + resetmarks(); if (hborder) delete hborder; if (logo) delete logo; if (overlap) delete overlap; @@ -785,11 +785,13 @@ void cMarkAdVideo::Clear() { aspectratio.Num=0; aspectratio.Den=0; + framelast=0; + framebeforelast=0; if (hborder) hborder->Clear(); if (logo) logo->Clear(); } -void cMarkAdVideo::ResetMarks() +void cMarkAdVideo::resetmarks() { for (int i=0; i<marks.maxCount; i++) { @@ -798,23 +800,32 @@ void cMarkAdVideo::ResetMarks() memset(&marks,0,sizeof(marks)); } -bool cMarkAdVideo::AddMark(int Type, int Position, const char *Comment) +bool cMarkAdVideo::addmark(int type, int position, const char *comment) { - if (!Comment) return false; + if (!comment) return false; if (marks.Count>marks.maxCount) return false; - marks.Number[marks.Count].Comment=strdup(Comment); - marks.Number[marks.Count].Position=Position; - marks.Number[marks.Count].Type=Type; + marks.Number[marks.Count].Comment=strdup(comment); + marks.Number[marks.Count].Position=position; + marks.Number[marks.Count].Type=type; marks.Count++; return true; } -bool cMarkAdVideo::AspectRatioChange(MarkAdAspectRatio *a, MarkAdAspectRatio *b) +bool cMarkAdVideo::aspectratiochange(MarkAdAspectRatio &a, MarkAdAspectRatio &b, bool &start) { - if ((!a) || (!b)) return false; - - if (a->Num==0 || a->Den==0 || b->Num==0 || b->Den==0) return false; - if ((a->Num!=b->Num) && (a->Den!=b->Den)) return true; + start=false; + if (a.Num==0 || a.Den==0 || b.Num==0 || b.Den==0) + { + if (((a.Num==4) || (b.Num==4)) && ((a.Den==3) || (b.Den==3))) + { + start=true; + } + else + { + return false; + } + } + if ((a.Num!=b.Num) && (a.Den!=b.Den)) return true; return false; } @@ -832,7 +843,7 @@ MarkAdMarks *cMarkAdVideo::Process(int FrameNumber, int FrameNumberNext) { if ((!FrameNumber) && (!FrameNumberNext)) return NULL; - ResetMarks(); + resetmarks(); if (!macontext->Video.Options.IgnoreLogoDetection) { @@ -845,7 +856,7 @@ MarkAdMarks *cMarkAdVideo::Process(int FrameNumber, int FrameNumberNext) { if (asprintf(&buf,"detected logo start (%i)",logoframenumber)!=-1) { - AddMark(MT_LOGOSTART,logoframenumber,buf); + addmark(MT_LOGOSTART,logoframenumber,buf); free(buf); } } @@ -853,7 +864,7 @@ MarkAdMarks *cMarkAdVideo::Process(int FrameNumber, int FrameNumberNext) { if (asprintf(&buf,"detected logo stop (%i)",logoframenumber)!=-1) { - AddMark(MT_LOGOSTOP,logoframenumber,buf); + addmark(MT_LOGOSTOP,logoframenumber,buf); free(buf); } } @@ -869,7 +880,7 @@ MarkAdMarks *cMarkAdVideo::Process(int FrameNumber, int FrameNumberNext) if (asprintf(&buf,"detected start of horiz. borders (%i [%i])", borderframenumber,FrameNumber)!=-1) { - AddMark(MT_BORDERSTART,borderframenumber,buf); + addmark(MT_BORDERSTART,borderframenumber,buf); free(buf); } } @@ -880,50 +891,58 @@ MarkAdMarks *cMarkAdVideo::Process(int FrameNumber, int FrameNumberNext) if (asprintf(&buf,"detected stop of horiz. borders (%i [%i])", borderframenumber,FrameNumber)!=-1) { - AddMark(MT_BORDERSTOP,borderframenumber,buf); + addmark(MT_BORDERSTOP,borderframenumber,buf); free(buf); } } if (!macontext->Video.Options.IgnoreAspectRatio) { - if (AspectRatioChange(&macontext->Video.Info.AspectRatio,&aspectratio)) + bool start; + if (aspectratiochange(macontext->Video.Info.AspectRatio,aspectratio,start)) { + if ((logo->Status()==LOGO_VISIBLE) && (!start)) + { + char *buf=NULL; + if (asprintf(&buf,"assuming logo stop (%i)",framebeforelast)!=-1) + { + addmark(MT_LOGOSTOP,framebeforelast,buf); + free(buf); + } + logo->SetStatusLogoInvisible(); + } char *buf=(char *) calloc(1,256); if (!buf) return NULL; - snprintf(buf,255,"aspect ratio change from %i:%i to %i:%i (", - aspectratio.Num,aspectratio.Den, - macontext->Video.Info.AspectRatio.Num, - macontext->Video.Info.AspectRatio.Den); + if (start) + { + snprintf(buf,255,"aspect ratio %i:%i (", + macontext->Video.Info.AspectRatio.Num, + macontext->Video.Info.AspectRatio.Den); + } + else + { + snprintf(buf,255,"aspect ratio change from %i:%i to %i:%i (", + aspectratio.Num,aspectratio.Den, + macontext->Video.Info.AspectRatio.Num, + macontext->Video.Info.AspectRatio.Den); + } - if ((macontext->Info.AspectRatio.Num) && (macontext->Info.AspectRatio.Den)) + if ((macontext->Video.Info.AspectRatio.Num==4) && + (macontext->Video.Info.AspectRatio.Den==3)) { - if ((macontext->Video.Info.AspectRatio.Num==macontext->Info.AspectRatio.Num) && - (macontext->Video.Info.AspectRatio.Den==macontext->Info.AspectRatio.Den)) - { - char nbuf[20]; - snprintf(nbuf,sizeof(nbuf),"%i)*",FrameNumberNext); - nbuf[19]=0; - strcat(buf,nbuf); - AddMark(MT_ASPECTSTART,FrameNumberNext,buf); - } - else - { - char nbuf[20]; - snprintf(nbuf,sizeof(nbuf),"%i)",framelast); - nbuf[19]=0; - strcat(buf,nbuf); - AddMark(MT_ASPECTSTOP,framelast,buf); - } + char nbuf[20]; + snprintf(nbuf,sizeof(nbuf),"%i)*",start ? FrameNumber : FrameNumberNext); + nbuf[19]=0; + strcat(buf,nbuf); + addmark(MT_ASPECTSTART,FrameNumberNext,buf); } else { char nbuf[20]; - snprintf(nbuf,sizeof(nbuf),"%i)?",FrameNumber); + snprintf(nbuf,sizeof(nbuf),"%i)",framelast); nbuf[19]=0; strcat(buf,nbuf); - - AddMark(MT_ASPECTCHANGE,FrameNumber,buf); + addmark(MT_ASPECTSTOP,framelast,buf); } free(buf); } @@ -932,5 +951,13 @@ MarkAdMarks *cMarkAdVideo::Process(int FrameNumber, int FrameNumberNext) aspectratio.Den=macontext->Video.Info.AspectRatio.Den; } framelast=FrameNumberNext; - return &marks; + framebeforelast=FrameNumber; + if (marks.Count) + { + return &marks; + } + else + { + return NULL; + } } diff --git a/command/video.h b/command/video.h index b6db23f..16f8899 100644 --- a/command/video.h +++ b/command/video.h @@ -10,7 +10,7 @@ #include "global.h" -#define LOGO_MAXHEIGHT 250 +#define LOGO_MAXHEIGHT 170 #define LOGO_MAXWIDTH 480 #define LOGO_DEFHEIGHT 100 @@ -22,11 +22,33 @@ #define LOGO_VMARK 0.5 // percantage of pixels for visible #define LOGO_IMARK 0.15 // percentage of pixels for invisible +enum +{ + LOGO_ERROR=-3, + LOGO_UNINITIALIZED=-2, + LOGO_INVISIBLE=-1, + LOGO_NOCHANGE=0, + LOGO_VISIBLE=1 +}; + +enum +{ + HBORDER_ERROR=-3, + HBORDER_UNINITIALIZED=-2, + HBORDER_INVISIBLE=-1, + HBORDER_NOCHANGE=0, + HBORDER_VISIBLE=1 +}; + +enum +{ + OV_BEFORE=0, + OV_AFTER=1 +}; + class cMarkAdOverlap { private: -#define BEFORE 0 -#define AFTER 1 MarkAdContext *macontext; typedef int simpleHistogram[256]; @@ -67,15 +89,6 @@ private: BOTTOM_RIGHT }; - enum - { - ERROR=-3, - UNINITIALIZED=-2, - NOLOGO=-1, - NOCHANGE=0, - LOGO=1 - }; - int LOGOHEIGHT; // max. 140 int LOGOWIDTH; // 192-288 @@ -113,27 +126,31 @@ private: public: cMarkAdLogo(MarkAdContext *maContext); int Process(int FrameNumber, int *LogoFrameNumber); + int Status() + { + return area.status; + } + void SetStatusLogoInvisible() + { + if (area.status==LOGO_VISIBLE) + area.status=LOGO_INVISIBLE; + } void Clear(); }; class cMarkAdBlackBordersHoriz { private: - enum - { - ERROR=-3, - UNINITIALIZED=-2, - NOBORDER=-1, - NOCHANGE=0, - BORDER=1 - }; - int borderstatus; int borderframenumber; MarkAdContext *macontext; public: cMarkAdBlackBordersHoriz(MarkAdContext *maContext); int Process(int FrameNumber,int *BorderFrameNumber); + int Status() + { + return borderstatus; + } void Clear(); }; @@ -148,11 +165,12 @@ private: cMarkAdLogo *logo; cMarkAdOverlap *overlap; - void ResetMarks(); - bool AddMark(int Type, int Position, const char *Comment); - bool AspectRatioChange(MarkAdAspectRatio *a, MarkAdAspectRatio *b); + void resetmarks(); + bool addmark(int Type, int position, const char *comment); + bool aspectratiochange(MarkAdAspectRatio &a, MarkAdAspectRatio &b, bool &start); int framelast; + int framebeforelast; public: cMarkAdVideo(MarkAdContext *maContext); |