From: Steinar H. Gunderson Date: Tue, 19 Jul 2022 12:21:13 +0000 (+0200) Subject: Make an interface to wrap X264Encoder. X-Git-Tag: 2.2.0~22 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=8929be6160ec0b2eaa5ba4b766363d4879de0cde;p=nageru Make an interface to wrap X264Encoder. This will be useful when adding more video codecs later. --- diff --git a/nageru/quicksync_encoder.cpp b/nageru/quicksync_encoder.cpp index c162189..19565ad 100644 --- a/nageru/quicksync_encoder.cpp +++ b/nageru/quicksync_encoder.cpp @@ -1435,8 +1435,8 @@ void QuickSyncEncoderImpl::release_gl_resources() has_released_gl_resources = true; } -QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, const AVOutputFormat *oformat, X264Encoder *http_encoder, X264Encoder *disk_encoder, DiskSpaceEstimator *disk_space_estimator) - : current_storage_frame(0), resource_pool(resource_pool), surface(surface), x264_http_encoder(http_encoder), x264_disk_encoder(disk_encoder), frame_width(width), frame_height(height), disk_space_estimator(disk_space_estimator) +QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, const AVOutputFormat *oformat, VideoCodecInterface *http_encoder, VideoCodecInterface *disk_encoder, DiskSpaceEstimator *disk_space_estimator) + : current_storage_frame(0), resource_pool(resource_pool), surface(surface), http_encoder(http_encoder), disk_encoder(disk_encoder), frame_width(width), frame_height(height), disk_space_estimator(disk_space_estimator) { file_audio_encoder.reset(new AudioEncoder(AUDIO_OUTPUT_CODEC_NAME, DEFAULT_AUDIO_OUTPUT_BIT_RATE, oformat)); open_output_file(filename); @@ -1448,11 +1448,11 @@ QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, Resource //print_input(); if (global_flags.x264_video_to_http || global_flags.x264_video_to_disk) { - assert(x264_http_encoder != nullptr); - assert(x264_disk_encoder != nullptr); + assert(http_encoder != nullptr); + assert(disk_encoder != nullptr); } else { - assert(x264_http_encoder == nullptr); - assert(x264_disk_encoder == nullptr); + assert(http_encoder == nullptr); + assert(disk_encoder == nullptr); } enable_zerocopy_if_possible(); @@ -1733,7 +1733,7 @@ void QuickSyncEncoderImpl::open_output_file(const std::string &filename) string video_extradata; // FIXME: See other comment about global headers. if (global_flags.x264_video_to_disk) { - video_extradata = x264_disk_encoder->get_global_headers(); + video_extradata = disk_encoder->get_global_headers(); } current_file_mux_metrics.reset(); @@ -1749,7 +1749,7 @@ void QuickSyncEncoderImpl::open_output_file(const std::string &filename) metric_current_file_start_time_seconds = get_timestamp_for_metrics(); if (global_flags.x264_video_to_disk) { - x264_disk_encoder->add_mux(file_mux.get()); + disk_encoder->add_mux(file_mux.get()); } } @@ -1912,10 +1912,10 @@ void QuickSyncEncoderImpl::pass_frame(QuickSyncEncoderImpl::PendingFrame frame, if (global_flags.uncompressed_video_to_http) { add_packet_for_uncompressed_frame(pts, duration, data); } else if (global_flags.x264_video_to_http || global_flags.x264_video_to_disk) { - x264_http_encoder->add_frame(pts, duration, frame.ycbcr_coefficients, data, received_ts); + http_encoder->add_frame(pts, duration, frame.ycbcr_coefficients, data, received_ts); } if (global_flags.x264_separate_disk_encode) { - x264_disk_encoder->add_frame(pts, duration, frame.ycbcr_coefficients, data, received_ts); + disk_encoder->add_frame(pts, duration, frame.ycbcr_coefficients, data, received_ts); } if (v4l_output != nullptr) { @@ -2017,7 +2017,7 @@ void QuickSyncEncoderImpl::encode_frame(QuickSyncEncoderImpl::PendingFrame frame } // Proxy object. -QuickSyncEncoder::QuickSyncEncoder(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, const AVOutputFormat *oformat, X264Encoder *http_encoder, X264Encoder *disk_encoder, DiskSpaceEstimator *disk_space_estimator) +QuickSyncEncoder::QuickSyncEncoder(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, const AVOutputFormat *oformat, VideoCodecInterface *http_encoder, VideoCodecInterface *disk_encoder, DiskSpaceEstimator *disk_space_estimator) : impl(new QuickSyncEncoderImpl(filename, resource_pool, surface, va_display, width, height, oformat, http_encoder, disk_encoder, disk_space_estimator)) {} // Must be defined here because unique_ptr<> destructor needs to know the impl. diff --git a/nageru/quicksync_encoder.h b/nageru/quicksync_encoder.h index 97109ce..9f59c2c 100644 --- a/nageru/quicksync_encoder.h +++ b/nageru/quicksync_encoder.h @@ -50,7 +50,7 @@ class Mux; class QSurface; class QuickSyncEncoderImpl; class RefCountedFrame; -class X264Encoder; +class VideoCodecInterface; namespace movit { class ResourcePool; @@ -63,7 +63,7 @@ class ResourcePool; // This class is _not_ thread-safe, except where mentioned. class QuickSyncEncoder { public: - QuickSyncEncoder(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const std::string &va_display, int width, int height, const AVOutputFormat *oformat, X264Encoder *http_encoder, X264Encoder *disk_encoder, DiskSpaceEstimator *disk_space_estimator); + QuickSyncEncoder(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const std::string &va_display, int width, int height, const AVOutputFormat *oformat, VideoCodecInterface *http_encoder, VideoCodecInterface *disk_encoder, DiskSpaceEstimator *disk_space_estimator); ~QuickSyncEncoder(); void set_stream_mux(Mux *mux); // Does not take ownership. Must be called unless x264 is used for the stream. diff --git a/nageru/quicksync_encoder_impl.h b/nageru/quicksync_encoder_impl.h index 5074115..3d777dc 100644 --- a/nageru/quicksync_encoder_impl.h +++ b/nageru/quicksync_encoder_impl.h @@ -39,11 +39,11 @@ class ResourcePool; } class DiskSpaceEstimator; class QSurface; -class X264Encoder; +class VideoCodecInterface; class QuickSyncEncoderImpl { public: - QuickSyncEncoderImpl(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const std::string &va_display, int width, int height, const AVOutputFormat *oformat, X264Encoder *http_encoder, X264Encoder *disk_encoder, DiskSpaceEstimator *disk_space_estimator); + QuickSyncEncoderImpl(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const std::string &va_display, int width, int height, const AVOutputFormat *oformat, VideoCodecInterface *http_encoder, VideoCodecInterface *disk_encoder, DiskSpaceEstimator *disk_space_estimator); ~QuickSyncEncoderImpl(); void add_audio(int64_t pts, std::vector audio); bool is_zerocopy() const; @@ -171,8 +171,8 @@ private: std::mutex file_audio_encoder_mutex; std::unique_ptr file_audio_encoder; - X264Encoder *x264_http_encoder; // nullptr if not using x264. - X264Encoder *x264_disk_encoder; + VideoCodecInterface *http_encoder; // nullptr if not using x264. + VideoCodecInterface *disk_encoder; std::unique_ptr v4l_output; // nullptr if not using V4L2 output. Mux* stream_mux = nullptr; // To HTTP. diff --git a/nageru/video_codec_interface.h b/nageru/video_codec_interface.h new file mode 100644 index 0000000..00524d7 --- /dev/null +++ b/nageru/video_codec_interface.h @@ -0,0 +1,32 @@ +// Common interface for low-level video codecs. Not to be confused +// with VideoEncoder (which is a higher-level orchestration class). + +#ifndef _VIDEO_CODEC_INTERFACE_H +#define _VIDEO_CODEC_INTERFACE_H 1 + +#include +#include + +#include + +#include "print_latency.h" + +class Mux; + +class VideoCodecInterface { +public: + // Called after the last frame. Will block; once this returns, + // the last data is flushed. + virtual ~VideoCodecInterface() {} + + // Must be called before first frame. Does not take ownership. + virtual void add_mux(Mux *mux) = 0; + + // is taken to be raw NV12 data of WIDTHxHEIGHT resolution. + // Does not block. + virtual void add_frame(int64_t pts, int64_t duration, movit::YCbCrLumaCoefficients ycbcr_coefficients, const uint8_t *data, const ReceivedTimestamps &received_ts) = 0; + + virtual std::string get_global_headers() const = 0; +}; + +#endif // !defined(_VIDEO_CODEC_INTERFACE_H) diff --git a/nageru/x264_encoder.h b/nageru/x264_encoder.h index 3aeca64..d767ac3 100644 --- a/nageru/x264_encoder.h +++ b/nageru/x264_encoder.h @@ -35,27 +35,28 @@ extern "C" { #include "defs.h" #include "shared/metrics.h" #include "print_latency.h" +#include "video_codec_interface.h" #include "x264_dynamic.h" class Mux; class X264SpeedControl; -class X264Encoder { +class X264Encoder : public VideoCodecInterface { public: X264Encoder(const AVOutputFormat *oformat, bool use_separate_disk_params); // Does not take ownership. // Called after the last frame. Will block; once this returns, // the last data is flushed. - ~X264Encoder(); + ~X264Encoder() override; // Must be called before first frame. Does not take ownership. - void add_mux(Mux *mux) { muxes.push_back(mux); } + void add_mux(Mux *mux) override { muxes.push_back(mux); } // is taken to be raw NV12 data of WIDTHxHEIGHT resolution. // Does not block. - void add_frame(int64_t pts, int64_t duration, movit::YCbCrLumaCoefficients ycbcr_coefficients, const uint8_t *data, const ReceivedTimestamps &received_ts); + void add_frame(int64_t pts, int64_t duration, movit::YCbCrLumaCoefficients ycbcr_coefficients, const uint8_t *data, const ReceivedTimestamps &received_ts) override; - std::string get_global_headers() const { + std::string get_global_headers() const override { while (!x264_init_done) { sched_yield(); }