Home | History | Annotate | Download | only in model
      1 /*
      2 Copyright (c) 2011 Stanislav Vitvitskiy
      3 
      4 Permission is hereby granted, free of charge, to any person obtaining a copy of this
      5 software and associated documentation files (the "Software"), to deal in the Software
      6 without restriction, including without limitation the rights to use, copy, modify,
      7 merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
      8 permit persons to whom the Software is furnished to do so, subject to the following
      9 conditions:
     10 
     11 The above copyright notice and this permission notice shall be included in all copies or
     12 substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
     15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
     16 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
     17 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     18 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
     19 OR OTHER DEALINGS IN THE SOFTWARE.
     20 */
     21 package com.googlecode.mp4parser.h264.model;
     22 
     23 import com.googlecode.mp4parser.h264.read.CAVLCReader;
     24 import com.googlecode.mp4parser.h264.write.CAVLCWriter;
     25 
     26 import java.io.ByteArrayInputStream;
     27 import java.io.IOException;
     28 import java.io.InputStream;
     29 import java.io.OutputStream;
     30 import java.util.Arrays;
     31 
     32 /**
     33  * Picture Parameter Set entity of H264 bitstream
     34  * <p/>
     35  * capable to serialize / deserialize with CAVLC bitstream
     36  *
     37  * @author Stanislav Vitvitskiy
     38  */
     39 public class PictureParameterSet extends BitstreamElement {
     40 
     41     public static class PPSExt {
     42         public boolean transform_8x8_mode_flag;
     43         public ScalingMatrix scalindMatrix = new ScalingMatrix();
     44         public int second_chroma_qp_index_offset;
     45         public boolean[] pic_scaling_list_present_flag;
     46 
     47         @Override
     48         public String toString() {
     49             return "PPSExt{" +
     50                     "transform_8x8_mode_flag=" + transform_8x8_mode_flag +
     51                     ", scalindMatrix=" + scalindMatrix +
     52                     ", second_chroma_qp_index_offset=" + second_chroma_qp_index_offset +
     53                     ", pic_scaling_list_present_flag=" + pic_scaling_list_present_flag +
     54                     '}';
     55         }
     56     }
     57 
     58     public boolean entropy_coding_mode_flag;
     59     public int num_ref_idx_l0_active_minus1;
     60     public int num_ref_idx_l1_active_minus1;
     61     public int slice_group_change_rate_minus1;
     62     public int pic_parameter_set_id;
     63     public int seq_parameter_set_id;
     64     public boolean pic_order_present_flag;
     65     public int num_slice_groups_minus1;
     66     public int slice_group_map_type;
     67     public boolean weighted_pred_flag;
     68     public int weighted_bipred_idc;
     69     public int pic_init_qp_minus26;
     70     public int pic_init_qs_minus26;
     71     public int chroma_qp_index_offset;
     72     public boolean deblocking_filter_control_present_flag;
     73     public boolean constrained_intra_pred_flag;
     74     public boolean redundant_pic_cnt_present_flag;
     75     public int[] top_left;
     76     public int[] bottom_right;
     77     public int[] run_length_minus1;
     78     public boolean slice_group_change_direction_flag;
     79     public int[] slice_group_id;
     80     public PPSExt extended;
     81 
     82     public static PictureParameterSet read(byte[] b) throws IOException {
     83         return read(new ByteArrayInputStream(b));
     84     }
     85 
     86     public static PictureParameterSet read(InputStream is) throws IOException {
     87         CAVLCReader reader = new CAVLCReader(is);
     88         PictureParameterSet pps = new PictureParameterSet();
     89 
     90         pps.pic_parameter_set_id = reader.readUE("PPS: pic_parameter_set_id");
     91         pps.seq_parameter_set_id = reader.readUE("PPS: seq_parameter_set_id");
     92         pps.entropy_coding_mode_flag = reader
     93                 .readBool("PPS: entropy_coding_mode_flag");
     94         pps.pic_order_present_flag = reader
     95                 .readBool("PPS: pic_order_present_flag");
     96         pps.num_slice_groups_minus1 = reader
     97                 .readUE("PPS: num_slice_groups_minus1");
     98         if (pps.num_slice_groups_minus1 > 0) {
     99             pps.slice_group_map_type = reader
    100                     .readUE("PPS: slice_group_map_type");
    101             pps.top_left = new int[pps.num_slice_groups_minus1 + 1];
    102             pps.bottom_right = new int[pps.num_slice_groups_minus1 + 1];
    103             pps.run_length_minus1 = new int[pps.num_slice_groups_minus1 + 1];
    104             if (pps.slice_group_map_type == 0)
    105                 for (int iGroup = 0; iGroup <= pps.num_slice_groups_minus1; iGroup++)
    106                     pps.run_length_minus1[iGroup] = reader
    107                             .readUE("PPS: run_length_minus1");
    108             else if (pps.slice_group_map_type == 2)
    109                 for (int iGroup = 0; iGroup < pps.num_slice_groups_minus1; iGroup++) {
    110                     pps.top_left[iGroup] = reader.readUE("PPS: top_left");
    111                     pps.bottom_right[iGroup] = reader
    112                             .readUE("PPS: bottom_right");
    113                 }
    114             else if (pps.slice_group_map_type == 3
    115                     || pps.slice_group_map_type == 4
    116                     || pps.slice_group_map_type == 5) {
    117                 pps.slice_group_change_direction_flag = reader
    118                         .readBool("PPS: slice_group_change_direction_flag");
    119                 pps.slice_group_change_rate_minus1 = reader
    120                         .readUE("PPS: slice_group_change_rate_minus1");
    121             } else if (pps.slice_group_map_type == 6) {
    122                 int NumberBitsPerSliceGroupId;
    123                 if (pps.num_slice_groups_minus1 + 1 > 4)
    124                     NumberBitsPerSliceGroupId = 3;
    125                 else if (pps.num_slice_groups_minus1 + 1 > 2)
    126                     NumberBitsPerSliceGroupId = 2;
    127                 else
    128                     NumberBitsPerSliceGroupId = 1;
    129                 int pic_size_in_map_units_minus1 = reader
    130                         .readUE("PPS: pic_size_in_map_units_minus1");
    131                 pps.slice_group_id = new int[pic_size_in_map_units_minus1 + 1];
    132                 for (int i = 0; i <= pic_size_in_map_units_minus1; i++) {
    133                     pps.slice_group_id[i] = reader.readU(
    134                             NumberBitsPerSliceGroupId, "PPS: slice_group_id ["
    135                             + i + "]f");
    136                 }
    137             }
    138         }
    139         pps.num_ref_idx_l0_active_minus1 = reader
    140                 .readUE("PPS: num_ref_idx_l0_active_minus1");
    141         pps.num_ref_idx_l1_active_minus1 = reader
    142                 .readUE("PPS: num_ref_idx_l1_active_minus1");
    143         pps.weighted_pred_flag = reader.readBool("PPS: weighted_pred_flag");
    144         pps.weighted_bipred_idc = (int) reader.readNBit(2,
    145                 "PPS: weighted_bipred_idc");
    146         pps.pic_init_qp_minus26 = reader.readSE("PPS: pic_init_qp_minus26");
    147         pps.pic_init_qs_minus26 = reader.readSE("PPS: pic_init_qs_minus26");
    148         pps.chroma_qp_index_offset = reader
    149                 .readSE("PPS: chroma_qp_index_offset");
    150         pps.deblocking_filter_control_present_flag = reader
    151                 .readBool("PPS: deblocking_filter_control_present_flag");
    152         pps.constrained_intra_pred_flag = reader
    153                 .readBool("PPS: constrained_intra_pred_flag");
    154         pps.redundant_pic_cnt_present_flag = reader
    155                 .readBool("PPS: redundant_pic_cnt_present_flag");
    156         if (reader.moreRBSPData()) {
    157             pps.extended = new PictureParameterSet.PPSExt();
    158             pps.extended.transform_8x8_mode_flag = reader
    159                     .readBool("PPS: transform_8x8_mode_flag");
    160             boolean pic_scaling_matrix_present_flag = reader
    161                     .readBool("PPS: pic_scaling_matrix_present_flag");
    162             if (pic_scaling_matrix_present_flag) {
    163                 for (int i = 0; i < 6 + 2 * (pps.extended.transform_8x8_mode_flag ? 1
    164                         : 0); i++) {
    165                     boolean pic_scaling_list_present_flag = reader
    166                             .readBool("PPS: pic_scaling_list_present_flag");
    167                     if (pic_scaling_list_present_flag) {
    168                         pps.extended.scalindMatrix.ScalingList4x4 = new ScalingList[8];
    169                         pps.extended.scalindMatrix.ScalingList8x8 = new ScalingList[8];
    170                         if (i < 6) {
    171                             pps.extended.scalindMatrix.ScalingList4x4[i] = ScalingList
    172                                     .read(reader, 16);
    173                         } else {
    174                             pps.extended.scalindMatrix.ScalingList8x8[i - 6] = ScalingList
    175                                     .read(reader, 64);
    176                         }
    177                     }
    178                 }
    179             }
    180             pps.extended.second_chroma_qp_index_offset = reader
    181                     .readSE("PPS: second_chroma_qp_index_offset");
    182         }
    183 
    184         reader.readTrailingBits();
    185 
    186         return pps;
    187     }
    188 
    189     public void write(OutputStream out) throws IOException {
    190         CAVLCWriter writer = new CAVLCWriter(out);
    191 
    192         writer.writeUE(pic_parameter_set_id, "PPS: pic_parameter_set_id");
    193         writer.writeUE(seq_parameter_set_id, "PPS: seq_parameter_set_id");
    194         writer.writeBool(entropy_coding_mode_flag,
    195                 "PPS: entropy_coding_mode_flag");
    196         writer.writeBool(pic_order_present_flag, "PPS: pic_order_present_flag");
    197         writer.writeUE(num_slice_groups_minus1, "PPS: num_slice_groups_minus1");
    198         if (num_slice_groups_minus1 > 0) {
    199             writer.writeUE(slice_group_map_type, "PPS: slice_group_map_type");
    200             int[] top_left = new int[1];
    201             int[] bottom_right = new int[1];
    202             int[] run_length_minus1 = new int[1];
    203             if (slice_group_map_type == 0) {
    204                 for (int iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++) {
    205                     writer.writeUE(run_length_minus1[iGroup], "PPS: ");
    206                 }
    207             } else if (slice_group_map_type == 2) {
    208                 for (int iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) {
    209                     writer.writeUE(top_left[iGroup], "PPS: ");
    210                     writer.writeUE(bottom_right[iGroup], "PPS: ");
    211                 }
    212             } else if (slice_group_map_type == 3 || slice_group_map_type == 4
    213                     || slice_group_map_type == 5) {
    214                 writer.writeBool(slice_group_change_direction_flag,
    215                         "PPS: slice_group_change_direction_flag");
    216                 writer.writeUE(slice_group_change_rate_minus1,
    217                         "PPS: slice_group_change_rate_minus1");
    218             } else if (slice_group_map_type == 6) {
    219                 int NumberBitsPerSliceGroupId;
    220                 if (num_slice_groups_minus1 + 1 > 4)
    221                     NumberBitsPerSliceGroupId = 3;
    222                 else if (num_slice_groups_minus1 + 1 > 2)
    223                     NumberBitsPerSliceGroupId = 2;
    224                 else
    225                     NumberBitsPerSliceGroupId = 1;
    226                 writer.writeUE(slice_group_id.length, "PPS: ");
    227                 for (int i = 0; i <= slice_group_id.length; i++) {
    228                     writer.writeU(slice_group_id[i], NumberBitsPerSliceGroupId);
    229                 }
    230             }
    231         }
    232         writer.writeUE(num_ref_idx_l0_active_minus1,
    233                 "PPS: num_ref_idx_l0_active_minus1");
    234         writer.writeUE(num_ref_idx_l1_active_minus1,
    235                 "PPS: num_ref_idx_l1_active_minus1");
    236         writer.writeBool(weighted_pred_flag, "PPS: weighted_pred_flag");
    237         writer.writeNBit(weighted_bipred_idc, 2, "PPS: weighted_bipred_idc");
    238         writer.writeSE(pic_init_qp_minus26, "PPS: pic_init_qp_minus26");
    239         writer.writeSE(pic_init_qs_minus26, "PPS: pic_init_qs_minus26");
    240         writer.writeSE(chroma_qp_index_offset, "PPS: chroma_qp_index_offset");
    241         writer.writeBool(deblocking_filter_control_present_flag,
    242                 "PPS: deblocking_filter_control_present_flag");
    243         writer.writeBool(constrained_intra_pred_flag,
    244                 "PPS: constrained_intra_pred_flag");
    245         writer.writeBool(redundant_pic_cnt_present_flag,
    246                 "PPS: redundant_pic_cnt_present_flag");
    247         if (extended != null) {
    248             writer.writeBool(extended.transform_8x8_mode_flag,
    249                     "PPS: transform_8x8_mode_flag");
    250             writer.writeBool(extended.scalindMatrix != null,
    251                     "PPS: scalindMatrix");
    252             if (extended.scalindMatrix != null) {
    253                 for (int i = 0; i < 6 + 2 * (extended.transform_8x8_mode_flag ? 1
    254                         : 0); i++) {
    255                     if (i < 6) {
    256                         writer
    257                                 .writeBool(
    258                                         extended.scalindMatrix.ScalingList4x4[i] != null,
    259                                         "PPS: ");
    260                         if (extended.scalindMatrix.ScalingList4x4[i] != null) {
    261                             extended.scalindMatrix.ScalingList4x4[i]
    262                                     .write(writer);
    263                         }
    264 
    265                     } else {
    266                         writer
    267                                 .writeBool(
    268                                         extended.scalindMatrix.ScalingList8x8[i - 6] != null,
    269                                         "PPS: ");
    270                         if (extended.scalindMatrix.ScalingList8x8[i - 6] != null) {
    271                             extended.scalindMatrix.ScalingList8x8[i - 6]
    272                                     .write(writer);
    273                         }
    274                     }
    275                 }
    276             }
    277             writer.writeSE(extended.second_chroma_qp_index_offset, "PPS: ");
    278         }
    279 
    280         writer.writeTrailingBits();
    281     }
    282 
    283     @Override
    284     public int hashCode() {
    285         final int prime = 31;
    286         int result = 1;
    287         result = prime * result + Arrays.hashCode(bottom_right);
    288         result = prime * result + chroma_qp_index_offset;
    289         result = prime * result + (constrained_intra_pred_flag ? 1231 : 1237);
    290         result = prime * result
    291                 + (deblocking_filter_control_present_flag ? 1231 : 1237);
    292         result = prime * result + (entropy_coding_mode_flag ? 1231 : 1237);
    293         result = prime * result
    294                 + ((extended == null) ? 0 : extended.hashCode());
    295         result = prime * result + num_ref_idx_l0_active_minus1;
    296         result = prime * result + num_ref_idx_l1_active_minus1;
    297         result = prime * result + num_slice_groups_minus1;
    298         result = prime * result + pic_init_qp_minus26;
    299         result = prime * result + pic_init_qs_minus26;
    300         result = prime * result + (pic_order_present_flag ? 1231 : 1237);
    301         result = prime * result + pic_parameter_set_id;
    302         result = prime * result
    303                 + (redundant_pic_cnt_present_flag ? 1231 : 1237);
    304         result = prime * result + Arrays.hashCode(run_length_minus1);
    305         result = prime * result + seq_parameter_set_id;
    306         result = prime * result
    307                 + (slice_group_change_direction_flag ? 1231 : 1237);
    308         result = prime * result + slice_group_change_rate_minus1;
    309         result = prime * result + Arrays.hashCode(slice_group_id);
    310         result = prime * result + slice_group_map_type;
    311         result = prime * result + Arrays.hashCode(top_left);
    312         result = prime * result + weighted_bipred_idc;
    313         result = prime * result + (weighted_pred_flag ? 1231 : 1237);
    314         return result;
    315     }
    316 
    317     @Override
    318     public boolean equals(Object obj) {
    319         if (this == obj)
    320             return true;
    321         if (obj == null)
    322             return false;
    323         if (getClass() != obj.getClass())
    324             return false;
    325         PictureParameterSet other = (PictureParameterSet) obj;
    326         if (!Arrays.equals(bottom_right, other.bottom_right))
    327             return false;
    328         if (chroma_qp_index_offset != other.chroma_qp_index_offset)
    329             return false;
    330         if (constrained_intra_pred_flag != other.constrained_intra_pred_flag)
    331             return false;
    332         if (deblocking_filter_control_present_flag != other.deblocking_filter_control_present_flag)
    333             return false;
    334         if (entropy_coding_mode_flag != other.entropy_coding_mode_flag)
    335             return false;
    336         if (extended == null) {
    337             if (other.extended != null)
    338                 return false;
    339         } else if (!extended.equals(other.extended))
    340             return false;
    341         if (num_ref_idx_l0_active_minus1 != other.num_ref_idx_l0_active_minus1)
    342             return false;
    343         if (num_ref_idx_l1_active_minus1 != other.num_ref_idx_l1_active_minus1)
    344             return false;
    345         if (num_slice_groups_minus1 != other.num_slice_groups_minus1)
    346             return false;
    347         if (pic_init_qp_minus26 != other.pic_init_qp_minus26)
    348             return false;
    349         if (pic_init_qs_minus26 != other.pic_init_qs_minus26)
    350             return false;
    351         if (pic_order_present_flag != other.pic_order_present_flag)
    352             return false;
    353         if (pic_parameter_set_id != other.pic_parameter_set_id)
    354             return false;
    355         if (redundant_pic_cnt_present_flag != other.redundant_pic_cnt_present_flag)
    356             return false;
    357         if (!Arrays.equals(run_length_minus1, other.run_length_minus1))
    358             return false;
    359         if (seq_parameter_set_id != other.seq_parameter_set_id)
    360             return false;
    361         if (slice_group_change_direction_flag != other.slice_group_change_direction_flag)
    362             return false;
    363         if (slice_group_change_rate_minus1 != other.slice_group_change_rate_minus1)
    364             return false;
    365         if (!Arrays.equals(slice_group_id, other.slice_group_id))
    366             return false;
    367         if (slice_group_map_type != other.slice_group_map_type)
    368             return false;
    369         if (!Arrays.equals(top_left, other.top_left))
    370             return false;
    371         if (weighted_bipred_idc != other.weighted_bipred_idc)
    372             return false;
    373         if (weighted_pred_flag != other.weighted_pred_flag)
    374             return false;
    375         return true;
    376     }
    377 
    378     @Override
    379     public String toString() {
    380         return "PictureParameterSet{" +
    381                 "\n       entropy_coding_mode_flag=" + entropy_coding_mode_flag +
    382                 ",\n       num_ref_idx_l0_active_minus1=" + num_ref_idx_l0_active_minus1 +
    383                 ",\n       num_ref_idx_l1_active_minus1=" + num_ref_idx_l1_active_minus1 +
    384                 ",\n       slice_group_change_rate_minus1=" + slice_group_change_rate_minus1 +
    385                 ",\n       pic_parameter_set_id=" + pic_parameter_set_id +
    386                 ",\n       seq_parameter_set_id=" + seq_parameter_set_id +
    387                 ",\n       pic_order_present_flag=" + pic_order_present_flag +
    388                 ",\n       num_slice_groups_minus1=" + num_slice_groups_minus1 +
    389                 ",\n       slice_group_map_type=" + slice_group_map_type +
    390                 ",\n       weighted_pred_flag=" + weighted_pred_flag +
    391                 ",\n       weighted_bipred_idc=" + weighted_bipred_idc +
    392                 ",\n       pic_init_qp_minus26=" + pic_init_qp_minus26 +
    393                 ",\n       pic_init_qs_minus26=" + pic_init_qs_minus26 +
    394                 ",\n       chroma_qp_index_offset=" + chroma_qp_index_offset +
    395                 ",\n       deblocking_filter_control_present_flag=" + deblocking_filter_control_present_flag +
    396                 ",\n       constrained_intra_pred_flag=" + constrained_intra_pred_flag +
    397                 ",\n       redundant_pic_cnt_present_flag=" + redundant_pic_cnt_present_flag +
    398                 ",\n       top_left=" + top_left +
    399                 ",\n       bottom_right=" + bottom_right +
    400                 ",\n       run_length_minus1=" + run_length_minus1 +
    401                 ",\n       slice_group_change_direction_flag=" + slice_group_change_direction_flag +
    402                 ",\n       slice_group_id=" + slice_group_id +
    403                 ",\n       extended=" + extended +
    404                 '}';
    405     }
    406 }
    407