X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=quicksync_encoder.cpp;h=4e974223d15def72a9d348a2a4eb94039077d0e2;hb=afe996bc7dfc8689ca356d00824fbfcd632f93a2;hp=001901873b7fd641a43183f0c7a2b15b45e46ed8;hpb=ab03e5e6f24b1651b4ca7df95e20aa5786939209;p=nageru diff --git a/quicksync_encoder.cpp b/quicksync_encoder.cpp index 0019018..4e97422 100644 --- a/quicksync_encoder.cpp +++ b/quicksync_encoder.cpp @@ -1,18 +1,17 @@ -//#include "sysdeps.h" #include "quicksync_encoder.h" -#include +#include // Must be above the Xlib includes. #include + #include -#include #include #include #include -#include +#include #include #include #include -#include +#include #include #include #include @@ -20,24 +19,40 @@ #include #include #include +#include #include +#include #include #include #include #include +#include #include #include #include +extern "C" { + +#include +#include +#include +#include + +} // namespace + #include "audio_encoder.h" #include "context.h" #include "defs.h" +#include "disk_space_estimator.h" +#include "ffmpeg_raii.h" #include "flags.h" #include "mux.h" +#include "ref_counted_frame.h" #include "timebase.h" #include "x264_encoder.h" using namespace std; +using namespace std::placeholders; class QOpenGLContext; class QSurface; @@ -194,7 +209,7 @@ FrameReorderer::Frame FrameReorderer::get_first_frame() class QuickSyncEncoderImpl { public: - QuickSyncEncoderImpl(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, AudioEncoder *stream_audio_encoder, X264Encoder *x264_encoder); + QuickSyncEncoderImpl(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, X264Encoder *x264_encoder, DiskSpaceEstimator *disk_space_estimator); ~QuickSyncEncoderImpl(); void add_audio(int64_t pts, vector audio); bool begin_frame(GLuint *y_tex, GLuint *cbcr_tex); @@ -206,6 +221,11 @@ public: stream_mux = mux; } + // So we never get negative dts. + int64_t global_delay() const { + return int64_t(ip_period - 1) * (TIMEBASE / MAX_FPS); + } + private: struct storage_task { unsigned long long display_order; @@ -219,11 +239,6 @@ private: int64_t pts, duration; }; - // So we never get negative dts. - int64_t global_delay() const { - return int64_t(ip_period - 1) * (TIMEBASE / MAX_FPS); - } - void open_output_file(const std::string &filename); void encode_thread_func(); void encode_remaining_frames_as_p(int encoding_frame_num, int gop_start_display_frame_num, int64_t last_dts); @@ -231,7 +246,6 @@ private: void encode_frame(PendingFrame frame, int encoding_frame_num, int display_frame_num, int gop_start_display_frame_num, int frame_type, int64_t pts, int64_t dts, int64_t duration); void storage_task_thread(); - void encode_remaining_audio(); void storage_task_enqueue(storage_task task); void save_codeddata(storage_task task); int render_packedsequence(); @@ -276,12 +290,10 @@ private: int current_storage_frame; map pending_video_frames; // under frame_queue_mutex - map> pending_audio_frames; // under frame_queue_mutex movit::ResourcePool *resource_pool; QSurface *surface; unique_ptr file_audio_encoder; - AudioEncoder *stream_audio_encoder; unique_ptr reorderer; X264Encoder *x264_encoder; // nullptr if not using x264. @@ -346,6 +358,8 @@ private: int frame_height; int frame_width_mbaligned; int frame_height_mbaligned; + + DiskSpaceEstimator *disk_space_estimator; }; // Supposedly vaRenderPicture() is supposed to destroy the buffer implicitly, @@ -1638,26 +1652,6 @@ void QuickSyncEncoderImpl::save_codeddata(storage_task task) stream_mux->add_packet(pkt, task.pts + global_delay(), task.dts + global_delay()); } } - // Encode and add all audio frames up to and including the pts of this video frame. - for ( ;; ) { - int64_t audio_pts; - vector audio; - { - unique_lock lock(frame_queue_mutex); - frame_queue_nonempty.wait(lock, [this]{ return storage_thread_should_quit || !pending_audio_frames.empty(); }); - if (storage_thread_should_quit && pending_audio_frames.empty()) return; - auto it = pending_audio_frames.begin(); - if (it->first > task.pts) break; - audio_pts = it->first; - audio = move(it->second); - pending_audio_frames.erase(it); - } - - file_audio_encoder->encode_audio(audio, audio_pts + global_delay()); - stream_audio_encoder->encode_audio(audio, audio_pts + global_delay()); - - if (audio_pts == task.pts) break; - } } @@ -1739,12 +1733,8 @@ int QuickSyncEncoderImpl::deinit_va() return 0; } -namespace { - -} // namespace - -QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, AudioEncoder *stream_audio_encoder, X264Encoder *x264_encoder) - : current_storage_frame(0), resource_pool(resource_pool), surface(surface), stream_audio_encoder(stream_audio_encoder), x264_encoder(x264_encoder), frame_width(width), frame_height(height) +QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, X264Encoder *x264_encoder, DiskSpaceEstimator *disk_space_estimator) + : current_storage_frame(0), resource_pool(resource_pool), surface(surface), x264_encoder(x264_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); @@ -1871,11 +1861,7 @@ bool QuickSyncEncoderImpl::begin_frame(GLuint *y_tex, GLuint *cbcr_tex) void QuickSyncEncoderImpl::add_audio(int64_t pts, vector audio) { assert(!is_shutdown); - { - unique_lock lock(frame_queue_mutex); - pending_audio_frames[pts] = move(audio); - } - frame_queue_nonempty.notify_all(); + file_audio_encoder->encode_audio(audio, pts + global_delay()); } RefCountedGLsync QuickSyncEncoderImpl::end_frame(int64_t pts, int64_t duration, const vector &input_frames) @@ -1943,7 +1929,9 @@ void QuickSyncEncoderImpl::shutdown() storage_task_queue_changed.notify_all(); } storage_thread.join(); - encode_remaining_audio(); + + // Encode any leftover audio in the queues, and also any delayed frames. + file_audio_encoder->encode_last_audio(); release_encode(); deinit_va(); @@ -1967,7 +1955,9 @@ void QuickSyncEncoderImpl::open_output_file(const std::string &filename) } string video_extradata = ""; // FIXME: See other comment about global headers. - file_mux.reset(new Mux(avctx, frame_width, frame_height, Mux::CODEC_H264, video_extradata, file_audio_encoder->get_ctx(), TIMEBASE, nullptr)); + AVCodecParametersWithDeleter audio_codecpar = file_audio_encoder->get_codec_parameters(); + file_mux.reset(new Mux(avctx, frame_width, frame_height, Mux::CODEC_H264, video_extradata, audio_codecpar.get(), TIMEBASE, + std::bind(&DiskSpaceEstimator::report_write, disk_space_estimator, filename, _1))); } void QuickSyncEncoderImpl::encode_thread_func() @@ -2050,25 +2040,6 @@ void QuickSyncEncoderImpl::encode_remaining_frames_as_p(int encoding_frame_num, } } -void QuickSyncEncoderImpl::encode_remaining_audio() -{ - // This really ought to be empty by now, but just to be sure... - for (auto &pending_frame : pending_audio_frames) { - int64_t audio_pts = pending_frame.first; - vector audio = move(pending_frame.second); - - file_audio_encoder->encode_audio(audio, audio_pts + global_delay()); - if (stream_audio_encoder) { - stream_audio_encoder->encode_audio(audio, audio_pts + global_delay()); - } - } - pending_audio_frames.clear(); - - // Encode any leftover audio in the queues, and also any delayed frames. - // Note: stream_audio_encoder is not owned by us, so don't call encode_last_audio(). - file_audio_encoder->encode_last_audio(); -} - void QuickSyncEncoderImpl::add_packet_for_uncompressed_frame(int64_t pts, int64_t duration, const uint8_t *data) { AVPacket pkt; @@ -2191,8 +2162,8 @@ void QuickSyncEncoderImpl::encode_frame(QuickSyncEncoderImpl::PendingFrame frame } // Proxy object. -QuickSyncEncoder::QuickSyncEncoder(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, AudioEncoder *stream_audio_encoder, X264Encoder *x264_encoder) - : impl(new QuickSyncEncoderImpl(filename, resource_pool, surface, va_display, width, height, oformat, stream_audio_encoder, x264_encoder)) {} +QuickSyncEncoder::QuickSyncEncoder(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, X264Encoder *x264_encoder, DiskSpaceEstimator *disk_space_estimator) + : impl(new QuickSyncEncoderImpl(filename, resource_pool, surface, va_display, width, height, oformat, x264_encoder, disk_space_estimator)) {} // Must be defined here because unique_ptr<> destructor needs to know the impl. QuickSyncEncoder::~QuickSyncEncoder() {} @@ -2222,3 +2193,6 @@ void QuickSyncEncoder::set_stream_mux(Mux *mux) impl->set_stream_mux(mux); } +int64_t QuickSyncEncoder::global_delay() const { + return impl->global_delay(); +}