예제 #1
0
EXPORT_C
#endif

GstByteReader *
gst_byte_reader_new_from_buffer (const GstBuffer * buffer)
{
  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);

  return gst_byte_reader_new (GST_BUFFER_DATA (buffer),
      GST_BUFFER_SIZE (buffer));
}
예제 #2
0
static GstFlowReturn
gst_asf_parse_parse_data_object (GstAsfParse * asfparse, GstBuffer * buffer)
{
  GstByteReader *reader;
  GstFlowReturn ret = GST_FLOW_OK;
  guint64 packet_count = 0;
  GstMapInfo map;

  GST_DEBUG_OBJECT (asfparse, "Parsing data object");

  gst_buffer_map (buffer, &map, GST_MAP_READ);
  reader = gst_byte_reader_new (map.data, map.size);
  /* skip to packet count */
  if (!gst_byte_reader_skip (reader, 40))
    goto error;
  if (!gst_byte_reader_get_uint64_le (reader, &packet_count))
    goto error;

  if (asfparse->asfinfo->packets_count != packet_count) {
    GST_WARNING_OBJECT (asfparse, "File properties object and data object have "
        "different packets count, %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
        asfparse->asfinfo->packets_count, packet_count);
  } else {
    GST_DEBUG_OBJECT (asfparse, "Total packets: %" G_GUINT64_FORMAT,
        packet_count);
  }

  gst_buffer_unmap (buffer, &map);
  gst_byte_reader_free (reader);
  return gst_asf_parse_push (asfparse, buffer);

error:
  ret = GST_FLOW_ERROR;
  GST_ERROR_OBJECT (asfparse, "Error while parsing data object headers");
  gst_buffer_unmap (buffer, &map);
  gst_byte_reader_free (reader);
  return ret;
}
static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSampleCount, GstBuffer* subSamplesBuffer)
{
    GstMapInfo ivMap;
    if (!gst_buffer_map(ivBuffer, &ivMap, GST_MAP_READ)) {
        GST_ERROR_OBJECT(self, "Failed to map IV");
        return false;
    }

    uint8_t ctr[CLEARKEY_SIZE];
    if (ivMap.size == 8) {
        memset(ctr + 8, 0, 8);
        memcpy(ctr, ivMap.data, 8);
    } else {
        ASSERT(ivMap.size == CLEARKEY_SIZE);
        memcpy(ctr, ivMap.data, CLEARKEY_SIZE);
    }
    gst_buffer_unmap(ivBuffer, &ivMap);

    WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
    gcry_error_t error = gcry_cipher_setctr(priv->handle, ctr, CLEARKEY_SIZE);
    if (error) {
        GST_ERROR_OBJECT(self, "gcry_cipher_setctr failed: %s", gpg_strerror(error));
        return false;
    }

    GstMapInfo map;
    gboolean bufferMapped = gst_buffer_map(buffer, &map, static_cast<GstMapFlags>(GST_MAP_READWRITE));
    if (!bufferMapped) {
        GST_ERROR_OBJECT(self, "Failed to map buffer");
        return false;
    }

    GstMapInfo subSamplesMap;
    gboolean subsamplesBufferMapped = gst_buffer_map(subSamplesBuffer, &subSamplesMap, GST_MAP_READ);
    if (!subsamplesBufferMapped) {
        GST_ERROR_OBJECT(self, "Failed to map subsample buffer");
        gst_buffer_unmap(buffer, &map);
        return false;
    }

    GstByteReader* reader = gst_byte_reader_new(subSamplesMap.data, subSamplesMap.size);
    unsigned position = 0;
    unsigned sampleIndex = 0;

    GST_DEBUG_OBJECT(self, "position: %d, size: %zu", 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)) {
                GST_DEBUG_OBJECT(self, "unsupported");
                gst_byte_reader_free(reader);
                gst_buffer_unmap(buffer, &map);
                gst_buffer_unmap(subSamplesBuffer, &subSamplesMap);
                return false;
            }

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

        GST_TRACE_OBJECT(self, "%d bytes clear (todo=%zu)", nBytesClear, map.size - position);
        position += nBytesClear;
        if (nBytesEncrypted) {
            GST_TRACE_OBJECT(self, "%d bytes encrypted (todo=%zu)", nBytesEncrypted, map.size - position);
            error = gcry_cipher_decrypt(priv->handle, map.data + position, nBytesEncrypted, 0, 0);
            if (error) {
                GST_ERROR_OBJECT(self, "decryption failed: %s", gpg_strerror(error));
                gst_byte_reader_free(reader);
                gst_buffer_unmap(buffer, &map);
                gst_buffer_unmap(subSamplesBuffer, &subSamplesMap);
                return false;
            }
            position += nBytesEncrypted;
        }
    }

    gst_byte_reader_free(reader);
    gst_buffer_unmap(buffer, &map);
    gst_buffer_unmap(subSamplesBuffer, &subSamplesMap);
    return true;
}
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;
}
예제 #5
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;
}