h26{4,5}parse: add support for forward predicted trick mode
authorMathieu Duponchelle <mathieu@centricular.com>
Wed, 10 Jul 2019 21:40:36 +0000 (23:40 +0200)
committerMathieu Duponchelle <mduponchelle1@gmail.com>
Thu, 18 Jul 2019 13:46:45 +0000 (13:46 +0000)
Also stop assigning TRUE to fields with |=

gst/videoparsers/gsth264parse.c
gst/videoparsers/gsth264parse.h
gst/videoparsers/gsth265parse.c
gst/videoparsers/gsth265parse.h

index c60ab4368109f8e12e428ecd146036e1212a59d3..abf6bab15e11e95e7eb78fa255658e7fedb6db41 100644 (file)
@@ -193,6 +193,8 @@ gst_h264_parse_reset_frame (GstH264Parse * h264parse)
   h264parse->idr_pos = -1;
   h264parse->sei_pos = -1;
   h264parse->keyframe = FALSE;
+  h264parse->predicted = FALSE;
+  h264parse->bidirectional = FALSE;
   h264parse->header = FALSE;
   h264parse->frame_start = FALSE;
   h264parse->aud_insert = TRUE;
@@ -260,6 +262,7 @@ gst_h264_parse_reset (GstH264Parse * h264parse)
   gst_event_replace (&h264parse->force_key_unit_event, NULL);
 
   h264parse->discont = FALSE;
+  h264parse->discard_bidirectional = FALSE;
 
   gst_h264_parse_reset_stream_info (h264parse);
 }
@@ -855,7 +858,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
       if (pres != GST_H264_PARSER_OK) {
         GST_WARNING_OBJECT (h264parse, "failed to parse SPS:");
         h264parse->state |= GST_H264_PARSE_STATE_GOT_SPS;
-        h264parse->header |= TRUE;
+        h264parse->header = TRUE;
         return FALSE;
       }
 
@@ -875,7 +878,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
       gst_h264_parser_store_nal (h264parse, sps.id, nal_type, nalu);
       gst_h264_sps_clear (&sps);
       h264parse->state |= GST_H264_PARSE_STATE_GOT_SPS;
-      h264parse->header |= TRUE;
+      h264parse->header = TRUE;
       break;
     case GST_H264_NAL_PPS:
       /* expected state: got-sps */
@@ -910,14 +913,14 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
       gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu);
       gst_h264_pps_clear (&pps);
       h264parse->state |= GST_H264_PARSE_STATE_GOT_PPS;
-      h264parse->header |= TRUE;
+      h264parse->header = TRUE;
       break;
     case GST_H264_NAL_SEI:
       /* expected state: got-sps */
       if (!GST_H264_PARSE_STATE_VALID (h264parse, GST_H264_PARSE_STATE_GOT_SPS))
         return FALSE;
 
-      h264parse->header |= TRUE;
+      h264parse->header = TRUE;
       gst_h264_parse_process_sei (h264parse, nalu);
       /* mark SEI pos */
       if (h264parse->sei_pos == -1) {
@@ -962,7 +965,12 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
             pres, slice.first_mb_in_slice, slice.type);
         if (pres == GST_H264_PARSER_OK) {
           if (GST_H264_IS_I_SLICE (&slice) || GST_H264_IS_SI_SLICE (&slice))
-            h264parse->keyframe |= TRUE;
+            h264parse->keyframe = TRUE;
+          else if (GST_H264_IS_P_SLICE (&slice)
+              || GST_H264_IS_SP_SLICE (&slice))
+            h264parse->predicted = TRUE;
+          else if (GST_H264_IS_B_SLICE (&slice))
+            h264parse->bidirectional = TRUE;
 
           h264parse->state |= GST_H264_PARSE_STATE_GOT_SLICE;
           h264parse->field_pic_flag = slice.field_pic_flag;
@@ -2335,6 +2343,9 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
   else
     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
 
+  if (h264parse->discard_bidirectional && h264parse->bidirectional)
+    goto discard;
+
   if (h264parse->header)
     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
   else
@@ -2356,7 +2367,14 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
     gst_buffer_unref (buf);
   }
 
+done:
   return GST_FLOW_OK;
