Exemple #1
0
static void
gst_compare_buffers (GstCompare * comp, GstBuffer * buf1, GstCaps * caps1,
    GstBuffer * buf2, GstCaps * caps2)
{
  gdouble delta = 0;
  gsize size1, size2;

  /* first check metadata */
  gst_compare_meta (comp, buf1, caps1, buf2, caps2);

  size1 = gst_buffer_get_size (buf1);
  size2 = gst_buffer_get_size (buf1);

  /* check content according to method */
  /* but at least size should match */
  if (size1 != size2) {
    delta = comp->threshold + 1;
  } else {
    GstMapInfo map1, map2;

    gst_buffer_map (buf1, &map1, GST_MAP_READ);
    gst_buffer_map (buf2, &map2, GST_MAP_READ);
    GST_MEMDUMP_OBJECT (comp, "buffer 1", map1.data, map2.size);
    GST_MEMDUMP_OBJECT (comp, "buffer 2", map2.data, map2.size);
    gst_buffer_unmap (buf1, &map1);
    gst_buffer_unmap (buf2, &map2);
    switch (comp->method) {
      case GST_COMPARE_METHOD_MEM:
        delta = gst_compare_mem (comp, buf1, caps1, buf2, caps2);
        break;
      case GST_COMPARE_METHOD_MAX:
        delta = gst_compare_max (comp, buf1, caps1, buf2, caps2);
        break;
      case GST_COMPARE_METHOD_SSIM:
        delta = gst_compare_ssim (comp, buf1, caps1, buf2, caps2);
        break;
      default:
        g_assert_not_reached ();
        break;
    }
  }

  if ((comp->upper && delta > comp->threshold) ||
      (!comp->upper && delta < comp->threshold)) {
    GST_WARNING_OBJECT (comp, "buffers %p and %p failed content match %f",
        buf1, buf2, delta);

    gst_element_post_message (GST_ELEMENT (comp),
        gst_message_new_element (GST_OBJECT (comp),
            gst_structure_new ("delta", "content", G_TYPE_DOUBLE, delta,
                NULL)));
  }
}
static int
gst_curl_base_sink_debug_cb (CURL * handle, curl_infotype type, char *data,
    size_t size, void *clientp)
{
  GstCurlBaseSink *sink = (GstCurlBaseSink *) clientp;
  gchar *msg = NULL;

  switch (type) {
    case CURLINFO_TEXT:
    case CURLINFO_HEADER_IN:
    case CURLINFO_HEADER_OUT:
      msg = g_memdup (data, size);
      if (size > 0) {
        msg[size - 1] = '\0';
        g_strchomp (msg);
      }
      break;
    default:
      break;
  }

  switch (type) {
    case CURLINFO_TEXT:
      GST_DEBUG_OBJECT (sink, "%s", msg);
      break;
    case CURLINFO_HEADER_IN:
      GST_DEBUG_OBJECT (sink, "incoming header: %s", msg);
      break;
    case CURLINFO_HEADER_OUT:
      GST_DEBUG_OBJECT (sink, "outgoing header: %s", msg);
      break;
    case CURLINFO_DATA_IN:
      GST_MEMDUMP_OBJECT (sink, "incoming data", (guint8 *) data, size);
      break;
    case CURLINFO_DATA_OUT:
      GST_MEMDUMP_OBJECT (sink, "outgoing data", (guint8 *) data, size);
      break;
    case CURLINFO_SSL_DATA_IN:
      GST_MEMDUMP_OBJECT (sink, "incoming ssl data", (guint8 *) data, size);
      break;
    case CURLINFO_SSL_DATA_OUT:
      GST_MEMDUMP_OBJECT (sink, "outgoing ssl data", (guint8 *) data, size);
      break;
    default:
      GST_DEBUG_OBJECT (sink, "unknown debug info type %d", type);
      GST_MEMDUMP_OBJECT (sink, "unknown data", (guint8 *) data, size);
      break;
  }
  g_free (msg);
  return 0;
}
static void
gst_compare_buffers (GstCompare * comp, GstBuffer * buf1, GstBuffer * buf2)
{
  gdouble delta = 0;

  /* first check metadata */
  gst_compare_meta (comp, buf1, buf2);

  /* check content according to method */
  /* but at least size should match */
  if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2)) {
    delta = comp->threshold + 1;
  } else {
    GST_MEMDUMP_OBJECT (comp, "buffer 1", GST_BUFFER_DATA (buf1),
        GST_BUFFER_SIZE (buf1));
    GST_MEMDUMP_OBJECT (comp, "buffer 2", GST_BUFFER_DATA (buf2),
        GST_BUFFER_SIZE (buf2));
    switch (comp->method) {
      case GST_COMPARE_METHOD_MEM:
        delta = gst_compare_mem (comp, buf1, buf2);
        break;
      case GST_COMPARE_METHOD_MAX:
        delta = gst_compare_max (comp, buf1, buf2);
        break;
      case GST_COMPARE_METHOD_SSIM:
        delta = gst_compare_ssim (comp, buf1, buf2);
        break;
      default:
        g_assert_not_reached ();
        break;
    }
  }

  if ((comp->upper && delta > comp->threshold) ||
      (!comp->upper && delta < comp->threshold)) {
    GST_WARNING_OBJECT (comp, "buffers %p and %p failed content match %f",
        buf1, buf2, delta);

    gst_element_post_message (GST_ELEMENT (comp),
        gst_message_new_element (GST_OBJECT (comp),
            gst_structure_new ("delta", "content", G_TYPE_DOUBLE, delta,
                NULL)));
  }
}
static gboolean
gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, gint skip,
    guint * framesize, guint * rate, guint * chans, guint * blocks,
    guint * sid, gboolean * eac)
{
  GstBitReader bits;
  guint16 sync;
  guint8 bsid;
  GstMapInfo map;
  gboolean ret = FALSE;

  gst_buffer_map (buf, &map, GST_MAP_READ);
  gst_bit_reader_init (&bits, map.data, map.size);

  GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", map.data, MIN (map.size, 16));

  gst_bit_reader_skip_unchecked (&bits, skip * 8);

  sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
  gst_bit_reader_skip_unchecked (&bits, 16 + 8);
  bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5);

  if (G_UNLIKELY (sync != 0x0b77))
    goto cleanup;

  GST_LOG_OBJECT (parse, "bsid = %d", bsid);

  if (bsid <= 10) {
    if (eac)
      *eac = FALSE;
    ret = gst_ac3_parse_frame_header_ac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
    goto cleanup;
  } else if (bsid <= 16) {
    if (eac)
      *eac = TRUE;
    ret = gst_ac3_parse_frame_header_eac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
    goto cleanup;
  } else {
    GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
    ret = FALSE;
    goto cleanup;
  }

  GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);

