Opus in TS input/output support
This commit is contained in:
parent
1c47e9cdfc
commit
97752f2c2d
9 changed files with 240 additions and 27 deletions
|
@ -584,6 +584,35 @@ namespace TS{
|
||||||
}
|
}
|
||||||
return tmpStr;
|
return tmpStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a PES Lead-in for a meta frame.
|
||||||
|
/// Prepends the lead-in to variable toSend, assumes toSend's length is all other data.
|
||||||
|
/// \param len The length of this frame.
|
||||||
|
/// \param PTS The timestamp of the frame.
|
||||||
|
std::string &Packet::getPESPS1LeadIn(unsigned int len, unsigned long long PTS, uint64_t bps){
|
||||||
|
if (bps >= 50){
|
||||||
|
len += 3;
|
||||||
|
}else{
|
||||||
|
bps = 0;
|
||||||
|
}
|
||||||
|
static std::string tmpStr;
|
||||||
|
tmpStr.clear();
|
||||||
|
tmpStr.reserve(20);
|
||||||
|
len += 8;
|
||||||
|
tmpStr.append("\000\000\001\275", 4);
|
||||||
|
tmpStr += (char)((len & 0xFF00) >> 8); // PES PacketLength
|
||||||
|
tmpStr += (char)(len & 0x00FF); // PES PacketLength (Cont)
|
||||||
|
tmpStr += (char)0x84; // isAligned
|
||||||
|
tmpStr += (char)(0x80 | (bps ? 0x10 : 0)); // PTS/DTS + Flags
|
||||||
|
tmpStr += (char)(5 + (bps ? 3 : 0)); // PESHeaderDataLength
|
||||||
|
encodePESTimestamp(tmpStr, 0x20, PTS);
|
||||||
|
if (bps){
|
||||||
|
char rate_buf[3];
|
||||||
|
Bit::htob24(rate_buf, (bps / 50) | 0x800001);
|
||||||
|
tmpStr.append(rate_buf, 3);
|
||||||
|
}
|
||||||
|
return tmpStr;
|
||||||
|
}
|
||||||
// END PES FUNCTIONS
|
// END PES FUNCTIONS
|
||||||
|
|
||||||
/// Fills the free bytes of the Packet.
|
/// Fills the free bytes of the Packet.
|
||||||
|
@ -1081,11 +1110,70 @@ namespace TS{
|
||||||
return "und";
|
return "und";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the registration field, or an empty string if none present.
|
||||||
|
std::string ProgramDescriptors::getRegistration() const{
|
||||||
|
for (uint32_t p = 0; p + 1 < p_len; p += p_data[p + 1] + 2){
|
||||||
|
if (p_data[p] == 0x05){// registration
|
||||||
|
return std::string(p_data + p + 2, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No tag found! Empty string.
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the extension field, or an empty string if none present.
|
||||||
|
std::string ProgramDescriptors::getExtension() const{
|
||||||
|
for (uint32_t p = 0; p + 1 < p_len; p += p_data[p + 1] + 2){
|
||||||
|
if (p_data[p] == 0x7F){// extension
|
||||||
|
return std::string(p_data + p + 2, p_data[p+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No tag found! Empty string.
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
/// Prints all descriptors we understand in a readable format, the others in raw hex.
|
/// Prints all descriptors we understand in a readable format, the others in raw hex.
|
||||||
std::string ProgramDescriptors::toPrettyString(size_t indent) const{
|
std::string ProgramDescriptors::toPrettyString(size_t indent) const{
|
||||||
std::stringstream output;
|
std::stringstream output;
|
||||||
for (uint32_t p = 0; p + 1 < p_len; p += p_data[p + 1] + 2){
|
for (uint32_t p = 0; p + 1 < p_len; p += p_data[p + 1] + 2){
|
||||||
switch (p_data[p]){
|
switch (p_data[p]){
|
||||||
|
case 0x05:{// registration descriptor
|
||||||
|
if ((p_data[p+2] >= 32 && p_data[p+2] <= 126) &&
|
||||||
|
(p_data[p+2] >= 32 && p_data[p+2] <= 126) &&
|
||||||
|
(p_data[p+2] >= 32 && p_data[p+2] <= 126) &&
|
||||||
|
(p_data[p+2] >= 32 && p_data[p+2] <= 126)){
|
||||||
|
//printable ASCII
|
||||||
|
output << std::string(indent, ' ') << "Registration: " << std::string(p_data + p + 2, 4);
|
||||||
|
//Extra binary data, if any
|
||||||
|
if (p_data[p+1] > 4){
|
||||||
|
output << " (";
|
||||||
|
for (uint32_t i = 6; i < p_data[p + 1] + 2; ++i){
|
||||||
|
output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase
|
||||||
|
<< (int)p_data[p + i] << std::dec;
|
||||||
|
}
|
||||||
|
output << ")";
|
||||||
|
}
|
||||||
|
output << std::endl;
|
||||||
|
}else{
|
||||||
|
output << std::string(indent, ' ') << "Registration (unprintable): ";
|
||||||
|
for (uint32_t i = 2; i < p_data[p + 1] + 2; ++i){
|
||||||
|
output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase
|
||||||
|
<< (int)p_data[p + i] << std::dec;
|
||||||
|
}
|
||||||
|
output << std::endl;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case 0x06:{// data alignment descriptor
|
||||||
|
output << std::string(indent, ' ') << "Data alignment: ";
|
||||||
|
switch (p_data[p+2]){
|
||||||
|
case 1: output << "Slice or Video Access Unit (1)"; break;
|
||||||
|
case 2: output << "Video Access Unit (2)"; break;
|
||||||
|
case 3: output << "GOP or SEQ (3)"; break;
|
||||||
|
case 4: output << "SEQ (4)"; break;
|
||||||
|
default: output << "Reserved (" << (int)(p_data[p+2]) << ")"; break;
|
||||||
|
}
|
||||||
|
output << std::endl;
|
||||||
|
}break;
|
||||||
case 0x0A:{// ISO 639-2 language tag (ISO 13818-1)
|
case 0x0A:{// ISO 639-2 language tag (ISO 13818-1)
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
while (offset < p_data[p + 1]){// single language
|
while (offset < p_data[p + 1]){// single language
|
||||||
|
@ -1146,6 +1234,22 @@ namespace TS{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}break;
|
}break;
|
||||||
|
case 0x7F:{// extension descriptor
|
||||||
|
output << std::string(indent, ' ') << "Extension: ";
|
||||||
|
if (p_data[p+2] < 0x80){
|
||||||
|
output << "Unimplemented";
|
||||||
|
}else{
|
||||||
|
output << "User defined";
|
||||||
|
}
|
||||||
|
output << " (";
|
||||||
|
output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)p_data[p + 2] << std::dec;
|
||||||
|
output << ") - ";
|
||||||
|
for (uint32_t i = 3; i < p_data[p + 1] + 2; ++i){
|
||||||
|
output << std::hex << std::setw(2) << std::setfill('0') << std::uppercase
|
||||||
|
<< (int)p_data[p + i] << std::dec;
|
||||||
|
}
|
||||||
|
output << std::endl;
|
||||||
|
}break;
|
||||||
case 0x52:{// DVB stream identifier
|
case 0x52:{// DVB stream identifier
|
||||||
output << std::string(indent, ' ') << "Stream identifier: Tag #" << (int)p_data[p + 2] << std::endl;
|
output << std::string(indent, ' ') << "Stream identifier: Tag #" << (int)p_data[p + 2] << std::endl;
|
||||||
}break;
|
}break;
|
||||||
|
@ -1186,12 +1290,11 @@ namespace TS{
|
||||||
std::string codec = M.getCodec(*it);
|
std::string codec = M.getCodec(*it);
|
||||||
sectionLen += 5;
|
sectionLen += 5;
|
||||||
if (codec == "ID3" || codec == "RAW"){sectionLen += M.getInit(*it).size();}
|
if (codec == "ID3" || codec == "RAW"){sectionLen += M.getInit(*it).size();}
|
||||||
if (codec == "AAC"){
|
if (codec == "AAC"){sectionLen += 4;} // length of AAC descriptor
|
||||||
sectionLen += 4; // aac descriptor
|
if (codec == "opus"){sectionLen += 10;} // 6 bytes registration desc, 4 bytes opus desc
|
||||||
std::string lang = M.getLang(*it);
|
std::string lang = M.getLang(*it);
|
||||||
if (lang.size() == 3 && lang != "und"){
|
if (lang.size() == 3 && lang != "und"){
|
||||||
sectionLen += 6; // language descriptor
|
sectionLen += 6; // language descriptor
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PMT.setSectionLength(0xB00D + sectionLen);
|
PMT.setSectionLength(0xB00D + sectionLen);
|
||||||
|
@ -1215,7 +1318,7 @@ namespace TS{
|
||||||
for (std::set<long unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
|
for (std::set<long unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
|
||||||
std::string codec = M.getCodec(*it);
|
std::string codec = M.getCodec(*it);
|
||||||
entry.setElementaryPid(getUniqTrackID(M, *it));
|
entry.setElementaryPid(getUniqTrackID(M, *it));
|
||||||
entry.setESInfo("");
|
std::string es_info;
|
||||||
if (codec == "H264"){
|
if (codec == "H264"){
|
||||||
entry.setStreamType(0x1B);
|
entry.setStreamType(0x1B);
|
||||||
}else if (codec == "HEVC"){
|
}else if (codec == "HEVC"){
|
||||||
|
@ -1224,18 +1327,15 @@ namespace TS{
|
||||||
entry.setStreamType(0x02);
|
entry.setStreamType(0x02);
|
||||||
}else if (codec == "AAC"){
|
}else if (codec == "AAC"){
|
||||||
entry.setStreamType(0x0F);
|
entry.setStreamType(0x0F);
|
||||||
std::string aac_info("\174\002\121\000",
|
// AAC descriptor: AAC Level 2. Hardcoded, because... what are AAC levels, anyway?
|
||||||
4); // AAC descriptor: AAC Level 2. Hardcoded, because... what are AAC levels, anyway?
|
es_info.append("\174\002\121\000", 4);
|
||||||
// language code ddescriptor
|
|
||||||
std::string lang = M.getLang(*it);
|
|
||||||
if (lang.size() == 3 && lang != "und"){
|
|
||||||
aac_info.append("\012\004", 2);
|
|
||||||
aac_info.append(lang);
|
|
||||||
aac_info.append("\000", 1);
|
|
||||||
}
|
|
||||||
entry.setESInfo(aac_info);
|
|
||||||
}else if (codec == "MP3" || codec == "MP2"){
|
}else if (codec == "MP3" || codec == "MP2"){
|
||||||
entry.setStreamType(0x03);
|
entry.setStreamType(0x03);
|
||||||
|
}else if (codec == "opus"){
|
||||||
|
entry.setStreamType(0x06);
|
||||||
|
es_info.append("\005\004Opus", 6);//registration descriptor
|
||||||
|
es_info.append("\177\002\200", 3);//Opus descriptor
|
||||||
|
es_info.append(1, (char)M.getChannels(*it));
|
||||||
}else if (codec == "AC3"){
|
}else if (codec == "AC3"){
|
||||||
entry.setStreamType(0x81);
|
entry.setStreamType(0x81);
|
||||||
}else if (codec == "ID3"){
|
}else if (codec == "ID3"){
|
||||||
|
@ -1245,6 +1345,14 @@ namespace TS{
|
||||||
entry.setStreamType(0x06);
|
entry.setStreamType(0x06);
|
||||||
entry.setESInfo(M.getInit(*it));
|
entry.setESInfo(M.getInit(*it));
|
||||||
}
|
}
|
||||||
|
// language code descriptor
|
||||||
|
std::string lang = M.getLang(*it);
|
||||||
|
if (lang.size() == 3 && lang != "und"){
|
||||||
|
es_info.append("\012\004", 2);
|
||||||
|
es_info.append(lang);
|
||||||
|
es_info.append("\000", 1);
|
||||||
|
}
|
||||||
|
entry.setESInfo(es_info);
|
||||||
entry.advance();
|
entry.advance();
|
||||||
}
|
}
|
||||||
PMT.calcCRC();
|
PMT.calcCRC();
|
||||||
|
|
|
@ -76,6 +76,7 @@ namespace TS{
|
||||||
unsigned long long offset, bool isAligned, uint64_t bps = 0);
|
unsigned long long offset, bool isAligned, uint64_t bps = 0);
|
||||||
static std::string &getPESAudioLeadIn(unsigned int len, unsigned long long PTS, uint64_t bps = 0);
|
static std::string &getPESAudioLeadIn(unsigned int len, unsigned long long PTS, uint64_t bps = 0);
|
||||||
static std::string &getPESMetaLeadIn(unsigned int len, unsigned long long PTS, uint64_t bps = 0);
|
static std::string &getPESMetaLeadIn(unsigned int len, unsigned long long PTS, uint64_t bps = 0);
|
||||||
|
static std::string &getPESPS1LeadIn(unsigned int len, unsigned long long PTS, uint64_t bps = 0);
|
||||||
|
|
||||||
// Printers and writers
|
// Printers and writers
|
||||||
std::string toPrettyString(size_t indent = 0, int detailLevel = 3) const;
|
std::string toPrettyString(size_t indent = 0, int detailLevel = 3) const;
|
||||||
|
@ -111,6 +112,8 @@ namespace TS{
|
||||||
public:
|
public:
|
||||||
ProgramDescriptors(const char *data, const uint32_t len);
|
ProgramDescriptors(const char *data, const uint32_t len);
|
||||||
std::string getLanguage() const;
|
std::string getLanguage() const;
|
||||||
|
std::string getRegistration() const;
|
||||||
|
std::string getExtension() const;
|
||||||
std::string toPrettyString(size_t indent) const;
|
std::string toPrettyString(size_t indent) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "tinythread.h"
|
#include "tinythread.h"
|
||||||
|
#include "opus.h"
|
||||||
|
|
||||||
tthread::recursive_mutex tMutex;
|
tthread::recursive_mutex tMutex;
|
||||||
|
|
||||||
|
@ -206,12 +207,19 @@ namespace TS{
|
||||||
case ID3:
|
case ID3:
|
||||||
case MP2:
|
case MP2:
|
||||||
case MPEG2:
|
case MPEG2:
|
||||||
case META:
|
case OPUS:
|
||||||
|
case META:{
|
||||||
pidToCodec[pid] = sType;
|
pidToCodec[pid] = sType;
|
||||||
if (sType == ID3 || sType == META){
|
std::string & init = metaInit[pid];
|
||||||
metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength());
|
init.assign(entry.getESInfo(), entry.getESInfoLength());
|
||||||
|
if (sType == META){
|
||||||
|
TS::ProgramDescriptors desc(init.data(), init.size());
|
||||||
|
std::string reg = desc.getRegistration();
|
||||||
|
if (reg == "Opus"){
|
||||||
|
pidToCodec[pid] = OPUS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
entry.advance();
|
entry.advance();
|
||||||
|
@ -547,7 +555,36 @@ namespace TS{
|
||||||
mp2Hdr[tid] = std::string(pesPayload, realPayloadSize);
|
mp2Hdr[tid] = std::string(pesPayload, realPayloadSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (thisCodec == OPUS){
|
||||||
|
size_t offset = 0;
|
||||||
|
while (realPayloadSize > offset+1){
|
||||||
|
size_t headSize = 2;
|
||||||
|
size_t packSize = 0;
|
||||||
|
bool control_ext = false;
|
||||||
|
if (pesPayload[offset+1] & 0x10){headSize += 2;}//trim start
|
||||||
|
if (pesPayload[offset+1] & 0x08){headSize += 2;}//trim end
|
||||||
|
if (pesPayload[offset+1] & 0x04){control_ext = true;}//control extension
|
||||||
|
while (pesPayload[offset+2] == 255){
|
||||||
|
packSize += 255;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
packSize += pesPayload[offset+2];
|
||||||
|
++offset;
|
||||||
|
offset += headSize;
|
||||||
|
//Skip control extension, if present
|
||||||
|
if (control_ext){
|
||||||
|
offset += pesPayload[offset] + 1;
|
||||||
|
}
|
||||||
|
if (realPayloadSize < offset+packSize){
|
||||||
|
WARN_MSG("Encountered invalid Opus frame (%zu > %zu) - discarding!", offset+packSize, realPayloadSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out.push_back(DTSC::Packet());
|
||||||
|
out.back().genericFill(timeStamp, timeOffset, tid, pesPayload+offset, packSize, bPos, 0);
|
||||||
|
timeStamp += Opus::Opus_getDuration(pesPayload+offset);
|
||||||
|
offset += packSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (thisCodec == H264 || thisCodec == H265){
|
if (thisCodec == H264 || thisCodec == H265){
|
||||||
const char *nextPtr;
|
const char *nextPtr;
|
||||||
const char *pesEnd = pesPayload + realPayloadSize;
|
const char *pesEnd = pesPayload + realPayloadSize;
|
||||||
|
@ -915,6 +952,52 @@ namespace TS{
|
||||||
codec = "AC3";
|
codec = "AC3";
|
||||||
size = 16;
|
size = 16;
|
||||||
}break;
|
}break;
|
||||||
|
case OPUS:{
|
||||||
|
addNewTrack = true;
|
||||||
|
type = "audio";
|
||||||
|
codec = "opus";
|
||||||
|
size = 16;
|
||||||
|
init = std::string("OpusHead\001\002\170\000\200\273\000\000\000\000\001", 19);
|
||||||
|
channels = 2;
|
||||||
|
std::string extData = TS::ProgramDescriptors(metaInit[it->first].data(), metaInit[it->first].size()).getExtension();
|
||||||
|
if (extData.size() > 1){
|
||||||
|
channels = extData[1];
|
||||||
|
uint8_t channel_map = extData[2];
|
||||||
|
if (channels > 8){
|
||||||
|
FAIL_MSG("Channel count %u not implemented", (int)channels);
|
||||||
|
if (channel_map == 1){channel_map = 255;}
|
||||||
|
}
|
||||||
|
if (channel_map > 1){
|
||||||
|
FAIL_MSG("Channel mapping table %u not implemented", (int)init[18]);
|
||||||
|
channel_map = 255;
|
||||||
|
}
|
||||||
|
if (channels > 2 && channels <= 8 && channel_map == 0){
|
||||||
|
WARN_MSG("Overriding channel mapping table from 0 to 1");
|
||||||
|
channel_map = 1;
|
||||||
|
}
|
||||||
|
init[9] = channels;
|
||||||
|
init[18] = channel_map;
|
||||||
|
if (channel_map == 1){
|
||||||
|
static const uint8_t opus_coupled_stream_cnt[9] = {1,0,1,1,2,2,2,3,3};
|
||||||
|
static const uint8_t opus_stream_cnt[9] = {1,1,1,2,2,3,4,4,5};
|
||||||
|
static const uint8_t opus_channel_map[8][8] = {
|
||||||
|
{0},
|
||||||
|
{0,1},
|
||||||
|
{0,2,1},
|
||||||
|
{0,1,2,3},
|
||||||
|
{0,4,1,2,3},
|
||||||
|
{0,4,1,2,3,5},
|
||||||
|
{0,4,1,2,3,5,6},
|
||||||
|
{0,6,1,2,3,4,5,7},
|
||||||
|
};
|
||||||
|
init += (char)opus_stream_cnt[channels];
|
||||||
|
init += (char)opus_coupled_stream_cnt[channels];
|
||||||
|
init += std::string("\000\000\000\000\000\000\000\000", channels);
|
||||||
|
memcpy((char*)init.data()+21, opus_channel_map[channels - 1], channels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rate = 48000;
|
||||||
|
}break;
|
||||||
case MP2:{
|
case MP2:{
|
||||||
addNewTrack = true;
|
addNewTrack = true;
|
||||||
Mpeg::MP2Info info = Mpeg::parseMP2Header(mp2Hdr[it->first]);
|
Mpeg::MP2Info info = Mpeg::parseMP2Header(mp2Hdr[it->first]);
|
||||||
|
@ -996,6 +1079,7 @@ namespace TS{
|
||||||
case ID3:
|
case ID3:
|
||||||
case MP2:
|
case MP2:
|
||||||
case MPEG2:
|
case MPEG2:
|
||||||
|
case OPUS:
|
||||||
case META: result.insert(entry.getElementaryPid()); break;
|
case META: result.insert(entry.getElementaryPid()); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ namespace TS{
|
||||||
ID3 = 0x15,
|
ID3 = 0x15,
|
||||||
MPEG2 = 0x02,
|
MPEG2 = 0x02,
|
||||||
MP2 = 0x03,
|
MP2 = 0x03,
|
||||||
META = 0x06
|
META = 0x06,
|
||||||
|
OPUS = 0x060001
|
||||||
};
|
};
|
||||||
|
|
||||||
class ADTSRemainder{
|
class ADTSRemainder{
|
||||||
|
|
|
@ -94,6 +94,10 @@ std::string AnalyserTS::printPES(const std::string &d, size_t PID){
|
||||||
res << " [Audio " << (int)(d[3] & 0x1F) << "]";
|
res << " [Audio " << (int)(d[3] & 0x1F) << "]";
|
||||||
known = true;
|
known = true;
|
||||||
}
|
}
|
||||||
|
if (!known && d[3] == 0xBD){
|
||||||
|
res << " [Private Stream 1]";
|
||||||
|
known = true;
|
||||||
|
}
|
||||||
if (!known){res << " [Unknown stream ID: " << (int)d[3] << "]";}
|
if (!known){res << " [Unknown stream ID: " << (int)d[3] << "]";}
|
||||||
if (d[0] != 0 || d[1] != 0 || d[2] != 1){
|
if (d[0] != 0 || d[1] != 0 || d[2] != 1){
|
||||||
res << " [!!! INVALID START CODE: " << (int)d[0] << " " << (int)d[1] << " " << (int)d[2] << " ]";
|
res << " [!!! INVALID START CODE: " << (int)d[0] << " " << (int)d[1] << " " << (int)d[2] << " ]";
|
||||||
|
|
|
@ -172,6 +172,7 @@ namespace Mist{
|
||||||
capa["codecs"][0u][1u].append("AAC");
|
capa["codecs"][0u][1u].append("AAC");
|
||||||
capa["codecs"][0u][1u].append("AC3");
|
capa["codecs"][0u][1u].append("AC3");
|
||||||
capa["codecs"][0u][1u].append("MP2");
|
capa["codecs"][0u][1u].append("MP2");
|
||||||
|
capa["codecs"][0u][1u].append("opus");
|
||||||
inFile = NULL;
|
inFile = NULL;
|
||||||
inputProcess = 0;
|
inputProcess = 0;
|
||||||
isFinished = false;
|
isFinished = false;
|
||||||
|
|
|
@ -70,6 +70,7 @@ namespace Mist{
|
||||||
capa["codecs"][0u][1u].append("+MP3");
|
capa["codecs"][0u][1u].append("+MP3");
|
||||||
capa["codecs"][0u][1u].append("+AC3");
|
capa["codecs"][0u][1u].append("+AC3");
|
||||||
capa["codecs"][0u][1u].append("+MP2");
|
capa["codecs"][0u][1u].append("+MP2");
|
||||||
|
capa["codecs"][0u][1u].append("+opus");
|
||||||
capa["methods"][0u]["handler"] = "http";
|
capa["methods"][0u]["handler"] = "http";
|
||||||
capa["methods"][0u]["type"] = "html5/video/mpeg";
|
capa["methods"][0u]["type"] = "html5/video/mpeg";
|
||||||
capa["methods"][0u]["priority"] = 1;
|
capa["methods"][0u]["priority"] = 1;
|
||||||
|
|
|
@ -110,6 +110,7 @@ namespace Mist{
|
||||||
capa["codecs"][0u][1u].append("MP3");
|
capa["codecs"][0u][1u].append("MP3");
|
||||||
capa["codecs"][0u][1u].append("AC3");
|
capa["codecs"][0u][1u].append("AC3");
|
||||||
capa["codecs"][0u][1u].append("MP2");
|
capa["codecs"][0u][1u].append("MP2");
|
||||||
|
capa["codecs"][0u][1u].append("opus");
|
||||||
cfg->addConnectorOptions(8888, capa);
|
cfg->addConnectorOptions(8888, capa);
|
||||||
config = cfg;
|
config = cfg;
|
||||||
capa["push_urls"].append("tsudp://*");
|
capa["push_urls"].append("tsudp://*");
|
||||||
|
|
|
@ -164,11 +164,21 @@ namespace Mist{
|
||||||
packTime = aacSamples * 90000 / freq;
|
packTime = aacSamples * 90000 / freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, M.getBps(thisIdx));
|
if (codec == "opus"){
|
||||||
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
|
tempLen += 3 + (dataLen/255);
|
||||||
if (codec == "AAC"){
|
bs = TS::Packet::getPESPS1LeadIn(tempLen, packTime, M.getBps(thisIdx));
|
||||||
bs = TS::getAudioHeader(dataLen, M.getInit(thisIdx));
|
|
||||||
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
|
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
|
||||||
|
bs = "\177\340";
|
||||||
|
bs.append(dataLen/255, (char)255);
|
||||||
|
bs.append(1, (char)(dataLen-255*(dataLen/255)));
|
||||||
|
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
|
||||||
|
}else{
|
||||||
|
bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, M.getBps(thisIdx));
|
||||||
|
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
|
||||||
|
if (codec == "AAC"){
|
||||||
|
bs = TS::getAudioHeader(dataLen, M.getInit(thisIdx));
|
||||||
|
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
|
fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
|
||||||
}else if (type == "meta"){
|
}else if (type == "meta"){
|
||||||
|
|
Loading…
Add table
Reference in a new issue