Skip to content

Commit

Permalink
Initial Support for .mp4 outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
edman007 committed Jan 29, 2021
1 parent 20fd129 commit bf2d8fa
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 18 deletions.
1 change: 0 additions & 1 deletion chiton_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
//we have to have valid values for these, these are the defaults when the user sets a bad value
const long DEFAULT_SECONDS_PER_FILE = 6;//Apple recommends 6 seconds per file to make live streaming reasonable
const long DEFAULT_MIN_FREE_SPACE = 1073741824;//1G in bytes
const std::string FILE_EXT = ".ts";
const std::string EXPORT_EXT = ".mp4";

class Config {
Expand Down
14 changes: 14 additions & 0 deletions database_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ bool DatabaseManager::initilize_db(){
"endtime bigint(20) DEFAULT NULL, "
"camera int(11) NOT NULL, "
"`locked` tinyint(1) NOT NULL DEFAULT 0, "
"`extension` ENUM('.ts','.mp4') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '.ts', "
"PRIMARY KEY (id,camera,starttime), "
"KEY endtime (endtime), "
"KEY starttime (starttime), "
Expand Down Expand Up @@ -259,6 +260,8 @@ bool DatabaseManager::upgrade_from_1_1(void){
"PRIMARY KEY (`id`), "
"KEY starttime (starttime) "
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
const std::string video_alter = "ALTER TABLE `videos` ADD `extension` ENUM('.ts','.mp4') "
"CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '.ts' AFTER `locked`";
bool ret = true;
DatabaseResult *res = db.query(images_tbl);
if (res){
Expand All @@ -268,6 +271,17 @@ bool DatabaseManager::upgrade_from_1_1(void){
ret = false;
}

//update the video table
if (ret){
res = db.query(video_alter);
if (res){
delete res;
} else {
LFATAL("Could not alter video table");
ret = false;
}
}

if (ret){
return set_latest_version();
} else {
Expand Down
4 changes: 2 additions & 2 deletions export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ void Export::run_job(void){
update_progress();

//query all segments we need
std::string sql = "SELECT id, path, endtime FROM videos WHERE camera = " + std::to_string(camera) + " AND ( "
std::string sql = "SELECT id, path, endtime, extension FROM videos WHERE camera = " + std::to_string(camera) + " AND ( "
"( endtime >= " + std::to_string(starttime) + " AND endtime <= " + std::to_string(endtime) + " ) "
" OR (starttime >= " + std::to_string(starttime) + " AND starttime <= " + std::to_string(endtime) + " )) "
" ORDER BY starttime ASC ";
Expand All @@ -116,7 +116,7 @@ void Export::run_job(void){
long reserved_bytes = 0;
bool output_opened = false;
while (res->next_row()){
std::string segment = fm.get_path(res->get_field_long(0), res->get_field(1));
std::string segment = fm.get_path(res->get_field_long(0), res->get_field(1), res->get_field(3));
LDEBUG("Exporting " + segment);
//we control the input stream by replacing the video-url with the segment
camera_cfg.set_value("video-url", segment);
Expand Down
31 changes: 20 additions & 11 deletions file_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ std::atomic<long> FileManager::reserved_bytes(0);
FileManager::FileManager(Database &db, Config &cfg) : db(db), cfg(cfg) {
bytes_per_segment = 1024*1024;//1M is our default guess
min_free_bytes = -1;

//we correct this if it's wrong now, so we can assume it's always right
const std::string &ext = cfg.get_value("output-extension");
if (ext != ".ts" && ext != ".mp4"){
LWARN("output-extension MUST be .ts or .mp4, using .mp4");
cfg.set_value("output-extension", ".mp4");
}
}

std::string FileManager::get_next_path(long int &file_id, int camera, const struct timeval &start_time){
Expand All @@ -44,12 +51,14 @@ std::string FileManager::get_next_path(long int &file_id, int camera, const stru
//make sure dir exists
std::string path = base + dir;
mkdir_recursive(path);

std::string sql = "INSERT INTO videos (path, starttime, camera) VALUES ('" + db.escape(dir + "/") + "'," + ptime + ", " + std::to_string(camera) + " )";
const std::string &ext = cfg.get_value("output-extension");

std::string sql = "INSERT INTO videos (path, starttime, camera, extension) VALUES ('" + db.escape(dir + "/") + "'," + ptime + ", " + std::to_string(camera) + ",'"
+ db.escape(ext) + "' )";
DatabaseResult* res = db.query(sql, NULL, &file_id);
delete res;

return path + "/" + std::to_string(file_id) + FILE_EXT;
return path + "/" + std::to_string(file_id) + ext;
}

std::string FileManager::get_export_path(long int export_id, int camera, const struct timeval &start_time){
Expand All @@ -67,9 +76,9 @@ std::string FileManager::get_export_path(long int export_id, int camera, const s
return path + "/" + std::to_string(export_id) + EXPORT_EXT;
}
//returns the path for the file referenced as id
std::string FileManager::get_path(long int id, const std::string &db_path){
std::string FileManager::get_path(long int id, const std::string &db_path, const std::string &ext){
std::string path;
path = db_path + std::to_string(id) + FILE_EXT;
path = db_path + std::to_string(id) + ext;
return get_output_dir() + path;
}

Expand Down Expand Up @@ -104,7 +113,7 @@ void FileManager::clean_disk(void){

//estimate the number of segments, add 10
long segment_count = target_clear/bytes_per_segment + 10;
std::string sql = "SELECT v.id, v.path, c.value, v.starttime FROM videos AS v LEFT JOIN config AS c ON v.camera=c.camera AND c.name = 'output-dir' "
std::string sql = "SELECT v.id, v.path, c.value, v.starttime, v.extension FROM videos AS v LEFT JOIN config AS c ON v.camera=c.camera AND c.name = 'output-dir' "
" WHERE v.locked = 0 ORDER BY starttime ASC LIMIT " + std::to_string(segment_count);

segment_count = 0;
Expand All @@ -115,7 +124,7 @@ void FileManager::clean_disk(void){
segment_count++;
long rm_size = 0;//size of file deleted
const std::string &id = res->get_field(0);
rm_size = rm_segment(res->get_field(2), res->get_field(1), id);
rm_size = rm_segment(res->get_field(2), res->get_field(1), id, res->get_field(4));
if (rm_size > 0){
target_clear -= rm_size;
actual_segment_bytes += rm_size;
Expand Down Expand Up @@ -153,11 +162,11 @@ void FileManager::clean_disk(void){
cleanup_mtx.unlock();
}

long FileManager::rm_segment(const std::string &base, const std::string &path, const std::string &id){
long FileManager::rm_segment(const std::string &base, const std::string &path, const std::string &id, const std::string &ext){
long filesize = 0;
std::string target_file = path;

target_file += id + FILE_EXT;
target_file += id + ext;
filesize = rm_file(target_file, base);
return filesize;
}
Expand All @@ -174,15 +183,15 @@ void FileManager::delete_broken_segments(void){
}
std::string future_time = std::to_string(Util::pack_time(curtime));

std::string sql = "SELECT v.id, v.path, c.value FROM videos AS v LEFT JOIN config AS c ON v.camera=c.camera AND c.name = 'output-dir' WHERE "
std::string sql = "SELECT v.id, v.path, c.value, v.extension FROM videos AS v LEFT JOIN config AS c ON v.camera=c.camera AND c.name = 'output-dir' WHERE "
"v.endtime < v.starttime OR v.starttime > " + future_time;
DatabaseResult* res = db.query(sql);
if (res && res->num_rows() > 0){
LWARN("Found " + std::to_string(res->num_rows()) + " broken segments, deleting them");
}
while (res && res->next_row()){
const std::string &id = res->get_field(0);
rm_segment(res->get_field(2), res->get_field(1), id);
rm_segment(res->get_field(2), res->get_field(1), id, res->get_field(3));
//delete it from the database
sql = "DELETE FROM videos WHERE id = " + id;
DatabaseResult* del_res = db.query(sql);
Expand Down
4 changes: 2 additions & 2 deletions file_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class FileManager {
bool get_image_path(std::string &path, std::string &name, const std::string &extension, const struct timeval *start_time = NULL);

//returns the real for the segments referenced as id and path name from the database
std::string get_path(long int file_id, const std::string &db_path);
std::string get_path(long int file_id, const std::string &db_path, const std::string &ext);

//update metadata about the file
bool update_file_metadata(long int file_id, struct timeval &end_time);
Expand Down Expand Up @@ -81,7 +81,7 @@ class FileManager {
long get_target_free_bytes(void);//return the bytes that must be deleted
long get_free_bytes(void);//return the free bytes on the disk
long get_min_free_bytes(void);//return the miniumn free bytes on the disk
long rm_segment(const std::string &base, const std::string &path, const std::string &id);//deletes a target segment, returns number of bytes removed
long rm_segment(const std::string &base, const std::string &path, const std::string &id, const std::string &ext);//deletes a target segment, returns number of bytes removed
long rm(const std::string &path);//delete a specific file and parent directories, returns negative if there was an error
std::string get_date_path(int camera, const struct timeval &start_time);//returns a path in the form of <camera>/<YYYY>/<MM>/<DD>/<HH>
std::string get_output_dir(void);//returns the output-dir cfg setting, with some fixups/sanity checks ensuring it always ends in a "/"
Expand Down
3 changes: 3 additions & 0 deletions setting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,7 @@ const std::vector<Setting> setting_options {
{"encode-format-audio", "copy", "Audio Encoding codec <copy|aac|ac3>", "The codec to save video with, copy will use the camera compressed video if compatible", SETTING_OPTIONAL_CAMERA},
{"ffmpeg-encode-audio-opt", "", "FFMPEG audio encode options", "Options for the ffmpeg encoder - audio", SETTING_OPTIONAL_CAMERA},
{"ffmpeg-encode-video-opt", "", "FFMPEG video encode options", "Options for the ffmpeg encoder - video", SETTING_OPTIONAL_CAMERA},
{"ffmpeg-decode-audio-opt", "", "FFMPEG audio decode options", "Options for the ffmpeg decoder - audio", SETTING_OPTIONAL_CAMERA},
{"ffmpeg-decode-video-opt", "", "FFMPEG video decode options", "Options for the ffmpeg decoder - video", SETTING_OPTIONAL_CAMERA},
{"output-extension", ".mp4", "Output Extension <.ts|.mp4>", "HLS Output Format, .ts for mpeg-ts files, .mp4 for fragmented mp4", SETTING_OPTIONAL_CAMERA},
};
4 changes: 2 additions & 2 deletions web/stream.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
$yesterday->sub(new DateInterval('P1D'));
//$yesterday->setTime(0,0);
//query the most recent video from the DB
$sql = 'SELECT id, path, starttime, endtime FROM videos WHERE camera = ' . ((int)$_GET['id']).' AND endtime IS NOT NULL AND starttime > ' . $packed_start;
$sql = 'SELECT id, path, starttime, endtime, extension FROM videos WHERE camera = ' . ((int)$_GET['id']).' AND endtime IS NOT NULL AND starttime > ' . $packed_start;
if ($start_time->getTimestamp() < $yesterday->getTimestamp()){
$endtime = new DateTime('@'.($start_time->getTimestamp() + 3600*24));
$packed_endtime = Datetime_to_dbtime($endtime);
Expand Down Expand Up @@ -87,7 +87,7 @@
if ($len == 0){//we have seen some with a len of zero...is this an ok workaround?
$len = 0.001;
}
$url = 'vids/' . $row['path'] . $row['id'] . '.ts';
$url = 'vids/' . $row['path'] . $row['id'] . $row['extension'];
$name = "Camera $camera: " . dbtime_to_DateTime($row['starttime'])->format('r');
echo "#EXTINF:$len,$name\n";
echo $url . "\n";
Expand Down

0 comments on commit bf2d8fa

Please sign in to comment.