# Description: Fixes failure to decode many common video files encoded as AVC 1 Baseline - L2.1, Baseline - L1.1 & others 
# Forwarded: not-needed
# Origin: upstream
# Bug-Ubuntu: https://bugs.launchpad.net/bugs/973014
--- gst-plugins-bad0.10-0.10.23.orig/gst/videoparsers/gsth264parse.c
+++ gst-plugins-bad0.10-0.10.23/gst/videoparsers/gsth264parse.c
@@ -177,11 +177,7 @@ gst_h264_parse_reset_frame (GstH264Parse
   GST_DEBUG_OBJECT (h264parse, "reset frame");
 
   /* done parsing; reset state */
-  h264parse->nalu.valid = FALSE;
-  h264parse->nalu.offset = 0;
-  h264parse->nalu.sc_offset = 0;
-  h264parse->nalu.size = 0;
-  h264parse->current_off = 0;
+  h264parse->current_off = -1;
 
   h264parse->picture_start = FALSE;
   h264parse->update_caps = FALSE;
@@ -213,6 +209,8 @@ gst_h264_parse_reset (GstH264Parse * h26
 
   h264parse->last_report = GST_CLOCK_TIME_NONE;
   h264parse->push_codec = FALSE;
+  h264parse->have_pps = FALSE;
+  h264parse->have_sps = FALSE;
 
   h264parse->dts = GST_CLOCK_TIME_NONE;
   h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE;
@@ -468,8 +466,15 @@ gst_h264_parse_process_nal (GstH264Parse
 
       GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
       h264parse->update_caps = TRUE;
-      /* found in stream, no need to forcibly push at start */
-      h264parse->push_codec = FALSE;
+      h264parse->have_sps = TRUE;
+      if (h264parse->push_codec && h264parse->have_pps) {
+        /* SPS and PPS found in stream before the first pre_push_frame, no need
+         * to forcibly push at start */
+        GST_INFO_OBJECT (h264parse, "have SPS/PPS in stream");
+        h264parse->push_codec = FALSE;
+        h264parse->have_sps = FALSE;
+        h264parse->have_pps = FALSE;
+      }
 
       gst_h264_parser_store_nal (h264parse, sps.id, nal_type, nalu);
       break;
@@ -478,8 +483,15 @@ gst_h264_parse_process_nal (GstH264Parse
       /* parameters might have changed, force caps check */
       GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
       h264parse->update_caps = TRUE;
-      /* found in stream, no need to forcibly push at start */
-      h264parse->push_codec = FALSE;
+      h264parse->have_pps = TRUE;
+      if (h264parse->push_codec && h264parse->have_sps) {
+        /* SPS and PPS found in stream before the first pre_push_frame, no need
+         * to forcibly push at start */
+        GST_INFO_OBJECT (h264parse, "have SPS/PPS in stream");
+        h264parse->push_codec = FALSE;
+        h264parse->have_sps = FALSE;
+        h264parse->have_pps = FALSE;
+      }
 
       gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu);
       break;
@@ -640,10 +652,12 @@ gst_h264_parse_check_valid_frame (GstBas
   GstH264Parse *h264parse = GST_H264_PARSE (parse);
   GstBuffer *buffer = frame->buffer;
   guint8 *data;
-  guint size, current_off = 0;
-  gboolean drain;
+  guint size;
+  gint current_off = 0;
+  gboolean drain, nonext;
   GstH264NalParser *nalparser = h264parse->nalparser;
   GstH264NalUnit nalu;
+  GstH264ParserResult pres;
 
   /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
   if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
@@ -665,16 +679,39 @@ gst_h264_parse_check_valid_frame (GstBas
   data = GST_BUFFER_DATA (buffer);
   size = GST_BUFFER_SIZE (buffer);
 
-  drain = FALSE;
-  nalu = h264parse->nalu;
+  drain = GST_BASE_PARSE_DRAINING (parse);
+  nonext = FALSE;
+
   current_off = h264parse->current_off;
+  if (current_off < 0)
+    current_off = 0;
 
   g_assert (current_off < size);
+  GST_DEBUG_OBJECT (h264parse, "last parse position %d", current_off);
 
-  GST_DEBUG_OBJECT (h264parse, "last parse position %u", current_off);
-  while (TRUE) {
-    GstH264ParserResult pres;
+  /* check for initial skip */
+  if (h264parse->current_off == -1) {
+    pres =
+        gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
+        size, &nalu);
+    switch (pres) {
+      case GST_H264_PARSER_OK:
+        if (nalu.sc_offset > 0) {
+          *skipsize = nalu.sc_offset;
+          goto skip;
+        }
+        break;
+      case GST_H264_PARSER_NO_NAL:
+        *skipsize = size - 3;
+        goto skip;
+        break;
+      default:
+        g_assert_not_reached ();
+        break;
+    }
+  }
 
+  while (TRUE) {
     if (h264parse->packetized_chunked)
       pres =
           gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
@@ -686,99 +723,85 @@ gst_h264_parse_check_valid_frame (GstBas
 
     switch (pres) {
       case GST_H264_PARSER_OK:
-        GST_DEBUG_OBJECT (h264parse, "complete nal found. "
-            "current offset: %u, Nal offset: %u, Nal Size: %u",
-            current_off, nalu.offset, nalu.size);
-
-        GST_DEBUG_OBJECT (h264parse, "current off. %u",
-            nalu.offset + nalu.size);
-
-        if (!h264parse->nalu.size && !h264parse->nalu.valid)
-          h264parse->nalu = nalu;
-
-        /* need 2 bytes of next nal */
-        if (!h264parse->packetized_chunked &&
-            (nalu.offset + nalu.size + 4 + 2 > size)) {
-          if (GST_BASE_PARSE_DRAINING (parse)) {
-            drain = TRUE;
-          } else {
-            GST_DEBUG_OBJECT (h264parse, "need more bytes of next nal");
-            current_off = nalu.sc_offset;
-            goto more;
-          }
-        } else if (h264parse->packetized_chunked) {
-          /* normal next nal based collection not possible,
-           * _chain will have to tell us whether this was last one for AU */
-          drain = h264parse->packetized_last;
-        }
+        GST_DEBUG_OBJECT (h264parse, "complete nal (offset, size): (%u, %u) ",
+            nalu.offset, nalu.size);
         break;
+      case GST_H264_PARSER_NO_NAL_END:
+        GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u",
+            nalu.offset);
+        /* if draining, accept it as complete nal */
+        if (drain) {
+          nonext = TRUE;
+          nalu.size = size - nalu.offset;
+          GST_DEBUG_OBJECT (h264parse, "draining, accepting with size %u",
+              nalu.size);
+          /* if it's not too short at least */
+          if (nalu.size < 2)
+            goto broken;
+          break;
+        }
+        /* otherwise need more */
+        goto more;
       case GST_H264_PARSER_BROKEN_LINK:
-        return FALSE;
+        g_assert_not_reached ();
+        break;
       case GST_H264_PARSER_ERROR:
-        current_off = size - 3;
-        goto parsing_error;
+        /* should not really occur either */
+        GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit");
+        /* fall-through */
       case GST_H264_PARSER_NO_NAL:
-        /* don't expect to have found any NAL so far */
-        g_assert (h264parse->nalu.size == 0);
-        current_off = h264parse->nalu.sc_offset = size - 3;
-        goto more;
+        g_assert_not_reached ();
+        break;
       case GST_H264_PARSER_BROKEN_DATA:
         GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
-            "it contains a NAL unit of length %d", nalu.size);
-
+            "it contains a NAL unit of length %u", nalu.size);
+      broken:
         /* broken nal at start -> arrange to skip it,
          * otherwise have it terminate current au
          * (and so it will be skipped on next frame round) */
-        if (nalu.sc_offset == h264parse->nalu.sc_offset) {
-          *skipsize = nalu.offset;
-
+        if (current_off == 0) {
           GST_DEBUG_OBJECT (h264parse, "skipping broken nal");
-          goto invalid;
+          *skipsize = nalu.offset;
+          goto skip;
         } else {
+          GST_DEBUG_OBJECT (h264parse, "terminating au");
           nalu.size = 0;
+          nalu.offset = nalu.sc_offset;
           goto end;
         }
-      case GST_H264_PARSER_NO_NAL_END:
-        GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u",
-            nalu.offset);
-
-        current_off = nalu.sc_offset;
-        /* We keep the reference to this nal so we start over the parsing
-         * here */
-        if (!h264parse->nalu.size && !h264parse->nalu.valid)
-          h264parse->nalu = nalu;
-
-        if (GST_BASE_PARSE_DRAINING (parse)) {
-          drain = TRUE;
-          GST_DEBUG_OBJECT (h264parse, "draining NAL %u %u %u", size,
-              h264parse->nalu.offset, h264parse->nalu.size);
-          /*  Can't parse the nalu */
-          if (size - h264parse->nalu.offset < 2) {
-            *skipsize = nalu.offset;
-            goto invalid;
-          }
-
-          /* We parse it anyway */
-          nalu.size = size - nalu.offset;
-          break;
-        }
-        goto more;
+        break;
+      default:
+        g_assert_not_reached ();
+        break;
     }
 
-    current_off = nalu.offset + nalu.size;
-
     GST_DEBUG_OBJECT (h264parse, "%p complete nal found. Off: %u, Size: %u",
         data, nalu.offset, nalu.size);
 
+    /* simulate no next nal if none needed */
+    nonext = nonext || (h264parse->align == GST_H264_PARSE_ALIGN_NAL);
+
+    if (!nonext && !h264parse->packetized_chunked) {
+      if (nalu.offset + nalu.size + 4 + 2 > size) {
+        GST_DEBUG_OBJECT (h264parse, "not enough data for next NALU");
+        if (drain) {
+          GST_DEBUG_OBJECT (h264parse, "but draining anyway");
+          nonext = TRUE;
+        } else {
+          goto more;
+        }
+      }
+    }
+
     gst_h264_parse_process_nal (h264parse, &nalu);
 
-    /* simulate no next nal if none needed */
-    drain = drain || (h264parse->align == GST_H264_PARSE_ALIGN_NAL);
+    if (nonext)
+      break;
 
     /* In packetized mode we know there's only on NALU in each input packet,
      * but we may not have seen the whole AU already, possibly need more */
     if (h264parse->packetized_chunked) {
-      if (drain)
+      if (h264parse->packetized_last)
         break;
       /* next NALU expected at end of current data */
       current_off = size;
@@ -786,42 +809,30 @@ gst_h264_parse_check_valid_frame (GstBas
     }
 
     /* if no next nal, we know it's complete here */
-    if (drain || gst_h264_parse_collect_nal (h264parse, data, size, &nalu))
+    if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu))
       break;
 
     GST_DEBUG_OBJECT (h264parse, "Looking for more");
+    current_off = nalu.offset + nalu.size;
   }
 
 end:
-  *skipsize = h264parse->nalu.sc_offset;
-  *framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset;
-  h264parse->current_off = current_off;
-
+  *framesize = nalu.offset + nalu.size;
   return TRUE;
 
-parsing_error:
-  GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit");
-
 more:
   /* ask for best next available */
   *framesize = G_MAXUINT;
-  if (!h264parse->nalu.size) {
-    /* skip up to initial startcode */
-    *skipsize = h264parse->nalu.sc_offset;
-    /* but mind some stuff will have been skipped */
-    g_assert (current_off >= *skipsize);
-    current_off -= *skipsize;
-    h264parse->nalu.sc_offset = 0;
-  } else {
-    *skipsize = 0;
-  }
+  *skipsize = 0;
 
   /* Restart parsing from here next time */
-  h264parse->current_off = current_off;
+  if (current_off > 0)
+    h264parse->current_off = current_off;
 
   return FALSE;
 
-invalid:
+skip:
+  GST_DEBUG_OBJECT (h264parse, "skipping %d", *skipsize);
   gst_h264_parse_reset_frame (h264parse);
   return FALSE;
 }
@@ -835,6 +846,7 @@ gst_h264_parse_make_codec_data (GstH264P
   guint8 profile_idc = 0, profile_comp = 0, level_idc = 0;
   gboolean found = FALSE;
   guint8 *data;
+  gint nl;
 
   /* only nal payload in stored nals */
 
@@ -867,12 +879,13 @@ gst_h264_parse_make_codec_data (GstH264P
 
   buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size);
   data = GST_BUFFER_DATA (buf);
+  nl = h264parse->nal_length_size;
 
   data[0] = 1;                  /* AVC Decoder Configuration Record ver. 1 */
   data[1] = profile_idc;        /* profile_idc                             */
   data[2] = profile_comp;       /* profile_compability                     */
   data[3] = level_idc;          /* level_idc                               */
-  data[4] = 0xfc | (4 - 1);     /* nal_length_size_minus1                  */
+  data[4] = 0xfc | (nl - 1);    /* nal_length_size_minus1                  */
   data[5] = 0xe0 | num_sps;     /* number of SPSs */
 
   data += 6;
@@ -1341,12 +1354,10 @@ check_pending_key_unit_event (GstEvent *
       running_time < pending_key_unit_ts)
     goto out;
 
-#if 0
   if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
     GST_DEBUG ("pending force key unit, waiting for keyframe");
     goto out;
   }
-#endif
 
   stream_time = gst_segment_to_stream_time (segment,
       GST_FORMAT_TIME, timestamp);
@@ -1479,32 +1490,38 @@ gst_h264_parse_pre_push_frame (GstBasePa
           GstByteWriter bw;
           GstBuffer *new_buf;
           const gboolean bs = h264parse->format == GST_H264_PARSE_FORMAT_BYTE;
+          const gint nls = 4 - h264parse->nal_length_size;
+          gboolean ok;
 
           gst_byte_writer_init_with_size (&bw, GST_BUFFER_SIZE (buffer), FALSE);
-          gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer),
+          ok = gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer),
               h264parse->idr_pos);
           GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS");
           for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
             if ((codec_nal = h264parse->sps_nals[i])) {
               GST_DEBUG_OBJECT (h264parse, "inserting SPS nal");
-              gst_byte_writer_put_uint32_be (&bw,
-                  bs ? 1 : GST_BUFFER_SIZE (codec_nal));
-              gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal),
-                  GST_BUFFER_SIZE (codec_nal));
+              ok &= gst_byte_writer_put_uint32_be (&bw,
+                  bs ? 1 : (GST_BUFFER_SIZE (codec_nal) << (nls * 8)));
+              ok &= gst_byte_writer_set_pos (&bw,
+                  gst_byte_writer_get_pos (&bw) - nls);
+              ok &= gst_byte_writer_put_data (&bw,
+                  GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal));
               h264parse->last_report = new_ts;
             }
           }
           for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
             if ((codec_nal = h264parse->pps_nals[i])) {
               GST_DEBUG_OBJECT (h264parse, "inserting PPS nal");
-              gst_byte_writer_put_uint32_be (&bw,
-                  bs ? 1 : GST_BUFFER_SIZE (codec_nal));
-              gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal),
-                  GST_BUFFER_SIZE (codec_nal));
+              ok &= gst_byte_writer_put_uint32_be (&bw,
+                  bs ? 1 : (GST_BUFFER_SIZE (codec_nal) << (nls * 8)));
+              ok &= gst_byte_writer_set_pos (&bw,
+                  gst_byte_writer_get_pos (&bw) - nls);
+              ok &= gst_byte_writer_put_data (&bw,
+                  GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal));
               h264parse->last_report = new_ts;
             }
           }
