Пример #1
0
static gboolean
gst_rtp_h263p_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
{
  gboolean res;
  GstCaps *peercaps;
  gchar *encoding_name = NULL;

  g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);

  peercaps =
      gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
  if (peercaps) {
    GstCaps *intersect = gst_caps_intersect (peercaps,
        gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload)));

    gst_caps_unref (peercaps);
    if (!gst_caps_is_empty (intersect)) {
      GstStructure *s = gst_caps_get_structure (intersect, 0);
      encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
    }
    gst_caps_unref (intersect);
  }

  if (!encoding_name)
    encoding_name = g_strdup ("H263-1998");

  gst_rtp_base_payload_set_options (payload, "video", TRUE,
      (gchar *) encoding_name, 90000);
  res = gst_rtp_base_payload_set_outcaps (payload, NULL);
  g_free (encoding_name);

  return res;
}
Пример #2
0
static GstCaps *
gst_rtp_opus_pay_getcaps (GstRTPBasePayload * payload,
    GstPad * pad, GstCaps * filter)
{
  GstCaps *caps, *peercaps, *tcaps;
  GstStructure *s;
  const gchar *stereo;

  if (pad == GST_RTP_BASE_PAYLOAD_SRCPAD (payload))
    return
        GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_opus_pay_parent_class)->get_caps
        (payload, pad, filter);

  tcaps = gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
  peercaps = gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload),
      tcaps);
  gst_caps_unref (tcaps);
  if (!peercaps)
    return
        GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_opus_pay_parent_class)->get_caps
        (payload, pad, filter);

  if (gst_caps_is_empty (peercaps))
    return peercaps;

  caps = gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));

  s = gst_caps_get_structure (peercaps, 0);
  stereo = gst_structure_get_string (s, "stereo");
  if (stereo != NULL) {
    caps = gst_caps_make_writable (caps);

    if (!strcmp (stereo, "1")) {
      GstCaps *caps2 = gst_caps_copy (caps);

      gst_caps_set_simple (caps, "channels", G_TYPE_INT, 2, NULL);
      gst_caps_set_simple (caps2, "channels", G_TYPE_INT, 1, NULL);
      caps = gst_caps_merge (caps, caps2);
    } else if (!strcmp (stereo, "0")) {
      GstCaps *caps2 = gst_caps_copy (caps);

      gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
      gst_caps_set_simple (caps2, "channels", G_TYPE_INT, 2, NULL);
      caps = gst_caps_merge (caps, caps2);
    }
  }
  gst_caps_unref (peercaps);

  if (filter) {
    GstCaps *tmp = gst_caps_intersect_full (caps, filter,
        GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (caps);
    caps = tmp;
  }

  GST_DEBUG_OBJECT (payload, "Returning caps: %" GST_PTR_FORMAT, caps);
  return caps;
}
Пример #3
0
/**
 * gst_rtp_base_payload_set_outcaps:
 * @payload: a #GstRTPBasePayload
 * @fieldname: the first field name or %NULL
 * @...: field values
 *
 * Configure the output caps with the optional parameters.
 *
 * Variable arguments should be in the form field name, field type
 * (as a GType), value(s).  The last variable argument should be NULL.
 *
 * Returns: %TRUE if the caps could be set.
 */
