Merge branch 'storageareas' of github.com:ConnorTechnology/ZoneMinder into storageareas
This commit is contained in:
commit
de63aa8e8d
|
@ -271,7 +271,7 @@ MAIN: while( $loop ) {
|
|||
} # end foreach event
|
||||
chdir( $Storage->Path() );
|
||||
} # if USE_DEEP_STORAGE
|
||||
Debug( 'Got '.int(keys(%$fs_events))." events for monitor $monitor_dir\n" );
|
||||
Debug( 'Got '.int(keys(%$fs_events))." filesystem events for monitor $monitor_dir\n" );
|
||||
|
||||
#delete_empty_directories( $monitor_dir );
|
||||
} # end foreach monitor
|
||||
|
@ -351,7 +351,7 @@ MAIN: while( $loop ) {
|
|||
if ( ! defined( $fs_events->{$db_event} ) ) {
|
||||
Debug("Event $db_event is not in fs.");
|
||||
my $Event = ZoneMinder::Event->find_one( Id=>$db_event );
|
||||
if ( $Event ) {
|
||||
if ( ! $Event ) {
|
||||
Debug("Event $db_event is no longer in db. Filter probably deleted it while we were auditing.");
|
||||
next;
|
||||
}
|
||||
|
|
|
@ -143,11 +143,11 @@ while( 1 ) {
|
|||
if ( !defined($image_time) ) {
|
||||
# Can't read from shared data
|
||||
$restart = 1;
|
||||
Error( "Error reading shared data for $$monitor{id} $$monitor{Name}\n");
|
||||
Error( "Error reading shared data for $$monitor{Id} $$monitor{Name}\n");
|
||||
} elsif ( !$image_time ) {
|
||||
# We can't get the last capture time so can't be sure it's died.
|
||||
$restart = 1;
|
||||
Error( "Error getting last capture time for $$monitor{id} $$monitor{Name}\n");
|
||||
Error( "Error getting last capture time for $$monitor{Id} $$monitor{Name}\n");
|
||||
} else {
|
||||
|
||||
my $max_image_delay = ( $monitor->{MaxFPS}
|
||||
|
@ -159,7 +159,7 @@ while( 1 ) {
|
|||
my $image_delay = $now-$image_time;
|
||||
Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" );
|
||||
if ( $image_delay > $max_image_delay ) {
|
||||
Info( "Analysis daemon for $$monitor{id} $$monitor{Name} needs restarting,"
|
||||
Info( "Analysis daemon for $$monitor{Id} $$monitor{Name} needs restarting,"
|
||||
." time since last analysis $image_delay seconds ($now-$image_time)\n"
|
||||
);
|
||||
$restart = 1;
|
||||
|
@ -167,7 +167,7 @@ while( 1 ) {
|
|||
}
|
||||
|
||||
if ( $restart ) {
|
||||
Info( "Restarting analysis daemon for $$monitor{id} $$monitor{Name}\n");
|
||||
Info( "Restarting analysis daemon for $$monitor{Id} $$monitor{Name}\n");
|
||||
my $command = "zmdc.pl restart zma -m ".$monitor->{Id};
|
||||
runCommand( $command );
|
||||
} # end if restart
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY)
|
||||
|
||||
# Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc)
|
||||
set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp)
|
||||
set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_input.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_swscale.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp zm_storage.cpp)
|
||||
|
||||
# A fix for cmake recompiling the source files for every target.
|
||||
add_library(zm STATIC ${ZM_BIN_SRC_FILES})
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
class Zone;
|
||||
class Monitor;
|
||||
class EventStream;
|
||||
|
||||
#define MAX_PRE_ALARM_FRAMES 16 // Maximum number of prealarm frames that can be stored
|
||||
|
||||
|
@ -191,81 +192,4 @@ class Event {
|
|||
}
|
||||
};
|
||||
|
||||
class EventStream : public StreamBase {
|
||||
public:
|
||||
typedef enum { MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
|
||||
|
||||
protected:
|
||||
struct FrameData {
|
||||
//unsigned long id;
|
||||
time_t timestamp;
|
||||
time_t offset;
|
||||
double delta;
|
||||
bool in_db;
|
||||
};
|
||||
|
||||
struct EventData {
|
||||
unsigned long event_id;
|
||||
unsigned long monitor_id;
|
||||
unsigned long storage_id;
|
||||
unsigned long frame_count;
|
||||
time_t start_time;
|
||||
double duration;
|
||||
char path[PATH_MAX];
|
||||
int n_frames;
|
||||
FrameData *frames;
|
||||
char video_file[PATH_MAX];
|
||||
};
|
||||
|
||||
protected:
|
||||
static const int STREAM_PAUSE_WAIT = 250000; // Microseconds
|
||||
|
||||
static const StreamMode DEFAULT_MODE = MODE_SINGLE;
|
||||
|
||||
protected:
|
||||
StreamMode mode;
|
||||
bool forceEventChange;
|
||||
|
||||
protected:
|
||||
int curr_frame_id;
|
||||
double curr_stream_time;
|
||||
bool send_frame; // Used as a flag whether or not to send out a frame.
|
||||
|
||||
EventData *event_data;
|
||||
|
||||
protected:
|
||||
bool loadEventData( int event_id );
|
||||
bool loadInitialEventData( int init_event_id, unsigned int init_frame_id );
|
||||
bool loadInitialEventData( int monitor_id, time_t event_time );
|
||||
|
||||
void checkEventLoaded();
|
||||
void processCommand( const CmdMsg *msg );
|
||||
bool sendFrame( int delta_us );
|
||||
|
||||
public:
|
||||
EventStream() {
|
||||
mode = DEFAULT_MODE;
|
||||
|
||||
forceEventChange = false;
|
||||
|
||||
curr_frame_id = 0;
|
||||
curr_stream_time = 0.0;
|
||||
|
||||
event_data = 0;
|
||||
}
|
||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
|
||||
loadInitialEventData( init_event_id, init_frame_id );
|
||||
loadMonitor( event_data->monitor_id );
|
||||
}
|
||||
void setStreamStart( int monitor_id, time_t event_time ) {
|
||||
loadInitialEventData( monitor_id, event_time );
|
||||
loadMonitor( monitor_id );
|
||||
}
|
||||
void setStreamMode( StreamMode p_mode ) {
|
||||
mode = p_mode;
|
||||
}
|
||||
void runStream();
|
||||
Image *getImage();
|
||||
};
|
||||
|
||||
#endif // ZM_EVENT_H
|
||||
|
|
|
@ -34,12 +34,11 @@
|
|||
#include "zm_mpeg.h"
|
||||
#include "zm_signal.h"
|
||||
#include "zm_event.h"
|
||||
#include "zm_eventstream.h"
|
||||
#include "zm_storage.h"
|
||||
#include "zm_monitor.h"
|
||||
|
||||
// sendfile tricks
|
||||
extern "C" {
|
||||
#include "zm_sendfile.h"
|
||||
}
|
||||
|
||||
bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) {
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
|
@ -138,6 +137,7 @@ bool EventStream::loadEventData( int event_id ) {
|
|||
event_data->start_time = atoi(dbrow[3]);
|
||||
event_data->duration = atof(dbrow[4]);
|
||||
strncpy( event_data->video_file, dbrow[5], sizeof( event_data->video_file )-1 );
|
||||
mysql_free_result( result );
|
||||
|
||||
Storage * storage = new Storage( event_data->storage_id );
|
||||
const char *storage_path = storage->Path();
|
||||
|
@ -160,7 +160,6 @@ bool EventStream::loadEventData( int event_id ) {
|
|||
|
||||
updateFrameRate( (double)event_data->frame_count/event_data->duration );
|
||||
|
||||
mysql_free_result( result );
|
||||
|
||||
snprintf( sql, sizeof(sql), "select FrameId, unix_timestamp( `TimeStamp` ), Delta from Frames where EventId = %d order by FrameId asc", event_id );
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
|
@ -207,12 +206,23 @@ bool EventStream::loadEventData( int event_id ) {
|
|||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
|
||||
mysql_free_result( result );
|
||||
//for ( int i = 0; i < 250; i++ )
|
||||
//{
|
||||
//Info( "%d -> %d @ %f (%d)", i+1, event_data->frames[i].timestamp, event_data->frames[i].delta, event_data->frames[i].in_db );
|
||||
//}
|
||||
|
||||
mysql_free_result( result );
|
||||
if ( event_data->video_file[0] ) {
|
||||
char filepath[PATH_MAX];
|
||||
snprintf( filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file );
|
||||
ffmpeg_input = new FFmpeg_Input();
|
||||
if ( 0 > ffmpeg_input->Open( filepath ) ) {
|
||||
Warning("Unable to open ffmpeg_input %s/%s", event_data->path, event_data->video_file );
|
||||
delete ffmpeg_input;
|
||||
ffmpeg_input = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( forceEventChange || mode == MODE_ALL_GAPLESS ) {
|
||||
if ( replay_rate > 0 )
|
||||
|
@ -223,7 +233,7 @@ bool EventStream::loadEventData( int event_id ) {
|
|||
Debug( 2, "Event:%ld, Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration );
|
||||
|
||||
return( true );
|
||||
}
|
||||
} // bool EventStream::loadEventData( int event_id )
|
||||
|
||||
void EventStream::processCommand( const CmdMsg *msg ) {
|
||||
Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] );
|
||||
|
@ -590,11 +600,12 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
} else if ( monitor->GetOptSaveJPEGs() & 2 ) {
|
||||
snprintf( filepath, sizeof(filepath), Event::analyse_file_format, event_data->path, curr_frame_id );
|
||||
if ( stat( filepath, &filestat ) < 0 ) {
|
||||
Debug(1, "%s not found, dalling back to capture");
|
||||
Debug(1, "analyze file %s not found will try to stream from other", filepath);
|
||||
snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id );
|
||||
filepath[0] = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if ( ! ffmpeg_input ) {
|
||||
Fatal("JPEGS not saved.zms is not capable of streaming jpegs from mp4 yet");
|
||||
return false;
|
||||
}
|
||||
|
@ -619,7 +630,7 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
int img_buffer_size = 0;
|
||||
uint8_t *img_buffer = temp_img_buffer;
|
||||
|
||||
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE));
|
||||
bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0];
|
||||
|
||||
fprintf( stdout, "--ZoneMinderFrame\r\n" );
|
||||
|
||||
|
@ -641,9 +652,27 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj );
|
||||
#endif
|
||||
} else {
|
||||
Image image( filepath );
|
||||
Image *image = NULL;
|
||||
|
||||
Image *send_image = prepareImage( &image );
|
||||
if ( filepath[0] ) {
|
||||
image = new Image( filepath );
|
||||
} else if ( ffmpeg_input ) {
|
||||
// Get the frame from the mp4 input
|
||||
Debug(1,"Getting frame from ffmpeg");
|
||||
AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id() );
|
||||
if ( frame ) {
|
||||
image = new Image( frame );
|
||||
av_frame_free(&frame);
|
||||
} else {
|
||||
Error("Failed getting a frame.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Error("Unable to get a frame");
|
||||
return false;
|
||||
}
|
||||
|
||||
Image *send_image = prepareImage( image );
|
||||
|
||||
switch( type ) {
|
||||
case STREAM_JPEG :
|
||||
|
@ -667,6 +696,8 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
Fatal( "Unexpected frame type %d", type );
|
||||
break;
|
||||
}
|
||||
delete image;
|
||||
image = NULL;
|
||||
}
|
||||
|
||||
switch( type ) {
|
||||
|
@ -705,6 +736,7 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
#endif
|
||||
fclose(fdj); /* Close the file handle */
|
||||
} else {
|
||||
Debug(3, "Content length: %d", img_buffer_size );
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size );
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) {
|
||||
Error( "Unable to send stream frame: %s", strerror(errno) );
|
||||
|
@ -721,11 +753,14 @@ bool EventStream::sendFrame( int delta_us ) {
|
|||
|
||||
void EventStream::runStream() {
|
||||
Event::Initialise();
|
||||
Debug(3, "Initialized");
|
||||
|
||||
openComms();
|
||||
Debug(3, "Comms open");
|
||||
|
||||
checkInitialised();
|
||||
|
||||
Debug(3, "frame rate is: (%f)", (double)event_data->frame_count/event_data->duration );
|
||||
updateFrameRate( (double)event_data->frame_count/event_data->duration );
|
||||
|
||||
if ( type == STREAM_JPEG )
|
||||
|
@ -748,6 +783,7 @@ void EventStream::runStream() {
|
|||
if ( step != 0 )
|
||||
curr_frame_id += step;
|
||||
|
||||
// Detects when we hit end of event and will load the next event or previous event
|
||||
checkEventLoaded();
|
||||
|
||||
// Get current frame data
|
||||
|
|
|
@ -26,6 +26,17 @@
|
|||
#include "zm_image.h"
|
||||
#include "zm_stream.h"
|
||||
#include "zm_video.h"
|
||||
#include "zm_ffmpeg_input.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavformat/avio.h"
|
||||
#include "libavcodec/avcodec.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class EventStream : public StreamBase {
|
||||
public:
|
||||
|
@ -43,6 +54,7 @@ protected:
|
|||
struct EventData {
|
||||
unsigned long event_id;
|
||||
unsigned long monitor_id;
|
||||
unsigned long storage_id;
|
||||
unsigned long frame_count;
|
||||
time_t start_time;
|
||||
double duration;
|
||||
|
@ -57,14 +69,15 @@ protected:
|
|||
|
||||
static const StreamMode DEFAULT_MODE = MODE_SINGLE;
|
||||
|
||||
protected:
|
||||
StreamMode mode;
|
||||
bool forceEventChange;
|
||||
|
||||
int curr_frame_id;
|
||||
double curr_stream_time;
|
||||
bool send_frame;
|
||||
|
||||
EventData *event_data;
|
||||
FFmpeg_Input *ffmpeg_input;
|
||||
|
||||
protected:
|
||||
bool loadEventData( int event_id );
|
||||
|
@ -85,6 +98,13 @@ public:
|
|||
curr_stream_time = 0.0;
|
||||
|
||||
event_data = 0;
|
||||
|
||||
// Used when loading frames from an mp4
|
||||
input_codec_context = 0;
|
||||
input_codec = 0;
|
||||
|
||||
ffmpeg_input = NULL;
|
||||
|
||||
}
|
||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
|
||||
loadInitialEventData( init_event_id, init_frame_id );
|
||||
|
@ -99,6 +119,9 @@ public:
|
|||
}
|
||||
void runStream();
|
||||
Image *getImage();
|
||||
private:
|
||||
AVCodecContext *input_codec_context;
|
||||
AVCodec *input_codec;
|
||||
};
|
||||
|
||||
#endif // ZM_EVENTSTREAM_H
|
||||
|
|
|
@ -130,181 +130,6 @@ int av_dict_parse_string(AVDictionary **pm, const char *str,
|
|||
#endif
|
||||
#endif // HAVE_LIBAVUTIL
|
||||
|
||||
#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), output_avframe(NULL) {
|
||||
Debug(4,"SWScale object created");
|
||||
|
||||
/* Allocate AVFrame for the input */
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
input_avframe = av_frame_alloc();
|
||||
#else
|
||||
input_avframe = avcodec_alloc_frame();
|
||||
#endif
|
||||
if(input_avframe == NULL) {
|
||||
Fatal("Failed allocating AVFrame for the input");
|
||||
}
|
||||
|
||||
/* Allocate AVFrame for the output */
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
output_avframe = av_frame_alloc();
|
||||
#else
|
||||
output_avframe = avcodec_alloc_frame();
|
||||
#endif
|
||||
if(output_avframe == NULL) {
|
||||
Fatal("Failed allocating AVFrame for the output");
|
||||
}
|
||||
}
|
||||
|
||||
SWScale::~SWScale() {
|
||||
|
||||
/* Free up everything */
|
||||
av_frame_free( &input_avframe );
|
||||
//input_avframe = NULL;
|
||||
|
||||
av_frame_free( &output_avframe );
|
||||
//output_avframe = NULL;
|
||||
|
||||
if(swscale_ctx) {
|
||||
sws_freeContext(swscale_ctx);
|
||||
swscale_ctx = NULL;
|
||||
}
|
||||
|
||||
Debug(4,"SWScale object destroyed");
|
||||
}
|
||||
|
||||
int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
|
||||
/* Assign the defaults */
|
||||
default_input_pf = in_pf;
|
||||
default_output_pf = out_pf;
|
||||
default_width = width;
|
||||
default_height = height;
|
||||
|
||||
gotdefaults = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
/* Parameter checking */
|
||||
if(in_buffer == NULL || out_buffer == NULL) {
|
||||
Error("NULL Input or output buffer");
|
||||
return -1;
|
||||
}
|
||||
// if(in_pf == 0 || out_pf == 0) {
|
||||
// Error("Invalid input or output pixel formats");
|
||||
// return -2;
|
||||
// }
|
||||
if (!width || !height) {
|
||||
Error("Invalid width or height");
|
||||
return -3;
|
||||
}
|
||||
|
||||
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
|
||||
/* Warn if the input or output pixelformat is not supported */
|
||||
if(!sws_isSupportedInput(in_pf)) {
|
||||
Warning("swscale does not support the input format: %c%c%c%c",(in_pf)&0xff,((in_pf)&0xff),((in_pf>>16)&0xff),((in_pf>>24)&0xff));
|
||||
}
|
||||
if(!sws_isSupportedOutput(out_pf)) {
|
||||
Warning("swscale does not support the output format: %c%c%c%c",(out_pf)&0xff,((out_pf>>8)&0xff),((out_pf>>16)&0xff),((out_pf>>24)&0xff));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check the buffer sizes */
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
size_t insize = av_image_get_buffer_size(in_pf, width, height,1);
|
||||
#else
|
||||
size_t insize = avpicture_get_size(in_pf, width, height);
|
||||
#endif
|
||||
if(insize != in_buffer_size) {
|
||||
Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size);
|
||||
return -4;
|
||||
}
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
size_t outsize = av_image_get_buffer_size(out_pf, width, height,1);
|
||||
#else
|
||||
size_t outsize = avpicture_get_size(out_pf, width, height);
|
||||
#endif
|
||||
|
||||
if(outsize < out_buffer_size) {
|
||||
Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size);
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Get the context */
|
||||
swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL );
|
||||
if(swscale_ctx == NULL) {
|
||||
Error("Failed getting swscale context");
|
||||
return -6;
|
||||
}
|
||||
|
||||
/* Fill in the buffers */
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize,
|
||||
(uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) {
|
||||
#else
|
||||
if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer,
|
||||
in_pf, width, height) <= 0) {
|
||||
#endif
|
||||
Error("Failed filling input frame with input buffer");
|
||||
return -7;
|
||||
}
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
|
||||
out_buffer, out_pf, width, height, 1) <= 0) {
|
||||
#else
|
||||
if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, width,
|
||||
height) <= 0) {
|
||||
#endif
|
||||
Error("Failed filling output frame with output buffer");
|
||||
return -8;
|
||||
}
|
||||
|
||||
/* Do the conversion */
|
||||
if(!sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, 0, height, output_avframe->data, output_avframe->linesize ) ) {
|
||||
Error("swscale conversion failed");
|
||||
return -10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
if(img->Width() != width) {
|
||||
Error("Source image width differs. Source: %d Output: %d",img->Width(), width);
|
||||
return -12;
|
||||
}
|
||||
|
||||
if(img->Height() != height) {
|
||||
Error("Source image height differs. Source: %d Output: %d",img->Height(), height);
|
||||
return -13;
|
||||
}
|
||||
|
||||
return Convert(img->Buffer(),img->Size(),out_buffer,out_buffer_size,in_pf,out_pf,width,height);
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(img,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(in_buffer,in_buffer_size,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
}
|
||||
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
|
||||
|
||||
#endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE
|
||||
|
||||
#if HAVE_LIBAVUTIL
|
||||
|
@ -530,3 +355,33 @@ unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src ) {
|
|||
}
|
||||
#endif
|
||||
|
||||
bool is_video_stream( AVStream * stream ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
if ( stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
||||
#else
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( stream->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
||||
#else
|
||||
if ( stream->codec->codec_type == CODEC_TYPE_VIDEO ) {
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_audio_stream( AVStream * stream ) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
if ( stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO ) {
|
||||
#else
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( stream->codec->codec_type == AVMEDIA_TYPE_AUDIO ) {
|
||||
#else
|
||||
if ( stream->codec->codec_type == CODEC_TYPE_AUDIO ) {
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,11 +21,8 @@
|
|||
#define ZM_FFMPEG_H
|
||||
#include <stdint.h>
|
||||
#include "zm.h"
|
||||
#include "zm_image.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// AVUTIL
|
||||
#if HAVE_LIBAVUTIL_AVUTIL_H
|
||||
|
@ -207,31 +204,6 @@ void FFMPEGInit();
|
|||
enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder);
|
||||
#endif // HAVE_LIBAVUTIL
|
||||
|
||||
|
||||
/* SWScale wrapper class to make our life easier and reduce code reuse */
|
||||
#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
class SWScale {
|
||||
public:
|
||||
SWScale();
|
||||
~SWScale();
|
||||
int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
|
||||
protected:
|
||||
bool gotdefaults;
|
||||
struct SwsContext* swscale_ctx;
|
||||
AVFrame* input_avframe;
|
||||
AVFrame* output_avframe;
|
||||
enum _AVPIXELFORMAT default_input_pf;
|
||||
enum _AVPIXELFORMAT default_output_pf;
|
||||
unsigned int default_width;
|
||||
unsigned int default_height;
|
||||
};
|
||||
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
|
||||
#if !LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100)
|
||||
#define AV_CODEC_ID_NONE CODEC_ID_NONE
|
||||
#define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW
|
||||
|
@ -353,4 +325,6 @@ unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src );
|
|||
|
||||
int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
|
||||
|
||||
bool is_video_stream( AVStream * stream );
|
||||
bool is_audio_stream( AVStream * stream );
|
||||
#endif // ZM_FFMPEG_H
|
||||
|
|
|
@ -304,17 +304,6 @@ int FfmpegCamera::Capture( Image &image ) {
|
|||
#endif
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
if ( mConvertContext == NULL ) {
|
||||
mConvertContext = sws_getContext(mVideoCodecContext->width,
|
||||
mVideoCodecContext->height,
|
||||
mVideoCodecContext->pix_fmt,
|
||||
width, height, imagePixFormat,
|
||||
SWS_BICUBIC, NULL, NULL, NULL);
|
||||
|
||||
if ( mConvertContext == NULL )
|
||||
Fatal( "Unable to create conversion context for %s", mPath.c_str() );
|
||||
}
|
||||
|
||||
if ( sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0 )
|
||||
Fatal("Unable to convert raw format %u to target format %u at frame %d", mVideoCodecContext->pix_fmt, imagePixFormat, frameCount);
|
||||
#else // HAVE_LIBSWSCALE
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
|
||||
#include "zm_ffmpeg_input.h"
|
||||
#include "zm_logger.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
|
||||
FFmpeg_Input::FFmpeg_Input() {
|
||||
input_format_context = NULL;
|
||||
video_stream_id = -1;
|
||||
audio_stream_id = -1;
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
|
||||
}
|
||||
FFmpeg_Input::~FFmpeg_Input() {
|
||||
}
|
||||
|
||||
int FFmpeg_Input::Open( const char *filepath ) {
|
||||
|
||||
int error;
|
||||
|
||||
/** Open the input file to read from it. */
|
||||
if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) {
|
||||
|
||||
Error("Could not open input file '%s' (error '%s')\n",
|
||||
filepath, av_make_error_string(error).c_str() );
|
||||
input_format_context = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
/** Get information on the input file (number of streams etc.). */
|
||||
if ( (error = avformat_find_stream_info(input_format_context, NULL)) < 0 ) {
|
||||
Error( "Could not open find stream info (error '%s')\n",
|
||||
av_make_error_string(error).c_str() );
|
||||
avformat_close_input(&input_format_context);
|
||||
return error;
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
|
||||
if ( is_video_stream( input_format_context->streams[i] ) ) {
|
||||
zm_dump_stream_format(input_format_context, i, 0, 0);
|
||||
if ( video_stream_id == -1 ) {
|
||||
video_stream_id = i;
|
||||
// if we break, then we won't find the audio stream
|
||||
} else {
|
||||
Warning( "Have another video stream." );
|
||||
}
|
||||
} else if ( is_audio_stream( input_format_context->streams[i] ) ) {
|
||||
if ( audio_stream_id == -1 ) {
|
||||
audio_stream_id = i;
|
||||
} else {
|
||||
Warning( "Have another audio stream." );
|
||||
}
|
||||
}
|
||||
|
||||
streams[i].frame_count = 0;
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
streams[i].context = avcodec_alloc_context3( NULL );
|
||||
avcodec_parameters_to_context( streams[i].context, input_format_context->streams[i]->codecpar );
|
||||
#else
|
||||
streams[i].context = input_format_context->streams[i]->codec;
|
||||
#endif
|
||||
|
||||
if ( !(streams[i].codec = avcodec_find_decoder(streams[i].context->codec_id)) ) {
|
||||
Error( "Could not find input codec\n");
|
||||
avformat_close_input(&input_format_context);
|
||||
return AVERROR_EXIT;
|
||||
} else {
|
||||
Debug(1, "Using codec (%s) for stream %d", streams[i].codec->name, i );
|
||||
}
|
||||
|
||||
if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) {
|
||||
Error( "Could not open input codec (error '%s')\n",
|
||||
av_make_error_string(error).c_str() );
|
||||
avcodec_free_context( &streams[i].context );
|
||||
avformat_close_input(&input_format_context);
|
||||
return error;
|
||||
}
|
||||
} // end foreach stream
|
||||
|
||||
if ( video_stream_id == -1 )
|
||||
Error( "Unable to locate video stream in %s", filepath );
|
||||
if ( audio_stream_id == -1 )
|
||||
Debug( 3, "Unable to locate audio stream in %s", filepath );
|
||||
|
||||
return 0;
|
||||
} // end int FFmpeg_Input::Open( const char * filepath )
|
||||
|
||||
AVFrame *FFmpeg_Input::get_frame( int stream_id ) {
|
||||
Debug(1, "Getting frame from stream %d", stream_id );
|
||||
|
||||
int frameComplete = false;
|
||||
AVPacket packet;
|
||||
av_init_packet( &packet );
|
||||
AVFrame *frame = zm_av_frame_alloc();
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
|
||||
while ( !frameComplete ) {
|
||||
int ret = av_read_frame( input_format_context, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
if (
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
Info( "av_read_frame returned %s.", errbuf );
|
||||
return NULL;
|
||||
}
|
||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) {
|
||||
Debug(1,"Packet is for our stream (%d)", packet.stream_index );
|
||||
|
||||
AVCodecContext *context = streams[packet.stream_index].context;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
ret = avcodec_send_packet( context, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
} else {
|
||||
Debug(1, "Success getting a packet");
|
||||
}
|
||||
|
||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||
if ( hwaccel ) {
|
||||
ret = avcodec_receive_frame( context, hwFrame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
|
||||
if (ret < 0) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
Debug(1,"Getting a frame?");
|
||||
ret = avcodec_receive_frame( context, frame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
|
||||
#if HAVE_AVUTIL_HWCONTEXT_H
|
||||
}
|
||||
#endif
|
||||
|
||||
frameComplete = 1;
|
||||
# else
|
||||
ret = zm_avcodec_decode_video( streams[packet.stream_index].context, frame, &frameComplete, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
} // end if it's the right stream
|
||||
|
||||
zm_av_packet_unref( &packet );
|
||||
|
||||
} // end while ! frameComplete
|
||||
return frame;
|
||||
|
||||
} // end AVFrame *FFmpeg_Input::get_frame
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef ZM_FFMPEG_INPUT_H
|
||||
#define ZM_FFMPEG_INPUT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavformat/avio.h"
|
||||
#include "libavcodec/avcodec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class FFmpeg_Input {
|
||||
|
||||
public:
|
||||
FFmpeg_Input();
|
||||
~FFmpeg_Input();
|
||||
|
||||
int Open( const char *filename );
|
||||
int Close();
|
||||
AVFrame *get_frame( int stream_id=-1 );
|
||||
int get_video_stream_id() {
|
||||
return video_stream_id;
|
||||
}
|
||||
int get_audio_stream_id() {
|
||||
return audio_stream_id;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
AVCodecContext *context;
|
||||
AVCodec *codec;
|
||||
int frame_count;
|
||||
} stream;
|
||||
|
||||
stream streams[2];
|
||||
int video_stream_id;
|
||||
int audio_stream_id;
|
||||
AVFormatContext *input_format_context;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -22,6 +22,7 @@
|
|||
#include "zm_image.h"
|
||||
#include "zm_utils.h"
|
||||
#include "zm_rgb.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
@ -128,6 +129,46 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin
|
|||
text[0] = '\0';
|
||||
}
|
||||
|
||||
Image::Image( const AVFrame *frame ) {
|
||||
AVFrame *dest_frame = zm_av_frame_alloc();
|
||||
|
||||
width = frame->width;
|
||||
height = frame->height;
|
||||
pixels = width*height;
|
||||
colours = ZM_COLOUR_RGB32;
|
||||
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
|
||||
size = pixels*colours;
|
||||
buffer = 0;
|
||||
holdbuffer = 0;
|
||||
AllocImgBuffer(size);
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
av_image_fill_arrays(dest_frame->data, dest_frame->linesize,
|
||||
buffer, AV_PIX_FMT_RGBA, width, height, 1);
|
||||
#else
|
||||
avpicture_fill( (AVPicture *)mFrame, buffer,
|
||||
AV_PIX_FMT_RGBA, width, height);
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
struct SwsContext *mConvertContext = sws_getContext(
|
||||
width,
|
||||
height,
|
||||
(AVPixelFormat)frame->format,
|
||||
width, height,
|
||||
AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL,
|
||||
NULL, NULL);
|
||||
if ( mConvertContext == NULL )
|
||||
Fatal( "Unable to create conversion context" );
|
||||
|
||||
if ( sws_scale(mConvertContext, frame->data, frame->linesize, 0, frame->height, dest_frame->data, dest_frame->linesize) < 0 )
|
||||
Fatal("Unable to convert raw format %u to target format %u", frame->format, AV_PIX_FMT_RGBA);
|
||||
#else // HAVE_LIBSWSCALE
|
||||
Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras");
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
av_frame_free( &dest_frame );
|
||||
}
|
||||
|
||||
Image::Image( const Image &p_image ) {
|
||||
if ( !initialised )
|
||||
Initialise();
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
#define ZM_IMAGE_H
|
||||
|
||||
#include "zm.h"
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#include "zm_jpeg.h"
|
||||
}
|
||||
#include "zm_rgb.h"
|
||||
|
@ -32,6 +31,9 @@ extern "C"
|
|||
#include "zm_mem_utils.h"
|
||||
#include "zm_utils.h"
|
||||
|
||||
class Image;
|
||||
#include "zm_ffmpeg.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if HAVE_ZLIB_H
|
||||
|
@ -148,12 +150,12 @@ protected:
|
|||
int holdbuffer; /* Hold the buffer instead of replacing it with new one */
|
||||
char text[1024];
|
||||
|
||||
|
||||
public:
|
||||
Image();
|
||||
Image( const char *filename );
|
||||
Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0);
|
||||
Image( const Image &p_image );
|
||||
Image( const AVFrame *frame );
|
||||
~Image();
|
||||
static void Initialise();
|
||||
static void Deinitialise();
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "zm_signal.h"
|
||||
#include "zm_monitor.h"
|
||||
#include "zm_video.h"
|
||||
#include "zm_eventstream.h"
|
||||
#if ZM_HAS_V4L
|
||||
#include "zm_local_camera.h"
|
||||
#endif // ZM_HAS_V4L
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "zm_packet.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ZMPacket::ZMPacket( AVPacket *p ) {
|
||||
|
|
|
@ -19,12 +19,11 @@
|
|||
|
||||
#include "zm_packetqueue.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
#include <sys/time.h>
|
||||
|
||||
#define VIDEO_QUEUESIZE 200
|
||||
#define AUDIO_QUEUESIZE 50
|
||||
|
||||
using namespace std;
|
||||
|
||||
zm_packetqueue::zm_packetqueue(){
|
||||
|
||||
}
|
||||
|
@ -68,7 +67,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream
|
|||
return 0;
|
||||
}
|
||||
|
||||
list<ZMPacket *>::reverse_iterator it;
|
||||
std::list<ZMPacket *>::reverse_iterator it;
|
||||
ZMPacket *packet = NULL;
|
||||
|
||||
for ( it = pktQueue.rbegin(); it != pktQueue.rend() && frames_to_keep; ++it ) {
|
||||
|
@ -121,7 +120,7 @@ void zm_packetqueue::clear_unwanted_packets( timeval *recording_started, int mVi
|
|||
|
||||
// Step 1 - find keyframe < recording_started.
|
||||
// Step 2 - pop packets until we get to the packet in step 2
|
||||
list<ZMPacket *>::reverse_iterator it;
|
||||
std::list<ZMPacket *>::reverse_iterator it;
|
||||
|
||||
Debug(3, "Looking for keyframe after start recording stream id (%d)", mVideoStreamId );
|
||||
for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) {
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
#ifndef ZM_SENDFILE_H
|
||||
#define ZM_SENDFILE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SENDFILE4_SUPPORT
|
||||
#include <sys/sendfile.h>
|
||||
int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) {
|
||||
|
@ -29,3 +36,9 @@ int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) {
|
|||
#else
|
||||
#error "Your platform does not support sendfile. Sorry."
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* ZoneMinder FFMPEG implementation, $Date$, $Revision$
|
||||
* Copyright (C) 2001-2008 Philip Coombes
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "zm_ffmpeg.h"
|
||||
#include "zm_image.h"
|
||||
#include "zm_rgb.h"
|
||||
|
||||
#include "zm_swscale.h"
|
||||
|
||||
#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), output_avframe(NULL) {
|
||||
Debug(4,"SWScale object created");
|
||||
|
||||
/* Allocate AVFrame for the input */
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
input_avframe = av_frame_alloc();
|
||||
#else
|
||||
input_avframe = avcodec_alloc_frame();
|
||||
#endif
|
||||
if(input_avframe == NULL) {
|
||||
Fatal("Failed allocating AVFrame for the input");
|
||||
}
|
||||
|
||||
/* Allocate AVFrame for the output */
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
output_avframe = av_frame_alloc();
|
||||
#else
|
||||
output_avframe = avcodec_alloc_frame();
|
||||
#endif
|
||||
if(output_avframe == NULL) {
|
||||
Fatal("Failed allocating AVFrame for the output");
|
||||
}
|
||||
}
|
||||
|
||||
SWScale::~SWScale() {
|
||||
|
||||
/* Free up everything */
|
||||
av_frame_free( &input_avframe );
|
||||
//input_avframe = NULL;
|
||||
|
||||
av_frame_free( &output_avframe );
|
||||
//output_avframe = NULL;
|
||||
|
||||
if(swscale_ctx) {
|
||||
sws_freeContext(swscale_ctx);
|
||||
swscale_ctx = NULL;
|
||||
}
|
||||
|
||||
Debug(4,"SWScale object destroyed");
|
||||
}
|
||||
|
||||
int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
|
||||
/* Assign the defaults */
|
||||
default_input_pf = in_pf;
|
||||
default_output_pf = out_pf;
|
||||
default_width = width;
|
||||
default_height = height;
|
||||
|
||||
gotdefaults = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
/* Parameter checking */
|
||||
if(in_buffer == NULL || out_buffer == NULL) {
|
||||
Error("NULL Input or output buffer");
|
||||
return -1;
|
||||
}
|
||||
// if(in_pf == 0 || out_pf == 0) {
|
||||
// Error("Invalid input or output pixel formats");
|
||||
// return -2;
|
||||
// }
|
||||
if (!width || !height) {
|
||||
Error("Invalid width or height");
|
||||
return -3;
|
||||
}
|
||||
|
||||
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
|
||||
/* Warn if the input or output pixelformat is not supported */
|
||||
if(!sws_isSupportedInput(in_pf)) {
|
||||
Warning("swscale does not support the input format: %c%c%c%c",(in_pf)&0xff,((in_pf)&0xff),((in_pf>>16)&0xff),((in_pf>>24)&0xff));
|
||||
}
|
||||
if(!sws_isSupportedOutput(out_pf)) {
|
||||
Warning("swscale does not support the output format: %c%c%c%c",(out_pf)&0xff,((out_pf>>8)&0xff),((out_pf>>16)&0xff),((out_pf>>24)&0xff));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check the buffer sizes */
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
size_t insize = av_image_get_buffer_size(in_pf, width, height,1);
|
||||
#else
|
||||
size_t insize = avpicture_get_size(in_pf, width, height);
|
||||
#endif
|
||||
if(insize != in_buffer_size) {
|
||||
Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size);
|
||||
return -4;
|
||||
}
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
size_t outsize = av_image_get_buffer_size(out_pf, width, height,1);
|
||||
#else
|
||||
size_t outsize = avpicture_get_size(out_pf, width, height);
|
||||
#endif
|
||||
|
||||
if(outsize < out_buffer_size) {
|
||||
Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size);
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Get the context */
|
||||
swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL );
|
||||
if(swscale_ctx == NULL) {
|
||||
Error("Failed getting swscale context");
|
||||
return -6;
|
||||
}
|
||||
|
||||
/* Fill in the buffers */
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize,
|
||||
(uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) {
|
||||
#else
|
||||
if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer,
|
||||
in_pf, width, height) <= 0) {
|
||||
#endif
|
||||
Error("Failed filling input frame with input buffer");
|
||||
return -7;
|
||||
}
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
|
||||
out_buffer, out_pf, width, height, 1) <= 0) {
|
||||
#else
|
||||
if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, width,
|
||||
height) <= 0) {
|
||||
#endif
|
||||
Error("Failed filling output frame with output buffer");
|
||||
return -8;
|
||||
}
|
||||
|
||||
/* Do the conversion */
|
||||
if(!sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, 0, height, output_avframe->data, output_avframe->linesize ) ) {
|
||||
Error("swscale conversion failed");
|
||||
return -10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
if(img->Width() != width) {
|
||||
Error("Source image width differs. Source: %d Output: %d",img->Width(), width);
|
||||
return -12;
|
||||
}
|
||||
|
||||
if(img->Height() != height) {
|
||||
Error("Source image height differs. Source: %d Output: %d",img->Height(), height);
|
||||
return -13;
|
||||
}
|
||||
|
||||
return Convert(img->Buffer(),img->Size(),out_buffer,out_buffer_size,in_pf,out_pf,width,height);
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(img,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(in_buffer,in_buffer_size,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
}
|
||||
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef ZM_SWSCALE_H
|
||||
#define ZM_SWSCALE_H
|
||||
|
||||
#include "zm_image.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
|
||||
/* SWScale wrapper class to make our life easier and reduce code reuse */
|
||||
#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
class SWScale {
|
||||
public:
|
||||
SWScale();
|
||||
~SWScale();
|
||||
int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
|
||||
protected:
|
||||
bool gotdefaults;
|
||||
struct SwsContext* swscale_ctx;
|
||||
AVFrame* input_avframe;
|
||||
AVFrame* output_avframe;
|
||||
enum _AVPIXELFORMAT default_input_pf;
|
||||
enum _AVPIXELFORMAT default_output_pf;
|
||||
unsigned int default_width;
|
||||
unsigned int default_height;
|
||||
};
|
||||
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
|
||||
#endif
|
|
@ -21,6 +21,7 @@
|
|||
#include "zm_utils.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
#include "zm_buffer.h"
|
||||
#include "zm_swscale.h"
|
||||
|
||||
/*
|
||||
#define HAVE_LIBX264 1
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,35 +18,35 @@ class VideoStore {
|
|||
private:
|
||||
unsigned int packets_written;
|
||||
|
||||
AVOutputFormat *output_format;
|
||||
AVOutputFormat *out_format;
|
||||
AVFormatContext *oc;
|
||||
AVStream *video_output_stream;
|
||||
AVStream *audio_output_stream;
|
||||
AVCodecContext *video_output_context;
|
||||
AVStream *video_out_stream;
|
||||
AVStream *audio_out_stream;
|
||||
AVCodecContext *video_out_ctx;
|
||||
|
||||
AVStream *video_input_stream;
|
||||
AVStream *audio_input_stream;
|
||||
AVStream *video_in_stream;
|
||||
AVStream *audio_in_stream;
|
||||
|
||||
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
|
||||
AVPacket opkt;
|
||||
// we are transcoding
|
||||
AVFrame *input_frame;
|
||||
AVFrame *output_frame;
|
||||
AVFrame *in_frame;
|
||||
AVFrame *out_frame;
|
||||
|
||||
AVCodecContext *video_input_context;
|
||||
AVCodecContext *audio_input_context;
|
||||
AVCodecContext *video_in_ctx;
|
||||
AVCodecContext *audio_in_ctx;
|
||||
int ret;
|
||||
|
||||
// The following are used when encoding the audio stream to AAC
|
||||
AVCodec *audio_output_codec;
|
||||
AVCodecContext *audio_output_context;
|
||||
AVCodec *audio_out_codec;
|
||||
AVCodecContext *audio_out_ctx;
|
||||
int data_present;
|
||||
AVAudioFifo *fifo;
|
||||
int output_frame_size;
|
||||
int out_frame_size;
|
||||
#ifdef HAVE_LIBAVRESAMPLE
|
||||
AVAudioResampleContext* resample_context;
|
||||
AVAudioResampleContext* resample_ctx;
|
||||
#endif
|
||||
uint8_t *converted_input_samples;
|
||||
uint8_t *converted_in_samples;
|
||||
|
||||
const char *filename;
|
||||
const char *format;
|
||||
|
@ -54,13 +54,13 @@ AVAudioResampleContext* resample_context;
|
|||
bool keyframeMessage;
|
||||
int keyframeSkipNumber;
|
||||
|
||||
// These are for input
|
||||
// These are for in
|
||||
int64_t video_last_pts;
|
||||
int64_t video_last_dts;
|
||||
int64_t audio_last_pts;
|
||||
int64_t audio_last_dts;
|
||||
|
||||
// These are for output, should start at zero. We assume they do not wrap because we just aren't going to save files that big.
|
||||
// These are for out, should start at zero. We assume they do not wrap because we just aren't going to save files that big.
|
||||
int64_t video_next_pts;
|
||||
int64_t video_next_dts;
|
||||
int64_t audio_next_pts;
|
||||
|
@ -71,7 +71,13 @@ AVAudioResampleContext* resample_context;
|
|||
bool setup_resampler();
|
||||
|
||||
public:
|
||||
VideoStore(const char *filename_in, const char *format_in, AVStream *video_input_stream, AVStream *audio_input_stream, int64_t nStartTime, Monitor * p_monitor );
|
||||
VideoStore(
|
||||
const char *filename_in,
|
||||
const char *format_in,
|
||||
AVStream *video_in_stream,
|
||||
AVStream *audio_in_stream,
|
||||
int64_t nStartTime,
|
||||
Monitor * p_monitor);
|
||||
~VideoStore();
|
||||
|
||||
int writeVideoFramePacket( AVPacket *pkt );
|
||||
|
|
11
src/zms.cpp
11
src/zms.cpp
|
@ -26,6 +26,7 @@
|
|||
#include "zm_signal.h"
|
||||
#include "zm_monitor.h"
|
||||
#include "zm_monitorstream.h"
|
||||
#include "zm_eventstream.h"
|
||||
|
||||
bool ValidateAccess( User *user, int mon_id ) {
|
||||
bool allowed = true;
|
||||
|
@ -51,7 +52,7 @@ int main( int argc, const char *argv[] ) {
|
|||
|
||||
srand( getpid() * time( 0 ) );
|
||||
|
||||
enum { ZMS_MONITOR, ZMS_EVENT } source = ZMS_MONITOR;
|
||||
enum { ZMS_UNKNOWN, ZMS_MONITOR, ZMS_EVENT } source = ZMS_UNKNOWN;
|
||||
enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_ZIP, ZMS_SINGLE } mode = ZMS_JPEG;
|
||||
char format[32] = "";
|
||||
int monitor_id = 0;
|
||||
|
@ -120,12 +121,16 @@ int main( int argc, const char *argv[] ) {
|
|||
strncpy( format, value, sizeof(format) );
|
||||
} else if ( !strcmp( name, "monitor" ) ) {
|
||||
monitor_id = atoi( value );
|
||||
if ( source == ZMS_UNKNOWN )
|
||||
source = ZMS_MONITOR;
|
||||
} else if ( !strcmp( name, "time" ) ) {
|
||||
event_time = atoi( value );
|
||||
} else if ( !strcmp( name, "event" ) ) {
|
||||
event_id = strtoull( value, (char **)NULL, 10 );
|
||||
source = ZMS_EVENT;
|
||||
} else if ( !strcmp( name, "frame" ) ) {
|
||||
frame_id = strtoull( value, (char **)NULL, 10 );
|
||||
source = ZMS_EVENT;
|
||||
} else if ( !strcmp( name, "scale" ) ) {
|
||||
scale = atoi( value );
|
||||
} else if ( !strcmp( name, "rate" ) ) {
|
||||
|
@ -263,6 +268,7 @@ int main( int argc, const char *argv[] ) {
|
|||
if ( ! event_id ) {
|
||||
Fatal( "Can't view an event without specifying an event_id." );
|
||||
}
|
||||
Debug(3,"Doing event stream scale(%d)", scale );
|
||||
EventStream stream;
|
||||
stream.setStreamScale( scale );
|
||||
stream.setStreamReplayRate( rate );
|
||||
|
@ -272,6 +278,7 @@ int main( int argc, const char *argv[] ) {
|
|||
if ( monitor_id && event_time ) {
|
||||
stream.setStreamStart( monitor_id, event_time );
|
||||
} else {
|
||||
Debug(3, "Setting stream start to frame (%d)", frame_id);
|
||||
stream.setStreamStart( event_id, frame_id );
|
||||
}
|
||||
if ( mode == ZMS_JPEG ) {
|
||||
|
@ -290,6 +297,8 @@ int main( int argc, const char *argv[] ) {
|
|||
#endif // HAVE_LIBAVCODEC
|
||||
} // end if jpeg or mpeg
|
||||
stream.runStream();
|
||||
} else {
|
||||
Error("Neither a monitor or event was specified.");
|
||||
} // end if monitor or event
|
||||
|
||||
logTerm();
|
||||
|
|
|
@ -131,7 +131,7 @@ class Event {
|
|||
} # end Event->delete
|
||||
|
||||
public function getStreamSrc( $args=array(), $querySep='&' ) {
|
||||
if ( $this->{'DefaultVideo'} ) {
|
||||
if ( $this->{'DefaultVideo'} and $args['mode'] != 'jpeg' ) {
|
||||
return ( ZM_BASE_PATH != '/' ? ZM_BASE_PATH : '' ).'/index.php?view=view_video&eid='.$this->{'Id'};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue