X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=mixer.cpp;h=cbc14f2784c34af19edad47337aa698b4eafeb5d;hb=a29ee5d5544e6a5613b14ca31d4107b8846859c5;hp=3dc8a4c3e5c3630965106755c38f6e4a1373c865;hpb=e45ebd282e3c6c369475ef0987945eca62ef8f58;p=nageru diff --git a/mixer.cpp b/mixer.cpp index 3dc8a4c..cbc14f2 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -33,7 +33,7 @@ #include "decklink_capture.h" #include "defs.h" #include "flags.h" -#include "h264encode.h" +#include "video_encoder.h" #include "pbo_frame_allocator.h" #include "ref_counted_gl_sync.h" #include "timebase.h" @@ -92,23 +92,6 @@ void insert_new_frame(RefCountedFrame frame, unsigned field_num, bool interlaced } } -string generate_local_dump_filename(int frame) -{ - time_t now = time(NULL); - tm now_tm; - localtime_r(&now, &now_tm); - - char timestamp[256]; - strftime(timestamp, sizeof(timestamp), "%F-%T%z", &now_tm); - - // Use the frame number to disambiguate between two cuts starting - // on the same second. - char filename[256]; - snprintf(filename, sizeof(filename), "%s%s-f%02d%s", - LOCAL_DUMP_PREFIX, timestamp, frame % 100, LOCAL_DUMP_SUFFIX); - return filename; -} - } // namespace void QueueLengthPolicy::update_policy(int queue_length) @@ -127,9 +110,9 @@ void QueueLengthPolicy::update_policy(int queue_length) if (queue_length >= int(safe_queue_length)) { been_at_safe_point_since_last_starvation = true; } - if (++frames_with_at_least_one >= 50 && safe_queue_length > 0) { + if (++frames_with_at_least_one >= 1000 && safe_queue_length > 0) { --safe_queue_length; - fprintf(stderr, "Card %u: Spare frames for more than 50 frames, reducing safe limit to %u frames\n", + fprintf(stderr, "Card %u: Spare frames for more than 1000 frames, reducing safe limit to %u frames\n", card_index, safe_queue_length); frames_with_at_least_one = 0; } @@ -139,7 +122,7 @@ void QueueLengthPolicy::update_policy(int queue_length) } Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) - : httpd(WIDTH, HEIGHT), + : httpd(), num_cards(num_cards), mixer_surface(create_surface(format)), h264_encoder_surface(create_surface(format)), @@ -148,8 +131,6 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) limiter(OUTPUT_FREQUENCY), compressor(OUTPUT_FREQUENCY) { - httpd.start(9095); - CHECK(init_movit(MOVIT_SHADER_DIR, MOVIT_DEBUG_OFF)); check_error(); @@ -176,8 +157,10 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) display_chain->set_dither_bits(0); // Don't bother. display_chain->finalize(); - h264_encoder.reset(new H264Encoder(h264_encoder_surface, global_flags.va_display, WIDTH, HEIGHT, &httpd)); - h264_encoder->open_output_file(generate_local_dump_filename(/*frame=*/0).c_str()); + video_encoder.reset(new VideoEncoder(resource_pool.get(), h264_encoder_surface, global_flags.va_display, WIDTH, HEIGHT, &httpd)); + + // Start listening for clients only once VideoEncoder has written its header, if any. + httpd.start(9095); // First try initializing the PCI devices, then USB, until we have the desired number of cards. unsigned num_pci_devices = 0, num_usb_devices = 0; @@ -273,7 +256,9 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) // and there's a limit to how important the peak meter is. peak_resampler.setup(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY * 4, /*num_channels=*/2, /*hlen=*/16, /*frel=*/1.0); - alsa.reset(new ALSAOutput(OUTPUT_FREQUENCY, /*num_channels=*/2)); + if (global_flags.enable_alsa_output) { + alsa.reset(new ALSAOutput(OUTPUT_FREQUENCY, /*num_channels=*/2)); + } } Mixer::~Mixer() @@ -291,7 +276,7 @@ Mixer::~Mixer() cards[card_index].capture->stop_dequeue_thread(); } - h264_encoder.reset(nullptr); + video_encoder.reset(nullptr); } void Mixer::configure_card(unsigned card_index, const QSurfaceFormat &format, CaptureInterface *capture) @@ -675,9 +660,10 @@ void Mixer::thread_func() } } - render_one_frame(); + int64_t duration = new_frames[master_card_index].length; + render_one_frame(duration); ++frame; - pts_int += new_frames[master_card_index].length; + pts_int += duration; clock_gettime(CLOCK_MONOTONIC, &now); double elapsed = now.tv_sec - start.tv_sec + @@ -690,12 +676,7 @@ void Mixer::thread_func() } if (should_cut.exchange(false)) { // Test and clear. - string filename = generate_local_dump_filename(frame); - printf("Starting new recording: %s\n", filename.c_str()); - h264_encoder->close_output_file(); - h264_encoder->shutdown(); - h264_encoder.reset(new H264Encoder(h264_encoder_surface, global_flags.va_display, WIDTH, HEIGHT, &httpd)); - h264_encoder->open_output_file(filename.c_str()); + video_encoder->do_cut(frame); } #if 0 @@ -773,7 +754,7 @@ void Mixer::schedule_audio_resampling_tasks(unsigned dropped_frames, int num_sam } } -void Mixer::render_one_frame() +void Mixer::render_one_frame(int64_t duration) { // Get the main chain from the theme, and set its state immediately. Theme::Chain theme_main_chain = theme->get_chain(0, pts(), WIDTH, HEIGHT, input_state); @@ -782,7 +763,7 @@ void Mixer::render_one_frame() //theme_main_chain.chain->enable_phase_timing(true); GLuint y_tex, cbcr_tex; - bool got_frame = h264_encoder->begin_frame(&y_tex, &cbcr_tex); + bool got_frame = video_encoder->begin_frame(&y_tex, &cbcr_tex); assert(got_frame); // Render main chain. @@ -804,7 +785,7 @@ void Mixer::render_one_frame() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); const int64_t av_delay = TIMEBASE / 10; // Corresponds to the fixed delay in resampling_queue.h. TODO: Make less hard-coded. - RefCountedGLsync fence = h264_encoder->end_frame(pts_int + av_delay, theme_main_chain.input_frames); + RefCountedGLsync fence = video_encoder->end_frame(pts_int + av_delay, duration, theme_main_chain.input_frames); // The live frame just shows the RGBA texture we just rendered. // It owns rgba_tex now. @@ -1025,7 +1006,7 @@ void Mixer::process_audio_one_frame(int64_t frame_pts_int, int num_samples) } // And finally add them to the output. - h264_encoder->add_audio(frame_pts_int, move(samples_out)); + video_encoder->add_audio(frame_pts_int, move(samples_out)); } void Mixer::subsample_chroma(GLuint src_tex, GLuint dst_tex) @@ -1204,3 +1185,5 @@ void Mixer::OutputChannel::set_frame_ready_callback(Mixer::new_frame_ready_callb new_frame_ready_callback = callback; has_new_frame_ready_callback = true; } + +mutex RefCountedGLsync::fence_lock;