Merge remote-tracking branch 'upstream/master'

pull/2570/head
aktarus82 2019-04-09 16:14:34 +02:00
commit eba52023f9
25 changed files with 694 additions and 577 deletions

View File

@ -639,7 +639,7 @@ CREATE TABLE `Users` (
`Devices` enum('None','View','Edit') NOT NULL default 'None', `Devices` enum('None','View','Edit') NOT NULL default 'None',
`System` enum('None','View','Edit') NOT NULL default 'None', `System` enum('None','View','Edit') NOT NULL default 'None',
`MaxBandwidth` varchar(16), `MaxBandwidth` varchar(16),
`MonitorIds` tinytext, `MonitorIds` text,
PRIMARY KEY (`Id`), PRIMARY KEY (`Id`),
UNIQUE KEY `UC_Username` (`Username`) UNIQUE KEY `UC_Username` (`Username`)
) ENGINE=@ZM_MYSQL_ENGINE@; ) ENGINE=@ZM_MYSQL_ENGINE@;

1
db/zm_update-1.33.6.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE Users MODIFY MonitorIds text;

View File

@ -23,7 +23,7 @@
%global _hardened_build 1 %global _hardened_build 1
Name: zoneminder Name: zoneminder
Version: 1.33.4 Version: 1.33.6
Release: 1%{?dist} Release: 1%{?dist}
Summary: A camera monitoring and analysis tool Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons Group: System Environment/Daemons
@ -410,11 +410,14 @@ EOF
%dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload %dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload
%changelog %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 * 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 * 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 * Sat Dec 08 2018 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.32.3-1
- 1.32.3 Release - 1.32.3 Release

View File

