X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=mixer.cpp;h=8c95f386f5f4d94d929d4496be31b6a3f6950a9a;hb=c8c2e85f9c4518c6d81275e16df32969aece33ce;hp=d65cdacf44ee9aa08e71fe02ca95222c17de4416;hpb=16a3d5c40e9b53383ba36cd13cd4fe5449f0570e;p=nageru diff --git a/mixer.cpp b/mixer.cpp index d65cdac..8c95f38 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -139,7 +139,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,9 +148,6 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) limiter(OUTPUT_FREQUENCY), compressor(OUTPUT_FREQUENCY) { - httpd.open_output_file(generate_local_dump_filename(/*frame=*/0).c_str()); - httpd.start(9095); - CHECK(init_movit(MOVIT_SHADER_DIR, MOVIT_DEBUG_OFF)); check_error(); @@ -159,7 +156,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) movit_texel_subpixel_precision /= 2.0; resource_pool.reset(new ResourcePool); - theme.reset(new Theme("theme.lua", resource_pool.get(), num_cards)); + theme.reset(new Theme(global_flags.theme_filename.c_str(), resource_pool.get(), num_cards)); for (unsigned i = 0; i < NUM_OUTPUTS; ++i) { output_channel[i].parent = this; } @@ -178,6 +175,10 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) 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()); + + // Start listening for clients only once H264Encoder 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; @@ -261,6 +262,14 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) locut.init(FILTER_HPF, 2); + // If --flat-audio is given, turn off everything that messes with the sound, + // except the final makeup gain. + if (global_flags.flat_audio) { + set_locut_enabled(false); + set_limiter_enabled(false); + set_compressor_enabled(false); + } + // hlen=16 is pretty low quality, but we use quite a bit of CPU otherwise, // 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); @@ -533,26 +542,36 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode, GLuint pbo = userdata->pbo; check_error(); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); - check_error(); - glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, video_frame.size); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); check_error(); + size_t field_y_start = y_offset + video_format.width * field_start_line; + size_t field_cbcr_start = cbcr_offset + cbcr_width * field_start_line * sizeof(uint16_t); + + if (global_flags.flush_pbos) { + glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, field_y_start, video_format.width * video_format.height); + check_error(); + glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, field_cbcr_start, cbcr_width * video_format.height * sizeof(uint16_t)); + check_error(); + } + glBindTexture(GL_TEXTURE_2D, userdata->tex_cbcr[field]); check_error(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cbcr_width, video_format.height, GL_RG, GL_UNSIGNED_BYTE, BUFFER_OFFSET(cbcr_offset + cbcr_width * field_start_line * sizeof(uint16_t))); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cbcr_width, video_format.height, GL_RG, GL_UNSIGNED_BYTE, BUFFER_OFFSET(field_cbcr_start)); check_error(); glBindTexture(GL_TEXTURE_2D, userdata->tex_y[field]); check_error(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_format.width, video_format.height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(y_offset + video_format.width * field_start_line)); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_format.width, video_format.height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(field_y_start)); check_error(); glBindTexture(GL_TEXTURE_2D, 0); check_error(); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); check_error(); RefCountedGLsync fence(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0); check_error(); assert(fence.get() != nullptr); + glFlush(); // Make sure the main thread doesn't have to wait until we push out enough frames to make a new command buffer. + check_error(); if (field == 1) { // Don't upload the second field as fast as we can; wait until @@ -674,10 +693,10 @@ 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(); - httpd.close_output_file(); - httpd.open_output_file(filename.c_str()); h264_encoder.reset(new H264Encoder(h264_encoder_surface, global_flags.va_display, WIDTH, HEIGHT, &httpd)); + h264_encoder->open_output_file(filename.c_str()); } #if 0 @@ -785,11 +804,8 @@ void Mixer::render_one_frame() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - RefCountedGLsync fence(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0); - check_error(); - const int64_t av_delay = TIMEBASE / 10; // Corresponds to the fixed delay in resampling_queue.h. TODO: Make less hard-coded. - h264_encoder->end_frame(fence, pts_int + av_delay, theme_main_chain.input_frames); + RefCountedGLsync fence = h264_encoder->end_frame(pts_int + av_delay, theme_main_chain.input_frames); // The live frame just shows the RGBA texture we just rendered. // It owns rgba_tex now.