Working PlayReady/Verimatrix DRM support

This commit is contained in:
Erik Zandvliet 2015-05-07 19:38:43 +02:00 committed by Thulinma
parent 27fdbb2468
commit 0913d2607e
25 changed files with 1360 additions and 103 deletions

View file

@ -53,6 +53,22 @@ namespace Mist {
option["long"] = "stream";
option["help"] = "The name of the stream that this connector will provide in player mode";
config->addOption("streamname", option);
/*LTS-START*/
//Encryption
option["arg"] = "string";
option["long"] = "verimatrix-playready";
option["short"] = "P";
option["help"] = "URL of the Verimatrix PlayReady keyserver";
config->addOption("verimatrix-playready", option);
capa["optional"]["verimatrix-playready"]["name"] = "Verimatrix PlayReady Server";
capa["optional"]["verimatrix-playready"]["help"] = "URL of the Verimatrix PlayReady keyserver";
capa["optional"]["verimatrix-playready"]["option"] = "--verimatrix-playready";
capa["optional"]["verimatrix-playready"]["type"] = "str";
capa["optional"]["verimatrix-playready"]["default"] = "";
option.null();
/*LTS-END*/
capa["optional"]["debug"]["name"] = "debug";
capa["optional"]["debug"]["help"] = "The debug level at which messages need to be printed.";

View file

@ -45,6 +45,7 @@ namespace Mist {
capa["optional"]["record"]["type"] = "str";
capa["optional"]["record"]["default"] = "";
option.null();
option["arg"] = "integer";
option["long"] = "cut";
option["short"] = "c";
@ -57,6 +58,7 @@ namespace Mist {
capa["optional"]["cut"]["type"] = "uint";
capa["optional"]["cut"]["default"] = 0LL;
option.null();
option["arg"] = "integer";
option["long"] = "segment-size";
option["short"] = "S";
@ -68,6 +70,7 @@ namespace Mist {
capa["optional"]["segmentsize"]["option"] = "--segment-size";
capa["optional"]["segmentsize"]["type"] = "uint";
capa["optional"]["segmentsize"]["default"] = 5000LL;
option.null();
/*LTS-end*/
capa["source_match"] = "push://*";
capa["priority"] = 9ll;
@ -746,6 +749,7 @@ namespace Mist {
recBpos = 0;
}
*/
/*LTS-END*/
configLock.post();
configLock.close();

View file

@ -0,0 +1,158 @@
#include <iostream>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <mist/stream.h>
#include <mist/base64.h>
#include <mist/defines.h>
#include <mist/encryption.h>
#include <mist/bitfields.h>
#include "input_dtsccrypt.h"
#include <ctime>
namespace Mist {
inputDTSC::inputDTSC(Util::Config * cfg) : Input(cfg) {
capa["name"] = "DTSC";
capa["desc"] = "Enables DTSC Input";
capa["priority"] = 9ll;
capa["source_match"] = "/*.dtsc";
capa["codecs"][0u][0u].append("H264");
capa["codecs"][0u][0u].append("H263");
capa["codecs"][0u][0u].append("VP6");
capa["codecs"][0u][0u].append("theora");
capa["codecs"][0u][1u].append("AAC");
capa["codecs"][0u][1u].append("MP3");
capa["codecs"][0u][1u].append("vorbis");
JSON::Value option;
option["long"] = "key";
option["short"] = "k";
option["arg"] = "string";
option["help"] = "The key to en/decrypt the current file with";
config->addOption("key", option);
option.null();
option["long"] = "keyseed";
option["short"] = "s";
option["arg"] = "string";
option["help"] = "The keyseed to en/decrypt the current file with";
config->addOption("keyseed", option);
option.null();
option["long"] = "keyid";
option["short"] = "i";
option["arg"] = "string";
option["help"] = "The keyid to en/decrypt the current file with";
config->addOption("keyid", option);
option.null();
srand(time(NULL));
}
bool inputDTSC::setup() {
key = Base64::decode(config->getString("key"));
if (key == ""){
if (config->getString("keyseed") == "" || config->getString("keyid") == ""){
std::cerr << "No key given, and no keyseed/keyid geven" << std::endl;
return false;
}
std::string tmpSeed = Base64::decode(config->getString("keyseed"));
std::string tmpID = Base64::decode(config->getString("keyid"));
std::string guid = Encryption::PR_GuidToByteArray(tmpID);
key = Encryption::PR_GenerateContentKey(tmpSeed, guid);
}
if (config->getString("input") == "-") {
std::cerr << "Input from stdin not yet supported" << std::endl;
return false;
}
if (!config->getString("streamname").size()){
if (config->getString("output") == "-") {
std::cerr << "Output to stdout not yet supported" << std::endl;
return false;
}
}else{
if (config->getString("output") != "-") {
std::cerr << "File output in player mode not supported" << std::endl;
return false;
}
}
//open File
inFile = DTSC::File(config->getString("input"));
if (!inFile) {
return false;
}
return true;
}
bool inputDTSC::readHeader() {
if (!inFile) {
return false;
}
DTSC::File tmp(config->getString("input") + ".dtsh");
if (tmp) {
myMeta = tmp.getMeta();
DEBUG_MSG(DLVL_HIGH,"Meta read in with %lu tracks", myMeta.tracks.size());
return true;
}
if (inFile.getMeta().moreheader < 0 || inFile.getMeta().tracks.size() == 0) {
DEBUG_MSG(DLVL_FAIL,"Missing external header file");
return false;
}
myMeta = DTSC::Meta(inFile.getMeta());
DEBUG_MSG(DLVL_DEVEL,"Meta read in with %lu tracks", myMeta.tracks.size());
return true;
}
void inputDTSC::getNext(bool smart) {
if (smart){
inFile.seekNext();
}else{
inFile.parseNext();
}
thisPacket = inFile.getPacket();
//Do encryption/decryption here
int tid = thisPacket.getTrackId();
char * ivec;
unsigned int ivecLen;
thisPacket.getString("ivec", ivec, ivecLen);
char iVec[16];
if (ivecLen){
memcpy(iVec, ivec, 8);
}else{
if (iVecs.find(tid) == iVecs.end()){
iVecs[tid] = ((long long unsigned int)rand() << 32) + rand();
}
Bit::htobll(iVec, iVecs[tid]);
iVecs[tid] ++;
}
Encryption::encryptPlayReady(thisPacket, myMeta.tracks[tid].codec, iVec, key.data());
}
void inputDTSC::seek(int seekTime) {
inFile.seek_time(seekTime);
initialTime = 0;
playUntil = 0;
}
void inputDTSC::trackSelect(std::string trackSpec) {
selectedTracks.clear();
long long unsigned int index;
while (trackSpec != "") {
index = trackSpec.find(' ');
selectedTracks.insert(atoi(trackSpec.substr(0, index).c_str()));
if (index != std::string::npos) {
trackSpec.erase(0, index + 1);
} else {
trackSpec = "";
}
}
inFile.selectTracks(selectedTracks);
}
}

View file

@ -0,0 +1,25 @@
#include "input.h"
#include <mist/dtsc.h>
namespace Mist {
class inputDTSC : public Input {
public:
inputDTSC(Util::Config * cfg);
protected:
//Private Functions
bool setup();
bool readHeader();
void getNext(bool smart = true);
void seek(int seekTime);
void trackSelect(std::string trackSpec);
DTSC::File inFile;
std::map<int,unsigned long long int> iVecs;
std::string key;
};
}
typedef Mist::inputDTSC mistIn;