@ -67,7 +67,7 @@ sub AUTOLOAD {
if ( exists($self->{$name}) ) { if ( exists($self->{$name}) ) {
return $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 { sub getKey {

View File

@ -84,7 +84,7 @@ sub open
use LWP::UserAgent; use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new(keep_alive => 1); $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'; $self->{state} = 'closed';
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string) # credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
$self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD); $self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD);

View File

@ -40,7 +40,7 @@ sub open
use LWP::UserAgent; use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new; $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'; $self->{state} = 'closed';
Debug( "sendCmd credentials control address:'".$ADDRESS Debug( "sendCmd credentials control address:'".$ADDRESS
."' realm:'" . $REALM ."' realm:'" . $REALM

View File

@ -45,7 +45,7 @@ sub open {
use LWP::UserAgent; use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new; $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'; $self->{state} = 'closed';
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string) # credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
Debug ( "sendCmd credentials control address:'".$ADDRESS Debug ( "sendCmd credentials control address:'".$ADDRESS
@ -120,6 +120,7 @@ sub sendCmd {
Debug('sendCmd command: ' . $url); Debug('sendCmd command: ' . $url);
if ( $res->is_success ) { if ( $res->is_success ) {
Debug($res->content);
return !undef; return !undef;
} }
Error("Error check failed: '".$res->status_line()."' cmd:'".$cmd."'"); 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."'"); Debug("sendCmdPost credentials control to: $PROTOCOL$ADDRESS$url realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'");
if ( $res->is_success ) { if ( $res->is_success ) {
Debug($res->content);
return !undef; return !undef;
} }
Error("sendCmdPost Error check failed: '".$res->status_line()."' cmd:"); Error("sendCmdPost Error check failed: '".$res->status_line()."' cmd:");

View File

@ -30,7 +30,7 @@ use autouse 'Pod::Usage'=>qw(pod2usage);
use POSIX qw/strftime EPIPE/; use POSIX qw/strftime EPIPE/;
use Socket; use Socket;
#use Data::Dumper; #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_CONNECT_DELAY => 15;
use constant MAX_COMMAND_WAIT => 1800; use constant MAX_COMMAND_WAIT => 1800;
@ -43,7 +43,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
logInit(); logInit();
my $arg_string = join( " ", @ARGV ); my $arg_string = join(' ', @ARGV);
my $id; my $id;
my %options; my %options;
@ -70,16 +70,40 @@ if ( !$id ) {
( $id ) = $id =~ /^(\w+)$/; ( $id ) = $id =~ /^(\w+)$/;
Debug("zmcontrol: arg string: $arg_string");
my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock'; 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) socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
or Fatal("Can't open socket: $!");
my $saddr = sockaddr_un($sock_file); 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 # The server isn't there
my $monitor = zmDbGetMonitorAndControl($id); my $monitor = zmDbGetMonitorAndControl($id);
if ( !$monitor ) { if ( !$monitor ) {
@ -113,31 +137,11 @@ if ( !$server_up ) {
Fatal("Can't load ZoneMinder::Control::$protocol\n$Module::Load::Conditional::ERROR"); Fatal("Can't load ZoneMinder::Control::$protocol\n$Module::Load::Conditional::ERROR");
} }
if ( my $cpid = fork() ) {
logReinit();
# 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);
setpgrp();
logReinit();
Info("Control server $id/$protocol starting at " Info("Control server $id/$protocol starting at "
.strftime('%y/%m/%d %H:%M:%S', localtime()) .strftime('%y/%m/%d %H:%M:%S', localtime())
); );
$0 = $0." --id $id"; $0 = $0." --id=$id";
my $control = "ZoneMinder::Control::$protocol"->new($id); my $control = "ZoneMinder::Control::$protocol"->new($id);
my $control_key = $control->getKey(); my $control_key = $control->getKey();
@ -145,8 +149,13 @@ if ( !$server_up ) {
$control->open(); $control->open();
socket(SERVER, PF_UNIX, SOCK_STREAM, 0) # If we have a command when starting up, then do it.
or Fatal("Can't open socket: $!"); 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); unlink($sock_file);
bind(SERVER, $saddr) or Fatal("Can't bind: $!"); bind(SERVER, $saddr) or Fatal("Can't bind: $!");
listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
@ -192,20 +201,8 @@ if ( !$server_up ) {
unlink($sock_file); unlink($sock_file);
$control->close(); $control->close();
exit(0); exit(0);
} else {
Fatal("Can't fork: $!");
}
} # end if !server up } # 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); exit(0);

View File

@ -193,6 +193,9 @@ Event::Event(
video_name[0] = 0; 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 */ /* Save as video */
if ( monitor->GetOptVideoWriter() != 0 ) { if ( monitor->GetOptVideoWriter() != 0 ) {
@ -251,7 +254,7 @@ Event::~Event() {
WriteDbFrames(); WriteDbFrames();
// Should not be static because we might be multi-threaded // 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), 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, "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, monitor->EventPrefix(), id, end_time.tv_sec,
@ -453,9 +456,9 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
frames++; frames++;
if ( monitor->GetOptSaveJPEGs() & 1 ) {
static char event_file[PATH_MAX]; static char event_file[PATH_MAX];
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
if ( monitor->GetOptSaveJPEGs() & 1 ) {
Debug(1, "Writing pre-capture frame %d", frames); Debug(1, "Writing pre-capture frame %d", frames);
WriteFrameImage(images[i], *(timestamps[i]), event_file); WriteFrameImage(images[i], *(timestamps[i]), event_file);
} else { } 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, // 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. // so I am changing this to 1, but we should overwrite it later with a better snapshot.
if ( frames == 1 ) { 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); WriteFrameImage(images[i], *(timestamps[i]), snapshot_file);
} }
} }
@ -537,32 +538,29 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
} }
frames++; frames++;
bool write_to_db = false;
static char event_file[PATH_MAX];
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
if ( monitor->GetOptSaveJPEGs() & 1 ) { 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); Debug(1, "Writing capture frame %d to %s", frames, event_file);
if ( ! WriteFrameImage(image, timestamp, event_file) ) { if ( ! WriteFrameImage(image, timestamp, event_file) ) {
Error("Failed to write frame image"); Error("Failed to write frame image");
} }
} else { } else {
//If this is the first frame, we should add a thumbnail to the event directory //If this is the first frame, we should add a thumbnail to the event directory
if ( frames == 1 || score > (int)max_score ) { if ( (frames == 1) || (score > (int)max_score) ) {
char snapshot_file[PATH_MAX]; write_to_db = true; // web ui might show this as thumbnail, so db needs to know about it.
snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path);
WriteFrameImage(image, timestamp, snapshot_file); WriteFrameImage(image, timestamp, snapshot_file);
} }
// The first frame with a score will be the frame that alarmed the event // 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; alarm_frame_written = true;
char alarm_file[PATH_MAX];
snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path);
WriteFrameImage(image, timestamp, alarm_file); WriteFrameImage(image, timestamp, alarm_file);
} }
} }
if ( videowriter != NULL ) { if ( videowriter != NULL ) {
Debug(3, "Writing video");
WriteFrameVideo(image, timestamp, videowriter); WriteFrameVideo(image, timestamp, videowriter);
} }
@ -579,7 +577,7 @@ Debug(3, "Writing video");
static char sql[ZM_SQL_MED_BUFSIZ]; static char sql[ZM_SQL_MED_BUFSIZ];
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); 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(); WriteDbFrames();
Debug(1, "Adding 20 frames to DB"); Debug(1, "Adding 20 frames to DB");
last_db_frame = frames; last_db_frame = frames;
@ -621,6 +619,7 @@ Debug(3, "Writing video");
if ( alarm_image ) { if ( alarm_image ) {
if ( monitor->GetOptSaveJPEGs() & 2 ) { if ( monitor->GetOptSaveJPEGs() & 2 ) {
static char event_file[PATH_MAX];
snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames); snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames);
Debug(1, "Writing analysis frame %d", frames); Debug(1, "Writing analysis frame %d", frames);
if ( ! WriteFrameImage(alarm_image, timestamp, event_file, true) ) { 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 /* This makes viewing the diagnostic images impossible because it keeps deleting them
if ( config.record_diag_images ) { if ( config.record_diag_images ) {

View File

@ -90,6 +90,8 @@ class Event {
unsigned int tot_score; unsigned int tot_score;
unsigned int max_score; unsigned int max_score;
char path[PATH_MAX]; char path[PATH_MAX];
char snapshot_file[PATH_MAX];
char alarm_file[PATH_MAX];
VideoWriter* videowriter; VideoWriter* videowriter;
FILE* timecodes_fd; FILE* timecodes_fd;
char video_name[PATH_MAX]; char video_name[PATH_MAX];

View File

@ -65,9 +65,10 @@ void log_libav_callback( void *ptr, int level, const char *fmt, va_list vargs )
} }
} }
void FFMPEGInit() {
static bool bInit = false; static bool bInit = false;
void FFMPEGInit() {
if ( !bInit ) { if ( !bInit ) {
if ( logDebugging() ) if ( logDebugging() )
av_log_set_level( AV_LOG_DEBUG ); av_log_set_level( AV_LOG_DEBUG );
@ -77,7 +78,7 @@ void FFMPEGInit() {
av_log_set_callback(log_libav_callback); av_log_set_callback(log_libav_callback);
else else
Info("Not enabling ffmpeg logs, as LOG_FFMPEG is disabled in options"); 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 #else
av_register_all(); av_register_all();
#endif #endif
@ -86,6 +87,11 @@ void FFMPEGInit() {
} }
} }
void FFMPEGDeInit() {
avformat_network_deinit();
bInit = false;
}
#if HAVE_LIBAVUTIL #if HAVE_LIBAVUTIL
enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder) { enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder) {
enum _AVPIXELFORMAT pf; 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) { 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, text,
frame->format, frame->format,
av_get_sample_fmt_name((AVSampleFormat)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, frame->nb_samples,
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) #if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
frame->channels, frame->channels,
frame->pkt_duration,
#else #else
0, 0, 0,
#endif #endif
frame->channel_layout, frame->channel_layout,
frame->pts frame->pts
@ -311,7 +320,8 @@ void zm_dump_codecpar ( const AVCodecParameters *par ) {
#endif #endif
void zm_dump_codec(const AVCodecContext *codec) { 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_type,
codec->codec_id, codec->codec_id,
codec->width, codec->width,
@ -319,10 +329,16 @@ void zm_dump_codec(const AVCodecContext *codec) {
codec->time_base.num, codec->time_base.num,
codec->time_base.den, codec->time_base.den,
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #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 #else
"unsupported on avconv" "unsupported on avconv",
#endif #endif
codec->gop_size,
codec->max_b_frames,
codec->me_cmp,
codec->me_range,
codec->qmin,
codec->qmax
); );
} }
@ -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); Debug(1, "ids [0x%x]", st->id);
if (lang) if (lang)
Debug(1, "language (%s)", lang->value); Debug(1, "language (%s)", lang->value);
Debug(1, "frames:%d, frame_size:%d stream timebase: %d/%d codec timebase: %d/%d", 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, st->codec_info_nb_frames, codec->frame_size,
st->codec->time_base.num, st->codec->time_base.den st->time_base.num, st->time_base.den
); );
avcodec_string(buf, sizeof(buf), st->codec, is_output); avcodec_string(buf, sizeof(buf), st->codec, is_output);
Debug(1, "codec: %s", buf); 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); 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 fps = st->avg_frame_rate.den && st->avg_frame_rate.num;
int tbn = st->time_base.den && st->time_base.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) if (fps)
zm_log_fps(av_q2d(st->avg_frame_rate), "fps"); zm_log_fps(av_q2d(st->avg_frame_rate), "fps");
if (tbn) if (tbn)
zm_log_fps(1 / av_q2d(st->time_base), "stream tb numerator"); 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) 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); av_new_packet(dst,src->size);
memcpy(dst->data, src->data, src->size); memcpy(dst->data, src->data, src->size);
dst->flags = src->flags; dst->flags = src->flags;
dst->pts = src->pts;
dst->dts = src->dts;
dst->duration = src->duration;
dst->stream_index = src->stream_index;
return 0; return 0;
} }
#endif #endif
@ -444,6 +461,14 @@ bool is_video_stream( AVStream * stream ) {
return false; 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 ) { bool is_audio_stream( AVStream * stream ) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
@ -460,6 +485,15 @@ bool is_audio_stream( AVStream * stream ) {
return false; 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 zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) {
int ret; int ret;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
@ -494,15 +528,20 @@ int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet
# else # else
int frameComplete = 0; int frameComplete = 0;
while ( !frameComplete ) { while ( !frameComplete ) {
if ( (ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet )) < 0 ) { if ( is_video_context(context) ) {
Error( "Unable to decode frame at frame: %s, continuing", ret = zm_avcodec_decode_video(context, frame, &frameComplete, &packet);
av_make_error_string(ret).c_str() ); } 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; return 0;
} }
} } // end while !frameComplete
#endif #endif
return 1; return 1;
} // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) } // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet )
void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) { void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) {
char b[10240]; char b[10240];

View File

@ -199,6 +199,7 @@ extern "C" {
/* A single function to initialize ffmpeg, to avoid multiple initializations */ /* A single function to initialize ffmpeg, to avoid multiple initializations */
void FFMPEGInit(); void FFMPEGInit();
void FFMPEGDeInit();
#if HAVE_LIBAVUTIL #if HAVE_LIBAVUTIL
enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder); 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); int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
bool is_video_stream( AVStream * stream ); bool is_video_stream(AVStream *);
bool is_audio_stream( AVStream * stream ); 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 ); int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet );
void dumpPacket(AVStream *, AVPacket *,const char *text=""); void dumpPacket(AVStream *, AVPacket *,const char *text="");
#endif // ZM_FFMPEG_H #endif // ZM_FFMPEG_H

