diff --git a/src/output/output_progressive_mp4.cpp b/src/output/output_progressive_mp4.cpp index 0180d570..28527854 100644 --- a/src/output/output_progressive_mp4.cpp +++ b/src/output/output_progressive_mp4.cpp @@ -21,6 +21,7 @@ namespace Mist { capa["socket"] = "http_progressive_mp4"; capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][1u].append("AAC"); + capa["codecs"][0u][1u].append("MP3"); capa["methods"][0u]["handler"] = "http"; capa["methods"][0u]["type"] = "html5/video/mp4"; capa["methods"][0u]["priority"] = 8ll; @@ -113,6 +114,9 @@ namespace Mist { if (myMeta.tracks[*it].codec == "AAC"){ ase.setCodec("mp4a"); ase.setDataReferenceIndex(1); + }else if (myMeta.tracks[*it].codec == "MP3"){ + ase.setCodec("mp4a"); + ase.setDataReferenceIndex(1); } ase.setSampleRate(myMeta.tracks[*it].rate); ase.setChannelCount(myMeta.tracks[*it].channels); @@ -121,23 +125,37 @@ namespace Mist { MP4::ESDS esdsBox; //outputting these values first, so malloc isn't called as often. - esdsBox.setESHeaderStartCodes(myMeta.tracks[*it].init); - esdsBox.setSLValue(2); - - esdsBox.setESDescriptorTypeLength(32+myMeta.tracks[*it].init.size()); + if (myMeta.tracks[*it].codec == "MP3"){ + esdsBox.setESHeaderStartCodes("\002"); + esdsBox.setConfigDescriptorTypeLength(1); + esdsBox.setSLConfigExtendedDescriptorTypeTag(0); + esdsBox.setSLDescriptorTypeLength(0); + esdsBox.setESDescriptorTypeLength(27); + esdsBox.setSLConfigDescriptorTypeTag(0); + esdsBox.setDecoderDescriptorTypeTag(0x06); + esdsBox.setSLValue(0); + //esdsBox.setBufferSize(0); + esdsBox.setDecoderConfigDescriptorTypeLength(13); + esdsBox.setByteObjectTypeID(0x6b); + }else{ + //AAC + esdsBox.setESHeaderStartCodes(myMeta.tracks[*it].init); + esdsBox.setConfigDescriptorTypeLength(myMeta.tracks[*it].init.size()); + esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080); + esdsBox.setSLDescriptorTypeLength(1); + esdsBox.setESDescriptorTypeLength(32+myMeta.tracks[*it].init.size()); + esdsBox.setSLConfigDescriptorTypeTag(0x6); + esdsBox.setSLValue(2); + esdsBox.setDecoderConfigDescriptorTypeLength(18 + myMeta.tracks[*it].init.size()); + esdsBox.setByteObjectTypeID(0x40); + } esdsBox.setESID(2); esdsBox.setStreamPriority(0); - esdsBox.setDecoderConfigDescriptorTypeLength(18 + myMeta.tracks[*it].init.size()); - esdsBox.setByteObjectTypeID(0x40); esdsBox.setStreamType(5); esdsBox.setReservedFlag(1); - esdsBox.setBufferSize(1250000); esdsBox.setMaximumBitRate(10000000); esdsBox.setAverageBitRate(myMeta.tracks[*it].bps * 8); - esdsBox.setConfigDescriptorTypeLength(5); - esdsBox.setSLConfigDescriptorTypeTag(0x6); - esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080); - esdsBox.setSLDescriptorTypeLength(1); + esdsBox.setBufferSize(1250000); ase.setCodecBox(esdsBox); stsdBox.setEntry(ase,0); } diff --git a/src/output/output_ts.cpp b/src/output/output_ts.cpp index 7d01d06c..589fc4f5 100644 --- a/src/output/output_ts.cpp +++ b/src/output/output_ts.cpp @@ -8,23 +8,6 @@ namespace Mist { AudioCounter = 0; VideoCounter = 0; std::string tracks = config->getString("tracks"); - unsigned int currTrack = 0; - //loop over tracks, add any found track IDs to selectedTracks - if (tracks != ""){ - for (unsigned int i = 0; i < tracks.size(); ++i){ - if (tracks[i] >= '0' && tracks[i] <= '9'){ - currTrack = currTrack*10 + (tracks[i] - '0'); - }else{ - if (currTrack > 0){ - selectedTracks.insert(currTrack); - } - currTrack = 0; - } - } - if (currTrack > 0){ - selectedTracks.insert(currTrack); - } - } streamName = config->getString("streamname"); parseData = true; wantRequest = false; @@ -48,6 +31,7 @@ namespace Mist { capa["optional"]["tracks"]["option"] = "--tracks"; capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][1u].append("AAC"); + capa["codecs"][0u][1u].append("MP3"); cfg->addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}")); cfg->addOption("tracks", @@ -91,8 +75,12 @@ namespace Mist { } ContCounter = &VideoCounter; }else if (myMeta.tracks[currentPacket.getTrackId()].type == "audio"){ - ToPack.append(TS::Packet::getPESAudioLeadIn(7+dataLen, currentPacket.getTime() * 90)); - ToPack.append(TS::GetAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init)); + if (myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ + ToPack.append(TS::Packet::getPESAudioLeadIn(7+dataLen, currentPacket.getTime() * 90)); + ToPack.append(TS::GetAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init)); + }else{ + ToPack.append(TS::Packet::getPESAudioLeadIn(dataLen, currentPacket.getTime() * 90)); + } ToPack.append(dataPointer, dataLen); ContCounter = &AudioCounter; } @@ -101,17 +89,11 @@ namespace Mist { //send TS packets while (ToPack.size()){ PackData.Clear(); - /// \todo Update according to sendHeader()'s generated data. - //0x100 - 1 + currentPacket.getTrackId() - if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){ - PackData.PID(0x100); - }else{ - PackData.PID(0x101); - } + PackData.PID(0x100 - 1 + currentPacket.getTrackId()); PackData.ContinuityCounter((*ContCounter)++); if (first){ PackData.UnitStart(1); - if (IsKeyFrame){ + if (IsKeyFrame || myMeta.tracks[currentPacket.getTrackId()].type == "audio"){ PackData.RandomAccess(1); PackData.PCR(currentPacket.getTime() * 27000); } @@ -124,11 +106,60 @@ namespace Mist { } } + ///this function generates the PMT packet + std::string OutTS::createPMT(){ + //0x02 = table ID = 2 = PMT + //0xB017 = section syntax(1) = 1, 0(1)=0, reserved(2) = 3, section_len(12) = 23 + //0x0001 = ProgNo = 1 + //0xC1 = reserved(2) = 3, version(5)=0, curr_next_indi(1) = 1 + //0x00 = section_number = 0 + //0x00 = last_section_no = 0 + //0xE100 = reserved(3) = 7, PCR_PID(13) = 0x100 + //0xF000 = reserved(4) = 15, proginfolen = 0 + //0x1B = streamtype = 27 = H264 + //0xE100 = reserved(3) = 7, elem_ID(13) = 0x100 + //0xF000 = reserved(4) = 15, es_info_len = 0 + //0x0F = streamtype = 15 = audio with ADTS transport syntax + //0xE101 = reserved(3) = 7, elem_ID(13) = 0x101 + //0xF000 = reserved(4) = 15, es_info_len = 0 + //0x2F44B99B = CRC32 + TS::ProgramMappingTable PMT; + PMT.PID(4096); + PMT.setTableId(2); + PMT.setSectionLength(0xB017); + PMT.setProgramNumber(1); + PMT.setVersionNumber(0); + PMT.setCurrentNextIndicator(0); + PMT.setSectionNumber(0); + PMT.setLastSectionNumber(0); + PMT.setPCRPID(0x100 + (*(selectedTracks.begin())) - 1); + PMT.setProgramInfoLength(0); + short id = 0; + //for all selected tracks + for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){ + if (myMeta.tracks[*it].codec == "H264"){ + PMT.setStreamType(0x1B,id); + }else if (myMeta.tracks[*it].codec == "AAC"){ + PMT.setStreamType(0x0F,id); + }else if (myMeta.tracks[*it].codec == "MP3"){ + PMT.setStreamType(0x03,id); + } + PMT.setElementaryPID(0x100 + (*it) - 1, id); + PMT.setESInfoLength(0,id); + id++; + } + PMT.calcCRC(); + INFO_MSG("stringsize: %d %s", PMT.getStrBuf().size(), PMT.toPrettyString(0).c_str()); + return PMT.getStrBuf(); + } + void OutTS::sendHeader(){ - /// \todo Update this to actually generate these from the selected tracks. - /// \todo ts_packet.h contains all neccesary info for this + /// \todo if --tracks is set, clear selected tracks and fill with --tracks tracks. myConn.SendNow(TS::PAT, 188); - myConn.SendNow(TS::PMT, 188); + /// \todo Find a nice way to not use strings in this case + std::string pmt = createPMT(); + myConn.SendNow(pmt.c_str(), 188); + //myConn.SendNow(TS::PMT, 188); sentHeader = true; } diff --git a/src/output/output_ts.h b/src/output/output_ts.h index 78efee19..9885a38e 100644 --- a/src/output/output_ts.h +++ b/src/output/output_ts.h @@ -1,6 +1,7 @@ #include "output.h" #include #include +#include namespace Mist { class OutTS : public Output { @@ -17,6 +18,7 @@ namespace Mist { char VideoCounter; char AudioCounter; MP4::AVCC avccbox; + std::string createPMT(); }; }