Working MP4 push output
This commit is contained in:
parent
9b83002e69
commit
b7c6815e4f
2 changed files with 38 additions and 10 deletions
|
@ -107,6 +107,7 @@ namespace Mist{
|
||||||
|
|
||||||
OutMP4::OutMP4(Socket::Connection &conn) : HTTPOutput(conn){
|
OutMP4::OutMP4(Socket::Connection &conn) : HTTPOutput(conn){
|
||||||
wsCmds = true;
|
wsCmds = true;
|
||||||
|
sending3GP = false;
|
||||||
nextHeaderTime = 0xffffffffffffffffull;
|
nextHeaderTime = 0xffffffffffffffffull;
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
endTime = 0xffffffffffffffffull;
|
endTime = 0xffffffffffffffffull;
|
||||||
|
@ -141,6 +142,17 @@ namespace Mist{
|
||||||
capa["methods"][1u]["hrn"] = "MP4 WebSocket";
|
capa["methods"][1u]["hrn"] = "MP4 WebSocket";
|
||||||
capa["methods"][1u]["priority"] = 10;
|
capa["methods"][1u]["priority"] = 10;
|
||||||
capa["methods"][1u]["url_rel"] = "/$.mp4";
|
capa["methods"][1u]["url_rel"] = "/$.mp4";
|
||||||
|
|
||||||
|
capa["push_urls"].append("/*.fmp4");
|
||||||
|
capa["push_urls"].append("/*.mp4");
|
||||||
|
|
||||||
|
JSON::Value opt;
|
||||||
|
opt["arg"] = "string";
|
||||||
|
opt["default"] = "";
|
||||||
|
opt["arg_num"] = 1;
|
||||||
|
opt["help"] = "Target filename to store (f)MP4 file as, or - for stdout.";
|
||||||
|
cfg->addOption("target", opt);
|
||||||
|
|
||||||
// MP4 live is broken on Apple
|
// MP4 live is broken on Apple
|
||||||
capa["exceptions"]["live"] =
|
capa["exceptions"]["live"] =
|
||||||
JSON::fromString("[[\"blacklist\",[\"iPad\",\"iPhone\",\"iPod\",\"Safari\"]], "
|
JSON::fromString("[[\"blacklist\",[\"iPad\",\"iPhone\",\"iPod\",\"Safari\"]], "
|
||||||
|
@ -1247,8 +1259,7 @@ namespace Mist{
|
||||||
if (webSock) {
|
if (webSock) {
|
||||||
/* create packet */
|
/* create packet */
|
||||||
webBuf.append(dataPointer, len);
|
webBuf.append(dataPointer, len);
|
||||||
}
|
}else{
|
||||||
else {
|
|
||||||
H.Chunkify(dataPointer, len, myConn);
|
H.Chunkify(dataPointer, len, myConn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1293,15 +1304,19 @@ namespace Mist{
|
||||||
len += 2;
|
len += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currPos >= byteStart){
|
if (isRecording()){
|
||||||
H.Chunkify(dataPointer, std::min(leftOver, (int64_t)len), myConn);
|
myConn.SendNow(dataPointer, len);
|
||||||
|
|
||||||
leftOver -= len;
|
|
||||||
}else{
|
}else{
|
||||||
if (currPos + len > byteStart){
|
if (currPos >= byteStart){
|
||||||
H.Chunkify(dataPointer + (byteStart - currPos),
|
H.Chunkify(dataPointer, std::min(leftOver, (int64_t)len), myConn);
|
||||||
std::min((uint64_t)leftOver, (len - (byteStart - currPos))), myConn);
|
|
||||||
leftOver -= len - (byteStart - currPos);
|
leftOver -= len;
|
||||||
|
}else{
|
||||||
|
if (currPos + len > byteStart){
|
||||||
|
H.Chunkify(dataPointer + (byteStart - currPos),
|
||||||
|
std::min((uint64_t)leftOver, (len - (byteStart - currPos))), myConn);
|
||||||
|
leftOver -= len - (byteStart - currPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,6 +1360,18 @@ namespace Mist{
|
||||||
sentHeader = true;
|
sentHeader = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're doing piped output or output to file, we still need to write the actual header here...
|
||||||
|
if (!streamName.size() || isFileTarget()){
|
||||||
|
Util::ResizeablePointer headerData;
|
||||||
|
if (!mp4Header(headerData, fileSize, M.getLive())){
|
||||||
|
FAIL_MSG("Could not generate MP4 header!");
|
||||||
|
}else{
|
||||||
|
myConn.SendNow(headerData, headerData.size());
|
||||||
|
}
|
||||||
|
seekPoint = Output::startTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
vidTrack = getMainSelectedTrack();
|
vidTrack = getMainSelectedTrack();
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,7 @@ namespace Mist{
|
||||||
void onWebsocketFrame();
|
void onWebsocketFrame();
|
||||||
virtual void dropTrack(size_t trackId, const std::string &reason, bool probablyBad = true);
|
virtual void dropTrack(size_t trackId, const std::string &reason, bool probablyBad = true);
|
||||||
protected:
|
protected:
|
||||||
|
bool isFileTarget(){return isRecording();}
|
||||||
void sendWebsocketCodecData(const std::string& type);
|
void sendWebsocketCodecData(const std::string& type);
|
||||||
bool handleWebsocketSeek(JSON::Value& command);
|
bool handleWebsocketSeek(JSON::Value& command);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue