All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jcodec.codecs.h264.io.write.SliceHeaderWriter Maven / Gradle / Ivy

There is a newer version: 0.2.5
Show newest version
package org.jcodec.codecs.h264.io.write;

import static org.jcodec.codecs.h264.io.write.CAVLCWriter.writeBool;
import static org.jcodec.codecs.h264.io.write.CAVLCWriter.writeSE;
import static org.jcodec.codecs.h264.io.write.CAVLCWriter.writeU;
import static org.jcodec.codecs.h264.io.write.CAVLCWriter.writeUE;
import static org.jcodec.common.model.ColorSpace.MONO;

import org.jcodec.codecs.h264.io.model.PictureParameterSet;
import org.jcodec.codecs.h264.io.model.RefPicMarking;
import org.jcodec.codecs.h264.io.model.RefPicMarking.Instruction;
import org.jcodec.codecs.h264.io.model.RefPicMarkingIDR;
import org.jcodec.codecs.h264.io.model.SeqParameterSet;
import org.jcodec.codecs.h264.io.model.SliceHeader;
import org.jcodec.codecs.h264.io.model.SliceType;
import org.jcodec.common.io.BitWriter;

/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed
 * under FreeBSD License
 * 
 * A writer for slice header data structure
 * 
 * @author Jay Codec
 * 
 */
public class SliceHeaderWriter {
    public void write(SliceHeader sliceHeader, boolean idrSlice, int nalRefIdc, BitWriter writer) {
        SeqParameterSet sps = sliceHeader.sps;
        PictureParameterSet pps = sliceHeader.pps;
        writeUE(writer, sliceHeader.first_mb_in_slice, "SH: first_mb_in_slice");
        writeUE(writer, sliceHeader.slice_type.ordinal() + (sliceHeader.slice_type_restr ? 5 : 0), "SH: slice_type");
        writeUE(writer, sliceHeader.pic_parameter_set_id, "SH: pic_parameter_set_id");
        writeU(writer, sliceHeader.frame_num, sps.log2_max_frame_num_minus4 + 4, "SH: frame_num");
        if (!sps.frame_mbs_only_flag) {
            writeBool(writer, sliceHeader.field_pic_flag, "SH: field_pic_flag");
            if (sliceHeader.field_pic_flag) {
                writeBool(writer, sliceHeader.bottom_field_flag, "SH: bottom_field_flag");
            }
        }
        if (idrSlice) {
            writeUE(writer, sliceHeader.idr_pic_id, "SH: idr_pic_id");
        }
        if (sps.pic_order_cnt_type == 0) {
            writeU(writer, sliceHeader.pic_order_cnt_lsb, sps.log2_max_pic_order_cnt_lsb_minus4 + 4);
            if (pps.pic_order_present_flag && !sps.field_pic_flag) {
                writeSE(writer, sliceHeader.delta_pic_order_cnt_bottom, "SH: delta_pic_order_cnt_bottom");
            }
        }
        if (sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero_flag) {
            writeSE(writer, sliceHeader.delta_pic_order_cnt[0], "SH: delta_pic_order_cnt");
            if (pps.pic_order_present_flag && !sps.field_pic_flag)
                writeSE(writer, sliceHeader.delta_pic_order_cnt[1], "SH: delta_pic_order_cnt");
        }
        if (pps.redundant_pic_cnt_present_flag) {
            writeUE(writer, sliceHeader.redundant_pic_cnt, "SH: redundant_pic_cnt");
        }
        if (sliceHeader.slice_type == SliceType.B) {
            writeBool(writer, sliceHeader.direct_spatial_mv_pred_flag, "SH: direct_spatial_mv_pred_flag");
        }
        if (sliceHeader.slice_type == SliceType.P || sliceHeader.slice_type == SliceType.SP
                || sliceHeader.slice_type == SliceType.B) {
            writeBool(writer, sliceHeader.num_ref_idx_active_override_flag, "SH: num_ref_idx_active_override_flag");
            if (sliceHeader.num_ref_idx_active_override_flag) {
                writeUE(writer, sliceHeader.num_ref_idx_active_minus1[0], "SH: num_ref_idx_l0_active_minus1");
                if (sliceHeader.slice_type == SliceType.B) {
                    writeUE(writer, sliceHeader.num_ref_idx_active_minus1[1], "SH: num_ref_idx_l1_active_minus1");
                }
            }
        }
        writeRefPicListReordering(sliceHeader, writer);
        if ((pps.weighted_pred_flag && (sliceHeader.slice_type == SliceType.P || sliceHeader.slice_type == SliceType.SP))
                || (pps.weighted_bipred_idc == 1 && sliceHeader.slice_type == SliceType.B))
            writePredWeightTable(sliceHeader, writer);
        if (nalRefIdc != 0)
            writeDecRefPicMarking(sliceHeader, idrSlice, writer);
        if (pps.entropy_coding_mode_flag && sliceHeader.slice_type.isInter()) {
            writeUE(writer, sliceHeader.cabac_init_idc, "SH: cabac_init_idc");
        }
        writeSE(writer, sliceHeader.slice_qp_delta, "SH: slice_qp_delta");
        if (sliceHeader.slice_type == SliceType.SP || sliceHeader.slice_type == SliceType.SI) {
            if (sliceHeader.slice_type == SliceType.SP) {
                writeBool(writer, sliceHeader.sp_for_switch_flag, "SH: sp_for_switch_flag");
            }
            writeSE(writer, sliceHeader.slice_qs_delta, "SH: slice_qs_delta");
        }
        if (pps.deblocking_filter_control_present_flag) {
            writeUE(writer, sliceHeader.disable_deblocking_filter_idc, "SH: disable_deblocking_filter_idc");
            if (sliceHeader.disable_deblocking_filter_idc != 1) {
                writeSE(writer, sliceHeader.slice_alpha_c0_offset_div2, "SH: slice_alpha_c0_offset_div2");
                writeSE(writer, sliceHeader.slice_beta_offset_div2, "SH: slice_beta_offset_div2");
            }
        }
        if (pps.num_slice_groups_minus1 > 0 && pps.slice_group_map_type >= 3 && pps.slice_group_map_type <= 5) {
            int len = (sps.pic_height_in_map_units_minus1 + 1) * (sps.pic_width_in_mbs_minus1 + 1)
                    / (pps.slice_group_change_rate_minus1 + 1);
            if (((sps.pic_height_in_map_units_minus1 + 1) * (sps.pic_width_in_mbs_minus1 + 1))
                    % (pps.slice_group_change_rate_minus1 + 1) > 0)
                len += 1;

            len = CeilLog2(len + 1);
            writeU(writer, sliceHeader.slice_group_change_cycle, len);
        }

    }

    private static int CeilLog2(int uiVal) {
        int uiTmp = uiVal - 1;
        int uiRet = 0;

        while (uiTmp != 0) {
            uiTmp >>= 1;
            uiRet++;
        }
        return uiRet;
    }

    private void writeDecRefPicMarking(SliceHeader sliceHeader, boolean idrSlice, BitWriter writer) {
        if (idrSlice) {
            RefPicMarkingIDR drpmidr = sliceHeader.refPicMarkingIDR;
            writeBool(writer, drpmidr.isDiscardDecodedPics(), "SH: no_output_of_prior_pics_flag");
            writeBool(writer, drpmidr.isUseForlongTerm(), "SH: long_term_reference_flag");
        } else {
            writeBool(writer, sliceHeader.refPicMarkingNonIDR != null, "SH: adaptive_ref_pic_marking_mode_flag");
            if (sliceHeader.refPicMarkingNonIDR != null) {
                RefPicMarking drpmidr = sliceHeader.refPicMarkingNonIDR;
                for (Instruction mmop : drpmidr.getInstructions()) {
                    switch (mmop.getType()) {
                    case REMOVE_SHORT:
                        writeUE(writer, 1, "SH: memory_management_control_operation");
                        writeUE(writer, mmop.getArg1() - 1, "SH: difference_of_pic_nums_minus1");
                        break;
                    case REMOVE_LONG:
                        writeUE(writer, 2, "SH: memory_management_control_operation");
                        writeUE(writer, mmop.getArg1(), "SH: long_term_pic_num");
                        break;
                    case CONVERT_INTO_LONG:
                        writeUE(writer, 3, "SH: memory_management_control_operation");
                        writeUE(writer, mmop.getArg1() - 1, "SH: difference_of_pic_nums_minus1");
                        writeUE(writer, mmop.getArg2(), "SH: long_term_frame_idx");
                        break;
                    case TRUNK_LONG:
                        writeUE(writer, 4, "SH: memory_management_control_operation");
                        writeUE(writer, mmop.getArg1() + 1, "SH: max_long_term_frame_idx_plus1");
                        break;
                    case CLEAR:
                        writeUE(writer, 5, "SH: memory_management_control_operation");
                        break;
                    case MARK_LONG:
                        writeUE(writer, 6, "SH: memory_management_control_operation");
                        writeUE(writer, mmop.getArg1(), "SH: long_term_frame_idx");
                        break;
                    }
                }
                writeUE(writer, 0, "SH: memory_management_control_operation");
            }
        }
    }

