// VERSION = "1.003"
//
// Standard C code loaded outside XS space. Contains useful routines used by advert detection functions
#include "ts_advert.h"
#include "ts_cut.h"
#include "ts_split.h"
//---------------------------------------------------------------------------------------------------------
// MACROS
//---------------------------------------------------------------------------------------------------------
#define _USER_SETTING(HREF, NAME, VAR) HVF_IV(HREF, NAME, user_data->VAR)
#define USER_SETTING(NAME) _USER_SETTING(settings_href, NAME, NAME)
#define USER_FRAME_SETTING(NAME) _USER_SETTING(frame_settings_href, NAME, frame_settings.NAME)
#define USER_LOGO_SETTING(NAME) _USER_SETTING(logo_settings_href, NAME, logo_settings.NAME)
#define USER_AUDIO_SETTING(NAME) _USER_SETTING(audio_settings_href, NAME, audio_settings.NAME)
#define USER_PERL_SETTING(NAME) _USER_SETTING(settings_href, NAME, perl_set.NAME)
#define USER_FRAME_PERL_SETTING(NAME) _USER_SETTING(frame_settings_href, NAME, frame_settings.perl_set.NAME)
#define USER_LOGO_PERL_SETTING(NAME) _USER_SETTING(logo_settings_href, NAME, logo_settings.perl_set.NAME)
#define USER_AUDIO_PERL_SETTING(NAME) _USER_SETTING(audio_settings_href, NAME, audio_settings.perl_set.NAME)
//---------------------------------------------------------------------------------------------------------
// HOOKS
//---------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------
static void advert_progress_hook(enum TS_progress_state state, unsigned progress, unsigned total, void *user_data)
{
dSP ;
struct Ad_user_data *hook_data = (struct Ad_user_data *)user_data ;
char *state_str ;
char ad_state_str[256] ;
ENTER;
SAVETMPS;
if (hook_data->progress_callback && total)
{
switch (state)
{
case PROGRESS_START : state_str = "START"; break ;
case PROGRESS_RUNNING : state_str = "RUNNING"; break ;
case PROGRESS_END : state_str = "END"; break ;
case PROGRESS_STOPPED : state_str = "STOPPED"; break ;
default : state_str = "UNKNOWN"; break ;
}
if (hook_data->process_state == ADVERT_PREPROCESS)
{
sprintf(ad_state_str, "PREPROCESS %s", state_str) ;
}
else
{
sprintf(ad_state_str, "PROCESS %s", state_str) ;
}
PUSHMARK(SP);
XPUSHs(sv_2mortal( newSVpv( (char *)ad_state_str, strlen(ad_state_str) ) ));
XPUSHs(sv_2mortal( newSViv(progress) ));
XPUSHs(sv_2mortal( newSViv(total) ));
XPUSHs((SV *)hook_data->extra_data);
PUTBACK;
call_sv(hook_data->progress_callback, G_DISCARD);
SPAGAIN;
}
FREETMPS;
LEAVE;
}
//========================================================================================================
// FUNCTIONS
//========================================================================================================
//---------------------------------------------------------------------------------------------------------
// Copy any user settings from the Perl HASH into the user_data
//
static void advert_set_settings(struct Ad_user_data *user_data, HV *settings_href)
{
SV **val;
HV *frame_settings_href = NULL ;
HV *logo_settings_href = NULL ;
HV *audio_settings_href = NULL ;
if (settings_href)
{
val = HVF(settings_href, frame) ;
if (val)
frame_settings_href = (HV *) SvRV (*val);
val = HVF(settings_href, logo) ;
if (val)
logo_settings_href = (HV *) SvRV (*val);
val = HVF(settings_href, audio) ;
if (val)
audio_settings_href = (HV *) SvRV (*val);
//-- user settings --
HVF_SVV(settings_href, progress_callback, user_data->progress_callback) ;
HVF_SVV(settings_href, user_data, user_data->extra_data) ;
_USER_SETTING(settings_href, dbg-adv, debug) ;
_USER_SETTING(settings_href, dbg-ts, ts_debug) ;
USER_SETTING(pid) ;
USER_SETTING(audio_pid) ;
USER_SETTING(detection_method) ;
USER_PERL_SETTING(max_advert) ;
USER_PERL_SETTING(min_advert) ;
USER_PERL_SETTING(min_program) ;
USER_PERL_SETTING(start_pad) ;
USER_PERL_SETTING(end_pad) ;
USER_PERL_SETTING(min_frames) ;
USER_PERL_SETTING(frame_window) ;
USER_PERL_SETTING(max_gap) ;
USER_PERL_SETTING(reduce_end) ;
USER_PERL_SETTING(reduce_min_gap) ;
//-- frame settings --
_USER_SETTING(settings_href, dbg-frame, frame_settings.debug) ;
if (frame_settings_href)
{
USER_FRAME_SETTING(max_black) ;
USER_FRAME_SETTING(window_percent) ;
USER_FRAME_SETTING(max_brightness) ;
USER_FRAME_SETTING(test_brightness) ;
USER_FRAME_SETTING(brightness_jump) ;
USER_FRAME_SETTING(schange_cutlevel) ;
USER_FRAME_SETTING(schange_jump) ;
USER_FRAME_SETTING(noise_level) ;
USER_FRAME_SETTING(remove_logo) ;
USER_FRAME_PERL_SETTING(max_advert) ;
USER_FRAME_PERL_SETTING(min_advert) ;
USER_FRAME_PERL_SETTING(min_program) ;
USER_FRAME_PERL_SETTING(start_pad) ;
USER_FRAME_PERL_SETTING(end_pad) ;
USER_FRAME_PERL_SETTING(min_frames) ;
USER_FRAME_PERL_SETTING(frame_window) ;
USER_FRAME_PERL_SETTING(max_gap) ;
USER_FRAME_PERL_SETTING(reduce_end) ;
USER_FRAME_PERL_SETTING(reduce_min_gap) ;
}
//-- logo settings --
_USER_SETTING(settings_href, dbg-logo, logo_settings.debug) ;
if (logo_settings_href)
{
USER_LOGO_SETTING(window_percent) ;
USER_LOGO_SETTING(logo_window) ;
USER_LOGO_SETTING(logo_edge_radius) ;
USER_LOGO_SETTING(logo_edge_step) ;
USER_LOGO_SETTING(logo_edge_threshold) ;
USER_LOGO_SETTING(logo_checking_period) ;
USER_LOGO_SETTING(logo_skip_frames) ;
USER_LOGO_SETTING(logo_num_checks) ;
USER_LOGO_SETTING(logo_ok_percent) ;
USER_LOGO_SETTING(logo_max_percentage_of_screen) ;
USER_LOGO_SETTING(logo_ave_points) ;
USER_LOGO_SETTING(logo_fall_threshold) ;
USER_LOGO_SETTING(logo_rise_threshold) ;
USER_LOGO_PERL_SETTING(max_advert) ;
USER_LOGO_PERL_SETTING(min_advert) ;
USER_LOGO_PERL_SETTING(min_program) ;
USER_LOGO_PERL_SETTING(start_pad) ;
USER_LOGO_PERL_SETTING(end_pad) ;
USER_LOGO_PERL_SETTING(min_frames) ;
USER_LOGO_PERL_SETTING(frame_window) ;
USER_LOGO_PERL_SETTING(max_gap) ;
USER_LOGO_PERL_SETTING(reduce_end) ;
USER_LOGO_PERL_SETTING(reduce_min_gap) ;
}
//-- audio settings --
_USER_SETTING(settings_href, dbg-audio, audio_settings.debug) ;
if (audio_settings_href)
{
USER_AUDIO_SETTING(scale) ;
USER_AUDIO_SETTING(silence_threshold) ;
USER_AUDIO_SETTING(silence_window) ;
USER_AUDIO_PERL_SETTING(max_advert) ;
USER_AUDIO_PERL_SETTING(min_advert) ;
USER_AUDIO_PERL_SETTING(min_program) ;
USER_AUDIO_PERL_SETTING(start_pad) ;
USER_AUDIO_PERL_SETTING(end_pad) ;
USER_AUDIO_PERL_SETTING(min_frames) ;
USER_AUDIO_PERL_SETTING(frame_window) ;
USER_AUDIO_PERL_SETTING(max_gap) ;
USER_AUDIO_PERL_SETTING(reduce_end) ;
USER_AUDIO_PERL_SETTING(reduce_min_gap) ;
}
}
}
//---------------------------------------------------------------------------------------------------------
// Copy all settings from the user_data struct into the Perl HASH
//
static void advert_get_settings(struct Ad_user_data *user_data, HV *settings)
{
HV * rh;
//== Common ===============
//-- Used by C routines ---
HVS_INT_SETTING(settings, pid, user_data->pid, ) ;
HVS_INT_SETTING(settings, audio_pid, user_data->audio_pid, ) ;
HVS_INT_SETTING(settings, detection_method, user_data->detection_method, ) ;
HVS_INT_SETTING(settings, num_frames, user_data->last_framenum+1, ) ;
//-- Used only by Perl modules --
HVS_INT_SETTING(settings, max_advert, user_data->perl_set.max_advert, ) ;
HVS_INT_SETTING(settings, min_advert, user_data->perl_set.min_advert, ) ;
HVS_INT_SETTING(settings, min_program, user_data->perl_set.min_program, ) ;
HVS_INT_SETTING(settings, start_pad, user_data->perl_set.start_pad, ) ;
HVS_INT_SETTING(settings, end_pad, user_data->perl_set.end_pad, ) ;
HVS_INT_SETTING(settings, min_frames, user_data->perl_set.min_frames, ) ;
HVS_INT_SETTING(settings, frame_window, user_data->perl_set.frame_window, ) ;
HVS_INT_SETTING(settings, max_gap, user_data->perl_set.max_gap, ) ;
HVS_INT_SETTING(settings, reduce_end, user_data->perl_set.reduce_end, ) ;
HVS_INT_SETTING(settings, reduce_min_gap, user_data->perl_set.reduce_min_gap, ) ;
// HVS_INT_SETTING(settings, increase_start, 0, ) ;
// HVS_INT_SETTING(settings, increase_min_gap, (60*FPS), ) ;
//== Frame ===============
//-- Used by C routines ---
rh = (HV *)sv_2mortal((SV *)newHV());
HVS_INT_SETTING(rh, max_black, user_data->frame_settings.max_black, frame.) ;
HVS_INT_SETTING(rh, window_percent, user_data->frame_settings.window_percent, frame.) ;
HVS_INT_SETTING(rh, max_brightness, user_data->frame_settings.max_brightness, frame.) ;
HVS_INT_SETTING(rh, test_brightness, user_data->frame_settings.test_brightness, frame.) ;
HVS_INT_SETTING(rh, brightness_jump, user_data->frame_settings.brightness_jump, frame.) ;
HVS_INT_SETTING(rh, schange_cutlevel, user_data->frame_settings.schange_cutlevel, frame.) ;
HVS_INT_SETTING(rh, schange_jump, user_data->frame_settings.schange_jump, frame.) ;
HVS_INT_SETTING(rh, noise_level, user_data->frame_settings.noise_level, frame.) ;
HVS_INT_SETTING(rh, remove_logo, user_data->frame_settings.remove_logo, frame.) ;
//-- Used only by Perl modules --
HVS_INT_SETTING(rh, max_advert, user_data->frame_settings.perl_set.max_advert, frame.) ;
HVS_INT_SETTING(rh, min_advert, user_data->frame_settings.perl_set.min_advert, frame.) ;
HVS_INT_SETTING(rh, min_program, user_data->frame_settings.perl_set.min_program, frame.) ;
HVS_INT_SETTING(rh, start_pad, user_data->frame_settings.perl_set.start_pad, frame.) ;
HVS_INT_SETTING(rh, end_pad, user_data->frame_settings.perl_set.end_pad, frame.) ;
HVS_INT_SETTING(rh, min_frames, user_data->frame_settings.perl_set.min_frames, frame.) ;
HVS_INT_SETTING(rh, frame_window, user_data->frame_settings.perl_set.frame_window, frame.) ;
HVS_INT_SETTING(rh, max_gap, user_data->frame_settings.perl_set.max_gap, frame.) ;
HVS_INT_SETTING(rh, reduce_end, user_data->frame_settings.perl_set.reduce_end, frame.) ;
HVS_INT_SETTING(rh, reduce_min_gap, user_data->frame_settings.perl_set.reduce_min_gap, frame.) ;
HVS(settings, frame, newRV((SV *)rh)) ;
//== Logo ===============
//-- Used by C routines ---
rh = (HV *)sv_2mortal((SV *)newHV());
HVS_INT_SETTING(rh, window_percent, user_data->logo_settings.window_percent, logo.) ;
HVS_INT_SETTING(rh, logo_window, user_data->logo_settings.logo_window, logo.) ;
HVS_INT_SETTING(rh, logo_edge_radius, user_data->logo_settings.logo_edge_radius, logo.) ;
HVS_INT_SETTING(rh, logo_edge_step, user_data->logo_settings.logo_edge_step, logo.) ;
HVS_INT_SETTING(rh, logo_edge_threshold, user_data->logo_settings.logo_edge_threshold, logo.) ;
HVS_INT_SETTING(rh, logo_checking_period, user_data->logo_settings.logo_checking_period, logo.) ;
HVS_INT_SETTING(rh, logo_skip_frames, user_data->logo_settings.logo_skip_frames, logo.) ;
HVS_INT_SETTING(rh, logo_num_checks, user_data->logo_settings.logo_num_checks, logo.) ;
HVS_INT_SETTING(rh, logo_ok_percent, user_data->logo_settings.logo_ok_percent, logo.) ;
HVS_INT_SETTING(rh, logo_max_percentage_of_screen, user_data->logo_settings.logo_max_percentage_of_screen, logo.) ;
HVS_INT_SETTING(rh, logo_ave_points, user_data->logo_settings.logo_ave_points, logo.) ;
//-- Used only by Perl modules --
HVS_INT_SETTING(rh, max_advert, user_data->logo_settings.perl_set.max_advert, logo.) ;
HVS_INT_SETTING(rh, min_advert, user_data->logo_settings.perl_set.min_advert, logo.) ;
HVS_INT_SETTING(rh, min_program, user_data->logo_settings.perl_set.min_program, logo.) ;
HVS_INT_SETTING(rh, start_pad, user_data->logo_settings.perl_set.start_pad, logo.) ;
HVS_INT_SETTING(rh, end_pad, user_data->logo_settings.perl_set.end_pad, logo.) ;
HVS_INT_SETTING(rh, min_frames, user_data->logo_settings.perl_set.min_frames, logo.) ;
HVS_INT_SETTING(rh, frame_window, user_data->logo_settings.perl_set.frame_window, logo.) ;
HVS_INT_SETTING(rh, max_gap, user_data->logo_settings.perl_set.max_gap, logo.) ;
HVS_INT_SETTING(rh, reduce_end, user_data->logo_settings.perl_set.reduce_end, logo.) ;
HVS_INT_SETTING(rh, reduce_min_gap, user_data->logo_settings.perl_set.reduce_min_gap, logo.) ;
HVS_INT_SETTING(rh, logo_rise_threshold, user_data->logo_settings.logo_rise_threshold, logo.) ;
HVS_INT_SETTING(rh, logo_fall_threshold, user_data->logo_settings.logo_fall_threshold, logo.) ;
HVS(settings, logo, newRV((SV *)rh)) ;
//== Audio ===============
//-- Used by C routines ---
rh = (HV *)sv_2mortal((SV *)newHV());
HVS_INT_SETTING(rh, scale, user_data->audio_settings.scale, audio.) ;
HVS_INT_SETTING(rh, silence_threshold, user_data->audio_settings.silence_threshold, audio.) ;
//-- Used only by Perl modules --
HVS_INT_SETTING(rh, max_advert, user_data->audio_settings.perl_set.max_advert, audio.) ;
HVS_INT_SETTING(rh, min_advert, user_data->audio_settings.perl_set.min_advert, audio.) ;
HVS_INT_SETTING(rh, min_program, user_data->audio_settings.perl_set.min_program, audio.) ;
HVS_INT_SETTING(rh, start_pad, user_data->audio_settings.perl_set.start_pad, audio.) ;
HVS_INT_SETTING(rh, end_pad, user_data->audio_settings.perl_set.end_pad, audio.) ;
HVS_INT_SETTING(rh, min_frames, user_data->audio_settings.perl_set.min_frames, audio.) ;
HVS_INT_SETTING(rh, frame_window, user_data->audio_settings.perl_set.frame_window, audio.) ;
HVS_INT_SETTING(rh, max_gap, user_data->audio_settings.perl_set.max_gap, audio.) ;
HVS_INT_SETTING(rh, reduce_end, user_data->audio_settings.perl_set.reduce_end, audio.) ;
HVS_INT_SETTING(rh, reduce_min_gap, user_data->audio_settings.perl_set.reduce_min_gap, audio.) ;
HVS_INT_SETTING(rh, silence_window, user_data->audio_settings.silence_window, audio.) ;
HVS(settings, audio, newRV((SV *)rh)) ;
//== Save Totals ===============
//-- Used only by Perl modules --
HVS_INT_SETTING(settings, total_logo_frames, user_data->logo_totals.num_logo_frames, ) ;
HVS_INT_SETTING(settings, total_black_frames, user_data->frame_totals.num_black_frames, ) ;
HVS_INT_SETTING(settings, total_scene_frames, user_data->frame_totals.num_scene_frames, ) ;
HVS_INT_SETTING(settings, total_size_frames, user_data->frame_totals.num_size_frames, ) ;
}
//---------------------------------------------------------------------------------------------------------
static HV *advert_result(struct Ad_user_data * user_data, unsigned index)
{
HV * rh;
HVS_RESULT_START ;
rh = (HV *)sv_2mortal((SV *)newHV());
HVS_INT_RESULT(rh, frame, user_data->results_array[index].video_framenum) ;
HVS_INT_RESULT(rh, frame_end, user_data->results_array[index].video_framenum) ;
HVS_INT_RESULT(rh, start_pkt, user_data->results_array[index].start_pkt) ;
HVS_INT_RESULT(rh, end_pkt, user_data->results_array[index].end_pkt) ;
HVS_INT_RESULT(rh, gop_pkt, user_data->results_array[index].gop_pkt) ;
/*
unsigned black_frame ;
unsigned scene_frame ;
unsigned screen_width ;
unsigned screen_height ;
unsigned brightness ;
unsigned uniform ;
unsigned dimCount;
int sceneChangePercent;
*/
HVS_FRAME_RESULT(rh, black_frame, index) ;
HVS_FRAME_RESULT(rh, scene_frame, index) ;
HVS_FRAME_RESULT(rh, size_change, index) ;
HVS_FRAME_RESULT(rh, screen_width, index) ;
HVS_FRAME_RESULT(rh, screen_height, index) ;
HVS_FRAME_RESULT(rh, brightness, index) ;
HVS_FRAME_RESULT(rh, uniform, index) ;
HVS_FRAME_RESULT(rh, dimCount, index) ;
HVS_FRAME_RESULT(rh, sceneChangePercent, index) ;
/*
unsigned logo_frame ; // boolean
unsigned match_percent ;
unsigned ave_percent ;
*/
HVS_LOGO_RESULT(rh, logo_frame, index) ;
HVS_LOGO_RESULT(rh, match_percent, index) ;
HVS_LOGO_RESULT(rh, ave_percent, index) ;
/*
unsigned audio_framenum ;
int64_t pts ;
unsigned volume ;
unsigned max_volume ;
unsigned sample_rate ;
unsigned channels ;
unsigned samples_per_frame ;
unsigned samples ;
unsigned framesize ;
*/
HVS_AUDIO_RESULT(rh, audio_framenum, index) ;
/*HVS_AUDIO_RESULT(rh, pts, index) ;*/
_store_ts(rh, "pts", user_data->results_array[index].audio_results.pts) ;
HVS_AUDIO_RESULT(rh, volume, index) ;
HVS_AUDIO_RESULT(rh, max_volume, index) ;
HVS_AUDIO_RESULT(rh, sample_rate, index) ;
HVS_AUDIO_RESULT(rh, channels, index) ;
HVS_AUDIO_RESULT(rh, samples_per_frame, index) ;
HVS_AUDIO_RESULT(rh, samples, index) ;
HVS_AUDIO_RESULT(rh, framesize, index) ;
HVS_AUDIO_RESULT(rh, silent_frame, index) ;
HVS_AUDIO_RESULT(rh, volume_dB, index) ;
HVS_RESULT_END ;
return rh ;
}
//---------------------------------------------------------------------------------------------------------
static void execute_advert_detection(struct Ad_user_data * user_data, char *filename, HV *settings_href, HV *results, HV *settings)
{
SV **val;
HV * rh;
unsigned i ;
unsigned video_framenum ;
char key[256] ;
// Set settings
advert_set_settings(user_data, settings_href) ;
if (user_data->debug) fprintf(stderr, "[XS] Pre-processing...\n") ;
if (user_data->debug) dbg_print_settings(user_data) ;
// Run detection - pre-process
user_data->process_state = ADVERT_PREPROCESS ;
run_preprocess(user_data, filename, advert_progress_hook) ;
if (user_data->debug) fprintf(stderr, "[XS] dvb_err=%s [%03d]\n", dvb_error_str(dvb_error_code), dvb_error_code) ;
if (user_data->debug) fprintf(stderr, "[XS] Detecting...\n") ;
// Run detection - main
user_data->process_state = ADVERT_PROCESS ;
run_detect(user_data, filename, advert_progress_hook) ;
if (user_data->debug) fprintf(stderr, "[XS] dvb_err=%s [%03d]\n", dvb_error_str(dvb_error_code), dvb_error_code) ;
if (user_data->debug) fprintf(stderr, "[XS] Detect done\n") ;
// == Pass results back to Perl ==
// copy settings
advert_get_settings(user_data, settings) ;
#ifdef PERLXS_DEBUG
printf("frame,frame_end,start_pkt,end_pkt,gop_pkt,black_frame,scene_frame,size_change,screen_width,screen_height,") ;
printf("brightness,uniform,dimCount,sceneChangePercent,") ;
printf("logo_frame,match_percent,ave_percent,") ;
printf("audio_framenum,volume,max_volume,sample_rate,channels,samples_per_frame,samples,") ;
printf("framesize,silent_frame,volume_dB") ;
printf("\n") ;
#endif
// // get frame data
// for (i=0; i < user_data->results_list_size; i++)
// {
// rh = advert_result(user_data, user_data->results_list[i].idx) ;
// av_push(frames, newRV((SV *)rh));
// }
// // Free up structures
// free_user_data(user_data) ;
}