]> git.sesse.net Git - nageru/blobdiff - nageru/mixer.cpp
Fix a segfault that could happen with FFmpeg inputs and slow startup.
[nageru] / nageru / mixer.cpp
index c25b22dc711fa528c2720493504f9bebcfe12f3b..d1b52ef2dc54b4a9db8ad84e755bbadc4ac76411 100644 (file)
@@ -779,12 +779,12 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
 
                bool success;
                do {
-                       success = audio_mixer->add_silence(device, silence_samples, dropped_frames, frame_length);
+                       success = audio_mixer->add_silence(device, silence_samples, dropped_frames);
                } while (!success);
        }
 
        if (num_samples > 0) {
-               audio_mixer->add_audio(device, audio_frame.data + audio_offset, num_samples, audio_format, frame_length, audio_frame.received_timestamp);
+               audio_mixer->add_audio(device, audio_frame.data + audio_offset, num_samples, audio_format, audio_frame.received_timestamp);
        }
 
        // Done with the audio, so release it.
@@ -795,10 +795,15 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
        card->last_timecode = timecode;
 
        PBOFrameAllocator::Userdata *userdata = (PBOFrameAllocator::Userdata *)video_frame.userdata;
+       if (card->type == CardType::FFMPEG_INPUT && userdata != nullptr) {
+               FFmpegCapture *ffmpeg_capture = static_cast<FFmpegCapture *>(card->capture.get());
+               userdata->has_last_subtitle = ffmpeg_capture->get_has_last_subtitle();
+               userdata->last_subtitle = ffmpeg_capture->get_last_subtitle();
+       }
 
        size_t cbcr_width, cbcr_height, cbcr_offset, y_offset;
        size_t expected_length = video_format.stride * (video_format.height + video_format.extra_lines_top + video_format.extra_lines_bottom);
-       if (userdata->pixel_format == PixelFormat_8BitYCbCrPlanar) {
+       if (userdata != nullptr && userdata->pixel_format == PixelFormat_8BitYCbCrPlanar) {
                // The calculation above is wrong for planar Y'CbCr, so just override it.
                assert(card->type == CardType::FFMPEG_INPUT);
                assert(video_offset == 0);
@@ -829,7 +834,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                // Still send on the information that we _had_ a frame, even though it's corrupted,
                // so that pts can go up accordingly.
                {
-                       unique_lock<mutex> lock(card_mutex);
+                       lock_guard<mutex> lock(card_mutex);
                        CaptureCard::NewFrame new_frame;
                        new_frame.frame = RefCountedFrame(FrameAllocator::Frame());
                        new_frame.length = frame_length;
@@ -860,6 +865,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                }
                frame_upload_start = steady_clock::now();
        }
+       assert(userdata != nullptr);
        userdata->last_interlaced = video_format.interlaced;
        userdata->last_has_signal = video_format.has_signal;
        userdata->last_is_connected = video_format.is_connected;
@@ -953,7 +959,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                }
 
                {
-                       unique_lock<mutex> lock(card_mutex);
+                       lock_guard<mutex> lock(card_mutex);
                        CaptureCard::NewFrame new_frame;
                        new_frame.frame = frame;
                        new_frame.length = frame_length;
@@ -1076,7 +1082,7 @@ void Mixer::thread_func()
                        }
 
                        // Only bother doing MJPEG encoding if there are any connected clients
-                       // that want the stream.
+                       // that want the stream. FIXME: We should also stop memcpy-ing if there are none!
                        if (httpd.get_num_connected_multicam_clients() > 0) {
                                auto stream_it = global_flags.card_to_mjpeg_stream_export.find(card_index);
                                if (stream_it != global_flags.card_to_mjpeg_stream_export.end()) {
@@ -1348,7 +1354,7 @@ void Mixer::schedule_audio_resampling_tasks(unsigned dropped_frames, int num_sam
                        // non-dropped frame; perhaps we should just discard that as well,
                        // since dropped frames are expected to be rare, and it might be
                        // better to just wait until we have a slightly more normal situation).
-                       unique_lock<mutex> lock(audio_mutex);
+                       lock_guard<mutex> lock(audio_mutex);
                        bool adjust_rate = !dropped_frame && !is_preroll;
                        audio_task_queue.push(AudioTask{pts_int, num_samples_per_frame, adjust_rate, frame_timestamp});
                        audio_task_queue_changed.notify_one();
@@ -1372,7 +1378,7 @@ void Mixer::render_one_frame(int64_t duration)
 
        // Update Y'CbCr settings for all cards.
        {
-               unique_lock<mutex> lock(card_mutex);
+               lock_guard<mutex> lock(card_mutex);
                for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                        YCbCrInterpretation *interpretation = &ycbcr_interpretation[card_index];
                        input_state.ycbcr_coefficients_auto[card_index] = interpretation->ycbcr_coefficients_auto;
@@ -1578,13 +1584,13 @@ void Mixer::channel_clicked(int preview_num)
 
 YCbCrInterpretation Mixer::get_input_ycbcr_interpretation(unsigned card_index) const
 {
-       unique_lock<mutex> lock(card_mutex);
+       lock_guard<mutex> lock(card_mutex);
        return ycbcr_interpretation[card_index];
 }
 
 void Mixer::set_input_ycbcr_interpretation(unsigned card_index, const YCbCrInterpretation &interpretation)
 {
-       unique_lock<mutex> lock(card_mutex);
+       lock_guard<mutex> lock(card_mutex);
        ycbcr_interpretation[card_index] = interpretation;
 }
 
@@ -1608,7 +1614,7 @@ void Mixer::start_mode_scanning(unsigned card_index)
 map<uint32_t, VideoMode> Mixer::get_available_output_video_modes() const
 {
        assert(desired_output_card_index != -1);
-       unique_lock<mutex> lock(card_mutex);
+       lock_guard<mutex> lock(card_mutex);
        return cards[desired_output_card_index].output->get_available_video_modes();
 }
 
@@ -1646,7 +1652,7 @@ void Mixer::OutputChannel::output_frame(DisplayFrame &&frame)
        // Store this frame for display. Remove the ready frame if any
        // (it was seemingly never used).
        {
-               unique_lock<mutex> lock(frame_mutex);
+               lock_guard<mutex> lock(frame_mutex);
                if (has_ready_frame) {
                        parent->release_display_frame(&ready_frame);
                }
@@ -1701,7 +1707,7 @@ void Mixer::OutputChannel::output_frame(DisplayFrame &&frame)
 
 bool Mixer::OutputChannel::get_display_frame(DisplayFrame *frame)
 {
-       unique_lock<mutex> lock(frame_mutex);
+       lock_guard<mutex> lock(frame_mutex);
        if (!has_current_frame && !has_ready_frame) {
                return false;
        }
@@ -1726,13 +1732,13 @@ bool Mixer::OutputChannel::get_display_frame(DisplayFrame *frame)
 
 void Mixer::OutputChannel::add_frame_ready_callback(void *key, Mixer::new_frame_ready_callback_t callback)
 {
-       unique_lock<mutex> lock(frame_mutex);
+       lock_guard<mutex> lock(frame_mutex);
        new_frame_ready_callbacks[key] = callback;
 }
 
 void Mixer::OutputChannel::remove_frame_ready_callback(void *key)
 {
-       unique_lock<mutex> lock(frame_mutex);
+       lock_guard<mutex> lock(frame_mutex);
        new_frame_ready_callbacks.erase(key);
 }