cleanup:
  gst_buffer_unmap (buf, &map);

  return ret;
}
static gboolean
gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, gint skip,
    guint * framesize, guint * rate, guint * chans, guint * blocks,
    guint * sid, gboolean * eac)
{
  GstBitReader bits = GST_BIT_READER_INIT_FROM_BUFFER (buf);
  guint16 sync;
  guint8 bsid;

  GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", GST_BUFFER_DATA (buf), 16);

  gst_bit_reader_skip_unchecked (&bits, skip * 8);

  sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
  gst_bit_reader_skip_unchecked (&bits, 16 + 8);
  bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5);

  if (G_UNLIKELY (sync != 0x0b77))
    return FALSE;

  GST_LOG_OBJECT (parse, "bsid = %d", bsid);

  if (bsid <= 10) {
    if (eac)
      *eac = FALSE;
    return gst_ac3_parse_frame_header_ac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
  } else if (bsid <= 16) {
    if (eac)
      *eac = TRUE;
    return gst_ac3_parse_frame_header_eac3 (parse, buf, skip, framesize, rate,
        chans, blocks, sid);
  } else {
    GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
    return FALSE;
  }
}
static void
handle_buffer (GstFluidDec * fluiddec, GstBuffer * buffer)
{
  GstMapInfo info;
  guint8 event;

  gst_buffer_map (buffer, &info, GST_MAP_READ);

  event = info.data[0];

  switch (event & 0xf0) {
    case 0xf0:
      switch (event) {
        case 0xff:
          GST_DEBUG_OBJECT (fluiddec, "system reset");
          fluid_synth_system_reset (fluiddec->synth);
          break;
        case 0xf0:
        case 0xf7:
          GST_DEBUG_OBJECT (fluiddec, "sysex 0x%02x", event);
          GST_MEMDUMP_OBJECT (fluiddec, "bytes ", info.data + 1, info.size - 1);
          fluid_synth_sysex (fluiddec->synth, (char *) info.data + 1,
              info.size - 1, NULL, NULL, NULL, 0);

          break;
        case 0xf9:
          GST_LOG_OBJECT (fluiddec, "midi tick");
          break;
        default:
          GST_WARNING_OBJECT (fluiddec, "unhandled event 0x%02x", event);
          break;
      }
      break;
    default:
    {
      guint8 channel, p1, p2;

      channel = event & 0x0f;

      p1 = info.size > 1 ? info.data[1] & 0x7f : 0;
      p2 = info.size > 2 ? info.data[2] & 0x7f : 0;

      GST_DEBUG_OBJECT (fluiddec, "event 0x%02x channel %d, 0x%02x 0x%02x",
          event, channel, p1, p2);

      switch (event & 0xf0) {
        case 0x80:
          fluid_synth_noteoff (fluiddec->synth, channel, p1);
          break;
        case 0x90:
          fluid_synth_noteon (fluiddec->synth, channel, p1, p2);
          break;
        case 0xA0:
          /* aftertouch */
          break;
        case 0xB0:
          fluid_synth_cc (fluiddec->synth, channel, p1, p2);
          break;
        case 0xC0:
          fluid_synth_program_change (fluiddec->synth, channel, p1);
          break;
        case 0xD0:
          fluid_synth_channel_pressure (fluiddec->synth, channel, p1);
          break;
        case 0xE0:
          fluid_synth_pitch_bend (fluiddec->synth, channel, (p2 << 7) | p1);
          break;
        default:
          break;
      }
      break;
    }
  }
  gst_buffer_unmap (buffer, &info);
}
static GstBuffer *
gst_rtp_vp9_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
{
  GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (depay);
  GstBuffer *payload;
  guint8 *data;
  guint hdrsize = 1;
  guint size;
  gint spatial_layer = 0;
  gboolean i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit;

  if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) {
    GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
    gst_adapter_clear (self->adapter);
    self->started = FALSE;
  }

  size = gst_rtp_buffer_get_payload_len (rtp);

  /* Mandatory with at least one header and one vp9 byte */
  if (G_UNLIKELY (size < hdrsize + 1))
    goto too_small;

  data = gst_rtp_buffer_get_payload (rtp);
  i_bit = (data[0] & 0x80) != 0;
  p_bit = (data[0] & 0x40) != 0;
  l_bit = (data[0] & 0x20) != 0;
  f_bit = (data[0] & 0x10) != 0;
  b_bit = (data[0] & 0x08) != 0;
  e_bit = (data[0] & 0x04) != 0;
  v_bit = (data[0] & 0x02) != 0;

  if (G_UNLIKELY (!self->started)) {
    /* Check if this is the start of a VP9 layer frame, otherwise bail */
    if (!b_bit)
      goto done;

    self->started = TRUE;
  }

  GST_TRACE_OBJECT (self, "IPLFBEV : %d%d%d%d%d%d%d", i_bit, p_bit, l_bit,
      f_bit, b_bit, e_bit, v_bit);

  /* Check I optional header Picture ID */
  if (i_bit) {
    hdrsize++;
    if (G_UNLIKELY (size < hdrsize + 1))
      goto too_small;
    /* Check M for 15 bits PictureID */
    if ((data[1] & 0x80) != 0) {
      hdrsize++;
      if (G_UNLIKELY (size < hdrsize + 1))
        goto too_small;
    }
  }

  /* flexible-mode not implemented */
  g_assert (!f_bit);

  /* Check L optional header layer indices */
  if (l_bit) {
    hdrsize++;
    /* Check TL0PICIDX temporal layer zero index (non-flexible mode) */
    if (!f_bit)
      hdrsize++;
  }

  /* Check V optional Scalability Structure */
  if (v_bit) {
    guint n_s, y_bit, g_bit;
    guint8 *ss = &data[hdrsize];
    guint sssize = 1;

    if (G_UNLIKELY (size < hdrsize + sssize + 1))
      goto too_small;

    n_s = (ss[0] & 0xe0) >> 5;
    y_bit = (ss[0] & 0x10) != 0;
    g_bit = (ss[0] & 0x08) != 0;

    GST_TRACE_OBJECT (self, "SS header: N_S=%u, Y=%u, G=%u", n_s, y_bit, g_bit);

    sssize += y_bit ? (n_s + 1) * 4 : 0;
    if (G_UNLIKELY (size < hdrsize + sssize + 1))
      goto too_small;

    if (y_bit) {
      guint i;
      for (i = 0; i <= n_s; i++) {
        /* For now, simply use the last layer specified for width and height */
        self->ss_width = ss[1 + i * 4] * 256 + ss[2 + i * 4];
        self->ss_height = ss[3 + i * 4] * 256 + ss[4 + i * 4];
        GST_TRACE_OBJECT (self, "N_S[%d]: WIDTH=%u, HEIGHT=%u", i,
            self->ss_width, self->ss_height);
      }
    }

    if (g_bit) {
      guint i, j;
      guint n_g = ss[sssize];
      sssize++;
      if (G_UNLIKELY (size < hdrsize + sssize + 1))
        goto too_small;
      for (i = 0; i < n_g; i++) {
        guint t = (ss[sssize] & 0xe0) >> 5;
        guint u = (ss[sssize] & 0x10) >> 4;
        guint r = (ss[sssize] & 0x0c) >> 2;
        GST_TRACE_OBJECT (self, "N_G[%u]: 0x%02x -> T=%u, U=%u, R=%u", i,
            ss[sssize], t, u, r);
        for (j = 0; j < r; j++)
          GST_TRACE_OBJECT (self, "  R[%u]: P_DIFF=%u", j, ss[sssize + 1 + j]);
        sssize += 1 + r;
        if (G_UNLIKELY (size < hdrsize + sssize + 1))
          goto too_small;
      }
    }
    hdrsize += sssize;
  }

  GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size);

  if (G_UNLIKELY (hdrsize >= size))
    goto too_small;

  payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1);
  {
    GstMapInfo map;
    gst_buffer_map (payload, &map, GST_MAP_READ);
    GST_MEMDUMP_OBJECT (self, "vp9 payload", map.data, 16);
    gst_buffer_unmap (payload, &map);
  }
  gst_adapter_push (self->adapter, payload);

  /* Marker indicates that it was the last rtp packet for this frame */
  if (gst_rtp_buffer_get_marker (rtp)) {
    GstBuffer *out;
    gboolean key_frame_first_layer = !p_bit && spatial_layer == 0;


    if (gst_adapter_available (self->adapter) < 10)
      goto too_small;

    out = gst_adapter_take_buffer (self->adapter,
        gst_adapter_available (self->adapter));

    self->started = FALSE;

    /* mark keyframes */
    out = gst_buffer_make_writable (out);
    /* Filter away all metas that are not sensible to copy */
    gst_rtp_drop_meta (GST_ELEMENT_CAST (self), out,
        g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
    if (!key_frame_first_layer) {
      GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);

      if (!self->caps_sent) {
        gst_buffer_unref (out);
        out = NULL;
        GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame");
        gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay),
            gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
                TRUE, 0));
      }
    } else {
      GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT);

      if (self->last_width != self->ss_width ||
          self->last_height != self->ss_height) {
        GstCaps *srccaps;

        /* Width and height are optional in the RTP header. Consider to parse
         * the frame header in addition if missing from RTP header */
        if (self->ss_width != 0 && self->ss_height != 0) {
          srccaps = gst_caps_new_simple ("video/x-vp9",
              "framerate", GST_TYPE_FRACTION, 0, 1,
              "width", G_TYPE_INT, self->ss_width,
              "height", G_TYPE_INT, self->ss_height, NULL);
        } else {
          srccaps = gst_caps_new_simple ("video/x-vp9",
              "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
        }

        gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps);
        gst_caps_unref (srccaps);

        self->caps_sent = TRUE;
        self->last_width = self->ss_width;
        self->last_height = self->ss_height;
        self->ss_width = 0;
        self->ss_height = 0;
      }
    }

    return out;
  }

