X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fffmpeg_capture.h;h=fc584827a373e791ae85123a3a58de3d553b72c7;hb=84e8b42b69804464ffb978ea4a2d0b700fe17d89;hp=468c213d17f677a9235242a5d9f7b1bcecdeaba3;hpb=1501c53153cb0daa846e4de7a73cfbfc797fd543;p=nageru diff --git a/nageru/ffmpeg_capture.h b/nageru/ffmpeg_capture.h index 468c213..fc58482 100644 --- a/nageru/ffmpeg_capture.h +++ b/nageru/ffmpeg_capture.h @@ -17,6 +17,11 @@ // changes parameters midway, which is allowed in some formats. // // You can get out the audio either as decoded or in raw form (Kaeru uses this). +// +// If there's a subtitle track, you can also get out the last subtitle at the +// point of the frame. Note that once we get a video frame, we don't look for +// subtitle, so if subtitles and a frame comes at the same time, you might not +// see the subtitle until the next frame. #include #include @@ -28,10 +33,12 @@ #include #include +#include #include extern "C" { #include +#include #include #include #include @@ -51,6 +58,10 @@ class FFmpegCapture : public bmusb::CaptureInterface { public: FFmpegCapture(const std::string &filename, unsigned width, unsigned height); +#ifdef HAVE_SRT + // Takes ownership of the SRT client socket. + FFmpegCapture(int srt_sock, const std::string &stream_id); +#endif ~FFmpegCapture(); void set_card_index(int card_index) @@ -149,9 +160,13 @@ public: std::placeholders::_11); } - // FFmpegCapture-specific callback that gives the raw audio. - typedef std::function audio_callback_t; - void set_audio_callback(audio_callback_t callback) + // FFmpegCapture-specific callback that gives the raw audio/video. + typedef std::function packet_callback_t; + void set_video_callback(packet_callback_t callback) + { + video_callback = callback; + } + void set_audio_callback(packet_callback_t callback) { audio_callback = callback; } @@ -164,6 +179,24 @@ public: return current_frame_ycbcr_format; } + // Only valid to call during the frame callback. + std::string get_last_subtitle() const + { + return last_subtitle; + } + + // Same. + bool get_has_last_subtitle() const + { + return has_last_subtitle; + } + + // Same. + movit::RGBTriplet get_last_neutral_color() const + { + return last_neutral_color; + } + void set_dequeue_thread_callbacks(std::function init, std::function cleanup) override { dequeue_init_callback = init; @@ -171,6 +204,11 @@ public: has_dequeue_callbacks = true; } + void set_card_disconnected_callback(bmusb::card_disconnected_callback_t callback) + { + card_disconnected_callback = callback; + } + std::string get_description() const override { return description; @@ -179,7 +217,8 @@ public: void configure_card() override; void start_bm_capture() override; void stop_dequeue_thread() override; - bool get_disconnected() const override { return false; } // We never unplug. + bool get_disconnected() const override { return disconnected; } // Only if play_once == true. + int get_srt_sock() const { return srt_sock; } std::map get_available_video_modes() const override; void set_video_mode(uint32_t video_mode_id) override {} // Ignore. @@ -218,38 +257,57 @@ private: // Returns nullptr if no frame was decoded (e.g. EOF). AVFrameWithDeleter decode_frame(AVFormatContext *format_ctx, AVCodecContext *video_codec_ctx, AVCodecContext *audio_codec_ctx, - const std::string &pathname, int video_stream_index, int audio_stream_index, + const std::string &pathname, int video_stream_index, int audio_stream_index, int subtitle_stream_index, bmusb::FrameAllocator::Frame *audio_frame, bmusb::AudioFormat *audio_format, int64_t *audio_pts, bool *error); void convert_audio(const AVFrame *audio_avframe, bmusb::FrameAllocator::Frame *audio_frame, bmusb::AudioFormat *audio_format); bmusb::VideoFormat construct_video_format(const AVFrame *frame, AVRational video_timebase); UniqueFrame make_video_frame(const AVFrame *frame, const std::string &pathname, bool *error); - static int interrupt_cb_thunk(void *unique); + static int interrupt_cb_thunk(void *opaque); int interrupt_cb(); +#ifdef HAVE_SRT + static int read_srt_thunk(void *opaque, uint8_t *buf, int buf_size); + int read_srt(uint8_t *buf, int buf_size); +#endif + + inline unsigned frame_width(const AVFrame *frame) const; + inline unsigned frame_height(const AVFrame *frame) const; + mutable std::mutex filename_mu; std::string description, filename; + int srt_sock = -1; uint16_t timecode = 0; - unsigned width, height; + unsigned width, height; // 0 means keep input size. bmusb::PixelFormat pixel_format = bmusb::PixelFormat_8BitBGRA; movit::YCbCrFormat current_frame_ycbcr_format; bool running = false; int card_index = -1; double rate = 1.0; + bool play_as_fast_as_possible = false; // Activated iff rate >= 10.0. std::atomic should_interrupt{false}; bool last_frame_was_connected = true; + // TODO: Replace with std::optional if we go C++17. + bool frame_timeout_valid = false; // If true, will time out any reads after ten seconds. + std::chrono::steady_clock::time_point frame_timeout_started; // Only relevant if frame_timeout_valid == true. + bool has_dequeue_callbacks = false; std::function dequeue_init_callback = nullptr; std::function dequeue_cleanup_callback = nullptr; + bmusb::card_disconnected_callback_t card_disconnected_callback = nullptr; + bool play_once = false; // End thread after playing. Only for SRT, since the socket is ephemeral. + std::atomic disconnected{false}; + bmusb::FrameAllocator *video_frame_allocator = nullptr; bmusb::FrameAllocator *audio_frame_allocator = nullptr; std::unique_ptr owned_video_frame_allocator; std::unique_ptr owned_audio_frame_allocator; frame_callback_t frame_callback = nullptr; - audio_callback_t audio_callback = nullptr; + packet_callback_t video_callback = nullptr; + packet_callback_t audio_callback = nullptr; SwsContextWithDeleter sws_ctx; int sws_last_width = -1, sws_last_height = -1, sws_last_src_format = -1; @@ -273,9 +331,19 @@ private: // Audio resampler. SwrContext *resampler = nullptr; AVSampleFormat last_src_format, last_dst_format; - int64_t last_channel_layout; + AVChannelLayout last_channel_layout; int last_sample_rate; + // Subtitles (no decoding done, really). + bool has_last_subtitle = false; + std::string last_subtitle; + + movit::RGBTriplet last_neutral_color{1.0f, 1.0f, 1.0f}; + + // Used for suppressing repeated warnings. Reset when a video starts playing. + // -1 is strictly speaking outside the range of the enum, but hopefully, it will be alright. + AVColorSpace last_colorspace = static_cast(-1); + AVChromaLocation last_chroma_location = static_cast(-1); }; #endif // !defined(_FFMPEG_CAPTURE_H)