9#include "libmythbase/mythconfig.h"
12#include <openssl/aes.h>
13#include <openssl/evp.h>
16#include <QMutexLocker>
20#ifdef HLS_USE_MYTHDOWNLOADMANAGER
24#define LOC QString("HLSRecstream[%1]: ").arg(m_inputId)
30 m_m3u8Url(std::move(m3u8_url)),
31 m_segmentBaseUrl(std::move(segment_base_url))
33 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"ctor");
38 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"dtor");
40 AESKeyMap::iterator Iaes;
42 for (Iaes = m_aesKeys.begin(); Iaes != m_aesKeys.end(); ++Iaes)
49 return QString(
"%1 bitrate %2").arg(
Id()).arg(
Bitrate());
58#ifdef HLS_USE_MYTHDOWNLOADMANAGER
59 bool ret = HLSReader::DownloadURL(keypath, &key);
61 QUrl keyUrl { keypath };
62 if (!keyUrl.isValid())
64 LOG(VB_RECORD, LOG_ERR,
LOC +
"Invalid key path: " + keypath);
74 LOG(VB_RECORD, LOG_ERR,
LOC +
75 QString(
"The AES key loaded doesn't have the right size (%1)")
80 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to download AES key: " +
87 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Downloaded AES key");
95int HLSRecStream::Decrypt(
unsigned char *ciphertext,
int ciphertext_len,
unsigned char *key,
96 unsigned char *iv,
unsigned char *plaintext)
const
100 int plaintext_len = 0;
103 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
106 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to create and initialize cipher context");
117 if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
119 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to initialize decryption operation");
127 if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
129 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to decrypt");
138 if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
140 LOG(VB_RECORD, LOG_ERR,
LOC +
"Failed to finalize decryption" +
141 QString(
" len:%1").arg(len) +
142 QString(
" plaintext_len:%1").arg(plaintext_len) );
145 plaintext_len += len;
148 EVP_CIPHER_CTX_free(ctx);
150 return plaintext_len;
154 const QByteArray& IV,
const QString& keypath,
155 QByteArray& data, int64_t sequence)
157 LOG(VB_RECORD, LOG_INFO,
LOC +
"DecodeData:" +
158 QString(
" IV.size():%1").arg(IV.size()) +
159 QString(
" keypath:%1..%2").arg(keypath.left(20),keypath.right(20)) +
160 QString(
" sequence:%1").arg(sequence));
162 AESKeyMap::iterator Ikey = m_aesKeys.find(keypath);
163 if (Ikey == m_aesKeys.end())
166 DownloadKey(downloader, keypath, key);
167 Ikey = m_aesKeys.insert(keypath, key);
168 if (Ikey == m_aesKeys.end())
170 LOG(VB_RECORD, LOG_ERR,
LOC +
171 "DecodeData: Unable to add AES key to map");
177 std::array<uint8_t,AES_BLOCK_SIZE> iv {};
178 auto *decrypted_data =
new uint8_t[data.size()];
189 iv[15] = sequence & 0xff;
190 iv[14] = (sequence >> 8) & 0xff;
191 iv[13] = (sequence >> 16) & 0xff;
192 iv[12] = (sequence >> 24) & 0xff;
199 int aeslen = data.size() & ~0xf;
200 if (aeslen != data.size())
202 LOG(VB_RECORD, LOG_WARNING,
LOC +
203 QString(
"Data size %1 not multiple of 16 bytes, rounding to %2")
204 .arg(data.size()).arg(aeslen));
207 int plaintext_len = Decrypt((
unsigned char*)data.constData(), aeslen, (*Ikey)->key.data(),
208 iv.data(), decrypted_data);
210 LOG(VB_RECORD, LOG_INFO,
LOC +
211 QString(
"Segment data.size()):%1 plaintext_len:%2")
212 .arg(data.size()).arg(plaintext_len));
214 data = QByteArray(
reinterpret_cast<char*
>(decrypted_data), plaintext_len);
215 delete[] decrypted_data;
233 QMutexLocker lock(&
m_lock);
static constexpr uint8_t AES128_KEY_SIZE
hls_aes_key_st HLS_AES_KEY
std::chrono::seconds Duration(void) const
bool operator>(const HLSRecStream &b) const
std::chrono::seconds m_duration
QString toString(void) const
uint64_t Bitrate(void) const
HLSRecStream(int inputId, int seq, uint64_t bitrate, QString m3u8_url, QString segment_base_url)
bool operator<(const HLSRecStream &b) const
QQueue< int64_t > m_bandwidthSegs
uint64_t AverageBandwidth(void) const
QString ErrorString(void) const
bool DownloadURL(const QUrl &url, QByteArray *buffer, std::chrono::seconds timeout=30s, uint redirs=0, qint64 maxsize=0, QString *final_url=nullptr)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
std::array< uint8_t, AES128_KEY_SIZE > key