mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 11:21:52 +00:00
hls fmp4: support cbcs subsample encryption.
This commit is contained in:
parent
fd4cf76427
commit
62a544a3fd
4 changed files with 1273 additions and 18 deletions
|
@ -81,6 +81,7 @@ SrsInitMp4Segment::SrsInitMp4Segment()
|
|||
{
|
||||
fw_ = new SrsFileWriter();
|
||||
init_ = new SrsMp4M2tsInitEncoder();
|
||||
const_iv_size_ = 0;
|
||||
}
|
||||
|
||||
SrsInitMp4Segment::~SrsInitMp4Segment()
|
||||
|
@ -89,6 +90,20 @@ SrsInitMp4Segment::~SrsInitMp4Segment()
|
|||
srs_freep(fw_);
|
||||
}
|
||||
|
||||
srs_error_t SrsInitMp4Segment::config_cipher(unsigned char* kid, unsigned char* const_iv, uint8_t const_iv_size)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
if (const_iv_size != 8 && const_iv_size != 16) {
|
||||
return srs_error_new(ERROR_MP4_BOX_STRING, "invalidate const_iv_size");
|
||||
}
|
||||
memcpy(kid_, kid, 16);
|
||||
memcpy(const_iv_, const_iv, const_iv_size);
|
||||
const_iv_size_ = const_iv_size;
|
||||
init_->config_encryption(1, 9, kid_, const_iv, const_iv_size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsInitMp4Segment::write(SrsFormat* format, int v_tid, int a_tid)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
@ -153,16 +168,15 @@ srs_error_t SrsInitMp4Segment::init_encoder()
|
|||
}
|
||||
|
||||
|
||||
SrsHlsM4sSegment::SrsHlsM4sSegment()
|
||||
SrsHlsM4sSegment::SrsHlsM4sSegment(SrsFileWriter* fw)
|
||||
{
|
||||
fw_ = new SrsFileWriter();
|
||||
fw_ = fw;
|
||||
enc_ = new SrsFmp4SegmentEncoder();
|
||||
}
|
||||
|
||||
SrsHlsM4sSegment::~SrsHlsM4sSegment()
|
||||
{
|
||||
srs_freep(enc_);
|
||||
srs_freep(fw_);
|
||||
}
|
||||
|
||||
srs_error_t SrsHlsM4sSegment::initialize(int64_t time, uint32_t v_tid, uint32_t a_tid, int sequence_number, std::string m4s_path)
|
||||
|
@ -188,6 +202,13 @@ srs_error_t SrsHlsM4sSegment::initialize(int64_t time, uint32_t v_tid, uint32_t
|
|||
return err;
|
||||
}
|
||||
|
||||
void SrsHlsM4sSegment::config_cipher(unsigned char* key, unsigned char* iv)
|
||||
{
|
||||
// TODO: set key and iv to mp4 box
|
||||
enc_->config_cipher(key, iv);
|
||||
memcpy(this->iv, iv,16);
|
||||
}
|
||||
|
||||
srs_error_t SrsHlsM4sSegment::write(SrsSharedPtrMessage* shared_msg, SrsFormat* format)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
@ -229,8 +250,9 @@ srs_error_t SrsHlsM4sSegment::reap(uint64_t& dts)
|
|||
return srs_error_wrap(err, "Flush encoder failed");
|
||||
}
|
||||
|
||||
srs_freep(fw_);
|
||||
|
||||
// srs_freep(fw_);
|
||||
fw_->close();
|
||||
|
||||
if ((err = rename()) != srs_success) {
|
||||
return srs_error_wrap(err, "rename");
|
||||
}
|
||||
|
@ -492,6 +514,10 @@ srs_error_t SrsHlsFmp4Muxer::write_init_mp4(SrsFormat* format, bool has_video, b
|
|||
|
||||
init_mp4->set_path(path);
|
||||
|
||||
if (hls_keys_) {
|
||||
init_mp4->config_cipher(kid_, iv_, 16);
|
||||
}
|
||||
|
||||
if (has_video && has_audio) {
|
||||
if ((err = init_mp4->write(format, video_track_id_, audio_track_id_)) != srs_success) {
|
||||
return srs_error_wrap(err, "write hls init.mp4 with audio and video");
|
||||
|
@ -637,11 +663,7 @@ srs_error_t SrsHlsFmp4Muxer::update_config(SrsRequest* r)
|
|||
}
|
||||
}
|
||||
|
||||
if(hls_keys_) {
|
||||
writer_ = new SrsEncFileWriter();
|
||||
} else {
|
||||
writer_ = new SrsFileWriter();
|
||||
}
|
||||
writer_ = new SrsFileWriter();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -656,7 +678,7 @@ srs_error_t SrsHlsFmp4Muxer::segment_open(srs_utime_t basetime)
|
|||
}
|
||||
|
||||
// new segment.
|
||||
current_ = new SrsHlsM4sSegment();
|
||||
current_ = new SrsHlsM4sSegment(writer_);
|
||||
current_->sequence_no = sequence_no_++;
|
||||
|
||||
if ((err = write_hls_key()) != srs_success) {
|
||||
|
@ -831,7 +853,41 @@ srs_error_t SrsHlsFmp4Muxer::do_segment_close()
|
|||
|
||||
srs_error_t SrsHlsFmp4Muxer::write_hls_key()
|
||||
{
|
||||
return srs_success;
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (hls_keys_ && current_->sequence_no % hls_fragments_per_key_ == 0) {
|
||||
if (RAND_bytes(key_, 16) < 0) {
|
||||
return srs_error_wrap(err, "rand key failed.");
|
||||
}
|
||||
if (RAND_bytes(kid_, 16) < 0) {
|
||||
return srs_error_wrap(err, "rand kid failed.");
|
||||
}
|
||||
if (RAND_bytes(iv_, 16) < 0) {
|
||||
return srs_error_wrap(err, "rand iv failed.");
|
||||
}
|
||||
|
||||
string key_file = srs_path_build_stream(hls_key_file_, req_->vhost, req_->app, req_->stream);
|
||||
key_file = srs_string_replace(key_file, "[seq]", srs_int2str(current_->sequence_no));
|
||||
string key_url = hls_key_file_path_ + "/" + key_file;
|
||||
|
||||
SrsFileWriter fw;
|
||||
if ((err = fw.open(key_url)) != srs_success) {
|
||||
return srs_error_wrap(err, "open file %s", key_url.c_str());
|
||||
}
|
||||
|
||||
err = fw.write(key_, 16, NULL);
|
||||
fw.close();
|
||||
|
||||
if (err != srs_success) {
|
||||
return srs_error_wrap(err, "write key");
|
||||
}
|
||||
}
|
||||
|
||||
if (hls_keys_) {
|
||||
current_->config_cipher(key_, iv_);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHlsFmp4Muxer::refresh_m3u8()
|
||||
|
@ -917,7 +973,7 @@ srs_error_t SrsHlsFmp4Muxer::_refresh_m3u8(std::string m3u8_file)
|
|||
ss << "#EXT-X-DISCONTINUITY" << SRS_CONSTS_LF;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
if(hls_keys_ && ((segment->sequence_no % hls_fragments_per_key_) == 0)) {
|
||||
char hexiv[33];
|
||||
srs_data_to_hex(hexiv, segment->iv, 16);
|
||||
|
@ -932,7 +988,7 @@ srs_error_t SrsHlsFmp4Muxer::_refresh_m3u8(std::string m3u8_file)
|
|||
key_path = hls_key_url_ + key_file;
|
||||
}
|
||||
|
||||
ss << "#EXT-X-KEY:METHOD=AES-128,URI=" << "\"" << key_path << "\",IV=0x" << hexiv << SRS_CONSTS_LF;
|
||||
ss << "#EXT-X-KEY:METHOD=SAMPLE-AES,URI=" << "\"" << key_path << "\",IV=0x" << hexiv << SRS_CONSTS_LF;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
SrsHlsSegment(SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc, SrsFileWriter* w);
|
||||
virtual ~SrsHlsSegment();
|
||||
public:
|
||||
void config_cipher(unsigned char* key,unsigned char* iv);
|
||||
void config_cipher(unsigned char* key, unsigned char* iv);
|
||||
// replace the placeholder
|
||||
virtual srs_error_t rename();
|
||||
};
|
||||
|
@ -69,13 +69,18 @@ class SrsInitMp4Segment : public SrsFragment
|
|||
private:
|
||||
SrsFileWriter* fw_;
|
||||
SrsMp4M2tsInitEncoder* init_;
|
||||
|
||||
unsigned char kid_[16];
|
||||
unsigned char const_iv_[16];
|
||||
uint8_t const_iv_size_;
|
||||
|
||||
public:
|
||||
SrsInitMp4Segment();
|
||||
virtual ~SrsInitMp4Segment();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
virtual srs_error_t config_cipher(unsigned char* kid, unsigned char* const_iv, uint8_t const_iv_size);
|
||||
// Write the init mp4 file, with the v_tid(video track id) and a_tid (audio track id).
|
||||
virtual srs_error_t write(SrsFormat* format, int v_tid, int a_tid);
|
||||
|
||||
|
@ -83,7 +88,6 @@ public:
|
|||
virtual srs_error_t write_audio_only(SrsFormat* format, int a_tid);
|
||||
private:
|
||||
virtual srs_error_t init_encoder();
|
||||
|
||||
};
|
||||
|
||||
// TODO: merge this code with SrsFragmentedMp4 in dash
|
||||
|
@ -95,11 +99,14 @@ private:
|
|||
public:
|
||||
// sequence number in m3u8.
|
||||
int sequence_no;
|
||||
// Will be saved in m3u8 file.
|
||||
unsigned char iv[16];
|
||||
public:
|
||||
SrsHlsM4sSegment();
|
||||
SrsHlsM4sSegment(SrsFileWriter* fw);
|
||||
virtual ~SrsHlsM4sSegment();
|
||||
|
||||
virtual srs_error_t initialize(int64_t time, uint32_t v_tid, uint32_t a_tid, int sequence_number, std::string m4s_path);
|
||||
virtual void config_cipher(unsigned char* key, unsigned char* iv);
|
||||
virtual srs_error_t write(SrsSharedPtrMessage* shared_msg, SrsFormat* format);
|
||||
virtual srs_error_t reap(uint64_t& dts);
|
||||
};
|
||||
|
@ -305,6 +312,7 @@ private:
|
|||
std::string hls_key_url_;
|
||||
// The key and iv.
|
||||
unsigned char key_[16];
|
||||
unsigned char kid_[16];
|
||||
unsigned char iv_[16];
|
||||
// The underlayer file writer.
|
||||
SrsFileWriter* writer_;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <srs_kernel_buffer.hpp>
|
||||
#include <srs_core_deprecated.hpp>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
@ -4776,6 +4777,664 @@ stringstream& SrsMp4SegmentIndexBox::dumps_detail(stringstream& ss, SrsMp4DumpCo
|
|||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SampleAuxiliaryInfoSizeBox::SrsMp4SampleAuxiliaryInfoSizeBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeSAIZ;
|
||||
}
|
||||
|
||||
SrsMp4SampleAuxiliaryInfoSizeBox::~SrsMp4SampleAuxiliaryInfoSizeBox()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsMp4SampleAuxiliaryInfoSizeBox::nb_header()
|
||||
{
|
||||
int size = SrsMp4FullBox::nb_header();
|
||||
|
||||
if (flags & 0x01) {
|
||||
size += 8; // add sizeof(aux_info_type) + sizeof(aux_info_type_parameter);
|
||||
}
|
||||
|
||||
size += 1; // sizeof(default_sample_info_size);
|
||||
size += 4; // sizeof(sample_count);
|
||||
|
||||
if (default_sample_info_size == 0) {
|
||||
size += sample_info_sizes.size();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleAuxiliaryInfoSizeBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::encode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
|
||||
if (flags & 0x01) {
|
||||
buf->write_4bytes(aux_info_type);
|
||||
buf->write_4bytes(aux_info_type_parameter);
|
||||
}
|
||||
|
||||
buf->write_1bytes(default_sample_info_size);
|
||||
|
||||
if (default_sample_info_size == 0) {
|
||||
buf->write_4bytes(sample_info_sizes.size());
|
||||
vector<uint8_t>::iterator it;
|
||||
for (it = sample_info_sizes.begin(); it != sample_info_sizes.end(); ++it)
|
||||
{
|
||||
buf->write_1bytes(*it);
|
||||
}
|
||||
} else {
|
||||
buf->write_4bytes(sample_count);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleAuxiliaryInfoSizeBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::decode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "decode header");
|
||||
}
|
||||
|
||||
if (flags & 0x01) {
|
||||
aux_info_type = buf->read_4bytes();
|
||||
aux_info_type_parameter = buf->read_4bytes();
|
||||
}
|
||||
|
||||
default_sample_info_size = buf->read_1bytes();
|
||||
sample_count = buf->read_4bytes();
|
||||
|
||||
if (default_sample_info_size == 0) {
|
||||
for (int i = 0; i < sample_count; i++) {
|
||||
sample_info_sizes.push_back(buf->read_1bytes());
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4SampleAuxiliaryInfoSizeBox::dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
ss << "default_sample_info_size=" << default_sample_info_size << ", sample_count=" << sample_count;
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SampleAuxiliaryInfoOffsetBox::SrsMp4SampleAuxiliaryInfoOffsetBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeSAIO;
|
||||
}
|
||||
|
||||
SrsMp4SampleAuxiliaryInfoOffsetBox::~SrsMp4SampleAuxiliaryInfoOffsetBox()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsMp4SampleAuxiliaryInfoOffsetBox::nb_header()
|
||||
{
|
||||
int size = SrsMp4FullBox::nb_header();
|
||||
|
||||
if (flags & 0x01) {
|
||||
size += 8; // sizeof(aux_info_type) + sizeof(aux_info_type_parameter);
|
||||
}
|
||||
|
||||
size += 4; // sizeof(entry_count);
|
||||
if (version == 0) {
|
||||
size += offsets.size() * 4;
|
||||
} else {
|
||||
size += offsets.size() * 8;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleAuxiliaryInfoOffsetBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::encode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
|
||||
if (flags & 0x01) {
|
||||
buf->write_4bytes(aux_info_type);
|
||||
buf->write_4bytes(aux_info_type_parameter);
|
||||
}
|
||||
|
||||
buf->write_4bytes(offsets.size());
|
||||
vector<uint64_t>::iterator it;
|
||||
for (it = offsets.begin(); it != offsets.end(); ++it)
|
||||
{
|
||||
if (version == 0) {
|
||||
buf->write_4bytes(*it);
|
||||
} else {
|
||||
buf->write_8bytes(*it);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleAuxiliaryInfoOffsetBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::decode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "decode header");
|
||||
}
|
||||
|
||||
if (flags & 0x01) {
|
||||
aux_info_type = buf->read_4bytes();
|
||||
aux_info_type_parameter = buf->read_4bytes();
|
||||
}
|
||||
|
||||
uint32_t entry_count = buf->read_4bytes();
|
||||
for (int i = 0; i < entry_count; i++)
|
||||
{
|
||||
if (version == 0) {
|
||||
offsets.push_back(buf->read_4bytes());
|
||||
} else {
|
||||
offsets.push_back(buf->read_8bytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4SampleAuxiliaryInfoOffsetBox::dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
ss << "entry_count=" << offsets.size();
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SubSampleEncryptionInfo::SrsMp4SubSampleEncryptionInfo()
|
||||
{
|
||||
bytes_of_clear_data = 0;
|
||||
bytes_of_protected_data = 0;
|
||||
}
|
||||
|
||||
SrsMp4SubSampleEncryptionInfo::~SrsMp4SubSampleEncryptionInfo()
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t SrsMp4SubSampleEncryptionInfo::nb_bytes()
|
||||
{
|
||||
// sizeof(bytes_of_clear_data) + sizeof(bytes_of_protected_data);
|
||||
return 6;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SubSampleEncryptionInfo::encode(SrsBuffer* buf)
|
||||
{
|
||||
buf->write_2bytes(bytes_of_clear_data);
|
||||
buf->write_4bytes(bytes_of_protected_data);
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SubSampleEncryptionInfo::decode(SrsBuffer* buf)
|
||||
{
|
||||
bytes_of_clear_data = buf->read_2bytes();
|
||||
bytes_of_protected_data = buf->read_4bytes();
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4SubSampleEncryptionInfo::dumps(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
ss << "bytes_of_clear_data=" << bytes_of_clear_data << ", bytes_of_protected_data=" << bytes_of_protected_data;
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SampleEncryptionEntry::SrsMp4SampleEncryptionEntry(SrsMp4FullBox* senc, uint8_t per_sample_iv_size)
|
||||
{
|
||||
senc_ = senc;
|
||||
srs_assert(per_sample_iv_size == 0 || per_sample_iv_size == 8 || per_sample_iv_size == 16);
|
||||
per_sample_iv_size_ = per_sample_iv_size;
|
||||
iv_ = (uint8_t*) malloc(per_sample_iv_size);
|
||||
}
|
||||
|
||||
SrsMp4SampleEncryptionEntry::~SrsMp4SampleEncryptionEntry()
|
||||
{
|
||||
srs_freep(iv_);
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleEncryptionEntry::set_iv(uint8_t* iv, uint8_t iv_size)
|
||||
{
|
||||
srs_assert(iv_size == per_sample_iv_size_);
|
||||
memcpy(iv_, iv, iv_size);
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
uint64_t SrsMp4SampleEncryptionEntry::nb_bytes()
|
||||
{
|
||||
uint64_t size = per_sample_iv_size_;
|
||||
if (senc_->flags & SrsMp4CencSampleEncryptionUseSubSample) {
|
||||
size += 2; // size of subsample_count
|
||||
size += subsample_infos.size() * 6;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleEncryptionEntry::encode(SrsBuffer* buf)
|
||||
{
|
||||
if (per_sample_iv_size_ != 0) {
|
||||
buf->write_bytes((char*) iv_, per_sample_iv_size_);
|
||||
}
|
||||
|
||||
if (senc_->flags & SrsMp4CencSampleEncryptionUseSubSample) {
|
||||
buf->write_2bytes(subsample_infos.size());
|
||||
|
||||
vector<SrsMp4SubSampleEncryptionInfo>::iterator it;
|
||||
for (it = subsample_infos.begin(); it != subsample_infos.end(); ++it) {
|
||||
(*it).encode(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleEncryptionEntry::decode(SrsBuffer* buf)
|
||||
{
|
||||
if (per_sample_iv_size_ > 0) {
|
||||
buf->read_bytes((char*)iv_, per_sample_iv_size_);
|
||||
}
|
||||
|
||||
if (senc_->flags & SrsMp4CencSampleEncryptionUseSubSample) {
|
||||
uint16_t subsample_count = buf->read_2bytes();
|
||||
for (uint16_t i = 0; i < subsample_count; i++) {
|
||||
SrsMp4SubSampleEncryptionInfo info;
|
||||
info.decode(buf);
|
||||
subsample_infos.push_back(info);
|
||||
}
|
||||
}
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4SampleEncryptionEntry::dumps(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
// TODO: dump what?
|
||||
ss << "iv=" << iv_ << endl;
|
||||
|
||||
vector<SrsMp4SubSampleEncryptionInfo>::iterator it;
|
||||
for (it = subsample_infos.begin(); it != subsample_infos.end(); ++it) {
|
||||
(*it).dumps(ss, dc);
|
||||
ss << endl;
|
||||
}
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SampleEncryptionBox::SrsMp4SampleEncryptionBox(uint8_t per_sample_iv_size)
|
||||
{
|
||||
version = 0;
|
||||
flags = SrsMp4CencSampleEncryptionUseSubSample;
|
||||
type = SrsMp4BoxTypeSENC;
|
||||
srs_assert(per_sample_iv_size == 0 || per_sample_iv_size == 8 || per_sample_iv_size == 16);
|
||||
per_sample_iv_size_ = per_sample_iv_size;
|
||||
}
|
||||
|
||||
SrsMp4SampleEncryptionBox::~SrsMp4SampleEncryptionBox()
|
||||
{
|
||||
vector<SrsMp4SampleEncryptionEntry*>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); it++)
|
||||
{
|
||||
SrsMp4SampleEncryptionEntry* entry = *it;
|
||||
srs_freep(entry);
|
||||
}
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
int SrsMp4SampleEncryptionBox::nb_header()
|
||||
{
|
||||
int size = SrsMp4FullBox::nb_header() + 4;
|
||||
|
||||
vector<SrsMp4SampleEncryptionEntry*>::iterator it;
|
||||
for (it = entries.begin(); it < entries.end(); it++)
|
||||
{
|
||||
size += (*it)->nb_bytes();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleEncryptionBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::encode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
|
||||
buf->write_4bytes(entries.size());
|
||||
vector<SrsMp4SampleEncryptionEntry*>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); it++)
|
||||
{
|
||||
(*it)->encode(buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SampleEncryptionBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::decode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "decode header");
|
||||
}
|
||||
|
||||
vector<SrsMp4SampleEncryptionEntry*>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); it++)
|
||||
{
|
||||
SrsMp4SampleEncryptionEntry* entry = *it;
|
||||
srs_freep(entry);
|
||||
}
|
||||
entries.clear();
|
||||
|
||||
int32_t size = buf->read_4bytes();
|
||||
for (int i = 0; i < size; i++) {
|
||||
SrsMp4SampleEncryptionEntry *entry = new SrsMp4SampleEncryptionEntry(this, per_sample_iv_size_);
|
||||
entry->decode(buf);
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4SampleEncryptionBox::dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
ss << "sample_count=" << entries.size() << endl;
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4ProtectionSchemeInfoBox::SrsMp4ProtectionSchemeInfoBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeSINF;
|
||||
}
|
||||
|
||||
SrsMp4ProtectionSchemeInfoBox::~SrsMp4ProtectionSchemeInfoBox()
|
||||
{
|
||||
}
|
||||
|
||||
SrsMp4OriginalFormatBox* SrsMp4ProtectionSchemeInfoBox::frma()
|
||||
{
|
||||
SrsMp4Box* box = get(SrsMp4BoxTypeFRMA);
|
||||
return dynamic_cast<SrsMp4OriginalFormatBox*>(box);
|
||||
}
|
||||
|
||||
void SrsMp4ProtectionSchemeInfoBox::set_frma(SrsMp4OriginalFormatBox* v)
|
||||
{
|
||||
remove(SrsMp4BoxTypeFRMA);
|
||||
boxes.push_back(v);
|
||||
}
|
||||
|
||||
SrsMp4SchemeTypeBox* SrsMp4ProtectionSchemeInfoBox::schm()
|
||||
{
|
||||
SrsMp4Box* box = get(SrsMp4BoxTypeSCHM);
|
||||
return dynamic_cast<SrsMp4SchemeTypeBox*>(box);
|
||||
}
|
||||
|
||||
void SrsMp4ProtectionSchemeInfoBox::set_schm(SrsMp4SchemeTypeBox* v)
|
||||
{
|
||||
remove(SrsMp4BoxTypeSCHM);
|
||||
boxes.push_back(v);
|
||||
}
|
||||
|
||||
SrsMp4SchemeInfoBox* SrsMp4ProtectionSchemeInfoBox::schi()
|
||||
{
|
||||
SrsMp4Box* box = get(SrsMp4BoxTypeSCHI);
|
||||
return dynamic_cast<SrsMp4SchemeInfoBox*>(box);
|
||||
}
|
||||
|
||||
void SrsMp4ProtectionSchemeInfoBox::set_schi(SrsMp4SchemeInfoBox* v)
|
||||
{
|
||||
remove(SrsMp4BoxTypeSCHI);
|
||||
boxes.push_back(v);
|
||||
}
|
||||
|
||||
|
||||
SrsMp4OriginalFormatBox::SrsMp4OriginalFormatBox(uint32_t original_format)
|
||||
{
|
||||
type = SrsMp4BoxTypeFRMA;
|
||||
data_format_ = original_format;
|
||||
}
|
||||
|
||||
SrsMp4OriginalFormatBox::~SrsMp4OriginalFormatBox()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsMp4OriginalFormatBox::nb_header()
|
||||
{
|
||||
return SrsMp4Box::nb_header() + 4;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4OriginalFormatBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4Box::encode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
|
||||
buf->write_4bytes(data_format_);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4OriginalFormatBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4Box::decode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "decode header");
|
||||
}
|
||||
|
||||
data_format_ = buf->read_4bytes();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4OriginalFormatBox::dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
ss << "original format=" << data_format_ << endl;
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SchemeTypeBox::SrsMp4SchemeTypeBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeSCHM;
|
||||
}
|
||||
|
||||
SrsMp4SchemeTypeBox::~SrsMp4SchemeTypeBox()
|
||||
{
|
||||
}
|
||||
|
||||
void SrsMp4SchemeTypeBox::set_scheme_uri(char* uri, uint32_t uri_size)
|
||||
{
|
||||
srs_assert(uri_size < SCHM_SCHEME_URI_MAX_SIZE);
|
||||
memcpy(scheme_uri, uri, uri_size);
|
||||
scheme_uri_size = uri_size;
|
||||
scheme_uri[uri_size] = '\0';
|
||||
}
|
||||
|
||||
int SrsMp4SchemeTypeBox::nb_header()
|
||||
{
|
||||
int size = SrsMp4FullBox::nb_header() + 4 + 4; // sizeof(scheme_type) + sizeof(scheme_version)
|
||||
|
||||
if (flags & 0x01) {
|
||||
size += scheme_uri_size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SchemeTypeBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::encode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
|
||||
buf->write_4bytes(scheme_type);
|
||||
buf->write_4bytes(scheme_version);
|
||||
|
||||
if (flags & 0x01) {
|
||||
buf->write_bytes(scheme_uri, scheme_uri_size);
|
||||
buf->write_1bytes(0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SchemeTypeBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::decode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
scheme_type = buf->read_4bytes();
|
||||
scheme_version = buf->read_4bytes();
|
||||
|
||||
if (flags & 0x01) {
|
||||
memset(scheme_uri, 0, SCHM_SCHEME_URI_MAX_SIZE);
|
||||
int s = 0;
|
||||
while (s < SCHM_SCHEME_URI_MAX_SIZE-1) {
|
||||
char c = buf->read_1bytes();
|
||||
scheme_uri[s] = c;
|
||||
s++;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
scheme_uri_size = s;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4SchemeTypeBox::dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
ss << "scheme_type=" << scheme_type << ", scheme_version=" << scheme_version << endl;
|
||||
if (flags & 0x01) {
|
||||
ss << "scheme_uri=" << scheme_uri << endl;
|
||||
}
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SchemeInfoBox::SrsMp4SchemeInfoBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeSCHI;
|
||||
}
|
||||
|
||||
SrsMp4SchemeInfoBox::~SrsMp4SchemeInfoBox()
|
||||
{
|
||||
}
|
||||
|
||||
SrsMp4TrackEncryptionBox::SrsMp4TrackEncryptionBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeTENC;
|
||||
}
|
||||
|
||||
SrsMp4TrackEncryptionBox::~SrsMp4TrackEncryptionBox()
|
||||
{
|
||||
}
|
||||
|
||||
void SrsMp4TrackEncryptionBox::set_default_constant_IV(uint8_t* iv, uint8_t iv_size)
|
||||
{
|
||||
srs_assert(iv_size == 8 || iv_size == 16);
|
||||
memcpy(default_constant_IV, iv, iv_size);
|
||||
default_constant_IV_size = iv_size;
|
||||
}
|
||||
|
||||
int SrsMp4TrackEncryptionBox::nb_header()
|
||||
{
|
||||
int size = SrsMp4FullBox::nb_header();
|
||||
size += 1; // sizeof(reserved)
|
||||
size += 1; // sizeof(reserved_2) or sizeof(default_crypt_byte_block) + sizeof(default_skip_byte_block);
|
||||
size += 1; // sizeof(default_isProtected);
|
||||
size += 1; // sizeof(default_Per_Sample_IV_Size;
|
||||
size += 16; // sizeof(default_KID);
|
||||
if (default_is_protected == 1 && default_per_sample_IV_size == 0) {
|
||||
size += 1 + default_constant_IV_size; // sizeof(default_constant_IV_size) + sizeof(default_constant_IV);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4TrackEncryptionBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::encode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
|
||||
buf->write_1bytes(reserved);
|
||||
if (version == 0) {
|
||||
buf->write_1bytes(reserved_2);
|
||||
} else {
|
||||
buf->write_1bytes( (default_crypt_byte_block << 4) | (default_skip_byte_block & 0x0F));
|
||||
}
|
||||
|
||||
buf->write_1bytes(default_is_protected);
|
||||
buf->write_1bytes(default_per_sample_IV_size);
|
||||
buf->write_bytes((char*)default_KID, 16);
|
||||
if (default_is_protected == 1 && default_per_sample_IV_size == 0) {
|
||||
buf->write_1bytes(default_constant_IV_size);
|
||||
buf->write_bytes((char*)default_constant_IV, default_constant_IV_size);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4TrackEncryptionBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4FullBox::decode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
reserved = buf->read_1bytes();
|
||||
if (version == 0) {
|
||||
reserved_2 = buf->read_1bytes();
|
||||
} else {
|
||||
uint8_t v = buf->read_1bytes();
|
||||
default_crypt_byte_block = v >> 4;
|
||||
default_skip_byte_block = v & 0x0f;
|
||||
}
|
||||
|
||||
default_is_protected = buf->read_1bytes();
|
||||
default_per_sample_IV_size = buf->read_1bytes();
|
||||
buf->read_bytes((char*)default_KID, 16);
|
||||
|
||||
if (default_is_protected == 1 && default_per_sample_IV_size == 0) {
|
||||
default_constant_IV_size = buf->read_1bytes();
|
||||
srs_assert(default_constant_IV_size == 8 || default_constant_IV_size == 16);
|
||||
buf->read_bytes((char*) default_constant_IV, default_constant_IV_size);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
std::stringstream& SrsMp4TrackEncryptionBox::dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
if (version != 0) {
|
||||
ss << "default_crypt_byte_block=" << default_crypt_byte_block << ", default_skip_byte_block=" << default_skip_byte_block << endl;
|
||||
}
|
||||
ss << "default_isProtected=" << default_is_protected << ", default_per_sample_IV_size=" << default_per_sample_IV_size << endl;
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4Sample::SrsMp4Sample()
|
||||
{
|
||||
type = SrsFrameTypeForbidden;
|
||||
|
@ -6177,6 +6836,10 @@ SrsMp4ObjectType SrsMp4Encoder::get_audio_object_type()
|
|||
SrsMp4M2tsInitEncoder::SrsMp4M2tsInitEncoder()
|
||||
{
|
||||
writer = NULL;
|
||||
crypt_byte_block_ = 0;
|
||||
skip_byte_block_ = 0;
|
||||
iv_size_ = 0;
|
||||
is_protected_ = false;
|
||||
}
|
||||
|
||||
SrsMp4M2tsInitEncoder::~SrsMp4M2tsInitEncoder()
|
||||
|
@ -6189,6 +6852,18 @@ srs_error_t SrsMp4M2tsInitEncoder::initialize(ISrsWriter* w)
|
|||
return srs_success;
|
||||
}
|
||||
|
||||
void SrsMp4M2tsInitEncoder::config_encryption(uint8_t crypt_byte_block, uint8_t skip_byte_block, unsigned char* kid, unsigned char* iv, uint8_t iv_size)
|
||||
{
|
||||
srs_assert(crypt_byte_block + skip_byte_block == 10);
|
||||
srs_assert(iv_size == 8 || iv_size == 16);
|
||||
crypt_byte_block_ = crypt_byte_block;
|
||||
skip_byte_block_ = skip_byte_block;
|
||||
memcpy(kid_, kid, 16);
|
||||
memcpy(iv_, iv, iv_size);
|
||||
iv_size_ = iv_size;
|
||||
is_protected_ = true;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
@ -6280,6 +6955,10 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
|||
avc1->set_avcC(avcC);
|
||||
|
||||
avcC->avc_config = format->vcodec->avc_extra_data;
|
||||
|
||||
if (is_protected_ && ((err = config_sample_description_encryption(avc1)) != srs_success)) {
|
||||
return srs_error_wrap(err, "encrypt avc1 box");
|
||||
}
|
||||
} else {
|
||||
SrsMp4VisualSampleEntry* hev1 = new SrsMp4VisualSampleEntry(SrsMp4BoxTypeHEV1);
|
||||
stsd->append(hev1);
|
||||
|
@ -6292,6 +6971,10 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
|||
hev1->set_hvcC(hvcC);
|
||||
|
||||
hvcC->hevc_config = format->vcodec->avc_extra_data;
|
||||
|
||||
if (is_protected_ && ((err = config_sample_description_encryption(hev1)) != srs_success)) {
|
||||
return srs_error_wrap(err, "encrypt hev1 box");
|
||||
}
|
||||
}
|
||||
|
||||
SrsMp4DecodingTime2SampleBox* stts = new SrsMp4DecodingTime2SampleBox();
|
||||
|
@ -6382,6 +7065,10 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
|||
|
||||
SrsMp4EsdsBox* esds = new SrsMp4EsdsBox();
|
||||
mp4a->set_esds(esds);
|
||||
|
||||
if (is_protected_ && ((err = config_sample_description_encryption(mp4a)) != srs_success)) {
|
||||
return srs_error_wrap(err, "encrypt mp4a box");
|
||||
}
|
||||
|
||||
SrsMp4ES_Descriptor* es = esds->es;
|
||||
es->ES_ID = 0x02;
|
||||
|
@ -6518,6 +7205,10 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, int v_tid, int a_tid
|
|||
avc1->set_avcC(avcC);
|
||||
|
||||
avcC->avc_config = format->vcodec->avc_extra_data;
|
||||
|
||||
if (is_protected_ && ((err = config_sample_description_encryption(avc1)) != srs_success)) {
|
||||
return srs_error_wrap(err, "encrypt avc1 box");
|
||||
}
|
||||
} else {
|
||||
SrsMp4VisualSampleEntry* hev1 = new SrsMp4VisualSampleEntry(SrsMp4BoxTypeHEV1);
|
||||
stsd->append(hev1);
|
||||
|
@ -6530,6 +7221,10 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, int v_tid, int a_tid
|
|||
hev1->set_hvcC(hvcC);
|
||||
|
||||
hvcC->hevc_config = format->vcodec->avc_extra_data;
|
||||
|
||||
if (is_protected_ && ((err = config_sample_description_encryption(hev1)) != srs_success)) {
|
||||
return srs_error_wrap(err, "encrypt hev1 box");
|
||||
}
|
||||
}
|
||||
|
||||
SrsMp4DecodingTime2SampleBox* stts = new SrsMp4DecodingTime2SampleBox();
|
||||
|
@ -6614,6 +7309,9 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, int v_tid, int a_tid
|
|||
|
||||
SrsMp4EsdsBox* esds = new SrsMp4EsdsBox();
|
||||
mp4a->set_esds(esds);
|
||||
if (is_protected_ && ((err = config_sample_description_encryption(mp4a)) != srs_success)) {
|
||||
return srs_error_wrap(err, "encrypt mp4a box.");
|
||||
}
|
||||
|
||||
SrsMp4ES_Descriptor* es = esds->es;
|
||||
es->ES_ID = 0x02;
|
||||
|
@ -6672,6 +7370,60 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, int v_tid, int a_tid
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* box->type = 'encv' or 'enca'
|
||||
* |encv|
|
||||
* | |sinf|
|
||||
* | | |frma|
|
||||
* | | |schm|
|
||||
* | | |schi|
|
||||
* | | | |tenc|
|
||||
*/
|
||||
srs_error_t SrsMp4M2tsInitEncoder::config_sample_description_encryption(SrsMp4SampleEntry* box)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
bool is_video_sample = false;
|
||||
SrsMp4BoxType original_type = box->type;
|
||||
|
||||
if (original_type == SrsMp4BoxTypeAVC1 || original_type == SrsMp4BoxTypeHEV1)
|
||||
{
|
||||
box->type = SrsMp4BoxTypeENCV;
|
||||
is_video_sample = true;
|
||||
} else if (original_type == SrsMp4BoxTypeMP4A) {
|
||||
box->type = SrsMp4BoxTypeENCA;
|
||||
} else {
|
||||
return srs_error_new(ERROR_MP4_BOX_ILLEGAL_TYPE, "unknown sample type 0x%x to encrypt", original_type);
|
||||
}
|
||||
|
||||
SrsMp4ProtectionSchemeInfoBox* sinf = new SrsMp4ProtectionSchemeInfoBox();
|
||||
box->append(sinf);
|
||||
|
||||
SrsMp4OriginalFormatBox* frma = new SrsMp4OriginalFormatBox(original_type);
|
||||
sinf->set_frma(frma);
|
||||
|
||||
SrsMp4SchemeTypeBox* schm = new SrsMp4SchemeTypeBox();
|
||||
schm->scheme_type = SrsMp4CENSchemeCBCS;
|
||||
schm->scheme_version = 0x00010000;
|
||||
sinf->set_schm(schm);
|
||||
|
||||
SrsMp4SchemeInfoBox* schi = new SrsMp4SchemeInfoBox();
|
||||
SrsMp4TrackEncryptionBox* tenc = new SrsMp4TrackEncryptionBox();
|
||||
tenc->version = 1;
|
||||
tenc->default_crypt_byte_block = is_video_sample ? crypt_byte_block_ : 0 ;
|
||||
tenc->default_skip_byte_block = is_video_sample ? skip_byte_block_ : 0;
|
||||
tenc->default_is_protected = 1;
|
||||
tenc->default_per_sample_IV_size = 0;
|
||||
tenc->default_constant_IV_size = iv_size_;
|
||||
memcpy(tenc->default_constant_IV, iv_, iv_size_);
|
||||
memcpy(tenc->default_KID, kid_, 16);
|
||||
|
||||
schi->append(tenc);
|
||||
sinf->set_schi(schi);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
|
||||
{
|
||||
writer = NULL;
|
||||
|
@ -6879,12 +7631,19 @@ SrsFmp4SegmentEncoder::SrsFmp4SegmentEncoder()
|
|||
mdat_video_bytes_ = 0;
|
||||
audio_samples_ = new SrsMp4SampleManager();
|
||||
video_samples_ = new SrsMp4SampleManager();
|
||||
|
||||
memset(iv_,0,16);
|
||||
key_ = (unsigned char*)new AES_KEY();
|
||||
do_sample_encryption_ = false;
|
||||
}
|
||||
|
||||
SrsFmp4SegmentEncoder::~SrsFmp4SegmentEncoder()
|
||||
{
|
||||
srs_freep(audio_samples_);
|
||||
srs_freep(video_samples_);
|
||||
|
||||
AES_KEY* k = (AES_KEY*)key_;
|
||||
srs_freep(k);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6901,6 +7660,21 @@ srs_error_t SrsFmp4SegmentEncoder::initialize(ISrsWriter* w, uint32_t sequence,
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsFmp4SegmentEncoder::config_cipher(unsigned char* key, unsigned char* iv)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
memcpy(this->iv_, iv, 16);
|
||||
|
||||
AES_KEY* k = (AES_KEY*)this->key_;
|
||||
if (AES_set_encrypt_key(key, 16 * 8, k)) {
|
||||
return srs_error_new(ERROR_SYSTEM_FILE_WRITE, "set aes key failed");
|
||||
}
|
||||
do_sample_encryption_ = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsFmp4SegmentEncoder::write_sample(SrsMp4HandlerType ht, uint16_t ft,
|
||||
uint32_t dts, uint32_t pts, uint8_t* sample, uint32_t nb_sample)
|
||||
{
|
||||
|
@ -6982,6 +7756,22 @@ srs_error_t SrsFmp4SegmentEncoder::flush(uint64_t& dts)
|
|||
if ((err = video_samples_->write(traf, dts)) != srs_success) {
|
||||
return srs_error_wrap(err, "write samples");
|
||||
}
|
||||
|
||||
// TODO: write senc, and optional saiz & saio
|
||||
if (do_sample_encryption_) {
|
||||
SrsMp4SampleEncryptionBox* senc = new SrsMp4SampleEncryptionBox(0);
|
||||
// video_samples_;
|
||||
vector<SrsMp4Sample*>::iterator it;
|
||||
// write video sample data
|
||||
for (it = video_samples_->samples.begin(); it != video_samples_->samples.end(); ++it) {
|
||||
SrsMp4Sample* sample = *it;
|
||||
// TODO: parse hevc|avc, nalu slice header, and calculate
|
||||
// sample->data;
|
||||
// sample->nb_data;
|
||||
}
|
||||
|
||||
traf->append(senc);
|
||||
}
|
||||
}
|
||||
|
||||
// write audio traf
|
||||
|
@ -7009,6 +7799,13 @@ srs_error_t SrsFmp4SegmentEncoder::flush(uint64_t& dts)
|
|||
if ((err = audio_samples_->write(traf, dts)) != srs_success) {
|
||||
return srs_error_wrap(err, "write samples");
|
||||
}
|
||||
|
||||
// TODO: write senc, and optional saiz & saio
|
||||
if (do_sample_encryption_) {
|
||||
SrsMp4SampleEncryptionBox* senc = new SrsMp4SampleEncryptionBox(0);
|
||||
// this->iv_;
|
||||
traf->append(senc);
|
||||
}
|
||||
}
|
||||
|
||||
// @remark Remember the data_offset of turn is size(moof)+header(mdat)
|
||||
|
@ -7051,6 +7848,7 @@ srs_error_t SrsFmp4SegmentEncoder::flush(uint64_t& dts)
|
|||
SrsMp4Sample* sample = *it;
|
||||
|
||||
// TODO: FIXME: Ensure all bytes are writen.
|
||||
// TODO: do cbcs encryption here. sample are nalu_length + nalu data.
|
||||
if ((err = writer_->write(sample->data, sample->nb_data, NULL)) != srs_success) {
|
||||
return srs_error_wrap(err, "write sample");
|
||||
}
|
||||
|
@ -7061,6 +7859,7 @@ srs_error_t SrsFmp4SegmentEncoder::flush(uint64_t& dts)
|
|||
SrsMp4Sample* sample = *it;
|
||||
|
||||
// TODO: FIXME: Ensure all bytes are writen.
|
||||
// TODO: do cbcs encryption here
|
||||
if ((err = writer_->write(sample->data, sample->nb_data, NULL)) != srs_success) {
|
||||
return srs_error_wrap(err, "write sample");
|
||||
}
|
||||
|
|
|
@ -113,6 +113,27 @@ enum SrsMp4BoxType
|
|||
SrsMp4BoxTypeSIDX = 0x73696478, // 'sidx'
|
||||
SrsMp4BoxTypeHEV1 = 0x68657631, // 'hev1'
|
||||
SrsMp4BoxTypeHVCC = 0x68766343, // 'hvcC'
|
||||
SrsMp4BoxTypeSENC = 0x73656e63, // 'senc'
|
||||
SrsMp4BoxTypeSAIZ = 0x7361697a, // 'saiz'
|
||||
SrsMp4BoxTypeSAIO = 0x7361696f, // 'saio'
|
||||
SrsMp4BoxTypeENCV = 0x656e6376, // 'encv'
|
||||
SrsMp4BoxTypeENCA = 0x656e6361, // 'enca'
|
||||
SrsMp4BoxTypeSINF = 0x73696e66, // 'sinf'
|
||||
SrsMp4BoxTypeSCHI = 0x73636869, // 'schi'
|
||||
SrsMp4BoxTypeTENC = 0x74656e63, // 'tenc'
|
||||
SrsMp4BoxTypeFRMA = 0x66726d61, // 'frma'
|
||||
SrsMp4BoxTypeSCHM = 0x7363686d, // 'schm'
|
||||
};
|
||||
|
||||
// Common encryption scheme types
|
||||
// @see ISO-IEC-23001-7.pdf, 4.2
|
||||
enum SrsMp4CENSchemeType
|
||||
{
|
||||
SrsMp4CENSchemeCENC = 0x63656e63, // 'cenc'
|
||||
SrsMp4CENSchemeCBC1 = 0x63626331, // 'cbc1'
|
||||
SrsMp4CENSchemeCENS = 0x63656e73, // 'cens'
|
||||
SrsMp4CENSchemeCBCS = 0x63626373, // 'cbcs'
|
||||
SrsMp4CENSchemeSVE1 = 0x73766531, // 'sve1'
|
||||
};
|
||||
|
||||
// 8.4.3.3 Semantics
|
||||
|
@ -1868,6 +1889,348 @@ public:
|
|||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// Sample auxiliary information sizes box (saiz)
|
||||
// @see ISO_IEC_14496-12-base-format-2012.pdf, 8.7.8, page 62
|
||||
// @see https://github.com/gpac/mp4box.js/blob/master/src/parsing/saiz.js
|
||||
// Syntax
|
||||
// aligned(8) class SampleAuxiliaryInformationSizesBox extends FullBox('saiz', version=0, flags)
|
||||
// {
|
||||
// if (flags & 1) {
|
||||
// unsigned int(32) aux_info_type;
|
||||
// unsigned int(32) aux_info_type_parameter;
|
||||
// }
|
||||
// unsigned int(8) default_sample_info_size;
|
||||
// unsigned int(32) sample_count;
|
||||
// if (default_sample_info_size == 0) {
|
||||
// unsigned int(8) sample_info_size[sample_count];
|
||||
// }
|
||||
// }
|
||||
class SrsMp4SampleAuxiliaryInfoSizeBox: public SrsMp4FullBox
|
||||
{
|
||||
public:
|
||||
uint32_t aux_info_type;
|
||||
uint32_t aux_info_type_parameter;
|
||||
|
||||
uint8_t default_sample_info_size;
|
||||
uint32_t sample_count;
|
||||
std::vector<uint8_t> sample_info_sizes;
|
||||
|
||||
public:
|
||||
SrsMp4SampleAuxiliaryInfoSizeBox();
|
||||
virtual ~SrsMp4SampleAuxiliaryInfoSizeBox();
|
||||
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual srs_error_t encode_header(SrsBuffer* buf);
|
||||
virtual srs_error_t decode_header(SrsBuffer* buf);
|
||||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// Sample auxiliary information offsets box (saio)
|
||||
// @see ISO_IEC_14496-12-base-format-2012.pdf, 8.7.9, page 63
|
||||
// @see https://github.com/gpac/mp4box.js/blob/master/src/parsing/saio.js
|
||||
// Syntax
|
||||
// aligned(8) class SampleAuxiliaryInformationOffsetsBox extends FullBox('saio', version, flags)
|
||||
// {
|
||||
// if (flags & 1) {
|
||||
// unsigned int(32) aux_info_type;
|
||||
// unsigned int(32) aux_info_type_parameter;
|
||||
// }
|
||||
// unsigned int(32) entry_count;
|
||||
// if (version == 0) {
|
||||
// unsigned int(32) offset[entry_count];
|
||||
// } else {
|
||||
// unsigned int(64) offset[entry_count];
|
||||
// }
|
||||
// }
|
||||
class SrsMp4SampleAuxiliaryInfoOffsetBox: public SrsMp4FullBox
|
||||
{
|
||||
public:
|
||||
uint32_t aux_info_type;
|
||||
uint32_t aux_info_type_parameter;
|
||||
// uint32_t entry_count;
|
||||
std::vector<uint64_t> offsets;
|
||||
|
||||
public:
|
||||
SrsMp4SampleAuxiliaryInfoOffsetBox();
|
||||
virtual ~SrsMp4SampleAuxiliaryInfoOffsetBox();
|
||||
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual srs_error_t encode_header(SrsBuffer* buf);
|
||||
virtual srs_error_t decode_header(SrsBuffer* buf);
|
||||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
enum SrsMp4CencSampleEncryptionFlags
|
||||
{
|
||||
SrsMp4CencSampleEncryptionTrackDefault = 0x01,
|
||||
SrsMp4CencSampleEncryptionUseSubSample = 0x02,
|
||||
};
|
||||
|
||||
struct SrsMp4SubSampleEncryptionInfo : public ISrsCodec
|
||||
{
|
||||
uint16_t bytes_of_clear_data;
|
||||
uint32_t bytes_of_protected_data;
|
||||
|
||||
SrsMp4SubSampleEncryptionInfo();
|
||||
virtual ~SrsMp4SubSampleEncryptionInfo();
|
||||
|
||||
virtual uint64_t nb_bytes();
|
||||
virtual srs_error_t encode(SrsBuffer* buf);
|
||||
virtual srs_error_t decode(SrsBuffer* buf);
|
||||
|
||||
virtual std::stringstream& dumps(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
class SrsMp4SampleEncryptionEntry : public ISrsCodec
|
||||
{
|
||||
public:
|
||||
// if flags && 0x02
|
||||
std::vector<SrsMp4SubSampleEncryptionInfo> subsample_infos;
|
||||
|
||||
public:
|
||||
SrsMp4SampleEncryptionEntry(SrsMp4FullBox* senc, uint8_t per_sample_iv_size);
|
||||
virtual ~SrsMp4SampleEncryptionEntry();
|
||||
|
||||
virtual srs_error_t set_iv(uint8_t* iv, uint8_t iv_size);
|
||||
virtual uint64_t nb_bytes();
|
||||
virtual srs_error_t encode(SrsBuffer* buf);
|
||||
virtual srs_error_t decode(SrsBuffer* buf);
|
||||
|
||||
virtual std::stringstream& dumps(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
|
||||
private:
|
||||
SrsMp4FullBox* senc_;
|
||||
uint8_t per_sample_iv_size_;
|
||||
uint8_t* iv_;
|
||||
};
|
||||
|
||||
// Sample encryption box (senc)
|
||||
// @see ISO-IEC-23001-7.pdf 7.2.1
|
||||
// @see https://cdn.standards.iteh.ai/samples/84637/c960c91d60ae4da7a2f9380bd7e08642/ISO-IEC-FDIS-23001-7.pdf
|
||||
// CENC SAI: sample auxiliary information associated with a sample and containing cryptographic information
|
||||
// such as initialization vector or subsample information
|
||||
// @see ISO-IEC-23001-7.pdf 7.2.2
|
||||
// Syntax
|
||||
// aligned(8) class SampleEncryptionBox extend FullBox(`senc`, version=0, flags)
|
||||
// {
|
||||
// unsigned int(32) sample_count;
|
||||
// {
|
||||
// unsigned int(Per_Sample_IV_Size*8) InitializationVector;
|
||||
// if (flags & 0x000002)
|
||||
// {
|
||||
// unsigned int(16) subsample_count;
|
||||
// {
|
||||
// unsigned int(16) BytesOfClearData;
|
||||
// unsigned int(32) BytesOfProtectedData;
|
||||
// } [ subsample_count ]
|
||||
// }
|
||||
// } [ sample_count ]
|
||||
// }
|
||||
class SrsMp4SampleEncryptionBox: public SrsMp4FullBox
|
||||
{
|
||||
public:
|
||||
std::vector<SrsMp4SampleEncryptionEntry*> entries;
|
||||
|
||||
private:
|
||||
uint8_t per_sample_iv_size_;
|
||||
|
||||
public:
|
||||
// @see ISO-IEC-23001-7.pdf 9.1
|
||||
// Per_Sample_IV_Size has supported values: 0, 8, 16.
|
||||
SrsMp4SampleEncryptionBox(uint8_t per_sample_iv_size);
|
||||
virtual ~SrsMp4SampleEncryptionBox();
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual srs_error_t encode_header(SrsBuffer* buf);
|
||||
virtual srs_error_t decode_header(SrsBuffer* buf);
|
||||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// Original Format Box (frma)
|
||||
// @see ISO_IEC_14496-12-base-format-2012.pdf, 8.12.2, page 81
|
||||
// aligned(8) class OriginalFormatBox(codingname) extends Box ('frma') {
|
||||
// unsigned int(32) data_format = codingname;
|
||||
// }
|
||||
class SrsMp4OriginalFormatBox : public SrsMp4Box
|
||||
{
|
||||
private:
|
||||
uint32_t data_format_;
|
||||
|
||||
public:
|
||||
SrsMp4OriginalFormatBox(uint32_t original_format);
|
||||
virtual ~SrsMp4OriginalFormatBox();
|
||||
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual srs_error_t encode_header(SrsBuffer* buf);
|
||||
virtual srs_error_t decode_header(SrsBuffer* buf);
|
||||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// Scheme Type Box (schm)
|
||||
// @see ISO_IEC_14496-12-base-format-2012.pdf, 8.12.5, page 81
|
||||
// aligned(8) class SchemeTypeBox extends FullBox('schm', 0, flags) {
|
||||
// unsigned int(32) scheme_type; // 4CC identifying the scheme
|
||||
// unsigned int(32) scheme_version; // scheme version
|
||||
// if (flags & 0x000001) {
|
||||
// unsigned int(8) scheme_uri[]; // browser uri
|
||||
// }
|
||||
// }
|
||||
// @see @see ISO-IEC-23001-7.pdf 4.1
|
||||
// the scheme_version field SHALL be set to 0x00010000 (Major version 1, Minor version 0).
|
||||
#define SCHM_SCHEME_URI_MAX_SIZE 128
|
||||
class SrsMp4SchemeTypeBox : public SrsMp4FullBox
|
||||
{
|
||||
public:
|
||||
uint32_t scheme_type;
|
||||
uint32_t scheme_version;
|
||||
char scheme_uri[SCHM_SCHEME_URI_MAX_SIZE];
|
||||
uint32_t scheme_uri_size;
|
||||
|
||||
public:
|
||||
SrsMp4SchemeTypeBox();
|
||||
virtual ~SrsMp4SchemeTypeBox();
|
||||
|
||||
public:
|
||||
virtual void set_scheme_uri(char* uri, uint32_t uri_size);
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual srs_error_t encode_header(SrsBuffer* buf);
|
||||
virtual srs_error_t decode_header(SrsBuffer* buf);
|
||||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// Scheme Information Box (schi)
|
||||
// @see ISO_IEC_14496-12-base-format-2012.pdf, 8.12.6, page 82
|
||||
// aligned(8) class SchemeInformationBox extends Box('schi') {
|
||||
// Box scheme_specific_data[];
|
||||
// }
|
||||
class SrsMp4SchemeInfoBox : public SrsMp4Box
|
||||
{
|
||||
public:
|
||||
SrsMp4SchemeInfoBox();
|
||||
virtual ~SrsMp4SchemeInfoBox();
|
||||
};
|
||||
|
||||
// Protection Scheme Information Box (sinf)
|
||||
// @see ISO_IEC_14496-12-base-format-2012.pdf, 8.12.1, page 80
|
||||
// aligned(8) class ProtectionSchemeInfoBox(fmt) extends Box('sinf') {
|
||||
// OriginalFormatBox(fmt) original_format; // frma
|
||||
// SchemeTypeBox scheme_type_box; // optional
|
||||
// SchemeInformationBox info; // optional
|
||||
// }
|
||||
class SrsMp4ProtectionSchemeInfoBox : public SrsMp4Box
|
||||
{
|
||||
public:
|
||||
SrsMp4ProtectionSchemeInfoBox();
|
||||
virtual ~SrsMp4ProtectionSchemeInfoBox();
|
||||
|
||||
public:
|
||||
// Get the Original Format Box (frma)
|
||||
virtual SrsMp4OriginalFormatBox* frma();
|
||||
virtual void set_frma(SrsMp4OriginalFormatBox* v);
|
||||
// Get the Scheme Type Box (schm)
|
||||
virtual SrsMp4SchemeTypeBox* schm();
|
||||
virtual void set_schm(SrsMp4SchemeTypeBox* v);
|
||||
// Get the Scheme Information Box (schi)
|
||||
virtual SrsMp4SchemeInfoBox* schi();
|
||||
virtual void set_schi(SrsMp4SchemeInfoBox* v);
|
||||
};
|
||||
|
||||
// Track Encryption box (tenc)
|
||||
// @see ISO-IEC-23001-7.pdf 8.2
|
||||
// aligned(8) class TrackEncryptionBox extends FullBox('tenc', version, flags=0) {
|
||||
// unsigned int(8) reserved = 0;
|
||||
// if (version == 0) {
|
||||
// unsigned int(8) reserved = 0;
|
||||
// } else { // version is 1 or greater
|
||||
// unsigned int(4) default_crypt_byte_block;
|
||||
// unsigned int(4) default_skip_byte_block;
|
||||
// }
|
||||
// unsigned int(8) default_isProtected;
|
||||
// unsigned int(8) default_Per_Sample_IV_Size;
|
||||
// unsigned int(8)[16] default_KID;
|
||||
// if (default_isProtected == 1 && default_Per_Sample_IV_Size == 0) {
|
||||
// unsigned int(8) default_constant_IV_size;
|
||||
// unsigned int(8)[default_constant_IV_size] default_constant_IV;
|
||||
// }
|
||||
// }
|
||||
// @see https://developer.apple.com/documentation/http-live-streaming/about-the-common-media-application-format-with-http-live-streaming-hls
|
||||
// For fragmented MPEG-4 Segments, an EXT-X-KEY tag with a METHOD=SAMPLE-AES attribute indicates that
|
||||
// the Segment is encrypted using the `cbcs` scheme in ISO/IEC 23001-7.
|
||||
// HLS supports unencrypted and encrypted with 'cbcs'.
|
||||
// @see ISO-IEC-23001-7.pdf 10.4.1 Definition
|
||||
// 'cbcs' AES-CBC subsample pattern encryption scheme.
|
||||
// The 'scheme_type' field of the scheme Type Box('schm') SHALL be set to 'cbcs'.
|
||||
// the version of the Track Encryption Box('tenc') SHALL be 1.
|
||||
// Encrypted video tracks using NAL Structured Video conforming to ISO/IEC 14496-15 SHALL be
|
||||
// protected using Subsample encryption specified in 9.5, and SHALL use pattern encryption as specified
|
||||
// in 9.6. As a result, the fields crypt_byte_block and skip_byte_block SHALL NOT be 0.
|
||||
// Constant IVs SHALL be used; 'default_Per_Sample_IV_Size' and 'Per_Sample_IV_Size', SHALL be 0.
|
||||
// Tracks other than video are protected using whole-block full-sample encryption as specified in 9.7 and
|
||||
// hence skip_byte_block SHALL be 0.
|
||||
// Pattern Block length, i.e. crypt_byte_block + skip_byte_block SHOULD equal 10.
|
||||
// For all video NAL units, including in 'avc1', the slice header SHALL be unencrypted.
|
||||
// The first complete byte of video slice data(following the video slice header) SHALL begin a single
|
||||
// Subsample protected byte range indicated by the start of BytesOfProtectedData, which extends to
|
||||
// the end of the video NAL.
|
||||
// NOTE 1 For AVC VCL NAL units, the encryption pattern starts at an offset rounded to the next byte after
|
||||
// the slice header, i.e. on the first full byte of slice data. For HEVC, the encryption pattern starts after
|
||||
// the byte_alignment() field that terminates the slice_segment_header(), i.e. on the first byte of slice data.
|
||||
//
|
||||
// @see ISO-IEC-23001-7.pdf 10.4.2 'cbcs' AES-CBC mode pattern encryption scheme application(informative)
|
||||
// An encrypt:skip pattern of 1:9(i.e. 10% partial encryption) is recommended. Even though the syntax
|
||||
// allows many different encryption patterns, a pattern of ten Blocks is recommended. This means that the
|
||||
// skipped Blocks will be (10-N). The number of encrypted cipher blocks N can span multiple contiguous
|
||||
// 16-byte Blocks(e.g. three encrypted Blocks followed by seven unencrypted Blocks would result in 30%
|
||||
// partial encryption of the video data).
|
||||
// For example, to achieve 10 % encryption, the first Block of the pattern is encrypted and the following
|
||||
// nine Blocks are left unencrypted. The pattern is repeated every 160 bytes of the protected range, until
|
||||
// the end of the range. If the protected range of the slice body is not a multiple of the pattern length
|
||||
// (e.g. 160 bytes), then the pattern sequence applies to the included whole 16-byte Blocks and a partial
|
||||
// 16-byte Block that may remain where the pattern is terminated by the byte length of the range
|
||||
// BytesOfProtectedData, is left unencrypted.
|
||||
//
|
||||
// @see ISO-IEC-23001-7.pdf 9.7 Whole-block full sample encryption
|
||||
// In whole-block full sample encryption, the entire sample is protected. Every sample is encrypted
|
||||
// starting at offset 0(there is no unprotected preamble) up to the last 16-byte boundary, leaving any
|
||||
// trailing 0-15 bytes in the clear. The IV is reset at every sample.
|
||||
class SrsMp4TrackEncryptionBox : public SrsMp4FullBox
|
||||
{
|
||||
public:
|
||||
uint8_t reserved;
|
||||
uint8_t reserved_2;
|
||||
uint8_t default_crypt_byte_block;
|
||||
uint8_t default_skip_byte_block;
|
||||
uint8_t default_is_protected;
|
||||
uint8_t default_per_sample_IV_size;
|
||||
uint8_t default_KID[16];
|
||||
uint8_t default_constant_IV_size;
|
||||
uint8_t default_constant_IV[16];
|
||||
public:
|
||||
SrsMp4TrackEncryptionBox();
|
||||
virtual ~SrsMp4TrackEncryptionBox();
|
||||
|
||||
public:
|
||||
virtual void set_default_constant_IV(uint8_t* iv, uint8_t iv_size);
|
||||
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual srs_error_t encode_header(SrsBuffer* buf);
|
||||
virtual srs_error_t decode_header(SrsBuffer* buf);
|
||||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// TODO: add SchemeTypeBox(schm), set scheme_type=cbcs
|
||||
|
||||
// Generally, a MP4 sample contains a frame, for example, a video frame or audio frame.
|
||||
class SrsMp4Sample
|
||||
{
|
||||
|
@ -2115,12 +2478,24 @@ class SrsMp4M2tsInitEncoder
|
|||
{
|
||||
private:
|
||||
ISrsWriter* writer;
|
||||
|
||||
private:
|
||||
uint8_t crypt_byte_block_;
|
||||
uint8_t skip_byte_block_;
|
||||
unsigned char kid_[16];
|
||||
unsigned char iv_[16];
|
||||
uint8_t iv_size_;
|
||||
bool is_protected_;
|
||||
|
||||
public:
|
||||
SrsMp4M2tsInitEncoder();
|
||||
virtual ~SrsMp4M2tsInitEncoder();
|
||||
public:
|
||||
// Initialize the encoder with a writer w.
|
||||
virtual srs_error_t initialize(ISrsWriter* w);
|
||||
// set encryption
|
||||
// TODO: review kid(map to a key) and iv, which are shared between audio/video tracks.
|
||||
virtual void config_encryption(uint8_t crypt_byte_block, uint8_t skip_byte_block, unsigned char* kid, unsigned char* iv, uint8_t iv_size);
|
||||
// Write the sequence header.
|
||||
// TODO: merge this method to its sibling.
|
||||
virtual srs_error_t write(SrsFormat* format, bool video, int tid);
|
||||
|
@ -2142,6 +2517,18 @@ public:
|
|||
* Write the sequence header with both video and audio track.
|
||||
*/
|
||||
virtual srs_error_t write(SrsFormat* format, int v_tid, int a_tid);
|
||||
|
||||
private:
|
||||
/**
|
||||
* box->type = 'encv' or 'enca'
|
||||
* |encv|
|
||||
* | |sinf|
|
||||
* | | |frma|
|
||||
* | | |schm|
|
||||
* | | |schi|
|
||||
* | | | |tenc|
|
||||
*/
|
||||
virtual srs_error_t config_sample_description_encryption(SrsMp4SampleEntry* box);
|
||||
};
|
||||
|
||||
// A fMP4 encoder, to cache segments then flush to disk, because the fMP4 should write
|
||||
|
@ -2200,12 +2587,17 @@ private:
|
|||
uint64_t mdat_video_bytes_;
|
||||
SrsMp4SampleManager* audio_samples_;
|
||||
SrsMp4SampleManager* video_samples_;
|
||||
unsigned char* key_;
|
||||
unsigned char iv_[16];
|
||||
bool do_sample_encryption_;
|
||||
public:
|
||||
SrsFmp4SegmentEncoder();
|
||||
virtual ~SrsFmp4SegmentEncoder();
|
||||
public:
|
||||
// Initialize the encoder with a writer w.
|
||||
virtual srs_error_t initialize(ISrsWriter* w, uint32_t sequence, srs_utime_t basetime, uint32_t v_tid, uint32_t a_tid);
|
||||
// config cipher
|
||||
virtual srs_error_t config_cipher(unsigned char* key, unsigned char* iv);
|
||||
// Cache a sample.
|
||||
// @param ht, The sample handler type, audio/soun or video/vide.
|
||||
// @param ft, The frame type. For video, it's SrsVideoAvcFrameType.
|
||||
|
|
Loading…
Reference in a new issue