Merge remote-tracking branch 'upstream/master'
commit
eba52023f9
|
@ -639,7 +639,7 @@ CREATE TABLE `Users` (
|
|||
`Devices` enum('None','View','Edit') NOT NULL default 'None',
|
||||
`System` enum('None','View','Edit') NOT NULL default 'None',
|
||||
`MaxBandwidth` varchar(16),
|
||||
`MonitorIds` tinytext,
|
||||
`MonitorIds` text,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `UC_Username` (`Username`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE Users MODIFY MonitorIds text;
|
|
@ -23,7 +23,7 @@
|
|||
%global _hardened_build 1
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.33.4
|
||||
Version: 1.33.6
|
||||
Release: 1%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
|
@ -410,11 +410,14 @@ EOF
|
|||
%dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload
|
||||
|
||||
%changelog
|
||||
* Sun Apr 07 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.6-1
|
||||
- Bump to 1.33.6 Development
|
||||
|
||||
* Sat Mar 30 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.4-1
|
||||
- Bump tp 1.33.4 Development
|
||||
- Bump to 1.33.4 Development
|
||||
|
||||
* Tue Dec 11 2018 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.0-1
|
||||
- Bump tp 1.33.0 Development
|
||||
- Bump to 1.33.0 Development
|
||||
|
||||
* Sat Dec 08 2018 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.32.3-1
|
||||
- 1.32.3 Release
|
||||
|
|
|
@ -67,7 +67,7 @@ sub AUTOLOAD {
|
|||
if ( exists($self->{$name}) ) {
|
||||
return $self->{$name};
|
||||
}
|
||||
Error("Can't access $name member of object of class $class");
|
||||
Error("Can't access $name $AUTOLOAD member of object of class $class");
|
||||
}
|
||||
|
||||
sub getKey {
|
||||
|
|
|
@ -84,7 +84,7 @@ sub open
|
|||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new(keep_alive => 1);
|
||||
$self->{ua}->agent("ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION);
|
||||
$self->{ua}->agent("ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION);
|
||||
$self->{state} = 'closed';
|
||||
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
|
||||
$self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD);
|
||||
|
|
|
@ -40,7 +40,7 @@ sub open
|
|||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION );
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
||||
$self->{state} = 'closed';
|
||||
Debug( "sendCmd credentials control address:'".$ADDRESS
|
||||
."' realm:'" . $REALM
|
||||
|
|
|
@ -45,7 +45,7 @@ sub open {
|
|||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent('ZoneMinder Control Agent/'.$ZoneMinder::Base::ZM_VERSION);
|
||||
$self->{ua}->agent('ZoneMinder Control Agent/'.ZoneMinder::Base::ZM_VERSION);
|
||||
$self->{state} = 'closed';
|
||||
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
|
||||
Debug ( "sendCmd credentials control address:'".$ADDRESS
|
||||
|
@ -120,6 +120,7 @@ sub sendCmd {
|
|||
|
||||
Debug('sendCmd command: ' . $url);
|
||||
if ( $res->is_success ) {
|
||||
Debug($res->content);
|
||||
return !undef;
|
||||
}
|
||||
Error("Error check failed: '".$res->status_line()."' cmd:'".$cmd."'");
|
||||
|
@ -155,6 +156,7 @@ sub sendCmdPost {
|
|||
Debug("sendCmdPost credentials control to: $PROTOCOL$ADDRESS$url realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'");
|
||||
|
||||
if ( $res->is_success ) {
|
||||
Debug($res->content);
|
||||
return !undef;
|
||||
}
|
||||
Error("sendCmdPost Error check failed: '".$res->status_line()."' cmd:");
|
||||
|
|
|
@ -30,7 +30,7 @@ use autouse 'Pod::Usage'=>qw(pod2usage);
|
|||
use POSIX qw/strftime EPIPE/;
|
||||
use Socket;
|
||||
#use Data::Dumper;
|
||||
use Module::Load::Conditional qw{can_load};;
|
||||
use Module::Load::Conditional qw{can_load};
|
||||
|
||||
use constant MAX_CONNECT_DELAY => 15;
|
||||
use constant MAX_COMMAND_WAIT => 1800;
|
||||
|
@ -43,7 +43,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
|||
|
||||
logInit();
|
||||
|
||||
my $arg_string = join( " ", @ARGV );
|
||||
my $arg_string = join(' ', @ARGV);
|
||||
|
||||
my $id;
|
||||
my %options;
|
||||
|
@ -64,22 +64,46 @@ GetOptions(
|
|||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
if ( !$id ) {
|
||||
print( STDERR "Please give a valid monitor id\n" );
|
||||
print(STDERR "Please give a valid monitor id\n");
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
( $id ) = $id =~ /^(\w+)$/;
|
||||
|
||||
Debug("zmcontrol: arg string: $arg_string");
|
||||
|
||||
my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock';
|
||||
Debug("zmcontrol: arg string: $arg_string sock file $sock_file");
|
||||
|
||||
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0)
|
||||
or Fatal("Can't open socket: $!");
|
||||
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
|
||||
|
||||
my $saddr = sockaddr_un($sock_file);
|
||||
my $server_up = connect(CLIENT, $saddr);
|
||||
if ( !$server_up ) {
|
||||
|
||||
if ( $options{command} ) {
|
||||
# Have a command, so we are the client, connect to the server and send it.
|
||||
|
||||
my $tries = 10;
|
||||
my $server_up;
|
||||
while ( $tries and ! ( $server_up = connect(CLIENT, $saddr) ) ) {
|
||||
Debug("Failed to connect to $server_up at $sock_file");
|
||||
runCommand("zmdc.pl start zmcontrol.pl --id=$id");
|
||||
sleep 1;
|
||||
$tries -= 1;
|
||||
}
|
||||
if ( $server_up ) {
|
||||
# The server is there, connect to it
|
||||
#print( "Writing commands\n" );
|
||||
CLIENT->autoflush();
|
||||
|
||||
if ( $options{command} ) {
|
||||
my $message = jsonEncode(\%options);
|
||||
print(CLIENT $message);
|
||||
}
|
||||
shutdown(CLIENT, 1);
|
||||
} else {
|
||||
Error("Unable to connect to zmcontrol server at $sock_file");
|
||||
}
|
||||
} else {
|
||||
|
||||
# The server isn't there
|
||||
my $monitor = zmDbGetMonitorAndControl($id);
|
||||
if ( !$monitor ) {
|
||||
|
@ -113,99 +137,72 @@ if ( !$server_up ) {
|
|||
Fatal("Can't load ZoneMinder::Control::$protocol\n$Module::Load::Conditional::ERROR");
|
||||
}
|
||||
|
||||
if ( my $cpid = fork() ) {
|
||||
logReinit();
|
||||
Info("Control server $id/$protocol starting at "
|
||||
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||
);
|
||||
|
||||
# Parent process just sleep and fall through
|
||||
socket(CLIENT, PF_UNIX, SOCK_STREAM, 0)
|
||||
or die("Can't open socket: $!");
|
||||
my $attempts = 0;
|
||||
while ( !connect(CLIENT, $saddr) ) {
|
||||
$attempts++;
|
||||
Fatal("Can't connect: $! after $attempts attempts to $sock_file") if $attempts > MAX_CONNECT_DELAY;
|
||||
sleep(1);
|
||||
}
|
||||
} elsif ( defined($cpid) ) {
|
||||
close(STDOUT);
|
||||
close(STDERR);
|
||||
$0 = $0." --id=$id";
|
||||
|
||||
setpgrp();
|
||||
my $control = "ZoneMinder::Control::$protocol"->new($id);
|
||||
my $control_key = $control->getKey();
|
||||
$control->loadMonitor();
|
||||
|
||||
logReinit();
|
||||
$control->open();
|
||||
|
||||
Info("Control server $id/$protocol starting at "
|
||||
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||
);
|
||||
|
||||
$0 = $0." --id $id";
|
||||
|
||||
my $control = "ZoneMinder::Control::$protocol"->new($id);
|
||||
my $control_key = $control->getKey();
|
||||
$control->loadMonitor();
|
||||
|
||||
$control->open();
|
||||
|
||||
socket(SERVER, PF_UNIX, SOCK_STREAM, 0)
|
||||
or Fatal("Can't open socket: $!");
|
||||
unlink($sock_file);
|
||||
bind(SERVER, $saddr) or Fatal("Can't bind: $!");
|
||||
listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
|
||||
|
||||
my $rin = '';
|
||||
vec( $rin, fileno(SERVER), 1 ) = 1;
|
||||
my $win = $rin;
|
||||
my $ein = $win;
|
||||
my $timeout = MAX_COMMAND_WAIT;
|
||||
while( 1 ) {
|
||||
my $nfound = select(my $rout = $rin, undef, undef, $timeout);
|
||||
if ( $nfound > 0 ) {
|
||||
if ( vec( $rout, fileno(SERVER), 1 ) ) {
|
||||
my $paddr = accept(CLIENT, SERVER);
|
||||
my $message = <CLIENT>;
|
||||
|
||||
next if !$message;
|
||||
|
||||
my $params = jsonDecode($message);
|
||||
#Debug( Dumper( $params ) );
|
||||
|
||||
my $command = $params->{command};
|
||||
close( CLIENT );
|
||||
if ( $command eq 'quit' ) {
|
||||
last;
|
||||
}
|
||||
$control->$command($params);
|
||||
} else {
|
||||
Fatal('Bogus descriptor');
|
||||
}
|
||||
} elsif ( $nfound < 0 ) {
|
||||
if ( $! == EPIPE ) {
|
||||
Error("Can't select: $!");
|
||||
} else {
|
||||
Fatal("Can't select: $!");
|
||||
}
|
||||
} else {
|
||||
#print( "Select timed out\n" );
|
||||
last;
|
||||
}
|
||||
} # end while forever
|
||||
Info("Control server $id/$protocol exiting");
|
||||
unlink($sock_file);
|
||||
$control->close();
|
||||
exit(0);
|
||||
} else {
|
||||
Fatal("Can't fork: $!");
|
||||
# If we have a command when starting up, then do it.
|
||||
if ( $options{command} ) {
|
||||
my $command = $options{command};
|
||||
$control->$command(\%options);
|
||||
}
|
||||
|
||||
socket(SERVER, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
|
||||
unlink($sock_file);
|
||||
bind(SERVER, $saddr) or Fatal("Can't bind: $!");
|
||||
listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
|
||||
|
||||
my $rin = '';
|
||||
vec( $rin, fileno(SERVER), 1 ) = 1;
|
||||
my $win = $rin;
|
||||
my $ein = $win;
|
||||
my $timeout = MAX_COMMAND_WAIT;
|
||||
while( 1 ) {
|
||||
my $nfound = select(my $rout = $rin, undef, undef, $timeout);
|
||||
if ( $nfound > 0 ) {
|
||||
if ( vec( $rout, fileno(SERVER), 1 ) ) {
|
||||
my $paddr = accept(CLIENT, SERVER);
|
||||
my $message = <CLIENT>;
|
||||
|
||||
next if !$message;
|
||||
|
||||
my $params = jsonDecode($message);
|
||||
#Debug( Dumper( $params ) );
|
||||
|
||||
my $command = $params->{command};
|
||||
close( CLIENT );
|
||||
if ( $command eq 'quit' ) {
|
||||
last;
|
||||
}
|
||||
$control->$command($params);
|
||||
} else {
|
||||
Fatal('Bogus descriptor');
|
||||
}
|
||||
} elsif ( $nfound < 0 ) {
|
||||
if ( $! == EPIPE ) {
|
||||
Error("Can't select: $!");
|
||||
} else {
|
||||
Fatal("Can't select: $!");
|
||||
}
|
||||
} else {
|
||||
#print( "Select timed out\n" );
|
||||
last;
|
||||
}
|
||||
} # end while forever
|
||||
Info("Control server $id/$protocol exiting");
|
||||
unlink($sock_file);
|
||||
$control->close();
|
||||
exit(0);
|
||||
} # end if !server up
|
||||
|
||||
# The server is there, connect to it
|
||||
#print( "Writing commands\n" );
|
||||
CLIENT->autoflush();
|
||||
|
||||
if ( $options{command} ) {
|
||||
my $message = jsonEncode(\%options);
|
||||
print(CLIENT $message);
|
||||
}
|
||||
shutdown(CLIENT, 1);
|
||||
|
||||
exit(0);
|
||||
|
||||
|
|
|
@ -193,6 +193,9 @@ Event::Event(
|
|||
|
||||
video_name[0] = 0;
|
||||
|
||||
snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path);
|
||||
snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path);
|
||||
|
||||
/* Save as video */
|
||||
|
||||
if ( monitor->GetOptVideoWriter() != 0 ) {
|
||||
|
@ -251,7 +254,7 @@ Event::~Event() {
|
|||
WriteDbFrames();
|
||||
|
||||
// Should not be static because we might be multi-threaded
|
||||
char sql[ZM_SQL_MED_BUFSIZ];
|
||||
char sql[ZM_SQL_LGE_BUFSIZ];
|
||||
snprintf(sql, sizeof(sql),
|
||||
"UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64,
|
||||
monitor->EventPrefix(), id, end_time.tv_sec,
|
||||
|
@ -453,9 +456,9 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
|
|||
|
||||
frames++;
|
||||
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||
if ( monitor->GetOptSaveJPEGs() & 1 ) {
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||
Debug(1, "Writing pre-capture frame %d", frames);
|
||||
WriteFrameImage(images[i], *(timestamps[i]), event_file);
|
||||
} else {
|
||||
|
@ -464,8 +467,6 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
|
|||
// neccessarily be of the motion. But some events are less than 10 frames,
|
||||
// so I am changing this to 1, but we should overwrite it later with a better snapshot.
|
||||
if ( frames == 1 ) {
|
||||
char snapshot_file[PATH_MAX];
|
||||
snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path);
|
||||
WriteFrameImage(images[i], *(timestamps[i]), snapshot_file);
|
||||
}
|
||||
}
|
||||
|
@ -537,32 +538,29 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
|||
}
|
||||
|
||||
frames++;
|
||||
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||
bool write_to_db = false;
|
||||
|
||||
if ( monitor->GetOptSaveJPEGs() & 1 ) {
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||
Debug(1, "Writing capture frame %d to %s", frames, event_file);
|
||||
if ( ! WriteFrameImage(image, timestamp, event_file) ) {
|
||||
Error("Failed to write frame image");
|
||||
}
|
||||
} else {
|
||||
//If this is the first frame, we should add a thumbnail to the event directory
|
||||
if ( frames == 1 || score > (int)max_score ) {
|
||||
char snapshot_file[PATH_MAX];
|
||||
snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path);
|
||||
if ( (frames == 1) || (score > (int)max_score) ) {
|
||||
write_to_db = true; // web ui might show this as thumbnail, so db needs to know about it.
|
||||
WriteFrameImage(image, timestamp, snapshot_file);
|
||||
}
|
||||
// The first frame with a score will be the frame that alarmed the event
|
||||
if (!alarm_frame_written && score > 0) {
|
||||
if ( (!alarm_frame_written) && (score > 0) ) {
|
||||
write_to_db = true; // OD processing will need it, so the db needs to know about it
|
||||
alarm_frame_written = true;
|
||||
char alarm_file[PATH_MAX];
|
||||
snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path);
|
||||
WriteFrameImage(image, timestamp, alarm_file);
|
||||
}
|
||||
}
|
||||
if ( videowriter != NULL ) {
|
||||
Debug(3, "Writing video");
|
||||
WriteFrameVideo(image, timestamp, videowriter);
|
||||
}
|
||||
|
||||
|
@ -579,7 +577,7 @@ Debug(3, "Writing video");
|
|||
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||
|
||||
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
|
||||
if ( frame_data.size() > 20 ) {
|
||||
if ( write_to_db || ( frame_data.size() > 20 ) ) {
|
||||
WriteDbFrames();
|
||||
Debug(1, "Adding 20 frames to DB");
|
||||
last_db_frame = frames;
|
||||
|
@ -621,6 +619,7 @@ Debug(3, "Writing video");
|
|||
|
||||
if ( alarm_image ) {
|
||||
if ( monitor->GetOptSaveJPEGs() & 2 ) {
|
||||
static char event_file[PATH_MAX];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames);
|
||||
Debug(1, "Writing analysis frame %d", frames);
|
||||
if ( ! WriteFrameImage(alarm_image, timestamp, event_file, true) ) {
|
||||
|
@ -628,7 +627,7 @@ Debug(3, "Writing video");
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if frame_type == ALARM
|
||||
|
||||
/* This makes viewing the diagnostic images impossible because it keeps deleting them
|
||||
if ( config.record_diag_images ) {
|
||||
|
|
|
@ -90,6 +90,8 @@ class Event {
|
|||
unsigned int tot_score;
|
||||
unsigned int max_score;
|
||||
char path[PATH_MAX];
|
||||
char snapshot_file[PATH_MAX];
|
||||
char alarm_file[PATH_MAX];
|
||||
VideoWriter* videowriter;
|
||||
FILE* timecodes_fd;
|
||||
char video_name[PATH_MAX];
|
||||
|
|
|
@ -65,8 +65,9 @@ void log_libav_callback( void *ptr, int level, const char *fmt, va_list vargs )
|
|||
}
|
||||
}
|
||||
|
||||
static bool bInit = false;
|
||||
|
||||
void FFMPEGInit() {
|
||||
static bool bInit = false;
|
||||
|
||||
if ( !bInit ) {
|
||||
if ( logDebugging() )
|
||||
|
@ -77,7 +78,7 @@ void FFMPEGInit() {
|
|||
av_log_set_callback(log_libav_callback);
|
||||
else
|
||||
Info("Not enabling ffmpeg logs, as LOG_FFMPEG is disabled in options");
|
||||
#if LIBAVCODEC_VERSION_CHECK(58, 18, 0, 64, 0)
|
||||
#if LIBAVFORMAT_VERSION_CHECK(58, 9, 0, 64, 0)
|
||||
#else
|
||||
av_register_all();
|
||||
#endif
|
||||
|
@ -86,6 +87,11 @@ void FFMPEGInit() {
|
|||
}
|
||||
}
|
||||
|
||||
void FFMPEGDeInit() {
|
||||
avformat_network_deinit();
|
||||
bInit = false;
|
||||
}
|
||||
|
||||
#if HAVE_LIBAVUTIL
|
||||
enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder) {
|
||||
enum _AVPIXELFORMAT pf;
|
||||
|
@ -279,7 +285,9 @@ static void zm_log_fps(double d, const char *postfix) {
|
|||
}
|
||||
|
||||
void zm_dump_frame(const AVFrame *frame,const char *text) {
|
||||
Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d layout %d pts %" PRId64,
|
||||
Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d"
|
||||
" duration %" PRId64
|
||||
" layout %d pts %" PRId64,
|
||||
text,
|
||||
frame->format,
|
||||
av_get_sample_fmt_name((AVSampleFormat)frame->format),
|
||||
|
@ -287,8 +295,9 @@ void zm_dump_frame(const AVFrame *frame,const char *text) {
|
|||
frame->nb_samples,
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
frame->channels,
|
||||
frame->pkt_duration,
|
||||
#else
|
||||
0,
|
||||
0, 0,
|
||||
#endif
|
||||
frame->channel_layout,
|
||||
frame->pts
|
||||
|
@ -311,7 +320,8 @@ void zm_dump_codecpar ( const AVCodecParameters *par ) {
|
|||
#endif
|
||||
|
||||
void zm_dump_codec(const AVCodecContext *codec) {
|
||||
Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d) format(%s)",
|
||||
Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d) format(%s)\n"
|
||||
"gop_size %d max_b_frames %d me_cmp %d me_range %d qmin %d qmax %d",
|
||||
codec->codec_type,
|
||||
codec->codec_id,
|
||||
codec->width,
|
||||
|
@ -319,11 +329,17 @@ void zm_dump_codec(const AVCodecContext *codec) {
|
|||
codec->time_base.num,
|
||||
codec->time_base.den,
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
(codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt))
|
||||
(codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt)),
|
||||
#else
|
||||
"unsupported on avconv"
|
||||
"unsupported on avconv",
|
||||
#endif
|
||||
);
|
||||
codec->gop_size,
|
||||
codec->max_b_frames,
|
||||
codec->me_cmp,
|
||||
codec->me_range,
|
||||
codec->qmin,
|
||||
codec->qmax
|
||||
);
|
||||
}
|
||||
|
||||
/* "user interface" functions */
|
||||
|
@ -347,9 +363,9 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
|||
Debug(1, "ids [0x%x]", st->id);
|
||||
if (lang)
|
||||
Debug(1, "language (%s)", lang->value);
|
||||
Debug(1, "frames:%d, frame_size:%d stream timebase: %d/%d codec timebase: %d/%d",
|
||||
st->codec_info_nb_frames, codec->frame_size, st->time_base.num, st->time_base.den,
|
||||
st->codec->time_base.num, st->codec->time_base.den
|
||||
Debug(1, "frames:%d, frame_size:%d stream timebase: %d/%d",
|
||||
st->codec_info_nb_frames, codec->frame_size,
|
||||
st->time_base.num, st->time_base.den
|
||||
);
|
||||
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
||||
Debug(1, "codec: %s", buf);
|
||||
|
@ -368,17 +384,14 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
|||
display_aspect_ratio.num, display_aspect_ratio.den);
|
||||
}
|
||||
|
||||
if ( st->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
||||
if ( codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
||||
int fps = st->avg_frame_rate.den && st->avg_frame_rate.num;
|
||||
int tbn = st->time_base.den && st->time_base.num;
|
||||
int tbc = st->codec->time_base.den && st->codec->time_base.num;
|
||||
|
||||
if (fps)
|
||||
zm_log_fps(av_q2d(st->avg_frame_rate), "fps");
|
||||
if (tbn)
|
||||
zm_log_fps(1 / av_q2d(st->time_base), "stream tb numerator");
|
||||
if (tbc)
|
||||
zm_log_fps(1 / av_q2d(st->codec->time_base), "codec time base:");
|
||||
}
|
||||
|
||||
if (st->disposition & AV_DISPOSITION_DEFAULT)
|
||||
|
@ -425,6 +438,10 @@ unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src ) {
|
|||
av_new_packet(dst,src->size);
|
||||
memcpy(dst->data, src->data, src->size);
|
||||
dst->flags = src->flags;
|
||||
dst->pts = src->pts;
|
||||
dst->dts = src->dts;
|
||||
dst->duration = src->duration;
|
||||
dst->stream_index = src->stream_index;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -444,6 +461,14 @@ bool is_video_stream( AVStream * stream ) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool is_video_context( AVCodecContext *codec_context ) {
|
||||
return
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
( codec_context->codec_type == AVMEDIA_TYPE_VIDEO );
|
||||
#else
|
||||
( codec_context->codec_type == CODEC_TYPE_VIDEO );
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_audio_stream( AVStream * stream ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
|
@ -460,6 +485,15 @@ bool is_audio_stream( AVStream * stream ) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool is_audio_context( AVCodecContext *codec_context ) {
|
||||
return
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
( codec_context->codec_type == AVMEDIA_TYPE_AUDIO );
|
||||
#else
|
||||
( codec_context->codec_type == CODEC_TYPE_AUDIO );
|
||||
#endif
|
||||
}
|
||||
|
||||
int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) {
|
||||
int ret;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
|
@ -494,15 +528,20 @@ int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet
|
|||
# else
|
||||
int frameComplete = 0;
|
||||
while ( !frameComplete ) {
|
||||
if ( (ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet )) < 0 ) {
|
||||
Error( "Unable to decode frame at frame: %s, continuing",
|
||||
av_make_error_string(ret).c_str() );
|
||||
if ( is_video_context(context) ) {
|
||||
ret = zm_avcodec_decode_video(context, frame, &frameComplete, &packet);
|
||||
} else {
|
||||
ret = avcodec_decode_audio4(context, frame, &frameComplete, &packet);
|
||||
}
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to decode frame: %s", av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // end while !frameComplete
|
||||
#endif
|
||||
return 1;
|
||||
} // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet )
|
||||
|
||||
void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) {
|
||||
char b[10240];
|
||||
|
||||
|
|
|
@ -199,6 +199,7 @@ extern "C" {
|
|||
|
||||
/* A single function to initialize ffmpeg, to avoid multiple initializations */
|
||||
void FFMPEGInit();
|
||||
void FFMPEGDeInit();
|
||||
|
||||
#if HAVE_LIBAVUTIL
|
||||
enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder);
|
||||
|
@ -325,8 +326,11 @@ void zm_dump_frame(const AVFrame *frame, const char *text="Frame");
|
|||
|
||||
int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
|
||||
|
||||
bool is_video_stream( AVStream * stream );
|
||||
bool is_audio_stream( AVStream * stream );
|
||||
bool is_video_stream(AVStream *);
|
||||
bool is_audio_stream(AVStream *);
|
||||
bool is_video_context(AVCodec *);
|
||||
bool is_audio_context(AVCodec *);
|
||||
|
||||
int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet );
|
||||
void dumpPacket(AVStream *, AVPacket *,const char *text="");
|
||||
#endif // ZM_FFMPEG_H
|
||||
|
|
|
@ -168,7 +168,7 @@ FfmpegCamera::~FfmpegCamera() {
|
|||
if ( capture ) {
|
||||
Terminate();
|
||||
}
|
||||
avformat_network_deinit();
|
||||
FFMPEGDeInit();
|
||||
}
|
||||
|
||||
void FfmpegCamera::Initialise() {
|
||||
|
@ -535,45 +535,45 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0);
|
||||
// Open the codec
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
||||
Debug(1, "Calling avcodec_open");
|
||||
if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 )
|
||||
ret = avcodec_open(mVideoCodecContext, mVideoCodec);
|
||||
#else
|
||||
Debug(1, "Calling avcodec_open2");
|
||||
if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 )
|
||||
ret = avcodec_open2(mVideoCodecContext, mVideoCodec, &opts);
|
||||
#endif
|
||||
{
|
||||
AVDictionaryEntry *e = NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
Error( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
AVDictionaryEntry *e = NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to open codec for video stream from %s", mPath.c_str());
|
||||
av_dict_free(&opts);
|
||||
return -1;
|
||||
} else {
|
||||
|
||||
AVDictionaryEntry *e = NULL;
|
||||
if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning( "Option %s not recognized by ffmpeg", e->key);
|
||||
}
|
||||
av_dict_free(&opts);
|
||||
}
|
||||
zm_dump_codec(mVideoCodecContext);
|
||||
}
|
||||
|
||||
if (mVideoCodecContext->hwaccel != NULL) {
|
||||
if ( mVideoCodecContext->hwaccel != NULL ) {
|
||||
Debug(1, "HWACCEL in use");
|
||||
} else {
|
||||
Debug(1, "HWACCEL not in use");
|
||||
}
|
||||
if ( mAudioStreamId >= 0 ) {
|
||||
if ( (mAudioCodec = avcodec_find_decoder(
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
mAudioCodecContext = avcodec_alloc_context3( NULL );
|
||||
avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar );
|
||||
mFormatContext->streams[mAudioStreamId]->codecpar->codec_id
|
||||
#else
|
||||
mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec;
|
||||
mFormatContext->streams[mAudioStreamId]->codec->codec_id
|
||||
#endif
|
||||
if ( (mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL ) {
|
||||
)) == NULL ) {
|
||||
Debug(1, "Can't find codec for audio stream from %s", mPath.c_str());
|
||||
} else {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
mAudioCodecContext = avcodec_alloc_context3(mAudioCodec);
|
||||
avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar );
|
||||
#else
|
||||
mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec;
|
||||
// = avcodec_alloc_context3(mAudioCodec);
|
||||
#endif
|
||||
|
||||
Debug(1, "Audio Found decoder");
|
||||
zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0);
|
||||
// Open the codec
|
||||
|
@ -584,10 +584,10 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 ) {
|
||||
#endif
|
||||
Error( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
Error( "Unable to open codec for audio stream from %s", mPath.c_str() );
|
||||
return -1;
|
||||
}
|
||||
Debug(2, "Opened audio codec");
|
||||
zm_dump_codec(mAudioCodecContext);
|
||||
} // end if find decoder
|
||||
} // end if have audio_context
|
||||
|
||||
|
@ -675,6 +675,11 @@ int FfmpegCamera::Close() {
|
|||
}
|
||||
#endif
|
||||
|
||||
if ( videoStore ) {
|
||||
delete videoStore;
|
||||
videoStore = NULL;
|
||||
}
|
||||
|
||||
if ( mVideoCodecContext ) {
|
||||
avcodec_close(mVideoCodecContext);
|
||||
Debug(1,"After codec close");
|
||||
|
@ -700,10 +705,6 @@ int FfmpegCamera::Close() {
|
|||
mFormatContext = NULL;
|
||||
}
|
||||
|
||||
if ( videoStore ) {
|
||||
delete videoStore;
|
||||
videoStore = NULL;
|
||||
}
|
||||
if ( packetqueue ) {
|
||||
delete packetqueue;
|
||||
packetqueue = NULL;
|
||||
|
@ -1034,7 +1035,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
|||
|
||||
int FfmpegCamera::FfmpegInterruptCallback(void *ctx) {
|
||||
//FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx);
|
||||
Debug(4, "FfmpegInterruptCallback");
|
||||
//Debug(4, "FfmpegInterruptCallback");
|
||||
return zm_terminate;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ VideoStore::VideoStore(
|
|||
filename, format);
|
||||
return;
|
||||
} else {
|
||||
Debug(4, "Success alocateing out ctx");
|
||||
Debug(4, "Success allocating out ctx");
|
||||
}
|
||||
} // end if ! oc
|
||||
|
||||
|
@ -92,9 +92,9 @@ VideoStore::VideoStore(
|
|||
|
||||
oc->metadata = pmetadata;
|
||||
out_format = oc->oformat;
|
||||
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
|
||||
|
||||
|
||||
AVCodec *video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
|
||||
video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
|
||||
if ( !video_out_codec ) {
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
Fatal("Could not find encoder for '%s'", avcodec_get_name(video_out_ctx->codec_id));
|
||||
|
@ -103,7 +103,8 @@ VideoStore::VideoStore(
|
|||
#endif
|
||||
}
|
||||
|
||||
video_out_stream = avformat_new_stream(oc, video_out_codec);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
video_out_stream = avformat_new_stream(oc, NULL);
|
||||
if ( !video_out_stream ) {
|
||||
Error("Unable to create video out stream");
|
||||
return;
|
||||
|
@ -111,21 +112,31 @@ VideoStore::VideoStore(
|
|||
Debug(2, "Success creating video out stream");
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
//video_out_stream->codec = avcodec_alloc_context3(video_out_codec);
|
||||
// Since we are not re-encoding, all we have to do is copy the parameters
|
||||
// by allocating our own copy, we don't run into the problems when we free the streams
|
||||
video_out_ctx = avcodec_alloc_context3(video_out_codec);
|
||||
// Since we are not re-encoding, all we have to do is copy the parameters
|
||||
// Copy params from instream to ctx
|
||||
ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not initialize video_out_ctx parameters");
|
||||
return;
|
||||
} else {
|
||||
zm_dump_codec(video_out_ctx);
|
||||
}
|
||||
#else
|
||||
video_out_stream = avformat_new_stream(oc, NULL);
|
||||
if ( !video_out_stream ) {
|
||||
Error("Unable to create video out stream");
|
||||
return;
|
||||
} else {
|
||||
Debug(2, "Success creating video out stream");
|
||||
}
|
||||
video_out_ctx = video_out_stream->codec;
|
||||
// This will wipe out the codec defaults
|
||||
ret = avcodec_copy_context(video_out_ctx, video_in_ctx);
|
||||
//video_out_ctx->width = video_in_ctx->width;
|
||||
//video_out_ctx->height = video_in_ctx->height;
|
||||
//video_out_ctx->pix_fmt = video_in_ctx->pix_fmt;
|
||||
//video_out_ctx->max_b_frames = video_in_ctx->max_b_frames;
|
||||
//video_out_ctx->has_b_frames = video_in_ctx->has_b_frames;
|
||||
if ( ret < 0 ) {
|
||||
Fatal("Unable to copy in video ctx to out video ctx %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
|
@ -143,8 +154,7 @@ VideoStore::VideoStore(
|
|||
|
||||
zm_dump_codec(video_out_ctx);
|
||||
|
||||
//video_out_ctx->bit_rate = 400*1024;
|
||||
//video_out_ctx->thread_count = 0;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
//// Fix deprecated formats
|
||||
switch ( video_out_ctx->pix_fmt ) {
|
||||
case AV_PIX_FMT_YUVJ422P :
|
||||
|
@ -163,15 +173,6 @@ VideoStore::VideoStore(
|
|||
break;
|
||||
}
|
||||
|
||||
if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) {
|
||||
video_out_ctx->max_b_frames = 1;
|
||||
if ( video_out_ctx->priv_data ) {
|
||||
av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN);
|
||||
//av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0);
|
||||
} else {
|
||||
Debug(2, "Not setting priv_data");
|
||||
}
|
||||
}
|
||||
|
||||
if ( !video_out_ctx->codec_tag ) {
|
||||
Debug(2, "No codec_tag");
|
||||
|
@ -186,6 +187,7 @@ VideoStore::VideoStore(
|
|||
video_out_ctx->codec_tag = video_in_ctx->codec_tag;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
video_out_stream->time_base = video_in_stream->time_base;
|
||||
if ( video_in_stream->avg_frame_rate.num ) {
|
||||
|
@ -196,13 +198,26 @@ VideoStore::VideoStore(
|
|||
video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate;
|
||||
}
|
||||
if ( video_in_stream->r_frame_rate.num ) {
|
||||
Debug(3,"Copying r_frame_rate (%d/%d)",
|
||||
Debug(3,"Copying r_frame_rate (%d/%d) to out (%d/%d)",
|
||||
video_in_stream->r_frame_rate.num,
|
||||
video_in_stream->r_frame_rate.den
|
||||
video_in_stream->r_frame_rate.den ,
|
||||
video_out_stream->r_frame_rate.num,
|
||||
video_out_stream->r_frame_rate.den
|
||||
);
|
||||
video_out_stream->r_frame_rate = video_in_stream->r_frame_rate;
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||
if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) {
|
||||
//video_out_ctx->level = 32;I//
|
||||
video_out_ctx->bit_rate = 400*1024;
|
||||
video_out_ctx->max_b_frames = 1;
|
||||
if ( video_out_ctx->priv_data ) {
|
||||
av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN);
|
||||
av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0);
|
||||
} else {
|
||||
Debug(2, "Not setting priv_data");
|
||||
}
|
||||
}
|
||||
ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not initialize video_out_ctx parameters");
|
||||
|
@ -230,7 +245,7 @@ VideoStore::VideoStore(
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||
AVDictionary *opts = 0;
|
||||
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
|
||||
Warning("Can't open video codec (%s) %s",
|
||||
|
@ -244,6 +259,7 @@ VideoStore::VideoStore(
|
|||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Warning("Encoder Option %s not recognized by ffmpeg codec", e->key);
|
||||
}
|
||||
#endif
|
||||
|
||||
Monitor::Orientation orientation = monitor->getOrientation();
|
||||
if ( orientation ) {
|
||||
|
@ -275,92 +291,6 @@ VideoStore::VideoStore(
|
|||
fifo = NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ( audio_in_stream ) {
|
||||
Debug(3, "Have audio stream");
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
audio_in_ctx = avcodec_alloc_context3(NULL);
|
||||
ret = avcodec_parameters_to_context(audio_in_ctx,
|
||||
audio_in_stream->codecpar);
|
||||
audio_in_ctx->time_base = audio_in_stream->time_base;
|
||||
#else
|
||||
audio_in_ctx = audio_in_stream->codec;
|
||||
#endif
|
||||
|
||||
if ( audio_in_ctx->codec_id != AV_CODEC_ID_AAC ) {
|
||||
static char error_buffer[256];
|
||||
avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0);
|
||||
Debug(2, "Got something other than AAC (%s)", error_buffer);
|
||||
|
||||
if ( !setup_resampler() ) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Debug(2, "Got AAC");
|
||||
|
||||
audio_out_stream =
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec));
|
||||
#else
|
||||
avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec);
|
||||
#endif
|
||||
if ( !audio_out_stream ) {
|
||||
Error("Unable to create audio out stream");
|
||||
audio_out_stream = NULL;
|
||||
} else {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
audio_out_ctx = avcodec_alloc_context3(audio_out_codec);
|
||||
// Copy params from instream to ctx
|
||||
ret = avcodec_parameters_to_context(
|
||||
audio_out_ctx, audio_in_stream->codecpar);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to copy audio params to ctx %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
ret = avcodec_parameters_from_context(
|
||||
audio_out_stream->codecpar, audio_out_ctx);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to copy audio params to stream %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
|
||||
if ( !audio_out_ctx->codec_tag ) {
|
||||
audio_out_ctx->codec_tag = av_codec_get_tag(
|
||||
oc->oformat->codec_tag, audio_in_ctx->codec_id);
|
||||
Debug(2, "Setting audio codec tag to %d",
|
||||
audio_out_ctx->codec_tag);
|
||||
}
|
||||
#else
|
||||
audio_out_ctx = audio_out_stream->codec;
|
||||
ret = avcodec_copy_context(audio_out_ctx, audio_in_ctx);
|
||||
audio_out_ctx->codec_tag = 0;
|
||||
#endif
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to copy audio ctx %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
audio_out_stream = NULL;
|
||||
} else {
|
||||
if ( audio_out_ctx->channels > 1 ) {
|
||||
Warning("Audio isn't mono, changing it.");
|
||||
audio_out_ctx->channels = 1;
|
||||
} else {
|
||||
Debug(3, "Audio is mono");
|
||||
}
|
||||
}
|
||||
} // end if audio_out_stream
|
||||
} // end if is AAC
|
||||
|
||||
if ( audio_out_stream ) {
|
||||
if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||
audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
#else
|
||||
audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // end if audio_in_stream
|
||||
|
||||
video_first_pts = 0;
|
||||
video_first_dts = 0;
|
||||
video_last_pts = 0;
|
||||
|
@ -368,11 +298,106 @@ VideoStore::VideoStore(
|
|||
|
||||
audio_first_pts = 0;
|
||||
audio_first_dts = 0;
|
||||
audio_last_pts = 0;
|
||||
audio_last_dts = 0;
|
||||
audio_next_pts = 0;
|
||||
audio_next_dts = 0;
|
||||
|
||||
if ( audio_in_stream ) {
|
||||
Debug(3, "Have audio stream");
|
||||
|
||||
if (
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
audio_in_stream->codecpar->codec_id
|
||||
#else
|
||||
audio_in_stream->codec->codec_id
|
||||
#endif
|
||||
!= AV_CODEC_ID_AAC ) {
|
||||
|
||||
audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
|
||||
if ( !audio_out_codec ) {
|
||||
Error("Could not find codec for AAC");
|
||||
return;
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
audio_out_stream = avformat_new_stream(oc, NULL);
|
||||
audio_out_stream->time_base = audio_in_stream->time_base;
|
||||
audio_out_ctx = avcodec_alloc_context3(audio_out_codec);
|
||||
if ( !audio_out_ctx ) {
|
||||
Error("could not allocate codec ctx for AAC");
|
||||
audio_out_stream = NULL;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
audio_out_stream = avformat_new_stream(oc, audio_out_codec);
|
||||
audio_out_ctx = audio_out_stream->codec;
|
||||
#endif
|
||||
audio_out_stream->time_base = audio_in_stream->time_base;
|
||||
|
||||
if ( !setup_resampler() ) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Debug(2, "Got AAC");
|
||||
|
||||
audio_out_stream = avformat_new_stream(oc, NULL);
|
||||
if ( !audio_out_stream ) {
|
||||
Error("Could not allocate new stream");
|
||||
return;
|
||||
}
|
||||
audio_out_stream->time_base = audio_in_stream->time_base;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// Just use the ctx to copy the parameters over
|
||||
audio_out_ctx = avcodec_alloc_context3(audio_out_codec);
|
||||
if ( !audio_out_ctx ) {
|
||||
Error("Could not allocate new output_context");
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't actually care what the time_base is..
|
||||
audio_out_ctx->time_base = audio_in_stream->time_base;
|
||||
|
||||
// Copy params from instream to ctx
|
||||
ret = avcodec_parameters_to_context(
|
||||
audio_out_ctx, audio_in_stream->codecpar);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to copy audio params to ctx %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
ret = avcodec_parameters_from_context(
|
||||
audio_out_stream->codecpar, audio_out_ctx);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to copy audio params to stream %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
#else
|
||||
audio_out_ctx = audio_out_stream->codec;
|
||||
ret = avcodec_copy_context(audio_out_ctx, audio_in_stream->codec);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to copy audio ctx %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
audio_out_stream = NULL;
|
||||
return;
|
||||
} // end if
|
||||
audio_out_ctx->codec_tag = 0;
|
||||
#endif
|
||||
|
||||
if ( audio_out_ctx->channels > 1 ) {
|
||||
Warning("Audio isn't mono, changing it.");
|
||||
audio_out_ctx->channels = 1;
|
||||
} else {
|
||||
Debug(3, "Audio is mono");
|
||||
}
|
||||
} // end if is AAC
|
||||
|
||||
if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||
audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
#else
|
||||
audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
#endif
|
||||
}
|
||||
} // end if audio_in_stream
|
||||
} // VideoStore::VideoStore
|
||||
|
||||
bool VideoStore::open() {
|
||||
|
@ -507,17 +532,21 @@ VideoStore::~VideoStore() {
|
|||
#endif
|
||||
video_in_ctx = NULL;
|
||||
|
||||
avcodec_close(video_out_ctx);
|
||||
if ( video_out_codec ) {
|
||||
avcodec_close(video_out_ctx);
|
||||
Debug(4, "Success closing video_out_ctx");
|
||||
video_out_codec = NULL;
|
||||
} // end if video_out_codec
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
//avcodec_free_context(&video_out_ctx);
|
||||
avcodec_free_context(&video_out_ctx);
|
||||
#endif
|
||||
video_out_ctx = NULL;
|
||||
Debug(4, "Success freeing video_out_ctx");
|
||||
} // end if video_out_stream
|
||||
|
||||
if ( audio_out_stream ) {
|
||||
if ( audio_in_codec ) {
|
||||
avcodec_close(audio_in_ctx);
|
||||
Debug(4, "Success closing audio_in_ctx");
|
||||
audio_in_codec = NULL;
|
||||
} // end if audio_in_codec
|
||||
|
||||
|
@ -525,27 +554,32 @@ VideoStore::~VideoStore() {
|
|||
// We allocate and copy in newer ffmpeg, so need to free it
|
||||
avcodec_free_context(&audio_in_ctx);
|
||||
#endif
|
||||
Debug(4, "Success freeing audio_in_ctx");
|
||||
audio_in_ctx = NULL;
|
||||
|
||||
avcodec_close(audio_out_ctx);
|
||||
if ( audio_out_ctx ) {
|
||||
avcodec_close(audio_out_ctx);
|
||||
Debug(4, "Success closing audio_out_ctx");
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
avcodec_free_context(&audio_out_ctx);
|
||||
avcodec_free_context(&audio_out_ctx);
|
||||
#endif
|
||||
}
|
||||
audio_out_ctx = NULL;
|
||||
|
||||
#if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE)
|
||||
if ( resample_ctx ) {
|
||||
#if defined(HAVE_LIBSWRESAMPLE)
|
||||
#if defined(HAVE_LIBSWRESAMPLE)
|
||||
if ( fifo ) {
|
||||
av_audio_fifo_free(fifo);
|
||||
fifo = NULL;
|
||||
}
|
||||
swr_free(&resample_ctx);
|
||||
#else
|
||||
#if defined(HAVE_LIBAVRESAMPLE)
|
||||
#else
|
||||
#if defined(HAVE_LIBAVRESAMPLE)
|
||||
avresample_close(resample_ctx);
|
||||
avresample_free(&resample_ctx);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
if ( in_frame ) {
|
||||
av_frame_free(&in_frame);
|
||||
|
@ -562,7 +596,7 @@ VideoStore::~VideoStore() {
|
|||
#endif
|
||||
} // end if audio_out_stream
|
||||
|
||||
/* free the stream */
|
||||
/* free the streams */
|
||||
avformat_free_context(oc);
|
||||
} // VideoStore::~VideoStore()
|
||||
|
||||
|
@ -579,34 +613,43 @@ bool VideoStore::setup_resampler() {
|
|||
// decoder, can't reuse the one from the camera.
|
||||
audio_in_codec =
|
||||
avcodec_find_decoder(audio_in_stream->codecpar->codec_id);
|
||||
#else
|
||||
audio_in_codec = avcodec_find_decoder(audio_in_ctx->codec_id);
|
||||
#endif
|
||||
if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) {
|
||||
Error("Can't open in codec!");
|
||||
return false;
|
||||
audio_in_ctx = avcodec_alloc_context3(audio_in_codec);
|
||||
// Copy params from instream to ctx
|
||||
ret = avcodec_parameters_to_context(
|
||||
audio_in_ctx, audio_in_stream->codecpar);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to copy audio params to ctx %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
|
||||
audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
|
||||
if ( !audio_out_codec ) {
|
||||
Error("Could not find codec for AAC");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// codec is already open in ffmpeg_camera
|
||||
audio_in_ctx = audio_in_stream->codec;
|
||||
audio_in_codec = (AVCodec *)audio_in_ctx->codec;
|
||||
//audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id);
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// audio_out_ctx = audio_out_stream->codec;
|
||||
audio_out_ctx = avcodec_alloc_context3(audio_out_codec);
|
||||
if ( !audio_out_ctx ) {
|
||||
Error("could not allocate codec ctx for AAC");
|
||||
audio_out_stream = NULL;
|
||||
#else
|
||||
#if 0
|
||||
ret = avcodec_copy_context(audio_in_ctx, audio_in_stream->codec);
|
||||
if ( ret < 0 ) {
|
||||
Fatal("Unable to copy in video ctx to out video ctx %s",
|
||||
av_make_error_string(ret).c_str());
|
||||
} else {
|
||||
Debug(3, "Success copying ctx");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// if the codec is already open, nothing is done.
|
||||
if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) {
|
||||
Error("Can't open audio in codec!");
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_out_stream = avformat_new_stream(oc, audio_out_codec);
|
||||
#else
|
||||
audio_out_stream = avformat_new_stream(oc, NULL);
|
||||
audio_out_ctx = audio_out_stream->codec;
|
||||
#endif
|
||||
Debug(2, "Got something other than AAC (%s)", audio_in_codec->name);
|
||||
|
||||
// Some formats (i.e. WAV) do not produce the proper channel layout
|
||||
if ( audio_in_ctx->channel_layout == 0 ) {
|
||||
Debug(2, "Setting input channel layout to mono");
|
||||
|
@ -620,10 +663,7 @@ bool VideoStore::setup_resampler() {
|
|||
audio_out_ctx->channels = audio_in_ctx->channels;
|
||||
audio_out_ctx->channel_layout = audio_in_ctx->channel_layout;
|
||||
audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
#else
|
||||
audio_out_ctx->refcounted_frames = 1;
|
||||
#endif
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
if ( !audio_out_ctx->channel_layout ) {
|
||||
Debug(3, "Correcting channel layout from (%d) to (%d)",
|
||||
audio_out_ctx->channel_layout,
|
||||
|
@ -631,7 +671,7 @@ bool VideoStore::setup_resampler() {
|
|||
);
|
||||
audio_out_ctx->channel_layout = av_get_default_channel_layout(audio_out_ctx->channels);
|
||||
}
|
||||
|
||||
#endif
|
||||
if ( audio_out_codec->supported_samplerates ) {
|
||||
int found = 0;
|
||||
for ( unsigned int i = 0; audio_out_codec->supported_samplerates[i]; i++ ) {
|
||||
|
@ -787,7 +827,9 @@ bool VideoStore::setup_resampler() {
|
|||
|
||||
out_frame->nb_samples = audio_out_ctx->frame_size;
|
||||
out_frame->format = audio_out_ctx->sample_fmt;
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
out_frame->channels = audio_out_ctx->channels;
|
||||
#endif
|
||||
out_frame->channel_layout = audio_out_ctx->channel_layout;
|
||||
out_frame->sample_rate = audio_out_ctx->sample_rate;
|
||||
|
||||
|
@ -826,7 +868,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
dumpPacket(video_in_stream, ipkt, "input packet");
|
||||
|
||||
int64_t duration;
|
||||
if ( ipkt->duration ) {
|
||||
if ( ipkt->duration != AV_NOPTS_VALUE ) {
|
||||
duration = av_rescale_q(
|
||||
ipkt->duration,
|
||||
video_in_stream->time_base,
|
||||
|
@ -880,29 +922,29 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
video_last_pts = ipkt->pts;
|
||||
} else {
|
||||
Debug(3, "opkt.pts = undef");
|
||||
opkt.pts = AV_NOPTS_VALUE;
|
||||
opkt.pts = 0;
|
||||
//AV_NOPTS_VALUE;
|
||||
}
|
||||
// Just because the in stream wraps, doesn't mean the out needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out. So need to handle in wrap, without causing out wrap.
|
||||
// Just because the in stream wraps, doesn't mean the out needs to.
|
||||
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
|
||||
// So need to handle in wrap, without causing out wrap.
|
||||
|
||||
if ( ipkt->dts != AV_NOPTS_VALUE ) {
|
||||
#if 0
|
||||
if ( (!video_first_dts) && ( ipkt->dts >= 0 ) ) {
|
||||
if ( !video_first_dts ) {
|
||||
// && ( ipkt->dts >= 0 ) ) {
|
||||
// This is the first packet.
|
||||
opkt.dts = 0;
|
||||
Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
|
||||
video_first_dts = ipkt->dts;
|
||||
} else {
|
||||
#endif
|
||||
opkt.dts = av_rescale_q(
|
||||
ipkt->dts - video_first_pts,
|
||||
ipkt->dts - video_first_dts,
|
||||
video_in_stream->time_base,
|
||||
video_out_stream->time_base
|
||||
);
|
||||
Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")",
|
||||
opkt.dts, ipkt->dts, video_first_pts);
|
||||
video_last_dts = ipkt->dts;
|
||||
#if 0
|
||||
opkt.dts, ipkt->dts, video_first_dts);
|
||||
}
|
||||
#endif
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
Debug(1,
|
||||
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen "
|
||||
|
@ -915,6 +957,16 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
opkt.dts = 0;
|
||||
}
|
||||
|
||||
# if 0
|
||||
if ( opkt.dts <= video_out_stream->cur_dts ) {
|
||||
Warning("Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
||||
opkt.dts, opkt.pts, video_out_stream->cur_dts);
|
||||
opkt.dts = video_out_stream->cur_dts + 1;
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
opkt.pts = opkt.dts;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
opkt.flags = ipkt->flags;
|
||||
opkt.pos = -1;
|
||||
|
@ -954,46 +1006,21 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at
|
||||
// the moment
|
||||
}
|
||||
dumpPacket(audio_in_stream, ipkt, "input packet");
|
||||
|
||||
if ( audio_out_codec ) {
|
||||
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
if ( (ret = avcodec_send_packet(audio_in_ctx, ipkt)) < 0 ) {
|
||||
Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str());
|
||||
Debug(2, "Have output codec");
|
||||
if ( ! zm_receive_frame(audio_in_ctx, in_frame, *ipkt) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (ret = avcodec_receive_frame(audio_in_ctx, in_frame)) < 0 ) {
|
||||
Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int data_present;
|
||||
if ( (ret = avcodec_decode_audio4(
|
||||
audio_in_ctx, in_frame, &data_present, ipkt)) < 0 ) {
|
||||
Error("Could not decode frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
dumpPacket(video_in_stream, ipkt);
|
||||
// I'm not sure if we should be freeing the frame.
|
||||
av_frame_free(&in_frame);
|
||||
return 0;
|
||||
}
|
||||
if ( !data_present ) {
|
||||
Debug(2, "Not ready to transcode a frame yet.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
zm_dump_frame(in_frame, "In frame from decode");
|
||||
int frame_size = in_frame->nb_samples;
|
||||
|
||||
// Resample the in into the audioSampleBuffer until we proceed the whole
|
||||
// decoded data. Note: pts does not survive resampling or converting
|
||||
#if defined(HAVE_LIBSWRESAMPLE)
|
||||
Debug(2, "Converting %d to %d samples using swresample", in_frame->nb_samples, out_frame->nb_samples);
|
||||
ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
|
||||
zm_dump_frame(out_frame, "Out frame after convert");
|
||||
if ( ! resample_audio() ) {
|
||||
//av_frame_unref(in_frame);
|
||||
return 0;
|
||||
}
|
||||
zm_dump_frame(out_frame, "Out frame after resample");
|
||||
|
||||
out_frame->pts = in_frame->pts;
|
||||
// out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder
|
||||
|
@ -1005,64 +1032,12 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
} else {
|
||||
out_frame->pts = out_frame->pts - audio_first_pts;
|
||||
}
|
||||
//
|
||||
} else {
|
||||
// sending AV_NOPTS_VALUE doesn't really work but we seem to get it in ffmpeg 2.8
|
||||
out_frame->pts = audio_next_pts;
|
||||
}
|
||||
av_frame_unref(in_frame);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not resample frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples)) < 0) {
|
||||
Error("Could not reallocate FIFO");
|
||||
return 0;
|
||||
}
|
||||
/** Store the new samples in the FIFO buffer. */
|
||||
ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples);
|
||||
if ( ret < frame_size ) {
|
||||
Error("Could not write data to FIFO on %d written", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset frame_size to output_frame_size
|
||||
frame_size = audio_out_ctx->frame_size;
|
||||
|
||||
// AAC requires 1024 samples per encode. Our input tends to be 160, so need to buffer them.
|
||||
if ( frame_size > av_audio_fifo_size(fifo) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) < frame_size ) {
|
||||
Error("Could not read data from FIFO");
|
||||
return 0;
|
||||
}
|
||||
out_frame->nb_samples = frame_size;
|
||||
/// FIXME this is not the correct pts
|
||||
#else
|
||||
#if defined(HAVE_LIBAVRESAMPLE)
|
||||
(ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
|
||||
0, in_frame->nb_samples))
|
||||
av_frame_unref(in_frame);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not resample frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int samples_available = avresample_available(resample_ctx);
|
||||
if ( samples_available < frame_size ) {
|
||||
Debug(1, "Not enough samples yet (%d)", samples_available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read a frame audio data from the resample fifo
|
||||
if ( avresample_read(resample_ctx, out_frame->data, frame_size) !=
|
||||
frame_size) {
|
||||
Warning("Error reading resampled audio.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
zm_dump_frame(out_frame, "Out frame after resample");
|
||||
audio_next_pts = out_frame->pts + out_frame->nb_samples;
|
||||
|
||||
av_init_packet(&opkt);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
|
@ -1087,6 +1062,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
return 0;
|
||||
}
|
||||
#else
|
||||
int data_present;
|
||||
if ( (ret = avcodec_encode_audio2(
|
||||
audio_out_ctx, &opkt, out_frame, &data_present)) < 0 ) {
|
||||
Error("Could not encode frame (error '%s')",
|
||||
|
@ -1100,11 +1076,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
Error("Have audio codec but no resampler?!");
|
||||
#endif
|
||||
//if ( out_frame ) {
|
||||
//opkt.duration = out_frame->nb_samples;
|
||||
opkt.duration = av_rescale_q(opkt.duration,
|
||||
audio_in_stream->time_base,
|
||||
audio_out_stream->time_base);
|
||||
|
@ -1114,12 +1085,15 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
opkt.dts = av_rescale_q(opkt.dts,
|
||||
audio_in_stream->time_base,
|
||||
audio_out_stream->time_base);
|
||||
dumpPacket(audio_out_stream, &opkt, "raw opkt");
|
||||
|
||||
} else {
|
||||
Debug(2,"copying");
|
||||
av_init_packet(&opkt);
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
|
||||
if ( ipkt->duration != AV_NOPTS_VALUE ) {
|
||||
if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) {
|
||||
opkt.duration = av_rescale_q(
|
||||
ipkt->duration,
|
||||
audio_in_stream->time_base,
|
||||
|
@ -1139,7 +1113,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")",
|
||||
opkt.pts, ipkt->pts, audio_first_pts);
|
||||
}
|
||||
audio_last_pts = ipkt->pts;
|
||||
} else {
|
||||
Debug(2, "opkt.pts = undef");
|
||||
opkt.pts = AV_NOPTS_VALUE;
|
||||
|
@ -1171,12 +1144,11 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
} else {
|
||||
opkt.dts = AV_NOPTS_VALUE;
|
||||
}
|
||||
}
|
||||
} // end if encoding or copying
|
||||
|
||||
opkt.pos = -1;
|
||||
opkt.stream_index = audio_out_stream->index;
|
||||
|
||||
dumpPacket(audio_out_stream, &opkt, "raw opkt");
|
||||
opkt.flags = ipkt->flags;
|
||||
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
Debug(1,
|
||||
|
@ -1198,3 +1170,75 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
zm_av_packet_unref(&opkt);
|
||||
return 0;
|
||||
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
|
||||
|
||||
int VideoStore::resample_audio() {
|
||||
// Resample the in into the audioSampleBuffer until we process the whole
|
||||
// decoded data. Note: pts does not survive resampling or converting
|
||||
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
|
||||
#if defined(HAVE_LIBSWRESAMPLE)
|
||||
Debug(2, "Converting %d to %d samples using swresample",
|
||||
in_frame->nb_samples, out_frame->nb_samples);
|
||||
ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
|
||||
zm_dump_frame(out_frame, "Out frame after convert");
|
||||
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not resample frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples)) < 0) {
|
||||
Error("Could not reallocate FIFO");
|
||||
return 0;
|
||||
}
|
||||
/** Store the new samples in the FIFO buffer. */
|
||||
ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples);
|
||||
if ( ret < in_frame->nb_samples ) {
|
||||
Error("Could not write data to FIFO on %d written", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset frame_size to output_frame_size
|
||||
int frame_size = audio_out_ctx->frame_size;
|
||||
|
||||
// AAC requires 1024 samples per encode. Our input tends to be 160, so need to buffer them.
|
||||
if ( frame_size > av_audio_fifo_size(fifo) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) < frame_size ) {
|
||||
Error("Could not read data from FIFO");
|
||||
return 0;
|
||||
}
|
||||
out_frame->nb_samples = frame_size;
|
||||
#else
|
||||
#if defined(HAVE_LIBAVRESAMPLE)
|
||||
ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
|
||||
0, in_frame->nb_samples);
|
||||
if ( ret < 0 ) {
|
||||
Error("Could not resample frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int frame_size = audio_out_ctx->frame_size;
|
||||
|
||||
int samples_available = avresample_available(resample_ctx);
|
||||
if ( samples_available < frame_size ) {
|
||||
Debug(1, "Not enough samples yet (%d)", samples_available);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read a frame audio data from the resample fifo
|
||||
if ( avresample_read(resample_ctx, out_frame->data, frame_size) !=
|
||||
frame_size) {
|
||||
Warning("Error reading resampled audio.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
Error("Have audio codec but no resampler?!");
|
||||
return 0;
|
||||
#endif
|
||||
return 1;
|
||||
} // end int VideoStore::resample_audio
|
||||
|
|
|
@ -20,14 +20,16 @@ extern "C" {
|
|||
class VideoStore {
|
||||
private:
|
||||
|
||||
AVOutputFormat *out_format;
|
||||
AVFormatContext *oc;
|
||||
AVStream *video_out_stream;
|
||||
AVStream *audio_out_stream;
|
||||
AVCodecContext *video_out_ctx;
|
||||
AVOutputFormat *out_format;
|
||||
AVFormatContext *oc;
|
||||
|
||||
AVStream *video_in_stream;
|
||||
AVStream *audio_in_stream;
|
||||
AVCodec *video_out_codec;
|
||||
AVCodecContext *video_out_ctx;
|
||||
AVStream *video_out_stream;
|
||||
|
||||
AVStream *video_in_stream;
|
||||
|
||||
AVStream *audio_in_stream;
|
||||
|
||||
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
|
||||
AVPacket opkt;
|
||||
|
@ -41,6 +43,7 @@ private:
|
|||
int ret;
|
||||
|
||||
// The following are used when encoding the audio stream to AAC
|
||||
AVStream *audio_out_stream;
|
||||
AVCodec *audio_out_codec;
|
||||
AVCodecContext *audio_out_ctx;
|
||||
#ifdef HAVE_LIBSWRESAMPLE
|
||||
|
@ -74,6 +77,7 @@ private:
|
|||
int64_t audio_next_dts;
|
||||
|
||||
bool setup_resampler();
|
||||
int resample_audio();
|
||||
|
||||
public:
|
||||
VideoStore(
|
||||
|
|
184
src/zmu.cpp
184
src/zmu.cpp
|
@ -426,12 +426,12 @@ int main(int argc, char *argv[]) {
|
|||
if ( config.opt_use_auth ) {
|
||||
if ( strcmp(config.auth_relay, "none") == 0 ) {
|
||||
if ( !username ) {
|
||||
fprintf(stderr, "Error, username must be supplied\n");
|
||||
Error("Username must be supplied");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
|
||||
if ( !checkUser(username)) {
|
||||
fprintf(stderr, "Error, username greater than allowed 32 characters\n");
|
||||
Error("Username greater than allowed 32 characters");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
|
||||
|
@ -439,7 +439,7 @@ int main(int argc, char *argv[]) {
|
|||
} else {
|
||||
|
||||
if ( !(username && password) && !auth ) {
|
||||
fprintf(stderr, "Error, username and password or auth string must be supplied\n");
|
||||
Error("Username and password or auth string must be supplied");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
if ( auth ) {
|
||||
|
@ -447,22 +447,22 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
if ( username && password ) {
|
||||
if ( !checkUser(username)) {
|
||||
fprintf(stderr, "Error, username greater than allowed 32 characters\n");
|
||||
Error("username greater than allowed 32 characters");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
if ( !checkPass(password)) {
|
||||
fprintf(stderr, "Error, password greater than allowed 64 characters\n");
|
||||
Error("password greater than allowed 64 characters");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
user = zmLoadUser(username, password);
|
||||
} // end if username && password
|
||||
} // end if relay or not
|
||||
if ( !user ) {
|
||||
fprintf(stderr, "Error, unable to authenticate user\n");
|
||||
return exit_zmu(-1);
|
||||
Error("Unable to authenticate user");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
if ( !ValidateAccess(user, mon_id, function) ) {
|
||||
fprintf(stderr, "Error, insufficient privileges for requested action\n");
|
||||
Error("Insufficient privileges for requested action");
|
||||
exit_zmu(-1);
|
||||
}
|
||||
} // end if auth
|
||||
|
@ -497,201 +497,201 @@ int main(int argc, char *argv[]) {
|
|||
if ( verbose ) {
|
||||
char timestamp_str[64] = "None";
|
||||
if ( timestamp.tv_sec )
|
||||
strftime( timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime( ×tamp.tv_sec ) );
|
||||
strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime(×tamp.tv_sec));
|
||||
if ( image_idx == -1 )
|
||||
printf( "Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000 );
|
||||
printf("Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000);
|
||||
else
|
||||
printf( "Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000 );
|
||||
printf("Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000);
|
||||
} else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
printf( "%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000 );
|
||||
if ( have_output ) printf("%c", separator);
|
||||
printf("%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000);
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_READ_IDX ) {
|
||||
if ( verbose )
|
||||
printf( "Last read index: %d\n", monitor->GetLastReadIndex() );
|
||||
printf("Last read index: %d\n", monitor->GetLastReadIndex());
|
||||
else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
printf( "%d", monitor->GetLastReadIndex() );
|
||||
if ( have_output ) printf("%c", separator);
|
||||
printf("%d", monitor->GetLastReadIndex());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_WRITE_IDX ) {
|
||||
if ( verbose )
|
||||
printf( "Last write index: %d\n", monitor->GetLastWriteIndex() );
|
||||
else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
printf( "%d", monitor->GetLastWriteIndex() );
|
||||
if ( verbose ) {
|
||||
printf("Last write index: %d\n", monitor->GetLastWriteIndex());
|
||||
} else {
|
||||
if ( have_output ) printf("%c", separator);
|
||||
printf("%d", monitor->GetLastWriteIndex());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_EVENT ) {
|
||||
if ( verbose )
|
||||
printf( "Last event id: %" PRIu64 "\n", monitor->GetLastEventId() );
|
||||
else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
printf( "%" PRIu64, monitor->GetLastEventId() );
|
||||
if ( verbose ) {
|
||||
printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId());
|
||||
} else {
|
||||
if ( have_output ) printf("%c", separator);
|
||||
printf("%" PRIu64, monitor->GetLastEventId());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_FPS ) {
|
||||
if ( verbose )
|
||||
printf( "Current capture rate: %.2f frames per second\n", monitor->GetFPS() );
|
||||
printf("Current capture rate: %.2f frames per second\n", monitor->GetFPS());
|
||||
else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
printf( "%.2f", monitor->GetFPS() );
|
||||
if ( have_output ) printf("%c", separator);
|
||||
printf("%.2f", monitor->GetFPS());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_IMAGE ) {
|
||||
if ( verbose ) {
|
||||
if ( image_idx == -1 )
|
||||
printf( "Dumping last image captured to Monitor%d.jpg", monitor->Id() );
|
||||
printf("Dumping last image captured to Monitor%d.jpg", monitor->Id());
|
||||
else
|
||||
printf( "Dumping buffer image %d to Monitor%d.jpg", image_idx, monitor->Id() );
|
||||
printf("Dumping buffer image %d to Monitor%d.jpg", image_idx, monitor->Id());
|
||||
if ( scale != -1 )
|
||||
printf( ", scaling by %d%%", scale );
|
||||
printf( "\n" );
|
||||
printf(", scaling by %d%%", scale);
|
||||
printf("\n");
|
||||
}
|
||||
monitor->GetImage( image_idx, scale>0?scale:100 );
|
||||
monitor->GetImage(image_idx, scale>0?scale:100);
|
||||
}
|
||||
if ( function & ZMU_ZONES ) {
|
||||
if ( verbose )
|
||||
printf( "Dumping zone image to Zones%d.jpg\n", monitor->Id() );
|
||||
monitor->DumpZoneImage( zoneString );
|
||||
printf("Dumping zone image to Zones%d.jpg\n", monitor->Id());
|
||||
monitor->DumpZoneImage(zoneString);
|
||||
}
|
||||
if ( function & ZMU_ALARM ) {
|
||||
if ( verbose )
|
||||
printf( "Forcing alarm on\n" );
|
||||
monitor->ForceAlarmOn( config.forced_alarm_score, "Forced Web" );
|
||||
printf("Forcing alarm on\n");
|
||||
monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web");
|
||||
while ( monitor->GetState() != Monitor::ALARM ) {
|
||||
// Wait for monitor to notice.
|
||||
usleep(1000);
|
||||
}
|
||||
printf( "Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId() );
|
||||
printf("Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId());
|
||||
}
|
||||
if ( function & ZMU_NOALARM ) {
|
||||
if ( verbose )
|
||||
printf( "Forcing alarm off\n" );
|
||||
printf("Forcing alarm off\n");
|
||||
monitor->ForceAlarmOff();
|
||||
}
|
||||
if ( function & ZMU_CANCEL ) {
|
||||
if ( verbose )
|
||||
printf( "Cancelling forced alarm on/off\n" );
|
||||
printf("Cancelling forced alarm on/off\n");
|
||||
monitor->CancelForced();
|
||||
}
|
||||
if ( function & ZMU_RELOAD ) {
|
||||
if ( verbose )
|
||||
printf( "Reloading monitor settings\n" );
|
||||
printf("Reloading monitor settings\n");
|
||||
monitor->actionReload();
|
||||
}
|
||||
if ( function & ZMU_ENABLE ) {
|
||||
if ( verbose )
|
||||
printf( "Enabling event generation\n" );
|
||||
printf("Enabling event generation\n");
|
||||
monitor->actionEnable();
|
||||
}
|
||||
if ( function & ZMU_DISABLE ) {
|
||||
if ( verbose )
|
||||
printf( "Disabling event generation\n" );
|
||||
printf("Disabling event generation\n");
|
||||
monitor->actionDisable();
|
||||
}
|
||||
if ( function & ZMU_SUSPEND ) {
|
||||
if ( verbose )
|
||||
printf( "Suspending event generation\n" );
|
||||
printf("Suspending event generation\n");
|
||||
monitor->actionSuspend();
|
||||
}
|
||||
if ( function & ZMU_RESUME ) {
|
||||
if ( verbose )
|
||||
printf( "Resuming event generation\n" );
|
||||
printf("Resuming event generation\n");
|
||||
monitor->actionResume();
|
||||
}
|
||||
if ( function & ZMU_QUERY ) {
|
||||
char monString[16382] = "";
|
||||
monitor->DumpSettings( monString, verbose );
|
||||
printf( "%s\n", monString );
|
||||
monitor->DumpSettings(monString, verbose);
|
||||
printf("%s\n", monString);
|
||||
}
|
||||
if ( function & ZMU_BRIGHTNESS ) {
|
||||
if ( verbose ) {
|
||||
if ( brightness >= 0 )
|
||||
printf( "New brightness: %d\n", monitor->actionBrightness( brightness ) );
|
||||
printf("New brightness: %d\n", monitor->actionBrightness(brightness));
|
||||
else
|
||||
printf( "Current brightness: %d\n", monitor->actionBrightness() );
|
||||
printf("Current brightness: %d\n", monitor->actionBrightness());
|
||||
} else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
if ( have_output ) printf("%c", separator);
|
||||
if ( brightness >= 0 )
|
||||
printf( "%d", monitor->actionBrightness( brightness ) );
|
||||
printf("%d", monitor->actionBrightness(brightness));
|
||||
else
|
||||
printf( "%d", monitor->actionBrightness() );
|
||||
printf("%d", monitor->actionBrightness());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_CONTRAST ) {
|
||||
if ( verbose ) {
|
||||
if ( contrast >= 0 )
|
||||
printf( "New brightness: %d\n", monitor->actionContrast( contrast ) );
|
||||
printf("New brightness: %d\n", monitor->actionContrast(contrast));
|
||||
else
|
||||
printf( "Current contrast: %d\n", monitor->actionContrast() );
|
||||
printf("Current contrast: %d\n", monitor->actionContrast());
|
||||
} else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
if ( have_output ) printf("%c", separator);
|
||||
if ( contrast >= 0 )
|
||||
printf( "%d", monitor->actionContrast( contrast ) );
|
||||
printf("%d", monitor->actionContrast(contrast));
|
||||
else
|
||||
printf( "%d", monitor->actionContrast() );
|
||||
printf("%d", monitor->actionContrast());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_HUE ) {
|
||||
if ( verbose ) {
|
||||
if ( hue >= 0 )
|
||||
printf( "New hue: %d\n", monitor->actionHue( hue ) );
|
||||
printf("New hue: %d\n", monitor->actionHue(hue));
|
||||
else
|
||||
printf( "Current hue: %d\n", monitor->actionHue() );
|
||||
printf("Current hue: %d\n", monitor->actionHue());
|
||||
} else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
if ( have_output ) printf("%c", separator);
|
||||
if ( hue >= 0 )
|
||||
printf( "%d", monitor->actionHue( hue ) );
|
||||
printf("%d", monitor->actionHue(hue));
|
||||
else
|
||||
printf( "%d", monitor->actionHue() );
|
||||
printf("%d", monitor->actionHue());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( function & ZMU_COLOUR ) {
|
||||
if ( verbose ) {
|
||||
if ( colour >= 0 )
|
||||
printf( "New colour: %d\n", monitor->actionColour( colour ) );
|
||||
printf("New colour: %d\n", monitor->actionColour(colour));
|
||||
else
|
||||
printf( "Current colour: %d\n", monitor->actionColour() );
|
||||
printf("Current colour: %d\n", monitor->actionColour());
|
||||
} else {
|
||||
if ( have_output ) printf( "%c", separator );
|
||||
if ( have_output ) printf("%c", separator);
|
||||
if ( colour >= 0 )
|
||||
printf( "%d", monitor->actionColour( colour ) );
|
||||
printf("%d", monitor->actionColour(colour));
|
||||
else
|
||||
printf( "%d", monitor->actionColour() );
|
||||
printf("%d", monitor->actionColour());
|
||||
have_output = true;
|
||||
}
|
||||
}
|
||||
if ( have_output ) {
|
||||
printf( "\n" );
|
||||
printf("\n");
|
||||
}
|
||||
if ( !function ) {
|
||||
Usage();
|
||||
}
|
||||
delete monitor;
|
||||
} else {
|
||||
fprintf(stderr, "Error, invalid monitor id %d\n", mon_id);
|
||||
Error("Invalid monitor id %d", mon_id);
|
||||
exit_zmu(-1);
|
||||
}
|
||||
} else {
|
||||
if ( function & ZMU_QUERY ) {
|
||||
#if ZM_HAS_V4L
|
||||
char vidString[0x10000] = "";
|
||||
bool ok = LocalCamera::GetCurrentSettings( device, vidString, v4lVersion, verbose );
|
||||
printf( "%s", vidString );
|
||||
exit_zmu( ok?0:-1 );
|
||||
bool ok = LocalCamera::GetCurrentSettings(device, vidString, v4lVersion, verbose);
|
||||
printf("%s", vidString);
|
||||
exit_zmu(ok ? 0 : -1);
|
||||
#else // ZM_HAS_V4L
|
||||
fprintf( stderr, "Error, video4linux is required for device querying\n" );
|
||||
exit_zmu( -1 );
|
||||
Error("Video4linux is required for device querying");
|
||||
exit_zmu(-1);
|
||||
#endif // ZM_HAS_V4L
|
||||
}
|
||||
|
||||
|
@ -702,25 +702,25 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
sql += " order by Id asc";
|
||||
|
||||
if ( mysql_query( &dbconn, sql.c_str() ) ) {
|
||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||
exit_zmu( mysql_errno( &dbconn ) );
|
||||
if ( mysql_query(&dbconn, sql.c_str()) ) {
|
||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||
exit_zmu(mysql_errno(&dbconn));
|
||||
}
|
||||
|
||||
MYSQL_RES *result = mysql_store_result( &dbconn );
|
||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||
if ( !result ) {
|
||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||
exit_zmu( mysql_errno( &dbconn ) );
|
||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||
exit_zmu(mysql_errno(&dbconn));
|
||||
}
|
||||
Debug( 1, "Got %d monitors", mysql_num_rows( result ) );
|
||||
Debug(1, "Got %d monitors", mysql_num_rows(result));
|
||||
|
||||
printf( "%4s%5s%6s%9s%14s%6s%6s%8s%8s\n", "Id", "Func", "State", "TrgState", "LastImgTim", "RdIdx", "WrIdx", "LastEvt", "FrmRate" );
|
||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
|
||||
printf("%4s%5s%6s%9s%14s%6s%6s%8s%8s\n", "Id", "Func", "State", "TrgState", "LastImgTim", "RdIdx", "WrIdx", "LastEvt", "FrmRate");
|
||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
||||
int mon_id = atoi(dbrow[0]);
|
||||
int function = atoi(dbrow[1]);
|
||||
if ( !user || user->canAccess( mon_id ) ) {
|
||||
if ( !user || user->canAccess(mon_id) ) {
|
||||
if ( function > 1 ) {
|
||||
Monitor *monitor = Monitor::Load( mon_id, false, Monitor::QUERY );
|
||||
Monitor *monitor = Monitor::Load(mon_id, false, Monitor::QUERY);
|
||||
if ( monitor && monitor->connect() ) {
|
||||
struct timeval tv = monitor->GetTimestamp();
|
||||
printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8" PRIu64 "%8.2f\n",
|
||||
|
@ -738,7 +738,7 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
} else {
|
||||
struct timeval tv = { 0, 0 };
|
||||
printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8d%8.2f\n",
|
||||
printf("%4d%5d%6d%9d%11ld.%02ld%6d%6d%8d%8.2f\n",
|
||||
mon_id,
|
||||
function,
|
||||
0,
|
||||
|
@ -749,11 +749,11 @@ int main(int argc, char *argv[]) {
|
|||
0,
|
||||
0.0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
mysql_free_result( result );
|
||||
}
|
||||
} // end if function filter
|
||||
} // endif !user || canAccess(mon_id)
|
||||
} // end foreach row
|
||||
mysql_free_result(result);
|
||||
} // end if function && ZMU_LIST
|
||||
}
|
||||
delete user;
|
||||
|
||||
|
|
|
@ -735,29 +735,29 @@ function buildControlCommand( $monitor ) {
|
|||
return( $ctrlCommand );
|
||||
}
|
||||
|
||||
function sendControlCommand($mid,$command) {
|
||||
function sendControlCommand($mid, $command) {
|
||||
// Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command.
|
||||
$socket = socket_create( AF_UNIX, SOCK_STREAM, 0 );
|
||||
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
|
||||
if ( $socket < 0 ) {
|
||||
Fatal( 'socket_create() failed: '.socket_strerror($socket) );
|
||||
Fatal('socket_create() failed: '.socket_strerror($socket));
|
||||
}
|
||||
$sockFile = ZM_PATH_SOCKS.'/zmcontrol-'.$mid.'.sock';
|
||||
if ( @socket_connect( $socket, $sockFile ) ) {
|
||||
if ( @socket_connect($socket, $sockFile) ) {
|
||||
$options = array();
|
||||
foreach ( explode( ' ', $command ) as $option ) {
|
||||
if ( preg_match( '/--([^=]+)(?:=(.+))?/', $option, $matches ) ) {
|
||||
foreach ( explode(' ', $command) as $option ) {
|
||||
if ( preg_match('/--([^=]+)(?:=(.+))?/', $option, $matches) ) {
|
||||
$options[$matches[1]] = $matches[2]?$matches[2]:1;
|
||||
}
|
||||
}
|
||||
$optionString = jsonEncode( $options );
|
||||
if ( !socket_write( $socket, $optionString ) ) {
|
||||
Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) );
|
||||
$optionString = jsonEncode($options);
|
||||
if ( !socket_write($socket, $optionString) ) {
|
||||
Fatal("Can't write to control socket: ".socket_strerror(socket_last_error($socket)));
|
||||
}
|
||||
socket_close( $socket );
|
||||
socket_close($socket);
|
||||
} else if ( $command != 'quit' ) {
|
||||
$command .= ' --id='.$mid;
|
||||
|
||||
// Can't connect so use script
|
||||
$ctrlOutput = exec( escapeshellcmd( $command ) );
|
||||
$ctrlOutput = exec(escapeshellcmd($command));
|
||||
}
|
||||
} // end function sendControlCommand( $mid, $command )
|
||||
} // end function sendControlCommand($mid, $command)
|
||||
|
|
|
@ -157,7 +157,8 @@ function csrf_ob_handler($buffer, $flags) {
|
|||
$input = "<input type='hidden' name='$name' value=\"$tokens\"$endslash>";
|
||||
$buffer = preg_replace('#(<form[^>]*method\s*=\s*["\']post["\'][^>]*>)#i', '$1' . $input, $buffer);
|
||||
if ($GLOBALS['csrf']['frame-breaker']) {
|
||||
$buffer = str_ireplace('</head>', '<script nonce="'.$cspNonce.'">if (top != self) {top.location.href = self.location.href;}</script></head>', $buffer);
|
||||
$buffer = str_ireplace('</head>', '<script nonce="'.$cspNonce.'">if (top != self) {top.location.href = self.location.href;}</script>
|
||||
</head>', $buffer);
|
||||
}
|
||||
if ($js = $GLOBALS['csrf']['rewrite-js']) {
|
||||
$buffer = str_ireplace(
|
||||
|
@ -165,7 +166,8 @@ function csrf_ob_handler($buffer, $flags) {
|
|||
'<script nonce="'.$cspNonce.'">'.
|
||||
'var csrfMagicToken = "'.$tokens.'";'.
|
||||
'var csrfMagicName = "'.$name.'";</script>'.
|
||||
'<script src="'.$js.'"></script></head>',
|
||||
'<script src="'.$js.'"></script>
|
||||
</head>',
|
||||
$buffer
|
||||
);
|
||||
$script = '<script nonce="'.$cspNonce.'">CsrfMagic.end();</script>';
|
||||
|
|
|
@ -782,6 +782,7 @@ $SLANG = array(
|
|||
'VersionRemindNever' => 'Don\'t remind about new versions',
|
||||
'VersionRemindWeek' => 'Remind again in 1 week',
|
||||
'Version' => 'Version',
|
||||
'ViewMatches' => 'View Matches',
|
||||
'VideoFormat' => 'Video Format',
|
||||
'VideoGenFailed' => 'Video Generation Failed!',
|
||||
'VideoGenFiles' => 'Existing Video Files',
|
||||
|
|
|
@ -149,26 +149,18 @@ echo output_link_if_exists( array(
|
|||
if ( $skinJsPhpFile ) {
|
||||
?>
|
||||
<script nonce="<?php echo $cspNonce; ?>">
|
||||
//<![CDATA[
|
||||
<!--
|
||||
<?php
|
||||
require_once( $skinJsPhpFile );
|
||||
?>
|
||||
//-->
|
||||
//]]>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
if ( $viewJsPhpFile ) {
|
||||
?>
|
||||
<script nonce="<?php echo $cspNonce; ?>">
|
||||
//<![CDATA[
|
||||
<!--
|
||||
<?php
|
||||
require_once( $viewJsPhpFile );
|
||||
?>
|
||||
//-->
|
||||
//]]>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
@ -186,12 +178,12 @@ echo output_link_if_exists( array(
|
|||
if ($basename == 'watch' or $basename == 'log' ) {
|
||||
// This is used in the log popup for the export function. Not sure if it's used anywhere else
|
||||
?>
|
||||
<script type="text/javascript" src="js/overlay.js"></script>
|
||||
<script src="js/overlay.js"></script>
|
||||
<?php } ?>
|
||||
<?php
|
||||
if ( $viewJsFile ) {
|
||||
?>
|
||||
<script type="text/javascript" src="<?php echo cache_bust($viewJsFile) ?>"></script>
|
||||
<script src="<?php echo cache_bust($viewJsFile) ?>"></script>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -293,8 +293,8 @@ for ( $i=0; $i < count($terms); $i++ ) {
|
|||
?>
|
||||
<td><?php if ( count($terms) > 2 ) { echo htmlSelect("filter[Query][terms][$i][cbr]", $cbracketTypes, $term['cbr']); } else { ?> <?php } ?></td>
|
||||
<td>
|
||||
<input type="button" data-on-click-this="addTerm" value="+"/>
|
||||
<input type="button" data-on-click-this="delTerm" value="-" <?php echo count($terms) == 1 ? 'disabled' : '' ?>/>
|
||||
<button type="button" data-on-click-this="addTerm">+</button>
|
||||
<button type="button" data-on-click-this="delTerm" <?php echo count($terms) == 1 ? 'disabled' : '' ?>>-</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
|
@ -392,8 +392,8 @@ if ( ZM_OPT_MESSAGE ) {
|
|||
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( $filter->AutoDelete() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/>
|
||||
</p>
|
||||
<p><label><?php echo translate('FilterMoveEvents') ?></label>
|
||||
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( $filter->AutoMove() ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);if(this.checked){$j(this.form.elements['filter[AutoMoveTo]']).css('display','inline');}else{this.form.elements['filter[AutoMoveTo]'].hide();};"/>
|
||||
<?php echo htmlSelect('filter[AutoMoveTo]', $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;' )); ?>
|
||||
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( $filter->AutoMove() ) { ?> checked="checked"<?php } ?> data-on-click-this="click_automove"/>
|
||||
<?php echo htmlSelect('filter[AutoMoveTo]', $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;')); ?>
|
||||
</p>
|
||||
<p>
|
||||
<label for="background"><?php echo translate('BackgroundFilter') ?></label>
|
||||
|
@ -407,6 +407,7 @@ if ( ZM_OPT_MESSAGE ) {
|
|||
<hr/>
|
||||
<div id="contentButtons">
|
||||
<button type="submit" data-on-click-this="submitToEvents"><?php echo translate('ListMatches') ?></button>
|
||||
<!--<button type="submit" data-on-click-this="submitToMontageReview"><?php echo translate('ViewMatches') ?></button>-->
|
||||
<button type="button" data-on-click-this="submitToExport"><?php echo translate('ExportMatches') ?></button>
|
||||
<button type="button" name="executeButton" id="executeButton" data-on-click-this="executeFilter"><?php echo translate('Execute') ?></button>
|
||||
<?php
|
||||
|
|
|
@ -63,6 +63,15 @@ function updateButtons(element) {
|
|||
}
|
||||
}
|
||||
|
||||
function click_automove(element) {
|
||||
updateButtons(this);
|
||||
if ( this.checked ) {
|
||||
$j(this.form.elements['filter[AutoMoveTo]']).css('display', 'inline');
|
||||
} else {
|
||||
this.form.elements['filter[AutoMoveTo]'].hide();
|
||||
}
|
||||
}
|
||||
|
||||
function checkValue( element ) {
|
||||
var rows = $j(element).closest('tbody').children();
|
||||
parseRows(rows);
|
||||
|
@ -83,6 +92,11 @@ function submitToEvents( element ) {
|
|||
form.action = thisUrl + '?view=events';
|
||||
history.replaceState(null, null, '?view=filter&' + $j(form).serialize());
|
||||
}
|
||||
function submitToMontageReview( element ) {
|
||||
var form = element.form;
|
||||
form.action = thisUrl + '?view=montagereview';
|
||||
history.replaceState(null, null, '?view=filter&' + $j(form).serialize());
|
||||
}
|
||||
|
||||
function submitToExport(element) {
|
||||
var form = element.form;
|
||||
|
|
|
@ -59,8 +59,13 @@ include('_monitor_filters.php');
|
|||
$filter_bar = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) {
|
||||
$filter = array(
|
||||
$filter = array();
|
||||
if ( isset($_REQUEST['filter']) ) {
|
||||
$filter = $_REQUEST['filter'];
|
||||
} else {
|
||||
|
||||
if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) {
|
||||
$filter = array(
|
||||
'Query' => array(
|
||||
'terms' => array(
|
||||
array('attr' => 'StartDateTime', 'op' => '>=', 'val' => $_REQUEST['minTime'], 'obr' => '1'),
|
||||
|
@ -68,21 +73,22 @@ if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($display
|
|||
)
|
||||
),
|
||||
);
|
||||
if ( count($selected_monitor_ids) ) {
|
||||
$filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => 'IN', 'val' => implode(',',$selected_monitor_ids), 'cnj' => 'and'));
|
||||
} else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) {
|
||||
# this should be redundant
|
||||
for ($i=0; $i < count($displayMonitors); $i++) {
|
||||
if ($i == '0') {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1');
|
||||
} else if ($i == (count($displayMonitors)-1)) {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1');
|
||||
} else {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or');
|
||||
if ( count($selected_monitor_ids) ) {
|
||||
$filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => 'IN', 'val' => implode(',',$selected_monitor_ids), 'cnj' => 'and'));
|
||||
} else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) {
|
||||
# this should be redundant
|
||||
for ($i=0; $i < count($displayMonitors); $i++) {
|
||||
if ($i == '0') {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1');
|
||||
} else if ($i == (count($displayMonitors)-1)) {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1');
|
||||
} else {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parseFilter( $filter );
|
||||
} # end if REQUEST[Filter]
|
||||
parseFilter($filter);
|
||||
# This is to enable the download button
|
||||
session_start();
|
||||
$_SESSION['montageReviewFilter'] = $filter;
|
||||
|
|
|
@ -87,8 +87,9 @@ if ( empty($_REQUEST['path']) ) {
|
|||
$Frame->Id('objdetect');
|
||||
} else if ( $_REQUEST['fid'] == 'alarm' ) {
|
||||
# look for first alarmed frame
|
||||
$Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'),
|
||||
array('order'=>'FrameId ASC'));
|
||||
$Frame = ZM\Frame::find_one(
|
||||
array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'),
|
||||
array('order'=>'FrameId ASC'));
|
||||
if ( !$Frame ) { # no alarms, get first one I find
|
||||
$Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid']));
|
||||
if ( !$Frame ) {
|
||||
|
@ -101,7 +102,7 @@ if ( empty($_REQUEST['path']) ) {
|
|||
$Monitor = $Event->Monitor();
|
||||
if ( $Monitor->SaveJPEGs() & 1 ) {
|
||||
# If we store Frames as jpgs, then we don't store an alarmed snapshot
|
||||
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
|
||||
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg';
|
||||
} else {
|
||||
$path = $Event->Path().'/alarm.jpg';
|
||||
}
|
||||
|
@ -113,12 +114,16 @@ if ( empty($_REQUEST['path']) ) {
|
|||
ZM\Warning('No frame found for event ' . $_REQUEST['eid']);
|
||||
$Frame = new ZM\Frame();
|
||||
$Frame->Delta(1);
|
||||
$Frame->FrameId('snapshot');
|
||||
if ( $Monitor->SaveJPEGs() & 1 ) {
|
||||
$Frame->FrameId(0);
|
||||
} else {
|
||||
$Frame->FrameId('snapshot');
|
||||
}
|
||||
}
|
||||
$Monitor = $Event->Monitor();
|
||||
if ( $Monitor->SaveJPEGs() & 1 ) {
|
||||
# If we store Frames as jpgs, then we don't store a snapshot
|
||||
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
|
||||
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg';
|
||||
} else {
|
||||
$path = $Event->Path().'/snapshot.jpg';
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue