コード例 #1
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static GstFlowReturn
gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
{
  GstH264Parse *h264parse;
  GstBuffer *buffer;
  guint av;

  h264parse = GST_H264_PARSE (parse);
  buffer = frame->buffer;

  gst_h264_parse_update_src_caps (h264parse);

  gst_h264_params_get_timestamp (h264parse->params,
      &GST_BUFFER_TIMESTAMP (buffer), &GST_BUFFER_DURATION (buffer),
      h264parse->frame_start);

  if (h264parse->keyframe)
    GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
  else
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);

  /* replace with transformed AVC output if applicable */
  av = gst_adapter_available (h264parse->frame_out);
  if (av) {
    GstBuffer *buf;

    buf = gst_adapter_take_buffer (h264parse->frame_out, av);
    gst_buffer_copy_metadata (buf, buffer, GST_BUFFER_COPY_ALL);
    gst_buffer_replace (&frame->buffer, buf);
  }

  return GST_FLOW_OK;
}
コード例 #2
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static void
gst_h264_parse_finalize (GObject * object)
{
  GstH264Parse *h264parse = GST_H264_PARSE (object);

  g_object_unref (h264parse->frame_out);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}
コード例 #3
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static gboolean
gst_h264_parse_stop (GstBaseParse * parse)
{
  GstH264Parse *h264parse = GST_H264_PARSE (parse);

  GST_DEBUG ("Stop");
  gst_h264_parse_reset (h264parse);

  gst_h264_params_free (h264parse->params);
  h264parse->params = NULL;

  return TRUE;
}
コード例 #4
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static gboolean
gst_h264_parse_start (GstBaseParse * parse)
{
  GstH264Parse *h264parse = GST_H264_PARSE (parse);

  GST_DEBUG ("Start");
  gst_h264_parse_reset (h264parse);

  gst_h264_params_create (&h264parse->params, GST_ELEMENT (h264parse));

  gst_base_parse_set_min_frame_size (parse, 512);

  return TRUE;
}
コード例 #5
0
static void
gst_h264_parse_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
  GstH264Parse *parse;

  parse = GST_H264_PARSE (object);

  switch (prop_id) {
    case PROP_CONFIG_INTERVAL:
      g_value_set_uint (value, parse->interval);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
コード例 #6
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static void
gst_h264_parse_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstH264Parse *parse;

  parse = GST_H264_PARSE (object);

  switch (prop_id) {
    case PROP_SPLIT_PACKETIZED:
      parse->split_packetized = g_value_get_boolean (value);
      break;
    case PROP_CONFIG_INTERVAL:
      parse->interval = g_value_get_uint (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
コード例 #7
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static gboolean
gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
{
  GstH264Parse *h264parse;
  GstStructure *str;
  const GValue *value;
  GstBuffer *buffer = NULL;
  guint size;

  h264parse = GST_H264_PARSE (parse);

  /* reset */
  h264parse->push_codec = FALSE;

  str = gst_caps_get_structure (caps, 0);

  /* accept upstream info if provided */
  gst_structure_get_int (str, "width", &h264parse->width);
  gst_structure_get_int (str, "height", &h264parse->height);
  gst_structure_get_fraction (str, "framerate", &h264parse->fps_num,
      &h264parse->fps_den);

  /* packetized video has a codec_data */
  if ((value = gst_structure_get_value (str, "codec_data"))) {
    guint8 *data;
    guint num_sps, num_pps, profile, len;
    gint i;

    GST_DEBUG_OBJECT (h264parse, "have packetized h264");
    /* make note for optional split processing */
    h264parse->packetized = TRUE;

    buffer = gst_value_get_buffer (value);
    if (!buffer)
      goto wrong_type;
    data = GST_BUFFER_DATA (buffer);
    size = GST_BUFFER_SIZE (buffer);

    /* parse the avcC data */
    if (size < 7)
      goto avcc_too_small;
    /* parse the version, this must be 1 */
    if (data[0] != 1)
      goto wrong_version;

    /* AVCProfileIndication */
    /* profile_compat */
    /* AVCLevelIndication */
    profile = (data[1] << 16) | (data[2] << 8) | data[3];
    GST_DEBUG_OBJECT (h264parse, "profile %06x", profile);

    /* 6 bits reserved | 2 bits lengthSizeMinusOne */
    /* this is the number of bytes in front of the NAL units to mark their
     * length */
    h264parse->nal_length_size = (data[4] & 0x03) + 1;
    GST_DEBUG_OBJECT (h264parse, "nal length %u", h264parse->nal_length_size);

    num_sps = data[5] & 0x1f;
    data += 6;
    size -= 6;
    for (i = 0; i < num_sps; i++) {
      len = GST_READ_UINT16_BE (data);
      if (size < len + 2 || len < 2)
        goto avcc_too_small;
      /* digest for later reference */
      gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
      data += len + 2;
      size -= len + 2;
    }
    num_pps = data[0];
    data++;
    size++;
    for (i = 0; i < num_pps; i++) {
      len = GST_READ_UINT16_BE (data);
      if (size < len + 2 || len < 2)
        goto avcc_too_small;
      /* digest for later reference */
      gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
      data += len + 2;
      size -= len + 2;
    }
  } else {
    GST_DEBUG_OBJECT (h264parse, "have bytestream h264");
    /* nothing to pre-process */
    h264parse->packetized = FALSE;
    /* we have 4 sync bytes */
    h264parse->nal_length_size = 4;
  }

  if (h264parse->packetized) {
    if (h264parse->split_packetized) {
      GST_DEBUG_OBJECT (h264parse,
          "converting AVC to nal bytestream prior to parsing");
      /* negotiate behaviour with upstream */
      gst_h264_parse_negotiate (h264parse);
      if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE) {
        /* arrange to insert codec-data in-stream if needed */
        h264parse->push_codec = h264parse->packetized;
      }
    } else {
      GST_DEBUG_OBJECT (h264parse, "passing on packetized AVC");
      /* no choice to negotiate */
      h264parse->format = GST_H264_PARSE_FORMAT_AVC;
      h264parse->align = GST_H264_PARSE_ALIGN_AU;
      /* fallback codec-data */
      h264parse->codec_data = gst_buffer_ref (buffer);
      /* pass through unharmed, though _chain will parse a bit */
      gst_base_parse_set_format (parse,
          GST_BASE_PARSE_FORMAT_PASSTHROUGH, TRUE);
      /* we did parse codec-data and might supplement src caps */
      gst_h264_parse_update_src_caps (h264parse);
    }
  }

  /* src caps are only arranged for later on */
  return TRUE;

  /* ERRORS */
avcc_too_small:
  {
    GST_DEBUG_OBJECT (h264parse, "avcC size %u < 7", size);
    goto refuse_caps;
  }
wrong_version:
  {
    GST_DEBUG_OBJECT (h264parse, "wrong avcC version");
    goto refuse_caps;
  }
wrong_type:
  {
    GST_DEBUG_OBJECT (h264parse, "wrong codec-data type");
    goto refuse_caps;
  }
refuse_caps:
  {
    GST_WARNING_OBJECT (h264parse, "refused caps %" GST_PTR_FORMAT, caps);
    return FALSE;
  }
}
コード例 #8
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static GstFlowReturn
gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
{
  GstH264Parse *h264parse;
  GstBuffer *buffer;

  h264parse = GST_H264_PARSE (parse);
  buffer = frame->buffer;

  /* periodic SPS/PPS sending */
  if (h264parse->interval > 0 || h264parse->push_codec) {
    GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
    guint64 diff;

    /* init */
    if (!GST_CLOCK_TIME_IS_VALID (h264parse->last_report)) {
      h264parse->last_report = timestamp;
    }

    if (h264parse->idr_pos >= 0) {
      GST_LOG_OBJECT (h264parse, "IDR nal at offset %d", h264parse->idr_pos);

      if (timestamp > h264parse->last_report)
        diff = timestamp - h264parse->last_report;
      else
        diff = 0;

      GST_LOG_OBJECT (h264parse,
          "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT,
          GST_TIME_ARGS (timestamp), GST_TIME_ARGS (h264parse->last_report));

      GST_DEBUG_OBJECT (h264parse,
          "interval since last SPS/PPS %" GST_TIME_FORMAT,
          GST_TIME_ARGS (diff));

      if (GST_TIME_AS_SECONDS (diff) >= h264parse->interval ||
          h264parse->push_codec) {
        GstBuffer *codec_nal;
        gint i;
        GstClockTime new_ts;

        /* avoid overwriting a perfectly fine timestamp */
        new_ts = GST_CLOCK_TIME_IS_VALID (timestamp) ? timestamp :
            h264parse->last_report;

        if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
          /* send separate config NAL buffers */
          GST_DEBUG_OBJECT (h264parse, "- sending SPS/PPS");
          for (i = 0; i < MAX_SPS_COUNT; i++) {
            if ((codec_nal = h264parse->params->sps_nals[i])) {
              GST_DEBUG_OBJECT (h264parse, "sending SPS nal");
              gst_h264_parse_push_codec_buffer (h264parse, codec_nal,
                  timestamp);
              h264parse->last_report = new_ts;
            }
          }
          for (i = 0; i < MAX_PPS_COUNT; i++) {
            if ((codec_nal = h264parse->params->pps_nals[i])) {
              GST_DEBUG_OBJECT (h264parse, "sending PPS nal");
              gst_h264_parse_push_codec_buffer (h264parse, codec_nal,
                  timestamp);
              h264parse->last_report = new_ts;
            }
          }
        } else {
          /* insert config NALs into AU */
          GstByteWriter bw;
          GstBuffer *new_buf;
          const gboolean bs = h264parse->format == GST_H264_PARSE_FORMAT_BYTE;

          gst_byte_writer_init_with_size (&bw, GST_BUFFER_SIZE (buffer), FALSE);
          gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer),
              h264parse->idr_pos);
          GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS");
          for (i = 0; i < MAX_SPS_COUNT; i++) {
            if ((codec_nal = h264parse->params->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));
              h264parse->last_report = new_ts;
            }
          }
          for (i = 0; i < MAX_PPS_COUNT; i++) {
            if ((codec_nal = h264parse->params->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));
              h264parse->last_report = new_ts;
            }
          }
          gst_byte_writer_put_data (&bw,
              GST_BUFFER_DATA (buffer) + h264parse->idr_pos,
              GST_BUFFER_SIZE (buffer) - h264parse->idr_pos);
          /* collect result and push */
          new_buf = gst_byte_writer_reset_and_get_buffer (&bw);
          gst_buffer_copy_metadata (new_buf, buffer, GST_BUFFER_COPY_ALL);
          gst_buffer_replace (&frame->buffer, new_buf);
        }
      }
      /* we pushed whatever we had */
      h264parse->push_codec = FALSE;
    }
  }

  gst_h264_parse_reset_frame (h264parse);

  return GST_FLOW_OK;
}
コード例 #9
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
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;
}
コード例 #10
0
ファイル: gsth264parse.c プロジェクト: c-a/gst-plugins-bad
static GstFlowReturn
gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
{
  GstH264Parse *h264parse = GST_H264_PARSE (GST_PAD_PARENT (pad));

  if (h264parse->packetized && buffer) {
    GstByteReader br;
    GstBuffer *sub;
    GstFlowReturn ret = GST_FLOW_OK;
    guint32 len;
    const guint nl = h264parse->nal_length_size;

    GST_LOG_OBJECT (h264parse, "processing packet buffer of size %d",
        GST_BUFFER_SIZE (buffer));
    gst_byte_reader_init_from_buffer (&br, buffer);
    while (ret == GST_FLOW_OK && gst_byte_reader_get_remaining (&br)) {
      GST_DEBUG_OBJECT (h264parse, "AVC nal offset %d",
          gst_byte_reader_get_pos (&br));
      if (gst_byte_reader_get_remaining (&br) < nl)
        goto parse_failed;
      switch (nl) {
        case 4:
          len = gst_byte_reader_get_uint32_be_unchecked (&br);
          break;
        case 3:
          len = gst_byte_reader_get_uint24_be_unchecked (&br);
          break;
        case 2:
          len = gst_byte_reader_get_uint16_be_unchecked (&br);
          break;
        case 1:
          len = gst_byte_reader_get_uint8_unchecked (&br);
          break;
        default:
          goto not_negotiated;
          break;
      }
      GST_DEBUG_OBJECT (h264parse, "AVC nal size %d", len);
      if (gst_byte_reader_get_remaining (&br) < len)
        goto parse_failed;
      if (h264parse->split_packetized) {
        /* convert to NAL aligned byte stream input */
        sub = gst_h264_parse_wrap_nal (h264parse, GST_H264_PARSE_FORMAT_BYTE,
            (guint8 *) gst_byte_reader_get_data_unchecked (&br, len), len);
        /* at least this should make sense */
        GST_BUFFER_TIMESTAMP (sub) = GST_BUFFER_TIMESTAMP (buffer);
        GST_LOG_OBJECT (h264parse, "pushing NAL of size %d", len);
        ret = h264parse->parse_chain (pad, sub);
      } else {
        /* pass-through: no looking for frames (and nal processing),
         * so need to parse to collect data here */
        /* NOTE: so if it is really configured to do so,
         * pre_push can/will still insert codec-data at intervals,
         * which is not really pure pass-through, but anyway ... */
        gst_h264_parse_process_nal (h264parse,
            GST_BUFFER_DATA (buffer), gst_byte_reader_get_pos (&br) - nl,
            gst_byte_reader_get_pos (&br), len);
        gst_byte_reader_skip_unchecked (&br, len);
      }
    }
    if (h264parse->split_packetized)
      return ret;
  }

exit:
  /* nal processing in pass-through might have collected stuff;
   * ensure nothing happens with this later on */
  gst_adapter_clear (h264parse->frame_out);

  return h264parse->parse_chain (pad, buffer);

  /* ERRORS */
not_negotiated:
  {
    GST_DEBUG_OBJECT (h264parse, "insufficient data to split input");
    return GST_FLOW_NOT_NEGOTIATED;
  }
parse_failed:
  {
    if (h264parse->split_packetized) {
      GST_ELEMENT_ERROR (h264parse, STREAM, FAILED, (NULL),
          ("invalid AVC input data"));
      return GST_FLOW_ERROR;
    } else {
      /* do not meddle to much in this case */
      GST_DEBUG_OBJECT (h264parse, "parsing packet failed");
      goto exit;
    }
  }
}
コード例 #11
0
static gboolean
gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
{
  GstH264Parse *h264parse;
  GstStructure *str;
  const GValue *value;
  GstBuffer *codec_data = NULL;
  guint size, format, align;

  h264parse = GST_H264_PARSE (parse);

  /* reset */
  h264parse->push_codec = FALSE;

  str = gst_caps_get_structure (caps, 0);

  /* accept upstream info if provided */
  gst_structure_get_int (str, "width", &h264parse->width);
  gst_structure_get_int (str, "height", &h264parse->height);
  gst_structure_get_fraction (str, "framerate", &h264parse->fps_num,
      &h264parse->fps_den);

  /* get upstream format and align from caps */
  gst_h264_parse_format_from_caps (caps, &format, &align);

  /* packetized video has a codec_data */
  if (format != GST_H264_PARSE_FORMAT_BYTE &&
      (value = gst_structure_get_value (str, "codec_data"))) {
    guint8 *data;
    guint num_sps, num_pps, profile, len;
    gint i;

    GST_DEBUG_OBJECT (h264parse, "have packetized h264");
    /* make note for optional split processing */
    h264parse->packetized = TRUE;

    codec_data = gst_value_get_buffer (value);
    if (!codec_data)
      goto wrong_type;
    data = GST_BUFFER_DATA (codec_data);
    size = GST_BUFFER_SIZE (codec_data);

    /* parse the avcC data */
    if (size < 7)
      goto avcc_too_small;
    /* parse the version, this must be 1 */
    if (data[0] != 1)
      goto wrong_version;

    /* AVCProfileIndication */
    /* profile_compat */
    /* AVCLevelIndication */
    profile = (data[1] << 16) | (data[2] << 8) | data[3];
    GST_DEBUG_OBJECT (h264parse, "profile %06x", profile);

    /* 6 bits reserved | 2 bits lengthSizeMinusOne */
    /* this is the number of bytes in front of the NAL units to mark their
     * length */
    h264parse->nal_length_size = (data[4] & 0x03) + 1;
    GST_DEBUG_OBJECT (h264parse, "nal length %u", h264parse->nal_length_size);

    num_sps = data[5] & 0x1f;
    data += 6;
    size -= 6;
    for (i = 0; i < num_sps; i++) {
      len = GST_READ_UINT16_BE (data);
      if (size < len + 2 || len < 2)
        goto avcc_too_small;
      /* digest for later reference */
      gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
      data += len + 2;
      size -= len + 2;
    }
    num_pps = data[0];
    data++;
    size++;
    for (i = 0; i < num_pps; i++) {
      len = GST_READ_UINT16_BE (data);
      if (size < len + 2 || len < 2)
        goto avcc_too_small;
      /* digest for later reference */
      gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
      data += len + 2;
      size -= len + 2;
    }

    h264parse->codec_data = gst_buffer_ref (codec_data);

    /* 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) {
      format = GST_H264_PARSE_FORMAT_AVC;
      align = GST_H264_PARSE_ALIGN_AU;
    }
  } else {
    GST_DEBUG_OBJECT (h264parse, "have bytestream h264");
    /* nothing to pre-process */
    h264parse->packetized = FALSE;
    /* we have 4 sync bytes */
    h264parse->nal_length_size = 4;

    if (format == GST_H264_PARSE_FORMAT_NONE) {
      format = GST_H264_PARSE_FORMAT_BYTE;
      align = GST_H264_PARSE_ALIGN_AU;
    }
  }

  /* negotiate with downstream, sets ->format and ->align */
  gst_h264_parse_negotiate (h264parse);

  if (format == h264parse->format && align == h264parse->align) {
    gst_base_parse_set_passthrough (parse, TRUE);

    /* we did parse codec-data and might supplement src caps */
    gst_h264_parse_update_src_caps (h264parse, caps);
  } else if (format == GST_H264_PARSE_FORMAT_AVC) {
    /* if input != output, and input is avc, must split before anything else */
    /* arrange to insert codec-data in-stream if needed.
     * src caps are only arranged for later on */
    h264parse->push_codec = TRUE;
    h264parse->split_packetized = TRUE;
    h264parse->packetized = TRUE;
  }

  return TRUE;

  /* ERRORS */
avcc_too_small:
  {
    GST_DEBUG_OBJECT (h264parse, "avcC size %u < 7", size);
    goto refuse_caps;
  }
wrong_version:
  {
    GST_DEBUG_OBJECT (h264parse, "wrong avcC version");
    goto refuse_caps;
  }
wrong_type:
  {
    GST_DEBUG_OBJECT (h264parse, "wrong codec-data type");
    goto refuse_caps;
  }
unknown_input_format:
  {
    GST_DEBUG_OBJECT (h264parse, "unknown stream-format and no codec_data");
    goto refuse_caps;
  }
refuse_caps:
  {
    GST_WARNING_OBJECT (h264parse, "refused caps %" GST_PTR_FORMAT, caps);
    return FALSE;
  }
}
コード例 #12
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;
}