Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 97 additions & 52 deletions src/core/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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++)
Expand Down Expand Up @@ -184,11 +192,14 @@ 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;
m_frame->set_display_size(sh.horizontal_size_value, sh.vertical_size_value);
}

bool mp2v_decoder_c::decode_user_data() {
Expand Down Expand Up @@ -241,10 +252,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])
Expand Down Expand Up @@ -275,57 +288,89 @@ void mp2v_decoder_c::out_pic(mp2v_picture_c* cur_pic) {
#endif
}

bool mp2v_decoder_c::decode(uint8_t* buffer, int len) {

m_bs.set_bitstream_buffer(buffer);
bool new_picture = false, sequence_end = false;
mp2v_picture_c* cur_pic = nullptr;
void mp2v_decoder_c::decode(uint8_t* buffer, int len) {
bool new_buffer = true;

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;
uint8_t* p = nullptr;
if (cur_pic) {
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);
}
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->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);
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;
}
});
if (!sequence_end)
flush(cur_pic);
return true;
}
}

void mp2v_slice_task_c::decode() {
Expand Down Expand Up @@ -388,7 +433,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);
Expand Down
34 changes: 29 additions & 5 deletions src/core/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,6 +29,7 @@ struct decoder_config_t {
int chroma_format;
int pictures_pool_size;
int num_threads;
int bitstream_chunk_size;
bool reordering;
};

Expand All @@ -39,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 };
};
Expand All @@ -55,14 +61,26 @@ 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) {
cur_bistream_pos = &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();
cur_bistream_pos = &bitstream_buffer[0];
last_start_code = nullptr;
}

private:
uint8_t* last_start_code = nullptr;
uint8_t* cur_bistream_pos = nullptr;
std::vector<uint8_t> bitstream_buffer;
mp2v_decoder_c* m_dec;
uint8_t quantiser_matrices[4][64];
parse_macroblock_func_t m_parse_macroblock_func = nullptr;
Expand Down Expand Up @@ -96,8 +114,9 @@ class mp2v_decoder_c {
};
~mp2v_decoder_c();
bool decoder_init(const decoder_config_t& config, std::function<void(frame_c*)> renderer);
bool decode(uint8_t* buffer, int len);
void flush(mp2v_picture_c* cur_pic = nullptr);
void decode(uint8_t* buffer, int len);
void decode_unit(uint8_t* start_code_ptr);
void flush();

protected:
bool decode_user_data();
Expand All @@ -119,6 +138,11 @@ class mp2v_decoder_c {
ThreadSafeQ<mp2v_picture_c*> m_free_pics;
std::vector<mp2v_picture_c*> 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;

public:
// headers & user data
Expand Down
1 change: 1 addition & 0 deletions src/core/threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/core/threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
45 changes: 26 additions & 19 deletions tiny_decoder/tiny_mp2v_dec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,39 @@
#include "sample_args.h"
#include "core/decoder.h"

std::vector<uint32_t, AlignmentAllocator<uint8_t, 32>> buffer_pool;
constexpr int CHUNK_SIZE = 65536;

#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++) {
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);
}
}

void load_bitstream(std::string input_file) {
std::ifstream fp(input_file, std::ios::binary);

// 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);
void decode_file(std::string filename, mp2v_decoder_c& dec) {
FILE* fp = fopen(filename.c_str(), "rb");
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(buffer, 1, CHUNK_SIZE, fp);

// Allocate buffer
buffer_pool.resize(size / sizeof(uint32_t));
bool end_of_file = feof(fp);
if (end_of_file) {
*((uint32_t*)(buffer + ret_code)) = 0xb7010000; // end of sequence code
ret_code = ALIGNUP_BITSTREAM(ret_code + 4);
}

// read file
fp.read((char*)&buffer_pool[0], size);
fp.close();
dec.decode(buffer, ret_code);
if (end_of_file) break;
}
dec.flush();
delete[] buffer;
fclose(fp);
}

int main(int argc, char* argv[])
Expand All @@ -44,12 +52,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); });
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();

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::milliseconds>(std::chrono::system_clock::now() - start);
printf("Time = %.2f ms\n", static_cast<double>(elapsed_ms.count()));
Expand Down