change how frame data is stored to be more useful, pass frame time offset to getFrame to tell ffmpeg which frame to get

This commit is contained in:
Isaac Connor 2018-09-11 13:20:41 -04:00
parent b545528bb0
commit ec6317bd66
2 changed files with 53 additions and 20 deletions

View File

@ -109,7 +109,10 @@ bool EventStream::loadInitialEventData( uint64_t init_event_id, unsigned int ini
bool EventStream::loadEventData(uint64_t event_id) { bool EventStream::loadEventData(uint64_t event_id) {
static char sql[ZM_SQL_MED_BUFSIZ]; static char sql[ZM_SQL_MED_BUFSIZ];
snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames, unix_timestamp( StartTime ) AS StartTimestamp, (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme FROM Events WHERE Id = %" PRIu64, event_id); snprintf(sql, sizeof(sql), "SELECT MonitorId, StorageId, Frames,"
" unix_timestamp( StartTime ) AS StartTimestamp,"
" (SELECT max(Delta)-min(Delta) FROM Frames WHERE EventId=Events.Id) AS Duration, DefaultVideo, Scheme"
" FROM Events WHERE Id = %" PRIu64, event_id);
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn)); Error("Can't run query: %s", mysql_error(&dbconn));
@ -161,18 +164,25 @@ bool EventStream::loadEventData(uint64_t event_id) {
if ( storage_path[0] == '/' ) if ( storage_path[0] == '/' )
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d",
storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); storage_path, event_data->monitor_id,
event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday,
event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
else else
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d",
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec ); staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday,
event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
} else if ( event_data->scheme == Storage::MEDIUM ) { } else if ( event_data->scheme == Storage::MEDIUM ) {
struct tm *event_time = localtime( &event_data->start_time ); struct tm *event_time = localtime( &event_data->start_time );
if ( storage_path[0] == '/' ) if ( storage_path[0] == '/' )
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%" PRIu64, snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%04d-%02d-%02d/%" PRIu64,
storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id ); storage_path, event_data->monitor_id,
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
event_data->event_id );
else else
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%" PRIu64, snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%04d-%02d-%02d/%" PRIu64,
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
event_data->event_id ); event_data->event_id );
} else { } else {
@ -186,8 +196,9 @@ bool EventStream::loadEventData(uint64_t event_id) {
delete storage; storage = NULL; delete storage; storage = NULL;
updateFrameRate( (double)event_data->frame_count/event_data->duration ); updateFrameRate( (double)event_data->frame_count/event_data->duration );
Debug(3,"fps set by frame_count(%d)/duration(%f)", event_data->frame_count, event_data->duration);
snprintf(sql, sizeof(sql), "SELECT FrameId, unix_timestamp( `TimeStamp` ), Delta FROM Frames where EventId = %" PRIu64 " ORDER BY FrameId ASC", event_id); snprintf(sql, sizeof(sql), "SELECT FrameId, unix_timestamp(`TimeStamp`), Delta FROM Frames WHERE EventId = %" PRIu64 " ORDER BY FrameId ASC", event_id);
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn)); Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn)); exit(mysql_errno(&dbconn));
@ -203,29 +214,46 @@ bool EventStream::loadEventData(uint64_t event_id) {
event_data->frames = new FrameData[event_data->frame_count]; event_data->frames = new FrameData[event_data->frame_count];
int last_id = 0; int last_id = 0;
time_t timestamp, last_timestamp = event_data->start_time; double last_timestamp = event_data->start_time;
double last_delta = 0.0; double last_delta = 0.0;
while ( ( dbrow = mysql_fetch_row( result ) ) ) { while ( ( dbrow = mysql_fetch_row( result ) ) ) {
int id = atoi(dbrow[0]); int id = atoi(dbrow[0]);
timestamp = atoi(dbrow[1]); //timestamp = atof(dbrow[1]);
double delta = atof(dbrow[2]); double delta = atof(dbrow[2]);
int id_diff = id - last_id; int id_diff = id - last_id;
double frame_delta = id_diff ? (delta-last_delta)/id_diff : 0; double frame_delta = id_diff ? (delta-last_delta)/id_diff : (delta - last_delta);
// Fill in data between bulk frames
if ( id_diff > 1 ) { if ( id_diff > 1 ) {
for ( int i = last_id+1; i < id; i++ ) { for ( int i = last_id+1; i < id; i++ ) {
event_data->frames[i-1].timestamp = (time_t)(last_timestamp + ((i-last_id)*frame_delta)); // Delta is the time since last frame, no since beginning of Event
event_data->frames[i-1].offset = (time_t)(event_data->frames[i-1].timestamp-event_data->start_time);
event_data->frames[i-1].delta = frame_delta; event_data->frames[i-1].delta = frame_delta;
event_data->frames[i-1].timestamp = last_timestamp + ((i-last_id)*frame_delta);
event_data->frames[i-1].offset = event_data->frames[i-1].timestamp - event_data->start_time;
event_data->frames[i-1].in_db = false; event_data->frames[i-1].in_db = false;
Debug(4,"Frame %d timestamp:(%f), offset(%f) delta(%f), in_db(%d)",
i,
event_data->frames[i-1].timestamp,
event_data->frames[i-1].offset,
event_data->frames[i-1].delta,
event_data->frames[i-1].in_db
);
} }
} }
event_data->frames[id-1].timestamp = timestamp; event_data->frames[id-1].timestamp = event_data->start_time + delta;
event_data->frames[id-1].offset = (time_t)(event_data->frames[id-1].timestamp-event_data->start_time); event_data->frames[id-1].offset = delta;
event_data->frames[id-1].delta = id>1?frame_delta:0.0; event_data->frames[id-1].delta = frame_delta;
event_data->frames[id-1].in_db = true; event_data->frames[id-1].in_db = true;
last_id = id; last_id = id;
last_delta = delta; last_delta = delta;
last_timestamp = timestamp; last_timestamp = event_data->frames[id-1].timestamp;
Debug(4,"Frame %d timestamp:(%f), offset(%f) delta(%f), in_db(%d)",
id,
event_data->frames[id-1].timestamp,
event_data->frames[id-1].offset,
event_data->frames[id-1].delta,
event_data->frames[id-1].in_db
);
} }
if ( mysql_errno( &dbconn ) ) { if ( mysql_errno( &dbconn ) ) {
Error( "Can't fetch row: %s", mysql_error( &dbconn ) ); Error( "Can't fetch row: %s", mysql_error( &dbconn ) );
@ -636,7 +664,8 @@ Debug(1, "Loading image");
} else if ( ffmpeg_input ) { } else if ( ffmpeg_input ) {
// Get the frame from the mp4 input // Get the frame from the mp4 input
Debug(1,"Getting frame from ffmpeg"); Debug(1,"Getting frame from ffmpeg");
AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id() ); FrameData *frame_data = &event_data->frames[curr_frame_id-1];
AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id(), frame_data->offset );
if ( frame ) { if ( frame ) {
image = new Image(frame); image = new Image(frame);
av_frame_free(&frame); av_frame_free(&frame);
@ -797,12 +826,16 @@ void EventStream::runStream() {
} }
// Figure out if we should send this frame // Figure out if we should send this frame
Debug(3,"cur_frame_id (%d-1) mod frame_mod(%d)",curr_frame_id, frame_mod);
// If we are streaming and this frame is due to be sent // If we are streaming and this frame is due to be sent
if ( ((curr_frame_id-1)%frame_mod) == 0 ) { // frame mod defaults to 1 and if we are going faster than max_fps will get multiplied by 2
// so if it is 2, then we send every other frame, if is it 4 then every fourth frame, etc.
if ( (frame_mod == 1) || (((curr_frame_id-1)%frame_mod) == 0) ) {
delta_us = (unsigned int)(frame_data->delta * 1000000); delta_us = (unsigned int)(frame_data->delta * 1000000);
Debug(3,"frame delta %u ", delta_us);
// if effective > base we should speed up frame delivery // if effective > base we should speed up frame delivery
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps); delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
Debug(3,"delta %u = base_fps(%f)/effective fps(%f)", delta_us, base_fps, effective_fps);
// but must not exceed maxfps // but must not exceed maxfps
delta_us = max(delta_us, 1000000 / maxfps); delta_us = max(delta_us, 1000000 / maxfps);
send_frame = true; send_frame = true;

View File

@ -47,8 +47,8 @@ class EventStream : public StreamBase {
protected: protected:
struct FrameData { struct FrameData {
//unsigned long id; //unsigned long id;
time_t timestamp; double timestamp;
time_t offset; double offset;
double delta; double delta;
bool in_db; bool in_db;
}; };