Fixed HTTP Connector F4V support.

This commit is contained in:
Thulinma 2012-04-10 17:01:09 +02:00
parent 9b6e220b88
commit b0880215df

View file

@ -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);