package org.mp4parser.muxer.tracks.h264; import org.mp4parser.muxer.tracks.h264.parsing.model.SeqParameterSet; import org.mp4parser.muxer.tracks.h264.parsing.read.CAVLCReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; /** * Created by sannies on 15.08.2015. */ public class SEIMessage { int payloadType = 0; int payloadSize = 0; boolean removal_delay_flag; int cpb_removal_delay; int dpb_removal_delay; boolean clock_timestamp_flag; int pic_struct; int ct_type; int nuit_field_based_flag; int counting_type; int full_timestamp_flag; int discontinuity_flag; int cnt_dropped_flag; int n_frames; int seconds_value; int minutes_value; int hours_value; int time_offset_length; int time_offset; SeqParameterSet sps; public SEIMessage(InputStream is, SeqParameterSet sps) throws IOException { this.sps = sps; is.read(); int datasize = is.available(); int read = 0; while (read < datasize) { payloadType = 0; payloadSize = 0; int last_payload_type_bytes = is.read(); read++; while (last_payload_type_bytes == 0xff) { payloadType += last_payload_type_bytes; last_payload_type_bytes = is.read(); read++; } payloadType += last_payload_type_bytes; int last_payload_size_bytes = is.read(); read++; while (last_payload_size_bytes == 0xff) { payloadSize += last_payload_size_bytes; last_payload_size_bytes = is.read(); read++; } payloadSize += last_payload_size_bytes; if (datasize - read >= payloadSize) { if (payloadType == 1) { // pic_timing is what we are interested in! if (sps.vuiParams != null && (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null || sps.vuiParams.pic_struct_present_flag)) { byte[] data = new byte[payloadSize]; is.read(data); read += payloadSize; CAVLCReader reader = new CAVLCReader(new ByteArrayInputStream(data)); if (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null) { removal_delay_flag = true; cpb_removal_delay = reader.readU(sps.vuiParams.nalHRDParams.cpb_removal_delay_length_minus1 + 1, "SEI: cpb_removal_delay"); dpb_removal_delay = reader.readU(sps.vuiParams.nalHRDParams.dpb_output_delay_length_minus1 + 1, "SEI: dpb_removal_delay"); } else { removal_delay_flag = false; } if (sps.vuiParams.pic_struct_present_flag) { pic_struct = reader.readU(4, "SEI: pic_struct"); int numClockTS; switch (pic_struct) { case 0: case 1: case 2: default: numClockTS = 1; break; case 3: case 4: case 7: numClockTS = 2; break; case 5: case 6: case 8: numClockTS = 3; break; } for (int i = 0; i < numClockTS; i++) { clock_timestamp_flag = reader.readBool("pic_timing SEI: clock_timestamp_flag[" + i + "]"); if (clock_timestamp_flag) { ct_type = reader.readU(2, "pic_timing SEI: ct_type"); nuit_field_based_flag = reader.readU(1, "pic_timing SEI: nuit_field_based_flag"); counting_type = reader.readU(5, "pic_timing SEI: counting_type"); full_timestamp_flag = reader.readU(1, "pic_timing SEI: full_timestamp_flag"); discontinuity_flag = reader.readU(1, "pic_timing SEI: discontinuity_flag"); cnt_dropped_flag = reader.readU(1, "pic_timing SEI: cnt_dropped_flag"); n_frames = reader.readU(8, "pic_timing SEI: n_frames"); if (full_timestamp_flag == 1) { seconds_value = reader.readU(6, "pic_timing SEI: seconds_value"); minutes_value = reader.readU(6, "pic_timing SEI: minutes_value"); hours_value = reader.readU(5, "pic_timing SEI: hours_value"); } else { if (reader.readBool("pic_timing SEI: seconds_flag")) { seconds_value = reader.readU(6, "pic_timing SEI: seconds_value"); if (reader.readBool("pic_timing SEI: minutes_flag")) { minutes_value = reader.readU(6, "pic_timing SEI: minutes_value"); if (reader.readBool("pic_timing SEI: hours_flag")) { hours_value = reader.readU(5, "pic_timing SEI: hours_value"); } } } } if (true) { if (sps.vuiParams.nalHRDParams != null) { time_offset_length = sps.vuiParams.nalHRDParams.time_offset_length; } else if (sps.vuiParams.vclHRDParams != null) { time_offset_length = sps.vuiParams.vclHRDParams.time_offset_length; } else { time_offset_length = 24; } time_offset = reader.readU(24, "pic_timing SEI: time_offset"); } } } } } else { for (int i = 0; i < payloadSize; i++) { is.read(); read++; } } } else { for (int i = 0; i < payloadSize; i++) { is.read(); read++; } } } else { read = datasize; } } } @Override public String toString() { String out = "SEIMessage{" + "payloadType=" + payloadType + ", payloadSize=" + payloadSize; if (payloadType == 1) { if (sps.vuiParams.nalHRDParams != null || sps.vuiParams.vclHRDParams != null) { out += ", cpb_removal_delay=" + cpb_removal_delay + ", dpb_removal_delay=" + dpb_removal_delay; } if (sps.vuiParams.pic_struct_present_flag) { out += ", pic_struct=" + pic_struct; if (clock_timestamp_flag) { out += ", ct_type=" + ct_type + ", nuit_field_based_flag=" + nuit_field_based_flag + ", counting_type=" + counting_type + ", full_timestamp_flag=" + full_timestamp_flag + ", discontinuity_flag=" + discontinuity_flag + ", cnt_dropped_flag=" + cnt_dropped_flag + ", n_frames=" + n_frames + ", seconds_value=" + seconds_value + ", minutes_value=" + minutes_value + ", hours_value=" + hours_value + ", time_offset_length=" + time_offset_length + ", time_offset=" + time_offset; } } } out += '}'; return out; } }