summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJochen Dolze <vdr@dolze.de>2010-09-16 21:37:36 +0200
committerJochen Dolze <vdr@dolze.de>2010-09-16 21:37:36 +0200
commit57df9917d4626d93323c7b0d2368fbf5d4748627 (patch)
treeebfe76fe280db47e223335266eab1bd34afa4226
parent03fc6351fce571b5ff7454bdfad9d4a0f0fb7679 (diff)
downloadvdr-plugin-markad-57df9917d4626d93323c7b0d2368fbf5d4748627.tar.gz
vdr-plugin-markad-57df9917d4626d93323c7b0d2368fbf5d4748627.tar.bz2
Added second pass processing (overlap, audio silence detection)
-rw-r--r--command/Makefile2
-rw-r--r--command/audio.cpp103
-rw-r--r--command/audio.h25
-rw-r--r--command/audio_gain_analysis.cpp423
-rw-r--r--command/audio_gain_analysis.h102
-rw-r--r--command/decoder.cpp121
-rw-r--r--command/decoder.h7
-rw-r--r--command/demux.cpp101
-rw-r--r--command/demux.h9
-rw-r--r--command/global.h8
-rw-r--r--command/markad-standalone.cpp678
-rw-r--r--command/markad-standalone.h43
-rw-r--r--command/marks.cpp167
-rw-r--r--command/marks.h5
-rw-r--r--command/pes2es.cpp24
-rw-r--r--command/pes2es.h82
-rw-r--r--command/queue.cpp25
-rw-r--r--command/queue.h8
-rw-r--r--command/streaminfo.cpp213
-rw-r--r--command/streaminfo.h10
-rw-r--r--command/ts2pkt.cpp58
-rw-r--r--command/ts2pkt.h28
-rw-r--r--command/video.cpp318
-rw-r--r--command/video.h52
24 files changed, 1977 insertions, 635 deletions
diff --git a/command/Makefile b/command/Makefile
index e6e1f2f..77f4f3e 100644
--- a/command/Makefile
+++ b/command/Makefile
@@ -28,7 +28,7 @@ INCLUDES += -I..
### The object files (add further files here):
-OBJS = markad-standalone.o decoder.o marks.o streaminfo.o video.o audio.o demux.o queue.o ts2pkt.o pes2es.o
+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
### The main target:
diff --git a/command/audio.cpp b/command/audio.cpp
index a5fc357..f0457b5 100644
--- a/command/audio.cpp
+++ b/command/audio.cpp
@@ -11,6 +11,11 @@
#include <stdlib.h>
#include <string.h>
+extern "C"
+{
+#include "debug.h"
+}
+
#include "audio.h"
cMarkAdAudio::cMarkAdAudio(MarkAdContext *maContext)
@@ -19,11 +24,14 @@ cMarkAdAudio::cMarkAdAudio(MarkAdContext *maContext)
mark.Comment=NULL;
mark.Position=0;
mark.Type=0;
+ result.CommentBefore=NULL;
+ result.CommentAfter=NULL;
Clear();
}
cMarkAdAudio::~cMarkAdAudio()
{
+ Clear();
ResetMark();
}
@@ -60,11 +68,18 @@ bool cMarkAdAudio::AddMark(int Type, int Position, const char *Comment)
return true;
}
-bool cMarkAdAudio::SilenceDetection()
+bool cMarkAdAudio::SilenceDetection(int FrameNumber)
{
+ // function taken from noad
+ if (!FrameNumber) return false;
if (!macontext->Audio.Data.Valid) return false;
- if (lastiframe_silence==lastiframe) return false; // we already detected silence for this frame
-
+ if (lastframe_silence==FrameNumber) return false; // we already detected silence for this frame
+ if (lastframe_silence==-1)
+ {
+ // ignore first detection
+ lastframe_silence=FrameNumber;
+ return false;
+ }
int samples=macontext->Audio.Data.SampleBufLen/
sizeof(*macontext->Audio.Data.SampleBuf)/
macontext->Audio.Info.Channels;
@@ -81,20 +96,23 @@ bool cMarkAdAudio::SilenceDetection()
lowvalcount++;
if (lowvalcount>MIN_LOWVALS)
{
- lastiframe_silence=lastiframe;
- return true;
+ lastframe_silence=FrameNumber;
}
}
else
{
+ if (lastframe_silence==FrameNumber)
+ {
+// isyslog("Silentium @%i (%i)!",FrameNumber,lowvalcount);
+ return true;
+ }
lowvalcount=0;
}
}
return false;
}
-#if 0
-bool cMarkAdAudio::AnalyzeGain()
+bool cMarkAdAudio::AnalyzeGain(int FrameNumber)
{
if (!macontext->Audio.Data.Valid) return false;
@@ -111,34 +129,37 @@ bool cMarkAdAudio::AnalyzeGain()
right[i]=macontext->Audio.Data.SampleBuf[1+(i*2)];
}
- if ((lastiframe-lastiframe_gain)>ANALYZEFRAMES)
+ if (FrameNumber!=lastframe_gain)
{
- if (lastiframe_gain>0)
+ if ((lastframe_gain>0) && (audiogain.AnalyzedSamples()>=(3*samples)))
{
- double dgain,gain = audiogain.GetGain();
- dgain=gain-lastgain;
- printf("%05i %+.2f db %+.2f db\n",lastiframe_gain,gain,lastgain);
- lastgain=gain;
+ double gain = audiogain.GetGain();
+ printf("%05i %+.2f db\n",lastframe_gain,gain);
}
audiogain.Init(macontext->Audio.Info.SampleRate);
- lastiframe_gain=lastiframe;
+ lastframe_gain=-1;
}
+
if (audiogain.AnalyzeSamples(left,right,samples,2)!=GAIN_ANALYSIS_OK)
{
- lastiframe_gain=-ANALYZEFRAMES;
+ lastframe_gain=-1;
+ return false;
+ }
+ else
+ {
+ lastframe_gain=FrameNumber;
}
-
return true;
}
-#endif
void cMarkAdAudio::Clear()
{
channels=0;
-#if 0
- lastiframe_gain=-ANALYZEFRAMES;
-#endif
- lastiframe_silence=-1;
+ lastframe_gain=-1;
+ lastframe_silence=-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)
@@ -148,47 +169,51 @@ bool cMarkAdAudio::ChannelChange(int a, int b)
return false;
}
-MarkAdMark *cMarkAdAudio::Process(int LastIFrame)
+MarkAdPos *cMarkAdAudio::Process2ndPass(int FrameNumber)
{
- ResetMark();
- if (!LastIFrame) return NULL;
- lastiframe=LastIFrame;
+ if (!FrameNumber) return NULL;
-#if 0
- AnalyzeGain();
-#endif
- if (macontext->Audio.Options.AudioSilenceDetection)
+ if (SilenceDetection(FrameNumber))
{
- if (SilenceDetection())
+ if (result.CommentBefore) free(result.CommentBefore);
+ if (asprintf(&result.CommentBefore,"audio silence detection (%i)",FrameNumber)==-1)
{
- char *buf=NULL;
- if (asprintf(&buf,"audio channel silence detecion (%i)",lastiframe)!=-1)
- {
- AddMark(MT_SILENCECHANGE,lastiframe,buf);
- free(buf);
- }
+ result.CommentBefore=NULL;
}
+ result.FrameNumberBefore=FrameNumber;
+ return &result;
}
+ return NULL;
+}
+
+MarkAdMark *cMarkAdAudio::Process(int FrameNumber, int FrameNumberNext)
+{
+ if ((!FrameNumber) || (!FrameNumberNext)) return NULL;
+ ResetMark();
+
if (ChannelChange(macontext->Audio.Info.Channels,channels))
{
char *buf=NULL;
if (asprintf(&buf,"audio channel change from %i to %i (%i)", channels,
- macontext->Audio.Info.Channels,lastiframe)!=-1)
+ macontext->Audio.Info.Channels,
+ (macontext->Audio.Info.Channels>2) ? FrameNumberNext :
+ framelast)!=-1)
{
if (macontext->Audio.Info.Channels>2)
{
- AddMark(MT_CHANNELSTART,lastiframe,buf);
+ AddMark(MT_CHANNELSTART,FrameNumberNext,buf);
}
else
{
- AddMark(MT_CHANNELSTOP,lastiframe,buf);
+ AddMark(MT_CHANNELSTOP,framelast,buf);
}
free(buf);
}
}
channels=macontext->Audio.Info.Channels;
+ framelast=FrameNumberNext;
return &mark;
}
diff --git a/command/audio.h b/command/audio.h
index bb751ae..56901a2 100644
--- a/command/audio.h
+++ b/command/audio.h
@@ -10,39 +10,38 @@
#include "global.h"
-#if 0
#include "audio_gain_analysis.h"
-#endif
class cMarkAdAudio
{
private:
- int lastiframe;
+ //int framenumber;
MarkAdContext *macontext;
MarkAdMark mark;
void ResetMark();
bool AddMark(int Type, int Position, const char *Comment);
-#define CUT_VAL 10
-#define MIN_LOWVALS 3
- bool SilenceDetection();
- int lastiframe_silence;
+#define CUT_VAL 4
+#define MIN_LOWVALS 25
+ bool SilenceDetection(int FrameNumber);
+ int lastframe_silence;
-#if 0
-#define ANALYZEFRAMES 1
- int lastiframe_gain;
+ int lastframe_gain;
double lastgain;
cMarkAdAudioGainAnalysis audiogain;
- bool AnalyzeGain();
-#endif
+ bool AnalyzeGain(int FrameNumber);
int channels;
bool ChannelChange(int a, int b);
+ int framelast;
+
+ MarkAdPos result;
public:
cMarkAdAudio(MarkAdContext *maContext);
~cMarkAdAudio();
- MarkAdMark *Process(int LastIFrame);
+ MarkAdMark *Process(int FrameNumber, int FrameNumberBefore);
+ MarkAdPos *Process2ndPass(int FrameNumber);
void Clear();
};
diff --git a/command/audio_gain_analysis.cpp b/command/audio_gain_analysis.cpp
new file mode 100644
index 0000000..b5abf9b
--- /dev/null
+++ b/command/audio_gain_analysis.cpp
@@ -0,0 +1,423 @@
+/*
+ * 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
new file mode 100644
index 0000000..abed123
--- /dev/null
+++ b/command/audio_gain_analysis.h
@@ -0,0 +1,102 @@
+/*
+ * 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/decoder.cpp b/command/decoder.cpp
index e600278..74919ad 100644
--- a/command/decoder.cpp
+++ b/command/decoder.cpp
@@ -27,6 +27,7 @@ cMarkAdDecoder::cMarkAdDecoder(bool useH264, bool useMP2, bool hasAC3)
avcodec_register_all();
last_qscale_table=NULL;
+ skipframes=true;
cpu_set_t cpumask;
uint len = sizeof(cpumask);
@@ -131,7 +132,7 @@ cMarkAdDecoder::cMarkAdDecoder(bool useH264, bool useMP2, bool hasAC3)
ac3_context=NULL;
}
- AVCodec *video_codec=NULL;
+ video_codec=NULL;
CodecID video_codecid;
if (useH264)
@@ -156,11 +157,12 @@ cMarkAdDecoder::cMarkAdDecoder(bool useH264, bool useMP2, bool hasAC3)
video_context = avcodec_alloc_context();
if (video_context)
{
+ video_context->get_buffer=our_get_buffer;
+ video_context->release_buffer=our_release_buffer;
video_context->thread_count=cpucount;
if (video_codec->capabilities & CODEC_CAP_TRUNCATED)
video_context->flags|=CODEC_FLAG_TRUNCATED; // we do not send complete frames
- video_context->flags|=CODEC_FLAG_GRAY; // only decode grayscale
video_context->flags2|=CODEC_FLAG2_FAST; // really?
video_context->skip_idct=AVDISCARD_ALL;
@@ -168,14 +170,12 @@ cMarkAdDecoder::cMarkAdDecoder(bool useH264, bool useMP2, bool hasAC3)
if (video_codecid==CODEC_ID_H264)
{
video_context->flags2|=CODEC_FLAG2_CHUNKS; // needed for H264!
- video_context->skip_loop_filter=AVDISCARD_ALL; // skip deblocking
av_log_set_level(AV_LOG_FATAL); // H264 decoder is very chatty
}
else
{
video_context->skip_frame=AVDISCARD_NONKEY; // just I-frames
}
-
video_context->codec_id = video_codecid;
video_context->codec_type = CODEC_TYPE_VIDEO;
int ret=avcodec_open(video_context, video_codec);
@@ -271,11 +271,12 @@ cMarkAdDecoder::cMarkAdDecoder(bool useH264, bool useMP2, bool hasAC3)
{
audiobuf=NULL;
}
-
+ initial_coded_picture=-1;
}
cMarkAdDecoder::~cMarkAdDecoder()
{
+ Clear();
if (video_context)
{
avcodec_close(video_context);
@@ -297,6 +298,58 @@ cMarkAdDecoder::~cMarkAdDecoder()
if (audiobuf) free(audiobuf);
}
+bool cMarkAdDecoder::Clear()
+{
+ bool ret=true;
+ if (video_context)
+ {
+ avcodec_flush_buffers(video_context);
+ AVCodecContext *dest;
+ dest=avcodec_alloc_context();
+ if (dest)
+ {
+ if (avcodec_copy_context(dest,video_context)!=0) ret=false;
+ }
+ else
+ {
+ ret=false;
+ }
+ avcodec_close(video_context);
+ av_free(video_context);
+ if (ret)
+ {
+ video_context=dest;
+ if (avcodec_open(video_context,video_codec)<0) ret=false;
+ }
+ }
+ if (ac3_context) avcodec_flush_buffers(ac3_context);
+ if (mp2_context) avcodec_flush_buffers(mp2_context);
+ return ret;
+}
+
+int cMarkAdDecoder::our_get_buffer(struct AVCodecContext *c, AVFrame *pic)
+{
+ int ret=avcodec_default_get_buffer(c,pic);
+ return ret;
+}
+
+void cMarkAdDecoder::our_release_buffer(struct AVCodecContext *c, AVFrame *pic)
+{
+ avcodec_default_release_buffer(c, pic);
+}
+
+bool cMarkAdDecoder::SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Audio_Context)
+{
+ if ((!maContext) || (!Audio_Context)) return false;
+
+ maContext->Audio.Info.SampleRate = Audio_Context->sample_rate;
+ maContext->Audio.Info.Channels = Audio_Context->channels;
+ maContext->Audio.Data.SampleBuf=audiobuf;
+ maContext->Audio.Data.SampleBufLen=audiobufsize;
+ maContext->Audio.Data.Valid=true;
+ return true;
+}
+
bool cMarkAdDecoder::DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen)
{
if (!mp2_context) return false;
@@ -314,14 +367,13 @@ bool cMarkAdDecoder::DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen
audiobufsize=AVCODEC_MAX_AUDIO_FRAME_SIZE;
int ret=false;
- int16_t Taudiobuf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
while (avpkt.size>0)
{
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(25<<8)+0)
- int len=avcodec_decode_audio2(mp2_context,Taudiobuf,&audiobufsize,
+ int len=avcodec_decode_audio2(mp2_context,audiobuf,&audiobufsize,
avpkt.data,avpkt.size);
#else
- int len=avcodec_decode_audio3(mp2_context,Taudiobuf,&audiobufsize,&avpkt);
+ int len=avcodec_decode_audio3(mp2_context,audiobuf,&audiobufsize,&avpkt);
#endif
if (len<0)
{
@@ -330,7 +382,6 @@ bool cMarkAdDecoder::DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen
}
if (audiobufsize>0)
{
- memcpy(audiobuf,Taudiobuf,audiobufsize);
SetAudioInfos(maContext,mp2_context);
ret=true;
avpkt.size-=len;
@@ -340,18 +391,6 @@ bool cMarkAdDecoder::DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen
return ret;
}
-bool cMarkAdDecoder::SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Audio_Context)
-{
- if ((!maContext) || (!Audio_Context)) return false;
-
- maContext->Audio.Info.SampleRate = Audio_Context->sample_rate;
- maContext->Audio.Info.Channels = Audio_Context->channels;
- maContext->Audio.Data.SampleBuf=audiobuf;
- maContext->Audio.Data.SampleBufLen=audiobufsize;
- maContext->Audio.Data.Valid=true;
- return true;
-}
-
bool cMarkAdDecoder::DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen)
{
if (!ac3_context) return false;
@@ -368,15 +407,14 @@ bool cMarkAdDecoder::DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen
avpkt.size=eslen;
int ret=false;
- int16_t Taudiobuf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
while (avpkt.size>0)
{
audiobufsize=AVCODEC_MAX_AUDIO_FRAME_SIZE;
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(25<<8)+0)
- int len=avcodec_decode_audio2(ac3_context,Taudiobuf,&audiobufsize,
+ int len=avcodec_decode_audio2(ac3_context,audiobuf,&audiobufsize,
avpkt.data,avpkt.size);
#else
- int len=avcodec_decode_audio3(ac3_context,Taudiobuf,&audiobufsize,&avpkt);
+ int len=avcodec_decode_audio3(ac3_context,audiobuf,&audiobufsize,&avpkt);
#endif
if (len<0)
{
@@ -385,7 +423,6 @@ bool cMarkAdDecoder::DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen
}
if (audiobufsize>0)
{
- memcpy(audiobuf,Taudiobuf,audiobufsize);
SetAudioInfos(maContext,ac3_context);
ret=true;
avpkt.size-=len;
@@ -395,12 +432,6 @@ bool cMarkAdDecoder::DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen
return ret;
}
-void cMarkAdDecoder::PAR2DAR(AVRational a, AVRational *erg)
-{
- av_reduce(&erg->num,&erg->den,video_context->width*a.num,
- video_context->height*a.den,1024*1024);
-}
-
bool cMarkAdDecoder::SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Video_Context, AVFrame *Video_Frame)
{
if ((!maContext) || (!Video_Context) || (!Video_Frame)) return false;
@@ -415,34 +446,35 @@ bool cMarkAdDecoder::SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Vide
}
maContext->Video.Info.Height=Video_Context->height;
maContext->Video.Info.Width=Video_Context->width;
-
- AVRational dar;
- PAR2DAR(Video_Context->sample_aspect_ratio,&dar);
-
- maContext->Video.Info.AspectRatio.Num=dar.num;
- maContext->Video.Info.AspectRatio.Den=dar.den;
-
return true;
}
bool cMarkAdDecoder::DecodeVideo(MarkAdContext *maContext,uchar *pkt, int plen)
{
if (!video_context) return false;
+ if (!video_frame) return false;
maContext->Video.Data.Valid=false;
if ((video_context->codec_id==CODEC_ID_H264) && (!video_context->skip_frame))
{
- if (maContext->Video.Info.Pict_Type)
+ // with H264 we cannot set skip_frame just to NONKEY, is depends on Interlaced...
+ if (maContext->Video.Info.Height)
{
if (maContext->Video.Info.Interlaced)
{
video_context->skip_frame=AVDISCARD_BIDIR; // just P/I-frames
+ video_context->skip_loop_filter=AVDISCARD_BIDIR;
}
else
{
video_context->skip_frame=AVDISCARD_NONKEY; // just I-frames
+ video_context->skip_loop_filter=AVDISCARD_NONKEY;
}
}
+ else
+ {
+ return false;
+ }
}
AVPacket avpkt;
@@ -481,10 +513,17 @@ bool cMarkAdDecoder::DecodeVideo(MarkAdContext *maContext,uchar *pkt, int plen)
}
if (video_frame_ready)
{
- if (last_qscale_table!=video_frame->qscale_table)
+ if (video_context->skip_frame!=AVDISCARD_DEFAULT)
+ {
+ if (last_qscale_table!=video_frame->qscale_table)
+ {
+ if (SetVideoInfos(maContext,video_context,video_frame)) ret=true;
+ last_qscale_table=video_frame->qscale_table;
+ }
+ }
+ else
{
if (SetVideoInfos(maContext,video_context,video_frame)) ret=true;
- last_qscale_table=video_frame->qscale_table;
}
}
}
diff --git a/command/decoder.h b/command/decoder.h
index 12b398e..12773fc 100644
--- a/command/decoder.h
+++ b/command/decoder.h
@@ -31,25 +31,30 @@ extern "C"
class cMarkAdDecoder
{
private:
+ bool skipframes;
int16_t *audiobuf;
int audiobufsize;
+ AVCodec *video_codec;
AVCodecContext *ac3_context;
AVCodecContext *mp2_context;
AVCodecContext *video_context;
AVFrame *video_frame;
int8_t *last_qscale_table;
+ int initial_coded_picture;
+ static int our_get_buffer(struct AVCodecContext *c, AVFrame *pic);
+ static void our_release_buffer(struct AVCodecContext *c, AVFrame *pic);
bool SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Audio_Context);
- void PAR2DAR(AVRational a, AVRational *erg);
bool SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Video_Context,
AVFrame *Video_Frame);
public:
bool DecodeVideo(MarkAdContext *maContext, uchar *pkt, int plen);
bool DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen);
bool DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen);
+ bool Clear();
cMarkAdDecoder(bool useH264, bool useMP2, bool hasAC3);
~cMarkAdDecoder();
};
diff --git a/command/demux.cpp b/command/demux.cpp
index 23bd78e..91a5a54 100644
--- a/command/demux.cpp
+++ b/command/demux.cpp
@@ -7,6 +7,8 @@
#include "demux.h"
+#include <string.h>
+
cMarkAdDemux::cMarkAdDemux()
{
ts2pkt=NULL;
@@ -39,17 +41,15 @@ void cMarkAdDemux::Clear()
skip=0;
}
-void cMarkAdDemux::ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, int *PktLen)
+void cMarkAdDemux::ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *Pkt)
{
- if ((!Pkt) || (!PktLen)) return;
- *Pkt=NULL;
- *PktLen=0;
+ if (!Pkt) return;
if ((Pid.Type==MARKAD_PIDTYPE_AUDIO_AC3) || (Pid.Type==MARKAD_PIDTYPE_AUDIO_MP2))
{
if (!pes2audioes) pes2audioes=new cMarkAdPES2ES("PES2ES audio");
if (!pes2audioes) return;
- pes2audioes->Process(Pid,Data,Count,Pkt,PktLen);
+ pes2audioes->Process(Pid,Data,Count,Pkt);
}
if ((Pid.Type==MARKAD_PIDTYPE_VIDEO_H262) || (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264))
@@ -66,20 +66,48 @@ void cMarkAdDemux::ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt
}
}
if (!pes2videoes) return;
- pes2videoes->Process(Pid,Data,Count,Pkt,PktLen);
+ pes2videoes->Process(Pid,Data,Count,Pkt);
}
return;
}
-void cMarkAdDemux::ProcessTS(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, int *PktLen)
+void cMarkAdDemux::GetVideoPTS(uchar *Data, int Count, unsigned int *Timestamp)
{
- if ((!Pkt) || (!PktLen)) return;
- *Pkt=NULL;
- *PktLen=0;
+ if (!Data) return;
+ if (Count<=0) return;
+ if (!Timestamp) return;
+ struct PESHDR *peshdr=(struct PESHDR *) Data;
+
+ if ((peshdr->Sync1!=0) && (peshdr->Sync2!=0) && (peshdr->Sync3!=1)) return;
+ if ((peshdr->StreamID & 0xF0)!=0xE0) return;
+
+ struct PESHDROPT *peshdropt=(struct PESHDROPT *) &Data[sizeof(struct PESHDR)];
+ if (peshdropt->MarkerBits!=0x2) return;
- uchar *pkt;
- int pktlen;
+ if (peshdropt->PTSDTS<2) return;
+
+ struct PESHDROPTPTS *peshdroptpts=(struct PESHDROPTPTS *) &Data[sizeof(struct PESHDR)+
+ sizeof(struct PESHDROPT)];
+
+ if (peshdroptpts->Marker1 && peshdroptpts->Marker2 &&
+ peshdroptpts->Marker3)
+{
+ unsigned int pts=0;
+ pts|=((peshdroptpts->PTS29_15_H<<7|peshdroptpts->PTS29_15_L)<<15);
+ pts|=(peshdroptpts->PTS14_0_H<<7|peshdroptpts->PTS14_0_L);
+ pts|=(peshdroptpts->PTS32_30<<30);
+ *Timestamp=pts;
+ }
+ return;
+}
+
+void cMarkAdDemux::ProcessTS(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *Pkt)
+{
+ if (!Pkt) return;
+
+ MarkAdPacket pkt;
+ memset(&pkt,0,sizeof(pkt));
if (!ts2pkt)
{
@@ -94,31 +122,31 @@ void cMarkAdDemux::ProcessTS(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt,
}
if (!ts2pkt) return;
- ts2pkt->Process(Pid,Data,Count,&pkt,&pktlen);
+ if (!ts2pkt->Process(Pid,Data,Count,&pkt))
+ {
+ if (pes2audioes) pes2audioes->Clear();
+ return;
+ }
if ((Pid.Type==MARKAD_PIDTYPE_AUDIO_AC3) || (Pid.Type==MARKAD_PIDTYPE_AUDIO_MP2))
{
if (!pes2audioes) pes2audioes=new cMarkAdPES2ES("PES2ES audio");
if (!pes2audioes) return;
- pes2audioes->Process(Pid,pkt,pktlen,Pkt,PktLen);
+ pes2audioes->Process(Pid,pkt.Data,pkt.Length,Pkt);
}
if ((Pid.Type==MARKAD_PIDTYPE_VIDEO_H262) || (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264))
{
- if ((pkt) && ((pkt[3] & 0xF0)==0xE0) && (pkt[4]!=0) && (pkt[5]!=0))
+ GetVideoPTS(pkt.Data,pkt.Length,&Pkt->Timestamp);
+ if ((pkt.Data) && ((pkt.Data[3] & 0xF0)==0xE0) && (pkt.Data[4]!=0) && (pkt.Data[5]!=0))
{
- ts2pkt->InjectVideoPES(pkt,pktlen);
- pkt=NULL;
- pktlen=0;
+ ts2pkt->InjectVideoPES(pkt.Data,pkt.Length);
+ pkt.Data=NULL;
+ pkt.Length=0;
}
+ Pkt->Data=pkt.Data;
+ Pkt->Length=pkt.Length;
}
-
- if ((pkt) && (!*Pkt))
- {
- *Pkt=pkt;
- *PktLen=pktlen;
- }
-
return;
}
@@ -171,32 +199,29 @@ int cMarkAdDemux::GetMinNeeded(MarkAdPid Pid, uchar *Data, int Count, bool *Offc
}
}
-int cMarkAdDemux::Process(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, int *PktLen, bool *Offcnt)
+int cMarkAdDemux::Process(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *Pkt)
{
- if ((!Data) && (!Count) && (!Pkt) || (!PktLen)) return -1;
-
- *Pkt=NULL;
- *PktLen=0;
+ if ((!Data) && (!Count) && (!Pkt)) return -1;
uchar *in=NULL;
int inlen=0;
int retval=0;
- if (Offcnt) *Offcnt=false;
-
if (!pause)
{
+ memset(Pkt,0,sizeof(MarkAdPacket));
+
if (!min_needed)
{
if (skip)
{
int t_skip=skip;
skip=0;
- if (Offcnt) *Offcnt=true;
+ Pkt->Offcnt=true;
return t_skip;
}
- int t_min_needed=GetMinNeeded(Pid,Data,Count,Offcnt);
+ int t_min_needed=GetMinNeeded(Pid,Data,Count,&Pkt->Offcnt);
if (t_min_needed==0)
{
return -1;
@@ -236,14 +261,14 @@ int cMarkAdDemux::Process(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, in
if (Pid.Num>=0)
{
- ProcessTS(Pid, in, inlen, Pkt, PktLen);
+ ProcessTS(Pid, in, inlen, Pkt);
}
else
{
- ProcessVDR(Pid, in, inlen, Pkt, PktLen);
+ ProcessVDR(Pid, in, inlen, Pkt);
}
- if (*Pkt)
+ if (Pkt->Data)
{
if (!pause_retval) pause_retval=retval;
pause=true;
@@ -260,6 +285,6 @@ int cMarkAdDemux::Process(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, in
pause=false;
}
- if (Offcnt) *Offcnt=true;
+ Pkt->Offcnt=true;
return retval;
}
diff --git a/command/demux.h b/command/demux.h
index f97fe08..489528b 100644
--- a/command/demux.h
+++ b/command/demux.h
@@ -14,13 +14,13 @@
#define PESHDRSIZE 6
-#include "global.h"
#include "queue.h"
#include "ts2pkt.h"
#include "pes2es.h"
class cMarkAdDemux
{
+
private:
cMarkAdTS2Pkt *ts2pkt;
cMarkAdPES2ES *pes2audioes;
@@ -32,14 +32,15 @@ private:
int min_needed;
int skip;
+ void GetVideoPTS(uchar *Data, int Count, unsigned int *Timestamp);
int GetMinNeeded(MarkAdPid Pid, uchar *Data, int Count, bool *Offcnt);
- void ProcessTS(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, int *PktLen);
- void ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, int *PktLen);
+ void ProcessTS(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *pkt);
+ void ProcessVDR(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *pkt);
public:
cMarkAdDemux();
~cMarkAdDemux();
void Clear();
- int Process(MarkAdPid Pid, uchar *Data, int Count, uchar **Pkt, int *PktLen, bool *Offcnt);
+ int Process(MarkAdPid Pid, uchar *Data, int Count, MarkAdPacket *pkt);
};
#endif
diff --git a/command/global.h b/command/global.h
index 8508f30..6bc6cb4 100644
--- a/command/global.h
+++ b/command/global.h
@@ -51,6 +51,14 @@ typedef unsigned char uchar;
#define MT_MOVED 0xE0
#define MT_ALL 0xFF
+typedef struct MarkAdPos
+{
+ int FrameNumberBefore;
+ int FrameNumberAfter;
+ char *CommentBefore;
+ char *CommentAfter;
+} MarkAdPos;
+
typedef struct MarkAdMark
{
char Type;
diff --git a/command/markad-standalone.cpp b/command/markad-standalone.cpp
index 3789290..51e0696 100644
--- a/command/markad-standalone.cpp
+++ b/command/markad-standalone.cpp
@@ -262,6 +262,14 @@ void cMarkAdStandalone::CheckFirstMark()
clMark *second=first->Next();
if (!second) return;
+ // if first and second mark is ASPECT/BORDER
+ // wait till its clear, if we use ASPECT
+ // or BORDER
+ int ft=first->type & 0xF0;
+ int st=second->type & 0xF0;
+ if (((ft==MT_BORDERCHANGE) && (st==MT_ASPECTCHANGE)) ||
+ ((st==MT_BORDERCHANGE) && (ft==MT_ASPECTCHANGE))) return;
+
if ((second->type & 0xF)==MT_START)
{
bool delsec=false;
@@ -439,6 +447,8 @@ void cMarkAdStandalone::AddMark(MarkAdMark *Mark)
{
case MT_START:
marks.DelAll();
+ // calculate new stop position based on new start
+ iStop=-(Mark->Position+(macontext.Info.Length*macontext.Video.Info.FramesPerSecond));
iStart=0;
break;
case MT_STOP:
@@ -640,7 +650,7 @@ void cMarkAdStandalone::SaveFrame(int frame)
fclose(pFile);
}
-void cMarkAdStandalone::CheckIndex(const char *Directory)
+void cMarkAdStandalone::CheckIndex()
{
// Here we check if the index is more
// advanced than our framecounter.
@@ -662,7 +672,7 @@ void cMarkAdStandalone::CheckIndex(const char *Directory)
if (maxframes<(framecnt+200))
{
if ((difftime(time(NULL),statbuf.st_mtime))>=10) return; // "old" file
- marks.Save(Directory,macontext.Video.Info.FramesPerSecond,isTS);
+ marks.Save(directory,macontext.Video.Info.FramesPerSecond,isTS);
sleep(WAITTIME); // now we sleep and hopefully the index will grow
waittime+=WAITTIME;
if (errno==EINTR) return;
@@ -683,25 +693,338 @@ void cMarkAdStandalone::CheckIndex(const char *Directory)
while (notenough);
}
-bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
+void cMarkAdStandalone::ChangeMarks(clMark **Mark1, clMark **Mark2, MarkAdPos *NewPos)
{
- if (!Directory) return false;
+ if (!NewPos) return;
+ if (!Mark1) return;
+ if (!*Mark1) return;
+ bool save=false;
+
+ if ((*Mark1)->position!=NewPos->FrameNumberBefore)
+ {
+ marks.Del(*Mark1);
+ *Mark1=marks.Add(MT_COMMON,NewPos->FrameNumberBefore,NewPos->CommentBefore);
+ save=true;
+ }
+ if (NewPos->CommentBefore) isyslog("%s",NewPos->CommentBefore);
+
+ if (Mark2 && (*Mark2) && (*Mark2)->position!=NewPos->FrameNumberAfter)
+ {
+ marks.Del(*Mark2);
+ *Mark2=marks.Add(MT_COMMON,NewPos->FrameNumberAfter,NewPos->CommentAfter);
+ if (NewPos->CommentAfter) isyslog("%s",NewPos->CommentAfter);
+ save=true;
+ }
+ if (save) marks.Save(directory,macontext.Video.Info.FramesPerSecond,isTS,true);
+}
+
+bool cMarkAdStandalone::ProcessFile2ndPass(clMark **Mark1, clMark **Mark2,int Number, off_t Offset,
+ int Frame, int Frames)
+{
+ if (!directory) return false;
if (!Number) return false;
+ if (!Frames) return false;
+ if (!decoder) return false;
+ if (!Mark1) return false;
+ if (!*Mark1) return false;
+
+ int pn; // process number 1=start mark, 2=before mark, 3=after mark
+ if (Mark1 && Mark2)
+ {
+ if (!(*Mark1) || !(*Mark2)) return false;
+ if (*Mark1==*Mark2) pn=1;
+ if (*Mark1!=*Mark2) pn=3;
+ }
+ else
+ {
+ pn=2;
+ }
+
+ if (!Reset(false))
+ {
+ // reset all, but marks
+ esyslog("failed resetting state");
+ return false;
+ }
+ iframe=Frame;
+ int actframe=Frame;
+ int framecounter=0;
+
+ MarkAdPos *pos=NULL;
+
+ while (framecounter<Frames)
+ {
+ if (abort) return false;
+
+ //const int datalen=8272;
+ const int datalen=319976;
+ uchar data[datalen];
+
+ char *fbuf;
+ if (isTS)
+ {
+ if (asprintf(&fbuf,"%s/%05i.ts",directory,Number)==-1) return false;
+ }
+ else
+ {
+ if (asprintf(&fbuf,"%s/%03i.vdr",directory,Number)==-1) return false;
+ }
+
+ int f=open(fbuf,O_RDONLY);
+ free(fbuf);
+ if (f==-1) return false;
+
+ int dataread;
+ if (pn==1)
+ {
+ dsyslog("processing file %05i (start mark)",Number);
+ }
+ else
+ {
+ dsyslog("processing file %05i %s",Number,(pn==3) ? "(after mark)" : "(before mark)");
+ }
+
+ if (lseek(f,Offset,SEEK_SET)!=Offset)
+ {
+ close(f);
+ 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))
+ {
+ MarkAdPacket pkt;
+
+ uchar *tspkt = data;
+ int tslen = dataread;
+
+ while (tslen>0)
+ {
+ int len=video_demux->Process(macontext.Info.VPid,tspkt,tslen,&pkt);
+ if (len<0)
+ {
+ esyslog("error demuxing video");
+ abort=true;
+ break;
+ }
+ else
+ {
+ if (pkt.Data)
+ {
+ bool dRes=false;
+ if (streaminfo->FindVideoInfos(&macontext,pkt.Data,pkt.Length))
+ {
+ actframe++;
+ framecnt2++;
+
+ if (macontext.Video.Info.Pict_Type==MA_I_TYPE)
+ {
+ lastiframe=iframe;
+ lastiframetime=iframetime;
+ if (macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264)
+ {
+ iframe=actframe;
+ }
+ else
+ {
+ iframe=actframe-1;
+ }
+ iframetime=pkt.Timestamp;
+ dRes=true;
+ }
+ }
+ if (pn>1) dRes=decoder->DecodeVideo(&macontext,pkt.Data,pkt.Length);
+ if (dRes)
+ {
+ if ((actframe-iframe)<=3)
+ {
+ if (pn>1) pos=video->Process2ndPass(lastiframe,Frames,(pn==2));
+ //SaveFrame(lastiframe);
+ framecounter++;
+ }
+ if ((pos) && (pn==3))
+ {
+ // found overlap
+ ChangeMarks(Mark1,Mark2,pos);
+ close(f);
+ return true;
+ }
+ }
+ }
+ tspkt+=len;
+ tslen-=len;
+ if (!pkt.Offcnt)
+ {
+ offset_add+=len;
+ }
+ else
+ {
+ offset+=offset_add;
+ offset+=len;
+ offset_add=0;
+ }
+ }
+ }
+ }
+
+ if ((mp2_demux) && (audio) && (pn!=3))
+ {
+ MarkAdPacket pkt;
+
+ uchar *tspkt = data;
+ int tslen = dataread;
+
+ while (tslen>0)
+ {
+ int len=mp2_demux->Process(macontext.Info.APid,tspkt,tslen,&pkt);
+ if (len<0)
+ {
+ esyslog("error demuxing mp2-audio");
+ break;
+ }
+ else
+ {
+ if (pkt.Data)
+ {
+ if (pkt.Timestamp) audiotime=pkt.Timestamp;
+
+ if (abs(audiotime-lastiframetime)<20000)
+ {
+ if (decoder->DecodeMP2(&macontext,pkt.Data,pkt.Length))
+ {
+ pos=audio->Process2ndPass(iframe);
+ if (pos) ChangeMarks(Mark1,NULL,pos);
+ }
+ }
+ }
+ tspkt+=len;
+ tslen-=len;
+ }
+ }
+ }
+
+ if (abort)
+ {
+ close(f);
+ return false;
+ }
- CheckIndex(Directory);
+ if (framecounter>Frames)
+ {
+ break;
+ }
+
+ }
+ close(f);
+ Number++;
+ Offset=0;
+ }
+ return true;
+}
+
+void cMarkAdStandalone::Process2ndPass()
+{
+ if (abort) return;
+ if (duplicate) return;
+ if (!decoder) return;
+
+ if (!macontext.Video.Info.FramesPerSecond)
+ macontext.Video.Info.FramesPerSecond=25;
+
+ if (!marks.Count())
+ {
+ marks.Load(directory,macontext.Video.Info.FramesPerSecond,isTS);
+ }
+
+ isyslog("2nd pass");
+
+ clMark *p1=NULL,*p2=NULL;
+
+ p1=marks.GetFirst();
+ if (p1->position>0)
+ {
+ 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);
+ }
+ }
+
+ if (marks.Count()<4) return; // here we cannot do much
+
+ p1=p1->Next();
+ if (p1) p2=p1->Next();
+
+ while ((p1) && (p2))
+ {
+ off_t offset;
+ int number,frame,iframes;
+ int frange=macontext.Video.Info.FramesPerSecond*120; // 40s + 80s
+
+ if (marks.ReadIndex(directory,isTS,p1->position-frange,frange,&number,&offset,&frame,&iframes))
+ {
+ if (!ProcessFile2ndPass(&p1,NULL,number,offset,frame,iframes)) break;
+
+ frange=macontext.Video.Info.FramesPerSecond*320; // 160s + 160s
+ if (marks.ReadIndex(directory,isTS,p2->position,frange,&number,&offset,&frame,&iframes))
+ {
+ if (!ProcessFile2ndPass(&p1,&p2,number,offset,frame,iframes)) break;
+ }
+ }
+
+ p1=p2->Next();
+ if (p1)
+ {
+ p2=p1->Next();
+ }
+ else
+ {
+ p2=NULL;
+ }
+ }
+}
+
+char *cMarkAdStandalone::Timestamp2HMS(unsigned int Timestamp)
+{
+ double val=(double) Timestamp/90000;
+ int h,m;
+ double s_ns;
+ h=(int) val/3600;
+ m=(int) (val-(3600*h))/60;
+ s_ns=val-(h*3600+m*60);
+ static char buf[20];
+ sprintf(buf,"%02d:%02d:%06.4f",h,m,s_ns);
+ return (char *) &buf;
+}
+
+bool cMarkAdStandalone::ProcessFile(int Number)
+{
+ if (!directory) return false;
+ if (!Number) return false;
+
+ CheckIndex();
if (abort) return false;
- const int datalen=385024;
+ //const int datalen=8272;
+ const int datalen=319976;
uchar data[datalen];
char *fbuf;
if (isTS)
{
- if (asprintf(&fbuf,"%s/%05i.ts",Directory,Number)==-1) return false;
+ if (asprintf(&fbuf,"%s/%05i.ts",directory,Number)==-1) return false;
}
else
{
- if (asprintf(&fbuf,"%s/%03i.vdr",Directory,Number)==-1) return false;
+ if (asprintf(&fbuf,"%s/%03i.vdr",directory,Number)==-1) return false;
}
int f=open(fbuf,O_RDONLY);
@@ -720,16 +1043,14 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
if ((video_demux) && (video) && (streaminfo))
{
- uchar *pkt;
- int pktlen;
- bool offcnt=false;
+ MarkAdPacket pkt;
uchar *tspkt = data;
int tslen = dataread;
while (tslen>0)
{
- int len=video_demux->Process(macontext.Info.VPid,tspkt,tslen,&pkt,&pktlen,&offcnt);
+ int len=video_demux->Process(macontext.Info.VPid,tspkt,tslen,&pkt);
if (len<0)
{
esyslog("error demuxing video");
@@ -738,50 +1059,75 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
}
else
{
- if (pkt)
+ if (pkt.Data)
{
bool dRes=false;
- if (streaminfo->FindVideoInfos(&macontext,pkt,pktlen))
+ if (streaminfo->FindVideoInfos(&macontext,pkt.Data,pkt.Length))
{
- if (!framecnt)
+ if ((macontext.Video.Info.Height) && (!noticeHEADER))
{
isyslog("%s %i%c",(macontext.Video.Info.Height>576) ? "HDTV" : "SDTV",
macontext.Video.Info.Height,
macontext.Video.Info.Interlaced ? 'i' : 'p');
+ noticeHEADER=true;
+ }
+
+ if (!framecnt)
+ {
AddStartMark();
+ nextPictType=MA_I_TYPE;
}
+
if (bGenIndex)
{
- marks.WriteIndex(Directory,isTS,offset,
- macontext.Video.Info.Pict_Type,Number);
+ if ((macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H262) ||
+ ((macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264) &&
+ (!macontext.Video.Info.Interlaced)))
+ {
+ nextPictType=macontext.Video.Info.Pict_Type;
+ }
+ marks.WriteIndex(directory,isTS,offset,nextPictType,Number);
}
+ nextPictType=macontext.Video.Info.Pict_Type;
framecnt++;
if (macontext.Video.Info.Pict_Type==MA_I_TYPE)
{
lastiframe=iframe;
+ lastiframetime=iframetime;
CheckStartStop(lastiframe);
if (lastiframe>chkLEFT) CheckInfoAspectRatio();
- iframe=framecnt-1;
+
+ if (macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264)
+ {
+ iframe=framecnt;
+ }
+ else
+ {
+ iframe=framecnt-1;
+ }
+ iframetime=pkt.Timestamp;
dRes=true;
}
}
- if ((decoder) && (bDecodeVideo)) dRes=decoder->DecodeVideo(&macontext,pkt,pktlen);
+ if ((decoder) && (bDecodeVideo)) dRes=decoder->DecodeVideo(&macontext,pkt.Data,pkt.Length);
if (dRes)
{
if ((framecnt-iframe)<=3)
{
- mark=video->Process(lastiframe);
- AddMark(mark);
+ //printf("VID %5i %s %x\n",lastiframe,Timestamp2HMS(lastiframetime),lastiframetime);
+
+ mark=video->Process(lastiframe,iframe);
+ if (mark) AddMark(mark);
//SaveFrame(lastiframe); // TODO: JUST FOR DEBUGGING!
}
}
}
tspkt+=len;
tslen-=len;
- if (!offcnt)
+ if (!pkt.Offcnt)
{
offset_add+=len;
}
@@ -797,15 +1143,14 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
if ((ac3_demux) && (streaminfo) && (audio))
{
- uchar *pkt;
- int pktlen;
+ MarkAdPacket pkt;
uchar *tspkt = data;
int tslen = dataread;
while (tslen>0)
{
- int len=ac3_demux->Process(macontext.Info.DPid,tspkt,tslen,&pkt,&pktlen,NULL);
+ int len=ac3_demux->Process(macontext.Info.DPid,tspkt,tslen,&pkt);
if (len<0)
{
esyslog("error demuxing ac3-audio");
@@ -813,59 +1158,23 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
}
else
{
- if (pkt)
+ if (pkt.Data)
{
- if (streaminfo->FindAC3AudioInfos(&macontext,pkt,pktlen))
+ if (streaminfo->FindAC3AudioInfos(&macontext,pkt.Data,pkt.Length))
{
if ((!isTS) && (!noticeVDR_AC3))
{
dsyslog("found AC3");
- if (mp2_demux)
- {
- delete mp2_demux;
- mp2_demux=NULL;
- }
noticeVDR_AC3=true;
}
- mark=audio->Process(lastiframe);
- AddMark(mark);
- }
- }
- tspkt+=len;
- tslen-=len;
- }
- }
- }
+ if (pkt.Timestamp) audiotime=pkt.Timestamp;
- if ((mp2_demux) && (decoder) && (audio) && (bDecodeAudio))
- {
- uchar *pkt;
- int pktlen;
-
- uchar *tspkt = data;
- int tslen = dataread;
-
- while (tslen>0)
- {
- int len=mp2_demux->Process(macontext.Info.APid,tspkt,tslen,&pkt,&pktlen,NULL);
- if (len<0)
- {
- esyslog("error demuxing mp2-audio");
- break;
- }
- else
- {
- if (pkt)
- {
- if (decoder->DecodeMP2(&macontext,pkt,pktlen))
- {
- if ((!isTS) && (!noticeVDR_MP2))
+ if (abs(audiotime-lastiframetime)<20000)
{
- dsyslog("found MP2");
- noticeVDR_MP2=true;
+ //printf("AC3 %5i %s %x\n",lastiframe,Timestamp2HMS(audiotime),audiotime);
+ mark=audio->Process(lastiframe,iframe);
+ if (mark) AddMark(mark);
}
- mark=audio->Process(lastiframe);
- AddMark(mark);
}
}
tspkt+=len;
@@ -880,7 +1189,7 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
return true;
}
- CheckIndex(Directory);
+ CheckIndex();
if (abort)
{
if (f!=-1) close(f);
@@ -891,55 +1200,60 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number)
return true;
}
-void cMarkAdStandalone::Reset()
+bool cMarkAdStandalone::Reset(bool FirstPass)
{
+ bool ret=true;
reprocess=false;
- framecnt=0;
+ if (FirstPass) framecnt=0;
lastiframe=0;
iframe=0;
+
+ lastiframetime=0;
+ iframetime=0;
+ audiotime=0;
+
+ fastexit=false;
+
iStart=0;
iStop=0;
chkLEFT=0;
chkRIGHT=0;
- marksAligned=false;
- marks.DelAll();
- marks.CloseIndex(directory,isTS);
+ if (FirstPass)
+ {
+ marksAligned=false;
+ marks.DelAll();
+ marks.CloseIndex(directory,isTS);
+ }
- memset(&macontext.Video.Info,0,sizeof(macontext.Video.Info));
- memset(&macontext.Audio.Info,0,sizeof(macontext.Audio.Info));
+ macontext.Video.Info.Pict_Type=0;
+ macontext.Video.Info.AspectRatio.Den=0;
+ macontext.Video.Info.AspectRatio.Num=0;
+ macontext.Audio.Info.Channels=0;
if (decoder)
{
- delete decoder;
- decoder = new cMarkAdDecoder(macontext.Info.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264,
- macontext.Info.APid.Num!=0,macontext.Info.DPid.Num!=0);
+ 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 (video) video->Clear();
if (audio) audio->Clear();
+ return ret;
}
-void cMarkAdStandalone::Process(const char *Directory)
+void cMarkAdStandalone::Process()
{
if (abort) return;
- struct timeval tv1,tv2;
- struct timezone tz;
-
- gettimeofday(&tv1,&tz);
-
- if (bBackupMarks) marks.Backup(Directory,isTS);
+ if (bBackupMarks) marks.Backup(directory,isTS);
for (int i=1; i<=MaxFiles; i++)
{
if (abort) break;
- if (!ProcessFile(Directory,i))
+ if (!ProcessFile(i))
{
break;
}
@@ -954,7 +1268,7 @@ void cMarkAdStandalone::Process(const char *Directory)
if (!abort)
{
- if ((lastiframe) && (!fastexit) && (iStop<0))
+ if ((lastiframe) && (!fastexit) && ((iStop<0) || (!tStart)))
{
char *buf;
MarkAdMark tempmark;
@@ -972,21 +1286,11 @@ void cMarkAdStandalone::Process(const char *Directory)
CheckLastMark();
CheckLogoMarks();
- gettimeofday(&tv2,&tz);
- time_t sec;
- suseconds_t usec;
- sec=tv2.tv_sec-tv1.tv_sec;
- usec=tv2.tv_usec-tv1.tv_usec;
- if (usec<0)
- {
- usec+=1000000;
- sec--;
- }
- marks.CloseIndex(Directory,isTS);
- if (marks.Save(Directory,macontext.Video.Info.FramesPerSecond,isTS))
+ marks.CloseIndex(directory,isTS);
+ if (marks.Save(directory,macontext.Video.Info.FramesPerSecond,isTS))
{
int iIndexError=false;
- if (marks.CheckIndex(Directory,isTS,bGenIndex ? framecnt : 0,&iIndexError))
+ if (marks.CheckIndex(directory,isTS,bGenIndex ? framecnt : 0,&iIndexError))
{
if (iIndexError)
{
@@ -996,11 +1300,9 @@ void cMarkAdStandalone::Process(const char *Directory)
{
case IERR_NOTFOUND:
isyslog("no index found");
-
break;
case IERR_TOOSHORT:
isyslog("index too short");
-
break;
default:
isyslog("index contains errors");
@@ -1026,36 +1328,20 @@ void cMarkAdStandalone::Process(const char *Directory)
}
}
}
- if (bGenIndex) marks.RemoveGeneratedIndex(Directory,isTS);
-
- SaveInfo(Directory);
-
- double etime,ftime=0,ptime=0;
- etime=sec+((double) usec/1000000)-waittime;
- if (etime>0) ftime=framecnt/etime;
- if (macontext.Video.Info.FramesPerSecond>0)
- ptime=ftime/macontext.Video.Info.FramesPerSecond;
- isyslog("processed time %.2fs, %i frames, %.1f fps, %.1f pps",
- etime,framecnt,ftime,ptime);
+ if (bGenIndex) marks.RemoveGeneratedIndex(directory,isTS);
+ if ((!bIgnoreAudioInfo) && (!bIgnoreVideoInfo)) SaveInfo();
}
}
-bool cMarkAdStandalone::SaveInfo(const char *Directory)
+bool cMarkAdStandalone::SaveInfo()
{
if ((!setVideo43) && (!setVideo169) && (!setAudio20) && (!setAudio51)) return true;
char *src,*dst;
- if (isTS)
- {
- if (asprintf(&src,"%s/info",Directory)==-1) return false;
- }
- else
- {
- if (asprintf(&src,"%s/info.vdr",Directory)==-1) return false;
- }
+ if (asprintf(&src,"%s/info%s",directory,isTS ? "" : ".vdr")==-1) return false;
- if (asprintf(&dst,"%s/info.bak",Directory)==-1)
+ if (asprintf(&dst,"%s/info.bak",directory)==-1)
{
free(src);
return false;
@@ -1082,6 +1368,8 @@ bool cMarkAdStandalone::SaveInfo(const char *Directory)
bool setAudio20_done=false;
bool setAudio51_done=false;
+ char lang[4]="";
+
bool err=false;
while (getline(&line,&length,r)!=-1)
{
@@ -1089,11 +1377,10 @@ bool cMarkAdStandalone::SaveInfo(const char *Directory)
{
int stream=0,type=0;
char descr[256]="";
- char lang[4]="";
+
int result=sscanf(line,"%*c %i %i %3c %250c",&stream,&type,(char *) &lang, (char *) &descr);
if ((result!=0) && (result!=EOF))
{
-
switch (stream)
{
case 1:
@@ -1163,21 +1450,23 @@ bool cMarkAdStandalone::SaveInfo(const char *Directory)
if (line) free(line);
line=lline;
+ if (lang[0]==0) strcpy(lang,"und");
+
if ((setVideo43) && (!setVideo43_done) && (!err))
{
- if (fprintf(w,"%s","X 1 01 und 4:3\n")<=0) err=true;
+ if (fprintf(w,"X 1 01 %s 4:3\n",lang)<=0) err=true;
}
if ((setVideo169) && (!setVideo169_done) && (!err))
{
- if (fprintf(w,"%s","X 1 03 und 16:9\n")<=0) err=true;
+ if (fprintf(w,"X 1 03 %s 16:9\n",lang)<=0) err=true;
}
if ((setAudio20) && (!setAudio20_done) && (!err))
{
- if (fprintf(w,"%s","X 2 05 und Dolby Digital 2.0\n")<=0) err=true;
+ if (fprintf(w,"X 2 05 %s Dolby Digital 2.0\n",lang)<=0) err=true;
}
if ((setAudio51) && (!setAudio51_done) && (!err))
{
- if (fprintf(w,"%s","X 2 05 und Dolby Digital 5.1\n")<=0) err=true;
+ if (fprintf(w,"X 2 05 %s Dolby Digital 5.1\n",lang)<=0) err=true;
}
if (line)
{
@@ -1199,7 +1488,7 @@ bool cMarkAdStandalone::SaveInfo(const char *Directory)
{
// if we are root, set fileowner to owner of 001.vdr/00001.ts file
char *spath=NULL;
- if (asprintf(&spath,"%s/%s",Directory,isTS ? "00001.ts" : "001.vdr")!=-1)
+ if (asprintf(&spath,"%s/%s",directory,isTS ? "00001.ts" : "001.vdr")!=-1)
{
struct stat statbuf;
if (!stat(spath,&statbuf))
@@ -1215,32 +1504,25 @@ bool cMarkAdStandalone::SaveInfo(const char *Directory)
return (err==false);
}
-bool cMarkAdStandalone::LoadInfo(const char *Directory)
+bool cMarkAdStandalone::LoadInfo()
{
char *buf;
- if (isTS)
- {
- if (asprintf(&buf,"%s/info",Directory)==-1) return false;
- }
- else
- {
- if (asprintf(&buf,"%s/info.vdr",Directory)==-1) return false;
- }
+ if (asprintf(&buf,"%s/info%s",directory,isTS ? "" : ".vdr")==-1) return false;
FILE *f;
f=fopen(buf,"r");
free(buf);
if (!f) return false;
- const char *timestr=strrchr(Directory,'/');
+ const char *timestr=strrchr(directory,'/');
if (timestr)
{
timestr++;
- if (!isdigit(*timestr)) timestr=Directory;
+ if (!isdigit(*timestr)) timestr=directory;
}
else
{
- timestr=Directory;
+ timestr=directory;
}
time_t now = time(NULL);
@@ -1253,6 +1535,7 @@ bool cMarkAdStandalone::LoadInfo(const char *Directory)
t.tm_year-=1900;
t.tm_mon--;
t.tm_sec=0;
+ t.tm_isdst=-1;
rStart=mktime(&t);
}
@@ -1373,7 +1656,7 @@ bool cMarkAdStandalone::LoadInfo(const char *Directory)
tStart=start-rStart;
if (tStart<0)
{
- isyslog("%s","start of broadcast truncated");
+ isyslog("broadcast start truncated by %ih %im",-tStart/3600,-tStart/60);
macontext.Info.Length+=tStart;
tStart=0;
}
@@ -1394,13 +1677,13 @@ bool cMarkAdStandalone::LoadInfo(const char *Directory)
}
}
-bool cMarkAdStandalone::CheckTS(const char *Directory)
+bool cMarkAdStandalone::CheckTS()
{
MaxFiles=0;
isTS=false;
- if (!Directory) return false;
+ if (!directory) return false;
char *buf;
- if (asprintf(&buf,"%s/00001.ts",Directory)==-1) return false;
+ if (asprintf(&buf,"%s/00001.ts",directory)==-1) return false;
struct stat statbuf;
if (stat(buf,&statbuf)==-1)
{
@@ -1410,7 +1693,7 @@ bool cMarkAdStandalone::CheckTS(const char *Directory)
return false;
}
free(buf);
- if (asprintf(&buf,"%s/001.vdr",Directory)==-1) return false;
+ if (asprintf(&buf,"%s/001.vdr",directory)==-1) return false;
if (stat(buf,&statbuf)==-1)
{
free(buf);
@@ -1429,10 +1712,10 @@ bool cMarkAdStandalone::CheckTS(const char *Directory)
return true;
}
-bool cMarkAdStandalone::CheckVDRHD(const char *Directory)
+bool cMarkAdStandalone::CheckVDRHD()
{
char *buf;
- if (asprintf(&buf,"%s/001.vdr",Directory)==-1) return false;
+ if (asprintf(&buf,"%s/001.vdr",directory)==-1) return false;
int fd=open(buf,O_RDONLY);
free(buf);
@@ -1460,10 +1743,10 @@ bool cMarkAdStandalone::CheckVDRHD(const char *Directory)
return false;
}
-bool cMarkAdStandalone::CheckPATPMT(const char *Directory)
+bool cMarkAdStandalone::CheckPATPMT()
{
char *buf;
- if (asprintf(&buf,"%s/00001.ts",Directory)==-1) return false;
+ if (asprintf(&buf,"%s/00001.ts",directory)==-1) return false;
int fd=open(buf,O_RDONLY);
free(buf);
@@ -1596,10 +1879,10 @@ bool cMarkAdStandalone::RegenerateIndex()
return true;
}
-bool cMarkAdStandalone::CreatePidfile(const char *Directory)
+bool cMarkAdStandalone::CreatePidfile()
{
char *buf=NULL;
- if (asprintf(&buf,"%s/markad.pid",Directory)==-1) return false;
+ if (asprintf(&buf,"%s/markad.pid",directory)==-1) return false;
// check for other running markad process
FILE *oldpid=fopen(buf,"r");
@@ -1633,7 +1916,7 @@ bool cMarkAdStandalone::CreatePidfile(const char *Directory)
{
// if we are root, set fileowner to owner of directory
struct stat statbuf;
- if (!stat(Directory,&statbuf))
+ if (!stat(directory,&statbuf))
{
if (chown(buf,statbuf.st_uid, statbuf.st_gid)) {};
}
@@ -1647,10 +1930,13 @@ bool cMarkAdStandalone::CreatePidfile(const char *Directory)
return true;
}
-void cMarkAdStandalone::RemovePidfile(const char *Directory)
+void cMarkAdStandalone::RemovePidfile()
{
+ if (!directory) return;
+ if (duplicate) return;
+
char *buf;
- if (asprintf(&buf,"%s/markad.pid",Directory)!=-1)
+ if (asprintf(&buf,"%s/markad.pid",directory)!=-1)
{
unlink(buf);
free(buf);
@@ -1662,7 +1948,7 @@ const char cMarkAdStandalone::frametypes[8]={'?','I','P','B','D','S','s','b'};
cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, int LogoExtraction,
int LogoWidth, int LogoHeight, bool DecodeVideo,
bool DecodeAudio, int IgnoreInfo,
- const char *LogoDir, const char *MarkFileName, bool ASD,
+ const char *LogoDir, const char *MarkFileName,
bool noPid, bool OSD, const char *SVDRPHost, int SVDRPPort,
bool Before, bool GenIndex)
{
@@ -1690,6 +1976,7 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, in
noticeVDR_MP2=false;
noticeVDR_AC3=false;
+ noticeHEADER=false;
sleepcnt=0;
waittime=0;
@@ -1702,7 +1989,6 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, in
macontext.Options.LogoExtraction=LogoExtraction;
macontext.Options.LogoWidth=LogoWidth;
macontext.Options.LogoHeight=LogoHeight;
- macontext.Audio.Options.AudioSilenceDetection=ASD;
bDecodeVideo=DecodeVideo;
bDecodeAudio=DecodeAudio;
@@ -1774,37 +2060,31 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, in
if (!noPid)
{
- CreatePidfile(Directory);
+ CreatePidfile();
if (abort) return;
}
if (Before) sleep(10);
- if (!CheckTS(Directory)) return;
+ if (!CheckTS()) return;
if (isTS)
{
- if (!CheckPATPMT(Directory))
+ if (!CheckPATPMT())
{
esyslog("no PAT/PMT found -> nothing to process");
abort=true;
- }
- if (!macontext.Audio.Options.AudioSilenceDetection)
- {
- macontext.Info.APid.Num=0;
+ return;
}
if (asprintf(&indexFile,"%s/index",Directory)==-1) indexFile=NULL;
}
else
{
- if (macontext.Audio.Options.AudioSilenceDetection)
- {
- macontext.Info.APid.Num=-1;
- }
+ macontext.Info.APid.Num=-1;
macontext.Info.DPid.Num=-1;
macontext.Info.VPid.Num=-1;
- if (CheckVDRHD(Directory))
+ if (CheckVDRHD())
{
macontext.Info.VPid.Type=MARKAD_PIDTYPE_VIDEO_H264;
}
@@ -1815,7 +2095,7 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, in
if (asprintf(&indexFile,"%s/index.vdr",Directory)==-1) indexFile=NULL;
}
- if (!LoadInfo(Directory))
+ if (!LoadInfo())
{
if (bDecodeVideo)
{
@@ -1827,7 +2107,7 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, in
}
if (tStart) isyslog("pre-timer %is",tStart);
- if (macontext.Info.Length) isyslog("broadcast length %is",macontext.Info.Length);
+ if (macontext.Info.Length) isyslog("broadcast length %ih %im",macontext.Info.Length/3600,macontext.Info.Length/60);
if (title[0])
{
@@ -1904,14 +2184,40 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory, bool BackupMarks, in
}
framecnt=0;
+ framecnt2=0;
lastiframe=0;
iframe=0;
+ lastiframetime=0;
+ iframetime=0;
+ audiotime=0;
chkLEFT=0;
chkRIGHT=0;
+ gettimeofday(&tv1,&tz);
}
cMarkAdStandalone::~cMarkAdStandalone()
{
+ if ((!abort) && (!duplicate))
+ {
+ gettimeofday(&tv2,&tz);
+ time_t sec;
+ suseconds_t usec;
+ sec=tv2.tv_sec-tv1.tv_sec;
+ usec=tv2.tv_usec-tv1.tv_usec;
+ if (usec<0)
+ {
+ usec+=1000000;
+ sec--;
+ }
+ double etime,ftime=0,ptime=0;
+ etime=sec+((double) usec/1000000)-waittime;
+ if (etime>0) ftime=(framecnt+framecnt2)/etime;
+ if (macontext.Video.Info.FramesPerSecond>0)
+ ptime=ftime/macontext.Video.Info.FramesPerSecond;
+ isyslog("processed time %.2fs, %i/%i frames, %.1f fps, %.1f pps",
+ etime,framecnt,framecnt2,ftime,ptime);
+ }
+
if (osd)
{
if (abort)
@@ -1936,7 +2242,7 @@ cMarkAdStandalone::~cMarkAdStandalone()
if (streaminfo) delete streaminfo;
if (osd) delete osd;
- if ((directory) && (!duplicate)) RemovePidfile(directory);
+ RemovePidfile();
}
bool isnumber(const char *s)
@@ -1989,8 +2295,6 @@ int usage()
" markad sends an OSD-Message for start and end\n"
"-V --version\n"
" print version-info and exit\n"
- " --asd\n"
- " enable audio silence detecion\n"
" --markfile=<markfilename>\n"
" set a different markfile-name\n"
" --online[=1|2] (default is 1)\n"
@@ -2000,6 +2304,8 @@ int usage()
" live-recordings are identified by having a '@' in the\n"
" filename so the entry 'Mark instant recording' in the menu\n"
" 'Setup - Recording' of the vdr should be set to 'yes'\n"
+ " --pass2only\n"
+ " process only second pass, fine adjustment or marks\n"
" --svdrphost=<ip/hostname> (default is 127.0.0.1)\n"
" ip/hostname of a remote VDR for OSD messages\n"
" --svdrpport=<port> (default is 2001)\n"
@@ -2064,7 +2370,6 @@ int main(int argc, char *argv[])
int c;
bool bAfter=false,bBefore=false,bEdited=false;
bool bFork=false,bNice=false,bImmediateCall=false;
- bool bASD=false;
int niceLevel = 19;
char *recDir=NULL;
char *tok,*str;
@@ -2081,6 +2386,7 @@ int main(int argc, char *argv[])
bool bDecodeAudio=true;
int ignoreInfo=0;
bool bGenIndex=false;
+ bool bPass2Only=false;
int online=0;
strcpy(logoDirectory,"/var/lib/markad");
@@ -2109,10 +2415,14 @@ int main(int argc, char *argv[])
{"markfile",1,0,1},
{"nopid",0,0,5},
{"online",2,0,4},
+ {"pass2only",0,0,10},
{"pass3only",0,0,7},
{"svdrphost",1,0,8},
{"svdrpport",1,0,9},
{"testmode",0,0,3},
+ {"vpid",1,0,11},
+ {"apid",1,0,12},
+ {"dpid",1,0,13},
{"backupmarks", 0, 0, 'B'},
{"scenechangedetection", 0, 0, 'C'},
@@ -2324,7 +2634,6 @@ int main(int argc, char *argv[])
break;
case 6: // --asd
- bASD=true;
break;
case 7: // --pass3only
@@ -2347,6 +2656,10 @@ int main(int argc, char *argv[])
}
break;
+ case 10: // --pass2only
+ bPass2Only=true;
+ break;
+
default:
printf ("? getopt returned character code 0%o ? (option_index %d)\n", c,option_index);
}
@@ -2521,11 +2834,12 @@ int main(int argc, char *argv[])
cmasta = new cMarkAdStandalone(recDir,bBackupMarks, logoExtraction, logoWidth, logoHeight,
bDecodeVideo,bDecodeAudio,ignoreInfo,
- logoDirectory,markFileName,bASD,bNoPid,bOSD,svdrphost,
+ logoDirectory,markFileName,bNoPid,bOSD,svdrphost,
svdrpport,bBefore,bGenIndex);
if (!cmasta) return -1;
- cmasta->Process(recDir);
+ if (!bPass2Only) cmasta->Process();
+ cmasta->Process2ndPass();
delete cmasta;
return 0;
}
diff --git a/command/markad-standalone.h b/command/markad-standalone.h
index dcf4769..3af97d7 100644
--- a/command/markad-standalone.h
+++ b/command/markad-standalone.h
@@ -166,22 +166,33 @@ unsigned Descriptor_Length:
char title[80],*ptitle;
- bool CreatePidfile(const char *Directory);
- void RemovePidfile(const char *Directory);
+ bool CreatePidfile();
+ void RemovePidfile();
bool duplicate; // are we a dup?
bool isTS;
int MaxFiles;
+
int lastiframe;
int iframe;
+
+ unsigned int iframetime;
+ unsigned int lastiframetime;
+ unsigned int audiotime;
+
int framecnt;
+ int framecnt2; // 2nd pass
+
bool abort;
bool fastexit;
bool reprocess;
int waittime;
+ struct timeval tv1,tv2;
+ struct timezone tz;
bool noticeVDR_MP2;
bool noticeVDR_AC3;
+ bool noticeHEADER;
bool bDecodeVideo;
bool bDecodeAudio;
@@ -198,10 +209,12 @@ unsigned Descriptor_Length:
bool setVideo43; // set video to 4:3 in info
bool setVideo169; // set video to 16:9 in info
+ int nextPictType;
+
int chkLEFT;
int chkRIGHT;
- void CheckIndex(const char *Directory);
+ void CheckIndex();
char *indexFile;
int sleepcnt;
@@ -219,25 +232,31 @@ unsigned Descriptor_Length:
void CheckLogoMarks();
void AddStartMark();
void AddMark(MarkAdMark *Mark);
- void Reset();
+ bool Reset(bool FirstPass=true);
+ void ChangeMarks(clMark **Mark1, clMark **Mark2, MarkAdPos *NewPos);
- bool CheckVDRHD(const char *Directory);
- bool CheckPATPMT(const char *Directory);
- bool CheckTS(const char *Directory);
- bool LoadInfo(const char *Directory);
- bool SaveInfo(const char *Directory);
+ bool CheckVDRHD();
+ bool CheckPATPMT();
+ bool CheckTS();
+ bool LoadInfo();
+ bool SaveInfo();
bool RegenerateIndex();
- bool ProcessFile(const char *Directory, int Number);
+ bool ProcessFile2ndPass(clMark **Mark1, clMark **Mark2, int Number, off_t Offset, int Frame, int Frames);
+ bool ProcessFile(int Number);
+
+ char *Timestamp2HMS(unsigned int Timestamp);
+
public:
void SetAbort()
{
abort=true;
}
- void Process(const char *Directory);
+ void Process2ndPass();
+ void Process();
cMarkAdStandalone(const char *Directory, bool BackupMarks, int LogoExtraction,
int LogoWidth, int LogoHeight, bool DecodeVideo,
bool DecodeAudio, int IgnoreInfo,
- const char *LogoDir, const char *MarkFileName, bool ASD,
+ const char *LogoDir, const char *MarkFileName,
bool noPid, bool OSD, const char *SVDRPHost, int SVDRPPort,
bool Before, bool GenIndex);
diff --git a/command/marks.cpp b/command/marks.cpp
index 5c9e25e..c7c8120 100644
--- a/command/marks.cpp
+++ b/command/marks.cpp
@@ -282,8 +282,20 @@ clMark *clMarks::Add(int Type, int Position,const char *Comment)
// add between two marks
newmark->Set(mark,mark->Next());
mark->SetNext(newmark);
+ newmark->Next()->SetPrev(newmark);
break;
}
+ else
+ {
+ if ((Position<mark->position) && (mark==first))
+ {
+ // add as first mark
+ first=newmark;
+ mark->SetPrev(newmark);
+ newmark->SetNext(mark);
+ break;
+ }
+ }
}
mark=mark->Next();
}
@@ -317,6 +329,111 @@ void clMarks::RemoveGeneratedIndex(const char *Directory, bool isTS)
return;
}
+bool clMarks::ReadIndex(const char *Directory, bool isTS, int FrameNumber, int Range, int *Number,
+ off_t *Offset, int *Frame, int *iFrames)
+{
+ if (!Offset) return false;
+ if (!Number) return false;
+ if (!Frame) return false;
+ if (!iFrames) return false;
+ *Offset=0;
+ *Number=0;
+ *Frame=0;
+ *iFrames=0;
+
+ char *ipath=NULL;
+ if (asprintf(&ipath,"%s/index%s",Directory,isTS ? "" : ".vdr")==-1) return false;
+ int ifd=open(ipath,O_RDONLY);
+ free(ipath);
+ if (ifd==-1) return false;
+
+ if (isTS)
+ {
+ struct tIndexTS IndexTS;
+ off_t pos=FrameNumber*sizeof(IndexTS);
+ if (lseek(ifd,pos,SEEK_SET)!=pos)
+ {
+ close(ifd);
+ return false;
+ }
+ do
+ {
+ if (read(ifd,&IndexTS,sizeof(IndexTS))!=sizeof(IndexTS))
+ {
+ close(ifd);
+ return false;
+ }
+ if (IndexTS.independent)
+ {
+ *Offset=IndexTS.offset;
+ *Number=IndexTS.number;
+ pos=lseek(ifd,0,SEEK_CUR);
+ *Frame=(int) (pos/sizeof(IndexTS))-1;
+ }
+ }
+ while (!IndexTS.independent);
+
+ int cnt=0;
+ do
+ {
+ if (read(ifd,&IndexTS,sizeof(IndexTS))!=sizeof(IndexTS))
+ {
+ close(ifd);
+ if (!*iFrames) return false;
+ (*iFrames)-=2; // just to be safe
+ return true;
+ }
+ if (IndexTS.independent) (*iFrames)++;
+ cnt++;
+ }
+ while (cnt<Range);
+ }
+ else
+ {
+ struct tIndexVDR IndexVDR;
+ off_t pos=FrameNumber*sizeof(IndexVDR);
+ if (lseek(ifd,pos,SEEK_SET)!=pos)
+ {
+ close(ifd);
+ return false;
+ }
+ do
+ {
+ if (read(ifd,&IndexVDR,sizeof(IndexVDR))!=sizeof(IndexVDR))
+ {
+ close(ifd);
+ return false;
+ }
+ if (IndexVDR.type==1)
+ {
+ *Offset=IndexVDR.offset;
+ *Number=IndexVDR.number;
+ pos=lseek(ifd,0,SEEK_CUR);
+ *Frame=(int) (pos/sizeof(IndexVDR))-1;
+ }
+ }
+ while (IndexVDR.type!=1);
+
+ int cnt=0;
+ do
+ {
+ if (read(ifd,&IndexVDR,sizeof(IndexVDR))!=sizeof(IndexVDR))
+ {
+ close(ifd);
+ if (!*iFrames) return false;
+ (*iFrames)-=2; // just to be safe
+ return true;
+ }
+ if (IndexVDR.type==1) (*iFrames)++;
+ cnt++;
+ }
+ while (cnt<Range);
+ }
+ close(ifd);
+ if (!*iFrames) return false;
+ return true;
+}
+
void clMarks::WriteIndex(const char *Directory, bool isTS, uint64_t Offset,
int FrameType, int Number)
{
@@ -328,6 +445,7 @@ void clMarks::WriteIndex(const char *Directory, bool isTS, uint64_t Offset,
free(ipath);
if (indexfd==-1) return;
Offset=0;
+ FrameType=1;
}
if (isTS)
{
@@ -481,10 +599,55 @@ bool clMarks::Backup(const char *Directory, bool isTS)
return (ret==0);
}
-bool clMarks::Save(const char *Directory, double FrameRate, bool isTS)
+bool clMarks::Load(const char *Directory, double FrameRate, bool isTS)
+{
+ char *fpath=NULL;
+ if (asprintf(&fpath,"%s/%s%s",Directory,filename,isTS ? "" : ".vdr")==-1) return false;
+
+ FILE *mf;
+ mf=fopen(fpath,"r+");
+ free(fpath);
+ if (!mf) return false;
+
+ char *line=NULL;
+ size_t length;
+ int h, m, s, f;
+
+ while (getline(&line,&length,mf)!=-1)
+ {
+ char descr[256]="";
+ f=1;
+ int n=sscanf(line,"%d:%d:%d.%d %80c",&h,&m,&s,&f,(char *) &descr);
+ if (n==1)
+ {
+ Add(0,h);
+ }
+ if (n>=3)
+ {
+ int pos=int(round((h*3600+m*60+s)*FrameRate))+f-1;
+ if (n<=4)
+ {
+ Add(0,pos);
+ }
+ else
+ {
+ char *lf=strchr(descr,10);
+ if (lf) *lf=0;
+ char *cr=strchr(descr,13);
+ if (cr) *cr=0;
+ Add(0,pos,descr);
+ }
+ }
+ }
+ if (line) free(line);
+ fclose(mf);
+ return true;
+}
+
+bool clMarks::Save(const char *Directory, double FrameRate, bool isTS, bool Force)
{
if (!first) return false;
- if (savedcount==count) return false;
+ if ((savedcount==count) && (!Force)) return false;
char *fpath=NULL;
if (asprintf(&fpath,"%s/%s%s",Directory,filename,isTS ? "" : ".vdr")==-1) return false;
diff --git a/command/marks.h b/command/marks.h
index 94ebb91..8deae5b 100644
--- a/command/marks.h
+++ b/command/marks.h
@@ -107,13 +107,16 @@ public:
return last;
}
bool Backup(const char *Directory, bool isTS);
- bool Save(const char *Directory, double FrameRate, bool isTS);
+ bool Load(const char *Directory, double FrameRate, bool isTS);
+ bool Save(const char *Directory, double FrameRate, bool isTS, bool Force=false);
#define IERR_NOTFOUND 1
#define IERR_TOOSHORT 2
#define IERR_SEEK 3
#define IERR_READ 4
#define IERR_FRAME 5
bool CheckIndex(const char *Directory, bool isTS, int FrameCnt, int *IndexError);
+ bool ReadIndex(const char *Directory, bool isTS, int FrameNumber, int Range, int *Number,
+ off_t *Offset, int *Frame, int *iFrames);
void WriteIndex(const char *Directory, bool isTS, uint64_t Offset,
int FrameType, int Number);
void CloseIndex(const char *Directory, bool isTS);
diff --git a/command/pes2es.cpp b/command/pes2es.cpp
index d0287d0..4c74e5f 100644
--- a/command/pes2es.cpp
+++ b/command/pes2es.cpp
@@ -10,7 +10,7 @@
#include <string.h>
#include "pes2es.h"
-
+#include <stdio.h>
cMarkAdPES2ES::cMarkAdPES2ES(const char *QueueName, int QueueSize)
{
queue = new cMarkAdPaketQueue(QueueName,QueueSize);
@@ -27,11 +27,9 @@ void cMarkAdPES2ES::Clear()
if (queue) queue->Clear();
}
-void cMarkAdPES2ES::Process(MarkAdPid Pid, uchar *PESData, int PESSize, uchar **ESData, int *ESSize)
+void cMarkAdPES2ES::Process(MarkAdPid Pid, uchar *PESData, int PESSize, MarkAdPacket *ESPkt)
{
- if ((!ESData) || (!ESSize) || (!queue)) return;
- *ESData=NULL;
- *ESSize=0;
+ if (!ESPkt) return;
if (PESData)
{
@@ -90,6 +88,20 @@ void cMarkAdPES2ES::Process(MarkAdPid Pid, uchar *PESData, int PESSize, uchar **
peshdropt->Length;
buf=&PESData[bpos];
buflen=PESSize-bpos;
+ if (peshdropt->PTSDTS>1)
+ {
+ struct PESHDROPTPTS *peshdroptpts=(struct PESHDROPTPTS *) &PESData[sizeof(struct PESHDR)+
+ sizeof(struct PESHDROPT)];
+
+ if (peshdroptpts->Marker1 && peshdroptpts->Marker2 && peshdroptpts->Marker3)
+ {
+ unsigned int pts=0;
+ pts|=((peshdroptpts->PTS29_15_H<<7|peshdroptpts->PTS29_15_L)<<15);
+ pts|=(peshdroptpts->PTS14_0_H<<7|peshdroptpts->PTS14_0_L);
+ pts|=(peshdroptpts->PTS32_30<<30);
+ ESPkt->Timestamp=pts;
+ }
+ }
}
else
{
@@ -99,6 +111,6 @@ void cMarkAdPES2ES::Process(MarkAdPid Pid, uchar *PESData, int PESSize, uchar **
}
queue->Put(buf,buflen);
}
- if (type) *ESData=queue->GetPacket(ESSize,type);
+ if (type) ESPkt->Data=queue->GetPacket(&ESPkt->Length,type);
return;
}
diff --git a/command/pes2es.h b/command/pes2es.h
index c2c08e6..bfeaaaa 100644
--- a/command/pes2es.h
+++ b/command/pes2es.h
@@ -15,60 +15,82 @@ typedef unsigned char uchar;
#include "global.h"
#include "queue.h"
-class cMarkAdPES2ES
+struct PESHDR
{
-private:
- struct PESHDR
- {
- uchar Sync1;
- uchar Sync2;
- uchar Sync3;
- uchar StreamID;
- uchar LenH;
- uchar LenL;
- };
+ uchar Sync1;
+ uchar Sync2;
+ uchar Sync3;
+ uchar StreamID;
+ uchar LenH;
+ uchar LenL;
+};
#pragma pack(1)
- struct PESHDROPT
- {
+struct PESHDROPT
+{
unsigned OOC:
- 1;
+ 1;
unsigned CY:
- 1;
+ 1;
unsigned DAI:
- 1;
+ 1;
unsigned PESP:
- 1;
+ 1;
unsigned PESSC:
- 2;
+ 2;
unsigned MarkerBits:
- 2;
+ 2;
unsigned EXT:
- 1;
+ 1;
unsigned CRC:
- 1;
+ 1;
unsigned ACI:
- 1;
+ 1;
unsigned TM:
- 1;
+ 1;
unsigned RATE:
- 1;
+ 1;
unsigned ESCR:
- 1;
-unsigned TSF:
- 2;
+ 1;
+unsigned PTSDTS:
+ 2;
unsigned Length:
- 8;
- };
+ 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, uchar **ESData, int *ESSize);
+ void Process(MarkAdPid Pid, uchar *PESData, int PESSize, MarkAdPacket *ESPkt);
};
#endif
diff --git a/command/queue.cpp b/command/queue.cpp
index 81c0287..4f4eaa0 100644
--- a/command/queue.cpp
+++ b/command/queue.cpp
@@ -361,32 +361,19 @@ uchar *cMarkAdPaketQueue::GetPacket(int *Size, int Type)
*Size=0;
if (Length()<4) return NULL;
- if ((Type==MA_PACKET_H264) && (pktinfo.pktsyncsize>5) && (pktinfo.pkthdr!=-1))
- {
- // ignore PES paket
- pktinfo.pkthdr=-1;
- outptr+=pktinfo.pktsyncsize;
- }
-
if (pktinfo.pkthdr==-1)
{
scanner=0xFFFFFFFF;
switch (Type)
{
case MA_PACKET_AC3:
- pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize, true);
+ pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,true);
break;
case MA_PACKET_MP2:
- pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize, false);
+ pktinfo.pkthdr=FindAudioHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,false);
break;
case MA_PACKET_H264:
pktinfo.pkthdr=FindPktHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,true);
- if (pktinfo.pktsyncsize>5)
- {
- // ignore PES paket
- pktinfo.pkthdr=-1;
- outptr+=pktinfo.pktsyncsize;
- }
break;
default:
pktinfo.pkthdr=FindPktHeader(0,&pktinfo.streamsize,&pktinfo.pktsyncsize,false);
@@ -418,16 +405,16 @@ uchar *cMarkAdPaketQueue::GetPacket(int *Size, int Type)
switch (Type)
{
case MA_PACKET_AC3:
- pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize, true);
+ pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize,true);
break;
case MA_PACKET_MP2:
- pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize, false);
+ pkthdr=FindAudioHeader(scannerstart,&streamsize,&pktsyncsize,false);
break;
case MA_PACKET_H264:
- pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize, true);
+ pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize,true);
break;
default:
- pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize, false);
+ pkthdr=FindPktHeader(scannerstart,&streamsize,&pktsyncsize,false);
break;
}
diff --git a/command/queue.h b/command/queue.h
index 09257fd..8f40ac3 100644
--- a/command/queue.h
+++ b/command/queue.h
@@ -14,6 +14,14 @@
typedef unsigned char uchar;
#endif
+typedef struct MarkAdPacket
+{
+ uchar *Data;
+ int Length;
+ unsigned int Timestamp;
+ bool Offcnt;
+} MarkAdPacket;
+
class cMarkAdPaketQueue
{
struct MP2HDR
diff --git a/command/streaminfo.cpp b/command/streaminfo.cpp
index 877eddd..583be70 100644
--- a/command/streaminfo.cpp
+++ b/command/streaminfo.cpp
@@ -17,8 +17,7 @@ cMarkAdStreamInfo::cMarkAdStreamInfo()
void cMarkAdStreamInfo::Clear()
{
- memset(&H264,0,sizeof(H264));
- H264.frame_num=-1;
+ H264skiptoggle=false;
}
bool cMarkAdStreamInfo::FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen)
@@ -131,10 +130,29 @@ bool cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt,
if (nalu==NAL_AUD)
{
+ if (!maContext->Video.Info.Width) return false;
if (pkt[5]==0x10)
{
- H264.primary_pic_typeI=true;
+ maContext->Video.Info.Pict_Type=MA_I_TYPE;
+ }
+ else
+ {
+ maContext->Video.Info.Pict_Type=0;
}
+ if (!maContext->Video.Info.Interlaced)
+ {
+ // this is very crude, drop every second "frame"
+ if (H264skiptoggle)
+ {
+ H264skiptoggle=false;
+ return false;
+ }
+ else
+ {
+ H264skiptoggle=true;
+ }
+ }
+ return true;
}
if (nalu==NAL_SPS)
@@ -181,7 +199,8 @@ bool cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt,
}
}
}
- H264.log2_max_frame_num=bs.getUeGolomb()+4; // log2_max_frame_num_minus4
+ // H264.log2_max_frame_num=bs.getUeGolomb()+4;
+ bs.skipUeGolomb(); // log2_max_frame_num_minus4
pic_order_cnt_type = bs.getUeGolomb(); // pic_order_cnt_type
if (pic_order_cnt_type == 0)
bs.skipUeGolomb(); // log2_max_pic_order_cnt_lsb_minus4
@@ -257,60 +276,60 @@ bool cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt,
frame_rate = time_scale / (2*num_units_in_tick);
if (frame_mbs_only_flag) frame_rate/=2;
}
- //bs.skipBit(); // fixed_frame_rate_flag
+ bs.skipBit(); // fixed_frame_rate_flag
}
- /*
- int nal_hrd_parameters_present_flag = bs.getBit(); // nal_hrd_parameters_present_flag
- if (nal_hrd_parameters_present_flag)
- {
- int cpb_cnt_minus1;
- cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1
- bs.skipBits(4); // bit_rate_scale
- bs.skipBits(4); // cpb_size_scale
- for (int i = 0; i <= cpb_cnt_minus1; i++)
- {
- bs.skipUeGolomb(); // bit_rate_value_minus1[i]
- bs.skipUeGolomb(); // cpb_size_value_minus1[i]
- bs.skipBit(); // cbr_flag[i]
- }
- bs.skipBits(5); // initial_cpb_removal_delay_length_minus1
- bs.skipBits(5); // cpb_removal_delay_length_minus1
- bs.skipBits(5); // dpb_output_delay_length_minus1
- bs.skipBits(5); // time_offset_length
- }
- int vlc_hrd_parameters_present_flag = bs.getBit(); // vlc_hrd_parameters_present_flag
- if (vlc_hrd_parameters_present_flag)
- {
- int cpb_cnt_minus1;
- cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1
- bs.skipBits(4); // bit_rate_scale
- bs.skipBits(4); // cpb_size_scale
- for (int i = 0; i <= cpb_cnt_minus1; i++)
- {
- bs.skipUeGolomb(); // bit_rate_value_minus1[i]
- bs.skipUeGolomb(); // cpb_size_value_minus1[i]
- bs.skipBit(); // cbr_flag[i]
- }
- bs.skipBits(5); // initial_cpb_removal_delay_length_minus1
- bs.skipBits(5); // cpb_removal_delay_length_minus1
- bs.skipBits(5); // dpb_output_delay_length_minus1
- bs.skipBits(5); // time_offset_length
- }
- cpb_dpb_delays_present_flag = (nal_hrd_parameters_present_flag | vlc_hrd_parameters_present_flag);
- if (cpb_dpb_delays_present_flag)
- bs.skipBit(); // low_delay_hrd_flag
- bs.skipBit(); // pic_struct_present_flag
- if (bs.getBit()) // bitstream_restriction_flag
- {
- bs.skipBit(); // motion_vectors_over_pic_boundaries_flag
- bs.skipUeGolomb(); // max_bytes_per_pic_denom
- bs.skipUeGolomb(); // max_bits_per_mb_denom
- bs.skipUeGolomb(); // log2_max_mv_length_horizontal
- bs.skipUeGolomb(); // log2_max_mv_length_vertical
- bs.skipUeGolomb(); // num_reorder_frames
- bs.skipUeGolomb(); // max_dec_frame_buffering
- }
- */
+#if 0
+ int nal_hrd_parameters_present_flag = bs.getBit(); // nal_hrd_parameters_present_flag
+ if (nal_hrd_parameters_present_flag)
+ {
+ int cpb_cnt_minus1;
+ cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1
+ bs.skipBits(4); // bit_rate_scale
+ bs.skipBits(4); // cpb_size_scale
+ for (int i = 0; i <= cpb_cnt_minus1; i++)
+ {
+ bs.skipUeGolomb(); // bit_rate_value_minus1[i]
+ bs.skipUeGolomb(); // cpb_size_value_minus1[i]
+ bs.skipBit(); // cbr_flag[i]
+ }
+ bs.skipBits(5); // initial_cpb_removal_delay_length_minus1
+ bs.skipBits(5); // cpb_removal_delay_length_minus1
+ bs.skipBits(5); // dpb_output_delay_length_minus1
+ bs.skipBits(5); // time_offset_length
+ }
+ int vlc_hrd_parameters_present_flag = bs.getBit(); // vlc_hrd_parameters_present_flag
+ if (vlc_hrd_parameters_present_flag)
+ {
+ int cpb_cnt_minus1;
+ cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1
+ bs.skipBits(4); // bit_rate_scale
+ bs.skipBits(4); // cpb_size_scale
+ for (int i = 0; i <= cpb_cnt_minus1; i++)
+ {
+ bs.skipUeGolomb(); // bit_rate_value_minus1[i]
+ bs.skipUeGolomb(); // cpb_size_value_minus1[i]
+ bs.skipBit(); // cbr_flag[i]
+ }
+ bs.skipBits(5); // initial_cpb_removal_delay_length_minus1
+ bs.skipBits(5); // cpb_removal_delay_length_minus1
+ bs.skipBits(5); // dpb_output_delay_length_minus1
+ bs.skipBits(5); // time_offset_length
+ }
+ cpb_dpb_delays_present_flag = (nal_hrd_parameters_present_flag | vlc_hrd_parameters_present_flag);
+ if (cpb_dpb_delays_present_flag)
+ bs.skipBit(); // low_delay_hrd_flag
+ bs.skipBit(); // pic_struct_present_flag
+ if (bs.getBit()) // bitstream_restriction_flag
+ {
+ bs.skipBit(); // motion_vectors_over_pic_boundaries_flag
+ bs.skipUeGolomb(); // max_bytes_per_pic_denom
+ bs.skipUeGolomb(); // max_bits_per_mb_denom
+ bs.skipUeGolomb(); // log2_max_mv_length_horizontal
+ bs.skipUeGolomb(); // log2_max_mv_length_vertical
+ bs.skipUeGolomb(); // num_reorder_frames
+ bs.skipUeGolomb(); // max_dec_frame_buffering
+ }
+#endif
}
if ((bs.getIndex() / 8)>0)
@@ -414,86 +433,6 @@ bool cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt,
}
}
}
-
- if ((nalu==NAL_SLICE) || (nalu==NAL_IDR_SLICE))
- {
- uint8_t *nal_data=(uint8_t*) alloca(len);
- if (!nal_data) return false;
- int nal_len = nalUnescape(nal_data, pkt + 5, len - 5);
- cBitStream bs(nal_data, nal_len);
-
- bs.skipUeGolomb(); // first_mb_in_slice
- int slice_type=bs.getUeGolomb();
- bs.skipUeGolomb(); // pic_parameter_set_id
- if (H264.separate_colour_plane_flag)
- {
- bs.skipBits(2); // colour_plane_id
- }
- int frame_num=bs.getBits(H264.log2_max_frame_num); // frame_num
- if (H264.frame_num==-1) H264.frame_num=frame_num;
-
- /*
- if (maContext->Video.Info.Interlaced)
- {
- bool field_pic_flag=bs.getBit();
- if (field_pic_flag)
- {
- bool bottom_field_flag=bs.getBit();
- }
- }
- */
- switch (slice_type)
- {
- case 0:
- case 5:
- slice_type=MA_P_TYPE;
- break;
-
- case 1:
- case 6:
- slice_type=MA_B_TYPE;
- break;
-
- case 2:
- case 7:
- slice_type=MA_I_TYPE;
- break;
-
- case 3:
- case 8:
- slice_type=MA_SP_TYPE;
- break;
-
- case 4:
- case 9:
- slice_type=MA_SI_TYPE;
- break;
-
- default:
- break;
- }
-
- maContext->Video.Info.Pict_Type=slice_type;
-
- if (!maContext->Video.Info.Interlaced)
- {
- if (frame_num!=H264.frame_num)
- {
- if (H264.primary_pic_typeI)
- {
- maContext->Video.Info.Pict_Type=MA_I_TYPE;
- H264.primary_pic_typeI=false;
- }
- H264.frame_num=frame_num;
- return true;
- }
- else
- {
- return false;
- }
- }
- return true;
- }
return false;
}
diff --git a/command/streaminfo.h b/command/streaminfo.h
index 7b5ba71..4c4a957 100644
--- a/command/streaminfo.h
+++ b/command/streaminfo.h
@@ -23,18 +23,12 @@ private:
NAL_PPS = 0x08, // Picture Parameter Set
NAL_AUD = 0x09, // Access Unit Delimiter
NAL_END_SEQ = 0x0A, // End of Sequence
+ NAL_FILLER = 0x0C, // Filler data
NAL_SPS_EXT = 0x0D, // Sequence Parameter Set Extension
NAL_AUX_SLICE = 0x19 // Auxilary Slice
};
- struct H264
- {
- bool primary_pic_typeI;
- bool separate_colour_plane_flag;
- int log2_max_frame_num;
- int frame_num;
- } H264;
-
+ bool H264skiptoggle;
int nalUnescape(uint8_t *dst, const uint8_t *src, int len);
bool FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len);
bool FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len);
diff --git a/command/ts2pkt.cpp b/command/ts2pkt.cpp
index 583cf1b..8667fd6 100644
--- a/command/ts2pkt.cpp
+++ b/command/ts2pkt.cpp
@@ -31,7 +31,7 @@ void cMarkAdTS2Pkt::Clear()
Reset();
}
-void cMarkAdTS2Pkt::Reset(int ErrIndex)
+bool cMarkAdTS2Pkt::Reset(int ErrIndex)
{
sync=false;
switch (ErrIndex)
@@ -57,6 +57,7 @@ void cMarkAdTS2Pkt::Reset(int ErrIndex)
}
counter=-1;
if (queue) queue->Clear();
+ return false;
}
bool cMarkAdTS2Pkt::InjectVideoPES(uchar *PESData, int PESSize)
@@ -96,25 +97,23 @@ bool cMarkAdTS2Pkt::InjectVideoPES(uchar *PESData, int PESSize)
return true;
}
-void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **PktData, int *PktSize)
+bool cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, MarkAdPacket *Pkt)
{
- if ((!PktData) || (!PktSize) || (!queue)) return;
- *PktData=NULL;
- *PktSize=0;
+ if ((!Pkt) || (!queue)) return false;
+
+ bool ret=true;
if (TSData)
{
if (TSSize!=TS_SIZE)
{
- Reset(MA_ERR_TSSIZE);
- return; // we need a full packet
+ return Reset(MA_ERR_TSSIZE); // we need a full packet
}
// check TS packet sync
if (TSData[0]!=0x47)
{
- Reset(MA_ERR_NOSYNC);
- return;
+ return Reset(MA_ERR_NOSYNC); // no sync
}
struct TSHDR *tshdr = (struct TSHDR *) TSData;
@@ -122,38 +121,36 @@ void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **Pk
int pid = (tshdr->PidH << 8) | tshdr->PidL;
if (Pid.Num!=pid)
{
- return; // not for us
- }
-
- if (tshdr->PayloadStart) sync=true;
- if (!sync)
- {
- return; // not synced
+ return true; // not for us, but this is ok
}
if ((counter!=-1) && (((counter+1) & 0xF)!=tshdr->Counter))
{
if (counter==(int) tshdr->Counter)
{
- // duplicate paket -> just ignore
- return;
+ return true; // duplicate paket -> just ignore
}
// sequence error
- Reset(MA_ERR_SEQ);
- return;
+ ret=Reset(MA_ERR_SEQ);
+ if (!tshdr->PayloadStart) return ret;
}
counter=tshdr->Counter;
+ if (tshdr->PayloadStart) sync=true;
+ if (!sync)
+ {
+ return false; // not synced
+ }
+
if ((tshdr->AFC<=0) || (tshdr->AFC>3))
{
- Reset(MA_ERR_AFC);
- return;
+ 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;
+ return true;
}
int buflen=TS_SIZE+1;
@@ -178,30 +175,29 @@ void cMarkAdTS2Pkt::Process(MarkAdPid Pid, uchar *TSData, int TSSize, uchar **Pk
if (buflen>TS_SIZE)
{
// size to large
- Reset(MA_ERR_TOBIG);
- return;
+ return Reset(MA_ERR_TOBIG);
}
if (buflen<0)
{
// error in size
- Reset(MA_ERR_NEG);
- return;
+ return Reset(MA_ERR_NEG);
}
if (buflen==0)
{
// no data?
- return;
+ return false;
}
queue->Put(buf,buflen);
}
+ if (!ret) return ret;
if (Pid.Type==MARKAD_PIDTYPE_VIDEO_H264)
{
- *PktData=queue->GetPacket(PktSize,MA_PACKET_H264);
+ Pkt->Data=queue->GetPacket(&Pkt->Length,MA_PACKET_H264);
}
else
{
- *PktData=queue->GetPacket(PktSize,MA_PACKET_PKT);
+ Pkt->Data=queue->GetPacket(&Pkt->Length,MA_PACKET_PKT);
}
- return;
+ return ret;
}
diff --git a/command/ts2pkt.h b/command/ts2pkt.h
index 6dbcd13..367a007 100644
--- a/command/ts2pkt.h
+++ b/command/ts2pkt.h
@@ -48,8 +48,28 @@ unsigned TSC:
{
unsigned Len:
8;
-unsigned Flags:
- 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
@@ -108,12 +128,12 @@ unsigned Length:
#define MA_ERR_AFC 4
#define MA_ERR_TOBIG 5
#define MA_ERR_NEG 6
- void Reset(int ErrIndex=MA_ERR_STARTUP);
+ bool Reset(int ErrIndex=MA_ERR_STARTUP);
public:
cMarkAdTS2Pkt(const char *QueueName="TS2Pkt", int QueueSize=32768);
~cMarkAdTS2Pkt();
void Clear();
- void Process(MarkAdPid Pid,uchar *TSData, int TSSize, uchar **PktData, int *PktSize);
+ bool Process(MarkAdPid Pid,uchar *TSData, int TSSize, MarkAdPacket *Pkt);
bool InjectVideoPES(uchar *PESData, int PESSize);
};
diff --git a/command/video.cpp b/command/video.cpp
index 3072542..06a9bf3 100644
--- a/command/video.cpp
+++ b/command/video.cpp
@@ -110,13 +110,13 @@ int cMarkAdLogo::Load(char *directory, char *file)
-void cMarkAdLogo::Save(int lastiframe, uchar *picture)
+void cMarkAdLogo::Save(int framenumber, uchar *picture)
{
if (!macontext) return;
char *buf=NULL;
- if (asprintf(&buf,"%s/%06d-%s-A%i_%i.pgm","/tmp/",lastiframe,
+ if (asprintf(&buf,"%s/%06d-%s-A%i_%i.pgm","/tmp/",framenumber,
macontext->Info.ChannelID,
area.aspectratio.Num,area.aspectratio.Den)!=-1)
{
@@ -139,7 +139,7 @@ void cMarkAdLogo::Save(int lastiframe, uchar *picture)
}
}
-int cMarkAdLogo::Detect(int lastiframe, int *logoiframe)
+int cMarkAdLogo::Detect(int framenumber, int *logoframenumber)
{
// Detection is made with Sobel-Operator
@@ -300,18 +300,18 @@ int cMarkAdLogo::Detect(int lastiframe, int *logoiframe)
if (area.counter>=LOGO_VMAXCOUNT)
{
area.status=ret=LOGO;
- *logoiframe=area.lastiframe;
+ *logoframenumber=area.framenumber;
area.counter=0;
}
else
{
- if (!area.counter) area.lastiframe=lastiframe;
+ if (!area.counter) area.framenumber=framenumber;
area.counter++;
}
}
else
{
- area.lastiframe=lastiframe;
+ area.framenumber=framenumber;
area.counter=0;
}
}
@@ -323,7 +323,7 @@ int cMarkAdLogo::Detect(int lastiframe, int *logoiframe)
if (area.counter>=LOGO_IMAXCOUNT)
{
area.status=ret=NOLOGO;
- *logoiframe=area.lastiframe;
+ *logoframenumber=area.framenumber;
area.counter=0;
}
else
@@ -343,21 +343,21 @@ int cMarkAdLogo::Detect(int lastiframe, int *logoiframe)
}
#if 0
- printf("%5i %3i %4i %4i %i %i %i\n",lastiframe,SUMA,area.rpixel,area.mpixel,
+ printf("%5i %3i %4i %4i %i %i %i\n",framenumber,SUMA,area.rpixel,area.mpixel,
(area.rpixel>=(area.mpixel*LOGO_VMARK)),(area.rpixel<(area.mpixel*LOGO_IMARK)),
area.counter );
- Save(lastiframe,area.sobel); // TODO: JUST FOR DEBUGGING!
+ Save(framenumber,area.sobel); // TODO: JUST FOR DEBUGGING!
#endif
}
else
{
- Save(lastiframe,area.sobel);
+ Save(framenumber,area.sobel);
}
}
return ret;
}
-int cMarkAdLogo::Process(int LastIFrame, int *LogoIFrame)
+int cMarkAdLogo::Process(int FrameNumber, int *LogoFrameNumber)
{
if (!macontext) return ERROR;
if (!macontext->Video.Data.Valid) return ERROR;
@@ -413,7 +413,7 @@ int cMarkAdLogo::Process(int LastIFrame, int *LogoIFrame)
if (!area.valid) return ERROR;
- return Detect(LastIFrame,LogoIFrame);
+ return Detect(FrameNumber,LogoFrameNumber);
}
cMarkAdBlackBordersHoriz::cMarkAdBlackBordersHoriz(MarkAdContext *maContext)
@@ -426,10 +426,10 @@ cMarkAdBlackBordersHoriz::cMarkAdBlackBordersHoriz(MarkAdContext *maContext)
void cMarkAdBlackBordersHoriz::Clear()
{
borderstatus=UNINITIALIZED;
- borderiframe=-1;
+ borderframenumber=-1;
}
-int cMarkAdBlackBordersHoriz::Process(int LastIFrame, int *BorderIFrame)
+int cMarkAdBlackBordersHoriz::Process(int FrameNumber, int *BorderIFrame)
{
#define CHECKHEIGHT 20
#define BRIGHTNESS 20
@@ -482,9 +482,9 @@ int cMarkAdBlackBordersHoriz::Process(int LastIFrame, int *BorderIFrame)
if ((fbottom) && (ftop))
{
- if (borderiframe==-1)
+ if (borderframenumber==-1)
{
- borderiframe=LastIFrame;
+ borderframenumber=FrameNumber;
}
else
{
@@ -492,52 +492,227 @@ int cMarkAdBlackBordersHoriz::Process(int LastIFrame, int *BorderIFrame)
switch (borderstatus)
{
case UNINITIALIZED:
- if (LastIFrame>(borderiframe+macontext->Video.Info.FramesPerSecond*MINSECS))
+ if (FrameNumber>(borderframenumber+macontext->Video.Info.FramesPerSecond*MINSECS))
{
borderstatus=BORDER;
}
break;
case NOBORDER:
- if (LastIFrame>(borderiframe+macontext->Video.Info.FramesPerSecond*MINSECS))
+ if (FrameNumber>(borderframenumber+macontext->Video.Info.FramesPerSecond*MINSECS))
{
- *BorderIFrame=borderiframe;
+ *BorderIFrame=borderframenumber;
borderstatus=BORDER;
return 1; // detected start of black border
}
break;
case BORDER:
- borderiframe=LastIFrame;
+ borderframenumber=FrameNumber;
break;
}
}
}
else
{
- if (borderiframe!=-1)
+ if (borderframenumber!=-1)
{
if (borderstatus==BORDER)
{
- *BorderIFrame=borderiframe;
+ *BorderIFrame=borderframenumber;
borderstatus=NOBORDER;
- borderiframe=-1;
+ borderframenumber=-1;
return -1; // detected stop of black border
}
else
{
- borderiframe=-1;
+ borderframenumber=-1;
}
}
else
{
- borderiframe=-1;
+ borderframenumber=-1;
borderstatus=NOBORDER;
}
}
return 0;
}
+cMarkAdOverlap::cMarkAdOverlap(MarkAdContext *maContext)
+{
+ macontext=maContext;
+
+ histbuf[BEFORE]=NULL;
+ histbuf[AFTER]=NULL;
+ result.CommentBefore=NULL;
+ result.CommentAfter=NULL;
+ Clear();
+}
+
+cMarkAdOverlap::~cMarkAdOverlap()
+{
+ Clear();
+}
+
+void cMarkAdOverlap::Clear()
+{
+ histcnt[BEFORE]=0;
+ histcnt[AFTER]=0;
+ histframes[BEFORE]=0;
+ histframes[AFTER]=0;
+ if (histbuf[BEFORE])
+ {
+ delete[] histbuf[BEFORE];
+ histbuf[BEFORE]=NULL;
+ }
+ if (histbuf[AFTER])
+ {
+ delete[] histbuf[AFTER];
+ histbuf[AFTER]=NULL;
+ }
+ if (result.CommentBefore) free(result.CommentBefore);
+ if (result.CommentAfter) free(result.CommentAfter);
+ memset(&result,0,sizeof(result));
+ similarCutOff=0;
+ similarMaxCnt=0;
+
+ lastframenumber=-1;
+}
+
+void cMarkAdOverlap::getHistogram(simpleHistogram &dest)
+{
+ memset(dest,0,sizeof(simpleHistogram));
+ for (int Y=0; Y<macontext->Video.Info.Height;Y++)
+ {
+ for (int X=0; X<macontext->Video.Info.Width;X++)
+ {
+ uchar val=macontext->Video.Data.Plane[0][X+(Y*macontext->Video.Data.PlaneLinesize[0])];
+ dest[val]++;
+ }
+ }
+}
+
+bool cMarkAdOverlap::areSimilar(simpleHistogram &hist1, simpleHistogram &hist2)
+{
+ int similar=0;
+ for (int i=0; i<256; i++)
+ {
+ similar+=abs(hist1[i]-hist2[i]);
+ }
+ if (similar<similarCutOff) return true;
+ return false;
+}
+
+MarkAdPos *cMarkAdOverlap::Detect()
+{
+ int start=0,simcnt=0;
+ int tmpA=0,tmpB=0;
+ if (result.FrameNumberBefore==-1) return NULL;
+ result.FrameNumberBefore=-1;
+ for (int B=0; B<histcnt[BEFORE]; B++)
+ {
+ for (int A=start; A<histcnt[AFTER]; A++)
+ {
+ bool simil=areSimilar(histbuf[BEFORE][B].histogram,histbuf[AFTER][A].histogram);
+ if (simil)
+ {
+ tmpA=A;
+ tmpB=B;
+ start=A+1;
+ simcnt++;
+ break;
+ }
+ else
+ {
+ //if (simcnt) printf("%i %i %i\n",simcnt,histbuf[BEFORE][B].framenumber,histbuf[AFTER][A].framenumber);
+
+ if (simcnt>similarMaxCnt)
+ {
+ result.FrameNumberBefore=histbuf[BEFORE][tmpB].framenumber;
+ result.FrameNumberAfter=histbuf[AFTER][tmpA].framenumber;
+ }
+ else
+ {
+ start=0;
+ }
+ simcnt=0;
+ }
+ }
+ }
+ if (result.FrameNumberBefore==-1)
+ {
+ if (simcnt>similarMaxCnt)
+ {
+ result.FrameNumberBefore=histbuf[BEFORE][tmpB].framenumber;
+ result.FrameNumberAfter=histbuf[AFTER][tmpA].framenumber;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+ if (asprintf(&result.CommentBefore,"detected overlap before (%i)",result.FrameNumberBefore)==-1)
+ {
+ result.CommentBefore=NULL;
+ }
+ if (asprintf(&result.CommentAfter,"detected overlap after (%i)",result.FrameNumberAfter)==-1)
+ {
+ result.CommentAfter=NULL;
+ }
+ return &result;
+}
+
+MarkAdPos *cMarkAdOverlap::Process(int FrameNumber, int Frames, bool BeforeAd)
+{
+ if ((lastframenumber>0) && (!similarMaxCnt))
+ {
+ similarCutOff=50000;
+ similarMaxCnt=4;
+ }
+
+ if (BeforeAd)
+ {
+ if ((histframes[BEFORE]) && (histcnt[BEFORE]>=histframes[BEFORE]))
+ {
+ if (result.FrameNumberBefore)
+ {
+ Clear();
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ if (!histbuf[BEFORE])
+ {
+ histframes[BEFORE]=Frames;
+ histbuf[BEFORE]=new histbuffer[Frames+1];
+ }
+ getHistogram(histbuf[BEFORE][histcnt[BEFORE]].histogram);
+ histbuf[BEFORE][histcnt[BEFORE]].framenumber=FrameNumber;
+ histcnt[BEFORE]++;
+ }
+ else
+ {
+ if (!histbuf[AFTER])
+ {
+ histframes[AFTER]=Frames;
+ histbuf[AFTER]=new histbuffer[Frames+1];
+ }
+
+ if (histcnt[AFTER]>=histframes[AFTER]-1)
+ {
+ if (result.FrameNumberBefore) return NULL;
+ return Detect();
+ }
+ getHistogram(histbuf[AFTER][histcnt[AFTER]].histogram);
+ histbuf[AFTER][histcnt[AFTER]].framenumber=FrameNumber;
+ histcnt[AFTER]++;
+ }
+ lastframenumber=FrameNumber;
+ return NULL;
+}
cMarkAdVideo::cMarkAdVideo(MarkAdContext *maContext)
{
@@ -549,6 +724,7 @@ cMarkAdVideo::cMarkAdVideo(MarkAdContext *maContext)
hborder=new cMarkAdBlackBordersHoriz(maContext);
logo = new cMarkAdLogo(maContext);
+ overlap = NULL;
Clear();
}
@@ -557,6 +733,7 @@ cMarkAdVideo::~cMarkAdVideo()
ResetMark();
if (hborder) delete hborder;
if (logo) delete logo;
+ if (overlap) delete overlap;
}
void cMarkAdVideo::Clear()
@@ -610,56 +787,68 @@ bool cMarkAdVideo::AspectRatioChange(MarkAdAspectRatio *a, MarkAdAspectRatio *b)
}
-MarkAdMark *cMarkAdVideo::Process(int LastIFrame)
+MarkAdPos *cMarkAdVideo::Process2ndPass(int FrameNumber, int Frames, bool BeforeAd)
+{
+ if (!FrameNumber) return NULL;
+ if (!overlap) overlap=new cMarkAdOverlap(macontext);
+ if (!overlap) return NULL;
+
+ return overlap->Process(FrameNumber, Frames, BeforeAd);
+}
+
+MarkAdMark *cMarkAdVideo::Process(int FrameNumber, int FrameNumberNext)
{
+ if ((!FrameNumber) && (!FrameNumberNext)) return NULL;
+
ResetMark();
- if (!LastIFrame) return NULL;
if (!macontext->Video.Options.IgnoreLogoDetection)
{
- int logoiframe;
- int lret=logo->Process(LastIFrame,&logoiframe);
+ int logoframenumber;
+ int lret=logo->Process(FrameNumber,&logoframenumber);
if ((lret>=-1) && (lret!=0))
{
char *buf=NULL;
if (lret>0)
{
- if (asprintf(&buf,"detected logo start (%i)",logoiframe)!=-1)
+ if (asprintf(&buf,"detected logo start (%i)",logoframenumber)!=-1)
{
- AddMark(MT_LOGOSTART,logoiframe,buf);
+ AddMark(MT_LOGOSTART,logoframenumber,buf);
free(buf);
}
}
else
{
- if (asprintf(&buf,"detected logo stop (%i)",logoiframe)!=-1)
+ if (asprintf(&buf,"detected logo stop (%i)",logoframenumber)!=-1)
{
- AddMark(MT_LOGOSTOP,logoiframe,buf);
+ AddMark(MT_LOGOSTOP,logoframenumber,buf);
free(buf);
}
}
}
}
- int borderiframe;
- int hret=hborder->Process(LastIFrame,&borderiframe);
+ int borderframenumber;
+ int hret=hborder->Process(FrameNumber,&borderframenumber);
- if ((hret>0) && (borderiframe))
+ if ((hret>0) && (borderframenumber))
{
char *buf=NULL;
- if (asprintf(&buf,"detected start of horiz. borders (%i [%i])",borderiframe,LastIFrame)!=-1)
+ if (asprintf(&buf,"detected start of horiz. borders (%i [%i])",
+ borderframenumber,FrameNumber)!=-1)
{
- AddMark(MT_BORDERSTART,borderiframe,buf);
+ AddMark(MT_BORDERSTART,borderframenumber,buf);
free(buf);
}
}
- if ((hret<0) && (borderiframe))
+ if ((hret<0) && (borderframenumber))
{
char *buf=NULL;
- if (asprintf(&buf,"detected stop of horiz. borders (%i [%i])",borderiframe,LastIFrame)!=-1)
+ if (asprintf(&buf,"detected stop of horiz. borders (%i [%i])",
+ borderframenumber,FrameNumber)!=-1)
{
- AddMark(MT_BORDERSTOP,borderiframe,buf);
+ AddMark(MT_BORDERSTOP,borderframenumber,buf);
free(buf);
}
}
@@ -668,34 +857,47 @@ MarkAdMark *cMarkAdVideo::Process(int LastIFrame)
{
if (AspectRatioChange(&macontext->Video.Info.AspectRatio,&aspectratio))
{
- char *buf=NULL;
- if (asprintf(&buf,"aspect ratio change from %i:%i to %i:%i (%i)",
- aspectratio.Num,aspectratio.Den,
- macontext->Video.Info.AspectRatio.Num,
- macontext->Video.Info.AspectRatio.Den,LastIFrame)!=-1)
+ char *buf=(char *) calloc(1,256);
+ 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->Info.AspectRatio.Num) && (macontext->Info.AspectRatio.Den))
+ if ((macontext->Video.Info.AspectRatio.Num==macontext->Info.AspectRatio.Num) &&
+ (macontext->Video.Info.AspectRatio.Den==macontext->Info.AspectRatio.Den))
{
- if ((macontext->Video.Info.AspectRatio.Num==macontext->Info.AspectRatio.Num) &&
- (macontext->Video.Info.AspectRatio.Den==macontext->Info.AspectRatio.Den))
- {
- AddMark(MT_ASPECTSTART,LastIFrame,buf);
- }
- else
- {
- AddMark(MT_ASPECTSTOP,LastIFrame,buf);
- }
+ char nbuf[20];
+ snprintf(nbuf,sizeof(nbuf),"%i)",FrameNumberNext);
+ nbuf[19]=0;
+ strcat(buf,nbuf);
+ AddMark(MT_ASPECTSTART,FrameNumberNext,buf);
}
else
{
- AddMark(MT_ASPECTCHANGE,LastIFrame,buf);
+ char nbuf[20];
+ snprintf(nbuf,sizeof(nbuf),"%i)",framelast);
+ nbuf[19]=0;
+ strcat(buf,nbuf);
+ AddMark(MT_ASPECTSTOP,framelast,buf);
}
- free(buf);
}
+ else
+ {
+ char nbuf[20];
+ snprintf(nbuf,sizeof(nbuf),"%i)",FrameNumber);
+ nbuf[19]=0;
+ strcat(buf,nbuf);
+
+ AddMark(MT_ASPECTCHANGE,FrameNumber,buf);
+ }
+ free(buf);
}
aspectratio.Num=macontext->Video.Info.AspectRatio.Num;
aspectratio.Den=macontext->Video.Info.AspectRatio.Den;
}
+ framelast=FrameNumberNext;
return &mark;
}
diff --git a/command/video.h b/command/video.h
index 1a03d97..22bcec7 100644
--- a/command/video.h
+++ b/command/video.h
@@ -22,6 +22,39 @@
#define LOGO_VMARK 0.5 // percantage of pixels for visible
#define LOGO_IMARK 0.15 // percentage of pixels for invisible
+class cMarkAdOverlap
+{
+private:
+#define BEFORE 0
+#define AFTER 1
+ MarkAdContext *macontext;
+ typedef int simpleHistogram[256];
+
+ typedef struct
+ {
+ int framenumber;
+ simpleHistogram histogram;
+ } histbuffer;
+ histbuffer *histbuf[2];
+ int histcnt[2];
+ int histframes[2];
+
+ int lastframenumber;
+
+ MarkAdPos result;
+
+ int similarCutOff;
+ int similarMaxCnt;
+ bool areSimilar(simpleHistogram &hist1, simpleHistogram &hist2);
+ void getHistogram(simpleHistogram &dest);
+ MarkAdPos *Detect();
+ void Clear();
+public:
+ cMarkAdOverlap(MarkAdContext *maContext);
+ ~cMarkAdOverlap();
+ MarkAdPos *Process(int FrameNumber, int Frames, bool BeforeAd);
+};
+
class cMarkAdLogo
{
private:
@@ -57,7 +90,7 @@ private:
int rpixel; // black pixel in result
int mpixel; // black pixel in mask
int status; // status = LOGO on, off, uninitialized
- int lastiframe; // start/stop frame
+ int framenumber; // start/stop frame
int counter; // how many logo on, offs detected?
int corner; // which corner
MarkAdAspectRatio aspectratio; // aspectratio
@@ -69,12 +102,12 @@ private:
int GY[3][3];
MarkAdContext *macontext;
- int Detect(int lastiframe, int *logoiframe); // ret 1 = logo, 0 = unknown, -1 = no logo
+ int Detect(int framenumber, int *logoframenumber); // ret 1 = logo, 0 = unknown, -1 = no logo
int Load(char *directory, char *file);
- void Save(int lastiframe, uchar *picture);
+ void Save(int framenumber, uchar *picture);
public:
cMarkAdLogo(MarkAdContext *maContext);
- int Process(int LastIFrame, int *LogoIFrame);
+ int Process(int FrameNumber, int *LogoFrameNumber);
void Clear();
};
@@ -91,11 +124,11 @@ private:
};
int borderstatus;
- int borderiframe;
+ int borderframenumber;
MarkAdContext *macontext;
public:
cMarkAdBlackBordersHoriz(MarkAdContext *maContext);
- int Process(int LastIFrame,int *BorderIFrame);
+ int Process(int FrameNumber,int *BorderFrameNumber);
void Clear();
};
@@ -108,16 +141,19 @@ private:
MarkAdAspectRatio aspectratio;
cMarkAdBlackBordersHoriz *hborder;
cMarkAdLogo *logo;
+ cMarkAdOverlap *overlap;
void ResetMark();
bool AddMark(int Type, int Position, const char *Comment);
bool AspectRatioChange(MarkAdAspectRatio *a, MarkAdAspectRatio *b);
- void SetTimerMarks(int LastIFrame);
+
+ int framelast;
public:
cMarkAdVideo(MarkAdContext *maContext);
~cMarkAdVideo();
- MarkAdMark *Process(int LastIFrame);
+ MarkAdPos *Process2ndPass(int FrameNumber, int Frames, bool BeforeAd);
+ MarkAdMark *Process(int FrameNumber, int FrameNumberNext);
void Clear();
};