PictureParameterSet.java revision dd9eb897ee7c7b507cbdcf80263bb4b5de6966bf
1/*
2Copyright (c) 2011 Stanislav Vitvitskiy
3
4Permission is hereby granted, free of charge, to any person obtaining a copy of this
5software and associated documentation files (the "Software"), to deal in the Software
6without restriction, including without limitation the rights to use, copy, modify,
7merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8permit persons to whom the Software is furnished to do so, subject to the following
9conditions:
10
11The above copyright notice and this permission notice shall be included in all copies or
12substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
17FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
19OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21package com.googlecode.mp4parser.h264.model;
22
23import com.googlecode.mp4parser.h264.read.CAVLCReader;
24import com.googlecode.mp4parser.h264.write.CAVLCWriter;
25
26import java.io.ByteArrayInputStream;
27import java.io.IOException;
28import java.io.InputStream;
29import java.io.OutputStream;
30import 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 */
39public 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