From b9ebb362830897dbdc4009e240bd8714ed6ee1ff Mon Sep 17 00:00:00 2001 From: VOvchinnikov Date: Mon, 1 Nov 2021 17:08:06 +0700 Subject: [PATCH 1/7] Squashed commit of the following: commit c5a4c154eaa65c959cb459c5ebd048bbecff37e0 Author: VOvchinnikov Date: Mon Nov 1 11:31:55 2021 +0700 [refactoring] organize decoding by chunks --- src/core/decoder.cpp | 109 ++++++++++++++++++++------------- src/core/decoder.h | 39 +++++++++++- src/core/threads.cpp | 1 + src/core/threads.h | 1 + tiny_decoder/tiny_mp2v_dec.cpp | 43 ++++++++----- 5 files changed, 133 insertions(+), 60 deletions(-) diff --git a/src/core/decoder.cpp b/src/core/decoder.cpp index 6085a06..54b482f 100644 --- a/src/core/decoder.cpp +++ b/src/core/decoder.cpp @@ -191,6 +191,11 @@ void mp2v_picture_c::init() { } } +void mp2v_picture_c::on_completed() { + for (auto*& subscriber : subscribed_buffers) + subscriber->release(); +} + bool mp2v_decoder_c::decode_user_data() { while (m_bs.get_next_bits(vlc_start_code.len) != vlc_start_code.value) { uint8_t data = m_bs.read_next_bits(8); @@ -241,10 +246,12 @@ bool mp2v_decoder_c::decode_extension_data(mp2v_picture_c* pic) { return true; } -void mp2v_decoder_c::flush(mp2v_picture_c* cur_pic) { +void mp2v_decoder_c::flush() { #ifdef MP2V_MT - if (cur_pic) + if (cur_pic) { task_queue->add_task(cur_pic, cur_pic->m_picture_header.picture_coding_type == picture_coding_type_bidir); + cur_pic = nullptr; + } task_queue->kill(); #else if (ref_frames[1]) @@ -275,57 +282,71 @@ void mp2v_decoder_c::out_pic(mp2v_picture_c* cur_pic) { #endif } -bool mp2v_decoder_c::decode(uint8_t* buffer, int len) { +buffer_handle_t* mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) { + bool new_buffer = false; + uint8_t* prev_start_code = nullptr, *last_start_code = nullptr; + buffer_handle_t* buf_handle = new buffer_handle_t(); + registered_buffers.push_back(buf_handle); m_bs.set_bitstream_buffer(buffer); - bool new_picture = false, sequence_end = false; - mp2v_picture_c* cur_pic = nullptr; scan_start_codes(buffer, buffer + len, [&](uint8_t* ptr) { - BITSTREAM((&m_bs)); - bit_idx = 32; - bit_ptr = (uint32_t*)(ptr + 4); - bit_buf = (uint64_t)bswap_32(*((uint32_t*)ptr)); - uint8_t start_code = *(ptr + 3); - switch (start_code) { - case sequence_header_code: parse_sequence_header(&m_bs, m_sequence_header); break; - case extension_start_code: decode_extension_data(cur_pic); break; - case group_start_code: parse_group_of_pictures_header(&m_bs, *(m_group_of_pictures_header = new group_of_pictures_header_t)); break; - case picture_start_code: - new_picture = true; - if (cur_pic) out_pic(cur_pic); - cur_pic = new_pic(); - parse_picture_header(&m_bs, cur_pic->m_picture_header); - if (cur_pic->m_picture_header.picture_coding_type == picture_coding_type_pred || cur_pic->m_picture_header.picture_coding_type == picture_coding_type_intra) { - cur_pic->add_dependency(ref_frames[1]); - ref_frames[0] = ref_frames[1]; - ref_frames[1] = cur_pic; - } else - for (auto* pic : ref_frames) cur_pic->add_dependency(pic); - break; - case user_data_start_code: decode_user_data(); break; - case sequence_error_code: - case sequence_end_code: - flush(cur_pic); - sequence_end = true; - break; - default: - if ((start_code >= slice_start_code_min) && (start_code <= slice_start_code_max)) { - if (new_picture) cur_pic->init(); + if (prev_start_code) { + last_start_code = ptr; + BITSTREAM((&m_bs)); + bit_idx = 32; + bit_ptr = (uint32_t*)(prev_start_code + 4); + bit_buf = (uint64_t)bswap_32(*((uint32_t*)prev_start_code)); + uint8_t start_code = *(prev_start_code + 3); + switch (start_code) { + case sequence_header_code: parse_sequence_header(&m_bs, m_sequence_header); break; + case extension_start_code: decode_extension_data(cur_pic); break; + case group_start_code: parse_group_of_pictures_header(&m_bs, *(m_group_of_pictures_header = new group_of_pictures_header_t)); break; + case picture_start_code: + new_picture = true; + new_buffer = true; + if (cur_pic) out_pic(cur_pic); + cur_pic = new_pic(); + parse_picture_header(&m_bs, cur_pic->m_picture_header); + if (cur_pic->m_picture_header.picture_coding_type == picture_coding_type_pred || cur_pic->m_picture_header.picture_coding_type == picture_coding_type_intra) { + cur_pic->add_dependency(ref_frames[1]); + ref_frames[0] = ref_frames[1]; + ref_frames[1] = cur_pic; + } + else + for (auto* pic : ref_frames) cur_pic->add_dependency(pic); + break; + case user_data_start_code: decode_user_data(); break; + case sequence_error_code: + case sequence_end_code: break; + default: + if ((start_code >= slice_start_code_min) && (start_code <= slice_start_code_max)) { + if (new_buffer) cur_pic->subscribe_buffer(buf_handle); + if (new_picture) cur_pic->init(); #ifdef MP2V_MT - auto tsk = new mp2v_slice_task_c(); - tsk->bs = m_bs; - cur_pic->add_slice_task(tsk); + auto tsk = new mp2v_slice_task_c(); + tsk->bs = m_bs; + cur_pic->add_slice_task(tsk); #else - cur_pic->decode_slice(m_bs); + cur_pic->decode_slice(m_bs); #endif - new_picture = false; + new_picture = false; + new_buffer = false; + } } } + prev_start_code = ptr; }); - if (!sequence_end) - flush(cur_pic); - return true; + + if (last_start_code) + consumed = (last_start_code - buffer); + else { + consumed = 0; + registered_buffers.pop_back(); + delete buf_handle; + buf_handle = nullptr; + } + return buf_handle; } void mp2v_slice_task_c::decode() { @@ -423,4 +444,6 @@ mp2v_decoder_c::~mp2v_decoder_c() { delete pic; } #endif + for (auto* buf_handle : registered_buffers) + delete buf_handle; } \ No newline at end of file diff --git a/src/core/decoder.h b/src/core/decoder.h index c39b181..599b653 100644 --- a/src/core/decoder.h +++ b/src/core/decoder.h @@ -31,6 +31,32 @@ struct decoder_config_t { bool reordering; }; +class buffer_handle_t { +public: + buffer_handle_t() : waiters(0) {}; + void release() { + std::unique_lock lck(mtx); + auto num_waiters = --waiters; + bool released = (num_waiters == 0); + lck.unlock(); + if (released) cv_free.notify_all(); + } + + void wait_for_release() { + std::unique_lock lck(mtx); + cv_free.wait(lck, [this] { return waiters.load() == 0; }); + } + + void add_waiter() { + waiters++; + } + +private: + std::atomic waiters; + std::condition_variable cv_free; + std::mutex mtx; +}; + class frame_c { friend class mp2v_picture_c; public: @@ -62,7 +88,12 @@ class mp2v_picture_c : public picture_task_c { bool decode_slice(bitstream_reader_c bs); frame_c* get_frame() { return m_frame; } + void reset() { picture_task_c::reset(); subscribed_buffers.clear(); } + void subscribe_buffer(buffer_handle_t* handle) { subscribed_buffers.push_back(handle); handle->add_waiter(); } + private: + void on_completed(); + std::vector subscribed_buffers; mp2v_decoder_c* m_dec; uint8_t quantiser_matrices[4][64]; parse_macroblock_func_t m_parse_macroblock_func = nullptr; @@ -96,8 +127,8 @@ class mp2v_decoder_c { }; ~mp2v_decoder_c(); bool decoder_init(const decoder_config_t& config, std::function renderer); - bool decode(uint8_t* buffer, int len); - void flush(mp2v_picture_c* cur_pic = nullptr); + buffer_handle_t* decode(uint8_t* buffer, int len, int& consumed); + void flush(); protected: bool decode_user_data(); @@ -107,6 +138,7 @@ class mp2v_decoder_c { bool reordering = true; bitstream_reader_c m_bs; mp2v_picture_c* ref_frames[2] = { 0 }; + std::vector registered_buffers; std::function render_func; std::thread* render_thread = nullptr; static void decoder_output_scheduler(mp2v_decoder_c* dec); @@ -119,6 +151,9 @@ class mp2v_decoder_c { ThreadSafeQ m_free_pics; std::vector m_pictures_pool; #endif + // Decoder state variables + mp2v_picture_c* cur_pic = nullptr; + bool new_picture = false; public: // headers & user data diff --git a/src/core/threads.cpp b/src/core/threads.cpp index 0c54291..ffc83ec 100644 --- a/src/core/threads.cpp +++ b/src/core/threads.cpp @@ -87,6 +87,7 @@ bool picture_task_c::slice_done() { pic_done = (done_slices_ >= slices_tasks.size()); } if (pic_done) { + on_completed(); for (int i = 0; i < num_dependencies; i++) if (dependencies[i]) dependencies[i]->release_waiter(); diff --git a/src/core/threads.h b/src/core/threads.h index e608ab0..c26b610 100644 --- a/src/core/threads.h +++ b/src/core/threads.h @@ -40,6 +40,7 @@ class picture_task_c { void render_done(); protected: + virtual void on_completed() {}; picture_task_c* dependencies[MAX_NUM_DEPENDENCIES] = {}; int num_dependencies = 0; diff --git a/tiny_decoder/tiny_mp2v_dec.cpp b/tiny_decoder/tiny_mp2v_dec.cpp index 4cd92ff..c053898 100644 --- a/tiny_decoder/tiny_mp2v_dec.cpp +++ b/tiny_decoder/tiny_mp2v_dec.cpp @@ -6,7 +6,8 @@ #include "sample_args.h" #include "core/decoder.h" -std::vector> buffer_pool; +constexpr int CHUNK_SIZE = 65536; +constexpr int MAX_BUFFER_SIZE = CHUNK_SIZE * 512; void write_yuv(FILE* fp, frame_c* frame) { for (int i = 0; i < 3; i++) { @@ -16,21 +17,34 @@ void write_yuv(FILE* fp, frame_c* frame) { } } -void load_bitstream(std::string input_file) { - std::ifstream fp(input_file, std::ios::binary); +void decode_file(std::string filename, mp2v_decoder_c& dec) { + FILE* fp = fopen(filename.c_str(), "rb"); + uint8_t* buffer = new uint8_t[MAX_BUFFER_SIZE]; + uint8_t* write_buf = &buffer[0]; + uint8_t* read_buf = &buffer[0]; + int consumed_bytes = 0; + int rest_bytes = 0; + while (1) { + size_t ret_code = fread(write_buf, 1, CHUNK_SIZE, fp); + write_buf += ret_code; - // Calculate size of buffer - fp.seekg(0, std::ios_base::end); - std::size_t size = fp.tellg(); - size = ((size + 15) & (~15)); - fp.seekg(0, std::ios_base::beg); + bool end_of_file = feof(fp); + if (end_of_file) { + *((uint32_t*)write_buf) = 0xb7010000; // end of sequence code + ret_code += 4; + ret_code = (ret_code + 15) & ~15; + } - // Allocate buffer - buffer_pool.resize(size / sizeof(uint32_t)); + size_t len = rest_bytes + ret_code; + dec.decode(read_buf, len, consumed_bytes); + read_buf += consumed_bytes; + rest_bytes = (len - consumed_bytes); - // read file - fp.read((char*)&buffer_pool[0], size); - fp.close(); + if (end_of_file) break; + } + dec.flush(); + delete[] buffer; + fclose(fp); } int main(int argc, char* argv[]) @@ -44,12 +58,11 @@ int main(int argc, char* argv[]) if (output_file) { FILE* fp = fopen(output_file->c_str(), "wb"); if (bitstream_file && fp) { - load_bitstream(*bitstream_file); mp2v_decoder_c mp2v_decoder({ 1920, 1088, 2, 10, 8, true }, [fp](frame_c* frame) { write_yuv(fp, frame); }); const auto start = std::chrono::system_clock::now(); - mp2v_decoder.decode((uint8_t*)&buffer_pool[0], buffer_pool.size() * 4); + decode_file(*bitstream_file, mp2v_decoder); auto elapsed_ms = std::chrono::duration_cast(std::chrono::system_clock::now() - start); printf("Time = %.2f ms\n", static_cast(elapsed_ms.count())); From e542b4ed570dc5edd2436cc2aabbffbab96480fc Mon Sep 17 00:00:00 2001 From: VOvchinnikov Date: Mon, 1 Nov 2021 17:12:25 +0700 Subject: [PATCH 2/7] [cleanup] buffers handlers --- src/core/decoder.cpp | 22 ++-------------------- src/core/decoder.h | 34 +--------------------------------- 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/src/core/decoder.cpp b/src/core/decoder.cpp index 54b482f..04553c0 100644 --- a/src/core/decoder.cpp +++ b/src/core/decoder.cpp @@ -191,11 +191,6 @@ void mp2v_picture_c::init() { } } -void mp2v_picture_c::on_completed() { - for (auto*& subscriber : subscribed_buffers) - subscriber->release(); -} - bool mp2v_decoder_c::decode_user_data() { while (m_bs.get_next_bits(vlc_start_code.len) != vlc_start_code.value) { uint8_t data = m_bs.read_next_bits(8); @@ -282,12 +277,9 @@ void mp2v_decoder_c::out_pic(mp2v_picture_c* cur_pic) { #endif } -buffer_handle_t* mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) { +void mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) { - bool new_buffer = false; uint8_t* prev_start_code = nullptr, *last_start_code = nullptr; - buffer_handle_t* buf_handle = new buffer_handle_t(); - registered_buffers.push_back(buf_handle); m_bs.set_bitstream_buffer(buffer); scan_start_codes(buffer, buffer + len, [&](uint8_t* ptr) { @@ -304,7 +296,6 @@ buffer_handle_t* mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) case group_start_code: parse_group_of_pictures_header(&m_bs, *(m_group_of_pictures_header = new group_of_pictures_header_t)); break; case picture_start_code: new_picture = true; - new_buffer = true; if (cur_pic) out_pic(cur_pic); cur_pic = new_pic(); parse_picture_header(&m_bs, cur_pic->m_picture_header); @@ -321,7 +312,6 @@ buffer_handle_t* mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) case sequence_end_code: break; default: if ((start_code >= slice_start_code_min) && (start_code <= slice_start_code_max)) { - if (new_buffer) cur_pic->subscribe_buffer(buf_handle); if (new_picture) cur_pic->init(); #ifdef MP2V_MT auto tsk = new mp2v_slice_task_c(); @@ -331,7 +321,6 @@ buffer_handle_t* mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) cur_pic->decode_slice(m_bs); #endif new_picture = false; - new_buffer = false; } } } @@ -340,13 +329,8 @@ buffer_handle_t* mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) if (last_start_code) consumed = (last_start_code - buffer); - else { + else consumed = 0; - registered_buffers.pop_back(); - delete buf_handle; - buf_handle = nullptr; - } - return buf_handle; } void mp2v_slice_task_c::decode() { @@ -444,6 +428,4 @@ mp2v_decoder_c::~mp2v_decoder_c() { delete pic; } #endif - for (auto* buf_handle : registered_buffers) - delete buf_handle; } \ No newline at end of file diff --git a/src/core/decoder.h b/src/core/decoder.h index 599b653..7fbda08 100644 --- a/src/core/decoder.h +++ b/src/core/decoder.h @@ -31,32 +31,6 @@ struct decoder_config_t { bool reordering; }; -class buffer_handle_t { -public: - buffer_handle_t() : waiters(0) {}; - void release() { - std::unique_lock lck(mtx); - auto num_waiters = --waiters; - bool released = (num_waiters == 0); - lck.unlock(); - if (released) cv_free.notify_all(); - } - - void wait_for_release() { - std::unique_lock lck(mtx); - cv_free.wait(lck, [this] { return waiters.load() == 0; }); - } - - void add_waiter() { - waiters++; - } - -private: - std::atomic waiters; - std::condition_variable cv_free; - std::mutex mtx; -}; - class frame_c { friend class mp2v_picture_c; public: @@ -88,12 +62,7 @@ class mp2v_picture_c : public picture_task_c { bool decode_slice(bitstream_reader_c bs); frame_c* get_frame() { return m_frame; } - void reset() { picture_task_c::reset(); subscribed_buffers.clear(); } - void subscribe_buffer(buffer_handle_t* handle) { subscribed_buffers.push_back(handle); handle->add_waiter(); } - private: - void on_completed(); - std::vector subscribed_buffers; mp2v_decoder_c* m_dec; uint8_t quantiser_matrices[4][64]; parse_macroblock_func_t m_parse_macroblock_func = nullptr; @@ -127,7 +96,7 @@ class mp2v_decoder_c { }; ~mp2v_decoder_c(); bool decoder_init(const decoder_config_t& config, std::function renderer); - buffer_handle_t* decode(uint8_t* buffer, int len, int& consumed); + void decode(uint8_t* buffer, int len, int& consumed); void flush(); protected: @@ -138,7 +107,6 @@ class mp2v_decoder_c { bool reordering = true; bitstream_reader_c m_bs; mp2v_picture_c* ref_frames[2] = { 0 }; - std::vector registered_buffers; std::function render_func; std::thread* render_thread = nullptr; static void decoder_output_scheduler(mp2v_decoder_c* dec); From 38b5bed07e5caf8510d63dff268e355487ab8f8a Mon Sep 17 00:00:00 2001 From: VOvchinnikov Date: Mon, 1 Nov 2021 18:49:51 +0700 Subject: [PATCH 3/7] [update] copybytes --- src/core/decoder.cpp | 27 +++++++++++++++++---------- src/core/decoder.h | 18 ++++++++++++++++-- tiny_decoder/tiny_mp2v_dec.cpp | 19 ++++++++----------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/core/decoder.cpp b/src/core/decoder.cpp index 04553c0..7a80e5b 100644 --- a/src/core/decoder.cpp +++ b/src/core/decoder.cpp @@ -277,19 +277,25 @@ void mp2v_decoder_c::out_pic(mp2v_picture_c* cur_pic) { #endif } -void mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) { +void mp2v_decoder_c::decode(uint8_t* buffer, int len) { - uint8_t* prev_start_code = nullptr, *last_start_code = nullptr; m_bs.set_bitstream_buffer(buffer); scan_start_codes(buffer, buffer + len, [&](uint8_t* ptr) { if (prev_start_code) { last_start_code = ptr; + uint8_t* p = prev_start_code; + if (cur_pic) { + p = cur_pic->bitstream_ptr; + size_t sz = last_start_code - prev_start_code; + memcpy(p, prev_start_code, sz); + cur_pic->bitstream_ptr += sz; + } BITSTREAM((&m_bs)); bit_idx = 32; - bit_ptr = (uint32_t*)(prev_start_code + 4); - bit_buf = (uint64_t)bswap_32(*((uint32_t*)prev_start_code)); - uint8_t start_code = *(prev_start_code + 3); + bit_ptr = (uint32_t*)(p + 4); + bit_buf = (uint64_t)bswap_32(*((uint32_t*)p)); + uint8_t start_code = *(p + 3); switch (start_code) { case sequence_header_code: parse_sequence_header(&m_bs, m_sequence_header); break; case extension_start_code: decode_extension_data(cur_pic); break; @@ -327,10 +333,11 @@ void mp2v_decoder_c::decode(uint8_t* buffer, int len, int& consumed) { prev_start_code = ptr; }); - if (last_start_code) - consumed = (last_start_code - buffer); - else - consumed = 0; + if (cur_pic) { + size_t sz = buffer + len - last_start_code; + memcpy(cur_pic->bitstream_ptr, prev_start_code, sz); + cur_pic->bitstream_ptr += sz; + } } void mp2v_slice_task_c::decode() { @@ -393,7 +400,7 @@ bool mp2v_decoder_c::decoder_init(const decoder_config_t &config, std::function< #ifdef MP2V_MT task_queue = new task_queue_c(num_pics, [&]() -> picture_task_c* { - return new mp2v_picture_c(this, new frame_c(width, height, chroma_format)); + return new mp2v_picture_c(this, new frame_c(width, height, chroma_format), config.bitstream_chunk_size); }); for (int i = 0; i < config.num_threads; i++) thread_pool[i] = new std::thread(threadpool_task_scheduler, this); diff --git a/src/core/decoder.h b/src/core/decoder.h index 7fbda08..8a28315 100644 --- a/src/core/decoder.h +++ b/src/core/decoder.h @@ -18,6 +18,7 @@ constexpr int MAX_NUM_THREADS = 256; constexpr int MAX_B_FRAMES = 8; constexpr int CACHE_LINE = 64; +constexpr int DEFAULT_BITSTREAM_BUFFER_SIZE = 1024*1024; class mp2v_picture_c; class mp2v_decoder_c; @@ -28,6 +29,7 @@ struct decoder_config_t { int chroma_format; int pictures_pool_size; int num_threads; + int bitstream_chunk_size; bool reordering; }; @@ -55,14 +57,24 @@ class mp2v_slice_task_c : public slice_task_c { }; class mp2v_picture_c : public picture_task_c { + friend class mp2v_decoder_c; public: - mp2v_picture_c(mp2v_decoder_c* decoder, frame_c* frame) : m_dec(decoder), m_frame(frame) {}; + mp2v_picture_c(mp2v_decoder_c* decoder, frame_c* frame, int bitstream_buffer_size = DEFAULT_BITSTREAM_BUFFER_SIZE) : + m_dec(decoder), m_frame(frame), bitstream_buffer(bitstream_buffer_size) { + bitstream_ptr = &bitstream_buffer[0]; + }; void init(); void attach(frame_c* frame) { m_frame = frame; } bool decode_slice(bitstream_reader_c bs); frame_c* get_frame() { return m_frame; } + void reset() { + picture_task_c::reset(); + bitstream_ptr = &bitstream_buffer[0]; + } private: + uint8_t* bitstream_ptr = nullptr; + std::vector bitstream_buffer; mp2v_decoder_c* m_dec; uint8_t quantiser_matrices[4][64]; parse_macroblock_func_t m_parse_macroblock_func = nullptr; @@ -96,7 +108,7 @@ class mp2v_decoder_c { }; ~mp2v_decoder_c(); bool decoder_init(const decoder_config_t& config, std::function renderer); - void decode(uint8_t* buffer, int len, int& consumed); + void decode(uint8_t* buffer, int len); void flush(); protected: @@ -120,6 +132,8 @@ class mp2v_decoder_c { std::vector m_pictures_pool; #endif // Decoder state variables + uint8_t* prev_start_code = nullptr; + uint8_t* last_start_code = nullptr; mp2v_picture_c* cur_pic = nullptr; bool new_picture = false; diff --git a/tiny_decoder/tiny_mp2v_dec.cpp b/tiny_decoder/tiny_mp2v_dec.cpp index c053898..7513bbc 100644 --- a/tiny_decoder/tiny_mp2v_dec.cpp +++ b/tiny_decoder/tiny_mp2v_dec.cpp @@ -20,26 +20,23 @@ void write_yuv(FILE* fp, frame_c* frame) { void decode_file(std::string filename, mp2v_decoder_c& dec) { FILE* fp = fopen(filename.c_str(), "rb"); uint8_t* buffer = new uint8_t[MAX_BUFFER_SIZE]; - uint8_t* write_buf = &buffer[0]; - uint8_t* read_buf = &buffer[0]; + uint8_t* buf_write = &buffer[0]; + uint8_t* buf_read = &buffer[0]; int consumed_bytes = 0; int rest_bytes = 0; while (1) { - size_t ret_code = fread(write_buf, 1, CHUNK_SIZE, fp); - write_buf += ret_code; + size_t ret_code = fread(buf_write, 1, CHUNK_SIZE, fp); + buf_write += ret_code; bool end_of_file = feof(fp); if (end_of_file) { - *((uint32_t*)write_buf) = 0xb7010000; // end of sequence code + *((uint32_t*)buf_write) = 0xb7010000; // end of sequence code ret_code += 4; ret_code = (ret_code + 15) & ~15; } - size_t len = rest_bytes + ret_code; - dec.decode(read_buf, len, consumed_bytes); - read_buf += consumed_bytes; - rest_bytes = (len - consumed_bytes); - + dec.decode(buf_read, ret_code); + buf_read += ret_code; if (end_of_file) break; } dec.flush(); @@ -58,7 +55,7 @@ int main(int argc, char* argv[]) if (output_file) { FILE* fp = fopen(output_file->c_str(), "wb"); if (bitstream_file && fp) { - mp2v_decoder_c mp2v_decoder({ 1920, 1088, 2, 10, 8, true }, [fp](frame_c* frame) { write_yuv(fp, frame); }); + mp2v_decoder_c mp2v_decoder({ 1920, 1088, 2, 10, 8, 1024 * 1024, true }, [fp](frame_c* frame) { write_yuv(fp, frame); }); const auto start = std::chrono::system_clock::now(); From 00837dff0a4758432e5ea8d4a75842ada11abb3e Mon Sep 17 00:00:00 2001 From: VOvchinnikov Date: Mon, 1 Nov 2021 19:53:37 +0700 Subject: [PATCH 4/7] [update] using display width & height --- src/core/decoder.cpp | 11 +++++++++++ src/core/decoder.h | 8 ++++++-- tiny_decoder/tiny_mp2v_dec.cpp | 4 ++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/core/decoder.cpp b/src/core/decoder.cpp index 7a80e5b..0aa5222 100644 --- a/src/core/decoder.cpp +++ b/src/core/decoder.cpp @@ -46,6 +46,7 @@ frame_c::frame_c(int width, int height, int chroma_format) { m_width [0] = width; m_height[0] = height; + m_chroma_format = chroma_format; switch (chroma_format) { case chroma_format_420: m_stride[1] = ((m_stride[0] >> 1) + CACHE_LINE - 1) & ~(CACHE_LINE - 1); @@ -76,6 +77,13 @@ frame_c::frame_c(int width, int height, int chroma_format) { #endif } +void frame_c::set_display_size(int display_width, int display_height) { + m_display_width [0] = display_width; + m_display_height[0] = display_height; + m_display_width [1] = m_display_width [2] = (m_chroma_format != chroma_format_444) ? display_width >> 1 : display_width; + m_display_height[1] = m_display_height[2] = (m_chroma_format != chroma_format_420) ? display_height : display_height >> 1; +} + frame_c::~frame_c() { #if defined(_MSC_VER) for (int i = 0; i < 3; i++) @@ -189,6 +197,9 @@ void mp2v_picture_c::init() { if (m_quant_matrix_extension->load_chroma_intra_quantiser_matrix) quantiser_matrices[2][i] = tmp[2][j]; if (m_quant_matrix_extension->load_chroma_non_intra_quantiser_matrix) quantiser_matrices[3][i] = tmp[3][j]; } + + auto sh = m_dec->m_sequence_header; + m_frame->set_display_size(sh.horizontal_size_value, sh.vertical_size_value); } bool mp2v_decoder_c::decode_user_data() { diff --git a/src/core/decoder.h b/src/core/decoder.h index 8a28315..6ac3494 100644 --- a/src/core/decoder.h +++ b/src/core/decoder.h @@ -41,11 +41,15 @@ class frame_c { uint8_t* get_planes (int plane_idx) { return m_planes[plane_idx]; } int get_strides(int plane_idx) { return m_stride[plane_idx]; } - int get_width (int plane_idx) { return m_width [plane_idx]; } - int get_height (int plane_idx) { return m_height[plane_idx]; } + int get_display_width (int plane_idx) { return m_display_width [plane_idx]; } + int get_display_height (int plane_idx) { return m_display_height[plane_idx]; } + void set_display_size (int display_width, int display_height); private: + int m_chroma_format = chroma_format_420; uint32_t m_width [3] = { 0 }; uint32_t m_height[3] = { 0 }; + uint32_t m_display_width [3] = { 0 }; + uint32_t m_display_height[3] = { 0 }; uint32_t m_stride[3] = { 0 }; uint8_t* m_planes[3] = { 0 }; }; diff --git a/tiny_decoder/tiny_mp2v_dec.cpp b/tiny_decoder/tiny_mp2v_dec.cpp index 7513bbc..64e1e4e 100644 --- a/tiny_decoder/tiny_mp2v_dec.cpp +++ b/tiny_decoder/tiny_mp2v_dec.cpp @@ -12,8 +12,8 @@ constexpr int MAX_BUFFER_SIZE = CHUNK_SIZE * 512; void write_yuv(FILE* fp, frame_c* frame) { for (int i = 0; i < 3; i++) { uint8_t* plane = frame->get_planes(i); - for (int y = 0; y < frame->get_height(i); y++, plane += frame->get_strides(i)) - fwrite(plane, 1, frame->get_width(i), fp); + for (int y = 0; y < frame->get_display_height(i); y++, plane += frame->get_strides(i)) + fwrite(plane, 1, frame->get_display_width(i), fp); } } From 8f772d3a17e2fd56a1d8c46c4ac95b85453c2175 Mon Sep 17 00:00:00 2001 From: VOvchinnikov Date: Mon, 1 Nov 2021 22:39:09 +0700 Subject: [PATCH 5/7] [update] intermediate result --- src/core/decoder.cpp | 114 ++++++++++++++++++++------------- src/core/decoder.h | 11 ++-- tiny_decoder/tiny_mp2v_dec.cpp | 2 +- 3 files changed, 76 insertions(+), 51 deletions(-) diff --git a/src/core/decoder.cpp b/src/core/decoder.cpp index 0aa5222..50b3453 100644 --- a/src/core/decoder.cpp +++ b/src/core/decoder.cpp @@ -289,65 +289,87 @@ void mp2v_decoder_c::out_pic(mp2v_picture_c* cur_pic) { } void mp2v_decoder_c::decode(uint8_t* buffer, int len) { - - m_bs.set_bitstream_buffer(buffer); + bool new_buffer = true; scan_start_codes(buffer, buffer + len, [&](uint8_t* ptr) { if (prev_start_code) { last_start_code = ptr; - uint8_t* p = prev_start_code; + uint8_t* p = nullptr; if (cur_pic) { - p = cur_pic->bitstream_ptr; - size_t sz = last_start_code - prev_start_code; - memcpy(p, prev_start_code, sz); - cur_pic->bitstream_ptr += sz; + p = cur_pic->cur_bistream_pos; + size_t sz = new_buffer ? last_start_code - buffer : last_start_code - prev_start_code; + memcpy(p, new_buffer ? buffer : prev_start_code, sz); + cur_pic->cur_bistream_pos += sz; + cur_pic->cur_bistream_pos[0] = 0; + cur_pic->cur_bistream_pos[1] = 0; + cur_pic->cur_bistream_pos[2] = 1; + if (!(cur_pic->last_start_code != nullptr && new_buffer)) cur_pic->last_start_code = p; + decode_unit(cur_pic->last_start_code); } - BITSTREAM((&m_bs)); - bit_idx = 32; - bit_ptr = (uint32_t*)(p + 4); - bit_buf = (uint64_t)bswap_32(*((uint32_t*)p)); - uint8_t start_code = *(p + 3); - switch (start_code) { - case sequence_header_code: parse_sequence_header(&m_bs, m_sequence_header); break; - case extension_start_code: decode_extension_data(cur_pic); break; - case group_start_code: parse_group_of_pictures_header(&m_bs, *(m_group_of_pictures_header = new group_of_pictures_header_t)); break; - case picture_start_code: - new_picture = true; - if (cur_pic) out_pic(cur_pic); - cur_pic = new_pic(); - parse_picture_header(&m_bs, cur_pic->m_picture_header); - if (cur_pic->m_picture_header.picture_coding_type == picture_coding_type_pred || cur_pic->m_picture_header.picture_coding_type == picture_coding_type_intra) { - cur_pic->add_dependency(ref_frames[1]); - ref_frames[0] = ref_frames[1]; - ref_frames[1] = cur_pic; - } - else - for (auto* pic : ref_frames) cur_pic->add_dependency(pic); - break; - case user_data_start_code: decode_user_data(); break; - case sequence_error_code: - case sequence_end_code: break; - default: - if ((start_code >= slice_start_code_min) && (start_code <= slice_start_code_max)) { - if (new_picture) cur_pic->init(); -#ifdef MP2V_MT - auto tsk = new mp2v_slice_task_c(); - tsk->bs = m_bs; - cur_pic->add_slice_task(tsk); -#else - cur_pic->decode_slice(m_bs); -#endif - new_picture = false; - } + else + decode_unit(prev_start_code); + + if (new_buffer) { + if (p[-1] == 0 && p[0] == 0 && p[1] == 1) + decode_unit(&p[-1]); + if (p[-2] == 0 && p[-1] == 0 && p[0] == 1) + decode_unit(&p[-2]); } } prev_start_code = ptr; + new_buffer = false; }); if (cur_pic) { size_t sz = buffer + len - last_start_code; - memcpy(cur_pic->bitstream_ptr, prev_start_code, sz); - cur_pic->bitstream_ptr += sz; + memcpy(cur_pic->cur_bistream_pos, prev_start_code, sz); + cur_pic->last_start_code = cur_pic->cur_bistream_pos; + cur_pic->cur_bistream_pos += sz; + } +} + +void mp2v_decoder_c::decode_unit(uint8_t* start_code_ptr) { + BITSTREAM((&m_bs)); + bit_idx = 32; + bit_ptr = (uint32_t*)(start_code_ptr + 4); + bit_buf = (uint64_t)bswap_32(*((uint32_t*)start_code_ptr)); + uint8_t start_code = *(start_code_ptr + 3); + switch (start_code) { + case sequence_header_code: parse_sequence_header(&m_bs, m_sequence_header); break; + case extension_start_code: decode_extension_data(cur_pic); break; + case group_start_code: parse_group_of_pictures_header(&m_bs, *(m_group_of_pictures_header = new group_of_pictures_header_t)); break; + case picture_start_code: + { + static int pic_num = 0; + ++pic_num; + } + new_picture = true; + if (cur_pic) out_pic(cur_pic); + cur_pic = new_pic(); + parse_picture_header(&m_bs, cur_pic->m_picture_header); + if (cur_pic->m_picture_header.picture_coding_type == picture_coding_type_pred || cur_pic->m_picture_header.picture_coding_type == picture_coding_type_intra) { + cur_pic->add_dependency(ref_frames[1]); + ref_frames[0] = ref_frames[1]; + ref_frames[1] = cur_pic; + } + else + for (auto* pic : ref_frames) cur_pic->add_dependency(pic); + break; + case user_data_start_code: decode_user_data(); break; + case sequence_error_code: + case sequence_end_code: break; + default: + if ((start_code >= slice_start_code_min) && (start_code <= slice_start_code_max)) { + if (new_picture) cur_pic->init(); +#ifdef MP2V_MT + auto tsk = new mp2v_slice_task_c(); + tsk->bs = m_bs; + cur_pic->add_slice_task(tsk); +#else + cur_pic->decode_slice(m_bs); +#endif + new_picture = false; + } } } diff --git a/src/core/decoder.h b/src/core/decoder.h index 6ac3494..d4f6bb4 100644 --- a/src/core/decoder.h +++ b/src/core/decoder.h @@ -13,7 +13,7 @@ #include "mb_decoder.h" #include "threads.h" -#define MP2V_MT +//#define MP2V_MT constexpr int MAX_NUM_THREADS = 256; constexpr int MAX_B_FRAMES = 8; @@ -65,7 +65,7 @@ class mp2v_picture_c : public picture_task_c { public: mp2v_picture_c(mp2v_decoder_c* decoder, frame_c* frame, int bitstream_buffer_size = DEFAULT_BITSTREAM_BUFFER_SIZE) : m_dec(decoder), m_frame(frame), bitstream_buffer(bitstream_buffer_size) { - bitstream_ptr = &bitstream_buffer[0]; + cur_bistream_pos = &bitstream_buffer[0]; }; void init(); void attach(frame_c* frame) { m_frame = frame; } @@ -73,11 +73,13 @@ class mp2v_picture_c : public picture_task_c { frame_c* get_frame() { return m_frame; } void reset() { picture_task_c::reset(); - bitstream_ptr = &bitstream_buffer[0]; + cur_bistream_pos = &bitstream_buffer[0]; + last_start_code = nullptr; } private: - uint8_t* bitstream_ptr = nullptr; + uint8_t* last_start_code = nullptr; + uint8_t* cur_bistream_pos = nullptr; std::vector bitstream_buffer; mp2v_decoder_c* m_dec; uint8_t quantiser_matrices[4][64]; @@ -113,6 +115,7 @@ class mp2v_decoder_c { ~mp2v_decoder_c(); bool decoder_init(const decoder_config_t& config, std::function renderer); void decode(uint8_t* buffer, int len); + void decode_unit(uint8_t* start_code_ptr); void flush(); protected: diff --git a/tiny_decoder/tiny_mp2v_dec.cpp b/tiny_decoder/tiny_mp2v_dec.cpp index 64e1e4e..29eb1a8 100644 --- a/tiny_decoder/tiny_mp2v_dec.cpp +++ b/tiny_decoder/tiny_mp2v_dec.cpp @@ -55,7 +55,7 @@ int main(int argc, char* argv[]) if (output_file) { FILE* fp = fopen(output_file->c_str(), "wb"); if (bitstream_file && fp) { - mp2v_decoder_c mp2v_decoder({ 1920, 1088, 2, 10, 8, 1024 * 1024, true }, [fp](frame_c* frame) { write_yuv(fp, frame); }); + mp2v_decoder_c mp2v_decoder({ 1920, 1088, 2, 10, 8, 4 * 1024 * 1024, true }, [fp](frame_c* frame) { write_yuv(fp, frame); }); const auto start = std::chrono::system_clock::now(); From 8192e8b77535c888f4d0e8444851f950e2be9b13 Mon Sep 17 00:00:00 2001 From: VOvchinnikov Date: Mon, 1 Nov 2021 23:20:00 +0700 Subject: [PATCH 6/7] [fix][update] input buffer conversation --- src/core/decoder.h | 2 +- tiny_decoder/tiny_mp2v_dec.cpp | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/core/decoder.h b/src/core/decoder.h index d4f6bb4..f8ebe6a 100644 --- a/src/core/decoder.h +++ b/src/core/decoder.h @@ -13,7 +13,7 @@ #include "mb_decoder.h" #include "threads.h" -//#define MP2V_MT +#define MP2V_MT constexpr int MAX_NUM_THREADS = 256; constexpr int MAX_B_FRAMES = 8; diff --git a/tiny_decoder/tiny_mp2v_dec.cpp b/tiny_decoder/tiny_mp2v_dec.cpp index 29eb1a8..61d6814 100644 --- a/tiny_decoder/tiny_mp2v_dec.cpp +++ b/tiny_decoder/tiny_mp2v_dec.cpp @@ -7,7 +7,9 @@ #include "core/decoder.h" constexpr int CHUNK_SIZE = 65536; -constexpr int MAX_BUFFER_SIZE = CHUNK_SIZE * 512; + +#define ALIGNUP_SIZE(size, align) ((size + align - 1) & ~(align - 1)) +#define ALIGNUP_BITSTREAM(size) ALIGNUP_SIZE(size, 16) void write_yuv(FILE* fp, frame_c* frame) { for (int i = 0; i < 3; i++) { @@ -19,24 +21,19 @@ void write_yuv(FILE* fp, frame_c* frame) { void decode_file(std::string filename, mp2v_decoder_c& dec) { FILE* fp = fopen(filename.c_str(), "rb"); - uint8_t* buffer = new uint8_t[MAX_BUFFER_SIZE]; - uint8_t* buf_write = &buffer[0]; - uint8_t* buf_read = &buffer[0]; + uint8_t* buffer = new uint8_t[ALIGNUP_BITSTREAM(CHUNK_SIZE + 4)]; int consumed_bytes = 0; int rest_bytes = 0; while (1) { - size_t ret_code = fread(buf_write, 1, CHUNK_SIZE, fp); - buf_write += ret_code; + size_t ret_code = fread(buffer, 1, CHUNK_SIZE, fp); bool end_of_file = feof(fp); if (end_of_file) { - *((uint32_t*)buf_write) = 0xb7010000; // end of sequence code - ret_code += 4; - ret_code = (ret_code + 15) & ~15; + *((uint32_t*)(buffer + ret_code)) = 0xb7010000; // end of sequence code + ret_code = ALIGNUP_BITSTREAM(ret_code + 4); } - dec.decode(buf_read, ret_code); - buf_read += ret_code; + dec.decode(buffer, ret_code); if (end_of_file) break; } dec.flush(); From 3ef7957d2440733888dfc6111b85ecb88a9e3e9b Mon Sep 17 00:00:00 2001 From: VOvchinnikov Date: Fri, 5 Nov 2021 18:06:28 +0700 Subject: [PATCH 7/7] [fix] --- src/core/decoder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/decoder.cpp b/src/core/decoder.cpp index 50b3453..6ba60fe 100644 --- a/src/core/decoder.cpp +++ b/src/core/decoder.cpp @@ -192,10 +192,10 @@ void mp2v_picture_c::init() { } for (int i = 0; i < 64; i++) { int j = g_shuffle[pcext.alternate_scan][i]; - if (m_quant_matrix_extension->load_intra_quantiser_matrix) quantiser_matrices[0][i] = tmp[0][j]; - if (m_quant_matrix_extension->load_non_intra_quantiser_matrix) quantiser_matrices[1][i] = tmp[1][j]; - if (m_quant_matrix_extension->load_chroma_intra_quantiser_matrix) quantiser_matrices[2][i] = tmp[2][j]; - if (m_quant_matrix_extension->load_chroma_non_intra_quantiser_matrix) quantiser_matrices[3][i] = tmp[3][j]; + quantiser_matrices[0][i] = tmp[0][j]; + quantiser_matrices[1][i] = tmp[1][j]; + quantiser_matrices[2][i] = tmp[2][j]; + quantiser_matrices[3][i] = tmp[3][j]; } auto sh = m_dec->m_sequence_header;