summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--encode2.c555
-rw-r--r--hevc.c711
-rw-r--r--hevc.h84
3 files changed, 821 insertions, 529 deletions
diff --git a/encode2.c b/encode2.c
index 6980850..33bec32 100644
--- a/encode2.c
+++ b/encode2.c
@@ -30,20 +30,9 @@
#include "bitstream.h"
#include "encode.h"
#include "gpu.h"
+#include "hevc.h"
#include "toolbox/utils.h"
-#define HEVC_SLICE_TYPE_B 0
-#define HEVC_SLICE_TYPE_P 1
-#define HEVC_SLICE_TYPE_I 2
-
-#define HEVC_NUT_BLA_W_LP 16
-#define HEVC_NUT_IDR_W_RADL 19
-#define HEVC_NUT_IDR_N_LP 20
-#define HEVC_NUT_RSV_IRAP_VCL23 23
-#define HEVC_NUT_VPS 32
-#define HEVC_NUT_SPS 33
-#define HEVC_NUT_PPS 34
-
struct EncodeContext {
struct GpuContext* gpu_context;
uint32_t width;
@@ -510,515 +499,6 @@ static bool UploadPackedBuffer(const struct EncodeContext* encode_context,
(bit_length + 7) / 8, data, presult);
}
-static void PackVpsRbsp(struct Bitstream* bitstream,
- const VAEncSequenceParameterBufferHEVC* seq) {
- char buffer[64];
- struct Bitstream vps_rbsp = {
- .data = buffer,
- .size = 0,
- };
-
- BitstreamAppend(bitstream, 32, 0x00000001);
- BitstreamAppend(bitstream, 1, 0); // forbidden_zero_bit
- BitstreamAppend(bitstream, 6, HEVC_NUT_VPS);
- BitstreamAppend(bitstream, 6, 0); // nuh_layer_id
- BitstreamAppend(bitstream, 3, 1); // nuh_temporal_id_plus1
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&vps_rbsp, 4, 0); // vps_video_parameter_set_id
- BitstreamAppend(&vps_rbsp, 1, 1); // vps_base_layer_internal_flag
- BitstreamAppend(&vps_rbsp, 1, 1); // vps_base_layer_available_flag
- BitstreamAppend(&vps_rbsp, 6, 0); // vps_max_layers_minus1
- BitstreamAppend(&vps_rbsp, 3, 0); // vps_max_sub_layers_minus1
- BitstreamAppend(&vps_rbsp, 1, 1); // vps_temporal_id_nesting_flag
- BitstreamAppend(&vps_rbsp, 16, 0xffff); // vps_reserved_0xffff_16bits
-
- // mburakov: Below is profile_tier_level structure.
- BitstreamAppend(&vps_rbsp, 2, 0); // general_profile_space
- BitstreamAppend(&vps_rbsp, 1, seq->general_tier_flag);
- BitstreamAppend(&vps_rbsp, 5, seq->general_profile_idc);
- BitstreamAppend(&vps_rbsp, 32, 1 << (31 - seq->general_profile_idc));
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&vps_rbsp, 1, 1); // general_progressive_source_flag
- BitstreamAppend(&vps_rbsp, 1, 0); // general_interlaced_source_flag
- BitstreamAppend(&vps_rbsp, 1, 1); // general_non_packed_constraint_flag
- BitstreamAppend(&vps_rbsp, 1, 1); // general_frame_only_constraint_flag
- BitstreamAppend(&vps_rbsp, 24, 0); // general_reserved_zero_43bits
- BitstreamAppend(&vps_rbsp, 19, 0); // general_reserved_zero_43bits
- BitstreamAppend(&vps_rbsp, 1, 0); // general_inbld_flag (TODO)
-
- BitstreamAppend(&vps_rbsp, 8, seq->general_level_idc);
- // mburakov: Above is profile_tier_level structure.
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&vps_rbsp, 1, 0); // vps_sub_layer_ordering_info_present_flag
-
- // mburakov: No B-frames.
- BitstreamAppendUE(&vps_rbsp, 1); // vps_max_dec_pic_buffering_minus1 (TODO)
- BitstreamAppendUE(&vps_rbsp, 0); // vps_max_num_reorder_pics
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppendUE(&vps_rbsp, 0); // vps_max_latency_increase_plus1
- BitstreamAppend(&vps_rbsp, 6, 0); // vps_max_layer_id
- BitstreamAppendUE(&vps_rbsp, 0); // vps_num_layer_sets_minus1
- BitstreamAppend(&vps_rbsp, 1, 1); // vps_timing_info_present_flag (TODO)
-
- // mburakov: 60 frames per second.
- BitstreamAppend(&vps_rbsp, 32, 1); // vps_num_units_in_tick
- BitstreamAppend(&vps_rbsp, 32, 60); // vps_time_scale
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&vps_rbsp, 1, 0); // vps_poc_proportional_to_timing_flag
- BitstreamAppendUE(&vps_rbsp, 0); // vps_num_hrd_parameters
- BitstreamAppend(&vps_rbsp, 1, 0); // vps_extension_flag
-
- // mburakov: Below is rbsp_trailing_bits structure.
- BitstreamAppend(&vps_rbsp, 1, 1); // rbsp_stop_one_bit
- BitstreamByteAlign(&vps_rbsp); // rbsp_alignment_zero_bit
-
- BitstreamInflate(bitstream, &vps_rbsp);
-}
-
-static void PackSpsRbsp(struct Bitstream* bitstream,
- const VAEncSequenceParameterBufferHEVC* seq,
- uint32_t crop_width, uint32_t crop_height) {
- char buffer[64];
- struct Bitstream sps_rbsp = {
- .data = buffer,
- .size = 0,
- };
-
- BitstreamAppend(bitstream, 32, 0x00000001);
- BitstreamAppend(bitstream, 1, 0); // forbidden_zero_bit
- BitstreamAppend(bitstream, 6, HEVC_NUT_SPS);
- BitstreamAppend(bitstream, 6, 0); // nuh_layer_id
- BitstreamAppend(bitstream, 3, 1); // nuh_temporal_id_plus1
-
- BitstreamAppend(&sps_rbsp, 4, 0); // sps_video_parameter_set_id
- BitstreamAppend(&sps_rbsp, 3, 0); // sps_max_sub_layers_minus1
- BitstreamAppend(&sps_rbsp, 1, 1); // sps_temporal_id_nesting_flag
-
- // mburakov: Below is profile_tier_level structure.
- BitstreamAppend(&sps_rbsp, 2, 0); // general_profile_space
- BitstreamAppend(&sps_rbsp, 1, seq->general_tier_flag);
- BitstreamAppend(&sps_rbsp, 5, seq->general_profile_idc);
- BitstreamAppend(&sps_rbsp, 32, 1 << (31 - seq->general_profile_idc));
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&sps_rbsp, 1, 1); // general_progressive_source_flag
- BitstreamAppend(&sps_rbsp, 1, 0); // general_interlaced_source_flag
- BitstreamAppend(&sps_rbsp, 1, 1); // general_non_packed_constraint_flag
- BitstreamAppend(&sps_rbsp, 1, 1); // general_frame_only_constraint_flag
- BitstreamAppend(&sps_rbsp, 24, 0); // general_reserved_zero_43bits
- BitstreamAppend(&sps_rbsp, 19, 0); // general_reserved_zero_43bits
- BitstreamAppend(&sps_rbsp, 1, 0); // general_inbld_flag (TODO)
-
- BitstreamAppend(&sps_rbsp, 8, seq->general_level_idc);
- // mburakov: Above is profile_tier_level structure.
-
- BitstreamAppendUE(&sps_rbsp, 0); // sps_seq_parameter_set_id
- BitstreamAppendUE(&sps_rbsp, seq->seq_fields.bits.chroma_format_idc);
- BitstreamAppendUE(&sps_rbsp, seq->pic_width_in_luma_samples);
- BitstreamAppendUE(&sps_rbsp, seq->pic_height_in_luma_samples);
- if (crop_width != seq->pic_width_in_luma_samples ||
- crop_height != seq->pic_height_in_luma_samples) {
- uint32_t crop_win_right_offset_in_chroma_samples =
- (seq->pic_width_in_luma_samples - crop_width) / 2;
- uint32_t crop_win_bottom_offset_in_chroma_samples =
- (seq->pic_height_in_luma_samples - crop_height) / 2;
- BitstreamAppend(&sps_rbsp, 1, 1); // conformance_window_flag
- BitstreamAppendUE(&sps_rbsp, 0); // conf_win_left_offset
- BitstreamAppendUE(&sps_rbsp, crop_win_right_offset_in_chroma_samples);
- BitstreamAppendUE(&sps_rbsp, 0); // conf_win_top_offset
- BitstreamAppendUE(&sps_rbsp, crop_win_bottom_offset_in_chroma_samples);
- } else {
- BitstreamAppend(&sps_rbsp, 1, 0); // conformance_window_flag
- }
-
- BitstreamAppendUE(&sps_rbsp, seq->seq_fields.bits.bit_depth_luma_minus8);
- BitstreamAppendUE(&sps_rbsp, seq->seq_fields.bits.bit_depth_chroma_minus8);
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppendUE(&sps_rbsp, 8); // log2_max_pic_order_cnt_lsb_minus4
- BitstreamAppend(&sps_rbsp, 1, 0); // sps_sub_layer_ordering_info_present_flag
-
- // mburakov: No B-frames.
- BitstreamAppendUE(&sps_rbsp, 1); // sps_max_dec_pic_buffering_minus1 (TODO)
- BitstreamAppendUE(&sps_rbsp, 0); // sps_max_num_reorder_pics
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppendUE(&sps_rbsp, 0); // sps_max_latency_increase_plus1
-
- BitstreamAppendUE(&sps_rbsp, seq->log2_min_luma_coding_block_size_minus3);
- BitstreamAppendUE(&sps_rbsp, seq->log2_diff_max_min_luma_coding_block_size);
- BitstreamAppendUE(&sps_rbsp, seq->log2_min_transform_block_size_minus2);
- BitstreamAppendUE(&sps_rbsp, seq->log2_diff_max_min_transform_block_size);
- BitstreamAppendUE(&sps_rbsp, seq->max_transform_hierarchy_depth_inter);
- BitstreamAppendUE(&sps_rbsp, seq->max_transform_hierarchy_depth_intra);
- BitstreamAppend(&sps_rbsp, 1, seq->seq_fields.bits.scaling_list_enabled_flag);
- // mburakov: scaling list details are absent because scaling_list_enabled_flag
- // is hardcoded to zero during sps initialization.
- BitstreamAppend(&sps_rbsp, 1, seq->seq_fields.bits.amp_enabled_flag);
- BitstreamAppend(&sps_rbsp, 1,
- seq->seq_fields.bits.sample_adaptive_offset_enabled_flag);
- BitstreamAppend(&sps_rbsp, 1, seq->seq_fields.bits.pcm_enabled_flag);
- // mburakov: pcm sample details are missing because pcm_enabled_flag is
- // hardcoded to zero during sps initialization.
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppendUE(&sps_rbsp, 0); // num_short_term_ref_pic_sets
- BitstreamAppend(&sps_rbsp, 1, 0); // long_term_ref_pics_present_flag
-
- BitstreamAppend(&sps_rbsp, 1,
- seq->seq_fields.bits.sps_temporal_mvp_enabled_flag);
- BitstreamAppend(&sps_rbsp, 1,
- seq->seq_fields.bits.strong_intra_smoothing_enabled_flag);
- // TODO(mburakov): ffmpeg hardcodes vui_parameters_present_flag to zero for
- // unpacked sps, but to one for packed sps. Why???
- BitstreamAppend(&sps_rbsp, 1, 1); // vui_parameters_present_flag
-
- // mburakov: Below is vui_parameters structure.
- BitstreamAppend(&sps_rbsp, 1, 0); // aspect_ratio_info_present_flag
- BitstreamAppend(&sps_rbsp, 1, 0); // overscan_info_present_flag
- BitstreamAppend(&sps_rbsp, 1, 1); // video_signal_type_present_flag
- BitstreamAppend(&sps_rbsp, 3, 5); // video_format
- BitstreamAppend(&sps_rbsp, 1, 0); // video_full_range_flag (TODO)
- BitstreamAppend(&sps_rbsp, 1, 1); // colour_description_present_flag
- BitstreamAppend(&sps_rbsp, 8, 2); // colour_primaries (TODO)
- BitstreamAppend(&sps_rbsp, 8, 2); // transfer_characteristics (TODO)
- BitstreamAppend(&sps_rbsp, 8, 6); // matrix_coeffs (TODO)
- BitstreamAppend(&sps_rbsp, 1, 0); // chroma_loc_info_present_flag
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&sps_rbsp, 1, 0); // neutral_chroma_indication_flag
- BitstreamAppend(&sps_rbsp, 1, 0); // field_seq_flag
- BitstreamAppend(&sps_rbsp, 1, 0); // frame_field_info_present_flag
- BitstreamAppend(&sps_rbsp, 1, 0); // default_display_window_flag
-
- BitstreamAppend(&sps_rbsp, 1, 1); // vui_timing_info_present_flag (TODO)
-
- // mburakov: 60 frames per second.
- BitstreamAppend(&sps_rbsp, 32, 1); // vui_num_units_in_tick
- BitstreamAppend(&sps_rbsp, 32, 60); // vui_time_scale
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&sps_rbsp, 1, 0); // vui_poc_proportional_to_timing_flag
- BitstreamAppend(&sps_rbsp, 1, 0); // vui_hrd_parameters_present_flag
- BitstreamAppend(&sps_rbsp, 1, 1); // bitstream_restriction_flag
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&sps_rbsp, 1, 0); // tiles_fixed_structure_flag
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&sps_rbsp, 1, 1); // motion_vectors_over_pic_boundaries_flag
- BitstreamAppend(&sps_rbsp, 1, 1); // restricted_ref_pic_lists_flag
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppendUE(&sps_rbsp, 0); // min_spatial_segmentation_idc
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppendUE(&sps_rbsp, 0); // max_bytes_per_pic_denom
- BitstreamAppendUE(&sps_rbsp, 0); // max_bits_per_min_cu_denom
- BitstreamAppendUE(&sps_rbsp, 15); // log2_max_mv_length_horizontal
- BitstreamAppendUE(&sps_rbsp, 15); // log2_max_mv_length_vertical
- // mburakov: Above is vui_parameters structure.
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppend(&sps_rbsp, 1, 0); // sps_extension_present_flag (TODO)
-
- // mburakov: Below is rbsp_trailing_bits structure.
- BitstreamAppend(&sps_rbsp, 1, 1); // rbsp_stop_one_bit
- BitstreamByteAlign(&sps_rbsp); // rbsp_alignment_zero_bit
-
- BitstreamInflate(bitstream, &sps_rbsp);
-}
-
-static void PackPpsRbsp(struct Bitstream* bitstream,
- const VAEncPictureParameterBufferHEVC* pic) {
- char buffer[64];
- struct Bitstream pps_rbsp = {
- .data = buffer,
- .size = 0,
- };
-
- BitstreamAppend(bitstream, 32, 0x00000001);
- BitstreamAppend(bitstream, 1, 0); // forbidden_zero_bit
- BitstreamAppend(bitstream, 6, HEVC_NUT_PPS);
- BitstreamAppend(bitstream, 6, 0); // nuh_layer_id
- BitstreamAppend(bitstream, 3, 1); // nuh_temporal_id_plus1
-
- // mburakov: ffmpeg hardcodes the parameters below.
- BitstreamAppendUE(&pps_rbsp, 0); // pps_pic_parameter_set_id
- BitstreamAppendUE(&pps_rbsp, 0); // pps_seq_parameter_set_id (TODO)
-
- BitstreamAppend(&pps_rbsp, 1,
- pic->pic_fields.bits.dependent_slice_segments_enabled_flag);
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&pps_rbsp, 1, 0); // output_flag_present_flag
- BitstreamAppend(&pps_rbsp, 3, 0); // num_extra_slice_header_bits
-
- BitstreamAppend(&pps_rbsp, 1,
- pic->pic_fields.bits.sign_data_hiding_enabled_flag);
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&pps_rbsp, 1, 0); // cabac_init_present_flag
-
- BitstreamAppendUE(&pps_rbsp, pic->num_ref_idx_l0_default_active_minus1);
- BitstreamAppendUE(&pps_rbsp, pic->num_ref_idx_l1_default_active_minus1);
- BitstreamAppendSE(&pps_rbsp, pic->pic_init_qp - 26);
- BitstreamAppend(&pps_rbsp, 1,
- pic->pic_fields.bits.constrained_intra_pred_flag);
- BitstreamAppend(&pps_rbsp, 1,
- pic->pic_fields.bits.transform_skip_enabled_flag);
- BitstreamAppend(&pps_rbsp, 1, pic->pic_fields.bits.cu_qp_delta_enabled_flag);
- if (pic->pic_fields.bits.cu_qp_delta_enabled_flag)
- BitstreamAppendUE(&pps_rbsp, pic->diff_cu_qp_delta_depth);
- BitstreamAppendSE(&pps_rbsp, pic->pps_cb_qp_offset);
- BitstreamAppendSE(&pps_rbsp, pic->pps_cr_qp_offset);
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&pps_rbsp, 1, 0); // pps_slice_chroma_qp_offsets_present_flag
-
- BitstreamAppend(&pps_rbsp, 1, pic->pic_fields.bits.weighted_pred_flag);
- BitstreamAppend(&pps_rbsp, 1, pic->pic_fields.bits.weighted_bipred_flag);
- BitstreamAppend(&pps_rbsp, 1,
- pic->pic_fields.bits.transquant_bypass_enabled_flag);
- BitstreamAppend(&pps_rbsp, 1, pic->pic_fields.bits.tiles_enabled_flag);
- BitstreamAppend(&pps_rbsp, 1,
- pic->pic_fields.bits.entropy_coding_sync_enabled_flag);
- if (pic->pic_fields.bits.tiles_enabled_flag) {
- BitstreamAppendUE(&pps_rbsp, pic->num_tile_columns_minus1);
- BitstreamAppendUE(&pps_rbsp, pic->num_tile_rows_minus1);
- // TODO(mburakov): Implement this!!!
- abort();
- }
- BitstreamAppend(
- &pps_rbsp, 1,
- pic->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag);
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&pps_rbsp, 1, 0); // deblocking_filter_control_present_flag
-
- BitstreamAppend(&pps_rbsp, 1,
- pic->pic_fields.bits.scaling_list_data_present_flag);
- if (pic->pic_fields.bits.scaling_list_data_present_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&pps_rbsp, 1, 0); // lists_modification_present_flag
-
- BitstreamAppendUE(&pps_rbsp, pic->log2_parallel_merge_level_minus2);
-
- // mburakov: ffmpeg defaults the parameters below.
- BitstreamAppend(&pps_rbsp, 1,
- 0); // slice_segment_header_extension_present_flag
- BitstreamAppend(&pps_rbsp, 1, 0); // pps_extension_present_flag
-
- // mburakov: Below is rbsp_trailing_bits structure.
- BitstreamAppend(&pps_rbsp, 1, 1); // rbsp_stop_one_bit
- BitstreamByteAlign(&pps_rbsp); // rbsp_alignment_zero_bit
-
- BitstreamInflate(bitstream, &pps_rbsp);
-}
-
-static void PackSliceSegmentHeaderRbsp(
- struct Bitstream* bitstream, const VAEncSequenceParameterBufferHEVC* seq,
- const VAEncPictureParameterBufferHEVC* pic,
- const VAEncSliceParameterBufferHEVC* slice) {
- BitstreamAppend(bitstream, 32, 0x00000001);
- BitstreamAppend(bitstream, 1, 0); // forbidden_zero_bit
- BitstreamAppend(bitstream, 6, pic->nal_unit_type);
- BitstreamAppend(bitstream, 6, 0); // nuh_layer_id
- BitstreamAppend(bitstream, 3, 1); // nuh_temporal_id_plus1
-
- // TODO(mburakov): I have no idea what I'm doing...
- static const uint32_t first_slice_segment_in_pic_flag = 1;
-
- // mburakov: ffmpeg defaults the parameteres below.
- static const uint32_t num_extra_slice_header_bits = 0;
- static const uint32_t output_flag_present_flag = 0;
- static const uint32_t lists_modification_present_flag = 0;
- static const uint32_t cabac_init_present_flag = 0;
- static const uint32_t motion_vector_resolution_control_idc = 0;
- static const uint32_t pps_slice_chroma_qp_offsets_present_flag = 0;
- static const uint32_t pps_slice_act_qp_offsets_present_flag = 0;
- static const uint32_t chroma_qp_offset_list_enabled_flag = 0;
- static const uint32_t deblocking_filter_override_enabled_flag = 0;
- static const uint32_t deblocking_filter_override_flag = 0;
- static const uint32_t num_entry_point_offsets = 0;
- static const uint32_t slice_segment_header_extension_present_flag = 0;
-
- // mburakov: ffmpeg hardcodes the parameters below.
- static const uint32_t log2_max_pic_order_cnt_lsb_minus4 = 8;
- static const uint32_t short_term_ref_pic_set_sps_flag = 0;
- static const uint32_t num_short_term_ref_pic_sets = 0;
- static const uint32_t long_term_ref_pics_present_flag = 0;
-
- BitstreamAppend(bitstream, 1, first_slice_segment_in_pic_flag);
- if (pic->nal_unit_type >= HEVC_NUT_BLA_W_LP &&
- pic->nal_unit_type <= HEVC_NUT_RSV_IRAP_VCL23) {
- BitstreamAppend(bitstream, 1,
- pic->pic_fields.bits.no_output_of_prior_pics_flag);
- }
- BitstreamAppendUE(bitstream, slice->slice_pic_parameter_set_id);
- if (!first_slice_segment_in_pic_flag) {
- if (pic->pic_fields.bits.dependent_slice_segments_enabled_flag) {
- BitstreamAppend(bitstream, 1,
- slice->slice_fields.bits.dependent_slice_segment_flag);
- }
- // TODO(mburakov): Implement this!!!
- abort();
- }
-
- if (!slice->slice_fields.bits.dependent_slice_segment_flag) {
- for (uint32_t i = 0; i < num_extra_slice_header_bits; i++) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- BitstreamAppendUE(bitstream, slice->slice_type);
- if (output_flag_present_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (seq->seq_fields.bits.separate_colour_plane_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (pic->nal_unit_type != HEVC_NUT_IDR_W_RADL &&
- pic->nal_unit_type != HEVC_NUT_IDR_N_LP) {
- uint32_t slice_pic_order_cnt_lsb =
- pic->decoded_curr_pic.pic_order_cnt &
- (1 << (log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1;
- BitstreamAppend(bitstream, log2_max_pic_order_cnt_lsb_minus4 + 4,
- slice_pic_order_cnt_lsb);
- BitstreamAppend(bitstream, 1, short_term_ref_pic_set_sps_flag);
- if (!short_term_ref_pic_set_sps_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- } else if (num_short_term_ref_pic_sets > 0) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (long_term_ref_pics_present_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (seq->seq_fields.bits.sps_temporal_mvp_enabled_flag) {
- BitstreamAppend(
- bitstream, 1,
- slice->slice_fields.bits.slice_temporal_mvp_enabled_flag);
- }
- }
- if (seq->seq_fields.bits.sample_adaptive_offset_enabled_flag) {
- BitstreamAppend(bitstream, 1,
- slice->slice_fields.bits.slice_sao_luma_flag);
- uint32_t ChromaArrayType =
- !seq->seq_fields.bits.separate_colour_plane_flag
- ? seq->seq_fields.bits.chroma_format_idc
- : 0;
- if (ChromaArrayType != 0) {
- BitstreamAppend(bitstream, 1,
- slice->slice_fields.bits.slice_sao_chroma_flag);
- }
- }
- if (slice->slice_type == HEVC_SLICE_TYPE_P ||
- slice->slice_type == HEVC_SLICE_TYPE_B) {
- BitstreamAppend(
- bitstream, 1,
- slice->slice_fields.bits.num_ref_idx_active_override_flag);
- if (slice->slice_fields.bits.num_ref_idx_active_override_flag) {
- BitstreamAppendUE(bitstream, slice->num_ref_idx_l0_active_minus1);
- if (slice->slice_type == HEVC_SLICE_TYPE_B)
- BitstreamAppendUE(bitstream, slice->num_ref_idx_l1_active_minus1);
- }
- if (lists_modification_present_flag /* && NumPicTotalCurr > 1*/) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (slice->slice_type == HEVC_SLICE_TYPE_B) {
- BitstreamAppend(bitstream, 1,
- slice->slice_fields.bits.mvd_l1_zero_flag);
- }
- if (cabac_init_present_flag) {
- BitstreamAppend(bitstream, 1, slice->slice_fields.bits.cabac_init_flag);
- }
- if (slice->slice_fields.bits.slice_temporal_mvp_enabled_flag) {
- if (slice->slice_type == HEVC_SLICE_TYPE_B) {
- BitstreamAppend(bitstream, 1,
- slice->slice_fields.bits.collocated_from_l0_flag);
- }
- if ((slice->slice_fields.bits.collocated_from_l0_flag &&
- slice->num_ref_idx_l0_active_minus1 > 0) ||
- (!slice->slice_fields.bits.collocated_from_l0_flag &&
- slice->num_ref_idx_l1_active_minus1 > 0)) {
- BitstreamAppendUE(bitstream, pic->collocated_ref_pic_index);
- }
- }
- if ((pic->pic_fields.bits.weighted_pred_flag &&
- slice->slice_type == HEVC_SLICE_TYPE_P) ||
- (pic->pic_fields.bits.weighted_bipred_flag &&
- slice->slice_type == HEVC_SLICE_TYPE_B)) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- BitstreamAppendUE(bitstream, 5 - slice->max_num_merge_cand);
- if (motion_vector_resolution_control_idc == 2) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- }
- BitstreamAppendSE(bitstream, slice->slice_qp_delta);
- if (pps_slice_chroma_qp_offsets_present_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (pps_slice_act_qp_offsets_present_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (chroma_qp_offset_list_enabled_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (deblocking_filter_override_enabled_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (deblocking_filter_override_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- if (pic->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag &&
- (slice->slice_fields.bits.slice_sao_luma_flag ||
- slice->slice_fields.bits.slice_sao_chroma_flag ||
- !slice->slice_fields.bits.slice_deblocking_filter_disabled_flag)) {
- BitstreamAppend(bitstream, 1,
- slice->slice_fields.bits
- .slice_loop_filter_across_slices_enabled_flag);
- }
- }
- if (pic->pic_fields.bits.tiles_enabled_flag ||
- pic->pic_fields.bits.entropy_coding_sync_enabled_flag) {
- BitstreamAppendUE(bitstream, num_entry_point_offsets);
- if (num_entry_point_offsets > 0) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
- }
- if (slice_segment_header_extension_present_flag) {
- // TODO(mburakov): Implement this!!!
- abort();
- }
-
- // mburakov: Below is byte_alignment structure.
- BitstreamAppend(bitstream, 1, 1); // alignment_bit_equal_to_one
- BitstreamByteAlign(bitstream); // alignment_bit_equal_to_zero
-}
-
static bool DrainBuffers(int fd, struct iovec* iovec, int count) {
for (;;) {
ssize_t result = writev(fd, iovec, count);
@@ -1077,7 +557,7 @@ bool EncodeContextEncodeFrame(struct EncodeContext* encode_context, int fd) {
};
}
encode_context->pic.coded_buf = encode_context->output_buffer_id;
- encode_context->pic.nal_unit_type = HEVC_NUT_IDR_W_RADL;
+ encode_context->pic.nal_unit_type = IDR_W_RADL;
encode_context->pic.pic_fields.bits.idr_pic_flag = 1;
encode_context->pic.pic_fields.bits.coding_type = 1;
encode_context->pic.pic_fields.bits.reference_pic_flag = 1;
@@ -1094,10 +574,24 @@ bool EncodeContextEncodeFrame(struct EncodeContext* encode_context, int fd) {
.data = buffer,
.size = 0,
};
- PackVpsRbsp(&bitstream, &encode_context->seq);
- PackSpsRbsp(&bitstream, &encode_context->seq, encode_context->width,
- encode_context->height);
- PackPpsRbsp(&bitstream, &encode_context->pic);
+ static const struct MoreVideoParameters mvp = {
+ .max_b_depth = 0,
+ .time_base_num = 1,
+ .time_base_den = 60,
+ };
+ PackVideoParameterSetNalUnit(&bitstream, &encode_context->seq, &mvp);
+ const struct MoreSeqParameters msp = {
+ .crop_width = encode_context->width,
+ .crop_height = encode_context->height,
+ .video_signal_type_present_flag = 1,
+ .video_full_range_flag = 0, // TODO
+ .colour_description_present_flag = 1,
+ .colour_primaries = 2, // Unsepcified
+ .transfer_characteristics = 2, // Unspecified
+ .matrix_coeffs = 6, // TODO
+ };
+ PackSeqParameterSetNalUnit(&bitstream, &encode_context->seq, &mvp, &msp);
+ PackPicParameterSetNalUnit(&bitstream, &encode_context->pic);
if (!UploadPackedBuffer(encode_context, VAEncPackedHeaderSequence,
(unsigned int)bitstream.size, bitstream.data,
&buffer_ptr)) {
@@ -1224,7 +718,7 @@ case PICTURE_TYPE_P:
.slice_segment_address = 0, // calculated
.num_ctu_in_slice = block_size,
- .slice_type = HEVC_SLICE_TYPE_I, // calculated
+ .slice_type = I, // calculated
.slice_pic_parameter_set_id =
encode_context->pic.slice_pic_parameter_set_id,
@@ -1294,8 +788,11 @@ case PICTURE_TYPE_P:
.data = buffer,
.size = 0,
};
- PackSliceSegmentHeaderRbsp(&bitstream, &encode_context->seq,
- &encode_context->pic, &slice);
+ const struct MoreSliceParamerters msp = {
+ .first_slice_segment_in_pic_flag = 1,
+ };
+ PackSliceSegmentHeaderNalUnit(&bitstream, &encode_context->seq,
+ &encode_context->pic, &slice, &msp);
if (!UploadPackedBuffer(encode_context, VAEncPackedHeaderSlice,
(unsigned int)bitstream.size, bitstream.data,
&buffer_ptr)) {
diff --git a/hevc.c b/hevc.c
new file mode 100644
index 0000000..5328139
--- /dev/null
+++ b/hevc.c
@@ -0,0 +1,711 @@
+/*
+ * Copyright (C) 2023 Mikhail Burakov. This file is part of streamer.
+ *
+ * streamer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * streamer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with streamer. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "hevc.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "bitstream.h"
+
+// mburakov: Below entries are hardcoded by ffmpeg:
+static const uint8_t vps_video_parameter_set_id = 0;
+static const bool vps_base_layer_internal_flag = 1;
+static const bool vps_base_layer_available_flag = 1;
+static const uint8_t vps_max_layers_minus1 = 0;
+static const uint8_t vps_max_sub_layers_minus1 = 0;
+static const bool vps_temporal_id_nesting_flag = 1;
+static const uint8_t general_profile_space = 0;
+static const bool general_progressive_source_flag = 1;
+static const bool general_interlaced_source_flag = 0;
+static const bool general_non_packed_constraint_flag = 1;
+static const bool general_frame_only_constraint_flag = 1;
+static const bool general_one_picture_only_constraint_flag = 0;
+static const bool vps_sub_layer_ordering_info_present_flag = 0;
+static const uint32_t vps_max_latency_increase_plus1 = 0;
+static const uint8_t vps_max_layer_id = 0;
+static const uint32_t vps_num_layer_sets_minus1 = 0;
+static const bool vps_timing_info_present_flag = 1;
+static const bool vps_poc_proportional_to_timing_flag = 0;
+static const uint32_t vps_num_hrd_parameters = 0;
+static const uint8_t sps_video_parameter_set_id = vps_video_parameter_set_id;
+static const uint8_t sps_max_sub_layers_minus1 = vps_max_sub_layers_minus1;
+static const bool sps_temporal_id_nesting_flag = vps_temporal_id_nesting_flag;
+static const uint32_t sps_seq_parameter_set_id = 0;
+static const uint32_t log2_max_pic_order_cnt_lsb_minus4 = 8;
+static const bool sps_sub_layer_ordering_info_present_flag =
+ vps_sub_layer_ordering_info_present_flag;
+static const uint32_t sps_max_latency_increase_plus1 =
+ vps_max_latency_increase_plus1;
+static const uint32_t num_short_term_ref_pic_sets = 0;
+static const bool long_term_ref_pics_present_flag = 0;
+static const bool vui_parameters_present_flag = 1;
+static const uint8_t video_format = 5;
+static const bool vui_timing_info_present_flag = 1;
+static const bool vui_poc_proportional_to_timing_flag =
+ vps_poc_proportional_to_timing_flag;
+static const bool vui_hrd_parameters_present_flag = 0;
+static const bool bitstream_restriction_flag = 1;
+static const bool motion_vectors_over_pic_boundaries_flag = 1;
+static const bool restricted_ref_pic_lists_flag = 1;
+static const uint32_t max_bytes_per_pic_denom = 0;
+static const uint32_t max_bits_per_min_cu_denom = 0;
+static const uint32_t log2_max_mv_length_horizontal = 15;
+static const uint32_t log2_max_mv_length_vertical = 15;
+static const uint32_t pps_pic_parameter_set_id = 0;
+static const uint32_t pps_seq_parameter_set_id = sps_seq_parameter_set_id;
+static const bool short_term_ref_pic_set_sps_flag = 0;
+
+// mburakov: Below entries are defaulted by ffmpeg:
+static const bool general_inbld_flag = 0;
+static const bool vps_extension_flag = 0;
+static const bool aspect_ratio_info_present_flag = 0;
+static const bool overscan_info_present_flag = 0;
+static const bool neutral_chroma_indication_flag = 0;
+static const bool field_seq_flag = 0;
+static const bool frame_field_info_present_flag = 0;
+static const bool default_display_window_flag = 0;
+static const bool tiles_fixed_structure_flag = 0;
+static const uint32_t min_spatial_segmentation_idc = 0;
+static const bool sps_extension_present_flag = 0;
+static const bool output_flag_present_flag = 0;
+static const uint8_t num_extra_slice_header_bits = 0;
+static const bool cabac_init_present_flag = 0;
+static const bool pps_slice_chroma_qp_offsets_present_flag = 0;
+static const bool deblocking_filter_control_present_flag = 0;
+static const bool lists_modification_present_flag = 0;
+static const bool slice_segment_header_extension_present_flag = 0;
+static const bool pps_extension_present_flag = 0;
+static const uint32_t motion_vector_resolution_control_idc = 0;
+static const bool pps_slice_act_qp_offsets_present_flag = 0;
+static const bool chroma_qp_offset_list_enabled_flag = 0;
+static const bool deblocking_filter_override_enabled_flag = 0;
+static const bool deblocking_filter_override_flag = 0;
+static const uint32_t num_entry_point_offsets = 0;
+
+// 7.3.1.2 NAL unit header syntax
+static void PackNalUnitHeader(struct Bitstream* bitstream,
+ uint8_t nal_unit_type) {
+ BitstreamAppend(bitstream, 32, 0x00000001);
+ BitstreamAppend(bitstream, 1, 0); // forbidden_zero_bit
+ BitstreamAppend(bitstream, 6, nal_unit_type);
+ BitstreamAppend(bitstream, 6, 0); // nuh_layer_id
+ BitstreamAppend(bitstream, 3, 1); // nuh_temporal_id_plus1
+}
+
+// 7.3.3 Profile, tier and level syntax
+static void PackProfileTierLevel(struct Bitstream* bitstream,
+ const VAEncSequenceParameterBufferHEVC* seq,
+ bool profilePresentFlag,
+ uint8_t maxNumSubLayersMinus1) {
+ if (profilePresentFlag) {
+ BitstreamAppend(bitstream, 2, general_profile_space);
+ BitstreamAppend(bitstream, 1, seq->general_tier_flag);
+ BitstreamAppend(bitstream, 5, seq->general_profile_idc);
+
+ // mburakov: ffmpeg deduces general_profile_compatibility_flag.
+ bool general_profile_compatibility_flag[32] = {0};
+ general_profile_compatibility_flag[seq->general_profile_idc] = 1;
+ if (general_profile_compatibility_flag[1])
+ general_profile_compatibility_flag[2] = 1;
+ if (general_profile_compatibility_flag[3]) {
+ general_profile_compatibility_flag[1] = 1;
+ general_profile_compatibility_flag[2] = 1;
+ }
+
+ for (uint8_t j = 0; j < 32; j++)
+ BitstreamAppend(bitstream, 1, general_profile_compatibility_flag[j]);
+
+ BitstreamAppend(bitstream, 1, general_progressive_source_flag);
+ BitstreamAppend(bitstream, 1, general_interlaced_source_flag);
+ BitstreamAppend(bitstream, 1, general_non_packed_constraint_flag);
+ BitstreamAppend(bitstream, 1, general_frame_only_constraint_flag);
+ if (seq->general_profile_idc == 4 ||
+ general_profile_compatibility_flag[4] ||
+ seq->general_profile_idc == 5 ||
+ general_profile_compatibility_flag[5] ||
+ seq->general_profile_idc == 6 ||
+ general_profile_compatibility_flag[6] ||
+ seq->general_profile_idc == 7 ||
+ general_profile_compatibility_flag[7] ||
+ seq->general_profile_idc == 8 ||
+ general_profile_compatibility_flag[8] ||
+ seq->general_profile_idc == 9 ||
+ general_profile_compatibility_flag[9] ||
+ seq->general_profile_idc == 10 ||
+ general_profile_compatibility_flag[10] ||
+ seq->general_profile_idc == 11 ||
+ general_profile_compatibility_flag[11]) {
+ // TODO(mburakov): Implement this!
+ abort();
+ } else if (seq->general_profile_idc == 2 ||
+ general_profile_compatibility_flag[2]) {
+ BitstreamAppend(bitstream, 7, 0); // general_reserved_zero_7bits
+ BitstreamAppend(bitstream, 1, general_one_picture_only_constraint_flag);
+ BitstreamAppend(bitstream, 24, 0); // general_reserved_zero_35bits
+ BitstreamAppend(bitstream, 11, 0); // general_reserved_zero_35bits
+ } else {
+ BitstreamAppend(bitstream, 24, 0); // general_reserved_zero_43bits
+ BitstreamAppend(bitstream, 19, 0); // general_reserved_zero_43bits
+ }
+
+ if (seq->general_profile_idc == 1 ||
+ general_profile_compatibility_flag[1] ||
+ seq->general_profile_idc == 2 ||
+ general_profile_compatibility_flag[2] ||
+ seq->general_profile_idc == 3 ||
+ general_profile_compatibility_flag[3] ||
+ seq->general_profile_idc == 4 ||
+ general_profile_compatibility_flag[4] ||
+ seq->general_profile_idc == 5 ||
+ general_profile_compatibility_flag[5] ||
+ seq->general_profile_idc == 9 ||
+ general_profile_compatibility_flag[9] ||
+ seq->general_profile_idc == 11 ||
+ general_profile_compatibility_flag[11]) {
+ BitstreamAppend(bitstream, 1, general_inbld_flag);
+ } else {
+ BitstreamAppend(bitstream, 1, 0); // general_reserved_zero_bit
+ }
+ }
+
+ BitstreamAppend(bitstream, 8, seq->general_level_idc);
+ for (uint8_t i = 0; i < maxNumSubLayersMinus1; i++) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+ if (maxNumSubLayersMinus1 > 0) {
+ for (uint8_t i = maxNumSubLayersMinus1; i < 8; i++)
+ BitstreamAppend(bitstream, 2, 0); // reserved_zero_2bits
+ }
+ for (uint8_t i = 0; i < maxNumSubLayersMinus1; i++) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+}
+
+// 7.3.2.11 RBSP trailing bits syntax
+static void PackRbspTrailingBits(struct Bitstream* bitstream) {
+ BitstreamAppend(bitstream, 1, 1); // rbsp_stop_one_bit
+ BitstreamByteAlign(bitstream); // rbsp_alignment_zero_bit
+}
+
+// 7.3.2.1 Video parameter set RBSP syntax
+void PackVideoParameterSetNalUnit(struct Bitstream* bitstream,
+ const VAEncSequenceParameterBufferHEVC* seq,
+ const struct MoreVideoParameters* mvp) {
+ PackNalUnitHeader(bitstream, VPS_NUT);
+
+ char buffer_on_the_stack[64];
+ struct Bitstream vps_rbsp = {
+ .data = buffer_on_the_stack,
+ .size = 0,
+ };
+
+ BitstreamAppend(&vps_rbsp, 4, vps_video_parameter_set_id);
+ BitstreamAppend(&vps_rbsp, 1, vps_base_layer_internal_flag);
+ BitstreamAppend(&vps_rbsp, 1, vps_base_layer_available_flag);
+ BitstreamAppend(&vps_rbsp, 6, vps_max_layers_minus1);
+ BitstreamAppend(&vps_rbsp, 3, vps_max_sub_layers_minus1);
+ BitstreamAppend(&vps_rbsp, 1, vps_temporal_id_nesting_flag);
+ BitstreamAppend(&vps_rbsp, 16, 0xffff); // vps_reserved_0xffff_16bits
+
+ PackProfileTierLevel(&vps_rbsp, seq, 1, vps_max_sub_layers_minus1);
+
+ BitstreamAppend(&vps_rbsp, 1, vps_sub_layer_ordering_info_present_flag);
+ for (uint8_t i = (vps_sub_layer_ordering_info_present_flag
+ ? 0
+ : vps_max_sub_layers_minus1);
+ i <= vps_max_sub_layers_minus1; i++) {
+ if (i != vps_max_sub_layers_minus1) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppendUE(
+ &vps_rbsp, mvp->max_b_depth + 1); // vps_max_dec_pic_buffering_minus1
+ BitstreamAppendUE(&vps_rbsp, mvp->max_b_depth); // vps_max_num_reorder_pics
+ BitstreamAppendUE(&vps_rbsp, vps_max_latency_increase_plus1);
+ }
+
+ BitstreamAppend(&vps_rbsp, 6, vps_max_layer_id);
+ BitstreamAppendUE(&vps_rbsp, vps_num_layer_sets_minus1);
+ for (uint8_t i = 1; i <= vps_max_layers_minus1; i++) {
+ for (uint8_t j = 0; j <= vps_max_layer_id; j++) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+ }
+
+ BitstreamAppend(&vps_rbsp, 1, vps_timing_info_present_flag);
+ if (vps_timing_info_present_flag) {
+ // TODO(mburakov): Is this section required?
+
+ BitstreamAppend(&vps_rbsp, 32,
+ mvp->time_base_num); // vps_num_units_in_tick
+ BitstreamAppend(&vps_rbsp, 32, mvp->time_base_den); // vps_time_scale
+ BitstreamAppend(&vps_rbsp, 1, vps_poc_proportional_to_timing_flag);
+ if (vps_poc_proportional_to_timing_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppendUE(&vps_rbsp, vps_num_hrd_parameters);
+ for (uint32_t i = 0; i < vps_num_hrd_parameters; i++) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+ }
+
+ BitstreamAppend(&vps_rbsp, 1, vps_extension_flag);
+ if (vps_extension_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ PackRbspTrailingBits(&vps_rbsp);
+ BitstreamInflate(bitstream, &vps_rbsp);
+}
+
+// E.2.1 VUI parameters syntax
+static void PackVuiParameters(struct Bitstream* bitstream,
+ const struct MoreVideoParameters* mvp,
+ const struct MoreSeqParameters* msp) {
+ BitstreamAppend(bitstream, 1, aspect_ratio_info_present_flag);
+ if (aspect_ratio_info_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(bitstream, 1, overscan_info_present_flag);
+ if (overscan_info_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(bitstream, 1, msp->video_signal_type_present_flag);
+ if (msp->video_signal_type_present_flag) {
+ BitstreamAppend(bitstream, 3, video_format);
+ BitstreamAppend(bitstream, 1, msp->video_full_range_flag);
+ BitstreamAppend(bitstream, 1, msp->colour_description_present_flag);
+ if (msp->colour_description_present_flag) {
+ BitstreamAppend(bitstream, 8, msp->colour_primaries);
+ BitstreamAppend(bitstream, 8, msp->transfer_characteristics);
+ BitstreamAppend(bitstream, 8, msp->matrix_coeffs);
+ }
+ }
+
+ BitstreamAppend(bitstream, 1, msp->chroma_loc_info_present_flag);
+ if (msp->chroma_loc_info_present_flag) {
+ BitstreamAppendUE(bitstream, msp->chroma_sample_loc_type_top_field);
+ BitstreamAppendUE(bitstream, msp->chroma_sample_loc_type_bottom_field);
+ }
+
+ BitstreamAppend(bitstream, 1, neutral_chroma_indication_flag);
+ if (neutral_chroma_indication_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(bitstream, 1, field_seq_flag);
+ BitstreamAppend(bitstream, 1, frame_field_info_present_flag);
+ BitstreamAppend(bitstream, 1, default_display_window_flag);
+ if (default_display_window_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(bitstream, 1, vui_timing_info_present_flag);
+ if (vui_timing_info_present_flag) {
+ BitstreamAppend(bitstream, 32,
+ mvp->time_base_num); // vui_num_units_in_tick
+ BitstreamAppend(bitstream, 32, mvp->time_base_den); // vui_time_scale
+ BitstreamAppend(bitstream, 1, vui_poc_proportional_to_timing_flag);
+ if (vui_poc_proportional_to_timing_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(bitstream, 1, vui_hrd_parameters_present_flag);
+ if (vui_hrd_parameters_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+ }
+
+ BitstreamAppend(bitstream, 1, bitstream_restriction_flag);
+ if (bitstream_restriction_flag) {
+ BitstreamAppend(bitstream, 1, tiles_fixed_structure_flag);
+ BitstreamAppend(bitstream, 1, motion_vectors_over_pic_boundaries_flag);
+ BitstreamAppend(bitstream, 1, restricted_ref_pic_lists_flag);
+ BitstreamAppendUE(bitstream, min_spatial_segmentation_idc);
+ BitstreamAppendUE(bitstream, max_bytes_per_pic_denom);
+ BitstreamAppendUE(bitstream, max_bits_per_min_cu_denom);
+ BitstreamAppendUE(bitstream, log2_max_mv_length_horizontal);
+ BitstreamAppendUE(bitstream, log2_max_mv_length_vertical);
+ }
+}
+
+void PackSeqParameterSetNalUnit(struct Bitstream* bitstream,
+ const VAEncSequenceParameterBufferHEVC* seq,
+ const struct MoreVideoParameters* mvp,
+ const struct MoreSeqParameters* msp) {
+ const typeof(seq->seq_fields.bits)* seq_bits = &seq->seq_fields.bits;
+
+ PackNalUnitHeader(bitstream, SPS_NUT);
+
+ char buffer_on_the_stack[64];
+ struct Bitstream sps_rbsp = {
+ .data = buffer_on_the_stack,
+ .size = 0,
+ };
+
+ BitstreamAppend(&sps_rbsp, 4, sps_video_parameter_set_id);
+ BitstreamAppend(&sps_rbsp, 3, sps_max_sub_layers_minus1);
+ BitstreamAppend(&sps_rbsp, 1, sps_temporal_id_nesting_flag);
+
+ PackProfileTierLevel(&sps_rbsp, seq, 1, sps_max_sub_layers_minus1);
+
+ BitstreamAppendUE(&sps_rbsp, sps_seq_parameter_set_id);
+ BitstreamAppendUE(&sps_rbsp, seq_bits->chroma_format_idc);
+ if (seq_bits->chroma_format_idc == 3) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppendUE(&sps_rbsp, seq->pic_width_in_luma_samples);
+ BitstreamAppendUE(&sps_rbsp, seq->pic_height_in_luma_samples);
+
+ bool conformance_window_flag =
+ msp->crop_width != seq->pic_width_in_luma_samples ||
+ msp->crop_height != seq->pic_height_in_luma_samples;
+ BitstreamAppend(&sps_rbsp, 1, conformance_window_flag);
+
+ if (conformance_window_flag) {
+ if (seq_bits->chroma_format_idc != 1) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ // mburakov: Offsets are in chroma samples.
+ uint32_t conf_win_right_offset =
+ (seq->pic_width_in_luma_samples - msp->crop_width) / 2;
+ uint32_t conf_win_bottom_offset =
+ (seq->pic_height_in_luma_samples - msp->crop_height) / 2;
+ BitstreamAppendUE(&sps_rbsp, 0); // conf_win_left_offset
+ BitstreamAppendUE(&sps_rbsp, conf_win_right_offset);
+ BitstreamAppendUE(&sps_rbsp, 0); // conf_win_top_offset
+ BitstreamAppendUE(&sps_rbsp, conf_win_bottom_offset);
+ }
+
+ BitstreamAppendUE(&sps_rbsp, seq_bits->bit_depth_luma_minus8);
+ BitstreamAppendUE(&sps_rbsp, seq_bits->bit_depth_chroma_minus8);
+ BitstreamAppendUE(&sps_rbsp, log2_max_pic_order_cnt_lsb_minus4);
+
+ BitstreamAppend(&sps_rbsp, 1, sps_sub_layer_ordering_info_present_flag);
+ for (uint8_t i = (sps_sub_layer_ordering_info_present_flag
+ ? 0
+ : sps_max_sub_layers_minus1);
+ i <= sps_max_sub_layers_minus1; i++) {
+ if (i != sps_max_sub_layers_minus1) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppendUE(
+ &sps_rbsp, mvp->max_b_depth + 1); // vps_max_dec_pic_buffering_minus1
+ BitstreamAppendUE(&sps_rbsp, mvp->max_b_depth); // vps_max_num_reorder_pics
+ BitstreamAppendUE(&sps_rbsp, sps_max_latency_increase_plus1);
+ }
+
+ BitstreamAppendUE(&sps_rbsp, seq->log2_min_luma_coding_block_size_minus3);
+ BitstreamAppendUE(&sps_rbsp, seq->log2_diff_max_min_luma_coding_block_size);
+ BitstreamAppendUE(&sps_rbsp, seq->log2_min_transform_block_size_minus2);
+ BitstreamAppendUE(&sps_rbsp, seq->log2_diff_max_min_transform_block_size);
+ BitstreamAppendUE(&sps_rbsp, seq->max_transform_hierarchy_depth_inter);
+ BitstreamAppendUE(&sps_rbsp, seq->max_transform_hierarchy_depth_intra);
+
+ BitstreamAppend(&sps_rbsp, 1, seq_bits->scaling_list_enabled_flag);
+ if (seq_bits->scaling_list_enabled_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(&sps_rbsp, 1, seq_bits->amp_enabled_flag);
+ BitstreamAppend(&sps_rbsp, 1, seq_bits->sample_adaptive_offset_enabled_flag);
+ BitstreamAppend(&sps_rbsp, 1, seq_bits->pcm_enabled_flag);
+ if (seq_bits->pcm_enabled_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppendUE(&sps_rbsp, num_short_term_ref_pic_sets);
+ for (uint32_t i = 0; i < num_short_term_ref_pic_sets; i++) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(&sps_rbsp, 1, long_term_ref_pics_present_flag);
+ if (long_term_ref_pics_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(&sps_rbsp, 1, seq_bits->sps_temporal_mvp_enabled_flag);
+ BitstreamAppend(&sps_rbsp, 1, seq_bits->strong_intra_smoothing_enabled_flag);
+ BitstreamAppend(&sps_rbsp, 1, vui_parameters_present_flag);
+ if (vui_parameters_present_flag) PackVuiParameters(&sps_rbsp, mvp, msp);
+ BitstreamAppend(&sps_rbsp, 1, sps_extension_present_flag);
+ if (sps_extension_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ PackRbspTrailingBits(&sps_rbsp);
+ BitstreamInflate(bitstream, &sps_rbsp);
+}
+
+// 7.3.2.3.1 General picture parameter set RBSP syntax
+void PackPicParameterSetNalUnit(struct Bitstream* bitstream,
+ const VAEncPictureParameterBufferHEVC* pic) {
+ const typeof(pic->pic_fields.bits)* pic_bits = &pic->pic_fields.bits;
+
+ PackNalUnitHeader(bitstream, PPS_NUT);
+
+ char buffer_on_the_stack[64];
+ struct Bitstream pps_rbsp = {
+ .data = buffer_on_the_stack,
+ .size = 0,
+ };
+
+ BitstreamAppendUE(&pps_rbsp, pps_pic_parameter_set_id);
+ BitstreamAppendUE(&pps_rbsp, pps_seq_parameter_set_id);
+ BitstreamAppend(&pps_rbsp, 1,
+ pic_bits->dependent_slice_segments_enabled_flag);
+ BitstreamAppend(&pps_rbsp, 1, output_flag_present_flag);
+ BitstreamAppend(&pps_rbsp, 3, num_extra_slice_header_bits);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->sign_data_hiding_enabled_flag);
+ BitstreamAppend(&pps_rbsp, 1, cabac_init_present_flag);
+ BitstreamAppendUE(&pps_rbsp, pic->num_ref_idx_l0_default_active_minus1);
+ BitstreamAppendUE(&pps_rbsp, pic->num_ref_idx_l1_default_active_minus1);
+ BitstreamAppendSE(&pps_rbsp,
+ pic->pic_init_qp - 26); // init_qp_minus26
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->constrained_intra_pred_flag);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->transform_skip_enabled_flag);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->cu_qp_delta_enabled_flag);
+ if (pic_bits->cu_qp_delta_enabled_flag)
+ BitstreamAppendUE(&pps_rbsp, pic->diff_cu_qp_delta_depth);
+ BitstreamAppendSE(&pps_rbsp, pic->pps_cb_qp_offset);
+ BitstreamAppendSE(&pps_rbsp, pic->pps_cr_qp_offset);
+ BitstreamAppend(&pps_rbsp, 1, pps_slice_chroma_qp_offsets_present_flag);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->weighted_pred_flag);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->weighted_bipred_flag);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->transquant_bypass_enabled_flag);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->tiles_enabled_flag);
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->entropy_coding_sync_enabled_flag);
+
+ if (pic_bits->tiles_enabled_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(&pps_rbsp, 1,
+ pic_bits->pps_loop_filter_across_slices_enabled_flag);
+ BitstreamAppend(&pps_rbsp, 1, deblocking_filter_control_present_flag);
+ if (deblocking_filter_control_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(&pps_rbsp, 1, pic_bits->scaling_list_data_present_flag);
+ if (pic_bits->scaling_list_data_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ BitstreamAppend(&pps_rbsp, 1, lists_modification_present_flag);
+ BitstreamAppendUE(&pps_rbsp, pic->log2_parallel_merge_level_minus2);
+ BitstreamAppend(&pps_rbsp, 1, slice_segment_header_extension_present_flag);
+ BitstreamAppend(&pps_rbsp, 1, pps_extension_present_flag);
+
+ if (pps_extension_present_flag) {
+ // TODO(mburakov): Implement this!
+ abort();
+ }
+
+ PackRbspTrailingBits(&pps_rbsp);
+ BitstreamInflate(bitstream, &pps_rbsp);
+}
+
+// 7.3.6.1 General slice segment header syntax
+void PackSliceSegmentHeaderNalUnit(struct Bitstream* bitstream,
+ const VAEncSequenceParameterBufferHEVC* seq,
+ const VAEncPictureParameterBufferHEVC* pic,
+ const VAEncSliceParameterBufferHEVC* slice,
+ const struct MoreSliceParamerters* msp) {
+ const typeof(seq->seq_fields.bits)* seq_bits = &seq->seq_fields.bits;
+ const typeof(pic->pic_fields.bits)* pic_bits = &pic->pic_fields.bits;
+ const typeof(slice->slice_fields.bits)* slice_bits =
+ &slice->slice_fields.bits;
+
+ PackNalUnitHeader(bitstream, pic->nal_unit_type);
+
+ char buffer_on_the_stack[64];
+ struct Bitstream slice_rbsp = {
+ .data = buffer_on_the_stack,
+ .size = 0,
+ };
+
+ BitstreamAppend(&slice_rbsp, 1, msp->first_slice_segment_in_pic_flag);
+ if (pic->nal_unit_type >= BLA_W_LP && pic->nal_unit_type <= RSV_IRAP_VCL23)
+ BitstreamAppend(&slice_rbsp, 1, pic_bits->no_output_of_prior_pics_flag);
+ BitstreamAppendUE(&slice_rbsp, slice->slice_pic_parameter_set_id);
+ if (!msp->first_slice_segment_in_pic_flag) {
+ if (pic_bits->dependent_slice_segments_enabled_flag)
+ BitstreamAppend(&slice_rbsp, 1, slice_bits->dependent_slice_segment_flag);
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+
+ if (!slice_bits->dependent_slice_segment_flag) {
+ for (uint32_t i = 0; i < num_extra_slice_header_bits; i++) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ BitstreamAppendUE(&slice_rbsp, slice->slice_type);
+ if (output_flag_present_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (seq_bits->separate_colour_plane_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (pic->nal_unit_type != IDR_W_RADL && pic->nal_unit_type != IDR_N_LP) {
+ uint32_t slice_pic_order_cnt_lsb =
+ pic->decoded_curr_pic.pic_order_cnt &
+ (1 << (log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1;
+ BitstreamAppend(&slice_rbsp, log2_max_pic_order_cnt_lsb_minus4 + 4,
+ slice_pic_order_cnt_lsb);
+ BitstreamAppend(&slice_rbsp, 1, short_term_ref_pic_set_sps_flag);
+ if (!short_term_ref_pic_set_sps_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ } else if (num_short_term_ref_pic_sets > 0) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (long_term_ref_pics_present_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (seq_bits->sps_temporal_mvp_enabled_flag) {
+ BitstreamAppend(&slice_rbsp, 1,
+ slice_bits->slice_temporal_mvp_enabled_flag);
+ }
+ }
+ if (seq_bits->sample_adaptive_offset_enabled_flag) {
+ BitstreamAppend(&slice_rbsp, 1, slice_bits->slice_sao_luma_flag);
+ uint32_t ChromaArrayType = !seq_bits->separate_colour_plane_flag
+ ? seq_bits->chroma_format_idc
+ : 0;
+ if (ChromaArrayType != 0)
+ BitstreamAppend(&slice_rbsp, 1, slice_bits->slice_sao_chroma_flag);
+ }
+ if (slice->slice_type == P || slice->slice_type == B) {
+ BitstreamAppend(&slice_rbsp, 1,
+ slice_bits->num_ref_idx_active_override_flag);
+ if (slice_bits->num_ref_idx_active_override_flag) {
+ BitstreamAppendUE(&slice_rbsp, slice->num_ref_idx_l0_active_minus1);
+ if (slice->slice_type == B)
+ BitstreamAppendUE(&slice_rbsp, slice->num_ref_idx_l1_active_minus1);
+ }
+ if (lists_modification_present_flag /* && NumPicTotalCurr > 1*/) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (slice->slice_type == B)
+ BitstreamAppend(&slice_rbsp, 1, slice_bits->mvd_l1_zero_flag);
+ if (cabac_init_present_flag)
+ BitstreamAppend(&slice_rbsp, 1, slice_bits->cabac_init_flag);
+ if (slice_bits->slice_temporal_mvp_enabled_flag) {
+ if (slice->slice_type == B)
+ BitstreamAppend(&slice_rbsp, 1, slice_bits->collocated_from_l0_flag);
+ if ((slice_bits->collocated_from_l0_flag &&
+ slice->num_ref_idx_l0_active_minus1 > 0) ||
+ (!slice_bits->collocated_from_l0_flag &&
+ slice->num_ref_idx_l1_active_minus1 > 0))
+ BitstreamAppendUE(&slice_rbsp, pic->collocated_ref_pic_index);
+ }
+ if ((pic_bits->weighted_pred_flag && slice->slice_type == P) ||
+ (pic_bits->weighted_bipred_flag && slice->slice_type == B)) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ BitstreamAppendUE(
+ &slice_rbsp,
+ 5 - slice->max_num_merge_cand); // five_minus_max_num_merge_cand
+ if (motion_vector_resolution_control_idc == 2) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ }
+ BitstreamAppendSE(&slice_rbsp, slice->slice_qp_delta);
+ if (pps_slice_chroma_qp_offsets_present_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (pps_slice_act_qp_offsets_present_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (chroma_qp_offset_list_enabled_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (deblocking_filter_override_enabled_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (deblocking_filter_override_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ if (pic_bits->pps_loop_filter_across_slices_enabled_flag &&
+ (slice_bits->slice_sao_luma_flag || slice_bits->slice_sao_chroma_flag ||
+ !slice_bits->slice_deblocking_filter_disabled_flag)) {
+ BitstreamAppend(&slice_rbsp, 1,
+ slice_bits->slice_loop_filter_across_slices_enabled_flag);
+ }
+ }
+ if (pic_bits->tiles_enabled_flag ||
+ pic_bits->entropy_coding_sync_enabled_flag) {
+ BitstreamAppendUE(&slice_rbsp, num_entry_point_offsets);
+ if (num_entry_point_offsets > 0) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+ }
+ if (slice_segment_header_extension_present_flag) {
+ // TODO(mburakov): Implement this!!!
+ abort();
+ }
+
+ PackRbspTrailingBits(&slice_rbsp);
+ BitstreamInflate(bitstream, &slice_rbsp);
+}
diff --git a/hevc.h b/hevc.h
new file mode 100644
index 0000000..14c3aa3
--- /dev/null
+++ b/hevc.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 Mikhail Burakov. This file is part of streamer.
+ *
+ * streamer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * streamer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with streamer. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef STREAMER_HEVC_H_
+#define STREAMER_HEVC_H_
+
+#include <stdbool.h>
+#include <va/va.h>
+
+// Table 7-1
+enum NalUnitType {
+ BLA_W_LP = 16,
+ IDR_W_RADL = 19,
+ IDR_N_LP = 20,
+ RSV_IRAP_VCL23 = 23,
+ VPS_NUT = 32,
+ SPS_NUT = 33,
+ PPS_NUT = 34,
+};
+
+// Table 7-7
+enum SliceType {
+ B = 0,
+ P = 1,
+ I = 2,
+};
+
+struct Bitstream;
+
+struct MoreVideoParameters {
+ uint32_t max_b_depth;
+ uint32_t time_base_num;
+ uint32_t time_base_den;
+};
+
+struct MoreSeqParameters {
+ uint32_t crop_width;
+ uint32_t crop_height;
+ // TODO(mburakov): Why ffmpeg ignores vui section in seq?
+ bool video_signal_type_present_flag;
+ bool video_full_range_flag;
+ bool colour_description_present_flag;
+ uint8_t colour_primaries;
+ uint8_t transfer_characteristics;
+ uint8_t matrix_coeffs;
+ bool chroma_loc_info_present_flag;
+ uint32_t chroma_sample_loc_type_top_field;
+ uint32_t chroma_sample_loc_type_bottom_field;
+};
+
+struct MoreSliceParamerters {
+ bool first_slice_segment_in_pic_flag;
+};
+
+void PackVideoParameterSetNalUnit(struct Bitstream* bitstream,
+ const VAEncSequenceParameterBufferHEVC* seq,
+ const struct MoreVideoParameters* mvp);
+void PackSeqParameterSetNalUnit(struct Bitstream* bitstream,
+ const VAEncSequenceParameterBufferHEVC* seq,
+ const struct MoreVideoParameters* mvp,
+ const struct MoreSeqParameters* msp);
+void PackPicParameterSetNalUnit(struct Bitstream* bitstream,
+ const VAEncPictureParameterBufferHEVC* pic);
+void PackSliceSegmentHeaderNalUnit(struct Bitstream* bitstream,
+ const VAEncSequenceParameterBufferHEVC* seq,
+ const VAEncPictureParameterBufferHEVC* pic,
+ const VAEncSliceParameterBufferHEVC* slice,
+ const struct MoreSliceParamerters* msp);
+
+#endif // STREAMER_HEVC_H_