-          gst_byte_writer_put_data (&bw,
+          ok &= gst_byte_writer_put_data (&bw,
               GST_BUFFER_DATA (buffer) + h264parse->idr_pos,
               GST_BUFFER_SIZE (buffer) - h264parse->idr_pos);
           /* collect result and push */
@@ -1515,10 +1532,16 @@ gst_h264_parse_pre_push_frame (GstBasePa
           GST_BUFFER_FLAG_UNSET (new_buf, GST_BUFFER_FLAG_DELTA_UNIT);
           gst_buffer_replace (&frame->buffer, new_buf);
           gst_buffer_unref (new_buf);
+          /* some result checking seems to make some compilers happy */
+          if (G_UNLIKELY (!ok)) {
+            GST_ERROR_OBJECT (h264parse, "failed to insert SPS/PPS");
+          }
         }
       }
       /* we pushed whatever we had */
       h264parse->push_codec = FALSE;
+      h264parse->have_sps = FALSE;
+      h264parse->have_pps = FALSE;
     }
   }
 
@@ -1623,10 +1646,10 @@ gst_h264_parse_set_caps (GstBaseParse *
 
     /* if upstream sets codec_data without setting stream-format and alignment, we
      * assume stream-format=avc,alignment=au */
-    if (format == GST_H264_PARSE_FORMAT_NONE) {
+    if (format == GST_H264_PARSE_FORMAT_NONE)
       format = GST_H264_PARSE_FORMAT_AVC;
+    if (align == GST_H264_PARSE_ALIGN_NONE)
       align = GST_H264_PARSE_ALIGN_AU;
-    }
   } else {
     GST_DEBUG_OBJECT (h264parse, "have bytestream h264");
     /* nothing to pre-process */
@@ -1665,6 +1688,8 @@ gst_h264_parse_set_caps (GstBaseParse *
     /* arrange to insert codec-data in-stream if needed.
      * src caps are only arranged for later on */
     h264parse->push_codec = TRUE;
+    h264parse->have_sps = FALSE;
+    h264parse->have_pps = FALSE;
     h264parse->split_packetized = TRUE;
     h264parse->packetized = TRUE;
   }
--- gst-plugins-bad0.10-0.10.23.orig/gst/videoparsers/gsth264parse.h
+++ gst-plugins-bad0.10-0.10.23/gst/videoparsers/gsth264parse.h
@@ -67,15 +67,16 @@ struct _GstH264Parse
 
   /* state */
   GstH264NalParser *nalparser;
-  GstH264NalUnit nalu;
   guint align;
   guint format;
-  guint current_off;
+  gint current_off;
   gboolean packetized_last;
   gboolean packetized_chunked;
 
   GstClockTime last_report;
   gboolean push_codec;
+  gboolean have_sps;
+  gboolean have_pps;
 
   /* collected SPS and PPS NALUs */
   GstBuffer *sps_nals[GST_H264_MAX_SPS_COUNT];
