From a56a1c9aa60c62be51aaa89f6d957f2eb456a478 Mon Sep 17 00:00:00 2001 From: Marko Viitanen Date: Tue, 5 Jun 2012 15:38:54 +0300 Subject: [PATCH] NAL writing and dummy SPS/PPS generation --- build/VS2010/HEVC_encoder.vcxproj | 2 + build/VS2010/HEVC_encoder.vcxproj.filters | 6 ++ src/bitstream.c | 9 +- src/bitstream.h | 6 +- src/encmain.c | 1 + src/encoder.c | 119 +++++++++++++++++++++- src/encoder.h | 4 + src/nal.c | 68 +++++++++++++ src/nal.h | 17 ++++ 9 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 src/nal.c create mode 100644 src/nal.h diff --git a/build/VS2010/HEVC_encoder.vcxproj b/build/VS2010/HEVC_encoder.vcxproj index 6622f69f..d0e86ec8 100644 --- a/build/VS2010/HEVC_encoder.vcxproj +++ b/build/VS2010/HEVC_encoder.vcxproj @@ -83,6 +83,7 @@ + @@ -91,6 +92,7 @@ + diff --git a/build/VS2010/HEVC_encoder.vcxproj.filters b/build/VS2010/HEVC_encoder.vcxproj.filters index dce2d423..dae96b0e 100644 --- a/build/VS2010/HEVC_encoder.vcxproj.filters +++ b/build/VS2010/HEVC_encoder.vcxproj.filters @@ -33,6 +33,9 @@ Source Files + + Source Files + @@ -53,5 +56,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/src/bitstream.c b/src/bitstream.c index 32c697bc..212c234d 100644 --- a/src/bitstream.c +++ b/src/bitstream.c @@ -71,9 +71,8 @@ void bitstream_init(bitstream* stream) { stream->cur_byte=0; stream->cur_bit=0; - stream->buffer_pos = 0; - memset(stream->data, 0, sizeof(uint32_t)*32); - + stream->output = 0; + memset(stream->data, 0, sizeof(uint32_t)*32); } /* @@ -181,13 +180,13 @@ void bitstream_flush(bitstream* stream) if(stream->cur_byte) { memcpy(&stream->buffer[stream->buffer_pos],&stream->data[0],stream->cur_byte*4); - stream->buffer_pos = stream->cur_byte*4; + stream->buffer_pos += stream->cur_byte*4; } if(stream->cur_bit>>3) { memcpy(&stream->buffer[stream->buffer_pos],&stream->data[stream->cur_byte],stream->cur_bit>>3); - stream->buffer_pos = stream->cur_bit>>3; + stream->buffer_pos += stream->cur_bit>>3; } } //Stream flushed, zero out the values diff --git a/src/bitstream.h b/src/bitstream.h index f72101cb..91a304bd 100644 --- a/src/bitstream.h +++ b/src/bitstream.h @@ -26,6 +26,8 @@ typedef struct }bitTable; extern bitTable *exp_table; + +int floorLog2(unsigned int n); void bitstream_alloc(bitstream* stream, uint32_t alloc); void bitstream_init(bitstream* stream); @@ -45,8 +47,8 @@ void init_exp_golomb(uint32_t len); #ifdef _DEBUG static int WRITE_VALUE = 0; #define WRITE_U(stream, data, bits, name) { printf("%8d %40s u(%d) : %d\n",WRITE_VALUE, name,bits,data); bitstream_put(stream,data,bits); WRITE_VALUE++;} -#define WRITE_UE(stream, data, name) { printf("%8d %40s ue(v) : %d\n",WRITE_VALUE, name,data); bitstream_put_ue(stream,data); WRITE_VALUE++;} -#define WRITE_SE(stream, data, name) { printf("%8d %40s se(v) : %d\n",WRITE_VALUE, name,data); bitstream_put_se(stream,data); WRITE_VALUE++;} +#define WRITE_UE(stream, data, name) { printf("%8d %40s ue(v): %d\n",WRITE_VALUE, name,data); bitstream_put_ue(stream,data); WRITE_VALUE++;} +#define WRITE_SE(stream, data, name) { printf("%8d %40s se(v): %d\n",WRITE_VALUE, name,data); bitstream_put_se(stream,data); WRITE_VALUE++;} #else #define WRITE_U(stream, data, bits, name) { bitstream_put(stream,data,bits); } #define WRITE_UE(stream, data, name) { bitstream_put_ue(stream,data); } diff --git a/src/encmain.c b/src/encmain.c index 934e40ab..c2f7f697 100644 --- a/src/encmain.c +++ b/src/encmain.c @@ -108,6 +108,7 @@ /* Init bitstream */ bitstream_init(encoder->stream); + encoder->stream->buffer_pos = 0; bitstream_alloc(encoder->stream, 1024*1024); /* Config pointer to encoder struct */ diff --git a/src/encoder.c b/src/encoder.c index dc14506b..021561de 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -23,6 +23,7 @@ #include "encoder.h" #include "cabac.h" #include "picture.h" +#include "nal.h" void init_encoder_control(encoder_control* control,bitstream* output) {control->stream = output;}; void init_encoder_input(encoder_input* input,FILE* inputfile, uint32_t width, uint32_t height) @@ -43,6 +44,122 @@ void init_encoder_input(encoder_input* input,FILE* inputfile, uint32_t width, ui void encode_one_frame(encoder_control* encoder) { + //output parameters before first frame + if(encoder->frame == 0) + { + encode_seq_parameter_set(encoder); + bitstream_align(encoder->stream); + bitstream_flush(encoder->stream); + nal_write(encoder->output, encoder->stream->buffer, encoder->stream->buffer_pos, 1, NAL_SEQ_PARAMETER_SET, 0); + + encode_pic_parameter_set(encoder); + bitstream_align(encoder->stream); + bitstream_flush(encoder->stream); + nal_write(encoder->output, encoder->stream->buffer, encoder->stream->buffer_pos, 1, NAL_PIC_PARAMETER_SET, 0); + + } + +} + +void encode_pic_parameter_set(encoder_control* encoder) +{ +#ifdef _DEBUG + printf("=========== Picture Parameter Set ID: 0 ===========\n"); +#endif + WRITE_UE(encoder->stream, 0, "pic_parameter_set_id"); + WRITE_UE(encoder->stream, 0, "seq_parameter_set_id"); + + WRITE_U(encoder->stream, 0, 1, "sign_data_hiding_flag"); + WRITE_U(encoder->stream, 0, 1, "cabac_init_present_flag"); + + WRITE_UE(encoder->stream, 0, "num_ref_idx_l0_default_active_minus1"); + WRITE_UE(encoder->stream, 0, "num_ref_idx_l1_default_active_minus1"); + WRITE_SE(encoder->stream, 0, "pic_init_qp_minus26"); + + WRITE_U(encoder->stream, 0, 1, "constrained_intra_pred_flag"); + WRITE_U(encoder->stream, 0, 1, "enable_temporal_mvp_flag"); + + WRITE_U(encoder->stream, 0, 2, "slice_granularity"); + + WRITE_UE(encoder->stream, 0, "max_cu_qp_delta_depth"); + + WRITE_SE(encoder->stream, 0, "cb_qp_offset"); + WRITE_SE(encoder->stream, 0, "cr_qp_offset"); + + WRITE_U(encoder->stream, 0, 1, "weighted_pred_flag"); + WRITE_U(encoder->stream, 0, 2, "weighted_bipred_idc"); + + WRITE_U(encoder->stream, 1, 1, "output_flag_present_flag"); + + WRITE_U(encoder->stream, 0, 1, "deblocking_filter_control_present_flag"); + + WRITE_UE(encoder->stream, 0, "log2_parallel_merge_level_minus2"); + + WRITE_U(encoder->stream, 0, 1, "pps_extension_flag"); + +} + +void encode_seq_parameter_set(encoder_control* encoder) +{ +#ifdef _DEBUG + printf("=========== Sequence Parameter Set ID: 0 ===========\n"); +#endif + WRITE_U(encoder->stream, 0, 8, "profile_idc"); + WRITE_U(encoder->stream, 0, 8, "reserved_zero_8bits"); + WRITE_U(encoder->stream, 0, 8, "level_idc"); + WRITE_UE(encoder->stream, 0, "seq_parameter_set_id"); + WRITE_UE(encoder->stream, 0, "chroma_format_idc"); /* 0 = 4:0:0, 1 = 4:2:0, 2 = 4:2:2, 3 = 4:4:4 */ + WRITE_U(encoder->stream, 0, 3, "max_temporal_layers_minus1"); + WRITE_UE(encoder->stream, encoder->in.width, "pic_width_in_luma_samples"); + WRITE_UE(encoder->stream, encoder->in.height, "pic_height_in_luma_samples"); + WRITE_U(encoder->stream, 0, 1, "pic_cropping_flag"); + + WRITE_UE(encoder->stream, 0, "bit_depth_luma_minus8"); + WRITE_UE(encoder->stream, 0, "bit_depth_chroma_minus8"); + + WRITE_U(encoder->stream, 0, 1, "pcm_enabled_flag"); + + WRITE_U(encoder->stream, 0, 1, "qpprime_y_zero_transquant_bypass_flag"); + + WRITE_UE(encoder->stream, 0, "log2_max_pic_order_cnt_lsb_minus4"); + + WRITE_UE(encoder->stream, 0, "max_dec_pic_buffering"); + WRITE_UE(encoder->stream, 0, "num_reorder_pics"); + WRITE_UE(encoder->stream, 0, "max_latency_increase"); + + WRITE_U(encoder->stream, 0, 1, "restricted_ref_pic_lists_flag"); + + WRITE_UE(encoder->stream, 0, "log2_min_coding_block_size_minus3"); + WRITE_UE(encoder->stream, 3, "log2_diff_max_min_coding_block_size"); + WRITE_UE(encoder->stream, 0, "log2_min_transform_block_size_minus2"); + WRITE_UE(encoder->stream, 3, "log2_diff_max_min_transform_block_size"); + + WRITE_UE(encoder->stream, 2, "max_transform_hierarchy_depth_inter"); + WRITE_UE(encoder->stream, 2, "max_transform_hierarchy_depth_intra"); -} \ No newline at end of file + WRITE_U(encoder->stream, 0, 1, "scaling_list_enable_flag"); + WRITE_U(encoder->stream, 0, 1, "chroma_pred_from_luma_enabled_flag"); + WRITE_U(encoder->stream, 0, 1, "transform_skip_enabled_flag"); + + + WRITE_U(encoder->stream, 0, 1, "deblocking_filter_in_aps_enabled_flag"); + WRITE_U(encoder->stream, 0, 1, "seq_loop_filter_across_slices_enabled_flag"); + WRITE_U(encoder->stream, 0, 1, "asymmetric_motion_partitions_enabled_flag"); + WRITE_U(encoder->stream, 0, 1, "nsrqt_enabled_flag"); + WRITE_U(encoder->stream, 0, 1, "sample_adaptive_offset_enabled_flag"); + WRITE_U(encoder->stream, 0, 1, "adaptive_loop_filter_enabled_flag"); + + WRITE_U(encoder->stream, 0, 1, "temporal_id_nesting_flag"); + + WRITE_UE(encoder->stream, 0, "num_short_term_ref_pic_sets"); + + WRITE_U(encoder->stream, 0, 1, "long_term_ref_pics_present_flag"); + + WRITE_U(encoder->stream, 0, 2, "tiles_or_entropy_coding_sync_idc"); + + WRITE_U(encoder->stream, 0, 1, "sps_extension_flag"); + +} + + diff --git a/src/encoder.h b/src/encoder.h index af6d77b1..66956d01 100644 --- a/src/encoder.h +++ b/src/encoder.h @@ -53,4 +53,8 @@ void init_encoder_control(encoder_control* control,bitstream* output); void init_encoder_input(encoder_input* input,FILE* inputfile, uint32_t width, uint32_t height); void encode_one_frame(encoder_control* encoder); + +void encode_seq_parameter_set(encoder_control* encoder); +void encode_pic_parameter_set(encoder_control* encoder); + #endif \ No newline at end of file diff --git a/src/nal.c b/src/nal.c new file mode 100644 index 00000000..7ffb4ee9 --- /dev/null +++ b/src/nal.c @@ -0,0 +1,68 @@ +/** + * HEVC Encoder + * - Marko Viitanen ( fador at iki.fi ), Tampere University of Technology, Department of Computer Systems. + */ + +/*! \file nal.c + \brief NAL + \author Marko Viitanen + \date 2012-06 + + NAL functions +*/ + + +#include +#include +#include +#include "global.h" +#include "config.h" +#include "encoder.h" +#include "cabac.h" +#include "picture.h" +#include "nal.h" + +void nal_write(FILE* output, uint8_t* buffer, uint32_t buffer_len, uint8_t nal_ref, uint8_t nal_type, uint8_t temporal_id) +{ + uint8_t byte; + uint32_t i; + uint8_t zerocount=0; + uint8_t emulation_prevention_three_byte = 0x03; + uint8_t start_code_prefix_one_3bytes = 0x01; + uint8_t zero = 0x00; + + //start_code_prefix_one_3bytes + fwrite(&zero, 1, 1, output); + fwrite(&zero, 1, 1, output); + fwrite(&zero, 1, 1, output); + fwrite(&start_code_prefix_one_3bytes, 1, 1, output); + + //forbidden_zero_flag(1) + nal_ref_flag(1) + nal_unit_type(6) + byte = nal_ref<<6 | nal_type; + fwrite(&byte, 1, 1, output); + + //Temporal_id(3) + reserved_one_5bits(5) + byte = temporal_id << 5 | 1; + fwrite(&byte, 1, 1, output); + + /* Write out bytes and add emulation_prevention_three_byte when needed */ + for(i = 0; i < buffer_len; i++) + { + if(zerocount == 2 && buffer[i] < 4) /* Prevent 0x0000 + 00/01/02/03 */ + { + /* Inserting 0x03 */ + fwrite(&emulation_prevention_three_byte, 1, 1, output); + zerocount = 0; + } + if(buffer[i] == 0) + zerocount++; + else + zerocount = 0; + + fwrite(&buffer[i], 1, 1, output); + } + //If last byte was 0, add emulation_prevention_three_byte + if(buffer[buffer_len-1] == 0) + fwrite(&emulation_prevention_three_byte, 1, 1, output); + +} \ No newline at end of file diff --git a/src/nal.h b/src/nal.h new file mode 100644 index 00000000..0ebe9610 --- /dev/null +++ b/src/nal.h @@ -0,0 +1,17 @@ +/** + * HEVC Encoder + * - Marko Viitanen ( fador at iki.fi ), Tampere University of Technology, Department of Computer Systems 2012. + */ + +/*! \file nal.h + \brief NAL + \author Marko Viitanen + \date 2012-06 + + NAL function headers +*/ + +#define NAL_SEQ_PARAMETER_SET 7 +#define NAL_PIC_PARAMETER_SET 8 + +void nal_write(FILE* output, uint8_t* buffer, uint32_t buffer_len, uint8_t nal_ref, uint8_t nal_type, uint8_t temporal_id); \ No newline at end of file