Fixed HTTP Connector F4V support.
This commit is contained in:
parent
9b6e220b88
commit
b0880215df
1 changed files with 38 additions and 68 deletions
|
@ -25,6 +25,10 @@ namespace Connector_HTTP{
|
||||||
/// Defines the type of handler used to process this request.
|
/// Defines the type of handler used to process this request.
|
||||||
enum {HANDLER_NONE, HANDLER_PROGRESSIVE, HANDLER_FLASH, HANDLER_APPLE, HANDLER_MICRO, HANDLER_JSCRIPT};
|
enum {HANDLER_NONE, HANDLER_PROGRESSIVE, HANDLER_FLASH, HANDLER_APPLE, HANDLER_MICRO, HANDLER_JSCRIPT};
|
||||||
|
|
||||||
|
std::queue<std::string> Flash_FragBuffer;///<Fragment buffer for F4V
|
||||||
|
DTSC::Stream Strm;///< Incoming stream buffer.
|
||||||
|
HTTP::Parser HTTP_R, HTTP_S;///<HTTP Receiver en HTTP Sender.
|
||||||
|
|
||||||
|
|
||||||
/// Returns AMF-format metadata for Adobe HTTP Dynamic Streaming.
|
/// Returns AMF-format metadata for Adobe HTTP Dynamic Streaming.
|
||||||
std::string GetMetaData( ) {
|
std::string GetMetaData( ) {
|
||||||
|
@ -66,7 +70,7 @@ namespace Connector_HTTP{
|
||||||
}//getMetaData
|
}//getMetaData
|
||||||
|
|
||||||
/// Returns a F4M-format manifest file for Adobe HTTP Dynamic Streaming.
|
/// Returns a F4M-format manifest file for Adobe HTTP Dynamic Streaming.
|
||||||
std::string BuildManifest( std::string MetaData, std::string MovieId, int CurrentMediaTime ) {
|
std::string BuildManifest(std::string MovieId) {
|
||||||
Interface * temp = new Interface;
|
Interface * temp = new Interface;
|
||||||
std::string Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n";
|
std::string Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n";
|
||||||
Result += "<id>";
|
Result += "<id>";
|
||||||
|
@ -100,7 +104,7 @@ namespace Connector_HTTP{
|
||||||
HTTP_S.SendResponse(conn, "200", "OK");//geen SetBody = unknown length! Dat willen we hier.
|
HTTP_S.SendResponse(conn, "200", "OK");//geen SetBody = unknown length! Dat willen we hier.
|
||||||
//HTTP_S.SendBodyPart(CONN_fd, FLVHeader, 13);//schrijf de FLV header
|
//HTTP_S.SendBodyPart(CONN_fd, FLVHeader, 13);//schrijf de FLV header
|
||||||
conn.write(FLV::Header, 13);
|
conn.write(FLV::Header, 13);
|
||||||
FLV::Tag tmp;
|
static FLV::Tag tmp;
|
||||||
tmp.DTSCMetaInit(Strm);
|
tmp.DTSCMetaInit(Strm);
|
||||||
conn.write(tmp.data, tmp.len);
|
conn.write(tmp.data, tmp.len);
|
||||||
if (Strm.metadata.getContentP("audio") && Strm.metadata.getContentP("audio")->getContentP("init")){
|
if (Strm.metadata.getContentP("audio") && Strm.metadata.getContentP("audio")->getContentP("init")){
|
||||||
|
@ -121,65 +125,28 @@ namespace Connector_HTTP{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles Flash Dynamic HTTP streaming requests
|
/// Handles Flash Dynamic HTTP streaming requests
|
||||||
void FlashDynamic(FLV::Tag & tag, HTTP::Parser HTTP_S, Socket::Connection & conn, DTSC::Stream & Strm){
|
void FlashDynamic(FLV::Tag & tag, DTSC::Stream & Strm){
|
||||||
static std::queue<std::string> Flash_FragBuffer;
|
|
||||||
static unsigned int Flash_StartTime = 0;
|
|
||||||
static std::string FlashBuf;
|
static std::string FlashBuf;
|
||||||
static std::string FlashMeta;
|
static FLV::Tag tmp;
|
||||||
static bool FlashFirstVideo = false;
|
if (Strm.getPacket(0).getContentP("keyframe")){
|
||||||
static bool FlashFirstAudio = false;
|
if (FlashBuf != ""){
|
||||||
static bool Flash_ManifestSent = false;
|
Flash_FragBuffer.push(FlashBuf);
|
||||||
static int Flash_RequestPending = 0;
|
#if DEBUG >= 4
|
||||||
if (tag.tagTime() > 0){
|
fprintf(stderr, "Received a fragment. Now %i in buffer.\n", (int)Flash_FragBuffer.size());
|
||||||
if (Flash_StartTime == 0){
|
#endif
|
||||||
Flash_StartTime = tag.tagTime();
|
}
|
||||||
|
FlashBuf.clear();
|
||||||
|
//fill buffer with init data, if needed.
|
||||||
|
if (Strm.metadata.getContentP("audio") && Strm.metadata.getContentP("audio")->getContentP("init")){
|
||||||
|
tmp.DTSCAudioInit(Strm);
|
||||||
|
FlashBuf.append(tmp.data, tmp.len);
|
||||||
|
}
|
||||||
|
if (Strm.metadata.getContentP("video") && Strm.metadata.getContentP("video")->getContentP("init")){
|
||||||
|
tmp.DTSCVideoInit(Strm);
|
||||||
|
FlashBuf.append(tmp.data, tmp.len);
|
||||||
}
|
}
|
||||||
tag.tagTime(tag.tagTime() - Flash_StartTime);
|
|
||||||
}
|
|
||||||
if (tag.data[0] != 0x12 ) {
|
|
||||||
if (tag.isKeyframe){
|
|
||||||
if (FlashBuf != "" && !FlashFirstVideo && !FlashFirstAudio){
|
|
||||||
Flash_FragBuffer.push(FlashBuf);
|
|
||||||
#if DEBUG >= 4
|
|
||||||
fprintf(stderr, "Received a fragment. Now %i in buffer.\n", (int)Flash_FragBuffer.size());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
FlashBuf.clear();
|
|
||||||
FlashFirstVideo = true;
|
|
||||||
FlashFirstAudio = true;
|
|
||||||
}
|
|
||||||
/// \todo Check metadata for video/audio, append if needed.
|
|
||||||
/*
|
|
||||||
if (FlashFirstVideo && (tag.data[0] == 0x09) && (Video_Init.len > 0)){
|
|
||||||
Video_Init.tagTime(tag.tagTime());
|
|
||||||
FlashBuf.append(Video_Init.data, Video_Init.len);
|
|
||||||
FlashFirstVideo = false;
|
|
||||||
}
|
|
||||||
if (FlashFirstAudio && (tag.data[0] == 0x08) && (Audio_Init.len > 0)){
|
|
||||||
Audio_Init.tagTime(tag.tagTime());
|
|
||||||
FlashBuf.append(Audio_Init.data, Audio_Init.len);
|
|
||||||
FlashFirstAudio = false;
|
|
||||||
}
|
|
||||||
#if DEBUG >= 5
|
|
||||||
fprintf(stderr, "Received a tag of type %2hhu and length %i\n", tag.data[0], tag.len);
|
|
||||||
#endif
|
|
||||||
if ((Video_Init.len > 0) && (Audio_Init.len > 0)){
|
|
||||||
FlashBuf.append(tag.data,tag.len);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
FlashMeta = "";
|
|
||||||
FlashMeta.append(tag.data+11,tag.len-15);
|
|
||||||
if( !Flash_ManifestSent ) {
|
|
||||||
HTTP_S.Clean();
|
|
||||||
HTTP_S.SetHeader("Content-Type","text/xml");
|
|
||||||
HTTP_S.SetHeader("Cache-Control","no-cache");
|
|
||||||
HTTP_S.SetBody(BuildManifest(FlashMeta, Movie, tag.tagTime()));
|
|
||||||
HTTP_S.SendResponse(conn, "200", "OK");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
FlashBuf.append(tag.data, tag.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -192,14 +159,14 @@ namespace Connector_HTTP{
|
||||||
std::string streamname;
|
std::string streamname;
|
||||||
FLV::Tag tag;///< Temporary tag buffer.
|
FLV::Tag tag;///< Temporary tag buffer.
|
||||||
std::string recBuffer = "";
|
std::string recBuffer = "";
|
||||||
DTSC::Stream Strm;///< Incoming stream buffer.
|
|
||||||
HTTP::Parser HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.
|
|
||||||
|
|
||||||
std::string Movie = "";
|
std::string Movie = "";
|
||||||
std::string Quality = "";
|
std::string Quality = "";
|
||||||
int Segment = -1;
|
int Segment = -1;
|
||||||
int ReqFragment = -1;
|
int ReqFragment = -1;
|
||||||
int temp;
|
int temp;
|
||||||
|
int Flash_RequestPending = 0;
|
||||||
|
bool Flash_ManifestSent = false;
|
||||||
unsigned int lastStats = 0;
|
unsigned int lastStats = 0;
|
||||||
//int CurrentFragment = -1; later herbruiken?
|
//int CurrentFragment = -1; later herbruiken?
|
||||||
|
|
||||||
|
@ -207,6 +174,7 @@ namespace Connector_HTTP{
|
||||||
//only parse input if available or not yet init'ed
|
//only parse input if available or not yet init'ed
|
||||||
if (HTTP_R.Read(conn, ready4data)){
|
if (HTTP_R.Read(conn, ready4data)){
|
||||||
handler = HANDLER_PROGRESSIVE;
|
handler = HANDLER_PROGRESSIVE;
|
||||||
|
std::cout << "Received request: " << HTTP_R.url << std::endl;
|
||||||
if ((HTTP_R.url.find("Seg") != std::string::npos) && (HTTP_R.url.find("Frag") != std::string::npos)){handler = HANDLER_FLASH;}
|
if ((HTTP_R.url.find("Seg") != std::string::npos) && (HTTP_R.url.find("Frag") != std::string::npos)){handler = HANDLER_FLASH;}
|
||||||
if (HTTP_R.url.find("f4m") != std::string::npos){handler = HANDLER_FLASH;}
|
if (HTTP_R.url.find("f4m") != std::string::npos){handler = HANDLER_FLASH;}
|
||||||
if (HTTP_R.url == "/crossdomain.xml"){
|
if (HTTP_R.url == "/crossdomain.xml"){
|
||||||
|
@ -233,11 +201,7 @@ namespace Connector_HTTP{
|
||||||
printf( "URL: %s\n", HTTP_R.url.c_str());
|
printf( "URL: %s\n", HTTP_R.url.c_str());
|
||||||
printf( "Movie: %s, Quality: %s, Seg %d Frag %d\n", Movie.c_str(), Quality.c_str(), Segment, ReqFragment);
|
printf( "Movie: %s, Quality: %s, Seg %d Frag %d\n", Movie.c_str(), Quality.c_str(), Segment, ReqFragment);
|
||||||
#endif
|
#endif
|
||||||
/// \todo Handle these requests properly...
|
|
||||||
/*
|
|
||||||
Flash_ManifestSent = true;//stop manifest from being sent multiple times
|
|
||||||
Flash_RequestPending++;
|
Flash_RequestPending++;
|
||||||
*/
|
|
||||||
}else{
|
}else{
|
||||||
Movie = HTTP_R.url.substr(1);
|
Movie = HTTP_R.url.substr(1);
|
||||||
Movie = Movie.substr(0,Movie.find("/"));
|
Movie = Movie.substr(0,Movie.find("/"));
|
||||||
|
@ -251,6 +215,15 @@ namespace Connector_HTTP{
|
||||||
}//strip nonalphanumeric
|
}//strip nonalphanumeric
|
||||||
}
|
}
|
||||||
streamname += Movie;
|
streamname += Movie;
|
||||||
|
if( !Flash_ManifestSent ) {
|
||||||
|
HTTP_S.Clean();
|
||||||
|
HTTP_S.SetHeader("Content-Type","text/xml");
|
||||||
|
HTTP_S.SetHeader("Cache-Control","no-cache");
|
||||||
|
HTTP_S.SetBody(BuildManifest(Movie));
|
||||||
|
HTTP_S.SendResponse(conn, "200", "OK");
|
||||||
|
Flash_ManifestSent = true;//stop manifest from being sent multiple times
|
||||||
|
std::cout << "Sent manifest" << std::endl;
|
||||||
|
}
|
||||||
ready4data = true;
|
ready4data = true;
|
||||||
}//FLASH handler
|
}//FLASH handler
|
||||||
if (handler == HANDLER_PROGRESSIVE){
|
if (handler == HANDLER_PROGRESSIVE){
|
||||||
|
@ -282,8 +255,6 @@ namespace Connector_HTTP{
|
||||||
#endif
|
#endif
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
/// \todo Send pending flash requests...
|
|
||||||
/*
|
|
||||||
if ((Flash_RequestPending > 0) && !Flash_FragBuffer.empty()){
|
if ((Flash_RequestPending > 0) && !Flash_FragBuffer.empty()){
|
||||||
HTTP_S.Clean();
|
HTTP_S.Clean();
|
||||||
HTTP_S.SetHeader("Content-Type","video/mp4");
|
HTTP_S.SetHeader("Content-Type","video/mp4");
|
||||||
|
@ -295,7 +266,6 @@ namespace Connector_HTTP{
|
||||||
fprintf(stderr, "Sending a video fragment. %i left in buffer, %i requested\n", (int)Flash_FragBuffer.size(), Flash_RequestPending);
|
fprintf(stderr, "Sending a video fragment. %i left in buffer, %i requested\n", (int)Flash_FragBuffer.size(), Flash_RequestPending);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if (inited){
|
if (inited){
|
||||||
unsigned int now = time(0);
|
unsigned int now = time(0);
|
||||||
if (now != lastStats){
|
if (now != lastStats){
|
||||||
|
@ -309,7 +279,7 @@ namespace Connector_HTTP{
|
||||||
if (Strm.parsePacket(ss.Received())){
|
if (Strm.parsePacket(ss.Received())){
|
||||||
tag.DTSCLoader(Strm);
|
tag.DTSCLoader(Strm);
|
||||||
if (handler == HANDLER_FLASH){
|
if (handler == HANDLER_FLASH){
|
||||||
FlashDynamic(tag, HTTP_S, conn, Strm);
|
FlashDynamic(tag, Strm);
|
||||||
}
|
}
|
||||||
if (handler == HANDLER_PROGRESSIVE){
|
if (handler == HANDLER_PROGRESSIVE){
|
||||||
Progressive(tag, HTTP_S, conn, Strm);
|
Progressive(tag, HTTP_S, conn, Strm);
|
||||||
|
|
Loading…
Add table
Reference in a new issue