done:
  return NULL;

too_small:
  GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring");
  gst_adapter_clear (self->adapter);
  self->started = FALSE;

  goto done;
}
static GstFlowReturn webkitMediaPlayReadyDecryptTransformInPlace(GstBaseTransform* base, GstBuffer* buffer)
{
    WebKitMediaPlayReadyDecrypt* self = WEBKIT_MEDIA_PLAYREADY_DECRYPT(base);
    GstFlowReturn result = GST_FLOW_OK;
    GstMapInfo map;
    const GValue* value;
    guint sampleIndex = 0;
    int errorCode;
    uint32_t trackID = 0;
    GstPad* pad;
    GstCaps* caps;
    GstMapInfo boxMap;
    GstBuffer* box = nullptr;
    GstProtectionMeta* protectionMeta = 0;
    gboolean boxMapped = FALSE;
    gboolean bufferMapped = FALSE;

    GST_TRACE_OBJECT(self, "Processing buffer");
    g_mutex_lock(&self->mutex);
    GST_TRACE_OBJECT(self, "Mutex acquired, stream received: %s", self->streamReceived ? "yes":"no");

    // The key might not have been received yet. Wait for it.
    if (!self->streamReceived)
        g_cond_wait(&self->condition, &self->mutex);

    if (!self->streamReceived) {
        GST_DEBUG_OBJECT(self, "Condition signaled from state change transition. Aborting.");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    GST_TRACE_OBJECT(self, "Proceeding with decryption");
    protectionMeta = reinterpret_cast<GstProtectionMeta*>(gst_buffer_get_protection_meta(buffer));
    if (!protectionMeta || !buffer) {
        if (!protectionMeta)
            GST_ERROR_OBJECT(self, "Failed to get GstProtection metadata from buffer %p", buffer);

        if (!buffer)
            GST_ERROR_OBJECT(self, "Failed to get writable buffer");

        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    bufferMapped = gst_buffer_map(buffer, &map, static_cast<GstMapFlags>(GST_MAP_READWRITE));
    if (!bufferMapped) {
        GST_ERROR_OBJECT(self, "Failed to map buffer");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    pad = gst_element_get_static_pad(GST_ELEMENT(self), "src");
    caps = gst_pad_get_current_caps(pad);
    if (g_str_has_prefix(gst_structure_get_name(gst_caps_get_structure(caps, 0)), "video/"))
        trackID = 1;
    else
        trackID = 2;
    gst_caps_unref(caps);
    gst_object_unref(pad);

    GST_TRACE_OBJECT(self, "Protection meta: %" GST_PTR_FORMAT, protectionMeta->info);

    if (gst_structure_get_uint(protectionMeta->info, "sample-index", &sampleIndex)) {
        // Process the PIFF box.
        value = gst_structure_get_value(protectionMeta->info, "box");
        if (!value) {
            GST_ERROR_OBJECT(self, "Failed to get encryption box for sample");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        box = gst_value_get_buffer(value);
        boxMapped = gst_buffer_map(box, &boxMap, GST_MAP_READ);
        if (!boxMapped) {
            GST_ERROR_OBJECT(self, "Failed to map encryption box");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        GST_TRACE_OBJECT(self, "decrypt sample %u", sampleIndex);
        if ((errorCode = self->sessionMetaData->decrypt(static_cast<void*>(map.data), static_cast<uint32_t>(map.size),
            static_cast<void*>(boxMap.data), static_cast<uint32_t>(boxMap.size), static_cast<uint32_t>(sampleIndex), trackID))) {
            GST_WARNING_OBJECT(self, "ERROR - packet decryption failed [%d]", errorCode);
            GST_MEMDUMP_OBJECT(self, "box", boxMap.data, boxMap.size);
            result = GST_FLOW_ERROR;
            goto beach;
        }
    } else {
        // Process CENC data.
        guint ivSize;
        gboolean encrypted;
        GstBuffer* ivBuffer = nullptr;
        GstMapInfo ivMap;
        unsigned position = 0;
        unsigned sampleIndex = 0;
        guint subSampleCount;
        GstBuffer* subsamplesBuffer = nullptr;
        GstMapInfo subSamplesMap;
        GstByteReader* reader = nullptr;

        if (!gst_structure_get_uint(protectionMeta->info, "iv_size", &ivSize)) {
            GST_ERROR_OBJECT(self, "failed to get iv_size");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        if (!gst_structure_get_boolean(protectionMeta->info, "encrypted", &encrypted)) {
            GST_ERROR_OBJECT(self, "failed to get encrypted flag");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        // Unencrypted sample.
        if (!ivSize || !encrypted)
            goto beach;

        if (!gst_structure_get_uint(protectionMeta->info, "subsample_count", &subSampleCount)) {
            GST_ERROR_OBJECT(self, "failed to get subsample_count");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        value = gst_structure_get_value(protectionMeta->info, "iv");
        if (!value) {
            GST_ERROR_OBJECT(self, "Failed to get IV for sample");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        ivBuffer = gst_value_get_buffer(value);
        if (!gst_buffer_map(ivBuffer, &ivMap, GST_MAP_READ)) {
            GST_ERROR_OBJECT(self, "Failed to map IV");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        if (subSampleCount) {
            value = gst_structure_get_value(protectionMeta->info, "subsamples");
            if (!value) {
                GST_ERROR_OBJECT(self, "Failed to get subsamples");
                result = GST_FLOW_NOT_SUPPORTED;
                goto release;
            }
            subsamplesBuffer = gst_value_get_buffer(value);
            if (!gst_buffer_map(subsamplesBuffer, &subSamplesMap, GST_MAP_READ)) {
                GST_ERROR_OBJECT(self, "Failed to map subsample buffer");
                result = GST_FLOW_NOT_SUPPORTED;
                goto release;
            }
        }

        reader = gst_byte_reader_new(subSamplesMap.data, subSamplesMap.size);
        if (!reader) {
            GST_ERROR_OBJECT(self, "Failed to allocate subsample reader");
            result = GST_FLOW_NOT_SUPPORTED;
            goto release;
        }

        GST_DEBUG_OBJECT(self, "position: %d, size: %d", position, map.size);
        while (position < map.size) {
            guint16 nBytesClear = 0;
            guint32 nBytesEncrypted = 0;

            if (sampleIndex < subSampleCount) {
                if (!gst_byte_reader_get_uint16_be(reader, &nBytesClear)
                    || !gst_byte_reader_get_uint32_be(reader, &nBytesEncrypted)) {
                    result = GST_FLOW_NOT_SUPPORTED;
                    GST_DEBUG_OBJECT(self, "unsupported");
                    goto release;
                }

                sampleIndex++;
            } else {
                nBytesClear = 0;
                nBytesEncrypted = map.size - position;
            }

            GST_TRACE_OBJECT(self, "%d bytes clear (todo=%d)", nBytesClear, map.size - position);
            position += nBytesClear;
            if (nBytesEncrypted) {
                GST_TRACE_OBJECT(self, "%d bytes encrypted (todo=%d)", nBytesEncrypted, map.size - position);
                if ((errorCode = self->sessionMetaData->processPayload(trackID, static_cast<const void*>(ivMap.data), static_cast<uint32_t>(ivMap.size), static_cast<void*>(map.data + position), static_cast<uint32_t>(nBytesEncrypted)))) {
                    GST_WARNING_OBJECT(self, "ERROR - packet decryption failed [%d]", errorCode);
                    result = GST_FLOW_ERROR;
                    goto release;
                }
                position += nBytesEncrypted;
            }
        }
    release:
        gst_buffer_unmap(ivBuffer, &ivMap);

        if (reader)
            gst_byte_reader_free(reader);

        if (subsamplesBuffer)
            gst_buffer_unmap(subsamplesBuffer, &subSamplesMap);
    }

beach:
    if (boxMapped)
        gst_buffer_unmap(box, &boxMap);

    if (bufferMapped)
        gst_buffer_unmap(buffer, &map);

    if (protectionMeta)
        gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));

    GST_TRACE_OBJECT(self, "Unlocking mutex");
    g_mutex_unlock(&self->mutex);
    return result;
}
Exemple #9
0
static GstFlowReturn
gst_cenc_decrypt_transform_ip (GstBaseTransform * base, GstBuffer * buf)
{
  GstCencDecrypt *self = GST_CENC_DECRYPT (base);
  GstFlowReturn ret = GST_FLOW_OK;
  GstMapInfo map, iv_map;
  const GstCencKeyPair *keypair;
  const GstProtectionMeta *prot_meta = NULL;
  guint pos = 0;
  gint sample_index = 0;
  guint subsample_count;
  AesCtrState *state = NULL;
  guint iv_size;
  gboolean encrypted;
  const GValue *value;
  GstBuffer *key_id = NULL;
  GstBuffer *iv_buf = NULL;
  GBytes *iv_bytes = NULL;
  GstBuffer *subsamples_buf = NULL;
  GstMapInfo subsamples_map;
  GstByteReader *reader=NULL;

  GST_TRACE_OBJECT (self, "decrypt in-place");
  prot_meta = (GstProtectionMeta*) gst_buffer_get_protection_meta (buf);
  if (!prot_meta || !buf) {
    if (!prot_meta) {
      GST_ERROR_OBJECT (self, "Failed to get GstProtection metadata from buffer");
    }
    if (!buf) {
      GST_ERROR_OBJECT (self, "Failed to get writable buffer");
    }
    ret = GST_FLOW_NOT_SUPPORTED;
    goto out;
  }

  if (!gst_buffer_map (buf, &map, GST_MAP_READWRITE)) {
    GST_ERROR_OBJECT (self, "Failed to map buffer");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }

  GST_TRACE_OBJECT (self, "decrypt sample %d", (gint)map.size);
  if(!gst_structure_get_uint(prot_meta->info,"iv_size",&iv_size)){
    GST_ERROR_OBJECT (self, "failed to get iv_size");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  if(!gst_structure_get_boolean(prot_meta->info,"encrypted",&encrypted)){
    GST_ERROR_OBJECT (self, "failed to get encrypted flag");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  if (iv_size == 0 || !encrypted) {
    /* sample is not encrypted */
    goto beach;
  }
  GST_DEBUG_OBJECT (base, "protection meta: %" GST_PTR_FORMAT, prot_meta->info);
  if(!gst_structure_get_uint(prot_meta->info,"subsample_count",&subsample_count)){
    GST_ERROR_OBJECT (self, "failed to get subsample_count");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  value = gst_structure_get_value (prot_meta->info, "kid");
  if(!value){
    GST_ERROR_OBJECT (self, "Failed to get KID for sample");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  key_id = gst_value_get_buffer (value);

  value = gst_structure_get_value (prot_meta->info, "iv");
  if(!value){
    GST_ERROR_OBJECT (self, "Failed to get IV for sample");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  iv_buf = gst_value_get_buffer (value);
  if(!gst_buffer_map (iv_buf, &iv_map, GST_MAP_READ)){
    GST_ERROR_OBJECT (self, "Failed to map IV");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  iv_bytes = g_bytes_new (iv_map.data, iv_map.size);
  gst_buffer_unmap (iv_buf, &iv_map);
  if(subsample_count){
    value = gst_structure_get_value (prot_meta->info, "subsamples");
    if(!value){
      GST_ERROR_OBJECT (self, "Failed to get subsamples");
      ret = GST_FLOW_NOT_SUPPORTED;
      goto release;
    }
    subsamples_buf = gst_value_get_buffer (value);
    if(!gst_buffer_map (subsamples_buf, &subsamples_map, GST_MAP_READ)){
      GST_ERROR_OBJECT (self, "Failed to map subsample buffer");
      ret = GST_FLOW_NOT_SUPPORTED;
      goto release;
    }
  }

  keypair = gst_cenc_decrypt_lookup_key (self,key_id);

  if (!keypair) {
    gsize sz;
    GST_ERROR_OBJECT (self, "Failed to lookup key");
    GST_MEMDUMP_OBJECT (self, "Key ID:", 
                        g_bytes_get_data (keypair->key_id, &sz),
                        sz);
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }

  state = gst_aes_ctr_decrypt_new (keypair->key, iv_bytes);

  if (!state) {
    GST_ERROR_OBJECT (self, "Failed to init AES cipher");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }

  if (subsample_count) {
    reader = gst_byte_reader_new (subsamples_map.data, subsamples_map.size);
    if(!reader){
      GST_ERROR_OBJECT (self, "Failed to allocate subsample reader");
      ret = GST_FLOW_NOT_SUPPORTED;
      goto release;
    }
  }

  while (pos < map.size) {
    guint16 n_bytes_clear = 0;
    guint32 n_bytes_encrypted = 0;

    if (sample_index < subsample_count) {
      if (!gst_byte_reader_get_uint16_be (reader, &n_bytes_clear)
            || !gst_byte_reader_get_uint32_be (reader, &n_bytes_encrypted)) {
          ret = GST_FLOW_NOT_SUPPORTED;
          goto release;
      }
      sample_index++;
    } else {
      n_bytes_clear = 0;
      n_bytes_encrypted = map.size - pos;
    }
    GST_TRACE_OBJECT (self, "%u bytes clear (todo=%d)", n_bytes_clear,
                      (gint)map.size - pos);
    pos += n_bytes_clear;
    if (n_bytes_encrypted) {
      GST_TRACE_OBJECT (self, "%u bytes encrypted (todo=%d)",
                        n_bytes_encrypted, (gint)map.size - pos);
      gst_aes_ctr_decrypt_ip (state, map.data + pos, n_bytes_encrypted);
      pos += n_bytes_encrypted;
    }
  }

beach:
  gst_buffer_unmap (buf, &map);
  if (state) {
    gst_aes_ctr_decrypt_unref (state);
  }
release:
  if (reader){
    gst_byte_reader_free (reader);
  }
  if(subsamples_buf){
    gst_buffer_unmap (subsamples_buf, &subsamples_map);
  }
  if (prot_meta) {
    gst_buffer_remove_meta (buf, (GstMeta *) prot_meta);
  }
  if (iv_bytes) {
    g_bytes_unref (iv_bytes);
  }
out:
  return ret;
}
static GstFlowReturn webkitMediaPlayReadyDecryptTransformInPlace(GstBaseTransform* base, GstBuffer* buffer)
{
    WebKitMediaPlayReadyDecrypt* self = WEBKIT_MEDIA_PLAYREADY_DECRYPT(base);
    GstFlowReturn result = GST_FLOW_OK;
    GstMapInfo map;
    const GValue* value;
    guint sampleIndex = 0;
    int errorCode;
    uint32_t trackID = 0;
    GstPad* pad;
    GstCaps* caps;
    GstMapInfo boxMap;
    GstBuffer* box = nullptr;
    GstProtectionMeta* protectionMeta = 0;
    gboolean boxMapped = FALSE;
    gboolean bufferMapped = FALSE;

    GST_TRACE_OBJECT(self, "Processing buffer");
    g_mutex_lock(&self->mutex);
    GST_TRACE_OBJECT(self, "Mutex acquired, stream received: %s", self->streamReceived ? "yes":"no");

    // The key might not have been received yet. Wait for it.
    if (!self->streamReceived)
        g_cond_wait(&self->condition, &self->mutex);

    if (!self->streamReceived) {
        GST_DEBUG_OBJECT(self, "Condition signaled from state change transition. Aborting.");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    GST_TRACE_OBJECT(self, "Proceeding with decryption");
    protectionMeta = reinterpret_cast<GstProtectionMeta*>(gst_buffer_get_protection_meta(buffer));
    if (!protectionMeta || !buffer) {
        if (!protectionMeta)
            GST_ERROR_OBJECT(self, "Failed to get GstProtection metadata from buffer %p", buffer);

        if (!buffer)
            GST_ERROR_OBJECT(self, "Failed to get writable buffer");

        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    bufferMapped = gst_buffer_map(buffer, &map, static_cast<GstMapFlags>(GST_MAP_READWRITE));
    if (!bufferMapped) {
        GST_ERROR_OBJECT(self, "Failed to map buffer");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    pad = gst_element_get_static_pad(GST_ELEMENT(self), "src");
    caps = gst_pad_get_current_caps(pad);
    if (g_str_has_prefix(gst_structure_get_name(gst_caps_get_structure(caps, 0)), "video/"))
        trackID = 1;
    else
        trackID = 2;
    gst_caps_unref(caps);
    gst_object_unref(pad);

    if (!gst_structure_get_uint(protectionMeta->info, "sample-index", &sampleIndex)) {
        GST_ERROR_OBJECT(self, "failed to get sample-index");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    value = gst_structure_get_value(protectionMeta->info, "box");
    if (!value) {
        GST_ERROR_OBJECT(self, "Failed to get encryption box for sample");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    box = gst_value_get_buffer(value);
    boxMapped = gst_buffer_map(box, &boxMap, GST_MAP_READ);
    if (!boxMapped) {
        GST_ERROR_OBJECT(self, "Failed to map encryption box");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    GST_TRACE_OBJECT(self, "decrypt sample %u", sampleIndex);
    if ((errorCode = self->sessionMetaData->decrypt(static_cast<void*>(map.data), static_cast<uint32_t>(map.size),
        static_cast<void*>(boxMap.data), static_cast<uint32_t>(boxMap.size), static_cast<uint32_t>(sampleIndex), trackID))) {
        GST_WARNING_OBJECT(self, "ERROR - packet decryption failed [%d]", errorCode);
        GST_MEMDUMP_OBJECT(self, "box", boxMap.data, boxMap.size);
        result = GST_FLOW_ERROR;
        goto beach;
    }

beach:
    if (boxMapped)
        gst_buffer_unmap(box, &boxMap);

    if (bufferMapped)
        gst_buffer_unmap(buffer, &map);

    if (protectionMeta)
        gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));

    GST_TRACE_OBJECT(self, "Unlocking mutex");
    g_mutex_unlock(&self->mutex);
    return result;
}
static gboolean
gst_ssa_parse_setcaps (GstPad * sinkpad, GstCaps * caps)
{
  GstSsaParse *parse = GST_SSA_PARSE (GST_PAD_PARENT (sinkpad));
  GstCaps *outcaps;
  const GValue *val;
  GstStructure *s;
  const guchar bom_utf8[] = { 0xEF, 0xBB, 0xBF };
  const gchar *end;
  GstBuffer *priv;
  GstMapInfo map;
  gchar *ptr;
  gsize left, bad_offset;
  gboolean ret;

  s = gst_caps_get_structure (caps, 0);
  val = gst_structure_get_value (s, "codec_data");
  if (val == NULL) {
    parse->framed = FALSE;
    GST_ERROR ("Only SSA subtitles embedded in containers are supported");
    return FALSE;
  }

  parse->framed = TRUE;
  parse->send_tags = TRUE;

  priv = (GstBuffer *) g_value_get_boxed (val);
  g_return_val_if_fail (priv != NULL, FALSE);

  gst_buffer_ref (priv);

  if (!gst_buffer_map (priv, &map, GST_MAP_READ))
    return FALSE;

  GST_MEMDUMP_OBJECT (parse, "init section", map.data, map.size);

  ptr = (gchar *) map.data;
  left = map.size;

  /* skip UTF-8 BOM */
  if (left >= 3 && memcmp (ptr, bom_utf8, 3) == 0) {
    ptr += 3;
    left -= 3;
  }

  if (!strstr (ptr, "[Script Info]"))
    goto invalid_init;

  if (!g_utf8_validate (ptr, left, &end)) {
    bad_offset = (gsize) (end - ptr);
    GST_WARNING_OBJECT (parse, "Init section is not valid UTF-8. Problem at "
        "byte offset %" G_GSIZE_FORMAT, bad_offset);
    /* continue with valid UTF-8 data */
    left = bad_offset;
  }

  /* FIXME: parse initial section */
  parse->ini = g_strndup (ptr, left);
  GST_LOG_OBJECT (parse, "Init section:\n%s", parse->ini);

  gst_buffer_unmap (priv, &map);
  gst_buffer_unref (priv);

  outcaps = gst_caps_new_simple ("text/x-raw",
      "format", G_TYPE_STRING, "pango-markup", NULL);

  ret = gst_pad_set_caps (parse->srcpad, outcaps);
  gst_caps_unref (outcaps);

  return ret;

  /* ERRORS */
invalid_init:
  {
    GST_WARNING_OBJECT (parse, "Invalid Init section - no Script Info header");
    gst_buffer_unmap (priv, &map);
    gst_buffer_unref (priv);
    return FALSE;
  }
}
Exemple #12
0
/**
 * gst_riff_parse_info:
 * @element: caller element (used for debugging/error).
 * @buf: input data to be used for parsing, stripped from header.
 * @taglist: a pointer to a taglist (returned by this function)
 *           containing information about this stream. May be
 *           NULL if no supported tags were found.
 *
 * Parses stream metadata from input data.
 */
void
gst_riff_parse_info (GstElement * element,
    GstBuffer * buf, GstTagList ** _taglist)
{
  guint8 *data;
  guint size, tsize;
  guint32 tag;
  const gchar *type;
  GstTagList *taglist;

  g_return_if_fail (_taglist != NULL);

  if (!buf) {
    *_taglist = NULL;
    return;
  }
  data = GST_BUFFER_DATA (buf);
  size = GST_BUFFER_SIZE (buf);
  taglist = gst_tag_list_new ();

  while (size > 8) {
    tag = GST_READ_UINT32_LE (data);
    tsize = GST_READ_UINT32_LE (data + 4);

    GST_MEMDUMP_OBJECT (element, "tag chunk", data, MIN (tsize + 8, size));

    size -= 8;
    data += 8;

    GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
        GST_FOURCC_ARGS (tag), tsize);

    if (tsize > size) {
      GST_WARNING_OBJECT (element,
          "Tagsize %d is larger than available data %d", tsize, size);
      tsize = size;
    }

    /* make uppercase */
    tag = tag & 0xDFDFDFDF;

    /* find out the type of metadata */
    switch (tag) {
      case GST_RIFF_INFO_IARL:
        type = GST_TAG_LOCATION;
        break;
      case GST_RIFF_INFO_IAAR:
        type = GST_TAG_ALBUM_ARTIST;
        break;
      case GST_RIFF_INFO_IART:
        type = GST_TAG_ARTIST;
        break;
      case GST_RIFF_INFO_ICMS:
        type = NULL;            /*"Commissioner"; */
        break;
      case GST_RIFF_INFO_ICMT:
        type = GST_TAG_COMMENT;
        break;
      case GST_RIFF_INFO_ICOP:
        type = GST_TAG_COPYRIGHT;
        break;
      case GST_RIFF_INFO_ICRD:
        type = GST_TAG_DATE;
        break;
      case GST_RIFF_INFO_ICRP:
        type = NULL;            /*"Cropped"; */
        break;
      case GST_RIFF_INFO_IDIM:
        type = NULL;            /*"Dimensions"; */
        break;
      case GST_RIFF_INFO_IDPI:
        type = NULL;            /*"Dots per Inch"; */
        break;
      case GST_RIFF_INFO_IENG:
        type = NULL;            /*"Engineer"; */
        break;
      case GST_RIFF_INFO_IGNR:
        type = GST_TAG_GENRE;
        break;
      case GST_RIFF_INFO_IKEY:
        type = GST_TAG_KEYWORDS;
        break;
      case GST_RIFF_INFO_ILGT:
        type = NULL;            /*"Lightness"; */
        break;
      case GST_RIFF_INFO_IMED:
        type = NULL;            /*"Medium"; */
        break;
      case GST_RIFF_INFO_INAM:
        type = GST_TAG_TITLE;
        break;
      case GST_RIFF_INFO_IPLT:
        type = NULL;            /*"Palette"; */
        break;
      case GST_RIFF_INFO_IPRD:
        type = GST_TAG_ALBUM;
        break;
      case GST_RIFF_INFO_ISBJ:
        type = GST_TAG_ALBUM_ARTIST;
        break;
      case GST_RIFF_INFO_ISFT:
        type = GST_TAG_ENCODER;
        break;
      case GST_RIFF_INFO_ISHP:
        type = NULL;            /*"Sharpness"; */
        break;
      case GST_RIFF_INFO_ISRC:
        type = GST_TAG_ISRC;
        break;
      case GST_RIFF_INFO_ISRF:
        type = NULL;            /*"Source Form"; */
        break;
      case GST_RIFF_INFO_ITCH:
        type = NULL;            /*"Technician"; */
        break;
      case GST_RIFF_INFO_ITRK:
        type = GST_TAG_TRACK_NUMBER;
        break;
      default:
        type = NULL;
        GST_WARNING_OBJECT (element,
            "Unknown INFO (metadata) tag entry %" GST_FOURCC_FORMAT,
            GST_FOURCC_ARGS (tag));
        break;
    }

    if (type != NULL && data[0] != '\0') {
      static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
        "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
      };
      GType tag_type;
      gchar *val;

      GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s",
          GST_FOURCC_ARGS (tag), type);

      tag_type = gst_tag_get_type (type);
      val = gst_tag_freeform_string_to_utf8 ((gchar *) data, tsize, env_vars);

      if (val != NULL) {
        if (tag_type == G_TYPE_STRING) {
          gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
        } else {
          GValue tag_val = { 0, };

          g_value_init (&tag_val, tag_type);
          if (gst_value_deserialize (&tag_val, val)) {
            gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type,
                &tag_val);
          } else {
            GST_WARNING_OBJECT (element, "could not deserialize '%s' into a "
                "tag %s of type %s", val, type, g_type_name (tag_type));
          }
          g_value_unset (&tag_val);
        }
        g_free (val);
      } else {
        GST_WARNING_OBJECT (element, "could not extract %s tag", type);
      }
    }

    if (tsize & 1) {
      tsize++;
      if (tsize > size)
        tsize = size;
    }

    data += tsize;
    size -= tsize;
  }

  if (!gst_tag_list_is_empty (taglist)) {
    GST_INFO_OBJECT (element, "extracted tags: %" GST_PTR_FORMAT, taglist);
    *_taglist = taglist;
  } else {
    *_taglist = NULL;
    gst_tag_list_free (taglist);
  }

  return;
}