forked from erikkaashoek/Comskip
-
Notifications
You must be signed in to change notification settings - Fork 1
/
comskip.c
16514 lines (15041 loc) · 538 KB
/
comskip.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//
// comskip.c
// Copyright (C) 2004 Scott Michael
// Based on the work of Chris Pinkham of MythTV
// comskip is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// comskip 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "platform.h"
#include "vo.h"
#include <argtable2.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
//#define restrict
//#include <libavcodec/ac3dec.h>
#include <libavutil/avutil.h>
#include <libavutil/pixdesc.h>
#include <libavutil/samplefmt.h>
#ifdef HARDWARE_DECODE
#include <fftools/ffmpeg.h>
#endif
#include "comskip.h"
// Define detection methods
#define BLACK_FRAME 1
#define LOGO 2
#define SCENE_CHANGE 4
#define RESOLUTION_CHANGE 8
#define CC 16
#define AR 32
#define SILENCE 64
#define CUTSCENE 128
// Define logo detection directions
#define HORIZ 0
#define VERT 1
#define DIAG1 2
#define DIAG2 3
// Define CC types
#define NONE 0
#define ROLLUP 1
#define POPON 2
#define PAINTON 3
#define COMMERCIAL 4
// Define aspect ratio
#define FULLSCREEN true
#define WIDESCREEN false
#define AR_TREND 0.8
#define DEEP_SILENCE 6 //max_volume / DEEP_SILENCE defines deep silence
#define OPEN_INPUT 1
#define OPEN_INI 2
#define SAVE_DMP 3
#define SAVE_INI 4
#ifdef DONATOR
#define COMSKIPPUBLIC "donator"
#else
#define COMSKIPPUBLIC "public"
#endif
#define MAX(X,Y) (X>Y?X:Y)
#define MIN(X,Y) (X<Y?X:Y)
// max number of frames that can be marked
#define MAX_IDENTIFIERS 300000
#define MAX_COMMERCIALS 100000
int argument_count;
char ** argument = NULL;
bool initialized = false;
const char* progname = "ComSkip";
FILE* out_file = NULL;
FILE* incommercial_file = NULL;
FILE* ini_file = NULL;
FILE* plist_cutlist_file = NULL;
FILE* zoomplayer_cutlist_file = NULL;
FILE* zoomplayer_chapter_file = NULL;
FILE* scf_file = NULL;
FILE* vcf_file = NULL;
FILE* vdr_file = NULL;
FILE* projectx_file = NULL;
FILE* avisynth_file = NULL;
FILE* videoredo_file = NULL;
FILE* videoredo3_file = NULL;
FILE* btv_file = NULL;
FILE* edl_file = NULL;
FILE* ffmeta_file = NULL;
FILE* ffsplit_file = NULL;
FILE* live_file = NULL;
FILE* ipodchap_file = NULL;
FILE* edlp_file = NULL;
FILE* bcf_file = NULL;
FILE* edlx_file = NULL;
FILE* cuttermaran_file = NULL;
FILE* chapters_file = NULL;
FILE* log_file = NULL;
FILE* womble_file = NULL;
FILE* mls_file = NULL;
FILE* mpgtx_file = NULL;
FILE* dvrcut_file = NULL;
FILE* dvrmstb_file = NULL;
FILE* mpeg2schnitt_file = NULL;
FILE* tuning_file = NULL;
FILE* training_file = NULL;
FILE* aspect_file = NULL;
FILE* cutscene_file = NULL;
FILE* mkvtoolnix_chapters_file = NULL;
FILE* mkvtoolnix_tags_file = NULL;
extern int demux_pid;
extern int selected_audio_pid;
extern int selected_subtitle_pid;
extern int selected_video_pid;
extern int demux_asf;
extern int key;
extern char osname[];
int audio_channels;
#define KDOWN 1
#define KUP 2
#define KLEFT 3
#define KRIGHT 4
#define KNEXT 5
#define KPREV 6
extern int xPos,yPos,lMouseDown;
extern int framenum_infer;
extern void list_codes;
extern int64_t headerpos;
int vo_init_done = 0;
extern int soft_seeking;
static FILE* in_file = NULL;
#undef FRAME_WITH_HISTOGRAM
#undef FRAME_WITH_LOGO
#undef FRAME_WITH_AR
typedef struct
{
// long frame;
int brightness;
int schange_percent;
int minY;
int maxY;
int uniform;
int volume;
double currentGoodEdge;
double ar_ratio;
bool logo_present;
bool commercial;
int isblack;
int64_t goppos;
double pts;
char pict_type;
int minX;
int maxX;
int hasBright;
int dimCount;
int cutscenematch;
double logo_filter;
int xds;
int cur_segment;
int audio_channels;
#ifdef FRAME_WITH_HISTOGRAM
int histogram[256];
#endif
} frame_info;
int debug_cur_segment;
frame_info* frame = NULL;
long frame_count = 0;
long max_frame_count;
double fps = 1.0; // frames per second (NTSC=29.970, PAL=25)
double get_frame_pts(int f) {
if (!frame) {
return(f / fps);
}
if (f < 1)
f = 1;
if (f > frame_count -1)
f = frame_count -1;
return(frame[f].pts);
}
#define F2V(X) (frame != NULL ? ((X) <= 0 ? frame[1].pts : ((X) >= framenum_real ? frame[framenum_real - 1].pts : frame[X].pts )) : (X) / fps)
#define assert(T) (aaa = ((T) ? 1 : *(int *)0))
//#define F2T(X) (F2V(X) - F2V(1))
#define F2T(X) (F2V(X))
#define F2L(X,Y) (F2V(X) - F2V(Y))
#define F2F(X) ((long) (F2T(X) * fps + 1.5 ))
typedef struct
{
long frame;
int percentage;
} schange_info;
schange_info* schange = NULL;
long schange_count = 0;
long max_schange_count = 0;
typedef struct
{
long frame;
int brightness;
long uniform;
int volume;
int cause;
} black_frame_info;
long black_count = 0;
black_frame_info* black = NULL;
long max_black_count;
typedef struct block_info
{
long f_start;
long f_end;
unsigned int b_head;
unsigned int b_tail;
unsigned int bframe_count;
unsigned int schange_count;
double schange_rate; // in changes per second
double length;
double score;
int combined_count;
int cc_type;
// bool ar;
double ar_ratio;
int audio_channels;
int cause;
int more;
int less;
int brightness;
int volume;
int silence;
int uniform;
int stdev;
char reffer;
double logo;
double correlation;
int strict;
int iscommercial;
} block_info;
#define MAX_BLOCKS 1000
struct block_info cblock[MAX_BLOCKS];
long block_count = 0;
long max_block_count;
#define C_c (1<<1)
#define C_l (1<<0)
#define C_s (1<<2)
#define C_a (1<<5)
#define C_u (1<<3)
#define C_b (1<<4)
#define C_r ((long)1<<29)
#define C_STRICT (1<<6)
#define C_NONSTRICT (1<<7)
#define C_COMBINED (1<<8)
#define C_LOGO (1<<9)
#define C_EXCEEDS (1<<10)
#define C_AR (1<<11)
#define C_SC (1<<12)
#define C_H1 (1<<13)
#define C_H2 (1<<14)
#define C_H3 (1<<15)
#define C_H4 ((long)1<<16)
#define C_H5 ((long)1<<17)
#define C_H6 ((long)1<<22)
#define C_v ((long)1<<18)
#define C_BRIGHT ((long)1<<19)
#define C_NOTBRIGHT ((long)1<<20)
#define C_DIM ((long)1<<21)
#define C_AB ((long)1<<23)
#define C_AU ((long)1<<24)
#define C_AL ((long)1<<25)
#define C_AS ((long)1<<26)
#define C_AC ((long)1<<26)
#define C_F ((long)1<<27)
#define C_t ((long)1<<28)
#define C_H7 ((long)1<<29)
#define C_H8 ((long)1<<30)
#define C_CUTMASK (C_c | C_l | C_s | C_a | C_u | C_b | C_t | C_r)
#define CUTCAUSE(c) ( c & C_CUTMASK)
//int minLogo = 30;
//int maxLogo = 120;
typedef struct
{
int start;
int end;
} logo_block_info;
logo_block_info* logo_block = NULL;
long logo_block_count = 0; // How many groups have already been identified. Increment after fill.
long max_logo_block_count;
bool processCC = false;
extern int reorderCC;
typedef struct
{
unsigned char cc1[2];
unsigned char cc2[2];
} ccPacket;
ccPacket lastcc;
ccPacket cc;
typedef struct
{
long start_frame;
long end_frame;
int type;
} cc_block_info;
cc_block_info* cc_block = NULL;
long cc_block_count = 0;
long max_cc_block_count;
int last_cc_type = NONE;
int current_cc_type = NONE;
bool cc_on_screen = false;
bool cc_in_memory = false;
typedef struct
{
long frame;
char name[40];
int v_chip;
int duration;
int position;
int composite1;
int composite2;
} XDS_block_info;
XDS_block_info* XDS_block = NULL;
long XDS_block_count = 0;
long max_XDS_block_count;
typedef struct
{
long start_frame;
long end_frame;
long text_len;
unsigned char text[256];
} cc_text_info;
cc_text_info* cc_text = NULL;
long cc_text_count = 0;
long max_cc_text_count = 0;
#define AR_UNDEF 0.0
typedef struct
{
int start;
int end;
// bool ar;
double ar_ratio;
int volume;
int height, width;
int minX,maxX,minY,maxY;
} ar_block_info;
ar_block_info* ar_block = NULL;
long ar_block_count = 0; // How many groups have already been identified. Increment after fill.
long max_ar_block_count;
int last_audio_channels = 2;
double last_ar_ratio = 0.0;
double ar_ratio_trend = 0.0;
int ar_ratio_trend_counter = 0;
int ar_ratio_start = 0;
int ar_misratio_trend_counter = 0;
int ar_misratio_start = 0;
#define AC_UNDEF 0
typedef struct
{
int start;
int end;
// bool ar;
int audio_channels;
} ac_block_info;
ac_block_info* ac_block = NULL;
long ac_block_count = 0; // How many groups have already been identified. Increment after fill.
long max_ac_block_count;
typedef struct
{
long start;
long end;
} commercial_list_info;
commercial_list_info* commercial_list = NULL;
int commercial_count = -1;
struct
{
long start_frame;
long end_frame;
int start_block;
int end_block;
double length;
} commercial[MAX_COMMERCIALS];
int reffer_count = -1;
struct
{
long start_frame;
long end_frame;
} reffer[MAX_COMMERCIALS];
#define MAX_ASPECT_RATIOS 1000
struct
{
long frames;
double ar_ratio;
} ar_histogram[MAX_ASPECT_RATIOS];
double dominant_ar;
#define MAX_AUDIO_CHANNELS 12
struct
{
long frames;
int audio_channels;
} ac_histogram[MAX_AUDIO_CHANNELS];
int dominant_ac;
int thread_count = 2;
int hardware_decode = 0;
int use_cuvid = 0;
int use_vdpau = 0;
int use_dxva2 = 0;
int skip_B_frames = 0;
int lowres = 0;
bool live_tv = false;
bool output_incommercial = false;
int incommercial_frames = 1000;
int live_tv_retries = 6;
int dvrms_live_tv_retries = 300;
int standoff = 0;
int dvrmsstandoff = 120000;
extern int standoff_retries;
extern int standoff_time;
extern int standoff_size;
extern int standoff_initial_size;
extern int standoff_initial_wait;
char incomingCommandLine[MAX_ARG];
char logofilename[MAX_PATH];
char logfilename[MAX_PATH];
char mpegfilename[MAX_PATH];
char exefilename[MAX_PATH];
char inbasename[MAX_PATH];
char workbasename[MAX_PATH];
char outbasename[MAX_PATH];
char shortbasename[MAX_PATH];
char inifilename[MAX_PATH];
char dictfilename[MAX_PATH];
char out_filename[MAX_PATH];
char incommercial_filename[MAX_PATH];
char outputdirname[MAX_PATH];
char filename[MAX_PATH];
int curvolume = -1;
extern int framenum;
//unsigned int frame_period;
//int audio_framenum = 0;
//extern int64_t pts;
extern int64_t initial_pts;
extern int initial_pts_set;
extern char pict_type;
int ascr,scr;
int framenum_real;
int frames_with_logo;
int framesprocessed = 0;
char HomeDir[256]; // comskip home directory
char tempString[256];
double average_score;
int brightness = 0;
long sum_brightness=0;
long sum_count;
int uniformHistogram[256];
#define UNIFORMSCALE 100
int brightHistogram[256];
int blackHistogram[256];
int volumeHistogram[256];
int silenceHistogram[256];
int logoHistogram[256];
int volumeScale = 10;
int last_brightness = 0;
int min_brightness_found;
int min_volume_found;
int max_logo_gap;
int max_nonlogo_block_length;
double logo_overshoot;
double logo_quality;
int width, old_width, videowidth;
int height, old_height;
int ar_width = 0;
int subsample_video = 0x1ff;
//#define MAXWIDTH 2000
//#define MAXHEIGHT 1200
char haslogo[MAXWIDTH*MAXHEIGHT];
// unsigned char oldframe[MAXWIDTH*MAXHEIGHT];
// variables defining options with defaults
int selftest = 0;
int verbose = 0; // show extra info
double avg_fps = 22;
int border = 10; // border around edge of video to ignore
int ticker_tape=0, ticker_tape_percentage=0; // border from bottom to ignore
int top_ticker_tape=0, top_ticker_tape_percentage=0; // border from bottom to ignore
int ignore_side=0;
int ignore_left_side=0;
int ignore_right_side=0;
int max_brightness = 60; // frame not black if any pixels checked are greater than this (scale 0 to 255)
int maxbright = 1;
int min_hasBright = 255000;
int min_dimCount = 255000;
int test_brightness = 40; // frame not pure black if any pixels are greater than this, will check average
int max_avg_brightness = 19; // maximum average brightness for a dim frame to be considered black (scale 0 to
int max_volume = 500;
int max_silence = 100;
int min_silence = 12;
int punish_no_logo = true;
int validate_silence = true;
int validate_uniform = true;
int validate_scenechange = true;
int remove_silent_segments = 0;
int validate_ar = true;
int punish = 0;
int reward = 0;
int min_volume=0;
int min_uniform = 0;
int volume_slip = 40;
extern int ms_audio_delay;
int max_repair_size = 40;
//int variable_bitrate = 1;
extern int is_h264;
///brightness (scale 0 to 255)
char ini_text[40000];
///255)
double max_commercialbreak = 600; // maximum length in seconds to consider a segment a commercial break
double min_commercialbreak = 20; // minimum length in seconds to consider a segment a commercial break
double max_commercial_size = 120; // maximum time in seconds for a single commercial
double min_commercial_size = 4; // mimimum time in seconds for a single commercial
double min_show_segment_length = 120.0;
bool require_div5 = 0; // set=1 to only mark breaks divisible by 5 as a commercial.
double div5_tolerance = -1;
bool play_nice = false;
double global_threshold = 1.05;
bool intelligent_brightness = false;
double logo_threshold = 0.80;
double logo_percentage_threshold = 0.25;
double logo_max_percentage_of_screen = 0.12;
int logo_filter = 0;
int non_uniformity = 500;
int brightness_jump = 200;
double black_percentile = 0.0076;
double uniform_percentile = 0.003;
double score_percentile = 0.71;
double logo_percentile = 0.92;
double logo_fraction = 0.40;
int commDetectMethod = BLACK_FRAME + LOGO + RESOLUTION_CHANGE + AR + SILENCE + (PROCESS_CC ? CC : 0);
int giveUpOnLogoSearch = 2000; // If no logo is identified after x seconds into the show - give up.
int delay_logo_search = 0; // If no logo is identified after x seconds into the show - give up.
int cut_on_ar_change = 1;
int cut_on_ac_change = 1;
int added_recording = 14;
int after_start = 0;
int before_end = 0;
int delete_show_after_last_commercial = false;
int delete_show_before_first_commercial = false;
int delete_block_after_commercial = 0;
int min_commercial_break_at_start_or_end = 39;
int always_keep_first_seconds = 0;
int always_keep_last_seconds = 0;
bool connect_blocks_with_logo = true;
int delete_show_before_or_after_current = false;
bool deleteLogoFile = true;
bool useExistingLogoFile = true;
bool startOverAfterLogoInfoAvail = true;
int doublCheckLogoCount = 0;
bool output_default = true;
bool output_chapters = false;
bool sage_framenumber_bug = false;
bool sage_minute_bug = false;
bool enable_mencoder_pts = false;
bool output_plist_cutlist = false;
bool output_zoomplayer_cutlist = false;
bool output_zoomplayer_chapter = false;
bool output_scf = false;
bool output_videoredo = false;
bool output_videoredo3 = false;
bool output_ipodchap = false;
int videoredo_offset = 2;
int edl_offset = 0;
int timeline_repair = 1;
int edl_skip_field = 0;
bool output_edl = false;
bool output_live = false;
bool output_edlp = false;
bool output_bsplayer = false;
bool output_edlx = false;
bool output_btv = false;
bool output_cuttermaran = false;
bool output_mpeg2schnitt = false;
char cuttermaran_options[1024];
char mpeg2schnitt_options[1024];
char avisynth_options[1024];
char dvrcut_options[1024];
bool output_demux = false;
bool output_data = false;
bool output_srt = false;
bool output_smi = false;
bool output_timing = false;
bool output_womble = false;
bool output_mls = false;
bool output_mpgtx = false;
bool output_dvrcut = false;
bool output_dvrmstb = false;
bool output_vdr = false;
bool output_vcf = false;
bool output_projectx = false;
bool output_avisynth = false;
int output_mkvtoolnix = 0;
bool output_debugwindow = false;
bool output_console = true;
int disable_heuristics = 0;
char windowtitle[1024] = "Comskip - %s";
bool output_tuning = false;
int output_training = 0;
bool output_false = false;
bool output_aspect = false;
bool output_ffmeta = false;
bool output_ffsplit = false;
int noise_level=5;
bool framearray = true;
bool output_framearray = false;
bool only_strict = false;
double length_strict_modifier = 3.0;
double length_nonstrict_modifier = 1.5;
double combined_length_strict_modifier = 2.0;
double combined_length_nonstrict_modifier = 1.25;
double logo_present_modifier = 0.01;
double punish_modifier = 2.0;
double punish_threshold = 1.3;
double reward_modifier = 0.5;
int after_logo=0;
int before_logo=0;
double shrink_logo=5.0;
int shrink_logo_tail=0;
int where_logo=0;
double excessive_length_modifier = 0.01;
double dark_block_modifier = 0.3;
int padding = 0;
int remove_before = 0;
int remove_after = 0;
double min_schange_modifier = 0.5;
double max_schange_modifier = 2.0;
int schange_threshold = 90;
int schange_cutlevel = 15;
double cc_commercial_type_modifier = 4.0;
double cc_wrong_type_modifier = 2.0;
double cc_correct_type_modifier = 0.75;
double ar_wrong_modifier = 2.0;
double ac_wrong_modifier = 1.0;
double ar_rounding = 100;
double ar_delta = 0.08;
long avg_brightness = 0;
long maxi_volume = 0;
long avg_volume = 0;
long avg_silence = 0;
long avg_uniform = 0;
double avg_schange = 0.0;
double dictionary_modifier = 1.05;
int aggressive_logo_rejection = false;
unsigned int min_black_frames_for_break = 1;
bool detectBlackFrames;
bool detectSceneChanges;
int dummy1;
unsigned char* frame_ptr = 0;
int dummy2;
// bool frameIsBlack;
bool sceneHasChanged;
int sceneChangePercent;
bool lastFrameWasBlack = false;
bool lastFrameWasSceneChange = false;
#include <libavutil/avutil.h> // only for DECLARE_ALIGNED
static DECLARE_ALIGNED(32, long, histogram)[256];
static DECLARE_ALIGNED(32, long, lastHistogram)[256];
#define MAXCSLENGTH 400*300
#define MAXCUTSCENES 8
void LoadCutScene(const char *filename);
void RecordCutScene(int frame_count,int brightness);
char cutscenefile[1024];
char cutscenefile1[1024];
char cutscenefile2[1024];
char cutscenefile3[1024];
char cutscenefile4[1024];
char cutscenefile5[1024];
char cutscenefile6[1024];
char cutscenefile7[1024];
char cutscenefile8[1024];
int cutscenematch;
int cutscenedelta = 10;
int cutsceneno = 0;
int cutscenes=0;
unsigned char cutscene[MAXCUTSCENES][MAXCSLENGTH];
int csbrightness[MAXCUTSCENES];
int cslength[MAXCUTSCENES];
// int cssum[MAXCUTSCENES];
// int csmatch[MAXCUTSCENES];
char debugText[20000];
bool logoInfoAvailable;
bool secondLogoSearch = false;
bool logoBuffersFull = false;
int logoTrendCounter = 0;
double logoFreq = 1.0; // times fps between logo checks
int num_logo_buffers = 50; // How many frames to compare at a time for logo detection;
bool lastLogoTest = false;
// int logoTrendStartFrame;
int* logoFrameNum = NULL; // Keep track of the frame numbers of each buffer
int oldestLogoBuffer; // Which buffer is the oldest?
// int lastRealLogoChange;
bool curLogoTest = false;
int minHitsForTrend = 10;
// bool hindsightLogoState = true;
double logoPercentage = 0.0;
bool reverseLogoLogic = false;
#define MULTI_EDGE_BUFFER 0
#if MULTI_EDGE_BUFFER
unsigned char ** horiz_edges = NULL; // rotating storage for detected horizontal edges
unsigned char ** vert_edges = NULL; // rotating storage for detected vertical edges
#else
unsigned char horiz_count[MAXHEIGHT*MAXWIDTH];
unsigned char vert_count[MAXHEIGHT*MAXWIDTH];
#endif
double borderIgnore = .05; // Percentage of each side to ignore for logo detection
int subtitles = 0;
int logo_at_bottom = 0;
int logo_at_side = 0;
int edge_radius = 2;
int int_edge_radius = 2;
int edge_step = 1;
int edge_level_threshold = 5;
int edge_weight = 10;
int edge_count = 0;
int hedge_count = 0;
int vedge_count = 0;
int newestLogoBuffer = -1; // Which buffer is the newest? Increments prior to fill so start at -1
unsigned char ** logoFrameBuffer = NULL; // rotating storage for frames
int logoFrameBufferSize = 0;
int lwidth;
int lheight;
int tlogoMinX;
int tlogoMaxX;
int tlogoMinY;
int tlogoMaxY;
int edgemask_filled=0;
unsigned char thoriz_edgemask[MAXHEIGHT*MAXWIDTH];
unsigned char tvert_edgemask[MAXHEIGHT*MAXWIDTH];
int clogoMinX;
int clogoMaxX;
int clogoMinY;
int clogoMaxY;
unsigned char choriz_edgemask[MAXHEIGHT*MAXWIDTH];
unsigned char cvert_edgemask[MAXHEIGHT*MAXWIDTH];
int play_nice_start = -1;
int play_nice_end = -1;
long play_nice_sleep = 2L;
FILE *dump_data_file = (FILE *)NULL;
uint8_t ccData[500];
int ccDataLen;
static uint8_t prevccData[500];
static int prevccDataLen;
long cc_count[5] = { 0, 0, 0, 0, 0 };
int most_cc_type = NONE;
unsigned char ** cc_screen = NULL;
unsigned char ** cc_memory = NULL;
int minY; // The top of the picture for aspect ratio calculation
int maxY; // The bottom of the picture for aspect ratio calculation
int minX; // The top of the picture for aspect ratio calculation
int maxX; // The bottom of the picture for aspect ratio calculation
//bool currentAR;
//bool lastAR;
//bool showAvgAR;
bool isSecondPass = false;
long lastFrame = 0;
long lastFrameCommCalculated = 0;
bool ccCheck = false;
bool loadingCSV = false;
bool loadingTXT = false;
int helpflag = 0;
int timeflag = 0;
#define MAXTIMEFLAG 2
int recalculate=0;
char *helptext[]=
{
"Help: press any key to remove",
"Key Action",
"Arrows Reposition current location",
"PgUp/PgDn Reposition current location",
"Alt+PgUp/PgDn Reposition current location by 1/2 second",
"n/p Jump to next/previous cutpoint",
"e/b Jump to next/previous end of cblock",
"z/u Zoom in/out on the timeline",
"g Graph on/off",
"x XDS info on/off",
"t Toggle current cblock between show and commercial",
"w Write the new cutpoints to the output files",
"c Dump this frame as CutScene"
"F2 Reduce the max_volume detection level",
"F3 Reduce the non_uniformity detection level",
"F4 Reduce the max_avg_brighness detection level",
"F5 Toggle frame number / timecode display",
"",
"During commercial break review",
"e Set end of commercial to this position",
"b Set begin of commercial to this position",
"i Insert a new commercial",
"d Delete the commercial at current location",
"s Jump to Start of the recording",
"f Jump to Finish of the recording",
"",
"Divide and conquer commercial break review",
"j Set the before marker frame",
"k Set the end marker frame",
"l Clear the marker frames",
0
};
double currentGoodEdge = 0.0;
int lineStart[MAXHEIGHT]; /* Area to include for black frame detection, non logo area */
int lineEnd[MAXHEIGHT];
unsigned char hor_edgecount[MAXHEIGHT*MAXWIDTH];
unsigned char ver_edgecount[MAXHEIGHT*MAXWIDTH];
unsigned char max_br[MAXHEIGHT*MAXWIDTH];
unsigned char min_br[MAXHEIGHT*MAXWIDTH];
unsigned char graph[MAXHEIGHT*MAXWIDTH*3];
int gy=0;
// Function Prototypes
bool BuildBlocks(bool recalc);
void Recalc(void);
double ValidateBlackFrames(long reason, double ratio, int remove);
int DetectCommercials(int, double);
bool BuildMasterCommList(void);
void WeighBlocks(void);
bool OutputBlocks(void);
void OutputAspect(void);
void OutputTraining(void);
bool ProcessLogoTest(int framenum_real, int curLogoTest, int close);
void OutputStrict(double len, double delta, double tol);
int InputReffer(char *ext, int setfps);
bool IsStandardCommercialLength(double length, double tolerance, bool strict);
bool LengthWithinTolerance(double test_length, double expected_length, double tolerance);
double FindNumber(char* str1, char* str2, double v);
char * FindString(char* str1, char* str2, char *v);
void AddIniString( char *s);
char* intSecondsToStrMinutes(int seconds);
char* dblSecondsToStrMinutes(double seconds);
char* dblSecondsToStrMinutesFrames(double seconds);
FILE* LoadSettings(int argc, char ** argv);
int GetAvgBrightness(void);
bool CheckFrameIsBlack(void);
void BuildBlackFrameCommList(void);
bool CheckSceneHasChanged(void);
#if 0
void BuildSceneChangeCommList(void);
void BuildSceneChangeCommList2(void);
#endif
void backfill_frame_volumes();
void PrintLogoFrameGroups(void);
void PrintCCBlocks(void);
void ResetLogoBuffers(void);
void EdgeDetect(unsigned char* frame_ptr, int maskNumber);
void EdgeCount(unsigned char* frame_ptr);
void FillLogoBuffer(void);
bool SearchForLogoEdges(void);
double CheckStationLogoEdge(unsigned char* testFrame);
double DoubleCheckStationLogoEdge(unsigned char* testFrame);
void SetEdgeMaskArea(unsigned char* temp);
int ClearEdgeMaskArea(unsigned char* temp, unsigned char* test);
int CountEdgePixels(void);
void DumpEdgeMask(unsigned char* buffer, int direction);
void DumpEdgeMasks(void);
void BuildBlackFrameAndLogoCommList(void);
bool CheckFramesForLogo(int start, int end);
char CheckFramesForCommercial(int start, int end);
char CheckFramesForReffer(int start, int end);
void SaveLogoMaskData(void);
void LoadLogoMaskData(void);
double CalculateLogoFraction(int start, int end);
bool CheckFrameForLogo(int i);
int CountSceneChanges(int StartFrame, int EndFrame);
void Debug(int level, char* fmt, ...);
void InitProcessLogoTest(void);
void InitComSkip(void);
void InitLogoBuffers(void);
void FindIniFile(void);
double FindScoreThreshold(double percentile);
void OutputLogoHistogram(int buckets);
void OutputbrightHistogram(void);
void OutputuniformHistogram(void);
void OutputHistogram(int *histogram, int scale, char *title, bool truncate);
int FindBlackThreshold(double percentile);
int FindUniformThreshold(double percentile);
void OutputFrameArray(bool screenOnly);
void OutputBlackArray();
void OutputFrame();
void OpenOutputFiles();
void InitializeFrameArray(long i);
void InitializeBlackArray(long i);
void InitializeSchangeArray(long i);
void InitializeLogoBlockArray(long i);
void InitializeARBlockArray(long i);
void InitializeACBlockArray(long i);
void InitializeBlockArray(long i);
void InitializeCCBlockArray(long i);
void InitializeCCTextArray(long i);
void PrintArgs(void);
void close_dump(void);
void OutputCommercialBlock(int i, long prev, long start, long end, bool last);
void ProcessCSV(FILE *);
void OutputCCBlock(long i);
void ProcessCCData(void);
bool CheckOddParity(unsigned char ch);
void AddNewCCBlock(long current_frame, int type, bool cc_on_screen, bool cc_in_memory);
char* CCTypeToStr(int type);
int DetermineCCTypeForBlock(long start, long end);
double AverageARForBlock(int start, int end);