forked from edman007/chiton
-
Notifications
You must be signed in to change notification settings - Fork 0
/
camera.cpp
147 lines (126 loc) · 5 KB
/
camera.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**************************************************************************
*
* This file is part of Chiton.
*
* Chiton 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 3 of the License, or
* (at your option) any later version.
*
* Chiton 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 Chiton. If not, see <https://www.gnu.org/licenses/>.
*
* Copyright 2020 Ed Martin <[email protected]>
*
**************************************************************************
*/
#include "camera.hpp"
#include "util.hpp"
#include "stream_writer.hpp"
Camera::Camera(int camera, Database& db) : id(camera), db(db), stream(cfg), fm(db, cfg) {
//load the config
load_cfg();
shutdown = false;
alive = true;
watchdog = false;
startup = true;
}
Camera::~Camera(){
}
void Camera::load_cfg(void){
//loads the global and then overwrites it with the local
DatabaseResult *res = db.query("SELECT name, value FROM config WHERE camera = -1 OR camera = " + std::to_string(id) + " ORDER by camera DESC" );
while (res && res->next_row()){
cfg.set_value(res->get_field(0), res->get_field(1));
}
delete res;
cfg.set_value("camera-id", std::to_string(id));//to allow us to pull this later
}
void Camera::run(void){
LINFO("Camera " + std::to_string(id) + " starting...");
if (!stream.connect()){
alive = false;
startup = false;
return;
}
watchdog = true;;
startup = false;
LINFO("Camera " + std::to_string(id) + " connected...");
long int file_id;
std::string new_output = fm.get_next_path(file_id, id, stream.get_start_time());
StreamWriter out = StreamWriter(cfg, new_output, stream);
out.open();
AVPacket pkt;
bool valid_keyframe = false;
//variables for cutting files...
AVRational last_cut = av_make_q(0, 1);
int seconds_per_file_raw = cfg.get_value_int("seconds-per-file");
if (seconds_per_file_raw <= 0){
seconds_per_file_raw = DEFAULT_SECONDS_PER_FILE;
}
AVRational seconds_per_file = av_make_q(seconds_per_file_raw, 1);
//used for calculating shutdown time for the last segment
long last_pts = 0;
long last_stream_index = 0;
while (!shutdown && stream.get_next_frame(pkt)){
watchdog = true;
last_pts = pkt.pts;
last_stream_index = pkt.stream_index;
if (pkt.flags & AV_PKT_FLAG_KEY && stream.get_format_context()->streams[pkt.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
//calculate the seconds:
AVRational sec = av_mul_q(av_make_q(pkt.dts, 1), stream.get_format_context()->streams[pkt.stream_index]->time_base);//current time..
sec = av_sub_q(sec, last_cut);
if (av_cmp_q(sec, seconds_per_file) == 1 || sec.num < 0){
//cutting the video
struct timeval start;
Util::compute_timestamp(stream.get_start_time(), start, pkt.pts, stream.get_format_context()->streams[pkt.stream_index]->time_base);
out.close();
fm.update_file_metadata(file_id, start);
if (sec.num < 0){
//this will cause a discontinuity which will be picked up and cause it to play correctly
start.tv_usec += 1000;
}
new_output = fm.get_next_path(file_id, id, start);
out.change_path(new_output);
out.open();
//save out this position
last_cut = av_mul_q(av_make_q(pkt.dts, 1), stream.get_format_context()->streams[pkt.stream_index]->time_base);
}
}
if (valid_keyframe || (pkt.flags & AV_PKT_FLAG_KEY && stream.get_format_context()->streams[pkt.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)){
out.write(pkt);//log it
valid_keyframe = true;
//LINFO("Got Frame " + std::to_string(id));
}
stream.unref_frame(pkt);
}
LINFO("Camera " + std::to_string(id)+ " is exiting");
struct timeval end;
Util::compute_timestamp(stream.get_start_time(), end, last_pts, stream.get_format_context()->streams[last_stream_index]->time_base);
out.close();
fm.update_file_metadata(file_id, end);
alive = false;
}
void Camera::stop(void){
shutdown = true;
}
bool Camera::ping(void){
return !watchdog.exchange(false) || !alive;
}
int Camera::get_id(void){
return id;
}
bool Camera::in_startup(void){
return startup && alive;
}
void Camera::set_thread_id(std::thread::id tid){
thread_id = tid;
}
std::thread::id Camera::get_thread_id(void){
return thread_id;
}