Example #1
0
static gboolean
gst_h264_parse_check_valid_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
{
  GstH264Parse *h264parse = GST_H264_PARSE (parse);
  GstBuffer *buffer = frame->buffer;
  gint sc_pos, nal_pos, next_sc_pos, next_nal_pos;
  guint8 *data;
  guint size;
  gboolean drain;

  /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
  if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
    return FALSE;

  /* need to configure aggregation */
  if (G_UNLIKELY (h264parse->format == GST_H264_PARSE_FORMAT_NONE))
    gst_h264_parse_negotiate (h264parse);

  data = GST_BUFFER_DATA (buffer);
  size = GST_BUFFER_SIZE (buffer);

  GST_LOG_OBJECT (h264parse, "last_nal_pos: %d, last_scan_pos %d",
      h264parse->last_nal_pos, h264parse->next_sc_pos);

  nal_pos = h264parse->last_nal_pos;
  next_sc_pos = h264parse->next_sc_pos;

  if (!next_sc_pos) {
    sc_pos = gst_h264_parse_find_sc (buffer, 0);

    if (sc_pos == -1) {
      /* SC not found, need more data */
      sc_pos = GST_BUFFER_SIZE (buffer) - 3;
      goto more;
    }

    nal_pos = sc_pos + 3;
    next_sc_pos = nal_pos;
    /* sc might have 2 or 3 0-bytes */
    if (sc_pos > 0 && data[sc_pos - 1] == 00)
      sc_pos--;
    GST_LOG_OBJECT (h264parse, "found sc at offset %d", sc_pos);
  } else {
    /* previous checks already arrange sc at start */
    sc_pos = 0;
  }

  drain = GST_BASE_PARSE_FRAME_DRAIN (frame);
  while (TRUE) {
    gint prev_sc_pos;

    next_sc_pos = gst_h264_parse_find_sc (buffer, next_sc_pos);
    if (next_sc_pos == -1) {
      GST_LOG_OBJECT (h264parse, "no next sc");
      if (drain) {
        /* FLUSH/EOS, it's okay if we can't find the next frame */
        next_sc_pos = size;
        next_nal_pos = size;
      } else {
        next_sc_pos = size - 3;
        goto more;
      }
    } else {
      next_nal_pos = next_sc_pos + 3;
      if (data[next_sc_pos - 1] == 00)
        next_sc_pos--;
      GST_LOG_OBJECT (h264parse, "found next sc at offset %d", next_sc_pos);
      /* need at least 1 more byte of next NAL */
      if (!drain && (next_nal_pos == size - 1))
        goto more;
    }

    /* determine nal's sc position */
    prev_sc_pos = nal_pos - 3;
    g_assert (prev_sc_pos >= 0);
    if (prev_sc_pos > 0 && data[prev_sc_pos - 1] == 0)
      prev_sc_pos--;

    /* already consume and gather info from NAL */
    gst_h264_parse_process_nal (h264parse, data, prev_sc_pos, nal_pos,
        next_sc_pos - nal_pos);
    if (next_nal_pos >= size - 1 ||
        gst_h264_parse_collect_nal (h264parse, data + nal_pos,
            data + next_nal_pos))
      break;

    /* move along */
    next_sc_pos = nal_pos = next_nal_pos;
  }

  *skipsize = sc_pos;
  *framesize = next_sc_pos - sc_pos;

  return TRUE;

more:
  /* Ask for 1024 bytes more - this is an arbitrary choice */
  gst_base_parse_set_min_frame_size (parse, GST_BUFFER_SIZE (buffer) + 1024);

  /* skip up to initial startcode */
  *skipsize = sc_pos;
  /* resume scanning here next time */
  h264parse->last_nal_pos = nal_pos;
  h264parse->next_sc_pos = next_sc_pos;

  return FALSE;
}
Example #2
0
static gboolean
gst_h264_parse_check_valid_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
{
  GstH264Parse *h264parse = GST_H264_PARSE (parse);
  GstBuffer *buffer = frame->buffer;
  gint sc_pos, nal_pos, next_sc_pos, next_nal_pos;
  guint8 *data;
  guint size;
  gboolean drain;

  /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
  if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
    return FALSE;

  /* need to configure aggregation */
  if (G_UNLIKELY (h264parse->format == GST_H264_PARSE_FORMAT_NONE))
    gst_h264_parse_negotiate (h264parse);

  /* avoid stale cached parsing state */
  if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) {
    GST_LOG_OBJECT (h264parse, "parsing new frame");
    gst_h264_parse_reset_frame (h264parse);
    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_PARSING;
  } else {
    GST_LOG_OBJECT (h264parse, "resuming frame parsing");
  }

  data = GST_BUFFER_DATA (buffer);
  size = GST_BUFFER_SIZE (buffer);

  GST_LOG_OBJECT (h264parse, "last_nal_pos: %d, last_scan_pos %d",
      h264parse->last_nal_pos, h264parse->next_sc_pos);

  nal_pos = h264parse->last_nal_pos;
  next_sc_pos = h264parse->next_sc_pos;

  if (!next_sc_pos) {
    sc_pos = gst_h264_parse_find_sc (buffer, 0);

    if (sc_pos == -1) {
      /* SC not found, need more data */
      sc_pos = GST_BUFFER_SIZE (buffer) - 3;
      /* avoid going < 0 later on */
      nal_pos = next_sc_pos = sc_pos;
      goto more;
    }

    nal_pos = sc_pos + 3;
    next_sc_pos = nal_pos;
    /* sc might have 2 or 3 0-bytes */
    if (sc_pos > 0 && data[sc_pos - 1] == 00)
      sc_pos--;
    GST_LOG_OBJECT (h264parse, "found sc at offset %d", sc_pos);
  } else {
    /* previous checks already arrange sc at start */
    sc_pos = 0;
  }

  drain = GST_BASE_PARSE_DRAINING (parse);
  while (TRUE) {
    gint prev_sc_pos;

    next_sc_pos = gst_h264_parse_find_sc (buffer, next_sc_pos);
    if (next_sc_pos == -1) {
      GST_LOG_OBJECT (h264parse, "no next sc");
      if (drain) {
        /* FLUSH/EOS, it's okay if we can't find the next frame */
        next_sc_pos = size;
        next_nal_pos = size;
      } else {
        next_sc_pos = size - 3;
        goto more;
      }
    } else {
      next_nal_pos = next_sc_pos + 3;
      if (data[next_sc_pos - 1] == 00)
        next_sc_pos--;
      GST_LOG_OBJECT (h264parse, "found next sc at offset %d", next_sc_pos);
      /* need at least 1 more byte of next NAL */
      if (!drain && (next_nal_pos == size - 1))
        goto more;
    }

    /* determine nal's sc position */
    prev_sc_pos = nal_pos - 3;
    g_assert (prev_sc_pos >= 0);
    if (prev_sc_pos > 0 && data[prev_sc_pos - 1] == 0)
      prev_sc_pos--;

    /* already consume and gather info from NAL */
    if (G_UNLIKELY (next_sc_pos - nal_pos < 2)) {
      GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
          "it contains a NAL unit of length %d", next_sc_pos - nal_pos);
      /* broken nal at start -> arrange to skip it,
       * otherwise have it terminate current au
       * (and so it will be skippd on next frame round) */
      if (prev_sc_pos == sc_pos) {
        *skipsize = sc_pos + 2;
        return FALSE;
      } else {
        next_sc_pos = prev_sc_pos;
        break;
      }
    }
    gst_h264_parse_process_nal (h264parse, data, prev_sc_pos, nal_pos,
        next_sc_pos - nal_pos);
    if (next_nal_pos >= size - 1 ||
        gst_h264_parse_collect_nal (h264parse, data + nal_pos,
            data + next_nal_pos))
      break;

    /* move along */
    next_sc_pos = nal_pos = next_nal_pos;
  }

  *skipsize = sc_pos;
  *framesize = next_sc_pos - sc_pos;

  return TRUE;

more:
  /* ask for best next available */
  *framesize = G_MAXUINT;

  /* skip up to initial startcode */
  *skipsize = sc_pos;
  /* resume scanning here next time */
  h264parse->last_nal_pos = nal_pos - sc_pos;
  h264parse->next_sc_pos = next_sc_pos - sc_pos;

  return FALSE;
}