+
+discard:
+  GST_DEBUG_OBJECT (h264parse, "Discarding bidirectional frame");
+  frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
+  gst_h264_parse_reset_frame (h264parse);
+  goto done;
 }
 
 /* sends a codec NAL downstream, decorating and transforming as needed.
@@ -3156,6 +3174,12 @@ gst_h264_parse_event (GstBaseParse * parse, GstEvent * event)
               || segment->applied_rate != 1.0))
         h264parse->do_ts = FALSE;
 
+      if (segment->flags & GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED) {
+        GST_DEBUG_OBJECT (h264parse, "Will discard bidirectional frames");
+        h264parse->discard_bidirectional = TRUE;
+      }
+
+
       h264parse->last_report = GST_CLOCK_TIME_NONE;
 
       res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
index 14f3ea716a415be02306c14f844a2d7990615120..812f110702e136d10328b0c80c59a3a4ba1b83f9 100644 (file)
@@ -123,6 +123,8 @@ struct _GstH264Parse
   gboolean update_caps;
   GstAdapter *frame_out;
   gboolean keyframe;
+  gboolean predicted;
+  gboolean bidirectional;
   gboolean header;
   gboolean frame_start;
   /* AU state */
@@ -147,6 +149,9 @@ struct _GstH264Parse
   guint8 closedcaptions[96];
   guint closedcaptions_size;
   GstVideoCaptionType closedcaptions_type;
+
+  /* For forward predicted trickmode */
+  gboolean discard_bidirectional;
 };
 
 struct _GstH264ParseClass
index 686f146d2d393961439f518c0003db4d8c03d6fb..501ab14fd1560e9b1a12f05bd985135ac622595a 100644 (file)
@@ -189,6 +189,8 @@ gst_h265_parse_reset_frame (GstH265Parse * h265parse)
   h265parse->idr_pos = -1;
   h265parse->sei_pos = -1;
   h265parse->keyframe = FALSE;
+  h265parse->predicted = FALSE;
+  h265parse->bidirectional = FALSE;
   h265parse->header = FALSE;
   h265parse->have_vps_in_frame = FALSE;
   h265parse->have_sps_in_frame = FALSE;
@@ -255,6 +257,7 @@ gst_h265_parse_reset (GstH265Parse * h265parse)
   gst_event_replace (&h265parse->force_key_unit_event, NULL);
 
   h265parse->discont = FALSE;
+  h265parse->discard_bidirectional = FALSE;
 
   gst_h265_parse_reset_stream_info (h265parse);
 }
@@ -593,11 +596,11 @@ gst_h265_parse_process_sei (GstH265Parse * h265parse, GstH265NalUnit * nalu)
         minfo.Wx_n = sei.payload.mastering_display_colour_volume.white_point_x;
         minfo.Wy_n = sei.payload.mastering_display_colour_volume.white_point_y;
         minfo.max_luma_n =
-            sei.payload.
-            mastering_display_colour_volume.max_display_mastering_luminance;
+            sei.payload.mastering_display_colour_volume.
+            max_display_mastering_luminance;
         minfo.min_luma_n =
-            sei.payload.
-            mastering_display_colour_volume.min_display_mastering_luminance;
+            sei.payload.mastering_display_colour_volume.
+            min_display_mastering_luminance;
 
         minfo.Gx_d = minfo.Gy_d = minfo.Bx_d = minfo.By_d =
             minfo.Rx_d = minfo.Ry_d = minfo.Wx_d = minfo.Wy_d = chroma_den;
@@ -716,7 +719,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
       }
 
       gst_h265_parser_store_nal (h265parse, vps.id, nal_type, nalu);
-      h265parse->header |= TRUE;
+      h265parse->header = TRUE;
       break;
     case GST_H265_NAL_SPS:
       /* reset state, everything else is obsolete */
@@ -732,7 +735,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
         if (pres != GST_H265_PARSER_OK) {
           GST_WARNING_OBJECT (h265parse, "failed to parse SPS:");
           h265parse->state |= GST_H265_PARSE_STATE_GOT_SPS;
-          h265parse->header |= TRUE;
+          h265parse->header = TRUE;
           return FALSE;
         }
         GST_WARNING_OBJECT (h265parse,
@@ -753,7 +756,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
       }
 
       gst_h265_parser_store_nal (h265parse, sps.id, nal_type, nalu);