gboolean
gst_rtp_base_payload_set_outcaps (GstRTPBasePayload * payload,
    const gchar * fieldname, ...)
{
  GstCaps *srccaps, *peercaps;
  gboolean res;

  /* fill in the defaults, their properties cannot be negotiated. */
  srccaps = gst_caps_new_simple ("application/x-rtp",
      "media", G_TYPE_STRING, payload->media,
      "clock-rate", G_TYPE_INT, payload->clock_rate,
      "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL);

  GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps);

  if (fieldname) {
    va_list varargs;

    /* override with custom properties */
    va_start (varargs, fieldname);
    gst_caps_set_simple_valist (srccaps, fieldname, varargs);
    va_end (varargs);

    GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps);
  }

  payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
  payload->ptime = 0;

  /* the peer caps can override some of the defaults */
  peercaps = gst_pad_peer_query_caps (payload->srcpad, srccaps);
  if (peercaps == NULL) {
    /* no peer caps, just add the other properties */
    gst_caps_set_simple (srccaps,
        "payload", G_TYPE_INT, GST_RTP_BASE_PAYLOAD_PT (payload),
        "ssrc", G_TYPE_UINT, payload->current_ssrc,
        "timestamp-offset", G_TYPE_UINT, payload->ts_base,
        "seqnum-offset", G_TYPE_UINT, payload->seqnum_base, NULL);

    GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps);
  } else {
    GstCaps *temp;
    GstStructure *s, *d;
    const GValue *value;
    gint pt;
    guint max_ptime, ptime;

    /* peer provides caps we can use to fixate. They are already intersected
     * with our srccaps, just make them writable */
    temp = gst_caps_make_writable (peercaps);
    gst_caps_unref (srccaps);

    if (gst_caps_is_empty (temp)) {
      gst_caps_unref (temp);
      return FALSE;
    }

    /* now fixate, start by taking the first caps */
    temp = gst_caps_truncate (temp);

    /* get first structure */
    s = gst_caps_get_structure (temp, 0);

    if (gst_structure_get_uint (s, "maxptime", &max_ptime))
      payload->priv->caps_max_ptime = max_ptime * GST_MSECOND;

    if (gst_structure_get_uint (s, "ptime", &ptime))
      payload->ptime = ptime * GST_MSECOND;

    if (gst_structure_get_int (s, "payload", &pt)) {
      /* use peer pt */
      GST_RTP_BASE_PAYLOAD_PT (payload) = pt;
      GST_LOG_OBJECT (payload, "using peer pt %d", pt);
    } else {
      if (gst_structure_has_field (s, "payload")) {
        /* can only fixate if there is a field */
        gst_structure_fixate_field_nearest_int (s, "payload",
            GST_RTP_BASE_PAYLOAD_PT (payload));
        gst_structure_get_int (s, "payload", &pt);
        GST_LOG_OBJECT (payload, "using peer pt %d", pt);
      } else {
        /* no pt field, use the internal pt */
        pt = GST_RTP_BASE_PAYLOAD_PT (payload);
        gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
        GST_LOG_OBJECT (payload, "using internal pt %d", pt);
      }
    }

    if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
      value = gst_structure_get_value (s, "ssrc");
      payload->current_ssrc = g_value_get_uint (value);
      GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc);
    } else {
      /* FIXME, fixate_nearest_uint would be even better */
      gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL);
      GST_LOG_OBJECT (payload, "using internal ssrc %08x",
          payload->current_ssrc);
    }

    if (gst_structure_has_field_typed (s, "timestamp-offset", G_TYPE_UINT)) {
      value = gst_structure_get_value (s, "timestamp-offset");
      payload->ts_base = g_value_get_uint (value);
      GST_LOG_OBJECT (payload, "using peer timestamp-offset %u",
          payload->ts_base);
    } else {
      /* FIXME, fixate_nearest_uint would be even better */
      gst_structure_set (s, "timestamp-offset", G_TYPE_UINT, payload->ts_base,
          NULL);
      GST_LOG_OBJECT (payload, "using internal timestamp-offset %u",
          payload->ts_base);
    }
    if (gst_structure_has_field_typed (s, "seqnum-offset", G_TYPE_UINT)) {
      value = gst_structure_get_value (s, "seqnum-offset");
      payload->seqnum_base = g_value_get_uint (value);
      GST_LOG_OBJECT (payload, "using peer seqnum-offset %u",
          payload->seqnum_base);
    } else {
      /* FIXME, fixate_nearest_uint would be even better */
      gst_structure_set (s, "seqnum-offset", G_TYPE_UINT, payload->seqnum_base,
          NULL);
      GST_LOG_OBJECT (payload, "using internal seqnum-offset %u",
          payload->seqnum_base);
    }

    /* make the target caps by copying over all the fixed caps, removing the
     * unfixed caps. */
    srccaps = gst_caps_new_empty_simple (gst_structure_get_name (s));
    d = gst_caps_get_structure (srccaps, 0);

    gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d);

    gst_caps_unref (temp);

    GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps);
  }

  update_max_ptime (payload);

  res = gst_pad_set_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), srccaps);
  gst_caps_unref (srccaps);

  return res;
}
Пример #4
0
static gboolean
gst_rtp_opus_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
{
  gboolean res;
  GstCaps *src_caps;
  GstStructure *s;
  char *encoding_name;
  gint channels, rate;
  const char *sprop_stereo = NULL;
  char *sprop_maxcapturerate = NULL;

  src_caps = gst_pad_get_allowed_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
  if (src_caps) {
    src_caps = gst_caps_make_writable (src_caps);
    src_caps = gst_caps_truncate (src_caps);
    s = gst_caps_get_structure (src_caps, 0);
    gst_structure_fixate_field_string (s, "encoding-name", "OPUS");
    encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
    gst_caps_unref (src_caps);
  } else {
    encoding_name = g_strdup ("X-GST-OPUS-DRAFT-SPITTKA-00");
  }

  s = gst_caps_get_structure (caps, 0);
  if (gst_structure_get_int (s, "channels", &channels)) {
    if (channels > 2) {
      GST_ERROR_OBJECT (payload,
          "More than 2 channels with channel-mapping-family=0 is invalid");
      return FALSE;
    } else if (channels == 2) {
      sprop_stereo = "1";
    } else {
      sprop_stereo = "0";
    }
  }

  if (gst_structure_get_int (s, "rate", &rate)) {
    sprop_maxcapturerate = g_strdup_printf ("%d", rate);
  }

  gst_rtp_base_payload_set_options (payload, "audio", FALSE,
      encoding_name, 48000);
  g_free (encoding_name);

  if (sprop_maxcapturerate && sprop_stereo) {
    res =
        gst_rtp_base_payload_set_outcaps (payload, "sprop-maxcapturerate",
        G_TYPE_STRING, sprop_maxcapturerate, "sprop-stereo", G_TYPE_STRING,
        sprop_stereo, NULL);
  } else if (sprop_maxcapturerate) {
    res =
        gst_rtp_base_payload_set_outcaps (payload, "sprop-maxcapturerate",
        G_TYPE_STRING, sprop_maxcapturerate, NULL);
  } else if (sprop_stereo) {
    res =
        gst_rtp_base_payload_set_outcaps (payload, "sprop-stereo",
        G_TYPE_STRING, sprop_stereo, NULL);
  } else {
    res = gst_rtp_base_payload_set_outcaps (payload, NULL);
  }

  g_free (sprop_maxcapturerate);

  return res;
}
static GstCaps *
gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
    GstCaps * filter)
{
  GstCaps *template_caps;
  GstCaps *allowed_caps;
  GstCaps *caps, *icaps;
  gboolean append_unrestricted;
  guint i;

  allowed_caps =
      gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);

  if (allowed_caps == NULL)
    return NULL;

  template_caps =
      gst_static_pad_template_get_caps (&gst_rtp_h264_pay_sink_template);

  if (gst_caps_is_any (allowed_caps)) {
    caps = gst_caps_ref (template_caps);
    goto done;
  }

  if (gst_caps_is_empty (allowed_caps)) {
    caps = gst_caps_ref (allowed_caps);
    goto done;
  }

  caps = gst_caps_new_empty ();

  append_unrestricted = FALSE;
  for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
    GstStructure *s = gst_caps_get_structure (allowed_caps, i);
    GstStructure *new_s = gst_structure_new_empty ("video/x-h264");
    const gchar *profile_level_id;

    profile_level_id = gst_structure_get_string (s, "profile-level-id");

    if (profile_level_id && strlen (profile_level_id) == 6) {
      const gchar *profile;
      const gchar *level;
      long int spsint;
      guint8 sps[3];

      spsint = strtol (profile_level_id, NULL, 16);
      sps[0] = spsint >> 16;
      sps[1] = spsint >> 8;
      sps[2] = spsint;

      profile = gst_codec_utils_h264_get_profile (sps, 3);
      level = gst_codec_utils_h264_get_level (sps, 3);

      if (profile && level) {
        GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s",
            profile, level);

        if (!strcmp (profile, "constrained-baseline"))
          gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
        else {
          GValue val = { 0, };
          GValue profiles = { 0, };

          g_value_init (&profiles, GST_TYPE_LIST);
          g_value_init (&val, G_TYPE_STRING);

          g_value_set_static_string (&val, profile);
          gst_value_list_append_value (&profiles, &val);

          g_value_set_static_string (&val, "constrained-baseline");
          gst_value_list_append_value (&profiles, &val);

          gst_structure_take_value (new_s, "profile", &profiles);
        }

        if (!strcmp (level, "1"))
          gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL);
        else {
          GValue levels = { 0, };
          GValue val = { 0, };
          int j;

          g_value_init (&levels, GST_TYPE_LIST);
          g_value_init (&val, G_TYPE_STRING);

          for (j = 0; j < G_N_ELEMENTS (all_levels); j++) {
            g_value_set_static_string (&val, all_levels[j]);
            gst_value_list_prepend_value (&levels, &val);
            if (!strcmp (level, all_levels[j]))
              break;
          }
          gst_structure_take_value (new_s, "level", &levels);
        }
      } else {
        /* Invalid profile-level-id means baseline */

        gst_structure_set (new_s,
            "profile", G_TYPE_STRING, "constrained-baseline", NULL);
      }
    } else {
      /* No profile-level-id means baseline or unrestricted */

      gst_structure_set (new_s,
          "profile", G_TYPE_STRING, "constrained-baseline", NULL);
      append_unrestricted = TRUE;
    }

    caps = gst_caps_merge_structure (caps, new_s);
  }
