X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=h264encode.cpp;h=02ada023b182879a0f0bf3fea15d3302dcad541b;hb=65d716be70e6295628dfa5bb0a72f3429b9696ba;hp=7fc62b3a920cde84d44ea68913138aa51acd9764;hpb=8c2ebd3fdae0bd663ed02098a693078e87d49451;p=nageru diff --git a/h264encode.cpp b/h264encode.cpp index 7fc62b3..02ada02 100644 --- a/h264encode.cpp +++ b/h264encode.cpp @@ -22,6 +22,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -109,20 +110,21 @@ class H264EncoderImpl { public: H264EncoderImpl(QSurface *surface, int width, int height, HTTPD *httpd); ~H264EncoderImpl(); - void add_audio(int64_t pts, std::vector audio); // Needs to come before end_frame() of same pts. + void add_audio(int64_t pts, vector audio); bool begin_frame(GLuint *y_tex, GLuint *cbcr_tex); - void end_frame(RefCountedGLsync fence, int64_t pts, const std::vector &input_frames); + void end_frame(RefCountedGLsync fence, int64_t pts, const vector &input_frames); + void shutdown(); private: struct storage_task { unsigned long long display_order; int frame_type; - std::vector audio; + vector audio; int64_t pts, dts; }; struct PendingFrame { RefCountedGLsync fence; - std::vector input_frames; + vector input_frames; int64_t pts; }; @@ -154,22 +156,24 @@ private: void update_ReferenceFrames(int frame_type); int update_RefPicList(int frame_type); - std::thread encode_thread, storage_thread; + bool is_shutdown = false; - std::mutex storage_task_queue_mutex; - std::condition_variable storage_task_queue_changed; + thread encode_thread, storage_thread; + + mutex storage_task_queue_mutex; + condition_variable storage_task_queue_changed; int srcsurface_status[SURFACE_NUM]; // protected by storage_task_queue_mutex - std::queue storage_task_queue; // protected by storage_task_queue_mutex + queue storage_task_queue; // protected by storage_task_queue_mutex bool storage_thread_should_quit = false; // protected by storage_task_queue_mutex - std::mutex frame_queue_mutex; - std::condition_variable frame_queue_nonempty; + mutex frame_queue_mutex; + condition_variable frame_queue_nonempty; bool encode_thread_should_quit = false; // under frame_queue_mutex int current_storage_frame; - std::map pending_video_frames; // under frame_queue_mutex - std::map> pending_audio_frames; // under frame_queue_mutex + map pending_video_frames; // under frame_queue_mutex + map> pending_audio_frames; // under frame_queue_mutex QSurface *surface; AVCodecContext *context_audio; @@ -228,7 +232,6 @@ private: int frame_height_mbaligned; }; - // Supposedly vaRenderPicture() is supposed to destroy the buffer implicitly, // but if we don't delete it here, we get leaks. The GStreamer implementation // does the same. @@ -1067,68 +1070,15 @@ int H264EncoderImpl::setup_encode() return 0; } - - -#define partition(ref, field, key, ascending) \ - while (i <= j) { \ - if (ascending) { \ - while (ref[i].field < key) \ - i++; \ - while (ref[j].field > key) \ - j--; \ - } else { \ - while (ref[i].field > key) \ - i++; \ - while (ref[j].field < key) \ - j--; \ - } \ - if (i <= j) { \ - tmp = ref[i]; \ - ref[i] = ref[j]; \ - ref[j] = tmp; \ - i++; \ - j--; \ - } \ - } \ - -static void sort_one(VAPictureH264 ref[], int left, int right, - int ascending, int frame_idx) +// Given a list like 1 9 3 0 2 8 4 and a pivot element 3, will produce +// +// 2 1 0 [3] 4 8 9 +template +static void sort_two(T *begin, T *end, const T &pivot, const C &less_than) { - int i = left, j = right; - unsigned int key; - VAPictureH264 tmp; - - if (frame_idx) { - key = ref[(left + right) / 2].frame_idx; - partition(ref, frame_idx, key, ascending); - } else { - key = ref[(left + right) / 2].TopFieldOrderCnt; - partition(ref, TopFieldOrderCnt, (signed int)key, ascending); - } - - /* recursion */ - if (left < j) - sort_one(ref, left, j, ascending, frame_idx); - - if (i < right) - sort_one(ref, i, right, ascending, frame_idx); -} - -static void sort_two(VAPictureH264 ref[], int left, int right, unsigned int key, unsigned int frame_idx, - int partition_ascending, int list0_ascending, int list1_ascending) -{ - int i = left, j = right; - VAPictureH264 tmp; - - if (frame_idx) { - partition(ref, frame_idx, key, partition_ascending); - } else { - partition(ref, TopFieldOrderCnt, (signed int)key, partition_ascending); - } - - - sort_one(ref, left, i-1, list0_ascending, frame_idx); - sort_one(ref, j+1, right, list1_ascending, frame_idx); + T *middle = partition(begin, end, [&](const T &elem) { return less_than(elem, pivot); }); + sort(begin, middle, [&](const T &a, const T &b) { return less_than(b, a); }); + sort(middle, end, less_than); } void H264EncoderImpl::update_ReferenceFrames(int frame_type) @@ -1154,21 +1104,25 @@ void H264EncoderImpl::update_ReferenceFrames(int frame_type) int H264EncoderImpl::update_RefPicList(int frame_type) { - unsigned int current_poc = CurrentCurrPic.TopFieldOrderCnt; + const auto descending_by_frame_idx = [](const VAPictureH264 &a, const VAPictureH264 &b) { + return a.frame_idx > b.frame_idx; + }; + const auto ascending_by_top_field_order_cnt = [](const VAPictureH264 &a, const VAPictureH264 &b) { + return a.TopFieldOrderCnt < b.TopFieldOrderCnt; + }; + const auto descending_by_top_field_order_cnt = [](const VAPictureH264 &a, const VAPictureH264 &b) { + return a.TopFieldOrderCnt > b.TopFieldOrderCnt; + }; if (frame_type == FRAME_P) { memcpy(RefPicList0_P, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); - sort_one(RefPicList0_P, 0, numShortTerm-1, 0, 1); - } - - if (frame_type == FRAME_B) { + sort(&RefPicList0_P[0], &RefPicList0_P[numShortTerm], descending_by_frame_idx); + } else if (frame_type == FRAME_B) { memcpy(RefPicList0_B, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); - sort_two(RefPicList0_B, 0, numShortTerm-1, current_poc, 0, - 1, 0, 1); + sort_two(&RefPicList0_B[0], &RefPicList0_B[numShortTerm], CurrentCurrPic, ascending_by_top_field_order_cnt); memcpy(RefPicList1_B, ReferenceFrames, numShortTerm * sizeof(VAPictureH264)); - sort_two(RefPicList1_B, 0, numShortTerm-1, current_poc, 0, - 0, 1, 0); + sort_two(&RefPicList1_B[0], &RefPicList1_B[numShortTerm], CurrentCurrPic, descending_by_top_field_order_cnt); } return 0; @@ -1698,26 +1652,12 @@ H264EncoderImpl::H264EncoderImpl(QSurface *surface, int width, int height, HTTPD H264EncoderImpl::~H264EncoderImpl() { - { - unique_lock lock(frame_queue_mutex); - encode_thread_should_quit = true; - frame_queue_nonempty.notify_all(); - } - encode_thread.join(); - { - unique_lock lock(storage_task_queue_mutex); - storage_thread_should_quit = true; - frame_queue_nonempty.notify_all(); - storage_task_queue_changed.notify_all(); - } - storage_thread.join(); - - release_encode(); - deinit_va(); + shutdown(); } bool H264EncoderImpl::begin_frame(GLuint *y_tex, GLuint *cbcr_tex) { + assert(!is_shutdown); { // Wait until this frame slot is done encoding. unique_lock lock(storage_task_queue_mutex); @@ -1782,6 +1722,7 @@ bool H264EncoderImpl::begin_frame(GLuint *y_tex, GLuint *cbcr_tex) void H264EncoderImpl::add_audio(int64_t pts, vector audio) { + assert(!is_shutdown); { unique_lock lock(frame_queue_mutex); pending_audio_frames[pts] = move(audio); @@ -1791,6 +1732,7 @@ void H264EncoderImpl::add_audio(int64_t pts, vector audio) void H264EncoderImpl::end_frame(RefCountedGLsync fence, int64_t pts, const vector &input_frames) { + assert(!is_shutdown); { unique_lock lock(frame_queue_mutex); pending_video_frames[current_storage_frame] = PendingFrame{ fence, input_frames, pts }; @@ -1799,6 +1741,31 @@ void H264EncoderImpl::end_frame(RefCountedGLsync fence, int64_t pts, const vecto frame_queue_nonempty.notify_all(); } +void H264EncoderImpl::shutdown() +{ + if (is_shutdown) { + return; + } + + { + unique_lock lock(frame_queue_mutex); + encode_thread_should_quit = true; + frame_queue_nonempty.notify_all(); + } + encode_thread.join(); + { + unique_lock lock(storage_task_queue_mutex); + storage_thread_should_quit = true; + frame_queue_nonempty.notify_all(); + storage_task_queue_changed.notify_all(); + } + storage_thread.join(); + + release_encode(); + deinit_va(); + is_shutdown = true; +} + void H264EncoderImpl::encode_thread_func() { int64_t last_dts = -1; @@ -1924,7 +1891,7 @@ H264Encoder::H264Encoder(QSurface *surface, int width, int height, HTTPD *httpd) // Must be defined here because unique_ptr<> destructor needs to know the impl. H264Encoder::~H264Encoder() {} -void H264Encoder::add_audio(int64_t pts, std::vector audio) +void H264Encoder::add_audio(int64_t pts, vector audio) { impl->add_audio(pts, audio); } @@ -1934,9 +1901,14 @@ bool H264Encoder::begin_frame(GLuint *y_tex, GLuint *cbcr_tex) return impl->begin_frame(y_tex, cbcr_tex); } -void H264Encoder::end_frame(RefCountedGLsync fence, int64_t pts, const std::vector &input_frames) +void H264Encoder::end_frame(RefCountedGLsync fence, int64_t pts, const vector &input_frames) { impl->end_frame(fence, pts, input_frames); } +void H264Encoder::shutdown() +{ + impl->shutdown(); +} + // Real class.