X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fmjpeg_encoder.h;h=330784bd94a30121cf30f9b3c7a5bfb1d48d2883;hb=0c7201c2d136870ea8c5fe205bee21207369312c;hp=6e0357f0c0f32bd4a862ece103bb74d3bb7b50e5;hpb=23da824e1d61e37fbe0cc1c0f4d32052022a50ba;p=nageru diff --git a/nageru/mjpeg_encoder.h b/nageru/mjpeg_encoder.h index 6e0357f..330784b 100644 --- a/nageru/mjpeg_encoder.h +++ b/nageru/mjpeg_encoder.h @@ -1,7 +1,9 @@ #ifndef _MJPEG_ENCODER_H #define _MJPEG_ENCODER_H 1 +#include "defs.h" #include "shared/ffmpeg_raii.h" +#include "shared/httpd.h" #include "ref_counted_frame.h" extern "C" { @@ -20,16 +22,16 @@ extern "C" { #include #include +#include #include -class HTTPD; struct jpeg_compress_struct; struct VADisplayWithCleanup; struct VectorDestinationManager; #define CHECK_VASTATUS(va_status, func) \ if (va_status != VA_STATUS_SUCCESS) { \ - fprintf(stderr, "%s:%d (%s) failed with %d\n", __func__, __LINE__, func, va_status); \ + fprintf(stderr, "%s:%d (%s) failed: %s\n", __func__, __LINE__, func, vaErrorStr(va_status)); \ exit(1); \ } @@ -38,17 +40,17 @@ public: MJPEGEncoder(HTTPD *httpd, const std::string &va_display); ~MJPEGEncoder(); void stop(); - void upload_frame(int64_t pts, unsigned card_index, RefCountedFrame frame, const bmusb::VideoFormat &video_format, size_t y_offset, size_t cbcr_offset); + void upload_frame(int64_t pts, unsigned card_index, RefCountedFrame frame, const bmusb::VideoFormat &video_format, size_t y_offset, size_t cbcr_offset, std::vector audio, const movit::RGBTriplet &white_balance); bool using_vaapi() const { return va_dpy != nullptr; } - // Returns -1 for inactive (ie., don't encode frames for this card right now). - int get_mjpeg_stream_for_card(unsigned card_index); + bool should_encode_mjpeg_for_card(unsigned card_index); private: static constexpr int quality = 90; struct VAResources { unsigned width, height; + uint32_t fourcc; VASurfaceID surface; VAContextID context; VABufferID data_buffer; @@ -104,6 +106,8 @@ private: RefCountedFrame frame; bmusb::VideoFormat video_format; size_t y_offset, cbcr_offset; + std::vector audio; + movit::RGBTriplet white_balance; // Only for frames in the process of being encoded by VA-API. VAResources resources; @@ -114,12 +118,21 @@ private: void va_receiver_thread_func(); void encode_jpeg_va(QueuedFrame &&qf); std::vector encode_jpeg_libjpeg(const QueuedFrame &qf); - void write_mjpeg_packet(int64_t pts, unsigned card_index, const uint8_t *jpeg, size_t jpeg_size); - void init_jpeg_422(unsigned width, unsigned height, VectorDestinationManager *dest, jpeg_compress_struct *cinfo); - std::vector get_jpeg_header(unsigned width, unsigned height, jpeg_compress_struct *cinfo); - + void write_mjpeg_packet(AVFormatContext *avctx, int64_t pts, unsigned stream_index, const uint8_t *jpeg, size_t jpeg_size); + void write_audio_packet(AVFormatContext *avctx, int64_t pts, unsigned stream_index, const std::vector &audio); + void init_jpeg(unsigned width, unsigned height, const movit::RGBTriplet &white_balance, VectorDestinationManager *dest, jpeg_compress_struct *cinfo, int y_h_samp_factor, int y_v_samp_factor); + std::vector get_jpeg_header(unsigned width, unsigned height, const movit::RGBTriplet &white_balance, int y_h_samp_factor, int y_v_samp_factor, jpeg_compress_struct *cinfo); + void add_stream(HTTPD::StreamID stream_id); // Can only be called from the constructor, or the thread owning . + void update_siphon_streams(); // Same. + void create_ffmpeg_context(HTTPD::StreamID stream_id); + + struct WritePacket2Context { + MJPEGEncoder *mjpeg_encoder; + HTTPD::StreamID stream_id; + }; + std::map ffmpeg_contexts; // Statically set up, so we never need to worry about dangling pointers. static int write_packet2_thunk(void *opaque, uint8_t *buf, int buf_size, AVIODataMarkerType type, int64_t time); - int write_packet2(uint8_t *buf, int buf_size, AVIODataMarkerType type, int64_t time); + int write_packet2(HTTPD::StreamID stream_id, uint8_t *buf, int buf_size, AVIODataMarkerType type, int64_t time); std::thread encoder_thread, va_receiver_thread; @@ -130,15 +143,38 @@ private: std::queue frames_encoding; // Under mu. Used for VA-API only. std::condition_variable any_frames_encoding; - AVFormatContextWithCloser avctx; + struct Stream { + AVFormatContextWithCloser avctx; + std::string mux_header; + }; + std::map streams; // Owned by the VA-API receiver thread if VA-API is active, or the encoder thread if not. HTTPD *httpd; - std::string mux_header; std::atomic should_quit{false}; bool running = false; std::unique_ptr va_dpy; - VAConfigID config_id; - + VAConfigID config_id_422, config_id_420; + + struct VAKey { + unsigned width, height, y_h_samp_factor, y_v_samp_factor; + movit::RGBTriplet white_balance; + + bool operator< (const VAKey &other) const { + if (width != other.width) + return width < other.width; + if (height != other.height) + return height < other.height; + if (y_h_samp_factor != other.y_h_samp_factor) + return y_h_samp_factor < other.y_h_samp_factor; + if (y_v_samp_factor != other.y_v_samp_factor) + return y_v_samp_factor < other.y_v_samp_factor; + if (white_balance.r != other.white_balance.r) + return white_balance.r < other.white_balance.r; + if (white_balance.g != other.white_balance.g) + return white_balance.g < other.white_balance.g; + return white_balance.b < other.white_balance.b; + } + }; struct VAData { std::vector jpeg_header; VAEncPictureParameterBufferJPEG pic_param; @@ -146,16 +182,14 @@ private: VAHuffmanTableBufferJPEGBaseline huff; VAEncSliceParameterBufferJPEG parms; }; - std::map, VAData> va_data_for_resolution; - VAData get_va_data_for_resolution(unsigned width, unsigned height); + std::map va_data_for_parameters; + VAData get_va_data_for_parameters(unsigned width, unsigned height, unsigned y_h_samp_factor, unsigned y_v_samp_factor, const movit::RGBTriplet &white_balance); std::list va_resources_freelist; std::mutex va_resources_mutex; - VAResources get_va_resources(unsigned width, unsigned height); + VAResources get_va_resources(unsigned width, unsigned height, uint32_t fourcc); void release_va_resources(VAResources resources); - static std::unique_ptr try_open_va(const std::string &va_display, std::string *error, VAConfigID *config_id); - uint8_t *tmp_y, *tmp_cbcr, *tmp_cb, *tmp_cr; // Private to the encoder thread. Used by the libjpeg backend only. std::atomic metric_mjpeg_frames_zero_size_dropped{0};