X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=futatabi%2Fmain.cpp;h=c13e19694783e3e2b178ce2f28ef5b6e8fcb3702;hb=b57d57b88a1d7388c6eacf8cc0867f680123120a;hp=7076230c7429f7cc2c236de332d4a1db253ebbbc;hpb=8c52fd7481d962d52b73961215251951a798a87a;p=nageru diff --git a/futatabi/main.cpp b/futatabi/main.cpp index 7076230..c13e196 100644 --- a/futatabi/main.cpp +++ b/futatabi/main.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include #include @@ -21,16 +21,17 @@ extern "C" { } #include "clip_list.h" -#include "shared/context.h" #include "defs.h" -#include "shared/disk_space_estimator.h" -#include "shared/ffmpeg_raii.h" #include "flags.h" -#include "frame_on_disk.h" #include "frame.pb.h" -#include "shared/httpd.h" +#include "frame_on_disk.h" #include "mainwindow.h" #include "player.h" +#include "shared/context.h" +#include "shared/disk_space_estimator.h" +#include "shared/ffmpeg_raii.h" +#include "shared/httpd.h" +#include "shared/metrics.h" #include "shared/post_to_main_thread.h" #include "shared/ref_counted_gl_sync.h" #include "shared/timebase.h" @@ -39,8 +40,8 @@ extern "C" { #include #include -#include #include +#include #include #include @@ -51,7 +52,7 @@ constexpr char frame_magic[] = "Ftbifrm0"; constexpr size_t frame_magic_len = 8; mutex RefCountedGLsync::fence_lock; -atomic should_quit{false}; +atomic should_quit{ false }; int64_t start_pts = -1; @@ -69,6 +70,9 @@ mutex frame_mu; vector frames[MAX_STREAMS]; // Under frame_mu. vector frame_filenames; // Under frame_mu. +atomic metric_received_frames[MAX_STREAMS]{ { 0 } }; +Summary metric_received_frame_size_bytes; + namespace { FrameOnDisk write_frame(int stream_idx, int64_t pts, const uint8_t *data, size_t size, DB *db) @@ -76,7 +80,7 @@ FrameOnDisk write_frame(int stream_idx, int64_t pts, const uint8_t *data, size_t if (open_frame_files.count(stream_idx) == 0) { char filename[256]; snprintf(filename, sizeof(filename), "%s/frames/cam%d-pts%09ld.frames", - global_flags.working_directory.c_str(), stream_idx, pts); + global_flags.working_directory.c_str(), stream_idx, pts); FILE *fp = fopen(filename, "wb"); if (fp == nullptr) { perror(filename); @@ -178,12 +182,12 @@ FrameOnDisk write_frame(int stream_idx, int64_t pts, const uint8_t *data, size_t return frame; } -} // namespace +} // namespace HTTPD *global_httpd; void load_existing_frames(); -int record_thread_func(); +void record_thread_func(); int main(int argc, char **argv) { @@ -200,17 +204,17 @@ int main(int argc, char **argv) string frame_dir = global_flags.working_directory + "/frames"; - struct stat st; - if (stat(frame_dir.c_str(), &st) == -1) { + if (mkdir(frame_dir.c_str(), 0777) == 0) { fprintf(stderr, "%s does not exist, creating it.\n", frame_dir.c_str()); - if (mkdir(frame_dir.c_str(), 0777) == -1) { - perror(global_flags.working_directory.c_str()); - exit(1); - } + } else if (errno != EEXIST) { + perror(global_flags.working_directory.c_str()); + exit(1); } avformat_network_init(); + global_metrics.set_prefix("futatabi"); global_httpd = new HTTPD; + global_metrics.remove("num_connected_multicam_clients"); QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); @@ -240,7 +244,10 @@ int main(int argc, char **argv) { QSurface *surface = create_surface(); QOpenGLContext *context = create_context(surface); - make_current(context, surface); + if (!make_current(context, surface)) { + printf("oops\n"); + exit(1); + } CHECK(movit::init_movit(MOVIT_SHADER_DIR, movit::MOVIT_DEBUG_OFF)); delete_context(context); // TODO: Delete the surface, too. @@ -279,7 +286,7 @@ void load_frame_file(const char *filename, const string &basename, unsigned file if (!all_frames.empty()) { // We already had this cached in the database, so no need to look in the file. for (const DB::FrameOnDiskAndStreamIdx &frame : all_frames) { - if (frame.stream_idx >= 0 && frame.stream_idx < MAX_STREAMS) { + if (frame.stream_idx < MAX_STREAMS) { frames[frame.stream_idx].push_back(frame.frame); start_pts = max(start_pts, frame.frame.pts); } @@ -313,9 +320,9 @@ void load_frame_file(const char *filename, const string &basename, unsigned file // OK, found the magic. Try to parse the frame header. magic_offset = 0; - if (skipped_bytes > 0) { + if (skipped_bytes > 0) { fprintf(stderr, "WARNING: %s: Skipped %zu garbage bytes in the middle.\n", - filename, skipped_bytes); + filename, skipped_bytes); skipped_bytes = 0; } @@ -341,6 +348,10 @@ void load_frame_file(const char *filename, const string &basename, unsigned file FrameOnDisk frame; frame.pts = hdr.pts(); frame.offset = ftell(fp); + if (frame.offset == -1) { + fprintf(stderr, "WARNING: %s: ftell() failed (%s).\n", filename, strerror(errno)); + break; + } frame.filename_idx = filename_idx; frame.size = hdr.file_size(); @@ -358,12 +369,17 @@ void load_frame_file(const char *filename, const string &basename, unsigned file if (skipped_bytes > 0) { fprintf(stderr, "WARNING: %s: Skipped %zu garbage bytes at the end.\n", - filename, skipped_bytes); + filename, skipped_bytes); } - size_t size = ftell(fp); + off_t size = ftell(fp); fclose(fp); + if (size == -1) { + fprintf(stderr, "WARNING: %s: ftell() failed (%s).\n", filename, strerror(errno)); + return; + } + db->store_frame_file(basename, size, all_frames); } @@ -385,7 +401,7 @@ void load_existing_frames() } vector frame_basenames; - for ( ;; ) { + for (;;) { errno = 0; dirent *de = readdir(dir); if (de == nullptr) { @@ -435,17 +451,27 @@ void load_existing_frames() for (int stream_idx = 0; stream_idx < MAX_STREAMS; ++stream_idx) { sort(frames[stream_idx].begin(), frames[stream_idx].end(), - [](const auto &a, const auto &b) { return a.pts < b.pts; }); + [](const auto &a, const auto &b) { return a.pts < b.pts; }); } db.clean_unused_frame_files(frame_basenames); } -int record_thread_func() +void record_thread_func() { + for (unsigned i = 0; i < MAX_STREAMS; ++i) { + global_metrics.add("received_frames", { { "stream", to_string(i) } }, &metric_received_frames[i]); + } + global_metrics.add("received_frame_size_bytes", &metric_received_frame_size_bytes); + + if (global_flags.stream_source.empty() || global_flags.stream_source == "/dev/null") { + // Save the user from some repetitive messages. + return; + } + pthread_setname_np(pthread_self(), "ReceiveFrames"); - int64_t pts_offset; + int64_t pts_offset = 0; // Needs to be initialized due to a spurious GCC warning. DB db(global_flags.working_directory + "/futatabi.db"); while (!should_quit.load()) { @@ -460,7 +486,7 @@ int record_thread_func() while (!should_quit.load()) { AVPacket pkt; - unique_ptr pkt_cleanup( + unique_ptr pkt_cleanup( &pkt, av_packet_unref); av_init_packet(&pkt); pkt.data = nullptr; @@ -471,6 +497,12 @@ int record_thread_func() if (av_read_frame(format_ctx.get(), &pkt) != 0) { break; } + if (pkt.stream_index >= MAX_STREAMS) { + continue; + } + + ++metric_received_frames[pkt.stream_index]; + metric_received_frame_size_bytes.count_event(pkt.size); // Convert pts to our own timebase. AVRational stream_timebase = format_ctx->streams[pkt.stream_index]->time_base; @@ -487,15 +519,7 @@ int record_thread_func() FrameOnDisk frame = write_frame(pkt.stream_index, pts, pkt.data, pkt.size, &db); post_to_main_thread([pkt, frame] { - if (pkt.stream_index == 0) { - global_mainwindow->ui->input1_display->setFrame(pkt.stream_index, frame); - } else if (pkt.stream_index == 1) { - global_mainwindow->ui->input2_display->setFrame(pkt.stream_index, frame); - } else if (pkt.stream_index == 2) { - global_mainwindow->ui->input3_display->setFrame(pkt.stream_index, frame); - } else if (pkt.stream_index == 3) { - global_mainwindow->ui->input4_display->setFrame(pkt.stream_index, frame); - } + global_mainwindow->display_frame(pkt.stream_index, frame); }); if (last_pts != -1 && global_flags.slow_down_input) { @@ -510,5 +534,4 @@ int record_thread_func() start_pts = last_pts + TIMEBASE; } - return 0; }