Merge branch 'storageareas' into record_audio
This commit is contained in:
commit
b8c7b6ae77
|
@ -328,22 +328,22 @@ CREATE TABLE `Monitors` (
|
|||
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL') NOT NULL default 'Local',
|
||||
`Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor',
|
||||
`Enabled` tinyint(3) unsigned NOT NULL default '1',
|
||||
`LinkedMonitors` varchar(255) NOT NULL default '',
|
||||
`LinkedMonitors` varchar(255),
|
||||
`Triggers` set('X10') NOT NULL default '',
|
||||
`Device` tinytext NOT NULL default '',
|
||||
`Channel` tinyint(3) unsigned NOT NULL default '0',
|
||||
`Format` int(10) unsigned NOT NULL default '0',
|
||||
`V4LMultiBuffer` tinyint(1) unsigned,
|
||||
`V4LCapturesPerFrame` tinyint(3) unsigned,
|
||||
`Protocol` varchar(16) NOT NULL default '',
|
||||
`Protocol` varchar(16),
|
||||
`Method` varchar(16) NOT NULL default '',
|
||||
`Host` varchar(64) NOT NULL default '',
|
||||
`Host` varchar(64),
|
||||
`Port` varchar(8) NOT NULL default '',
|
||||
`SubPath` varchar(64) NOT NULL default '',
|
||||
`Path` varchar(255) NOT NULL default '',
|
||||
`Options` varchar(255) not null default '',
|
||||
`User` varchar(64) NOT NULL default '',
|
||||
`Pass` varchar(64) NOT NULL default '',
|
||||
`Options` varchar(255),
|
||||
`User` varchar(64),
|
||||
`Pass` varchar(64),
|
||||
`Width` smallint(5) unsigned NOT NULL default '0',
|
||||
`Height` smallint(5) unsigned NOT NULL default '0',
|
||||
`Colours` tinyint(3) unsigned NOT NULL default '1',
|
||||
|
@ -354,13 +354,13 @@ CREATE TABLE `Monitors` (
|
|||
`VideoWriter` TINYINT NOT NULL DEFAULT '0',
|
||||
`EncoderParameters` TEXT NOT NULL,
|
||||
`RecordAudio` TINYINT NOT NULL DEFAULT '0',
|
||||
`RTSPDescribe` tinyint(1) unsigned NOT NULL default '0',
|
||||
`RTSPDescribe` tinyint(1) unsigned,
|
||||
`Brightness` mediumint(7) NOT NULL default '-1',
|
||||
`Contrast` mediumint(7) NOT NULL default '-1',
|
||||
`Hue` mediumint(7) NOT NULL default '-1',
|
||||
`Colour` mediumint(7) NOT NULL default '-1',
|
||||
`EventPrefix` varchar(32) NOT NULL default 'Event-',
|
||||
`LabelFormat` varchar(64) NOT NULL default '%N - %y/%m/%d %H:%M:%S',
|
||||
`LabelFormat` varchar(64) default '%N - %y/%m/%d %H:%M:%S',
|
||||
`LabelX` smallint(5) unsigned NOT NULL default '0',
|
||||
`LabelY` smallint(5) unsigned NOT NULL default '0',
|
||||
`LabelSize` smallint(5) unsigned NOT NULL DEFAULT '1',
|
||||
|
@ -381,14 +381,14 @@ CREATE TABLE `Monitors` (
|
|||
`RefBlendPerc` tinyint(3) unsigned NOT NULL default '6',
|
||||
`AlarmRefBlendPerc` tinyint(3) unsigned NOT NULL default '6',
|
||||
`Controllable` tinyint(3) unsigned NOT NULL default '0',
|
||||
`ControlId` int(10) unsigned NOT NULL default '0',
|
||||
`ControlId` int(10) unsigned,
|
||||
`ControlDevice` varchar(255) default NULL,
|
||||
`ControlAddress` varchar(255) default NULL,
|
||||
`AutoStopTimeout` decimal(5,2) default NULL,
|
||||
`TrackMotion` tinyint(3) unsigned NOT NULL default '0',
|
||||
`TrackDelay` smallint(5) unsigned NOT NULL default '0',
|
||||
`TrackDelay` smallint(5) unsigned,
|
||||
`ReturnLocation` tinyint(3) NOT NULL default '-1',
|
||||
`ReturnDelay` smallint(5) unsigned NOT NULL default '0',
|
||||
`ReturnDelay` smallint(5) unsigned,
|
||||
`DefaultView` enum('Events','Control') NOT NULL default 'Events',
|
||||
`DefaultRate` smallint(5) unsigned NOT NULL default '100',
|
||||
`DefaultScale` smallint(5) unsigned NOT NULL default '100',
|
||||
|
@ -477,7 +477,7 @@ CREATE TABLE `Users` (
|
|||
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||
`Username` varchar(32) character set latin1 collate latin1_bin NOT NULL default '',
|
||||
`Password` varchar(64) NOT NULL default '',
|
||||
`Language` varchar(8) NOT NULL default '',
|
||||
`Language` varchar(8),
|
||||
`Enabled` tinyint(3) unsigned NOT NULL default '1',
|
||||
`Stream` enum('None','View') NOT NULL default 'None',
|
||||
`Events` enum('None','View','Edit') NOT NULL default 'None',
|
||||
|
@ -486,8 +486,8 @@ CREATE TABLE `Users` (
|
|||
`Groups` 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',
|
||||
`MaxBandwidth` varchar(16) NOT NULL default '',
|
||||
`MonitorIds` tinytext NOT NULL,
|
||||
`MaxBandwidth` varchar(16),
|
||||
`MonitorIds` tinytext,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `UC_Username` (`Username`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
|
|
@ -4,5 +4,7 @@
|
|||
-- Changing StorageId to be NOT NULL and default 0
|
||||
--
|
||||
|
||||
UPDATE Monitors SET StorageId = 0 WHERE StorageId IS NULL;
|
||||
ALTER TABLE Monitors MODIFY `StorageId` smallint(5) unsigned NOT NULL default 0;
|
||||
UPDATE Events SET StorageId = 0 WHERE StorageId IS NULL;
|
||||
ALTER TABLE Events MODIFY `StorageId` smallint(5) unsigned NOT NULL default 0;
|
||||
|
|
|
@ -37,7 +37,7 @@ Package: zoneminder
|
|||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||
,javascript-common
|
||||
,libav-tools
|
||||
,libav-tools | ffmpeg
|
||||
,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
|
||||
,libdbd-mysql-perl
|
||||
,libphp-serialization-perl
|
||||
|
|
|
@ -206,11 +206,11 @@ MAIN: while( $loop ) {
|
|||
Debug( "Checking day dir $day_dir" );
|
||||
( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint
|
||||
if ( ! chdir( $day_dir ) ) {
|
||||
Error( "Can't chdir to '$$Storage{Path}/$monitor_dir/$day_dir': $!" );
|
||||
Error( "Can't chdir to '$$Storage{Path}/$day_dir': $!" );
|
||||
next;
|
||||
}
|
||||
if ( ! opendir( DIR, '.' ) ) {
|
||||
Error( "Can't open directory $$Storage{Path}/$monitor_dir/'$day_dir': $!" );
|
||||
Error( "Can't open directory '$$Storage{Path}/$day_dir': $!" );
|
||||
next;
|
||||
}
|
||||
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR );
|
||||
|
@ -237,7 +237,7 @@ MAIN: while( $loop ) {
|
|||
Debug( "Checking link $event_link points to $event_path " );
|
||||
my $Event = $fs_events->{$event} = new ZoneMinder::Event();
|
||||
$$Event{Id} = $event;
|
||||
$$Event{Path} = join('/', $Storage->Path(), $monitor_dir,$day_dir,$event_path);
|
||||
$$Event{Path} = join('/', $Storage->Path(), $day_dir,$event_path);
|
||||
$Event->MonitorId( $monitor_dir );
|
||||
$Event->StorageId( $Storage->Id() );
|
||||
} # event path exists
|
||||
|
|
|
@ -424,6 +424,7 @@ static void zm_log_fps(double d, const char *postfix) {
|
|||
/* "user interface" functions */
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
|
||||
char buf[256];
|
||||
Debug(1, "Dumping stream index i(%d) index(%d)", i, index );
|
||||
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
||||
AVStream *st = ic->streams[i];
|
||||
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
||||
|
@ -437,8 +438,7 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
|||
Debug(1, "[0x%x]", st->id);
|
||||
if (lang)
|
||||
Debug(1, "(%s)", lang->value);
|
||||
av_log(NULL, AV_LOG_DEBUG, ", %d, %d/%d", st->codec_info_nb_frames,
|
||||
st->time_base.num, st->time_base.den);
|
||||
Debug(1, ", %d, %d/%d", st->codec_info_nb_frames, st->time_base.num, st->time_base.den);
|
||||
Debug(1, ": %s", buf);
|
||||
|
||||
if (st->sample_aspect_ratio.num && // default
|
||||
|
@ -464,9 +464,9 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
|||
if (fps)
|
||||
zm_log_fps(av_q2d(st->avg_frame_rate), tbn || tbc ? "fps, " : "fps");
|
||||
if (tbn)
|
||||
zm_log_fps(1 / av_q2d(st->time_base), tbc ? "tbn, " : "tbn");
|
||||
zm_log_fps(1 / av_q2d(st->time_base), tbc ? "stream tb numerator , " : "stream tb numerator");
|
||||
if (tbc)
|
||||
zm_log_fps(1 / av_q2d(st->codec->time_base), "tbc");
|
||||
zm_log_fps(1 / av_q2d(st->codec->time_base), "codec time base:");
|
||||
}
|
||||
|
||||
if (st->disposition & AV_DISPOSITION_DEFAULT)
|
||||
|
|
|
@ -323,8 +323,8 @@ static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, in
|
|||
#endif
|
||||
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100)
|
||||
#define zm_av_unref_packet( packet ) av_unref_packet( packet )
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
#define zm_av_unref_packet( packet ) av_packet_unref( packet )
|
||||
#else
|
||||
#define zm_av_unref_packet( packet ) av_free_packet( packet )
|
||||
#endif
|
||||
|
|
|
@ -146,8 +146,6 @@ int FfmpegCamera::Capture( Image &image )
|
|||
mReopenThread = 0;
|
||||
}
|
||||
|
||||
AVPacket packet;
|
||||
|
||||
int frameComplete = false;
|
||||
while ( !frameComplete ) {
|
||||
int avResult = av_read_frame( mFormatContext, &packet );
|
||||
|
@ -167,7 +165,7 @@ int FfmpegCamera::Capture( Image &image )
|
|||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf );
|
||||
return( -1 );
|
||||
}
|
||||
Debug( 5, "Got packet from stream %d", packet.stream_index );
|
||||
Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts );
|
||||
// What about audio stream? Maybe someday we could do sound detection...
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
|
@ -290,7 +288,6 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Debug ( 1, "Opened input" );
|
||||
|
||||
Info( "Stream open %s", mPath.c_str() );
|
||||
startTime=av_gettime();//FIXME here or after find_Stream_info
|
||||
|
||||
//FIXME can speed up initial analysis but need sensible parameters...
|
||||
//mFormatContext->probesize = 32;
|
||||
|
@ -305,6 +302,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
#endif
|
||||
Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) );
|
||||
|
||||
startTime=av_gettime();//FIXME here or after find_Stream_info
|
||||
Debug ( 1, "Got stream info" );
|
||||
|
||||
// Find first video stream present
|
||||
|
@ -386,9 +384,6 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
||||
Debug ( 1, "Opened codec" );
|
||||
|
||||
// Allocate space for the native video frame
|
||||
|
@ -555,11 +550,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
|||
|
||||
int frameComplete = false;
|
||||
while ( !frameComplete ) {
|
||||
// We are now allocating dynamically because we need to queue these and may go out of scope.
|
||||
AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
|
||||
av_init_packet( packet );
|
||||
Debug(5, "Before av_init_packe");
|
||||
av_init_packet( &packet );
|
||||
|
||||
Debug(5, "Before av_read_frame");
|
||||
ret = av_read_frame( mFormatContext, packet );
|
||||
ret = av_read_frame( mFormatContext, &packet );
|
||||
Debug(5, "After av_read_frame (%d)", ret );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
|
@ -573,21 +568,32 @@ Debug(5, "After av_read_frame (%d)", ret );
|
|||
ReopenFfmpeg();
|
||||
}
|
||||
|
||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet->stream_index, ret, errbuf );
|
||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf );
|
||||
return( -1 );
|
||||
}
|
||||
Debug( 5, "Got packet from stream %d", packet->stream_index );
|
||||
Debug( 3, "Got packet from stream %d dts (%d) pts(%d) key?(%d)", packet.stream_index, packet.dts, packet.pts, packet.flags & AV_PKT_FLAG_KEY );
|
||||
//av_packet_ref( &packet, &packet );
|
||||
|
||||
//Video recording
|
||||
if ( recording ) {
|
||||
|
||||
// The directory we are recording to is no longer tied to the current event.
|
||||
// Need to re-init the videostore with the correct directory and start recording again
|
||||
// for efficiency's sake, we should test for keyframe before we test for directory change...
|
||||
if ( videoStore && (packet->flags & AV_PKT_FLAG_KEY) && (strcmp(oldDirectory, event_file) != 0 ) ) {
|
||||
if ( videoStore && (packet.flags & AV_PKT_FLAG_KEY) && (strcmp(oldDirectory, event_file) != 0 ) ) {
|
||||
// don't open new videostore until we're on a key frame..would this require an offset adjustment for the event as a result?...
|
||||
// if we store our key frame location with the event will that be enough?
|
||||
Info("Re-starting video storage module");
|
||||
|
||||
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
|
||||
// Also don't know how much it matters for audio.
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
//Write the packet to our video store
|
||||
int ret = videoStore->writeVideoFramePacket( &packet );
|
||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
||||
Warning("Error writing last packet to videostore.");
|
||||
}
|
||||
} // end if video
|
||||
|
||||
delete videoStore;
|
||||
videoStore = NULL;
|
||||
}
|
||||
|
@ -628,11 +634,11 @@ Debug(5, "After av_read_frame (%d)", ret );
|
|||
while ( ( queued_packet = packetqueue.popPacket() ) ) {
|
||||
packet_count += 1;
|
||||
//Write the packet to our video store
|
||||
Debug(2, "Writing queued packet stream: %d KEY %d", queued_packet->stream_index, packet->flags & AV_PKT_FLAG_KEY );
|
||||
Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", queued_packet->stream_index, queued_packet->flags & AV_PKT_FLAG_KEY, packetqueue.size() );
|
||||
if ( queued_packet->stream_index == mVideoStreamId ) {
|
||||
ret = videoStore->writeVideoFramePacket( queued_packet, mFormatContext->streams[mVideoStreamId]);
|
||||
ret = videoStore->writeVideoFramePacket( queued_packet );
|
||||
} else if ( queued_packet->stream_index == mAudioStreamId ) {
|
||||
ret = videoStore->writeAudioFramePacket( queued_packet, mFormatContext->streams[mAudioStreamId]);
|
||||
ret = videoStore->writeAudioFramePacket( queued_packet );
|
||||
} else {
|
||||
Warning("Unknown stream id in queued packet (%d)", queued_packet->stream_index );
|
||||
ret = -1;
|
||||
|
@ -641,6 +647,7 @@ Debug(5, "After av_read_frame (%d)", ret );
|
|||
//Less than zero and we skipped a frame
|
||||
}
|
||||
zm_av_unref_packet( queued_packet );
|
||||
av_free( queued_packet );
|
||||
} // end while packets in the packetqueue
|
||||
Debug(2, "Wrote %d queued packets", packet_count );
|
||||
} // end if ! wasRecording
|
||||
|
@ -653,27 +660,32 @@ Debug(5, "After av_read_frame (%d)", ret );
|
|||
videoStore = NULL;
|
||||
}
|
||||
|
||||
//Buffer video packets, since we are not recording
|
||||
if ( (packet->stream_index == mVideoStreamId) && ( packet->flags & AV_PKT_FLAG_KEY ) ) {
|
||||
//Buffer video packets, since we are not recording. All audio packets are keyframes, so only if it's a video keyframe
|
||||
if ( (packet.stream_index == mVideoStreamId) && ( packet.flags & AV_PKT_FLAG_KEY ) ) {
|
||||
Debug(3, "Clearing queue");
|
||||
packetqueue.clearQueue();
|
||||
}
|
||||
packetqueue.queuePacket(packet);
|
||||
} // end if
|
||||
if ( packet.stream_index != mAudioStreamId || record_audio ) {
|
||||
Debug(3, "Queuing");
|
||||
packetqueue.queuePacket( &packet );
|
||||
}
|
||||
} // end if recording or not
|
||||
|
||||
if ( packet->stream_index == mVideoStreamId ) {
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
if ( videoStore ) {
|
||||
//Write the packet to our video store
|
||||
int ret = videoStore->writeVideoFramePacket( packet, mFormatContext->streams[mVideoStreamId] );
|
||||
int ret = videoStore->writeVideoFramePacket( &packet );
|
||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
||||
zm_av_unref_packet( packet );
|
||||
zm_av_unref_packet( &packet );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, packet );
|
||||
Debug(3, "about to decode video" );
|
||||
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_unref_packet( packet );
|
||||
zm_av_unref_packet( &packet );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -688,7 +700,7 @@ Debug(5, "After av_read_frame (%d)", ret );
|
|||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if ( directbuffer == NULL ) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
zm_av_unref_packet( packet );
|
||||
zm_av_unref_packet( &packet );
|
||||
return (-1);
|
||||
}
|
||||
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
|
||||
|
@ -717,16 +729,16 @@ Debug(5, "After av_read_frame (%d)", ret );
|
|||
} else {
|
||||
Debug( 3, "Not framecomplete after av_read_frame" );
|
||||
} // end if frameComplete
|
||||
} else if ( packet->stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams
|
||||
Debug( 4, "Audio stream index %d", packet->stream_index );
|
||||
} else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams
|
||||
if ( videoStore ) {
|
||||
if ( record_audio ) {
|
||||
Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet->stream_index );
|
||||
Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet.stream_index );
|
||||
//Write the packet to our video store
|
||||
//FIXME no relevance of last key frame
|
||||
int ret = videoStore->writeAudioFramePacket( packet, mFormatContext->streams[packet->stream_index] );
|
||||
int ret = videoStore->writeAudioFramePacket( &packet );
|
||||
if ( ret < 0 ) {//Less than zero and we skipped a frame
|
||||
zm_av_unref_packet( packet );
|
||||
Warning("Failure to write audio packet.");
|
||||
zm_av_unref_packet( &packet );
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -735,12 +747,16 @@ Debug(5, "After av_read_frame (%d)", ret );
|
|||
}
|
||||
} else {
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 23, 0, 23, 0)
|
||||
Debug( 3, "Some other stream index %d, %s", packet->stream_index, av_get_media_type_string( mFormatContext->streams[packet->stream_index]->codec->codec_type) );
|
||||
Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codec->codec_type) );
|
||||
#else
|
||||
Debug( 3, "Some other stream index %d", packet->stream_index );
|
||||
Debug( 3, "Some other stream index %d", packet.stream_index );
|
||||
#endif
|
||||
}
|
||||
zm_av_unref_packet( packet );
|
||||
//if ( videoStore ) {
|
||||
|
||||
// the packet contents are ref counted... when queuing, we allocate another packet and reference it with that one, so we should always need to unref here, which should not affect the queued version.
|
||||
zm_av_unref_packet( &packet );
|
||||
//}
|
||||
} // end while ! frameComplete
|
||||
return (frameCount);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,11 @@ class FfmpegCamera : public Camera
|
|||
AVFrame *mFrame;
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
|
||||
// Used to store the incoming packet, it will get copied when queued.
|
||||
// We only ever need one at a time, so instead of constantly allocating
|
||||
// and freeing this structure, we will just make it a member of the object.
|
||||
AVPacket packet;
|
||||
|
||||
int OpenFfmpeg();
|
||||
int ReopenFfmpeg();
|
||||
int CloseFfmpeg();
|
||||
|
@ -67,11 +72,9 @@ class FfmpegCamera : public Camera
|
|||
bool wasRecording;
|
||||
VideoStore *videoStore;
|
||||
char oldDirectory[4096];
|
||||
unsigned int old_event_id;
|
||||
zm_packetqueue packetqueue;
|
||||
|
||||
// Last Key frame
|
||||
//AVPacket lastKeyframePkt;
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
struct SwsContext *mConvertContext;
|
||||
#endif
|
||||
|
|
|
@ -179,6 +179,12 @@ Image::~Image()
|
|||
delete decodejpg_dcinfo;
|
||||
decodejpg_dcinfo = 0;
|
||||
}
|
||||
for ( unsigned int quality=0; quality <= 100; quality += 1 ) {
|
||||
if ( writejpg_ccinfo[quality] ) {
|
||||
delete writejpg_ccinfo[quality];
|
||||
writejpg_ccinfo[quality] = NULL;
|
||||
}
|
||||
} // end foreach quality
|
||||
}
|
||||
|
||||
void Image::Initialise()
|
||||
|
|
|
@ -35,12 +35,19 @@ zm_packetqueue::~zm_packetqueue() {
|
|||
|
||||
bool zm_packetqueue::queuePacket( AVPacket* packet ) {
|
||||
|
||||
//AVPacket *input_ref = (AVPacket *)av_malloc(sizeof(AVPacket));
|
||||
//if ( av_packet_ref( input_ref, packet ) < 0 ) {
|
||||
//free(input_ref);
|
||||
//return false;
|
||||
//}
|
||||
pktQueue.push( packet );
|
||||
AVPacket *input_ref = (AVPacket *)av_malloc(sizeof(AVPacket));
|
||||
av_init_packet( input_ref );
|
||||
if ( av_packet_ref( input_ref, packet ) < 0 ) {
|
||||
Error("error refing packet");
|
||||
av_free(input_ref);
|
||||
return false;
|
||||
} else {
|
||||
Debug(3, "made a ref");
|
||||
}
|
||||
|
||||
pktQueue.push( input_ref );
|
||||
Debug(3, "queued");
|
||||
//pktQueue.push( input_ref );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -64,5 +71,10 @@ void zm_packetqueue::clearQueue() {
|
|||
pktQueue.pop();
|
||||
// If we clear it, then no freeing gets done, whereas when we pop off, we assume that the packet was freed somewhere else.
|
||||
zm_av_unref_packet( packet );
|
||||
av_free( packet );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int zm_packetqueue::size() {
|
||||
return pktQueue.size();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
bool popVideoPacket(AVPacket* packet);
|
||||
bool popAudioPacket(AVPacket* packet);
|
||||
void clearQueue( );
|
||||
unsigned int size();
|
||||
private:
|
||||
std::queue<AVPacket *> pktQueue;
|
||||
|
||||
|
|
|
@ -523,7 +523,7 @@ int RemoteCameraRtsp::CaptureAndRecord(Image &image, bool recording, char* event
|
|||
|
||||
if ( videoStore ) {
|
||||
//Write the packet to our video store
|
||||
int ret = videoStore->writeVideoFramePacket(&packet, mFormatContext->streams[mVideoStreamId]);//, &lastKeyframePkt);
|
||||
int ret = videoStore->writeVideoFramePacket(&packet);//, &lastKeyframePkt);
|
||||
if ( ret < 0 ) {//Less than zero and we skipped a frame
|
||||
// Should not
|
||||
av_free_packet( &packet );
|
||||
|
@ -553,7 +553,7 @@ int RemoteCameraRtsp::CaptureAndRecord(Image &image, bool recording, char* event
|
|||
if ( videoStore && record_audio ) {
|
||||
Debug( 4, "Storing Audio packet" );
|
||||
//Write the packet to our video store
|
||||
int ret = videoStore->writeAudioFramePacket(&packet, mFormatContext->streams[packet.stream_index]); //FIXME no relevance of last key frame
|
||||
int ret = videoStore->writeAudioFramePacket( &packet ); //FIXME no relevance of last key frame
|
||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100)
|
||||
av_packet_unref( &packet );
|
||||
|
|
|
@ -33,11 +33,15 @@ extern "C"{
|
|||
}
|
||||
|
||||
VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||
AVStream *input_video_stream,
|
||||
AVStream *input_audio_stream,
|
||||
AVStream *p_video_input_stream,
|
||||
AVStream *p_audio_input_stream,
|
||||
int64_t nStartTime,
|
||||
Monitor::Orientation orientation
|
||||
) {
|
||||
video_input_stream = p_video_input_stream;
|
||||
audio_input_stream = p_audio_input_stream;
|
||||
|
||||
video_input_context = video_input_context;
|
||||
|
||||
//store inputs in variables local to class
|
||||
filename = filename_in;
|
||||
|
@ -60,6 +64,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
filename,
|
||||
av_make_error_string(ret).c_str()
|
||||
);
|
||||
} else {
|
||||
Debug(2, "Success alocateing output context");
|
||||
}
|
||||
|
||||
//Couldn't deduce format from filename, trying from format name
|
||||
|
@ -70,6 +76,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
" could not be assigned based on filename or format %s",
|
||||
filename, format);
|
||||
}
|
||||
} else {
|
||||
Debug(2, "Success alocateing output context");
|
||||
}
|
||||
|
||||
AVDictionary *pmetadata = NULL;
|
||||
|
@ -80,93 +88,140 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
|||
|
||||
output_format = oc->oformat;
|
||||
|
||||
video_stream = avformat_new_stream(oc, (AVCodec *)input_video_stream->codec->codec);
|
||||
if (!video_stream) {
|
||||
video_output_stream = avformat_new_stream(oc, video_input_context->codec);
|
||||
if (!video_output_stream) {
|
||||
Fatal("Unable to create video out stream\n");
|
||||
} else {
|
||||
Debug(2, "Success creating video out stream" );
|
||||
}
|
||||
|
||||
ret = avcodec_copy_context(video_stream->codec, input_video_stream->codec);
|
||||
video_output_context = video_output_stream->codec;
|
||||
|
||||
#if 0
|
||||
ret = avcodec_copy_context(video_output_context, video_input_context );
|
||||
if (ret < 0) {
|
||||
Fatal("Unable to copy input video context to output video context %s\n",
|
||||
av_make_error_string(ret).c_str());
|
||||
} else {
|
||||
Debug(3, "Success copying context" );
|
||||
}
|
||||
#else
|
||||
Debug(2, "getting parameters");
|
||||
ret = avcodec_parameters_from_context( video_output_stream->codecpar, video_output_context );
|
||||
if ( ret < 0 ) {
|
||||
Error( "Could not initialize stream parameteres");
|
||||
return;
|
||||
} else {
|
||||
Debug(2, "Success getting parameters");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Debug(3, "Time bases input stream time base(%d/%d) input codec tb: (%d/%d) video_output_stream->time-base(%d/%d) output codec tb (%d/%d)",
|
||||
video_input_stream->time_base.num,
|
||||
video_input_stream->time_base.den,
|
||||
video_input_context->time_base.num,
|
||||
video_input_context->time_base.den,
|
||||
video_output_stream->time_base.num,
|
||||
video_output_stream->time_base.den,
|
||||
video_output_context->time_base.num,
|
||||
video_output_context->time_base.den
|
||||
);
|
||||
|
||||
#if 0
|
||||
if ( video_input_context->sample_aspect_ratio.den && ( video_output_stream->sample_aspect_ratio.den != video_input_context->sample_aspect_ratio.den ) ) {
|
||||
Warning("Fixing sample_aspect_ratio.den from (%d) to (%d)", video_output_stream->sample_aspect_ratio.den, video_input_context->sample_aspect_ratio.den );
|
||||
video_output_stream->sample_aspect_ratio.den = video_input_context->sample_aspect_ratio.den;
|
||||
} else {
|
||||
Debug(3, "aspect ratio denominator is (%d)", video_output_stream->sample_aspect_ratio.den );
|
||||
}
|
||||
if ( video_input_context->sample_aspect_ratio.num && ( video_output_stream->sample_aspect_ratio.num != video_input_context->sample_aspect_ratio.num ) ) {
|
||||
Warning("Fixing sample_aspect_ratio.num from video_output_stream(%d) to video_input_stream(%d)", video_output_stream->sample_aspect_ratio.num, video_input_context->sample_aspect_ratio.num );
|
||||
video_output_stream->sample_aspect_ratio.num = video_input_context->sample_aspect_ratio.num;
|
||||
} else {
|
||||
Debug(3, "aspect ratio numerator is (%d)", video_output_stream->sample_aspect_ratio.num );
|
||||
}
|
||||
if ( video_output_context->codec_id != video_input_context->codec_id ) {
|
||||
Warning("Fixing video_output_context->codec_id");
|
||||
video_output_context->codec_id = video_input_context->codec_id;
|
||||
}
|
||||
if ( ! video_output_context->time_base.num ) {
|
||||
Warning("video_output_context->time_base.num is not set%d/%d. Fixing by setting it to 1", video_output_context->time_base.num, video_output_context->time_base.den);
|
||||
Warning("video_output_context->time_base.num is not set%d/%d. Fixing by setting it to 1", video_output_stream->time_base.num, video_output_stream->time_base.den);
|
||||
video_output_context->time_base.num = video_output_stream->time_base.num;
|
||||
video_output_context->time_base.den = video_output_stream->time_base.den;
|
||||
}
|
||||
|
||||
if ( input_video_stream->codec->sample_aspect_ratio.den && ( video_stream->sample_aspect_ratio.den != input_video_stream->codec->sample_aspect_ratio.den ) ) {
|
||||
Warning("Fixing sample_aspect_ratio.den from (%d) to (%d)", video_stream->sample_aspect_ratio.den, input_video_stream->codec->sample_aspect_ratio.den );
|
||||
video_stream->sample_aspect_ratio.den = input_video_stream->codec->sample_aspect_ratio.den;
|
||||
} else {
|
||||
Debug(3, "aspect ratio denominator is (%d)", video_stream->sample_aspect_ratio.den );
|
||||
}
|
||||
if ( input_video_stream->codec->sample_aspect_ratio.num && ( video_stream->sample_aspect_ratio.num != input_video_stream->codec->sample_aspect_ratio.num ) ) {
|
||||
Warning("Fixing sample_aspect_ratio.num from video_stream(%d) to input_video_stream(%d)", video_stream->sample_aspect_ratio.num, input_video_stream->codec->sample_aspect_ratio.num );
|
||||
video_stream->sample_aspect_ratio.num = input_video_stream->codec->sample_aspect_ratio.num;
|
||||
} else {
|
||||
Debug(3, "aspect ratio numerator is (%d)", video_stream->sample_aspect_ratio.num );
|
||||
}
|
||||
if ( video_stream->codec->codec_id != input_video_stream->codec->codec_id ) {
|
||||
Warning("Fixing video_stream->codec->codec_id");
|
||||
video_stream->codec->codec_id = input_video_stream->codec->codec_id;
|
||||
}
|
||||
if ( ! video_stream->codec->time_base.num ) {
|
||||
Warning("video_stream->codec->time_base.num is not set%d/%d. Fixing by setting it to 1", video_stream->codec->time_base.num, video_stream->codec->time_base.den);
|
||||
Warning("video_stream->codec->time_base.num is not set%d/%d. Fixing by setting it to 1", video_stream->time_base.num, video_stream->time_base.den);
|
||||
video_stream->codec->time_base.num = video_stream->time_base.num;
|
||||
video_stream->codec->time_base.den = video_stream->time_base.den;
|
||||
}
|
||||
|
||||
if ( video_stream->sample_aspect_ratio.den != video_stream->codec->sample_aspect_ratio.den ) {
|
||||
if ( video_output_stream->sample_aspect_ratio.den != video_output_context->sample_aspect_ratio.den ) {
|
||||
Warning("Fixingample_aspect_ratio.den");
|
||||
video_stream->sample_aspect_ratio.den = video_stream->codec->sample_aspect_ratio.den;
|
||||
video_output_stream->sample_aspect_ratio.den = video_output_context->sample_aspect_ratio.den;
|
||||
}
|
||||
if ( video_stream->sample_aspect_ratio.num != input_video_stream->codec->sample_aspect_ratio.num ) {
|
||||
if ( video_output_stream->sample_aspect_ratio.num != video_input_context->sample_aspect_ratio.num ) {
|
||||
Warning("Fixingample_aspect_ratio.num");
|
||||
video_stream->sample_aspect_ratio.num = input_video_stream->codec->sample_aspect_ratio.num;
|
||||
video_output_stream->sample_aspect_ratio.num = video_input_context->sample_aspect_ratio.num;
|
||||
}
|
||||
if ( video_stream->codec->codec_id != input_video_stream->codec->codec_id ) {
|
||||
Warning("Fixing video_stream->codec->codec_id");
|
||||
video_stream->codec->codec_id = input_video_stream->codec->codec_id;
|
||||
if ( video_output_context->codec_id != video_input_context->codec_id ) {
|
||||
Warning("Fixing video_output_context->codec_id");
|
||||
video_output_context->codec_id = video_input_context->codec_id;
|
||||
}
|
||||
if ( ! video_output_context->time_base.num ) {
|
||||
Warning("video_output_context->time_base.num is not set%d/%d. Fixing by setting it to 1", video_output_context->time_base.num, video_output_context->time_base.den);
|
||||
Warning("video_output_context->time_base.num is not set%d/%d. Fixing by setting it to 1", video_output_stream->time_base.num, video_output_stream->time_base.den);
|
||||
video_output_context->time_base.num = video_output_stream->time_base.num;
|
||||
video_output_context->time_base.den = video_output_stream->time_base.den;
|
||||
}
|
||||
#endif
|
||||
|
||||
// WHY?
|
||||
//video_output_context->codec_tag = 0;
|
||||
if (!video_output_context->codec_tag) {
|
||||
Debug(2, "No codec_tag");
|
||||
if (! oc->oformat->codec_tag
|
||||
|| av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id
|
||||
|| av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id) <= 0) {
|
||||
Warning("Setting codec tag");
|
||||
video_output_context->codec_tag = video_input_context->codec_tag;
|
||||
}
|
||||
if ( ! video_stream->codec->time_base.num ) {
|
||||
Warning("video_stream->codec->time_base.num is not set%d/%d. Fixing by setting it to 1", video_stream->codec->time_base.num, video_stream->codec->time_base.den);
|
||||
Warning("video_stream->codec->time_base.num is not set%d/%d. Fixing by setting it to 1", video_stream->time_base.num, video_stream->time_base.den);
|
||||
video_stream->codec->time_base.num = video_stream->time_base.num;
|
||||
video_stream->codec->time_base.den = video_stream->time_base.den;
|
||||
}
|
||||
|
||||
video_stream->codec->codec_tag = 0;
|
||||
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
video_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
video_output_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
|
||||
if ( orientation ) {
|
||||
if ( orientation == Monitor::ROTATE_0 ) {
|
||||
|
||||
} else if ( orientation == Monitor::ROTATE_90 ) {
|
||||
dsr = av_dict_set( &video_stream->metadata, "rotate", "90", 0);
|
||||
dsr = av_dict_set( &video_output_stream->metadata, "rotate", "90", 0);
|
||||
if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ );
|
||||
} else if ( orientation == Monitor::ROTATE_180 ) {
|
||||
dsr = av_dict_set( &video_stream->metadata, "rotate", "180", 0);
|
||||
dsr = av_dict_set( &video_output_stream->metadata, "rotate", "180", 0);
|
||||
if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ );
|
||||
} else if ( orientation == Monitor::ROTATE_270 ) {
|
||||
dsr = av_dict_set( &video_stream->metadata, "rotate", "270", 0);
|
||||
dsr = av_dict_set( &video_output_stream->metadata, "rotate", "270", 0);
|
||||
if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ );
|
||||
} else {
|
||||
Warning( "Unsupported Orientation(%d)", orientation );
|
||||
}
|
||||
}
|
||||
audio_output_codec = NULL;
|
||||
|
||||
if (input_audio_stream) {
|
||||
audio_output_codec = NULL;
|
||||
audio_input_context = NULL;
|
||||
|
||||
if ( input_audio_stream->codec->codec_id != AV_CODEC_ID_AAC ) {
|
||||
if (audio_input_stream) {
|
||||
audio_input_context = audio_input_stream->codec;
|
||||
|
||||
if ( audio_input_context->codec_id != AV_CODEC_ID_AAC ) {
|
||||
Warning("Can't transcode to AAC at this time");
|
||||
audio_stream = NULL;
|
||||
audio_output_stream = NULL;
|
||||
|
||||
audio_output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
|
||||
if ( audio_output_codec ) {
|
||||
audio_stream = avformat_new_stream(oc, audio_output_codec );
|
||||
audio_output_stream = avformat_new_stream(oc, audio_output_codec );
|
||||
|
||||
audio_output_context = audio_stream->codec;
|
||||
audio_output_context = audio_output_stream->codec;
|
||||
|
||||
//audio_output_context = avcodec_alloc_context3( audio_output_codec );
|
||||
if ( audio_output_context ) {
|
||||
|
@ -176,11 +231,11 @@ Debug(2, "Have audio_output_context");
|
|||
av_dict_set(&opts, "strict", "experimental", 0);
|
||||
|
||||
/* put sample parameters */
|
||||
audio_output_context->bit_rate = input_audio_stream->codec->bit_rate;
|
||||
audio_output_context->sample_rate = input_audio_stream->codec->sample_rate;
|
||||
audio_output_context->channels = input_audio_stream->codec->channels;
|
||||
audio_output_context->channel_layout = input_audio_stream->codec->channel_layout;
|
||||
audio_output_context->sample_fmt = input_audio_stream->codec->sample_fmt;
|
||||
audio_output_context->bit_rate = audio_input_context->bit_rate;
|
||||
audio_output_context->sample_rate = audio_input_context->sample_rate;
|
||||
audio_output_context->channels = audio_input_context->channels;
|
||||
audio_output_context->channel_layout = audio_input_context->channel_layout;
|
||||
audio_output_context->sample_fmt = audio_input_context->sample_fmt;
|
||||
|
||||
/* check that the encoder supports s16 pcm input */
|
||||
if (!check_sample_fmt( audio_output_codec, audio_output_context->sample_fmt)) {
|
||||
|
@ -198,20 +253,23 @@ Debug(2, "Have audio_output_context");
|
|||
);
|
||||
|
||||
/** Set the sample rate for the container. */
|
||||
audio_stream->time_base.den = input_audio_stream->codec->sample_rate;
|
||||
audio_stream->time_base.num = 1;
|
||||
audio_output_stream->time_base.den = audio_input_context->sample_rate;
|
||||
audio_output_stream->time_base.num = 1;
|
||||
|
||||
ret = avcodec_open2(audio_output_context, audio_output_codec, &opts );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror(ret, error_buffer, sizeof(error_buffer));
|
||||
Fatal( "could not open codec (%d) (%s)\n", ret, error_buffer );
|
||||
} else {
|
||||
|
||||
#if 0
|
||||
/** Create the FIFO buffer based on the specified output sample format. */
|
||||
if (!(fifo = av_audio_fifo_alloc(audio_output_context->sample_fmt,
|
||||
audio_output_context->channels, 1))) {
|
||||
Error("Could not allocate FIFO\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
output_frame_size = audio_output_context->frame_size;
|
||||
Debug(2, "Success opening AAC codec");
|
||||
}
|
||||
|
@ -224,29 +282,29 @@ Debug(2, "Have audio_output_context");
|
|||
}
|
||||
|
||||
} else {
|
||||
Debug(3, "Got something other than AAC (%d)", input_audio_stream->codec->codec_id );
|
||||
Debug(3, "Got something other than AAC (%d)", audio_input_context->codec_id );
|
||||
|
||||
audio_stream = avformat_new_stream(oc, (AVCodec *)input_audio_stream->codec->codec);
|
||||
if (!audio_stream) {
|
||||
audio_output_stream = avformat_new_stream(oc, (AVCodec *)audio_input_context->codec);
|
||||
if (!audio_output_stream) {
|
||||
Error("Unable to create audio out stream\n");
|
||||
audio_stream = NULL;
|
||||
audio_output_stream = NULL;
|
||||
}
|
||||
ret = avcodec_copy_context(audio_stream->codec, input_audio_stream->codec);
|
||||
ret = avcodec_copy_context(audio_output_context, audio_input_context);
|
||||
if (ret < 0) {
|
||||
Fatal("Unable to copy audio context %s\n", av_make_error_string(ret).c_str());
|
||||
}
|
||||
audio_stream->codec->codec_tag = 0;
|
||||
if ( audio_stream->codec->channels > 1 ) {
|
||||
audio_output_context->codec_tag = 0;
|
||||
if ( audio_output_context->channels > 1 ) {
|
||||
Warning("Audio isn't mono, changing it.");
|
||||
audio_stream->codec->channels = 1;
|
||||
audio_output_context->channels = 1;
|
||||
}
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
audio_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
audio_output_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
} // end if is AAC
|
||||
} else {
|
||||
Debug(3, "No Audio output stream");
|
||||
audio_stream = NULL;
|
||||
audio_output_stream = NULL;
|
||||
}
|
||||
|
||||
/* open the output file, if needed */
|
||||
|
@ -269,7 +327,7 @@ Debug(2, "Have audio_output_context");
|
|||
ret = avformat_write_header(oc, NULL);
|
||||
if (ret < 0) {
|
||||
zm_dump_stream_format( oc, 0, 0, 1 );
|
||||
if ( audio_stream )
|
||||
if ( audio_output_stream )
|
||||
zm_dump_stream_format( oc, 1, 0, 1 );
|
||||
Error("Error occurred when writing output file header to %s: %s\n",
|
||||
filename,
|
||||
|
@ -277,12 +335,16 @@ Debug(2, "Have audio_output_context");
|
|||
}
|
||||
|
||||
prevDts = 0;
|
||||
startPts = 0;
|
||||
startDts = 0;
|
||||
video_start_pts = 0;
|
||||
video_start_dts = 0;
|
||||
audio_start_pts = 0;
|
||||
audio_start_dts = 0;
|
||||
|
||||
filter_in_rescale_delta_last = AV_NOPTS_VALUE;
|
||||
|
||||
startTime=av_gettime()-nStartTime;//oc->start_time;
|
||||
Info("VideoStore startTime=%d\n",startTime);
|
||||
// now - when streaming started
|
||||
//startTime=av_gettime()-nStartTime;//oc->start_time;
|
||||
//Info("VideoStore startTime=%d\n",startTime);
|
||||
} // VideoStore::VideoStore
|
||||
|
||||
|
||||
|
@ -297,11 +359,11 @@ VideoStore::~VideoStore(){
|
|||
// I wonder if we should be closing the file first.
|
||||
// I also wonder if we really need to be doing all the context allocation/de-allocation constantly, or whether we can just re-use it. Just do a file open/close/writeheader/etc.
|
||||
// What if we were only doing audio recording?
|
||||
if ( video_stream ) {
|
||||
avcodec_close(video_stream->codec);
|
||||
if ( video_output_stream ) {
|
||||
avcodec_close(video_output_context);
|
||||
}
|
||||
if (audio_stream) {
|
||||
avcodec_close(audio_stream->codec);
|
||||
if (audio_output_stream) {
|
||||
avcodec_close(audio_output_context);
|
||||
}
|
||||
|
||||
// WHen will be not using a file ?
|
||||
|
@ -330,63 +392,85 @@ void VideoStore::dumpPacket( AVPacket *pkt ){
|
|||
, pkt->stream_index
|
||||
, pkt->flags
|
||||
, pkt->pos
|
||||
, pkt->convergence_duration
|
||||
, pkt->duration
|
||||
);
|
||||
Info("%s:%d:DEBUG: %s", __FILE__, __LINE__, b);
|
||||
Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b);
|
||||
}
|
||||
|
||||
int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_video_stream){
|
||||
|
||||
Debug(4, "writeVideoFrame");
|
||||
Debug(3, "before ost_tbcket starttime %d, timebase%d", startTime, video_stream->time_base );
|
||||
//zm_dump_stream_format( oc, ipkt->stream_index, 0, 1 );
|
||||
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, video_stream->time_base);
|
||||
Debug(2, "before ost_tbcket starttime %d, ost_tbcket %d", startTime, ost_tb_start_time );
|
||||
int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) {
|
||||
|
||||
AVPacket opkt;
|
||||
AVPicture pict;
|
||||
|
||||
Debug(2, "writeVideoFrame init_packet");
|
||||
Debug(4, "writeVideoFrame init_packet");
|
||||
av_init_packet(&opkt);
|
||||
|
||||
if ( 1 ) {
|
||||
//Scale the PTS of the outgoing packet to be the correct time base
|
||||
if (ipkt->pts != AV_NOPTS_VALUE) {
|
||||
opkt.pts = av_rescale_q(ipkt->pts-startPts, input_video_stream->time_base, video_stream->time_base) - ost_tb_start_time;
|
||||
Debug(3, "opkt.pts = %d from ipkt->pts(%d) - startPts(%d), input->time_base(%d) video_stream->time-base(%d)", opkt.pts, ipkt->pts, startPts, input_video_stream->time_base, video_stream->time_base );
|
||||
if ( ! video_start_pts ) {
|
||||
//never gets set, so the first packet can set it.
|
||||
video_start_pts = ipkt->pts;
|
||||
}
|
||||
opkt.pts = av_rescale_q(ipkt->pts - video_start_pts, video_input_stream->time_base, video_output_stream->time_base);
|
||||
//- ost_tb_start_time;
|
||||
Debug(3, "opkt.pts = %d from ipkt->pts(%d) - startPts(%d)", opkt.pts, ipkt->pts, video_start_pts );
|
||||
} else {
|
||||
Debug(3, "opkt.pts = undef");
|
||||
opkt.pts = AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
//Scale the DTS of the outgoing packet to be the correct time base
|
||||
if(ipkt->dts == AV_NOPTS_VALUE) {
|
||||
opkt.dts = av_rescale_q(input_video_stream->cur_dts-startDts, AV_TIME_BASE_Q, video_stream->time_base);
|
||||
Debug(3, "opkt.dts = %d from input_video_stream->cur_dts(%d) - startDts(%d), video_stream->time-base(%d)", opkt.dts, input_video_stream->cur_dts, startDts, video_stream->time_base );
|
||||
// why are we using cur_dts instead of packet.dts?
|
||||
if ( ! video_start_dts ) video_start_dts = video_input_stream->cur_dts;
|
||||
opkt.dts = av_rescale_q(video_input_stream->cur_dts - video_start_dts, AV_TIME_BASE_Q, video_output_stream->time_base);
|
||||
Debug(3, "opkt.dts = %d from video_input_stream->cur_dts(%d) - startDts(%d)",
|
||||
opkt.dts, video_input_stream->cur_dts, video_start_dts
|
||||
);
|
||||
} else {
|
||||
opkt.dts = av_rescale_q(ipkt->dts-startDts, input_video_stream->time_base, video_stream->time_base);
|
||||
Debug(3, "opkt.dts = %d from ipkt->dts(%d) - startDts(%d), video_stream->time-base(%d)", opkt.dts, ipkt->dts, startDts, video_stream->time_base );
|
||||
if ( ! video_start_dts ) video_start_dts = ipkt->dts;
|
||||
opkt.dts = av_rescale_q(ipkt->dts - video_start_dts, video_input_stream->time_base, video_output_stream->time_base);
|
||||
Debug(3, "opkt.dts = %d from ipkt->dts(%d) - startDts(%d)", opkt.dts, ipkt->dts, video_start_dts );
|
||||
}
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
Debug( 1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts );
|
||||
opkt.dts = opkt.pts;
|
||||
}
|
||||
|
||||
opkt.dts -= ost_tb_start_time;
|
||||
|
||||
opkt.duration = av_rescale_q(ipkt->duration, input_video_stream->time_base, video_stream->time_base);
|
||||
opkt.duration = av_rescale_q(ipkt->duration, video_input_stream->time_base, video_output_stream->time_base);
|
||||
} else {
|
||||
av_packet_rescale_ts( &opkt, video_input_stream->time_base, video_output_stream->time_base );
|
||||
}
|
||||
opkt.flags = ipkt->flags;
|
||||
opkt.pos=-1;
|
||||
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
|
||||
// Some camera have audio on stream 0 and video on stream 1. So when we remove the audio, video stream has to go on 0
|
||||
if ( ipkt->stream_index > 0 and ! audio_output_stream ) {
|
||||
Debug(1,"Setting stream index to 0 instead of %d", ipkt->stream_index );
|
||||
opkt.stream_index = 0;
|
||||
} else {
|
||||
opkt.stream_index = ipkt->stream_index;
|
||||
}
|
||||
|
||||
/*opkt.flags |= AV_PKT_FLAG_KEY;*/
|
||||
|
||||
if (video_stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && (output_format->flags & AVFMT_RAWPICTURE)) {
|
||||
#if 0
|
||||
if (video_output_context->codec_type == AVMEDIA_TYPE_VIDEO && (output_format->flags & AVFMT_RAWPICTURE)) {
|
||||
Debug(3, "video and RAWPICTURE");
|
||||
/* store AVPicture in AVPacket, as expected by the output format */
|
||||
avpicture_fill(&pict, opkt.data, video_stream->codec->pix_fmt, video_stream->codec->width, video_stream->codec->height);
|
||||
avpicture_fill(&pict, opkt.data, video_output_context->pix_fmt, video_output_context->width, video_output_context->height, 0);
|
||||
av_image_fill_arrays(
|
||||
opkt.data = (uint8_t *)&pict;
|
||||
opkt.size = sizeof(AVPicture);
|
||||
opkt.flags |= AV_PKT_FLAG_KEY;
|
||||
} else {
|
||||
Debug(3, "Not video and RAWPICTURE");
|
||||
Debug(4, "Not video and RAWPICTURE");
|
||||
}
|
||||
#endif
|
||||
|
||||
//memcpy(&safepkt, &opkt, sizeof(AVPacket));
|
||||
|
||||
|
@ -404,6 +488,7 @@ Debug(3, "Not video and RAWPICTURE");
|
|||
int ret;
|
||||
|
||||
prevDts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance
|
||||
dumpPacket(&opkt);
|
||||
ret = av_interleaved_write_frame(oc, &opkt);
|
||||
if(ret<0){
|
||||
// There's nothing we can really do if the frame is rejected, just drop it and get on with the next
|
||||
|
@ -418,11 +503,11 @@ Debug(3, "Not video and RAWPICTURE");
|
|||
|
||||
}
|
||||
|
||||
int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_audio_stream){
|
||||
Debug(2, "writeAudioFrame");
|
||||
int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) {
|
||||
Debug(4, "writeAudioFrame");
|
||||
|
||||
if(!audio_stream) {
|
||||
Error("Called writeAudioFramePacket when no audio_stream");
|
||||
if(!audio_output_stream) {
|
||||
Error("Called writeAudioFramePacket when no audio_output_stream");
|
||||
return 0;//FIXME -ve return codes do not free packet in ffmpeg_camera at the moment
|
||||
}
|
||||
/*if(!keyframeMessage)
|
||||
|
@ -430,8 +515,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_audio_stre
|
|||
//zm_dump_stream_format( oc, ipkt->stream_index, 0, 1 );
|
||||
|
||||
int ret;
|
||||
// What is this doing? Getting the time of the start of this video chunk? Does that actually make sense?
|
||||
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, audio_stream->time_base);
|
||||
|
||||
AVPacket opkt;
|
||||
|
||||
|
@ -440,61 +523,45 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_audio_stre
|
|||
|
||||
//Scale the PTS of the outgoing packet to be the correct time base
|
||||
if (ipkt->pts != AV_NOPTS_VALUE) {
|
||||
Debug(2, "Rescaling output pts");
|
||||
opkt.pts = av_rescale_q(ipkt->pts-startPts, input_audio_stream->time_base, audio_stream->time_base) - ost_tb_start_time;
|
||||
if ( ! audio_start_pts ) {
|
||||
//never gets set, so the first packet can set it.
|
||||
audio_start_pts = ipkt->pts;
|
||||
}
|
||||
opkt.pts = av_rescale_q(ipkt->pts-audio_start_pts, audio_input_stream->time_base, audio_output_stream->time_base);
|
||||
Debug(3, "opkt.pts = %d from ipkt->pts(%d) - startPts(%d)", opkt.pts, ipkt->pts, audio_start_pts );
|
||||
} else {
|
||||
Debug(2, "Setting output pts to AV_NOPTS_VALUE");
|
||||
Debug(3, "opkt.pts = undef");
|
||||
opkt.pts = AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
//Scale the DTS of the outgoing packet to be the correct time base
|
||||
if(ipkt->dts == AV_NOPTS_VALUE) {
|
||||
Debug(2, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||
opkt.dts = av_rescale_q(input_audio_stream->cur_dts-startDts, AV_TIME_BASE_Q, audio_stream->time_base);
|
||||
Debug(2, "ipkt->dts == AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||
if ( ! audio_start_dts ) audio_start_dts = video_input_stream->cur_dts;
|
||||
opkt.dts = av_rescale_q(video_input_stream->cur_dts - audio_start_dts, AV_TIME_BASE_Q, audio_output_stream->time_base);
|
||||
Debug(3, "opkt.dts = %d from video_input_stream->cur_dts(%d) - startDts(%d)",
|
||||
opkt.dts, audio_input_stream->cur_dts, audio_start_dts
|
||||
);
|
||||
} else {
|
||||
Debug(2, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||
opkt.dts = av_rescale_q(ipkt->dts-startDts, input_audio_stream->time_base, audio_stream->time_base);
|
||||
Debug(2, "ipkt->dts != AV_NOPTS_VALUE %d to %d", AV_NOPTS_VALUE, opkt.dts );
|
||||
if ( ! audio_start_dts ) audio_start_dts = ipkt->dts;
|
||||
opkt.dts = av_rescale_q(ipkt->dts - audio_start_dts, audio_input_stream->time_base, audio_output_stream->time_base);
|
||||
Debug(3, "opkt.dts = %d from ipkt->dts(%d) - startDts(%d)", opkt.dts, ipkt->dts, audio_start_dts );
|
||||
}
|
||||
Debug(2, "Not sure what ost_tb_start_time is (%d) - (%d)", opkt.dts, ost_tb_start_time );
|
||||
opkt.dts -= ost_tb_start_time;
|
||||
|
||||
// Seems like it would be really weird for the codec type to NOT be audiu
|
||||
if (audio_stream->codec->codec_type == AVMEDIA_TYPE_AUDIO && ipkt->dts != AV_NOPTS_VALUE) {
|
||||
int duration = av_get_audio_frame_duration(input_audio_stream->codec, ipkt->size);
|
||||
Debug( 1, "code is audio, dts != AV_NOPTS_VALUE got duration(%d)", duration );
|
||||
if ( ! duration ) {
|
||||
duration = input_audio_stream->codec->frame_size;
|
||||
Warning( "got no duration from av_get_audio_frame_duration. Using frame size(%d)", duration );
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
Debug(1,"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts );
|
||||
opkt.dts = opkt.pts;
|
||||
}
|
||||
|
||||
//FIXME where to get filter_in_rescale_delta_last
|
||||
//FIXME av_rescale_delta doesn't exist in ubuntu vivid libavtools
|
||||
opkt.dts = opkt.pts = av_rescale_delta(input_audio_stream->time_base, ipkt->dts,
|
||||
(AVRational){1, input_audio_stream->codec->sample_rate}, duration, &filter_in_rescale_delta_last,
|
||||
audio_stream->time_base) - ost_tb_start_time;
|
||||
Debug(2, "rescaled dts is: (%d)", opkt.dts );
|
||||
}
|
||||
|
||||
opkt.duration = av_rescale_q(ipkt->duration, input_audio_stream->time_base, audio_stream->time_base);
|
||||
opkt.pos=-1;
|
||||
opkt.duration = av_rescale_q(ipkt->duration, audio_input_stream->time_base, audio_output_stream->time_base);
|
||||
// pkt.pos: byte position in stream, -1 if unknown
|
||||
opkt.pos = -1;
|
||||
opkt.flags = ipkt->flags;
|
||||
opkt.stream_index = ipkt->stream_index;
|
||||
|
||||
if ( audio_output_codec ) {
|
||||
// we are transcoding
|
||||
AVFrame *input_frame;
|
||||
AVFrame *output_frame;
|
||||
|
||||
// Need to re-encode
|
||||
if ( 0 ) {
|
||||
//avcodec_send_packet( input_audio_stream->codec, ipkt);
|
||||
//avcodec_receive_frame( input_audio_stream->codec, input_frame );
|
||||
//avcodec_send_frame( audio_stream->codec, input_frame );
|
||||
//
|
||||
////avcodec_receive_packet( audio_stream->codec, &opkt );
|
||||
} else {
|
||||
|
||||
/** Create a new frame to store the audio samples. */
|
||||
if (!(input_frame = zm_av_frame_alloc())) {
|
||||
Error("Could not allocate input frame");
|
||||
|
@ -504,17 +571,36 @@ if ( 0 ) {
|
|||
Debug(2, "Got input frame alloc");
|
||||
}
|
||||
|
||||
/** Create a new frame to store the audio samples. */
|
||||
if (!(output_frame = zm_av_frame_alloc())) {
|
||||
Error("Could not allocate output frame");
|
||||
av_frame_free(&input_frame);
|
||||
zm_av_unref_packet(&opkt);
|
||||
return 0;
|
||||
} else {
|
||||
Debug(2, "Got output frame alloc");
|
||||
}
|
||||
// Need to re-encode
|
||||
#if 1
|
||||
avcodec_send_packet( audio_input_context, ipkt );
|
||||
avcodec_receive_frame( audio_input_context, input_frame );
|
||||
avcodec_send_frame( audio_output_context, input_frame );
|
||||
//
|
||||
avcodec_receive_packet( audio_output_context, &opkt );
|
||||
#else
|
||||
|
||||
|
||||
/**
|
||||
* Decode the audio frame stored in the packet.
|
||||
* The input audio stream decoder is used to do this.
|
||||
* If we are at the end of the file, pass an empty packet to the decoder
|
||||
* to flush it.
|
||||
*/
|
||||
if ((ret = avcodec_decode_audio4(input_audio_stream->codec, input_frame,
|
||||
if ((ret = avcodec_decode_audio4(audio_input_context, input_frame,
|
||||
&data_present, ipkt)) < 0) {
|
||||
Error( "Could not decode frame (error '%s')\n",
|
||||
av_make_error_string(ret).c_str());
|
||||
dumpPacket( ipkt);
|
||||
dumpPacket( ipkt );
|
||||
av_frame_free(&input_frame);
|
||||
zm_av_unref_packet(&opkt);
|
||||
return 0;
|
||||
|
@ -549,6 +635,48 @@ av_make_error_string(ret).c_str() );
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a resampler context for the conversion.
|
||||
* Set the conversion parameters.
|
||||
* Default channel layouts based on the number of channels
|
||||
* are assumed for simplicity (they are sometimes not detected
|
||||
* properly by the demuxer and/or decoder).
|
||||
*/
|
||||
*resample_context = swr_alloc_set_opts(NULL,
|
||||
av_get_default_channel_layout(audio_output_context->channels),
|
||||
audio_output_context->sample_fmt,
|
||||
audio_output_context->sample_rate,
|
||||
av_get_default_channel_layout( audio_input_context->channels),
|
||||
audio_input_stream->sample_fmt,
|
||||
audio_input_stream->sample_rate,
|
||||
0, NULL);
|
||||
if (!*resample_context) {
|
||||
Error( "Could not allocate resample context\n");
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Perform a sanity check so that the number of converted samples is
|
||||
* not greater than the number of samples to be converted.
|
||||
* If the sample rates differ, this case has to be handled differently
|
||||
*/
|
||||
av_assert0(audio_output_context->sample_rate == audio_input_context->sample_rate);
|
||||
/** Open the resampler with the specified parameters. */
|
||||
if ((ret = swr_init(*resample_context)) < 0) {
|
||||
Error( "Could not open resample context\n");
|
||||
swr_free(resample_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Convert the samples using the resampler. */
|
||||
if ((error = swr_convert(resample_context,
|
||||
converted_input_samples, frame_size,
|
||||
input_data , frame_size)) < 0) {
|
||||
fprintf(stderr, "Could not convert input samples (error '%s')\n",
|
||||
get_error_text(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) {
|
||||
Error( "Could not reallocate FIFO\n");
|
||||
return 0;
|
||||
|
@ -559,15 +687,6 @@ av_make_error_string(ret).c_str() );
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Create a new frame to store the audio samples. */
|
||||
if (!(output_frame = zm_av_frame_alloc())) {
|
||||
Error("Could not allocate output frame");
|
||||
av_frame_free(&input_frame);
|
||||
zm_av_unref_packet(&opkt);
|
||||
return 0;
|
||||
} else {
|
||||
Debug(2, "Got output frame alloc");
|
||||
}
|
||||
/**
|
||||
* Set the frame's parameters, especially its size and format.
|
||||
* av_frame_get_buffer needs this to allocate memory for the
|
||||
|
@ -575,7 +694,7 @@ av_make_error_string(ret).c_str() );
|
|||
* Default channel layouts based on the number of channels
|
||||
* are assumed for simplicity.
|
||||
*/
|
||||
output_frame->nb_samples = audio_stream->codec->frame_size;
|
||||
output_frame->nb_samples = audio_output_context->frame_size;
|
||||
output_frame->channel_layout = audio_output_context->channel_layout;
|
||||
output_frame->channels = audio_output_context->channels;
|
||||
output_frame->format = audio_output_context->sample_fmt;
|
||||
|
@ -615,7 +734,7 @@ av_make_error_string(ret).c_str() );
|
|||
} else {
|
||||
Debug(2, "Not data present" );
|
||||
} // end if data_present
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
opkt.data = ipkt->data;
|
||||
opkt.size = ipkt->size;
|
||||
|
|
|
@ -13,8 +13,15 @@ private:
|
|||
|
||||
AVOutputFormat *output_format;
|
||||
AVFormatContext *oc;
|
||||
AVStream *video_stream;
|
||||
AVStream *audio_stream;
|
||||
AVStream *video_output_stream;
|
||||
AVStream *audio_output_stream;
|
||||
AVCodecContext *video_output_context;
|
||||
|
||||
AVStream *video_input_stream;
|
||||
AVStream *audio_input_stream;
|
||||
|
||||
AVCodecContext *video_input_context;
|
||||
AVCodecContext *audio_input_context;
|
||||
|
||||
// The following are used when encoding the audio stream to AAC
|
||||
AVCodec *audio_output_codec;
|
||||
|
@ -29,33 +36,23 @@ private:
|
|||
bool keyframeMessage;
|
||||
int keyframeSkipNumber;
|
||||
|
||||
int64_t startTime;
|
||||
int64_t startPts;
|
||||
int64_t startDts;
|
||||
int64_t video_start_pts;
|
||||
int64_t video_start_dts;
|
||||
int64_t audio_start_pts;
|
||||
int64_t audio_start_dts;
|
||||
|
||||
int64_t prevDts;
|
||||
int64_t filter_in_rescale_delta_last;
|
||||
|
||||
public:
|
||||
VideoStore(const char *filename_in, const char *format_in, AVStream *input_video_stream, AVStream *input_audio_stream, int64_t nStartTime, Monitor::Orientation p_orientation );
|
||||
VideoStore(const char *filename_in, const char *format_in, AVStream *video_input_stream, AVStream *audio_input_stream, int64_t nStartTime, Monitor::Orientation p_orientation );
|
||||
~VideoStore();
|
||||
|
||||
int writeVideoFramePacket(AVPacket *pkt, AVStream *input_st);//, AVPacket *lastKeyframePkt);
|
||||
int writeAudioFramePacket(AVPacket *pkt, AVStream *input_st);
|
||||
int writeVideoFramePacket( AVPacket *pkt );
|
||||
int writeAudioFramePacket( AVPacket *pkt );
|
||||
void dumpPacket( AVPacket *pkt );
|
||||
};
|
||||
|
||||
/*
|
||||
class VideoEvent {
|
||||
public:
|
||||
VideoEvent(unsigned int eid);
|
||||
~VideoEvent();
|
||||
|
||||
int createEventImage(unsigned int fid, char *&pBuff);
|
||||
|
||||
private:
|
||||
unsigned int m_eid;
|
||||
};*/
|
||||
|
||||
#endif //havelibav
|
||||
#endif //zm_videostore_h
|
||||
|
||||
|
|
|
@ -48,7 +48,10 @@ void Zone::Setup( Monitor *p_monitor, int p_id, const char *p_label, ZoneType p_
|
|||
overload_frames = p_overload_frames;
|
||||
extend_alarm_frames = p_extend_alarm_frames;
|
||||
|
||||
Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames );
|
||||
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames );
|
||||
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames );
|
||||
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method );
|
||||
Debug( 1, "Initialised zone %d/%s - %d - %dx%d", id, label, type, polygon.Width(), polygon.Height() );
|
||||
|
||||
alarmed = false;
|
||||
pixel_diff = 0;
|
||||
|
|
|
@ -171,7 +171,7 @@ private $control_fields = array(
|
|||
}
|
||||
}
|
||||
public function getStreamSrc( $args, $querySep='&' ) {
|
||||
if ( isset($this->{'ServerId'}) ) {
|
||||
if ( isset($this->{'ServerId'}) and $this->{'ServerId'} ) {
|
||||
$Server = new Server( $this->{'ServerId'} );
|
||||
$streamSrc = ZM_BASE_PROTOCOL.'://'.$Server->Hostname().ZM_PATH_ZMS;
|
||||
} else {
|
||||
|
|
|
@ -27,7 +27,14 @@ class Storage {
|
|||
if ( isset( $this->{'Path'} ) and ( $this->{'Path'} != '' ) ) {
|
||||
return $this->{'Path'};
|
||||
} else if ( ! isset($this->{'Id'}) ) {
|
||||
return ZM_DIR_EVENTS;
|
||||
$path = ZM_DIR_EVENTS;
|
||||
if ( $path[0] != '/' ) {
|
||||
$this->{'Path'} = ZM_PATH_WEB.'/'.ZM_DIR_EVENTS;
|
||||
} else {
|
||||
$this->{'Path'} = ZM_DIR_EVENTS;
|
||||
}
|
||||
return $this->{'Path'};
|
||||
|
||||
}
|
||||
return $this->{'Name'};
|
||||
}
|
||||
|
|
|
@ -39,8 +39,6 @@ if ( !canView( 'Events' ) ) {
|
|||
require_once('includes/Event.php');
|
||||
require_once('includes/Frame.php');
|
||||
|
||||
header( 'Content-type: image/jpeg' );
|
||||
|
||||
// Compatibility for PHP 5.4
|
||||
if (!function_exists('imagescale')) {
|
||||
function imagescale($image, $new_width, $new_height = -1, $mode = 0) {
|
||||
|
@ -85,6 +83,10 @@ if ( empty($_REQUEST['path']) ) {
|
|||
$retval = 0;
|
||||
exec( $command, $output, $retval );
|
||||
Debug("Retval: $retval, output: " . implode("\n", $output));
|
||||
if ( ! file_exists( $path ) ) {
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
Fatal("Can't create frame images from video for this event (".$Event->DefaultVideo() );
|
||||
}
|
||||
} else {
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
Fatal("Can't create frame images from video becuase there is no video file for this event (".$Event->DefaultVideo() );
|
||||
|
@ -138,6 +140,10 @@ if( !empty($_REQUEST['height']) ) {
|
|||
}
|
||||
|
||||
|
||||
header( 'Content-type: image/jpeg' );
|
||||
ob_clean();
|
||||
flush();
|
||||
|
||||
if ( $errorText ) {
|
||||
Error( $errorText );
|
||||
} else {
|
||||
|
@ -167,13 +173,8 @@ if ( $errorText ) {
|
|||
|
||||
# Slight optimisation, thumbnails always specify width and height, so we can cache them.
|
||||
$scaled_path = preg_replace('/\.jpg$/', "-${width}x${height}.jpg", $path );
|
||||
if ( file_exists( $scaled_path ) ) {
|
||||
Debug( "Using cached scaled image at $scaled_path.");
|
||||
if ( ! readfile( $scaled_path ) ) {
|
||||
Error("No bytes read from scaled image". $scaled_path );
|
||||
}
|
||||
} else {
|
||||
Debug( "Cached scaled image does not exist at $scaled_path. Creating it");
|
||||
if ( ! file_exists( $scaled_path ) or ! readfile( $scaled_path ) ) {
|
||||
Debug( "Cached scaled image does not exist at $scaled_path or is no good.. Creating it");
|
||||
ob_start();
|
||||
if ( ! $i )
|
||||
$i = imagecreatefromjpeg( $path );
|
||||
|
@ -188,4 +189,3 @@ if ( $errorText ) {
|
|||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -85,6 +85,10 @@ header("Content-Range: bytes $begin-$end/$size");
|
|||
header("Content-Transfer-Encoding: binary\n");
|
||||
header('Connection: close');
|
||||
|
||||
// Apparently without these we get a few extra bytes of output at the end...
|
||||
ob_clean();
|
||||
flush();
|
||||
|
||||
$cur = $begin;
|
||||
fseek( $fh, $begin, 0 );
|
||||
|
||||
|
@ -94,5 +98,3 @@ while( ! feof( $fh ) && $cur < $end && ( connection_status() == 0 ) ) {
|
|||
$cur += 1024*16;
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
Loading…
Reference in New Issue