mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-03-17 21:38:45 -04:00
Merge branch 'storageareas' into ffmpeg_output
This commit is contained in:
@@ -128,10 +128,10 @@ int cURLCamera::Capture( Image &image ) {
|
||||
/* Grab the mutex to ensure exclusive access to the shared data */
|
||||
lock();
|
||||
|
||||
while (!frameComplete) {
|
||||
while ( !frameComplete ) {
|
||||
|
||||
/* If the work thread did a reset, reset our local variables */
|
||||
if(bReset) {
|
||||
if ( bReset ) {
|
||||
SubHeadersParsingComplete = false;
|
||||
frame_content_length = 0;
|
||||
frame_content_type.clear();
|
||||
@@ -139,25 +139,25 @@ int cURLCamera::Capture( Image &image ) {
|
||||
bReset = false;
|
||||
}
|
||||
|
||||
if(mode == MODE_UNSET) {
|
||||
if ( mode == MODE_UNSET ) {
|
||||
/* Don't have a mode yet. Sleep while waiting for data */
|
||||
nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex);
|
||||
if(nRet != 0) {
|
||||
if ( nRet != 0 ) {
|
||||
Error("Failed waiting for available data condition variable: %s",strerror(nRet));
|
||||
return -20;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == MODE_STREAM) {
|
||||
if ( mode == MODE_STREAM ) {
|
||||
|
||||
/* Subheader parsing */
|
||||
while(!SubHeadersParsingComplete && !need_more_data) {
|
||||
while( !SubHeadersParsingComplete && !need_more_data ) {
|
||||
|
||||
size_t crlf_start, crlf_end, crlf_size;
|
||||
std::string subheader;
|
||||
|
||||
/* Check if the buffer contains something */
|
||||
if(databuffer.empty()) {
|
||||
if ( databuffer.empty() ) {
|
||||
/* Empty buffer, wait for data */
|
||||
need_more_data = true;
|
||||
break;
|
||||
@@ -165,14 +165,14 @@ int cURLCamera::Capture( Image &image ) {
|
||||
|
||||
/* Find crlf start */
|
||||
crlf_start = memcspn(databuffer,"\r\n",databuffer.size());
|
||||
if(crlf_start == databuffer.size()) {
|
||||
if ( crlf_start == databuffer.size() ) {
|
||||
/* Not found, wait for more data */
|
||||
need_more_data = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* See if we have enough data for determining crlf length */
|
||||
if(databuffer.size() < crlf_start+5) {
|
||||
if ( databuffer.size() < crlf_start+5 ) {
|
||||
/* Need more data */
|
||||
need_more_data = true;
|
||||
break;
|
||||
@@ -183,13 +183,13 @@ int cURLCamera::Capture( Image &image ) {
|
||||
crlf_size = (crlf_start + crlf_end) - crlf_start;
|
||||
|
||||
/* Is this the end of a previous stream? (This is just before the boundary) */
|
||||
if(crlf_start == 0) {
|
||||
if ( crlf_start == 0 ) {
|
||||
databuffer.consume(crlf_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for invalid CRLF size */
|
||||
if(crlf_size > 4) {
|
||||
if ( crlf_size > 4 ) {
|
||||
Error("Invalid CRLF length");
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ int cURLCamera::Capture( Image &image ) {
|
||||
|
||||
/* Find where the data in this header starts */
|
||||
size_t subheader_data_start = subheader.rfind(' ');
|
||||
if(subheader_data_start == std::string::npos) {
|
||||
if ( subheader_data_start == std::string::npos ) {
|
||||
subheader_data_start = subheader.find(':');
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "zm_stream.h"
|
||||
#include "zm_video.h"
|
||||
#include "zm_ffmpeg_input.h"
|
||||
#include "zm_monitor.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -108,11 +109,17 @@ class EventStream : public StreamBase {
|
||||
}
|
||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
|
||||
loadInitialEventData( init_event_id, init_frame_id );
|
||||
loadMonitor( event_data->monitor_id );
|
||||
if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
|
||||
Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id );
|
||||
return;
|
||||
}
|
||||
}
|
||||
void setStreamStart( int monitor_id, time_t event_time ) {
|
||||
loadInitialEventData( monitor_id, event_time );
|
||||
loadMonitor( monitor_id );
|
||||
if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) {
|
||||
Fatal( "Unable to load monitor id %d for streaming", monitor_id );
|
||||
return;
|
||||
}
|
||||
}
|
||||
void setStreamMode( StreamMode p_mode ) {
|
||||
mode = p_mode;
|
||||
|
||||
@@ -317,7 +317,7 @@ int FfmpegCamera::Capture( Image &image ) {
|
||||
} // end if packet.stream_index == mVideoStreamId
|
||||
zm_av_packet_unref( &packet );
|
||||
} // end while ! frameComplete
|
||||
return (0);
|
||||
return 1;
|
||||
} // FfmpegCamera::Capture
|
||||
|
||||
int FfmpegCamera::PostCapture() {
|
||||
@@ -495,7 +495,16 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
#ifdef AV_CODEC_ID_H265
|
||||
if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) {
|
||||
Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." );
|
||||
} else {
|
||||
#endif
|
||||
Error( "Input stream is not h264. The stored event file may not be viewable in browser." );
|
||||
#ifdef AV_CODEC_ID_H265
|
||||
}
|
||||
#endif
|
||||
} // end if h264
|
||||
#endif
|
||||
|
||||
@@ -752,6 +761,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
||||
while ( ! frameComplete ) {
|
||||
av_init_packet( &packet );
|
||||
|
||||
Debug(4,"before read frame");
|
||||
ret = av_read_frame( mFormatContext, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
@@ -961,11 +971,11 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
|
||||
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
||||
Warning( "Unable to receive frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||
}
|
||||
#endif
|
||||
@@ -981,8 +991,6 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
Debug( 4, "Decoded video packet at frame %d", frameCount );
|
||||
|
||||
if ( frameComplete ) {
|
||||
Debug( 4, "Got frame %d", frameCount );
|
||||
|
||||
@@ -1013,6 +1021,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
|
||||
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
|
||||
frameComplete = 1;
|
||||
if ( videoStore ) {
|
||||
if ( record_audio ) {
|
||||
if ( have_video_keyframe ) {
|
||||
@@ -1034,6 +1043,8 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
|
||||
} else {
|
||||
Debug(4, "Have audio packet, but not recording atm" );
|
||||
}
|
||||
zm_av_packet_unref( &packet );
|
||||
return 0;
|
||||
} else {
|
||||
#if LIBAVUTIL_VERSION_CHECK(56, 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]->codecpar->codec_type) );
|
||||
@@ -1045,7 +1056,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) {
|
||||
// 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_packet_unref( &packet );
|
||||
} // end while ! frameComplete
|
||||
return (frameCount);
|
||||
return frameCount;
|
||||
} // end FfmpegCamera::CaptureAndRecord
|
||||
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
#if HAVE_LIBVLC
|
||||
|
||||
// Do all the buffer checking work here to avoid unnecessary locking
|
||||
void* LibvlcLockBuffer(void* opaque, void** planes)
|
||||
{
|
||||
void* LibvlcLockBuffer(void* opaque, void** planes) {
|
||||
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
||||
data->mutex.lock();
|
||||
|
||||
@@ -36,15 +35,12 @@ void* LibvlcLockBuffer(void* opaque, void** planes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes)
|
||||
{
|
||||
void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
|
||||
LibvlcPrivateData* data = (LibvlcPrivateData*)opaque;
|
||||
|
||||
bool newFrame = false;
|
||||
for(uint32_t i = 0; i < data->bufferSize; i++)
|
||||
{
|
||||
if(data->buffer[i] != data->prevBuffer[i])
|
||||
{
|
||||
for( uint32_t i = 0; i < data->bufferSize; i++ ) {
|
||||
if ( data->buffer[i] != data->prevBuffer[i] ) {
|
||||
newFrame = true;
|
||||
break;
|
||||
}
|
||||
@@ -54,8 +50,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes)
|
||||
time_t now;
|
||||
time(&now);
|
||||
// Return frames slightly faster than 1fps (if time() supports greater than one second resolution)
|
||||
if(newFrame || difftime(now, data->prevTime) >= 0.8)
|
||||
{
|
||||
if ( newFrame || difftime(now, data->prevTime) >= 0.8 ) {
|
||||
data->prevTime = now;
|
||||
data->newImage.updateValueSignal(true);
|
||||
}
|
||||
@@ -90,58 +85,46 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri
|
||||
Panic("Unexpected colours: %d",colours);
|
||||
}
|
||||
|
||||
if ( capture )
|
||||
{
|
||||
if ( capture ) {
|
||||
Initialise();
|
||||
}
|
||||
}
|
||||
|
||||
LibvlcCamera::~LibvlcCamera()
|
||||
{
|
||||
if ( capture )
|
||||
{
|
||||
LibvlcCamera::~LibvlcCamera() {
|
||||
if ( capture ) {
|
||||
Terminate();
|
||||
}
|
||||
if(mLibvlcMediaPlayer != NULL)
|
||||
{
|
||||
if ( mLibvlcMediaPlayer != NULL ) {
|
||||
libvlc_media_player_release(mLibvlcMediaPlayer);
|
||||
mLibvlcMediaPlayer = NULL;
|
||||
}
|
||||
if(mLibvlcMedia != NULL)
|
||||
{
|
||||
if ( mLibvlcMedia != NULL ) {
|
||||
libvlc_media_release(mLibvlcMedia);
|
||||
mLibvlcMedia = NULL;
|
||||
}
|
||||
if(mLibvlcInstance != NULL)
|
||||
{
|
||||
if ( mLibvlcInstance != NULL ) {
|
||||
libvlc_release(mLibvlcInstance);
|
||||
mLibvlcInstance = NULL;
|
||||
}
|
||||
if (mOptArgV != NULL)
|
||||
{
|
||||
if ( mOptArgV != NULL ) {
|
||||
delete[] mOptArgV;
|
||||
}
|
||||
}
|
||||
|
||||
void LibvlcCamera::Initialise()
|
||||
{
|
||||
void LibvlcCamera::Initialise() {
|
||||
}
|
||||
|
||||
void LibvlcCamera::Terminate()
|
||||
{
|
||||
void LibvlcCamera::Terminate() {
|
||||
libvlc_media_player_stop(mLibvlcMediaPlayer);
|
||||
if(mLibvlcData.buffer != NULL)
|
||||
{
|
||||
if(mLibvlcData.buffer != NULL) {
|
||||
zm_freealigned(mLibvlcData.buffer);
|
||||
}
|
||||
if(mLibvlcData.prevBuffer != NULL)
|
||||
{
|
||||
if(mLibvlcData.prevBuffer != NULL) {
|
||||
zm_freealigned(mLibvlcData.prevBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
int LibvlcCamera::PrimeCapture()
|
||||
{
|
||||
int LibvlcCamera::PrimeCapture() {
|
||||
Info("Priming capture from %s", mPath.c_str());
|
||||
|
||||
StringVector opVect = split(Options(), ",");
|
||||
@@ -154,8 +137,7 @@ int LibvlcCamera::PrimeCapture()
|
||||
else if ( Method() == "rtpRtspHttp" )
|
||||
opVect.push_back("--rtsp-http");
|
||||
|
||||
if (opVect.size() > 0)
|
||||
{
|
||||
if ( opVect.size() > 0 ) {
|
||||
mOptArgV = new char*[opVect.size()];
|
||||
Debug(2, "Number of Options: %d",opVect.size());
|
||||
for (size_t i=0; i< opVect.size(); i++) {
|
||||
@@ -166,7 +148,7 @@ int LibvlcCamera::PrimeCapture()
|
||||
}
|
||||
|
||||
mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV);
|
||||
if(mLibvlcInstance == NULL)
|
||||
if ( mLibvlcInstance == NULL )
|
||||
Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg());
|
||||
|
||||
mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str());
|
||||
@@ -189,17 +171,15 @@ int LibvlcCamera::PrimeCapture()
|
||||
|
||||
libvlc_media_player_play(mLibvlcMediaPlayer);
|
||||
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LibvlcCamera::PreCapture()
|
||||
{
|
||||
int LibvlcCamera::PreCapture() {
|
||||
return(0);
|
||||
}
|
||||
|
||||
// Should not return -1 as cancels capture. Always wait for image if available.
|
||||
int LibvlcCamera::Capture( Image &image )
|
||||
{
|
||||
int LibvlcCamera::Capture( Image &image ) {
|
||||
while(!mLibvlcData.newImage.getValueImmediate())
|
||||
mLibvlcData.newImage.getUpdatedValue(1);
|
||||
|
||||
@@ -208,25 +188,15 @@ int LibvlcCamera::Capture( Image &image )
|
||||
mLibvlcData.newImage.setValueImmediate(false);
|
||||
mLibvlcData.mutex.unlock();
|
||||
|
||||
return (0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Should not return -1 as cancels capture. Always wait for image if available.
|
||||
int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory)
|
||||
{
|
||||
while(!mLibvlcData.newImage.getValueImmediate())
|
||||
mLibvlcData.newImage.getUpdatedValue(1);
|
||||
|
||||
mLibvlcData.mutex.lock();
|
||||
image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp);
|
||||
mLibvlcData.newImage.setValueImmediate(false);
|
||||
mLibvlcData.mutex.unlock();
|
||||
|
||||
int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
int LibvlcCamera::PostCapture()
|
||||
{
|
||||
int LibvlcCamera::PostCapture() {
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1995,17 +1995,14 @@ int LocalCamera::Contrast( int p_contrast )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
int LocalCamera::PrimeCapture()
|
||||
{
|
||||
int LocalCamera::PrimeCapture() {
|
||||
Initialise();
|
||||
|
||||
Debug( 2, "Priming capture" );
|
||||
#if ZM_HAS_V4L2
|
||||
if ( v4l_version == 2 )
|
||||
{
|
||||
if ( v4l_version == 2 ) {
|
||||
Debug( 3, "Queueing buffers" );
|
||||
for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ )
|
||||
{
|
||||
for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ ) {
|
||||
struct v4l2_buffer vid_buf;
|
||||
|
||||
memset( &vid_buf, 0, sizeof(vid_buf) );
|
||||
@@ -2028,13 +2025,10 @@ int LocalCamera::PrimeCapture()
|
||||
}
|
||||
#endif // ZM_HAS_V4L2
|
||||
#if ZM_HAS_V4L1
|
||||
if ( v4l_version == 1 )
|
||||
{
|
||||
for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ )
|
||||
{
|
||||
if ( v4l_version == 1 ) {
|
||||
for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ ) {
|
||||
Debug( 3, "Queueing frame %d", frame );
|
||||
if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 )
|
||||
{
|
||||
if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 ) {
|
||||
Error( "Capture failure for frame %d: %s", frame, strerror(errno) );
|
||||
return( -1 );
|
||||
}
|
||||
@@ -2045,14 +2039,12 @@ int LocalCamera::PrimeCapture()
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int LocalCamera::PreCapture()
|
||||
{
|
||||
Debug( 2, "Pre-capturing" );
|
||||
int LocalCamera::PreCapture() {
|
||||
Debug( 5, "Pre-capturing" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int LocalCamera::Capture( Image &image )
|
||||
{
|
||||
int LocalCamera::Capture( Image &image ) {
|
||||
Debug( 3, "Capturing" );
|
||||
static uint8_t* buffer = NULL;
|
||||
static uint8_t* directbuffer = NULL;
|
||||
@@ -2069,11 +2061,9 @@ int LocalCamera::Capture( Image &image )
|
||||
|
||||
|
||||
// Do the capture, unless we are the second or subsequent camera on a channel, in which case just reuse the buffer
|
||||
if ( channel_prime )
|
||||
{
|
||||
if ( channel_prime ) {
|
||||
#if ZM_HAS_V4L2
|
||||
if ( v4l_version == 2 )
|
||||
{
|
||||
if ( v4l_version == 2 ) {
|
||||
static struct v4l2_buffer vid_buf;
|
||||
|
||||
memset( &vid_buf, 0, sizeof(vid_buf) );
|
||||
@@ -2083,10 +2073,8 @@ int LocalCamera::Capture( Image &image )
|
||||
vid_buf.memory = v4l2_data.reqbufs.memory;
|
||||
|
||||
Debug( 3, "Capturing %d frames", captures_per_frame );
|
||||
while ( captures_per_frame )
|
||||
{
|
||||
if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 )
|
||||
{
|
||||
while ( captures_per_frame ) {
|
||||
if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) {
|
||||
if ( errno == EIO )
|
||||
Warning( "Capture failure, possible signal loss?: %s", strerror(errno) )
|
||||
else
|
||||
@@ -2096,15 +2084,13 @@ int LocalCamera::Capture( Image &image )
|
||||
|
||||
v4l2_data.bufptr = &vid_buf;
|
||||
capture_frame = v4l2_data.bufptr->index;
|
||||
if ( --captures_per_frame )
|
||||
{
|
||||
if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 )
|
||||
{
|
||||
if ( --captures_per_frame ) {
|
||||
if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) {
|
||||
Error( "Unable to requeue buffer %d: %s", vid_buf.index, strerror(errno) );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // while captures_per_frame
|
||||
|
||||
Debug( 3, "Captured frame %d/%d from channel %d", capture_frame, v4l2_data.bufptr->sequence, channel );
|
||||
|
||||
@@ -2115,23 +2101,19 @@ int LocalCamera::Capture( Image &image )
|
||||
Fatal("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",v4l2_data.fmt.fmt.pix.width,v4l2_data.fmt.fmt.pix.height,width,height);
|
||||
}
|
||||
|
||||
}
|
||||
} // end if v4l2
|
||||
#endif // ZM_HAS_V4L2
|
||||
#if ZM_HAS_V4L1
|
||||
if ( v4l_version == 1 )
|
||||
{
|
||||
if ( v4l_version == 1 ) {
|
||||
Debug( 3, "Capturing %d frames", captures_per_frame );
|
||||
while ( captures_per_frame )
|
||||
{
|
||||
while ( captures_per_frame ) {
|
||||
Debug( 3, "Syncing frame %d", v4l1_data.active_frame );
|
||||
if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 )
|
||||
{
|
||||
if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) {
|
||||
Error( "Sync failure for frame %d buffer %d: %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) );
|
||||
return( -1 );
|
||||
}
|
||||
captures_per_frame--;
|
||||
if ( captures_per_frame )
|
||||
{
|
||||
if ( captures_per_frame ) {
|
||||
Debug( 3, "Capturing frame %d", v4l1_data.active_frame );
|
||||
if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 )
|
||||
{
|
||||
@@ -2148,18 +2130,18 @@ int LocalCamera::Capture( Image &image )
|
||||
#endif // ZM_HAS_V4L1
|
||||
} /* prime capture */
|
||||
|
||||
if(conversion_type != 0) {
|
||||
if ( conversion_type != 0 ) {
|
||||
|
||||
Debug( 3, "Performing format conversion" );
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if(directbuffer == NULL) {
|
||||
if ( directbuffer == NULL ) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
#if HAVE_LIBSWSCALE
|
||||
if(conversion_type == 1) {
|
||||
if ( conversion_type == 1 ) {
|
||||
|
||||
Debug( 9, "Calling sws_scale to perform the conversion" );
|
||||
/* Use swscale to convert the image directly into the shared memory */
|
||||
@@ -2174,14 +2156,11 @@ int LocalCamera::Capture( Image &image )
|
||||
sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize );
|
||||
}
|
||||
#endif
|
||||
if(conversion_type == 2) {
|
||||
|
||||
if ( conversion_type == 2 ) {
|
||||
Debug( 9, "Calling the conversion function" );
|
||||
/* Call the image conversion function and convert directly into the shared memory */
|
||||
(*conversion_fptr)(buffer, directbuffer, pixels);
|
||||
}
|
||||
else if(conversion_type == 3) {
|
||||
|
||||
} else if ( conversion_type == 3 ) {
|
||||
Debug( 9, "Decoding the JPEG image" );
|
||||
/* JPEG decoding */
|
||||
image.DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder);
|
||||
@@ -2192,10 +2171,9 @@ int LocalCamera::Capture( Image &image )
|
||||
|
||||
/* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */
|
||||
image.Assign( width, height, colours, subpixelorder, buffer, imagesize);
|
||||
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LocalCamera::PostCapture()
|
||||
|
||||
@@ -1178,7 +1178,7 @@ bool Monitor::Analyse() {
|
||||
gettimeofday( &now, NULL );
|
||||
|
||||
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
||||
fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
|
||||
fps = double(fps_report_interval)/(now.tv_sec - last_fps_time);
|
||||
Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps );
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", fps, id );
|
||||
@@ -2889,33 +2889,27 @@ int Monitor::Capture() {
|
||||
|
||||
} else {
|
||||
//Check if FFMPEG camera
|
||||
if ( (videowriter == H264PASSTHROUGH ) && camera->SupportsNativeVideo() ) {
|
||||
if ( (videowriter == H264PASSTHROUGH) && camera->SupportsNativeVideo() ) {
|
||||
//Warning("ZMC: Recording: %d", video_store_data->recording);
|
||||
captureResult = camera->CaptureAndRecord(*capture_image, video_store_data->recording, video_store_data->event_file);
|
||||
}else{
|
||||
// Should return -1 on error, like loss of signal. Should return 0 if ok but no video frame. > 0 for received a frame.
|
||||
captureResult = camera->CaptureAndRecord(
|
||||
*capture_image,
|
||||
video_store_data->recording,
|
||||
video_store_data->event_file
|
||||
);
|
||||
} else {
|
||||
/* Capture directly into image buffer, avoiding the need to memcpy() */
|
||||
captureResult = camera->Capture(*capture_image);
|
||||
}
|
||||
}
|
||||
|
||||
// CaptureAndRecord returns # of frames captured I think
|
||||
if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) {
|
||||
//video_store_data->frameNumber = captureResult;
|
||||
captureResult = 0;
|
||||
}
|
||||
|
||||
if ( captureResult != 0 ) {
|
||||
Debug(4, "Return from Capture (%d)", captureResult);
|
||||
if ( captureResult < 0 ) {
|
||||
// Unable to capture image for temporary reason
|
||||
// Fake a signal loss image
|
||||
Rgb signalcolor;
|
||||
signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */
|
||||
capture_image->Fill(signalcolor);
|
||||
captureResult = 0;
|
||||
} else {
|
||||
captureResult = 1;
|
||||
}
|
||||
|
||||
if ( captureResult == 1 ) {
|
||||
} else if ( captureResult > 0 ) {
|
||||
|
||||
/* Deinterlacing */
|
||||
if ( deinterlacing_value == 1 ) {
|
||||
@@ -2969,49 +2963,58 @@ int Monitor::Capture() {
|
||||
if ( privacy_bitmask )
|
||||
capture_image->MaskPrivacy( privacy_bitmask );
|
||||
|
||||
// Might be able to remove this call, when we start passing around ZMPackets, which will already have a timestamp
|
||||
gettimeofday( image_buffer[index].timestamp, NULL );
|
||||
if ( config.timestamp_on_capture ) {
|
||||
TimestampImage( capture_image, image_buffer[index].timestamp );
|
||||
}
|
||||
// Maybe we don't need to do this on all camera types
|
||||
shared_data->signal = CheckSignal(capture_image);
|
||||
shared_data->last_write_index = index;
|
||||
shared_data->last_write_time = image_buffer[index].timestamp->tv_sec;
|
||||
|
||||
image_count++;
|
||||
} // end if captureResult
|
||||
|
||||
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
||||
time_t now = image_buffer[index].timestamp->tv_sec;
|
||||
fps = double(fps_report_interval)/(now-last_fps_time);
|
||||
//Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time );
|
||||
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
|
||||
|
||||
struct timeval now;
|
||||
if ( !captureResult ) {
|
||||
gettimeofday( &now, NULL );
|
||||
} else {
|
||||
now.tv_sec = image_buffer[index].timestamp->tv_sec;
|
||||
}
|
||||
// If we are too fast, we get div by zero. This seems to happen in the case of audio packets.
|
||||
if ( now.tv_sec != last_fps_time ) {
|
||||
fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
|
||||
Info( "%d -> %d -> %d", fps_report_interval, now.tv_sec, last_fps_time );
|
||||
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
|
||||
Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps );
|
||||
last_fps_time = now;
|
||||
last_fps_time = now.tv_sec;
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id );
|
||||
snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id );
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Icon: I'm not sure these should be here. They have nothing to do with capturing
|
||||
if ( shared_data->action & GET_SETTINGS ) {
|
||||
shared_data->brightness = camera->Brightness();
|
||||
shared_data->hue = camera->Hue();
|
||||
shared_data->colour = camera->Colour();
|
||||
shared_data->contrast = camera->Contrast();
|
||||
shared_data->action &= ~GET_SETTINGS;
|
||||
}
|
||||
if ( shared_data->action & SET_SETTINGS ) {
|
||||
camera->Brightness( shared_data->brightness );
|
||||
camera->Hue( shared_data->hue );
|
||||
camera->Colour( shared_data->colour );
|
||||
camera->Contrast( shared_data->contrast );
|
||||
shared_data->action &= ~SET_SETTINGS;
|
||||
}
|
||||
return( 0 );
|
||||
} // end if captureResults == 1 which is success I think
|
||||
shared_data->signal = false;
|
||||
return( -1 );
|
||||
// Icon: I'm not sure these should be here. They have nothing to do with capturing
|
||||
if ( shared_data->action & GET_SETTINGS ) {
|
||||
shared_data->brightness = camera->Brightness();
|
||||
shared_data->hue = camera->Hue();
|
||||
shared_data->colour = camera->Colour();
|
||||
shared_data->contrast = camera->Contrast();
|
||||
shared_data->action &= ~GET_SETTINGS;
|
||||
}
|
||||
if ( shared_data->action & SET_SETTINGS ) {
|
||||
camera->Brightness( shared_data->brightness );
|
||||
camera->Hue( shared_data->hue );
|
||||
camera->Colour( shared_data->colour );
|
||||
camera->Contrast( shared_data->contrast );
|
||||
shared_data->action &= ~SET_SETTINGS;
|
||||
}
|
||||
return captureResult;
|
||||
}
|
||||
|
||||
void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const {
|
||||
|
||||
@@ -270,7 +270,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
|
||||
Debug( 1, "Got SCALE command, to %d", scale );
|
||||
break;
|
||||
}
|
||||
case CMD_QUIT :
|
||||
case CMD_QUIT :
|
||||
{
|
||||
Info ("User initiated exit - CMD_QUIT");
|
||||
break;
|
||||
@@ -316,7 +316,7 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
|
||||
//status_data.enabled = monitor->shared_data->active;
|
||||
status_data.enabled = monitor->trigger_data->trigger_state!=Monitor::TRIGGER_OFF;
|
||||
status_data.forced = monitor->trigger_data->trigger_state==Monitor::TRIGGER_ON;
|
||||
Debug( 2, "L:%d, D:%d, P:%d, R:%d, d:%.3f, Z:%d, E:%d F:%d",
|
||||
Debug( 2, "Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d",
|
||||
status_data.buffer_level,
|
||||
status_data.delayed,
|
||||
status_data.paused,
|
||||
@@ -338,11 +338,15 @@ void MonitorStream::processCommand( const CmdMsg *msg ) {
|
||||
//exit( -1 );
|
||||
}
|
||||
}
|
||||
Debug(2, "NUmber of bytes sent: (%d)", nbytes );
|
||||
|
||||
// quit after sending a status, if this was a quit request
|
||||
if ((MsgCommand)msg->msg_data[0]==CMD_QUIT)
|
||||
exit(0);
|
||||
if ( (MsgCommand)msg->msg_data[0]==CMD_QUIT ) {
|
||||
Debug(2,"Quitting");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Debug(2,"Updating framrate");
|
||||
updateFrameRate( monitor->GetFPS() );
|
||||
} // end void MonitorStream::processCommand( const CmdMsg *msg )
|
||||
|
||||
@@ -553,20 +557,28 @@ void MonitorStream::runStream() {
|
||||
Debug( 2, "Assigned temporary buffer" );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end if connkey & playback_buffer
|
||||
|
||||
float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs)
|
||||
while ( !zm_terminate ) {
|
||||
bool got_command = false;
|
||||
if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) {
|
||||
if ( feof( stdout ) ) {
|
||||
Debug(2,"feof stdout");
|
||||
} else if ( ferror( stdout ) ) {
|
||||
Debug(2,"ferror stdout");
|
||||
} else if ( !monitor->ShmValid() ) {
|
||||
Debug(2,"monitor not valid.... maybe we should wait until it comes back.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
gettimeofday( &now, NULL );
|
||||
|
||||
if ( connkey ) {
|
||||
Debug(2, "checking command Queue");
|
||||
//Debug(2, "checking command Queue for connkey: %d", connkey );
|
||||
while(checkCommandQueue()) {
|
||||
Debug(2, "Have checking command Queue for connkey: %d", connkey );
|
||||
got_command = true;
|
||||
}
|
||||
}
|
||||
@@ -655,8 +667,10 @@ Debug(2, "checking command Queue");
|
||||
// Send the next frame
|
||||
Monitor::Snapshot *snap = &monitor->image_buffer[index];
|
||||
|
||||
if ( !sendFrame( snap->image, snap->timestamp ) )
|
||||
if ( !sendFrame( snap->image, snap->timestamp ) ) {
|
||||
Debug(2, "sendFrame failed, quiting.");
|
||||
zm_terminate = true;
|
||||
}
|
||||
memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) );
|
||||
//frame_sent = true;
|
||||
|
||||
@@ -693,9 +707,12 @@ Debug(2, "checking command Queue");
|
||||
} // end if buffered playback
|
||||
frame_count++;
|
||||
}
|
||||
unsigned long sleep_time = (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2)));
|
||||
Debug(2, "Sleeping for (%d)", sleep_time);
|
||||
usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) );
|
||||
if ( ttl ) {
|
||||
if ( (now.tv_sec - stream_start_time) > ttl ) {
|
||||
Debug(2, "now(%d) - start(%d) > ttl(%d) break", now.tv_sec, stream_start_time, ttl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1063,23 +1063,18 @@ int RemoteCameraHttp::GetResponse()
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int RemoteCameraHttp::PreCapture()
|
||||
{
|
||||
if ( sd < 0 )
|
||||
{
|
||||
int RemoteCameraHttp::PreCapture() {
|
||||
if ( sd < 0 ) {
|
||||
Connect();
|
||||
if ( sd < 0 )
|
||||
{
|
||||
if ( sd < 0 ) {
|
||||
Error( "Unable to connect to camera" );
|
||||
return( -1 );
|
||||
}
|
||||
mode = SINGLE_IMAGE;
|
||||
buffer.clear();
|
||||
}
|
||||
if ( mode == SINGLE_IMAGE )
|
||||
{
|
||||
if ( SendRequest() < 0 )
|
||||
{
|
||||
if ( mode == SINGLE_IMAGE ) {
|
||||
if ( SendRequest() < 0 ) {
|
||||
Error( "Unable to send request" );
|
||||
Disconnect();
|
||||
return( -1 );
|
||||
@@ -1088,50 +1083,43 @@ int RemoteCameraHttp::PreCapture()
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int RemoteCameraHttp::Capture( Image &image )
|
||||
{
|
||||
int RemoteCameraHttp::Capture( Image &image ) {
|
||||
int content_length = GetResponse();
|
||||
if ( content_length == 0 )
|
||||
{
|
||||
if ( content_length == 0 ) {
|
||||
Warning( "Unable to capture image, retrying" );
|
||||
return( 1 );
|
||||
return 0;
|
||||
}
|
||||
if ( content_length < 0 )
|
||||
{
|
||||
if ( content_length < 0 ) {
|
||||
Error( "Unable to get response, disconnecting" );
|
||||
Disconnect();
|
||||
return( -1 );
|
||||
return -1;
|
||||
}
|
||||
switch( format )
|
||||
{
|
||||
switch( format ) {
|
||||
case JPEG :
|
||||
{
|
||||
if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) )
|
||||
{
|
||||
if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) {
|
||||
Error( "Unable to decode jpeg" );
|
||||
Disconnect();
|
||||
return( -1 );
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case X_RGB :
|
||||
{
|
||||
if ( content_length != (long)image.Size() )
|
||||
{
|
||||
if ( content_length != (long)image.Size() ) {
|
||||
Error( "Image length mismatch, expected %d bytes, content length was %d", image.Size(), content_length );
|
||||
Disconnect();
|
||||
return( -1 );
|
||||
return -1;
|
||||
}
|
||||
image.Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
||||
break;
|
||||
}
|
||||
case X_RGBZ :
|
||||
{
|
||||
if ( !image.Unzip( buffer.extract( content_length ), content_length ) )
|
||||
{
|
||||
if ( !image.Unzip( buffer.extract( content_length ), content_length ) ) {
|
||||
Error( "Unable to unzip RGB image" );
|
||||
Disconnect();
|
||||
return( -1 );
|
||||
return -1;
|
||||
}
|
||||
image.Assign( width, height, colours, subpixelorder, buffer, imagesize );
|
||||
break;
|
||||
@@ -1140,13 +1128,12 @@ int RemoteCameraHttp::Capture( Image &image )
|
||||
{
|
||||
Error( "Unexpected image format encountered" );
|
||||
Disconnect();
|
||||
return( -1 );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return( 0 );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RemoteCameraHttp::PostCapture()
|
||||
{
|
||||
return( 0 );
|
||||
int RemoteCameraHttp::PostCapture() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -266,15 +266,15 @@ int RemoteCameraRtsp::Capture( Image &image ) {
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if(directbuffer == NULL) {
|
||||
if ( directbuffer == NULL ) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( true ) {
|
||||
buffer.clear();
|
||||
if ( !rtspThread->isRunning() )
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
if ( rtspThread->getFrame( buffer ) ) {
|
||||
Debug( 3, "Read frame %d bytes", buffer.size() );
|
||||
@@ -282,21 +282,21 @@ int RemoteCameraRtsp::Capture( Image &image ) {
|
||||
Hexdump( 4, buffer.head(), 16 );
|
||||
|
||||
if ( !buffer.size() )
|
||||
return( -1 );
|
||||
return -1;
|
||||
|
||||
if(mCodecContext->codec_id == AV_CODEC_ID_H264) {
|
||||
if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) {
|
||||
// SPS and PPS frames should be saved and appended to IDR frames
|
||||
int nalType = (buffer.head()[3] & 0x1f);
|
||||
|
||||
// SPS The SPS NAL unit contains parameters that apply to a series of consecutive coded video pictures
|
||||
if(nalType == 7) {
|
||||
if ( nalType == 7 ) {
|
||||
lastSps = buffer;
|
||||
continue;
|
||||
} else if(nalType == 8) {
|
||||
} else if ( nalType == 8 ) {
|
||||
// PPS The PPS NAL unit contains parameters that apply to the decoding of one or more individual pictures inside a coded video sequence
|
||||
lastPps = buffer;
|
||||
continue;
|
||||
} else if(nalType == 5) {
|
||||
} else if ( nalType == 5 ) {
|
||||
// IDR
|
||||
buffer += lastSps;
|
||||
buffer += lastPps;
|
||||
@@ -357,13 +357,13 @@ int RemoteCameraRtsp::Capture( Image &image ) {
|
||||
zm_av_packet_unref( &packet );
|
||||
} /* getFrame() */
|
||||
|
||||
if(frameComplete)
|
||||
return (0);
|
||||
if ( frameComplete )
|
||||
return 1;
|
||||
|
||||
} // end while true
|
||||
|
||||
// can never get here.
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Function to handle capture and store
|
||||
|
||||
@@ -311,7 +311,7 @@ void StreamBase::openComms() {
|
||||
strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) );
|
||||
rem_addr.sun_family = AF_UNIX;
|
||||
} // end if connKey > 0
|
||||
Debug(3, "comms open" );
|
||||
Debug(2, "comms open" );
|
||||
}
|
||||
|
||||
void StreamBase::closeComms() {
|
||||
|
||||
@@ -960,19 +960,19 @@ void VideoStore::write_video_packet( AVPacket &opkt ) {
|
||||
int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
||||
Debug(4, "writeAudioFrame");
|
||||
|
||||
if (!audio_out_stream) {
|
||||
if ( !audio_out_stream ) {
|
||||
Debug(1, "Called writeAudioFramePacket when no audio_out_stream");
|
||||
return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at
|
||||
// the moment
|
||||
}
|
||||
|
||||
if (audio_out_codec) {
|
||||
if ( audio_out_codec ) {
|
||||
Debug(3, "Have audio codec");
|
||||
#ifdef HAVE_LIBAVRESAMPLE
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
ret = avcodec_send_packet(audio_in_ctx, ipkt);
|
||||
if (ret < 0) {
|
||||
if ( ret < 0 ) {
|
||||
Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user