-      h265parse->header |= TRUE;
+      h265parse->header = TRUE;
       h265parse->state |= GST_H265_PARSE_STATE_GOT_SPS;
       break;
     case GST_H265_NAL_PPS:
@@ -789,7 +792,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
       }
 
       gst_h265_parser_store_nal (h265parse, pps.id, nal_type, nalu);
-      h265parse->header |= TRUE;
+      h265parse->header = TRUE;
       h265parse->state |= GST_H265_PARSE_STATE_GOT_PPS;
       break;
     case GST_H265_NAL_PREFIX_SEI:
@@ -798,7 +801,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
       if (!GST_H265_PARSE_STATE_VALID (h265parse, GST_H265_PARSE_STATE_GOT_SPS))
         return FALSE;
 
-      h265parse->header |= TRUE;
+      h265parse->header = TRUE;
 
       gst_h265_parse_process_sei (h265parse, nalu);
 
@@ -844,7 +847,11 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
 
       if (pres == GST_H265_PARSER_OK) {
         if (GST_H265_IS_I_SLICE (&slice))
-          h265parse->keyframe |= TRUE;
+          h265parse->keyframe = TRUE;
+        else if (GST_H265_IS_P_SLICE (&slice))
+          h265parse->predicted = TRUE;
+        else if (GST_H265_IS_B_SLICE (&slice))
+          h265parse->bidirectional = TRUE;
 
         h265parse->state |= GST_H265_PARSE_STATE_GOT_SLICE;
       }
@@ -2118,6 +2125,10 @@ gst_h265_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
   else
     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
 
+  if (h265parse->discard_bidirectional && h265parse->bidirectional)
+    goto discard;
+
+
   if (h265parse->header)
     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
   else
@@ -2139,7 +2150,15 @@ gst_h265_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
     gst_buffer_unref (buf);
   }
 
+done:
   return GST_FLOW_OK;
+
+discard:
+  GST_DEBUG_OBJECT (h265parse, "Discarding bidirectional frame");
+  frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
+  gst_h265_parse_reset_frame (h265parse);
+  goto done;
+
 }
 
 /* sends a codec NAL downstream, decorating and transforming as needed.
@@ -2551,12 +2570,12 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
           h265parse->parsed_fps_d,
           NULL,
           flags,
-          h265parse->time_code.hours_flag[i] ? h265parse->
-          time_code.hours_value[i] : 0,
-          h265parse->time_code.minutes_flag[i] ? h265parse->
-          time_code.minutes_value[i] : 0,
-          h265parse->time_code.seconds_flag[i] ? h265parse->
-          time_code.seconds_value[i] : 0, n_frames, field_count);
+          h265parse->time_code.hours_flag[i] ? h265parse->time_code.
+          hours_value[i] : 0,
+          h265parse->time_code.minutes_flag[i] ? h265parse->time_code.
+          minutes_value[i] : 0,
+          h265parse->time_code.seconds_flag[i] ? h265parse->time_code.
+          seconds_value[i] : 0, n_frames, field_count);
     }
   }
 
@@ -2846,8 +2865,17 @@ gst_h265_parse_event (GstBaseParse * parse, GstEvent * event)
       break;
     case GST_EVENT_SEGMENT:
     {
+      const GstSegment *segment = NULL;
+
+      gst_event_parse_segment (event, &segment);
+
       h265parse->last_report = GST_CLOCK_TIME_NONE;
 
+      if (segment->flags & GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED) {
+        GST_DEBUG_OBJECT (h265parse, "Will discard bidirectional frames");
+        h265parse->discard_bidirectional = TRUE;
+      }
+
       res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
       break;
     }
index 7b777e33693c5313a5a51daa30edb1903f277f92..0af1528d70f2ec08ef4b1245633ade74fcc6beb6 100644 (file)
@@ -102,6 +102,8 @@ struct _GstH265Parse
   gboolean update_caps;
   GstAdapter *frame_out;
   gboolean keyframe;
+  gboolean predicted;
+  gboolean bidirectional;
   gboolean header;
   /* AU state */
   gboolean picture_start;
@@ -119,6 +121,9 @@ struct _GstH265Parse
 
   GstVideoContentLightLevel content_light_level;
   guint content_light_level_state;
+
+  /* For forward predicted trickmode */
+  gboolean discard_bidirectional;
 };
 
 struct _GstH265ParseClass