mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
hlsdemux: re-enable decryption after uridownloader removal
Now the decryption is done buffer by buffer instead of on the whole fragment at once. As it expects multiples of 16 bytes a GstAdapter was added to properly chunk the buffers. Also the last buffer must be resized depending on the value of the last byte of the fragment, so hlsdemux always keeps a pending buffer as it doesn't know if it is the last one yet
This commit is contained in:
parent
3611759557
commit
c93c222786
2 changed files with 212 additions and 108 deletions
|
@ -41,12 +41,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef HAVE_NETTLE
|
|
||||||
#include <nettle/aes.h>
|
|
||||||
#include <nettle/cbc.h>
|
|
||||||
#else
|
|
||||||
#include <gcrypt.h>
|
|
||||||
#endif
|
|
||||||
#include <gst/base/gsttypefindhelper.h>
|
#include <gst/base/gsttypefindhelper.h>
|
||||||
#include "gsthlsdemux.h"
|
#include "gsthlsdemux.h"
|
||||||
|
|
||||||
|
@ -117,6 +111,12 @@ static gchar *gst_hls_src_buf_to_utf8_playlist (GstBuffer * buf);
|
||||||
|
|
||||||
static gboolean gst_hls_demux_change_playlist (GstHLSDemux * demux,
|
static gboolean gst_hls_demux_change_playlist (GstHLSDemux * demux,
|
||||||
guint max_bitrate);
|
guint max_bitrate);
|
||||||
|
static GstBuffer *gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
|
||||||
|
GstBuffer * encrypted_buffer, GError ** err);
|
||||||
|
static gboolean
|
||||||
|
gst_hls_demux_decrypt_start (GstHLSDemux * demux, const guint8 * key_data,
|
||||||
|
const guint8 * iv_data);
|
||||||
|
static void gst_hls_demux_decrypt_end (GstHLSDemux * demux);
|
||||||
|
|
||||||
#define gst_hls_demux_parent_class parent_class
|
#define gst_hls_demux_parent_class parent_class
|
||||||
G_DEFINE_TYPE (GstHLSDemux, gst_hls_demux, GST_TYPE_BIN);
|
G_DEFINE_TYPE (GstHLSDemux, gst_hls_demux, GST_TYPE_BIN);
|
||||||
|
@ -307,6 +307,9 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
|
||||||
gst_hls_demux_reset (demux, FALSE);
|
gst_hls_demux_reset (demux, FALSE);
|
||||||
gst_uri_downloader_reset (demux->downloader);
|
gst_uri_downloader_reset (demux->downloader);
|
||||||
break;
|
break;
|
||||||
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
|
demux->adapter = gst_adapter_new ();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -321,6 +324,10 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
|
||||||
gst_task_join (demux->stream_task);
|
gst_task_join (demux->stream_task);
|
||||||
gst_hls_demux_reset (demux, FALSE);
|
gst_hls_demux_reset (demux, FALSE);
|
||||||
break;
|
break;
|
||||||
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
gst_object_unref (demux->adapter);
|
||||||
|
demux->adapter = NULL;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -735,14 +742,90 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is it encrypted? */
|
||||||
|
if (demux->current_key) {
|
||||||
|
GError *err = NULL;
|
||||||
|
GstBuffer *tmp_buffer;
|
||||||
|
gsize available;
|
||||||
|
|
||||||
|
/* restart the decrypting lib for a new fragment */
|
||||||
|
if (demux->starting_fragment) {
|
||||||
|
GstFragment *key_fragment;
|
||||||
|
GstBuffer *key_buffer;
|
||||||
|
GstMapInfo key_info;
|
||||||
|
|
||||||
|
/* new key? */
|
||||||
|
if (demux->key_url && strcmp (demux->key_url, demux->current_key) == 0) {
|
||||||
|
key_fragment = g_object_ref (demux->key_fragment);
|
||||||
|
} else {
|
||||||
|
g_free (demux->key_url);
|
||||||
|
demux->key_url = NULL;
|
||||||
|
|
||||||
|
if (demux->key_fragment)
|
||||||
|
g_object_unref (demux->key_fragment);
|
||||||
|
demux->key_fragment = NULL;
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (demux, "Fetching key %s", demux->current_key);
|
||||||
|
key_fragment =
|
||||||
|
gst_uri_downloader_fetch_uri_with_referer (demux->downloader,
|
||||||
|
demux->current_key, demux->client->main ?
|
||||||
|
demux->client->main->uri : NULL, FALSE, &err);
|
||||||
|
if (key_fragment == NULL)
|
||||||
|
goto key_failed;
|
||||||
|
demux->key_url = g_strdup (demux->current_key);
|
||||||
|
demux->key_fragment = g_object_ref (key_fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
key_buffer = gst_fragment_get_buffer (key_fragment);
|
||||||
|
gst_buffer_map (key_buffer, &key_info, GST_MAP_READ);
|
||||||
|
|
||||||
|
gst_hls_demux_decrypt_start (demux, key_info.data, demux->current_iv);
|
||||||
|
|
||||||
|
gst_buffer_unmap (key_buffer, &key_info);
|
||||||
|
gst_buffer_unref (key_buffer);
|
||||||
|
gst_object_unref (key_fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_adapter_push (demux->adapter, buffer);
|
||||||
|
|
||||||
|
/* must be a multiple of 16 */
|
||||||
|
available = gst_adapter_available (demux->adapter) & (~0xF);
|
||||||
|
|
||||||
|
if (available == 0) {
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = gst_adapter_take_buffer (demux->adapter, available);
|
||||||
|
buffer = gst_hls_demux_decrypt_fragment (demux, buffer, &err);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"),
|
||||||
|
("decryption failed %s", err->message));
|
||||||
|
g_error_free (err);
|
||||||
|
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_buffer = demux->pending_buffer;
|
||||||
|
demux->pending_buffer = buffer;
|
||||||
|
buffer = tmp_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (demux->starting_fragment) {
|
||||||
|
if (demux->segment.rate < 0)
|
||||||
|
/* Set DISCONT flag for every first buffer in reverse playback mode
|
||||||
|
* as each fragment for its own has to be reversed */
|
||||||
|
demux->discont = TRUE;
|
||||||
|
demux->starting_fragment = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (demux->discont) {
|
if (demux->discont) {
|
||||||
GST_DEBUG_OBJECT (demux, "Marking fragment as discontinuous");
|
GST_DEBUG_OBJECT (demux, "Marking fragment as discontinuous");
|
||||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||||
demux->discont = FALSE;
|
demux->discont = FALSE;
|
||||||
} else if (demux->starting_fragment && demux->segment.rate < 0) {
|
|
||||||
/* Set DISCONT flag for every buffer in reverse playback mode
|
|
||||||
* as each fragment for its own has to be reversed */
|
|
||||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
|
||||||
} else {
|
} else {
|
||||||
GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
|
GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||||
}
|
}
|
||||||
|
@ -788,6 +871,10 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
key_failed:
|
||||||
|
/* TODO ERROR here */
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -798,6 +885,27 @@ _src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
|
if (demux->current_key)
|
||||||
|
gst_hls_demux_decrypt_end (demux);
|
||||||
|
/* TODO adapter should be empty */
|
||||||
|
|
||||||
|
/* pending buffer is only used for encrypted streams */
|
||||||
|
if (demux->pending_buffer) {
|
||||||
|
GstMapInfo info;
|
||||||
|
gsize unpadded_size;
|
||||||
|
|
||||||
|
/* Handle pkcs7 unpadding here */
|
||||||
|
gst_buffer_map (demux->pending_buffer, &info, GST_MAP_READ);
|
||||||
|
unpadded_size = info.size - info.data[info.size - 1];
|
||||||
|
gst_buffer_unmap (demux->pending_buffer, &info);
|
||||||
|
|
||||||
|
gst_buffer_resize (demux->pending_buffer, 0, unpadded_size);
|
||||||
|
|
||||||
|
/* TODO check return */
|
||||||
|
gst_pad_push (demux->srcpad, demux->pending_buffer);
|
||||||
|
demux->pending_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
g_cond_signal (&demux->fragment_download_cond);
|
g_cond_signal (&demux->fragment_download_cond);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1120,6 +1228,14 @@ gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose)
|
||||||
demux->srcpad = NULL;
|
demux->srcpad = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (demux->adapter)
|
||||||
|
gst_adapter_clear (demux->adapter);
|
||||||
|
if (demux->pending_buffer)
|
||||||
|
gst_buffer_unref (demux->pending_buffer);
|
||||||
|
demux->pending_buffer = NULL;
|
||||||
|
demux->current_key = NULL;
|
||||||
|
demux->current_iv = NULL;
|
||||||
|
|
||||||
demux->current_download_rate = -1;
|
demux->current_download_rate = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1325,8 +1441,8 @@ gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
|
||||||
|
|
||||||
GST_M3U8_CLIENT_LOCK (demux->client);
|
GST_M3U8_CLIENT_LOCK (demux->client);
|
||||||
last_sequence =
|
last_sequence =
|
||||||
GST_M3U8_MEDIA_FILE (g_list_last (demux->client->current->
|
GST_M3U8_MEDIA_FILE (g_list_last (demux->client->current->files)->
|
||||||
files)->data)->sequence;
|
data)->sequence;
|
||||||
|
|
||||||
if (demux->client->sequence >= last_sequence - 3) {
|
if (demux->client->sequence >= last_sequence - 3) {
|
||||||
GST_DEBUG_OBJECT (demux, "Sequence is beyond playlist. Moving back to %u",
|
GST_DEBUG_OBJECT (demux, "Sequence is beyond playlist. Moving back to %u",
|
||||||
|
@ -1426,8 +1542,8 @@ retry_failover_protection:
|
||||||
gst_m3u8_client_set_current (demux->client, previous_variant->data);
|
gst_m3u8_client_set_current (demux->client, previous_variant->data);
|
||||||
/* Try a lower bitrate (or stop if we just tried the lowest) */
|
/* Try a lower bitrate (or stop if we just tried the lowest) */
|
||||||
if (GST_M3U8 (previous_variant->data)->iframe && new_bandwidth ==
|
if (GST_M3U8 (previous_variant->data)->iframe && new_bandwidth ==
|
||||||
GST_M3U8 (g_list_first (demux->client->main->iframe_lists)->data)->
|
GST_M3U8 (g_list_first (demux->client->main->iframe_lists)->
|
||||||
bandwidth)
|
data)->bandwidth)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (!GST_M3U8 (previous_variant->data)->iframe && new_bandwidth ==
|
else if (!GST_M3U8 (previous_variant->data)->iframe && new_bandwidth ==
|
||||||
GST_M3U8 (g_list_first (demux->client->main->lists)->data)->bandwidth)
|
GST_M3U8 (g_list_first (demux->client->main->lists)->data)->bandwidth)
|
||||||
|
@ -1487,126 +1603,105 @@ gst_hls_demux_switch_playlist (GstHLSDemux * demux, GstFragment * fragment)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
#ifdef HAVE_NETTLE
|
#ifdef HAVE_NETTLE
|
||||||
static gboolean
|
static gboolean
|
||||||
decrypt_fragment (GstHLSDemux * demux, gsize length,
|
gst_hls_demux_decrypt_start (GstHLSDemux * demux, const guint8 * key_data,
|
||||||
const guint8 * encrypted_data, guint8 * decrypted_data,
|
const guint8 * iv_data)
|
||||||
const guint8 * key_data, const guint8 * iv_data)
|
|
||||||
{
|
{
|
||||||
struct CBC_CTX (struct aes_ctx, AES_BLOCK_SIZE) aes_ctx;
|
aes_set_decrypt_key (&demux->aes_ctx.ctx, 16, key_data);
|
||||||
|
CBC_SET_IV (&demux->aes_ctx, iv_data);
|
||||||
if (length % 16 != 0)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
aes_set_decrypt_key (&aes_ctx.ctx, 16, key_data);
|
|
||||||
CBC_SET_IV (&aes_ctx, iv_data);
|
|
||||||
|
|
||||||
CBC_DECRYPT (&aes_ctx, aes_decrypt, length, decrypted_data, encrypted_data);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static gboolean
|
static gboolean
|
||||||
decrypt_fragment (GstHLSDemux * demux, gsize length,
|
decrypt_fragment (GstHLSDemux * demux, gsize length,
|
||||||
const guint8 * encrypted_data, guint8 * decrypted_data,
|
const guint8 * encrypted_data, guint8 * decrypted_data)
|
||||||
const guint8 * key_data, const guint8 * iv_data)
|
{
|
||||||
|
if (length % 16 != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
CBC_DECRYPT (&demux->aes_ctx, aes_decrypt, length, decrypted_data,
|
||||||
|
encrypted_data);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_hls_demux_decrypt_end (GstHLSDemux * demux)
|
||||||
|
{
|
||||||
|
/* NOP */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static gboolean
|
||||||
|
gst_hls_demux_decrypt_start (GstHLSDemux * demux, const guint8 * key_data,
|
||||||
|
const guint8 * iv_data)
|
||||||
{
|
{
|
||||||
gcry_cipher_hd_t aes_ctx = NULL;
|
|
||||||
gcry_error_t err = 0;
|
gcry_error_t err = 0;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
err =
|
err =
|
||||||
gcry_cipher_open (&aes_ctx, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
|
gcry_cipher_open (&demux->aes_ctx, GCRY_CIPHER_AES128,
|
||||||
|
GCRY_CIPHER_MODE_CBC, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
err = gcry_cipher_setkey (aes_ctx, key_data, 16);
|
err = gcry_cipher_setkey (demux->aes_ctx, key_data, 16);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
err = gcry_cipher_setiv (aes_ctx, iv_data, 16);
|
err = gcry_cipher_setiv (demux->aes_ctx, iv_data, 16);
|
||||||
if (err)
|
if (!err)
|
||||||
goto out;
|
ret = TRUE;
|
||||||
err = gcry_cipher_decrypt (aes_ctx, decrypted_data, length,
|
|
||||||
encrypted_data, length);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (aes_ctx)
|
if (!ret)
|
||||||
gcry_cipher_close (aes_ctx);
|
if (demux->aes_ctx)
|
||||||
|
gcry_cipher_close (demux->aes_ctx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
decrypt_fragment (GstHLSDemux * demux, gsize length,
|
||||||
|
const guint8 * encrypted_data, guint8 * decrypted_data)
|
||||||
|
{
|
||||||
|
gcry_error_t err = 0;
|
||||||
|
|
||||||
|
err = gcry_cipher_decrypt (demux->aes_ctx, decrypted_data, length,
|
||||||
|
encrypted_data, length);
|
||||||
|
|
||||||
|
return err == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_hls_demux_decrypt_end (GstHLSDemux * demux)
|
||||||
|
{
|
||||||
|
if (demux->aes_ctx)
|
||||||
|
gcry_cipher_close (demux->aes_ctx);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static GstFragment *
|
static GstBuffer *
|
||||||
gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
|
gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
|
||||||
GstFragment * encrypted_fragment, const gchar * key, const guint8 * iv,
|
GstBuffer * encrypted_buffer, GError ** err)
|
||||||
GError ** err)
|
|
||||||
{
|
{
|
||||||
GstFragment *key_fragment, *ret = NULL;
|
GstBuffer *decrypted_buffer = NULL;
|
||||||
GstBuffer *key_buffer, *encrypted_buffer, *decrypted_buffer;
|
GstMapInfo encrypted_info, decrypted_info;
|
||||||
GstMapInfo key_info, encrypted_info, decrypted_info;
|
|
||||||
gsize unpadded_size;
|
|
||||||
|
|
||||||
if (demux->key_url && strcmp (demux->key_url, key) == 0) {
|
|
||||||
key_fragment = g_object_ref (demux->key_fragment);
|
|
||||||
} else {
|
|
||||||
g_free (demux->key_url);
|
|
||||||
demux->key_url = NULL;
|
|
||||||
|
|
||||||
if (demux->key_fragment)
|
|
||||||
g_object_unref (demux->key_fragment);
|
|
||||||
demux->key_fragment = NULL;
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (demux, "Fetching key %s", key);
|
|
||||||
key_fragment =
|
|
||||||
gst_uri_downloader_fetch_uri_with_referer (demux->downloader, key,
|
|
||||||
demux->client->main ? demux->client->main->uri : NULL, FALSE, err);
|
|
||||||
if (key_fragment == NULL)
|
|
||||||
goto key_failed;
|
|
||||||
demux->key_url = g_strdup (key);
|
|
||||||
demux->key_fragment = g_object_ref (key_fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
key_buffer = gst_fragment_get_buffer (key_fragment);
|
|
||||||
encrypted_buffer = gst_fragment_get_buffer (encrypted_fragment);
|
|
||||||
decrypted_buffer =
|
decrypted_buffer =
|
||||||
gst_buffer_new_allocate (NULL, gst_buffer_get_size (encrypted_buffer),
|
gst_buffer_new_allocate (NULL, gst_buffer_get_size (encrypted_buffer),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
gst_buffer_map (key_buffer, &key_info, GST_MAP_READ);
|
|
||||||
gst_buffer_map (encrypted_buffer, &encrypted_info, GST_MAP_READ);
|
gst_buffer_map (encrypted_buffer, &encrypted_info, GST_MAP_READ);
|
||||||
gst_buffer_map (decrypted_buffer, &decrypted_info, GST_MAP_WRITE);
|
gst_buffer_map (decrypted_buffer, &decrypted_info, GST_MAP_WRITE);
|
||||||
|
|
||||||
if (key_info.size != 16)
|
|
||||||
goto decrypt_error;
|
|
||||||
if (!decrypt_fragment (demux, encrypted_info.size,
|
if (!decrypt_fragment (demux, encrypted_info.size,
|
||||||
encrypted_info.data, decrypted_info.data, key_info.data, iv))
|
encrypted_info.data, decrypted_info.data))
|
||||||
goto decrypt_error;
|
goto decrypt_error;
|
||||||
|
|
||||||
/* Handle pkcs7 unpadding here */
|
|
||||||
unpadded_size =
|
|
||||||
decrypted_info.size - decrypted_info.data[decrypted_info.size - 1];
|
|
||||||
|
|
||||||
gst_buffer_unmap (decrypted_buffer, &decrypted_info);
|
gst_buffer_unmap (decrypted_buffer, &decrypted_info);
|
||||||
gst_buffer_unmap (encrypted_buffer, &encrypted_info);
|
gst_buffer_unmap (encrypted_buffer, &encrypted_info);
|
||||||
gst_buffer_unmap (key_buffer, &key_info);
|
|
||||||
|
|
||||||
gst_buffer_resize (decrypted_buffer, 0, unpadded_size);
|
|
||||||
|
|
||||||
gst_buffer_unref (key_buffer);
|
|
||||||
gst_buffer_unref (encrypted_buffer);
|
|
||||||
g_object_unref (key_fragment);
|
|
||||||
|
|
||||||
ret = gst_fragment_new ();
|
|
||||||
gst_fragment_add_buffer (ret, decrypted_buffer);
|
|
||||||
ret->completed = TRUE;
|
|
||||||
key_failed:
|
|
||||||
g_object_unref (encrypted_fragment);
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
decrypt_error:
|
decrypt_error:
|
||||||
GST_ERROR_OBJECT (demux, "Failed to decrypt fragment");
|
GST_ERROR_OBJECT (demux, "Failed to decrypt fragment");
|
||||||
|
@ -1615,17 +1710,12 @@ decrypt_error:
|
||||||
|
|
||||||
gst_buffer_unmap (decrypted_buffer, &decrypted_info);
|
gst_buffer_unmap (decrypted_buffer, &decrypted_info);
|
||||||
gst_buffer_unmap (encrypted_buffer, &encrypted_info);
|
gst_buffer_unmap (encrypted_buffer, &encrypted_info);
|
||||||
gst_buffer_unmap (key_buffer, &key_info);
|
|
||||||
|
|
||||||
gst_buffer_unref (key_buffer);
|
|
||||||
gst_buffer_unref (encrypted_buffer);
|
gst_buffer_unref (encrypted_buffer);
|
||||||
gst_buffer_unref (decrypted_buffer);
|
gst_buffer_unref (decrypted_buffer);
|
||||||
|
|
||||||
g_object_unref (key_fragment);
|
return decrypted_buffer;
|
||||||
g_object_unref (encrypted_fragment);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
|
@ -1661,6 +1751,8 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
/* set up our source for download */
|
/* set up our source for download */
|
||||||
demux->current_timestamp = timestamp;
|
demux->current_timestamp = timestamp;
|
||||||
demux->starting_fragment = TRUE;
|
demux->starting_fragment = TRUE;
|
||||||
|
demux->current_key = key;
|
||||||
|
demux->current_iv = iv;
|
||||||
g_object_set (demux->src, "location", next_fragment_uri, NULL);
|
g_object_set (demux->src, "location", next_fragment_uri, NULL);
|
||||||
gst_element_set_state (demux->src, GST_STATE_READY); /* TODO check return */
|
gst_element_set_state (demux->src, GST_STATE_READY); /* TODO check return */
|
||||||
gst_element_send_event (demux->src, gst_event_new_seek (1.0, GST_FORMAT_BYTES,
|
gst_element_send_event (demux->src, gst_event_new_seek (1.0, GST_FORMAT_BYTES,
|
||||||
|
@ -1675,13 +1767,5 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
|
||||||
g_mutex_unlock (&demux->fragment_download_lock);
|
g_mutex_unlock (&demux->fragment_download_lock);
|
||||||
gst_element_set_state (demux->src, GST_STATE_NULL);
|
gst_element_set_state (demux->src, GST_STATE_NULL);
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (key) {
|
|
||||||
download = gst_hls_demux_decrypt_fragment (demux, download, key, iv, err);
|
|
||||||
if (download == NULL)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,12 @@
|
||||||
#include "m3u8.h"
|
#include "m3u8.h"
|
||||||
#include "gstfragmented.h"
|
#include "gstfragmented.h"
|
||||||
#include <gst/uridownloader/gsturidownloader.h>
|
#include <gst/uridownloader/gsturidownloader.h>
|
||||||
|
#ifdef HAVE_NETTLE
|
||||||
|
#include <nettle/aes.h>
|
||||||
|
#include <nettle/cbc.h>
|
||||||
|
#else
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
#define GST_TYPE_HLS_DEMUX \
|
#define GST_TYPE_HLS_DEMUX \
|
||||||
|
@ -110,6 +116,20 @@ struct _GstHLSDemux
|
||||||
GCond fragment_download_cond;
|
GCond fragment_download_cond;
|
||||||
GstClockTime current_timestamp;
|
GstClockTime current_timestamp;
|
||||||
gboolean starting_fragment;
|
gboolean starting_fragment;
|
||||||
|
|
||||||
|
/* decryption tooling */
|
||||||
|
#ifdef HAVE_NETTLE
|
||||||
|
struct CBC_CTX (struct aes_ctx, AES_BLOCK_SIZE) aes_ctx;
|
||||||
|
#else
|
||||||
|
gcry_cipher_hd_t aes_ctx;
|
||||||
|
#endif
|
||||||
|
const gchar *current_key;
|
||||||
|
const guint8 *current_iv;
|
||||||
|
GstAdapter *adapter; /* used to accumulate 16 bytes multiple chunks */
|
||||||
|
GstBuffer *pending_buffer; /* decryption scenario:
|
||||||
|
* the last buffer can only be pushed when
|
||||||
|
* resized, so need to store and wait for
|
||||||
|
* EOS to know it is the last */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstHLSDemuxClass
|
struct _GstHLSDemuxClass
|
||||||
|
|
Loading…
Reference in a new issue