    private void writePredWeightTable(SliceHeader sliceHeader, BitWriter writer) {
        SeqParameterSet sps = sliceHeader.sps;
        writeUE(writer, sliceHeader.pred_weight_table.luma_log2_weight_denom, "SH: luma_log2_weight_denom");
        if (sps.chroma_format_idc != MONO) {
            writeUE(writer, sliceHeader.pred_weight_table.chroma_log2_weight_denom, "SH: chroma_log2_weight_denom");
        }

        writeOffsetWeight(sliceHeader, writer, 0);
        if (sliceHeader.slice_type == SliceType.B) {
            writeOffsetWeight(sliceHeader, writer, 1);
        }
    }

    private void writeOffsetWeight(SliceHeader sliceHeader, BitWriter writer, int list) {
        SeqParameterSet sps = sliceHeader.sps;
        int defaultLW = 1 << sliceHeader.pred_weight_table.luma_log2_weight_denom;
        int defaultCW = 1 << sliceHeader.pred_weight_table.chroma_log2_weight_denom;
        
        for (int i = 0; i < sliceHeader.pred_weight_table.luma_weight[list].length; i++) {
            boolean flagLuma = sliceHeader.pred_weight_table.luma_weight[list][i] != defaultLW
                    || sliceHeader.pred_weight_table.luma_offset[list][i] != 0;
            writeBool(writer, flagLuma, "SH: luma_weight_l0_flag");
            if (flagLuma) {
                writeSE(writer, sliceHeader.pred_weight_table.luma_weight[list][i], "SH: luma_weight_l" + list);
                writeSE(writer, sliceHeader.pred_weight_table.luma_offset[list][i], "SH: luma_offset_l" + list);
            }
            if (sps.chroma_format_idc != MONO) {
                boolean flagChroma = sliceHeader.pred_weight_table.chroma_weight[list][0][i] != defaultCW
                        || sliceHeader.pred_weight_table.chroma_offset[list][0][i] != 0
                        || sliceHeader.pred_weight_table.chroma_weight[list][1][i] != defaultCW
                        || sliceHeader.pred_weight_table.chroma_offset[list][1][i] != 0;
                writeBool(writer, flagChroma, "SH: chroma_weight_l0_flag");
                if (flagChroma)
                    for (int j = 0; j < 2; j++) {
                        writeSE(writer, sliceHeader.pred_weight_table.chroma_weight[list][j][i], "SH: chroma_weight_l" + list);
                        writeSE(writer, sliceHeader.pred_weight_table.chroma_offset[list][j][i], "SH: chroma_offset_l" + list);
                    }
            }
        }
    }

    private void writeRefPicListReordering(SliceHeader sliceHeader, BitWriter writer) {
        if (sliceHeader.slice_type.isInter()) {
            writeBool(writer, sliceHeader.refPicReordering[0] != null, "SH: ref_pic_list_reordering_flag_l0");
            writeReorderingList(sliceHeader.refPicReordering[0], writer);
        }
        if (sliceHeader.slice_type == SliceType.B) {
            writeBool(writer, sliceHeader.refPicReordering[1] != null, "SH: ref_pic_list_reordering_flag_l1");
            writeReorderingList(sliceHeader.refPicReordering[1], writer);
        }
    }

    private void writeReorderingList(int[][] reordering, BitWriter writer) {
        if (reordering == null)
            return;

        for (int i = 0; i < reordering[0].length; i++) {
            writeUE(writer, reordering[0][i], "SH: reordering_of_pic_nums_idc");
            writeUE(writer, reordering[1][i], "SH: abs_diff_pic_num_minus1");
        }
        writeUE(writer, 3, "SH: reordering_of_pic_nums_idc");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy