1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

add HLS encryption feature

This commit is contained in:
Harlan 2018-03-25 12:05:52 +08:00
parent 0d78b908a7
commit 52596a0b04
8 changed files with 378 additions and 11 deletions

View file

@ -52,6 +52,8 @@ using namespace std;
#include <srs_app_http_hooks.hpp>
#include <srs_protocol_format.hpp>
#include <openssl/rand.h>
// drop the segment when duration of ts too small.
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
@ -60,13 +62,28 @@ using namespace std;
// reset the piece id when deviation overflow this.
#define SRS_JUMP_WHEN_PIECE_DEVIATION 20
SrsHlsSegment::SrsHlsSegment(SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc)
SrsHlsSegment::SrsHlsSegment(SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc,bool needenc)
{
sequence_no = 0;
writer = new SrsFileWriter();
if(needenc)
{
writer = new SrsEncFileWriter();
}
else
{
writer = new SrsFileWriter();
}
tscw = new SrsTsContextWriter(writer, c, ac, vc);
}
void SrsHlsSegment::SrsSetEncCfg(unsigned char* keyval,unsigned char *ivval)
{
memcpy(iv,ivval,16);
dynamic_cast<SrsEncFileWriter*>(writer)->SetEncCfg(keyval,ivval);
}
SrsHlsSegment::~SrsHlsSegment()
{
srs_freep(tscw);
@ -193,6 +210,8 @@ SrsHlsMuxer::SrsHlsMuxer()
max_td = 0;
_sequence_no = 0;
current = NULL;
hls_keys = false;
hls_fragments_per_key = 10;
async = new SrsAsyncCallWorker();
context = new SrsTsContext();
segments = new SrsFragmentWindow();
@ -265,8 +284,9 @@ srs_error_t SrsHlsMuxer::initialize()
srs_error_t SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
string path, string m3u8_file, string ts_file, double fragment, double window,
bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe
) {
bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe, bool keys,
int fragments_per_key, string key_file ,string key_file_path, string key_url)
{
srs_error_t err = srs_success;
srs_freep(req);
@ -284,7 +304,13 @@ srs_error_t SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
accept_floor_ts = 0;
hls_window = window;
deviation_ts = 0;
hls_keys = keys;
hls_fragments_per_key = fragments_per_key;
hls_key_file = key_file;
hls_key_file_path = key_file_path;
hls_key_url = key_url;
// generate the m3u8 dir and path.
m3u8_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
m3u8 = path + "/" + m3u8_url;
@ -297,7 +323,18 @@ srs_error_t SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
if ((err = srs_create_dir_recursively(m3u8_dir)) != srs_success) {
return srs_error_wrap(err, "create dir");
}
if(hls_keys && (hls_path != hls_key_file_path) )
{
string key_file = hls_key_file;
key_file = srs_path_build_stream(key_file, req->vhost, req->app, req->stream);
string key_dir = srs_path_dirname(hls_key_file_path + "/" + key_file);
if ((err = srs_create_dir_recursively(key_dir)) != srs_success) {
return srs_error_wrap(err, "create dir");
}
}
return err;
}
@ -342,8 +379,53 @@ srs_error_t SrsHlsMuxer::segment_open()
}
// new segment.
current = new SrsHlsSegment(context, default_acodec, default_vcodec);
current = new SrsHlsSegment(context, default_acodec, default_vcodec, hls_keys);
current->sequence_no = _sequence_no++;
if(hls_keys){
if(current->sequence_no % hls_fragments_per_key == 0)
{
string key_file = hls_key_file;
key_file = srs_path_build_stream(key_file, req->vhost, req->app, req->stream);
if (true) {
std::stringstream ss;
ss << current->sequence_no;
key_file = srs_string_replace(key_file, "[seq]", ss.str());
}
string key_full_path = hls_key_file_path + "/" + key_file;
if (RAND_bytes(key, 16) < 0) {
srs_error_wrap(err, "rand key failed.");
}
if (RAND_bytes(iv, 16) < 0) {
srs_error_wrap(err, "rand iv failed.");
}
int flags = O_CREAT|O_WRONLY|O_TRUNC;
mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;
int fd;
if ((fd = ::open(key_full_path.c_str(), flags, mode)) < 0) {
return srs_error_new(ERROR_SYSTEM_FILE_OPENE, "open file %s failed", key_full_path.c_str());
}
ssize_t nwrite;
if ((nwrite = ::write(fd, key, 16)) != 16) {
return srs_error_new(ERROR_SYSTEM_FILE_WRITE, "write to file %s failed", key_full_path.c_str());
}
if (::close(fd) < 0) {
srs_warn("close file %s failed",key_full_path.c_str());
}
}
current->SrsSetEncCfg(key,iv);
}
// generate filename.
std::string ts_file = hls_ts_file;
@ -681,6 +763,22 @@ srs_error_t SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
// #EXT-X-DISCONTINUITY\n
ss << "#EXT-X-DISCONTINUITY" << SRS_CONSTS_LF;
}
if(hls_keys && (segment->sequence_no%hls_fragments_per_key == 0))
{
string filename = req->stream+"-"+srs_int2str(segment->sequence_no)+".key";
char hexiv[33];
ff_data_to_hex(hexiv,segment->iv,16,0);
hexiv[32] = '\0';
string key_path;
//if key_url is not set,only use the file name
if(hls_key_url == hls_key_file_path){
key_path = filename;
}else{
key_path = hls_key_url+"/"+filename;
}
ss << "#EXT-X-KEY:METHOD=AES-128,URI=" << "\""<< key_path <<"\",IV=0x"<<hexiv<< SRS_CONSTS_LF;
}
// "#EXTINF:4294967295.208,\n"
ss.precision(3);
@ -771,13 +869,20 @@ srs_error_t SrsHlsController::on_publish(SrsRequest* req)
bool ts_floor = _srs_config->get_hls_ts_floor(vhost);
// the seconds to dispose the hls.
int hls_dispose = _srs_config->get_hls_dispose(vhost);
bool hls_keys = _srs_config->get_hls_keys(vhost);
int hls_fragments_per_key = _srs_config->get_hls_fragments_per_key(vhost);
string hls_key_file = _srs_config->get_hls_key_file(vhost);
string hls_key_file_path = _srs_config->get_hls_key_file_path(vhost);
string hls_key_url = _srs_config->get_hls_key_url(vhost);
// TODO: FIXME: support load exists m3u8, to continue publish stream.
// for the HLS donot requires the EXT-X-MEDIA-SEQUENCE be monotonically increase.
// open muxer
if ((err = muxer->update_config(req, entry_prefix, path, m3u8_file, ts_file, hls_fragment,
hls_window, ts_floor, hls_aof_ratio, cleanup, wait_keyframe)) != srs_success ) {
hls_window, ts_floor, hls_aof_ratio, cleanup, wait_keyframe,hls_keys,hls_fragments_per_key,
hls_key_file, hls_key_file_path, hls_key_url)) != srs_success ) {
return srs_error_wrap(err, "hls: update config");
}