Пример #6
0
static GstCaps *
gst_rtp_h263p_pay_sink_getcaps (GstRTPBasePayload * payload, GstPad * pad,
    GstCaps * filter)
{
  GstRtpH263PPay *rtph263ppay;
  GstCaps *caps = NULL, *templ;
  GstCaps *peercaps = NULL;
  GstCaps *intersect = NULL;
  guint i;

  rtph263ppay = GST_RTP_H263P_PAY (payload);

  peercaps =
      gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), filter);

  /* if we're just outputting to udpsink or fakesink or so, we should also
   * accept any input compatible with our sink template caps */
  if (!peercaps || gst_caps_is_any (peercaps))
    return
        gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));

  /* We basically need to differentiate two use-cases here: One where there's
   * a capsfilter after the payloader with caps created from an SDP; in this
   * case the filter caps are fixed and we want to signal to an encoder what
   * we want it to produce. The second case is simply payloader ! depayloader
   * where we are dealing with the depayloader's template caps. In this case
   * we should accept any input compatible with our sink template caps. */
  if (!gst_caps_is_fixed (peercaps))
    return
        gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));

  templ = gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
  intersect = gst_caps_intersect (peercaps, templ);
  gst_caps_unref (peercaps);
  gst_caps_unref (templ);

  if (gst_caps_is_empty (intersect))
    return intersect;

  caps = gst_caps_new_empty ();
  for (i = 0; i < gst_caps_get_size (intersect); i++) {
    GstStructure *s = gst_caps_get_structure (intersect, i);
    const gchar *encoding_name = gst_structure_get_string (s, "encoding-name");

    if (!strcmp (encoding_name, "H263-2000")) {
      const gchar *profile_str = gst_structure_get_string (s, "profile");
      const gchar *level_str = gst_structure_get_string (s, "level");
      int profile = 0;
      int level = 0;

      if (profile_str && level_str) {
        gboolean i = FALSE, j = FALSE, l = FALSE, t = FALSE, f = FALSE,
            v = FALSE;
        GstStructure *new_s = gst_structure_new ("video/x-h263",
            "variant", G_TYPE_STRING, "itu",
            NULL);

        profile = atoi (profile_str);
        level = atoi (level_str);

        /* These profiles are defined in the H.263 Annex X */
        switch (profile) {
          case 0:
            /* The Baseline Profile (Profile 0) */
            break;
          case 1:
            /* H.320 Coding Efficiency Version 2 Backward-Compatibility Profile
             * (Profile 1)
             * Baseline + Annexes I, J, L.4 and T
             */
            i = j = l = t = TRUE;
            break;
          case 2:
            /* Version 1 Backward-Compatibility Profile (Profile 2)
             * Baseline + Annex F
             */
            i = j = l = t = f = TRUE;
            break;
          case 3:
            /* Version 2 Interactive and Streaming Wireless Profile
             * Baseline + Annexes I, J, T
             */
            i = j = t = TRUE;
            break;
          case 4:
            /* Version 3 Interactive and Streaming Wireless Profile (Profile 4)
             * Baseline + Annexes I, J, T, V, W.6.3.8,
             */
            /* Missing W.6.3.8 */
            i = j = t = v = TRUE;
            break;
          case 5:
            /* Conversational High Compression Profile (Profile 5)
             * Baseline + Annexes F, I, J, L.4, T, D, U
             */
            /* Missing D, U */
            f = i = j = l = t = TRUE;
            break;
          case 6:
            /* Conversational Internet Profile (Profile 6)
             * Baseline + Annexes F, I, J, L.4, T, D, U and
             * K with arbitratry slice ordering
             */
            /* Missing D, U, K with arbitratry slice ordering */
            f = i = j = l = t = TRUE;
            break;
          case 7:
            /* Conversational Interlace Profile (Profile 7)
             * Baseline + Annexes F, I, J, L.4, T, D, U,  W.6.3.11
             */
            /* Missing D, U, W.6.3.11 */
            f = i = j = l = t = TRUE;
            break;
          case 8:
            /* High Latency Profile (Profile 8)
             * Baseline + Annexes F, I, J, L.4, T, D, U, P.5, O.1.1 and
             * K with arbitratry slice ordering
             */
            /* Missing D, U, P.5, O.1.1 */
            f = i = j = l = t = TRUE;
            break;
        }


        if (f || i || j || t || l || v) {
          GValue list = { 0 };
          GValue vstr = { 0 };

          g_value_init (&list, GST_TYPE_LIST);
          g_value_init (&vstr, G_TYPE_STRING);

          g_value_set_static_string (&vstr, "h263");
          gst_value_list_append_value (&list, &vstr);
          g_value_set_static_string (&vstr, "h263p");
          gst_value_list_append_value (&list, &vstr);

          if (l || v) {
            g_value_set_static_string (&vstr, "h263pp");
            gst_value_list_append_value (&list, &vstr);
          }
          g_value_unset (&vstr);

          gst_structure_set_value (new_s, "h263version", &list);
          g_value_unset (&list);
        } else {
          gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
        }


        if (!f)
          gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
        if (!i)
          gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
        if (!j)
          gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
        if (!t)
          gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);
        if (!l)
          gst_structure_set (new_s, "annex-l", G_TYPE_BOOLEAN, FALSE, NULL);
        if (!v)
          gst_structure_set (new_s, "annex-v", G_TYPE_BOOLEAN, FALSE, NULL);


        if (level <= 10 || level == 45) {
          gst_structure_set (new_s,
              "width", GST_TYPE_INT_RANGE, 1, 176,
              "height", GST_TYPE_INT_RANGE, 1, 144,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
          caps = gst_caps_merge_structure (caps, new_s);
        } else if (level <= 20) {
          GstStructure *s_copy = gst_structure_copy (new_s);

          gst_structure_set (new_s,
              "width", GST_TYPE_INT_RANGE, 1, 352,
              "height", GST_TYPE_INT_RANGE, 1, 288,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
          caps = gst_caps_merge_structure (caps, new_s);

          gst_structure_set (s_copy,
              "width", GST_TYPE_INT_RANGE, 1, 176,
              "height", GST_TYPE_INT_RANGE, 1, 144,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
          caps = gst_caps_merge_structure (caps, s_copy);
        } else if (level <= 40) {

          gst_structure_set (new_s,
              "width", GST_TYPE_INT_RANGE, 1, 352,
              "height", GST_TYPE_INT_RANGE, 1, 288,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
          caps = gst_caps_merge_structure (caps, new_s);
        } else if (level <= 50) {
          GstStructure *s_copy = gst_structure_copy (new_s);

          gst_structure_set (new_s,
              "width", GST_TYPE_INT_RANGE, 1, 352,
              "height", GST_TYPE_INT_RANGE, 1, 288,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
          caps = gst_caps_merge_structure (caps, new_s);

          gst_structure_set (s_copy,
              "width", GST_TYPE_INT_RANGE, 1, 352,
              "height", GST_TYPE_INT_RANGE, 1, 240,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
          caps = gst_caps_merge_structure (caps, s_copy);
        } else if (level <= 60) {
          GstStructure *s_copy = gst_structure_copy (new_s);

          gst_structure_set (new_s,
              "width", GST_TYPE_INT_RANGE, 1, 720,
              "height", GST_TYPE_INT_RANGE, 1, 288,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
          caps = gst_caps_merge_structure (caps, new_s);

          gst_structure_set (s_copy,
              "width", GST_TYPE_INT_RANGE, 1, 720,
              "height", GST_TYPE_INT_RANGE, 1, 240,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
          caps = gst_caps_merge_structure (caps, s_copy);
        } else if (level <= 70) {
          GstStructure *s_copy = gst_structure_copy (new_s);

          gst_structure_set (new_s,
              "width", GST_TYPE_INT_RANGE, 1, 720,
              "height", GST_TYPE_INT_RANGE, 1, 576,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
          caps = gst_caps_merge_structure (caps, new_s);

          gst_structure_set (s_copy,
              "width", GST_TYPE_INT_RANGE, 1, 720,
              "height", GST_TYPE_INT_RANGE, 1, 480,
              "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
          caps = gst_caps_merge_structure (caps, s_copy);
        } else {
          caps = gst_caps_merge_structure (caps, new_s);
        }

      } else {
        GstStructure *new_s = gst_structure_new ("video/x-h263",
            "variant", G_TYPE_STRING, "itu",
            "h263version", G_TYPE_STRING, "h263",
            NULL);

        GST_DEBUG_OBJECT (rtph263ppay, "No profile or level specified"
            " for H263-2000, defaulting to baseline H263");

        caps = gst_caps_merge_structure (caps, new_s);
      }
    } else {
      gboolean f = FALSE, i = FALSE, j = FALSE, t = FALSE;
      /* FIXME: ffmpeg support the Appendix K too, how do we express it ?
       *   guint k;
       */
      const gchar *str;
      GstStructure *new_s = gst_structure_new ("video/x-h263",
          "variant", G_TYPE_STRING, "itu",
          NULL);
      gboolean added = FALSE;

      str = gst_structure_get_string (s, "f");
      if (str && !strcmp (str, "1"))
        f = TRUE;

      str = gst_structure_get_string (s, "i");
      if (str && !strcmp (str, "1"))
        i = TRUE;

      str = gst_structure_get_string (s, "j");
      if (str && !strcmp (str, "1"))
        j = TRUE;

      str = gst_structure_get_string (s, "t");
      if (str && !strcmp (str, "1"))
        t = TRUE;

      if (f || i || j || t) {
        GValue list = { 0 };
        GValue vstr = { 0 };

        g_value_init (&list, GST_TYPE_LIST);
        g_value_init (&vstr, G_TYPE_STRING);

        g_value_set_static_string (&vstr, "h263");
        gst_value_list_append_value (&list, &vstr);
        g_value_set_static_string (&vstr, "h263p");
        gst_value_list_append_value (&list, &vstr);
        g_value_unset (&vstr);

        gst_structure_set_value (new_s, "h263version", &list);
        g_value_unset (&list);
      } else {
        gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
      }

      if (!f)
        gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
      if (!i)
        gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
      if (!j)
        gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
      if (!t)
        gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);


      str = gst_structure_get_string (s, "custom");
      if (str) {
        unsigned int xmax, ymax, mpi;
        if (sscanf (str, "%u,%u,%u", &xmax, &ymax, &mpi) == 3) {
          if (xmax % 4 && ymax % 4 && mpi >= 1 && mpi <= 32) {
            caps = caps_append (caps, new_s, xmax, ymax, mpi);
            added = TRUE;
          } else {
            GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI"
                " %u x %u at %u, ignoring", xmax, ymax, mpi);
          }
        } else {
          GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI: %s,"
              " ignoring", str);
        }
      }

      str = gst_structure_get_string (s, "16cif");
      if (str) {
        int mpi = atoi (str);
        caps = caps_append (caps, new_s, 1408, 1152, mpi);
        added = TRUE;
      }

      str = gst_structure_get_string (s, "4cif");
      if (str) {
        int mpi = atoi (str);
        caps = caps_append (caps, new_s, 704, 576, mpi);
        added = TRUE;
      }

      str = gst_structure_get_string (s, "cif");
      if (str) {
        int mpi = atoi (str);
        caps = caps_append (caps, new_s, 352, 288, mpi);
        added = TRUE;
      }

      str = gst_structure_get_string (s, "qcif");
      if (str) {
        int mpi = atoi (str);
        caps = caps_append (caps, new_s, 176, 144, mpi);
        added = TRUE;
      }

      str = gst_structure_get_string (s, "sqcif");
      if (str) {
        int mpi = atoi (str);
        caps = caps_append (caps, new_s, 128, 96, mpi);
        added = TRUE;
      }

      if (added)
        gst_structure_free (new_s);
      else
        caps = gst_caps_merge_structure (caps, new_s);
    }
  }

  gst_caps_unref (intersect);

  return caps;
}
Пример #7
0
static GstFlowReturn
gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
{
    GstRTPBasePayload *rtppay;
    GstAsfPacketInfo *packetinfo;
    guint8 flags;
    guint8 *data;
    guint32 packet_util_size;
    guint32 packet_offset;
    guint32 size_left;
    GstFlowReturn ret = GST_FLOW_OK;

    rtppay = GST_RTP_BASE_PAYLOAD (rtpasfpay);
    packetinfo = &rtpasfpay->packetinfo;

    if (!gst_asf_parse_packet (buffer, packetinfo, TRUE,
                               rtpasfpay->asfinfo.packet_size)) {
        GST_ERROR_OBJECT (rtpasfpay, "Error while parsing asf packet");
        gst_buffer_unref (buffer);
        return GST_FLOW_ERROR;
    }

    if (packetinfo->packet_size == 0)
        packetinfo->packet_size = rtpasfpay->asfinfo.packet_size;

    GST_LOG_OBJECT (rtpasfpay, "Packet size: %" G_GUINT32_FORMAT
                    ", padding: %" G_GUINT32_FORMAT, packetinfo->packet_size,
                    packetinfo->padding);

    /* update padding field to 0 */
    if (packetinfo->padding > 0) {
        GstAsfPacketInfo info;
        /* find padding field offset */
        guint offset = packetinfo->err_cor_len + 2 +
                       gst_asf_get_var_size_field_len (packetinfo->packet_field_type) +
                       gst_asf_get_var_size_field_len (packetinfo->seq_field_type);
        buffer = gst_buffer_make_writable (buffer);
        switch (packetinfo->padd_field_type) {
        case ASF_FIELD_TYPE_DWORD:
            gst_buffer_memset (buffer, offset, 0, 4);
            break;
        case ASF_FIELD_TYPE_WORD:
            gst_buffer_memset (buffer, offset, 0, 2);
            break;
        case ASF_FIELD_TYPE_BYTE:
            gst_buffer_memset (buffer, offset, 0, 1);
            break;
        case ASF_FIELD_TYPE_NONE:
        default:
            break;
        }
        gst_asf_parse_packet (buffer, &info, FALSE, 0);
    }

    if (packetinfo->padding != 0)
        packet_util_size = rtpasfpay->asfinfo.packet_size - packetinfo->padding;
    else
        packet_util_size = packetinfo->packet_size;
    packet_offset = 0;
    while (packet_util_size > 0) {
        /* Even if we don't fill completely an output buffer we
         * push it when we add an fragment. Because it seems that
         * it is not possible to determine where a asf packet
         * fragment ends inside a rtp packet payload.
         * This flag tells us to push the packet.
         */
        gboolean force_push = FALSE;
        GstRTPBuffer rtp;

        /* we have no output buffer pending, create one */
        if (rtpasfpay->current == NULL) {
            GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer");
            rtpasfpay->current =
                gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU (rtpasfpay),
                                                 0, 0);
            rtpasfpay->cur_off = 0;
            rtpasfpay->has_ts = FALSE;
            rtpasfpay->marker = FALSE;
        }
        gst_rtp_buffer_map (rtpasfpay->current, GST_MAP_READWRITE, &rtp);
        data = gst_rtp_buffer_get_payload (&rtp);
        data += rtpasfpay->cur_off;
        size_left = gst_rtp_buffer_get_payload_len (&rtp) - rtpasfpay->cur_off;

        GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %"
                          G_GUINT32_FORMAT "/%" G_GSIZE_FORMAT, packet_offset,
                          gst_buffer_get_size (buffer));

        GST_DEBUG_OBJECT (rtpasfpay, "Output rtpbuffer status");
        GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT,
                          rtpasfpay->cur_off);
        GST_DEBUG_OBJECT (rtpasfpay, "Size left: %" G_GUINT32_FORMAT, size_left);
        GST_DEBUG_OBJECT (rtpasfpay, "Has ts: %s",
                          rtpasfpay->has_ts ? "yes" : "no");
        if (rtpasfpay->has_ts) {
            GST_DEBUG_OBJECT (rtpasfpay, "Ts: %" G_GUINT32_FORMAT, rtpasfpay->ts);
        }

        flags = 0;
        if (packetinfo->has_keyframe) {
            flags = flags | 0x80;
        }
        flags = flags | 0x20;       /* Relative timestamp is present */

        if (!rtpasfpay->has_ts) {
            /* this is the first asf packet, its send time is the
             * rtp packet timestamp */
            rtpasfpay->has_ts = TRUE;
            rtpasfpay->ts = packetinfo->send_time;
        }

        if (size_left >= packet_util_size + 8) {
            /* enough space for the rest of the packet */
            if (packet_offset == 0) {
                flags = flags | 0x40;
                GST_WRITE_UINT24_BE (data + 1, packet_util_size);
            } else {
                GST_WRITE_UINT24_BE (data + 1, packet_offset);
                force_push = TRUE;
            }
            data[0] = flags;
            GST_WRITE_UINT32_BE (data + 4,
                                 (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
            gst_buffer_extract (buffer, packet_offset, data + 8, packet_util_size);

            /* updating status variables */
            rtpasfpay->cur_off += 8 + packet_util_size;
            size_left -= packet_util_size + 8;
            packet_offset += packet_util_size;
            packet_util_size = 0;
            rtpasfpay->marker = TRUE;
        } else {
            /* fragment packet */
            data[0] = flags;
            GST_WRITE_UINT24_BE (data + 1, packet_offset);
            GST_WRITE_UINT32_BE (data + 4,
                                 (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
            gst_buffer_extract (buffer, packet_offset, data + 8, size_left - 8);

            /* updating status variables */
            rtpasfpay->cur_off += size_left;
            packet_offset += size_left - 8;
            packet_util_size -= size_left - 8;
            size_left = 0;
            force_push = TRUE;
        }

        /* there is not enough room for any more buffers */
        if (force_push || size_left <= 8) {

            gst_rtp_buffer_set_ssrc (&rtp, rtppay->current_ssrc);
            gst_rtp_buffer_set_marker (&rtp, rtpasfpay->marker);
            gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (rtppay));
            gst_rtp_buffer_set_seq (&rtp, rtppay->seqnum + 1);
            gst_rtp_buffer_set_timestamp (&rtp, packetinfo->send_time);
            gst_rtp_buffer_unmap (&rtp);

            /* trim remaining bytes not used */
            if (size_left != 0) {
                gst_buffer_set_size (rtpasfpay->current,
                                     gst_buffer_get_size (rtpasfpay->current) - size_left);
            }

            GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer);

            rtppay->seqnum++;
            rtppay->timestamp = packetinfo->send_time;

            GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer");
            ret =
                gst_pad_push (GST_RTP_BASE_PAYLOAD_SRCPAD (rtppay),
                              rtpasfpay->current);
            rtpasfpay->current = NULL;
            if (ret != GST_FLOW_OK) {
                gst_buffer_unref (buffer);
                return ret;
            }
        }
    }
    gst_buffer_unref (buffer);
    return ret;
}