return FALSE;
}
+static gboolean
+gst_h264_write_sei_pic_timing (NalWriter * nw, GstH264PicTiming * tim)
+{
+ if (tim->CpbDpbDelaysPresentFlag) {
+ WRITE_UINT32 (nw, tim->cpb_removal_delay,
+ tim->cpb_removal_delay_length_minus1 + 1);
+ WRITE_UINT32 (nw, tim->dpb_output_delay,
+ tim->dpb_output_delay_length_minus1 + 1);
+ }
+
+ if (tim->pic_struct_present_flag) {
+ const guint8 num_clock_ts_table[9] = {
+ 1, 1, 1, 2, 2, 3, 3, 2, 3
+ };
+ guint8 num_clock_num_ts;
+ guint i;
+
+ WRITE_UINT8 (nw, tim->pic_struct, 4);
+
+ num_clock_num_ts = num_clock_ts_table[tim->pic_struct];
+ for (i = 0; i < num_clock_num_ts; i++) {
+ WRITE_UINT8 (nw, tim->clock_timestamp_flag[i], 1);
+ if (tim->clock_timestamp_flag[i]) {
+ GstH264ClockTimestamp *timestamp = &tim->clock_timestamp[i];
+
+ WRITE_UINT8 (nw, timestamp->ct_type, 2);
+ WRITE_UINT8 (nw, timestamp->nuit_field_based_flag, 1);
+ WRITE_UINT8 (nw, timestamp->counting_type, 5);
+ WRITE_UINT8 (nw, timestamp->full_timestamp_flag, 1);
+ WRITE_UINT8 (nw, timestamp->discontinuity_flag, 1);
+ WRITE_UINT8 (nw, timestamp->cnt_dropped_flag, 1);
+ WRITE_UINT8 (nw, timestamp->n_frames, 8);
+
+ if (timestamp->full_timestamp_flag) {
+ WRITE_UINT8 (nw, timestamp->seconds_value, 6);
+ WRITE_UINT8 (nw, timestamp->minutes_value, 6);
+ WRITE_UINT8 (nw, timestamp->hours_value, 5);
+ } else {
+ WRITE_UINT8 (nw, timestamp->seconds_flag, 1);
+ if (timestamp->seconds_flag) {
+ WRITE_UINT8 (nw, timestamp->seconds_value, 6);
+ WRITE_UINT8 (nw, timestamp->minutes_flag, 1);
+ if (timestamp->minutes_flag) {
+ WRITE_UINT8 (nw, timestamp->minutes_value, 6);
+ WRITE_UINT8 (nw, timestamp->hours_flag, 1);
+ if (timestamp->hours_flag)
+ WRITE_UINT8 (nw, timestamp->hours_value, 5);
+ }
+ }
+ }
+
+ if (tim->time_offset_length > 0) {
+ WRITE_UINT32 (nw, timestamp->time_offset, tim->time_offset_length);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ return FALSE;
+}
+
static GstMemory *
gst_h264_create_sei_memory_internal (guint8 nal_prefix_size,
gboolean packetized, GArray * messages)
*/
payload_size_data = 4;
break;
+ case GST_H264_SEI_PIC_TIMING:{
+ GstH264PicTiming *tim = &msg->payload.pic_timing;
+ const guint8 num_clock_ts_table[9] = {
+ 1, 1, 1, 2, 2, 3, 3, 2, 3
+ };
+ guint8 num_clock_num_ts;
+ guint i;
+
+ if (!tim->CpbDpbDelaysPresentFlag && !tim->pic_struct_present_flag) {
+ GST_WARNING
+ ("Both CpbDpbDelaysPresentFlag and pic_struct_present_flag are zero");
+ break;
+ }
+
+ if (tim->CpbDpbDelaysPresentFlag) {
+ payload_size_in_bits = tim->cpb_removal_delay_length_minus1 + 1;
+ payload_size_in_bits += tim->dpb_output_delay_length_minus1 + 1;
+ }
+
+ if (tim->pic_struct_present_flag) {
+ /* pic_struct: 4bits */
+ payload_size_in_bits += 4;
+
+ num_clock_num_ts = num_clock_ts_table[tim->pic_struct];
+ for (i = 0; i < num_clock_num_ts; i++) {
+ /* clock_timestamp_flag: 1bit */
+ payload_size_in_bits++;
+
+ if (tim->clock_timestamp_flag[i]) {
+ GstH264ClockTimestamp *timestamp = &tim->clock_timestamp[i];
+
+ /* ct_type: 2bits
+ * nuit_field_based_flag: 1bit
+ * counting_type: 5bits
+ * full_timestamp_flag: 1bit
+ * discontinuity_flag: 1bit
+ * cnt_dropped_flag: 1bit
+ * n_frames: 8bits
+ */
+ payload_size_in_bits += 19;
+ if (timestamp->full_timestamp_flag) {
+ /* seconds_value: 6bits
+ * minutes_value: 6bits
+ * hours_value: 5bits
+ */
+ payload_size_in_bits += 17;
+ } else {
+ /* seconds_flag: 1bit */
+ payload_size_in_bits++;
+
+ if (timestamp->seconds_flag) {
+ /* seconds_value: 6bits
+ * minutes_flag: 1bit
+ */
+ payload_size_in_bits += 7;
+ if (timestamp->minutes_flag) {
+ /* minutes_value: 6bits
+ * hours_flag: 1bits
+ */
+ payload_size_in_bits += 7;
+ if (timestamp->hours_flag) {
+ /* hours_value: 5bits */
+ payload_size_in_bits += 5;
+ }
+ }
+ }
+ }
+
+ /* time_offset_length bits */
+ payload_size_in_bits += tim->time_offset_length;
+ }
+ }
+ }
+
+ payload_size_data = payload_size_in_bits >> 3;
+
+ if ((payload_size_in_bits & 0x7) != 0) {
+ GST_INFO ("Bits for Picture Timing SEI is not byte aligned");
+ payload_size_data++;
+ need_align = TRUE;
+ }
+ break;
+ }
default:
break;
}
}
have_written_data = TRUE;
break;
+ case GST_H264_SEI_PIC_TIMING:
+ GST_DEBUG ("Writing \"Picture timing\"");
+ if (!gst_h264_write_sei_pic_timing (&nw, &msg->payload.pic_timing)) {
+ GST_WARNING ("Failed to write \"Picture timing\"");
+ goto error;
+ }
+ have_written_data = TRUE;
+ break;
default:
break;
}
};
static guint8 nalu_sei_pic_timing[] = {
- 0x00, 0x00, 0x01, 0x06, 0x01, 0x01, 0x32, 0x80
+ 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x01, 0x32, 0x80
};
static guint8 nalu_chained_sei[] = {
(a->max_pic_average_light_level == b->max_pic_average_light_level);
}
+static gboolean
+check_sei_pic_timing (const GstH264PicTiming * a, const GstH264PicTiming * b)
+{
+ if (a->CpbDpbDelaysPresentFlag != b->CpbDpbDelaysPresentFlag)
+ return FALSE;
+
+ if (a->CpbDpbDelaysPresentFlag) {
+ if (a->cpb_removal_delay != b->cpb_removal_delay ||
+ a->cpb_removal_delay_length_minus1 != b->cpb_removal_delay_length_minus1
+ || a->dpb_output_delay != b->dpb_output_delay
+ || a->dpb_output_delay_length_minus1 !=
+ b->dpb_output_delay_length_minus1)
+ return FALSE;
+ }
+
+ if (a->pic_struct_present_flag != b->pic_struct_present_flag)
+ return FALSE;
+
+ if (a->pic_struct_present_flag) {
+ const guint8 num_clock_ts_table[9] = {
+ 1, 1, 1, 2, 2, 3, 3, 2, 3
+ };
+ guint8 num_clock_num_ts;
+ guint i;
+
+ if (a->pic_struct != b->pic_struct)
+ return FALSE;
+
+ if (a->time_offset_length != b->time_offset_length)
+ return FALSE;
+
+ num_clock_num_ts = num_clock_ts_table[a->pic_struct];
+
+ for (i = 0; i < num_clock_num_ts; i++) {
+ if (a->clock_timestamp_flag[i] != b->clock_timestamp_flag[i])
+ return FALSE;
+
+ if (a->clock_timestamp_flag[i]) {
+ const GstH264ClockTimestamp *ta = &a->clock_timestamp[i];
+ const GstH264ClockTimestamp *tb = &b->clock_timestamp[i];
+
+ if (ta->ct_type != tb->ct_type ||
+ ta->nuit_field_based_flag != tb->nuit_field_based_flag ||
+ ta->counting_type != tb->counting_type ||
+ ta->discontinuity_flag != tb->discontinuity_flag ||
+ ta->cnt_dropped_flag != tb->cnt_dropped_flag ||
+ ta->n_frames != tb->n_frames)
+ return FALSE;
+
+ if (ta->full_timestamp_flag) {
+ if (ta->seconds_value != tb->seconds_value ||
+ ta->minutes_value != tb->minutes_value ||
+ ta->hours_value != tb->hours_value)
+ return FALSE;
+ } else {
+ if (ta->seconds_flag != tb->seconds_flag)
+ return FALSE;
+
+ if (ta->seconds_flag) {
+ if (ta->seconds_value != tb->seconds_value ||
+ ta->minutes_flag != tb->minutes_flag)
+ return FALSE;
+
+ if (ta->minutes_flag) {
+ if (ta->minutes_value != tb->minutes_value ||
+ ta->hours_flag != tb->hours_flag)
+ return FALSE;
+
+ if (ta->hours_flag) {
+ if (ta->hours_value != tb->hours_value)
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ if (ta->time_offset != tb->time_offset)
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
GST_START_TEST (test_h264_create_sei)
{
GstH264NalParser *parser;
{h264_sei_cll, G_N_ELEMENTS (h264_sei_cll),
GST_H264_SEI_CONTENT_LIGHT_LEVEL, {0,},
(SEICheckFunc) check_sei_cll},
+ {nalu_sei_pic_timing, G_N_ELEMENTS (nalu_sei_pic_timing),
+ GST_H264_SEI_PIC_TIMING, {0,},
+ (SEICheckFunc) check_sei_pic_timing},
/* *INDENT-ON* */
};
parser = gst_h264_nal_parser_new ();
+ /* inject SPS for picture timing sei */
+ parse_ret =
+ gst_h264_parser_identify_nalu_unchecked (parser, nalu_sps_with_vui, 0,
+ sizeof (nalu_sps_with_vui), &nalu);
+ assert_equals_int (parse_ret, GST_H264_PARSER_OK);
+ assert_equals_int (nalu.type, GST_H264_NAL_SPS);
+ assert_equals_int (nalu.size, 28);
+
+ parse_ret = gst_h264_parser_parse_nal (parser, &nalu);
+ assert_equals_int (parse_ret, GST_H264_PARSER_OK);
+
/* test single sei message per sei nal unit */
for (i = 0; i < G_N_ELEMENTS (test_list); i++) {
gsize nal_size;