View File

@ -168,7 +168,7 @@ FfmpegCamera::~FfmpegCamera() {
if ( capture ) { if ( capture ) {
Terminate(); Terminate();
} }
avformat_network_deinit(); FFMPEGDeInit();
} }
void FfmpegCamera::Initialise() { void FfmpegCamera::Initialise() {
@ -535,28 +535,20 @@ int FfmpegCamera::OpenFfmpeg() {
zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0); zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0);
// Open the codec // Open the codec
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
Debug(1, "Calling avcodec_open"); ret = avcodec_open(mVideoCodecContext, mVideoCodec);
if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 )
#else #else
Debug(1, "Calling avcodec_open2"); ret = avcodec_open2(mVideoCodecContext, mVideoCodec, &opts);
if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 )
#endif #endif
{
AVDictionaryEntry *e = NULL; AVDictionaryEntry *e = NULL;
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Warning( "Option %s not recognized by ffmpeg", e->key); 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()); Error("Unable to open codec for video stream from %s", mPath.c_str());
av_dict_free(&opts); av_dict_free(&opts);
return -1; 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 ) {
@ -565,15 +557,23 @@ int FfmpegCamera::OpenFfmpeg() {
Debug(1, "HWACCEL not in use"); Debug(1, "HWACCEL not in use");
} }
if ( mAudioStreamId >= 0 ) { if ( mAudioStreamId >= 0 ) {
if ( (mAudioCodec = avcodec_find_decoder(
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
mAudioCodecContext = avcodec_alloc_context3( NULL ); mFormatContext->streams[mAudioStreamId]->codecpar->codec_id
#else
mFormatContext->streams[mAudioStreamId]->codec->codec_id
#endif
)) == 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 ); avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar );
#else #else
mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec; mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec;
// = avcodec_alloc_context3(mAudioCodec);
#endif #endif
if ( (mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL ) {
Debug(1, "Can't find codec for audio stream from %s", mPath.c_str());
} else {
Debug(1, "Audio Found decoder"); Debug(1, "Audio Found decoder");
zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0); zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0);
// Open the codec // Open the codec
@ -584,10 +584,10 @@ int FfmpegCamera::OpenFfmpeg() {
Debug ( 1, "Calling avcodec_open2" ); Debug ( 1, "Calling avcodec_open2" );
if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 ) { if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 ) {
#endif #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; return -1;
} }
Debug(2, "Opened audio codec"); zm_dump_codec(mAudioCodecContext);
} // end if find decoder } // end if find decoder
} // end if have audio_context } // end if have audio_context
@ -675,6 +675,11 @@ int FfmpegCamera::Close() {
} }
#endif #endif
if ( videoStore ) {
delete videoStore;
videoStore = NULL;
}
if ( mVideoCodecContext ) { if ( mVideoCodecContext ) {
avcodec_close(mVideoCodecContext); avcodec_close(mVideoCodecContext);
Debug(1,"After codec close"); Debug(1,"After codec close");
@ -700,10 +705,6 @@ int FfmpegCamera::Close() {
mFormatContext = NULL; mFormatContext = NULL;
} }
if ( videoStore ) {
delete videoStore;
videoStore = NULL;
}
if ( packetqueue ) { if ( packetqueue ) {
delete packetqueue; delete packetqueue;
packetqueue = NULL; packetqueue = NULL;
@ -1034,7 +1035,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
int FfmpegCamera::FfmpegInterruptCallback(void *ctx) { int FfmpegCamera::FfmpegInterruptCallback(void *ctx) {
//FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx); //FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx);
Debug(4, "FfmpegInterruptCallback"); //Debug(4, "FfmpegInterruptCallback");
return zm_terminate; return zm_terminate;
} }

View File

@ -81,7 +81,7 @@ VideoStore::VideoStore(
filename, format); filename, format);
return; return;
} else { } else {
Debug(4, "Success alocateing out ctx"); Debug(4, "Success allocating out ctx");
} }
} // end if ! oc } // end if ! oc
@ -92,9 +92,9 @@ VideoStore::VideoStore(
oc->metadata = pmetadata; oc->metadata = pmetadata;
out_format = oc->oformat; out_format = oc->oformat;
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
AVCodec *video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
if ( !video_out_codec ) { if ( !video_out_codec ) {
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) #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)); Fatal("Could not find encoder for '%s'", avcodec_get_name(video_out_ctx->codec_id));
@ -103,7 +103,8 @@ VideoStore::VideoStore(
#endif #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 ) { if ( !video_out_stream ) {
Error("Unable to create video out stream"); Error("Unable to create video out stream");
return; return;
@ -111,21 +112,31 @@ VideoStore::VideoStore(
Debug(2, "Success creating video out stream"); Debug(2, "Success creating video out stream");
} }
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // by allocating our own copy, we don't run into the problems when we free the streams
//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
video_out_ctx = avcodec_alloc_context3(video_out_codec); 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 // Copy params from instream to ctx
ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar);
if ( ret < 0 ) { if ( ret < 0 ) {
Error("Could not initialize video_out_ctx parameters"); Error("Could not initialize video_out_ctx parameters");
return; return;
} else {
zm_dump_codec(video_out_ctx);
} }
#else #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; video_out_ctx = video_out_stream->codec;
// This will wipe out the codec defaults
ret = avcodec_copy_context(video_out_ctx, video_in_ctx); 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 ) { if ( ret < 0 ) {
Fatal("Unable to copy in video ctx to out video ctx %s", Fatal("Unable to copy in video ctx to out video ctx %s",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
@ -143,8 +154,7 @@ VideoStore::VideoStore(
zm_dump_codec(video_out_ctx); zm_dump_codec(video_out_ctx);
//video_out_ctx->bit_rate = 400*1024; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
//video_out_ctx->thread_count = 0;
//// Fix deprecated formats //// Fix deprecated formats
switch ( video_out_ctx->pix_fmt ) { switch ( video_out_ctx->pix_fmt ) {
case AV_PIX_FMT_YUVJ422P : case AV_PIX_FMT_YUVJ422P :
@ -163,15 +173,6 @@ VideoStore::VideoStore(
break; 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 ) { if ( !video_out_ctx->codec_tag ) {
Debug(2, "No codec_tag"); Debug(2, "No codec_tag");
@ -186,6 +187,7 @@ VideoStore::VideoStore(
video_out_ctx->codec_tag = video_in_ctx->codec_tag; video_out_ctx->codec_tag = video_in_ctx->codec_tag;
} }
} }
#endif
video_out_stream->time_base = video_in_stream->time_base; video_out_stream->time_base = video_in_stream->time_base;
if ( video_in_stream->avg_frame_rate.num ) { 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; video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate;
} }
if ( video_in_stream->r_frame_rate.num ) { 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.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; video_out_stream->r_frame_rate = video_in_stream->r_frame_rate;
} }
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) #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); ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx);
if ( ret < 0 ) { if ( ret < 0 ) {
Error("Could not initialize video_out_ctx parameters"); Error("Could not initialize video_out_ctx parameters");
@ -230,7 +245,7 @@ VideoStore::VideoStore(
#endif #endif
} }
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
AVDictionary *opts = 0; AVDictionary *opts = 0;
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
Warning("Can't open video codec (%s) %s", 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 ) { while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Warning("Encoder Option %s not recognized by ffmpeg codec", e->key); Warning("Encoder Option %s not recognized by ffmpeg codec", e->key);
} }
#endif
Monitor::Orientation orientation = monitor->getOrientation(); Monitor::Orientation orientation = monitor->getOrientation();
if ( orientation ) { if ( orientation ) {
@ -275,22 +291,47 @@ VideoStore::VideoStore(
fifo = NULL; fifo = NULL;
#endif #endif
#endif #endif
video_first_pts = 0;
video_first_dts = 0;
video_last_pts = 0;
video_last_dts = 0;
audio_first_pts = 0;
audio_first_dts = 0;
audio_next_pts = 0;
audio_next_dts = 0;
if ( audio_in_stream ) { if ( audio_in_stream ) {
Debug(3, "Have audio 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 ) { if (
static char error_buffer[256]; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); audio_in_stream->codecpar->codec_id
Debug(2, "Got something other than AAC (%s)", error_buffer); #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() ) { if ( !setup_resampler() ) {
return; return;
@ -298,18 +339,24 @@ VideoStore::VideoStore(
} else { } else {
Debug(2, "Got AAC"); Debug(2, "Got AAC");
audio_out_stream = audio_out_stream = avformat_new_stream(oc, NULL);
#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 ) { if ( !audio_out_stream ) {
Error("Unable to create audio out stream"); Error("Could not allocate new stream");
audio_out_stream = NULL; return;
} else { }
audio_out_stream->time_base = audio_in_stream->time_base;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #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); 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 // Copy params from instream to ctx
ret = avcodec_parameters_to_context( ret = avcodec_parameters_to_context(
audio_out_ctx, audio_in_stream->codecpar); audio_out_ctx, audio_in_stream->codecpar);
@ -323,34 +370,26 @@ VideoStore::VideoStore(
Error("Unable to copy audio params to stream %s", Error("Unable to copy audio params to stream %s",
av_make_error_string(ret).c_str()); 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 #else
audio_out_ctx = audio_out_stream->codec; audio_out_ctx = audio_out_stream->codec;
ret = avcodec_copy_context(audio_out_ctx, audio_in_ctx); ret = avcodec_copy_context(audio_out_ctx, audio_in_stream->codec);
audio_out_ctx->codec_tag = 0;
#endif
if ( ret < 0 ) { if ( ret < 0 ) {
Error("Unable to copy audio ctx %s", Error("Unable to copy audio ctx %s",
av_make_error_string(ret).c_str()); av_make_error_string(ret).c_str());
audio_out_stream = NULL; audio_out_stream = NULL;
} else { return;
} // end if
audio_out_ctx->codec_tag = 0;
#endif
if ( audio_out_ctx->channels > 1 ) { if ( audio_out_ctx->channels > 1 ) {
Warning("Audio isn't mono, changing it."); Warning("Audio isn't mono, changing it.");
audio_out_ctx->channels = 1; audio_out_ctx->channels = 1;
} else { } else {
Debug(3, "Audio is mono"); Debug(3, "Audio is mono");
} }
}
} // end if audio_out_stream
} // end if is AAC } // end if is AAC
if ( audio_out_stream ) {
if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) {
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
@ -358,21 +397,7 @@ VideoStore::VideoStore(
audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
#endif #endif
} }
}
} // end if audio_in_stream } // end if audio_in_stream
video_first_pts = 0;
video_first_dts = 0;
video_last_pts = 0;
video_last_dts = 0;
audio_first_pts = 0;
audio_first_dts = 0;
audio_last_pts = 0;
audio_last_dts = 0;
audio_next_pts = 0;
audio_next_dts = 0;
} // VideoStore::VideoStore } // VideoStore::VideoStore
bool VideoStore::open() { bool VideoStore::open() {
@ -507,17 +532,21 @@ VideoStore::~VideoStore() {
#endif #endif
video_in_ctx = NULL; video_in_ctx = NULL;
if ( video_out_codec ) {
avcodec_close(video_out_ctx); 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) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
//avcodec_free_context(&video_out_ctx); avcodec_free_context(&video_out_ctx);
#endif #endif
video_out_ctx = NULL; video_out_ctx = NULL;
Debug(4, "Success freeing video_out_ctx");
} // end if video_out_stream } // end if video_out_stream
if ( audio_out_stream ) { if ( audio_out_stream ) {
if ( audio_in_codec ) { if ( audio_in_codec ) {
avcodec_close(audio_in_ctx); avcodec_close(audio_in_ctx);
Debug(4, "Success closing audio_in_ctx");
audio_in_codec = NULL; audio_in_codec = NULL;
} // end if audio_in_codec } // end if audio_in_codec
@ -525,13 +554,18 @@ VideoStore::~VideoStore() {
// We allocate and copy in newer ffmpeg, so need to free it // We allocate and copy in newer ffmpeg, so need to free it
avcodec_free_context(&audio_in_ctx); avcodec_free_context(&audio_in_ctx);
#endif #endif
Debug(4, "Success freeing audio_in_ctx");
audio_in_ctx = NULL; audio_in_ctx = NULL;
if ( audio_out_ctx ) {
avcodec_close(audio_out_ctx); avcodec_close(audio_out_ctx);
Debug(4, "Success closing audio_out_ctx");
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_free_context(&audio_out_ctx); avcodec_free_context(&audio_out_ctx);
#endif #endif
}
audio_out_ctx = NULL; audio_out_ctx = NULL;
#if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE) #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE)
if ( resample_ctx ) { if ( resample_ctx ) {
#if defined(HAVE_LIBSWRESAMPLE) #if defined(HAVE_LIBSWRESAMPLE)
@ -562,7 +596,7 @@ VideoStore::~VideoStore() {
#endif #endif
} // end if audio_out_stream } // end if audio_out_stream
/* free the stream */ /* free the streams */
avformat_free_context(oc); avformat_free_context(oc);
} // VideoStore::~VideoStore() } // VideoStore::~VideoStore()
@ -579,34 +613,43 @@ bool VideoStore::setup_resampler() {
// decoder, can't reuse the one from the camera. // decoder, can't reuse the one from the camera.
audio_in_codec = audio_in_codec =
avcodec_find_decoder(audio_in_stream->codecpar->codec_id); avcodec_find_decoder(audio_in_stream->codecpar->codec_id);
#else audio_in_ctx = avcodec_alloc_context3(audio_in_codec);
audio_in_codec = avcodec_find_decoder(audio_in_ctx->codec_id); // Copy params from instream to ctx
#endif ret = avcodec_parameters_to_context(
if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { audio_in_ctx, audio_in_stream->codecpar);
Error("Can't open in codec!"); if ( ret < 0 ) {
return false; 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); #else
if ( !audio_out_codec ) { // codec is already open in ffmpeg_camera
Error("Could not find codec for AAC"); audio_in_ctx = audio_in_stream->codec;
return false; 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) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// audio_out_ctx = audio_out_stream->codec; #else
audio_out_ctx = avcodec_alloc_context3(audio_out_codec); #if 0
if ( !audio_out_ctx ) { ret = avcodec_copy_context(audio_in_ctx, audio_in_stream->codec);
Error("could not allocate codec ctx for AAC"); if ( ret < 0 ) {
audio_out_stream = NULL; 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; return false;
} }
audio_out_stream = avformat_new_stream(oc, audio_out_codec); Debug(2, "Got something other than AAC (%s)", audio_in_codec->name);
#else
audio_out_stream = avformat_new_stream(oc, NULL);
audio_out_ctx = audio_out_stream->codec;
#endif
// Some formats (i.e. WAV) do not produce the proper channel layout // Some formats (i.e. WAV) do not produce the proper channel layout
if ( audio_in_ctx->channel_layout == 0 ) { if ( audio_in_ctx->channel_layout == 0 ) {
Debug(2, "Setting input channel layout to mono"); 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->channels = audio_in_ctx->channels;
audio_out_ctx->channel_layout = audio_in_ctx->channel_layout; audio_out_ctx->channel_layout = audio_in_ctx->channel_layout;
audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
#else
audio_out_ctx->refcounted_frames = 1;
#endif
if ( !audio_out_ctx->channel_layout ) { if ( !audio_out_ctx->channel_layout ) {
Debug(3, "Correcting channel layout from (%d) to (%d)", Debug(3, "Correcting channel layout from (%d) to (%d)",
audio_out_ctx->channel_layout, 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); audio_out_ctx->channel_layout = av_get_default_channel_layout(audio_out_ctx->channels);
} }
#endif
if ( audio_out_codec->supported_samplerates ) { if ( audio_out_codec->supported_samplerates ) {
int found = 0; int found = 0;
for ( unsigned int i = 0; audio_out_codec->supported_samplerates[i]; i++ ) { 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->nb_samples = audio_out_ctx->frame_size;
out_frame->format = audio_out_ctx->sample_fmt; out_frame->format = audio_out_ctx->sample_fmt;
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
out_frame->channels = audio_out_ctx->channels; out_frame->channels = audio_out_ctx->channels;
#endif
out_frame->channel_layout = audio_out_ctx->channel_layout; out_frame->channel_layout = audio_out_ctx->channel_layout;
out_frame->sample_rate = audio_out_ctx->sample_rate; 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"); dumpPacket(video_in_stream, ipkt, "input packet");
int64_t duration; int64_t duration;
if ( ipkt->duration ) { if ( ipkt->duration != AV_NOPTS_VALUE ) {
duration = av_rescale_q( duration = av_rescale_q(
ipkt->duration, ipkt->duration,
video_in_stream->time_base, video_in_stream->time_base,
@ -880,29 +922,29 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
video_last_pts = ipkt->pts; video_last_pts = ipkt->pts;
} else { } else {
Debug(3, "opkt.pts = undef"); 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 ( ipkt->dts != AV_NOPTS_VALUE ) {
#if 0 if ( !video_first_dts ) {
if ( (!video_first_dts) && ( ipkt->dts >= 0 ) ) { // && ( ipkt->dts >= 0 ) ) {
// This is the first packet. // This is the first packet.
opkt.dts = 0; opkt.dts = 0;
Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts); Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
video_first_dts = ipkt->dts; video_first_dts = ipkt->dts;
} else { } else {
#endif
opkt.dts = av_rescale_q( opkt.dts = av_rescale_q(
ipkt->dts - video_first_pts, ipkt->dts - video_first_dts,
video_in_stream->time_base, video_in_stream->time_base,
video_out_stream->time_base video_out_stream->time_base
); );
Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")", Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")",
opkt.dts, ipkt->dts, video_first_pts); opkt.dts, ipkt->dts, video_first_dts);
video_last_dts = ipkt->dts;
#if 0
} }
#endif
if ( opkt.dts > opkt.pts ) { if ( opkt.dts > opkt.pts ) {
Debug(1, Debug(1,
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen "
@ -915,6 +957,16 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
opkt.dts = 0; 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.flags = ipkt->flags;
opkt.pos = -1; 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 return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at
// the moment // the moment
} }
dumpPacket(audio_in_stream, ipkt, "input packet");
if ( audio_out_codec ) { if ( audio_out_codec ) {
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE) Debug(2, "Have output codec");
if ( ! zm_receive_frame(audio_in_ctx, in_frame, *ipkt) ) {
#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());
return 0; 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"); 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 if ( ! resample_audio() ) {
// decoded data. Note: pts does not survive resampling or converting //av_frame_unref(in_frame);
#if defined(HAVE_LIBSWRESAMPLE) return 0;
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 resample");
zm_dump_frame(out_frame, "Out frame after convert");
out_frame->pts = in_frame->pts; out_frame->pts = in_frame->pts;
// out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder // 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 { } else {
out_frame->pts = out_frame->pts - audio_first_pts; 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); audio_next_pts = out_frame->pts + out_frame->nb_samples;
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");
av_init_packet(&opkt); av_init_packet(&opkt);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
@ -1087,6 +1062,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
return 0; return 0;
} }
#else #else
int data_present;
if ( (ret = avcodec_encode_audio2( if ( (ret = avcodec_encode_audio2(
audio_out_ctx, &opkt, out_frame, &data_present)) < 0 ) { audio_out_ctx, &opkt, out_frame, &data_present)) < 0 ) {
Error("Could not encode frame (error '%s')", Error("Could not encode frame (error '%s')",
@ -1100,11 +1076,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
return 0; return 0;
} }
#endif #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, opkt.duration = av_rescale_q(opkt.duration,
audio_in_stream->time_base, audio_in_stream->time_base,
audio_out_stream->time_base); audio_out_stream->time_base);
@ -1114,12 +1085,15 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
opkt.dts = av_rescale_q(opkt.dts, opkt.dts = av_rescale_q(opkt.dts,
audio_in_stream->time_base, audio_in_stream->time_base,
audio_out_stream->time_base); audio_out_stream->time_base);
dumpPacket(audio_out_stream, &opkt, "raw opkt");
} else { } else {
Debug(2,"copying");
av_init_packet(&opkt); av_init_packet(&opkt);
opkt.data = ipkt->data; opkt.data = ipkt->data;
opkt.size = ipkt->size; opkt.size = ipkt->size;
if ( ipkt->duration != AV_NOPTS_VALUE ) { if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) {
opkt.duration = av_rescale_q( opkt.duration = av_rescale_q(
ipkt->duration, ipkt->duration,
audio_in_stream->time_base, 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 ")", Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")",
opkt.pts, ipkt->pts, audio_first_pts); opkt.pts, ipkt->pts, audio_first_pts);
} }
audio_last_pts = ipkt->pts;
} else { } else {
Debug(2, "opkt.pts = undef"); Debug(2, "opkt.pts = undef");
opkt.pts = AV_NOPTS_VALUE; opkt.pts = AV_NOPTS_VALUE;
@ -1171,12 +1144,11 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
} else { } else {
opkt.dts = AV_NOPTS_VALUE; opkt.dts = AV_NOPTS_VALUE;
} }
} } // end if encoding or copying
opkt.pos = -1; opkt.pos = -1;
opkt.stream_index = audio_out_stream->index; opkt.stream_index = audio_out_stream->index;
opkt.flags = ipkt->flags;
dumpPacket(audio_out_stream, &opkt, "raw opkt");
if ( opkt.dts > opkt.pts ) { if ( opkt.dts > opkt.pts ) {
Debug(1, Debug(1,
@ -1198,3 +1170,75 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
zm_av_packet_unref(&opkt); zm_av_packet_unref(&opkt);
return 0; return 0;
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt) } // 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

View File

@ -22,11 +22,13 @@ private:
AVOutputFormat *out_format; AVOutputFormat *out_format;
AVFormatContext *oc; AVFormatContext *oc;
AVStream *video_out_stream;
AVStream *audio_out_stream; AVCodec *video_out_codec;
AVCodecContext *video_out_ctx; AVCodecContext *video_out_ctx;
AVStream *video_out_stream;
AVStream *video_in_stream; AVStream *video_in_stream;
AVStream *audio_in_stream; AVStream *audio_in_stream;
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack // Move this into the object so that we aren't constantly allocating/deallocating it on the stack
@ -41,6 +43,7 @@ private:
int ret; int ret;
// The following are used when encoding the audio stream to AAC // The following are used when encoding the audio stream to AAC
AVStream *audio_out_stream;
AVCodec *audio_out_codec; AVCodec *audio_out_codec;
AVCodecContext *audio_out_ctx; AVCodecContext *audio_out_ctx;
#ifdef HAVE_LIBSWRESAMPLE #ifdef HAVE_LIBSWRESAMPLE
@ -74,6 +77,7 @@ private:
int64_t audio_next_dts; int64_t audio_next_dts;
bool setup_resampler(); bool setup_resampler();
int resample_audio();
public: public:
VideoStore( VideoStore(

View File

@ -426,12 +426,12 @@ int main(int argc, char *argv[]) {
if ( config.opt_use_auth ) { if ( config.opt_use_auth ) {
if ( strcmp(config.auth_relay, "none") == 0 ) { if ( strcmp(config.auth_relay, "none") == 0 ) {
if ( !username ) { if ( !username ) {
fprintf(stderr, "Error, username must be supplied\n"); Error("Username must be supplied");
exit_zmu(-1); exit_zmu(-1);
} }
if ( !checkUser(username)) { if ( !checkUser(username)) {
fprintf(stderr, "Error, username greater than allowed 32 characters\n"); Error("Username greater than allowed 32 characters");
exit_zmu(-1); exit_zmu(-1);
} }
@ -439,7 +439,7 @@ int main(int argc, char *argv[]) {
} else { } else {
if ( !(username && password) && !auth ) { 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); exit_zmu(-1);
} }
if ( auth ) { if ( auth ) {
@ -447,22 +447,22 @@ int main(int argc, char *argv[]) {
} }
if ( username && password ) { if ( username && password ) {
if ( !checkUser(username)) { if ( !checkUser(username)) {
fprintf(stderr, "Error, username greater than allowed 32 characters\n"); Error("username greater than allowed 32 characters");
exit_zmu(-1); exit_zmu(-1);
} }
if ( !checkPass(password)) { if ( !checkPass(password)) {
fprintf(stderr, "Error, password greater than allowed 64 characters\n"); Error("password greater than allowed 64 characters");
exit_zmu(-1); exit_zmu(-1);
} }
user = zmLoadUser(username, password); user = zmLoadUser(username, password);
} // end if username && password } // end if username && password
} // end if relay or not } // end if relay or not
if ( !user ) { if ( !user ) {
fprintf(stderr, "Error, unable to authenticate user\n"); Error("Unable to authenticate user");
return exit_zmu(-1); exit_zmu(-1);
} }
if ( !ValidateAccess(user, mon_id, function) ) { if ( !ValidateAccess(user, mon_id, function) ) {
fprintf(stderr, "Error, insufficient privileges for requested action\n"); Error("Insufficient privileges for requested action");
exit_zmu(-1); exit_zmu(-1);
} }
} // end if auth } // end if auth
@ -518,18 +518,18 @@ int main(int argc, char *argv[]) {
} }
} }
if ( function & ZMU_WRITE_IDX ) { if ( function & ZMU_WRITE_IDX ) {
if ( verbose ) if ( verbose ) {
printf("Last write index: %d\n", monitor->GetLastWriteIndex()); printf("Last write index: %d\n", monitor->GetLastWriteIndex());
else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) printf("%c", separator);
printf("%d", monitor->GetLastWriteIndex()); printf("%d", monitor->GetLastWriteIndex());
have_output = true; have_output = true;
} }
} }
if ( function & ZMU_EVENT ) { if ( function & ZMU_EVENT ) {
if ( verbose ) if ( verbose ) {
printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId()); printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId());
else { } else {
if ( have_output ) printf("%c", separator); if ( have_output ) printf("%c", separator);
printf("%" PRIu64, monitor->GetLastEventId()); printf("%" PRIu64, monitor->GetLastEventId());
have_output = true; have_output = true;
@ -679,7 +679,7 @@ int main(int argc, char *argv[]) {
} }
delete monitor; delete monitor;
} else { } else {
fprintf(stderr, "Error, invalid monitor id %d\n", mon_id); Error("Invalid monitor id %d", mon_id);
exit_zmu(-1); exit_zmu(-1);
} }
} else { } else {
@ -690,7 +690,7 @@ int main(int argc, char *argv[]) {
printf("%s", vidString); printf("%s", vidString);
exit_zmu(ok ? 0 : -1); exit_zmu(ok ? 0 : -1);
#else // ZM_HAS_V4L #else // ZM_HAS_V4L
fprintf( stderr, "Error, video4linux is required for device querying\n" ); Error("Video4linux is required for device querying");
exit_zmu(-1); exit_zmu(-1);
#endif // ZM_HAS_V4L #endif // ZM_HAS_V4L
} }
@ -749,11 +749,11 @@ int main(int argc, char *argv[]) {
0, 0,
0.0 0.0
); );
} } // end if function filter
} } // endif !user || canAccess(mon_id)
} } // end foreach row
mysql_free_result(result); mysql_free_result(result);
} } // end if function && ZMU_LIST
} }
delete user; delete user;

View File

@ -1 +1 @@
1.33.5 1.33.6

View File

@ -157,7 +157,8 @@ function csrf_ob_handler($buffer, $flags) {
$input = "<input type='hidden' name='$name' value=\"$tokens\"$endslash>"; $input = "<input type='hidden' name='$name' value=\"$tokens\"$endslash>";
$buffer = preg_replace('#(<form[^>]*method\s*=\s*["\']post["\'][^>]*>)#i', '$1' . $input, $buffer); $buffer = preg_replace('#(<form[^>]*method\s*=\s*["\']post["\'][^>]*>)#i', '$1' . $input, $buffer);
if ($GLOBALS['csrf']['frame-breaker']) { 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']) { if ($js = $GLOBALS['csrf']['rewrite-js']) {
$buffer = str_ireplace( $buffer = str_ireplace(
@ -165,7 +166,8 @@ function csrf_ob_handler($buffer, $flags) {
'<script nonce="'.$cspNonce.'">'. '<script nonce="'.$cspNonce.'">'.
'var csrfMagicToken = "'.$tokens.'";'. 'var csrfMagicToken = "'.$tokens.'";'.
'var csrfMagicName = "'.$name.'";</script>'. 'var csrfMagicName = "'.$name.'";</script>'.
'<script src="'.$js.'"></script></head>', '<script src="'.$js.'"></script>
</head>',
$buffer $buffer
); );
$script = '<script nonce="'.$cspNonce.'">CsrfMagic.end();</script>'; $script = '<script nonce="'.$cspNonce.'">CsrfMagic.end();</script>';

View File

@ -782,6 +782,7 @@ $SLANG = array(
'VersionRemindNever' => 'Don\'t remind about new versions', 'VersionRemindNever' => 'Don\'t remind about new versions',
'VersionRemindWeek' => 'Remind again in 1 week', 'VersionRemindWeek' => 'Remind again in 1 week',
'Version' => 'Version', 'Version' => 'Version',
'ViewMatches' => 'View Matches',
'VideoFormat' => 'Video Format', 'VideoFormat' => 'Video Format',
'VideoGenFailed' => 'Video Generation Failed!', 'VideoGenFailed' => 'Video Generation Failed!',
'VideoGenFiles' => 'Existing Video Files', 'VideoGenFiles' => 'Existing Video Files',

View File

@ -149,26 +149,18 @@ echo output_link_if_exists( array(
if ( $skinJsPhpFile ) { if ( $skinJsPhpFile ) {
?> ?>
<script nonce="<?php echo $cspNonce; ?>"> <script nonce="<?php echo $cspNonce; ?>">
//<![CDATA[
<!--
<?php <?php
require_once( $skinJsPhpFile ); require_once( $skinJsPhpFile );
?> ?>
//-->
//]]>
</script> </script>
<?php <?php
} }
if ( $viewJsPhpFile ) { if ( $viewJsPhpFile ) {
?> ?>
<script nonce="<?php echo $cspNonce; ?>"> <script nonce="<?php echo $cspNonce; ?>">
//<![CDATA[
<!--
<?php <?php
require_once( $viewJsPhpFile ); require_once( $viewJsPhpFile );
?> ?>
//-->
//]]>
</script> </script>
<?php <?php
} }
@ -186,12 +178,12 @@ echo output_link_if_exists( array(
if ($basename == 'watch' or $basename == 'log' ) { 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 // 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 } ?>
<?php <?php
if ( $viewJsFile ) { if ( $viewJsFile ) {
?> ?>
<script type="text/javascript" src="<?php echo cache_bust($viewJsFile) ?>"></script> <script src="<?php echo cache_bust($viewJsFile) ?>"></script>
<?php <?php
} }
?> ?>

View File

@ -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 { ?>&nbsp;<?php } ?></td> <td><?php if ( count($terms) > 2 ) { echo htmlSelect("filter[Query][terms][$i][cbr]", $cbracketTypes, $term['cbr']); } else { ?>&nbsp;<?php } ?></td>
<td> <td>
<input type="button" data-on-click-this="addTerm" value="+"/> <button type="button" data-on-click-this="addTerm">+</button>
<input type="button" data-on-click-this="delTerm" value="-" <?php echo count($terms) == 1 ? 'disabled' : '' ?>/> <button type="button" data-on-click-this="delTerm" <?php echo count($terms) == 1 ? 'disabled' : '' ?>>-</button>
</td> </td>
</tr> </tr>
<?php <?php
@ -392,7 +392,7 @@ if ( ZM_OPT_MESSAGE ) {
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( $filter->AutoDelete() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/> <input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( $filter->AutoDelete() ) { ?> checked="checked"<?php } ?> data-on-click-this="updateButtons"/>
</p> </p>
<p><label><?php echo translate('FilterMoveEvents') ?></label> <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();};"/> <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;')); ?> <?php echo htmlSelect('filter[AutoMoveTo]', $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;')); ?>
</p> </p>
<p> <p>
@ -407,6 +407,7 @@ if ( ZM_OPT_MESSAGE ) {
<hr/> <hr/>
<div id="contentButtons"> <div id="contentButtons">
<button type="submit" data-on-click-this="submitToEvents"><?php echo translate('ListMatches') ?></button> <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" 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> <button type="button" name="executeButton" id="executeButton" data-on-click-this="executeFilter"><?php echo translate('Execute') ?></button>
<?php <?php

View File

@ -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 ) { function checkValue( element ) {
var rows = $j(element).closest('tbody').children(); var rows = $j(element).closest('tbody').children();
parseRows(rows); parseRows(rows);
@ -83,6 +92,11 @@ function submitToEvents( element ) {
form.action = thisUrl + '?view=events'; form.action = thisUrl + '?view=events';
history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); 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) { function submitToExport(element) {
var form = element.form; var form = element.form;

View File

@ -59,6 +59,11 @@ include('_monitor_filters.php');
$filter_bar = ob_get_contents(); $filter_bar = ob_get_contents();
ob_end_clean(); ob_end_clean();
$filter = array();
if ( isset($_REQUEST['filter']) ) {
$filter = $_REQUEST['filter'];
} else {
if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) { if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) {
$filter = array( $filter = array(
'Query' => array( 'Query' => array(
@ -82,6 +87,7 @@ if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($display
} }
} }
} }
} # end if REQUEST[Filter]
parseFilter($filter); parseFilter($filter);
# This is to enable the download button # This is to enable the download button
session_start(); session_start();

View File

@ -87,7 +87,8 @@ if ( empty($_REQUEST['path']) ) {
$Frame->Id('objdetect'); $Frame->Id('objdetect');
} else if ( $_REQUEST['fid'] == 'alarm' ) { } else if ( $_REQUEST['fid'] == 'alarm' ) {
# look for first alarmed frame # look for first alarmed frame
$Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), $Frame = ZM\Frame::find_one(
array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'),
array('order'=>'FrameId ASC')); array('order'=>'FrameId ASC'));
if ( !$Frame ) { # no alarms, get first one I find if ( !$Frame ) { # no alarms, get first one I find
$Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'])); $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid']));
@ -113,8 +114,12 @@ if ( empty($_REQUEST['path']) ) {
ZM\Warning('No frame found for event ' . $_REQUEST['eid']); ZM\Warning('No frame found for event ' . $_REQUEST['eid']);
$Frame = new ZM\Frame(); $Frame = new ZM\Frame();
$Frame->Delta(1); $Frame->Delta(1);
if ( $Monitor->SaveJPEGs() & 1 ) {
$Frame->FrameId(0);
} else {
$Frame->FrameId('snapshot'); $Frame->FrameId('snapshot');
} }
}
$Monitor = $Event->Monitor(); $Monitor = $Event->Monitor();
if ( $Monitor->SaveJPEGs() & 1 ) { if ( $Monitor->SaveJPEGs() & 1 ) {
# If we store Frames as jpgs, then we don't store a snapshot # If we store Frames as jpgs, then we don't store a snapshot