Working MP4 intro
This commit is contained in:
		
							parent
							
								
									07fad893ab
								
							
						
					
					
						commit
						df6ea8eb0d
					
				
					 3 changed files with 127 additions and 173 deletions
				
			
		|  | @ -8,7 +8,7 @@ EXTRA_DIST=server.html server.html.h embed.js.h | ||||||
| AM_CPPFLAGS = $(global_CFLAGS) $(MIST_CFLAGS) | AM_CPPFLAGS = $(global_CFLAGS) $(MIST_CFLAGS) | ||||||
| LDADD = $(MIST_LIBS) | LDADD = $(MIST_LIBS) | ||||||
| SUBDIRS=converters analysers | SUBDIRS=converters analysers | ||||||
| bin_PROGRAMS=MistBuffer MistController MistConnRAW MistConnRTMP MistConnHTTP MistConnHTTPProgressive MistConnHTTPDynamic MistPlayer | bin_PROGRAMS=MistBuffer MistController MistConnRAW MistConnRTMP MistConnHTTP MistConnHTTPProgressive MistConnHTTPDynamic MistConnHTTPSmooth MistPlayer | ||||||
| MistBuffer_SOURCES=buffer.cpp buffer_user.h buffer_user.cpp buffer_stream.h buffer_stream.cpp tinythread.cpp tinythread.h ../VERSION | MistBuffer_SOURCES=buffer.cpp buffer_user.h buffer_user.cpp buffer_stream.h buffer_stream.cpp tinythread.cpp tinythread.h ../VERSION | ||||||
| MistBuffer_LDADD=$(MIST_LIBS) -lpthread | MistBuffer_LDADD=$(MIST_LIBS) -lpthread | ||||||
| MistController_SOURCES=controller.cpp ../VERSION ./server.html.h | MistController_SOURCES=controller.cpp ../VERSION ./server.html.h | ||||||
|  | @ -18,6 +18,7 @@ MistConnHTTP_SOURCES=conn_http.cpp tinythread.cpp tinythread.h ../VERSION ./embe | ||||||
| MistConnHTTP_LDADD=$(MIST_LIBS) -lpthread | MistConnHTTP_LDADD=$(MIST_LIBS) -lpthread | ||||||
| MistConnHTTPProgressive_SOURCES=conn_http_progressive.cpp ../VERSION | MistConnHTTPProgressive_SOURCES=conn_http_progressive.cpp ../VERSION | ||||||
| MistConnHTTPDynamic_SOURCES=conn_http_dynamic.cpp ../VERSION | MistConnHTTPDynamic_SOURCES=conn_http_dynamic.cpp ../VERSION | ||||||
|  | MistConnHTTPSmooth_SOURCES=conn_http_smooth.cpp ../VERSION | ||||||
| MistPlayer_SOURCES=player.cpp | MistPlayer_SOURCES=player.cpp | ||||||
| MistPlayer_LDADD=$(MIST_LIBS) | MistPlayer_LDADD=$(MIST_LIBS) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -318,6 +318,12 @@ namespace Connector_HTTP{ | ||||||
|       H.SetVar("stream", streamname); |       H.SetVar("stream", streamname); | ||||||
|       return "dynamic"; |       return "dynamic"; | ||||||
|     } |     } | ||||||
|  |     if (url.find("/smooth/") != std::string::npos ) { | ||||||
|  |       std::string streamname = url.substr(8,url.find("/",8)-8); | ||||||
|  |       Util::Stream::sanitizeName(streamname); | ||||||
|  |       H.SetVar("stream", streamname); | ||||||
|  |       return "smooth"; | ||||||
|  |     } | ||||||
|     if (url.length() > 4){ |     if (url.length() > 4){ | ||||||
|       std::string ext = url.substr(url.length() - 4, 4); |       std::string ext = url.substr(url.length() - 4, 4); | ||||||
|       if (ext == ".flv" || ext == ".mp3"){ |       if (ext == ".flv" || ext == ".mp3"){ | ||||||
|  | @ -404,7 +410,8 @@ int main(int argc, char ** argv){ | ||||||
|   //start progressive and dynamic handlers from the same folder as this application
 |   //start progressive and dynamic handlers from the same folder as this application
 | ||||||
|   Util::Procs::Start("progressive", Util::getMyPath() + "MistConnHTTPProgressive -n"); |   Util::Procs::Start("progressive", Util::getMyPath() + "MistConnHTTPProgressive -n"); | ||||||
|   Util::Procs::Start("dynamic", Util::getMyPath() + "MistConnHTTPDynamic -n"); |   Util::Procs::Start("dynamic", Util::getMyPath() + "MistConnHTTPDynamic -n"); | ||||||
|    |   Util::Procs::Start("smooth", Util::getMyPath() + "MistConnHTTPSmooth -n"); | ||||||
|  | 
 | ||||||
|   while (server_socket.connected() && conf.is_active){ |   while (server_socket.connected() && conf.is_active){ | ||||||
|     Socket::Connection S = server_socket.accept(); |     Socket::Connection S = server_socket.accept(); | ||||||
|     if (S.connected()){//check if the new connection is valid
 |     if (S.connected()){//check if the new connection is valid
 | ||||||
|  |  | ||||||
|  | @ -25,136 +25,55 @@ | ||||||
| 
 | 
 | ||||||
| /// Holds everything unique to HTTP Dynamic Connector.
 | /// Holds everything unique to HTTP Dynamic Connector.
 | ||||||
| namespace Connector_HTTP{ | namespace Connector_HTTP{ | ||||||
| 
 |   /// Returns a Smooth-format manifest file
 | ||||||
|   std::string GenerateBootstrap(std::string & MovieId, JSON::Value & metadata, int fragnum, int starttime, int endtime){ |  | ||||||
|     std::string empty; |  | ||||||
| 
 |  | ||||||
|     MP4::ASRT asrt; |  | ||||||
|     if (starttime == 0){ |  | ||||||
|       asrt.setUpdate(false); |  | ||||||
|     }else{ |  | ||||||
|       asrt.setUpdate(true); |  | ||||||
|     } |  | ||||||
|     asrt.setVersion(1); |  | ||||||
|     asrt.setQualityEntry(empty, 0); |  | ||||||
|     if (!metadata.isMember("keytime") || metadata["keytime"].size() == 0){ |  | ||||||
|       asrt.setSegmentRun(1, 20000, 0); |  | ||||||
|     }else{ |  | ||||||
|       asrt.setSegmentRun(1, metadata["keytime"].size(), 0); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     MP4::AFRT afrt; |  | ||||||
|     if (starttime == 0){ |  | ||||||
|       afrt.setUpdate(false); |  | ||||||
|     }else{ |  | ||||||
|       afrt.setUpdate(true); |  | ||||||
|     } |  | ||||||
|     afrt.setVersion(1); |  | ||||||
|     afrt.setTimeScale(1000); |  | ||||||
|     afrt.setQualityEntry(empty, 0); |  | ||||||
|     MP4::afrt_runtable afrtrun; |  | ||||||
|     if (!metadata.isMember("keytime") || metadata["keytime"].size() == 0){ |  | ||||||
|       afrtrun.firstFragment = 1; |  | ||||||
|       afrtrun.firstTimestamp = 0; |  | ||||||
|       if (!metadata.isMember("video") || !metadata["video"].isMember("keyms") || metadata["video"]["keyms"].asInt() == 0){ |  | ||||||
|         afrtrun.duration = 2000; |  | ||||||
|       }else{ |  | ||||||
|         afrtrun.duration = metadata["video"]["keyms"].asInt(); |  | ||||||
|       } |  | ||||||
|       afrt.setFragmentRun(afrtrun, 0); |  | ||||||
|     }else{ |  | ||||||
|       for (int i = 0; i < metadata["keytime"].size(); i++){ |  | ||||||
|         afrtrun.firstFragment = i+1; |  | ||||||
|         afrtrun.firstTimestamp = metadata["keytime"][i].asInt(); |  | ||||||
|         if (i+1 < metadata["keytime"].size()){ |  | ||||||
|           afrtrun.duration = metadata["keytime"][i+1].asInt() - metadata["keytime"][i].asInt(); |  | ||||||
|         }else{ |  | ||||||
|           if (metadata["lastms"].asInt()){ |  | ||||||
|             afrtrun.duration = metadata["lastms"].asInt() - metadata["keytime"][i].asInt(); |  | ||||||
|           }else{ |  | ||||||
|             afrtrun.duration = 3000;//guess 3 seconds if unknown
 |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         afrt.setFragmentRun(afrtrun, i); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     MP4::ABST abst; |  | ||||||
|     abst.setVersion(1); |  | ||||||
|     abst.setBootstrapinfoVersion(1); |  | ||||||
|     abst.setProfile(0); |  | ||||||
|     if (starttime == 0){ |  | ||||||
|       abst.setUpdate(false); |  | ||||||
|     }else{ |  | ||||||
|       abst.setUpdate(true); |  | ||||||
|     } |  | ||||||
|     abst.setTimeScale(1000); |  | ||||||
|     if (metadata.isMember("length") && metadata["length"].asInt() > 0){ |  | ||||||
|       abst.setLive(false); |  | ||||||
|       if (metadata["lastms"].asInt()){ |  | ||||||
|         abst.setCurrentMediaTime(metadata["lastms"].asInt()); |  | ||||||
|       }else{ |  | ||||||
|         abst.setCurrentMediaTime(1000*metadata["length"].asInt()); |  | ||||||
|       } |  | ||||||
|     }else{ |  | ||||||
|       abst.setLive(true); |  | ||||||
|       abst.setCurrentMediaTime(0xFFFFFFFF); |  | ||||||
|     } |  | ||||||
|     abst.setSmpteTimeCodeOffset(0); |  | ||||||
|     abst.setMovieIdentifier(MovieId); |  | ||||||
|     abst.setServerEntry(empty, 0); |  | ||||||
|     abst.setQualityEntry(empty, 0); |  | ||||||
|     abst.setDrmData(empty); |  | ||||||
|     abst.setMetaData(empty); |  | ||||||
|     abst.setSegmentRunTable(asrt, 0); |  | ||||||
|     abst.setFragmentRunTable(afrt, 0); |  | ||||||
| 
 |  | ||||||
|     #if DEBUG >= 8 |  | ||||||
|     std::cout << "Sending bootstrap:" << std::endl << abst.toPrettyString(0) << std::endl; |  | ||||||
|     #endif |  | ||||||
|     return std::string((char*)abst.asBox(), (int)abst.boxedSize()); |  | ||||||
|   } |  | ||||||
|    |  | ||||||
| 
 |  | ||||||
|   /// Returns a F4M-format manifest file
 |  | ||||||
|   std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){ |   std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){ | ||||||
|     std::string Result; |     std::stringstream Result; | ||||||
|     if (metadata.isMember("length") && metadata["length"].asInt() > 0){ |     Result << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; | ||||||
|       Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" |     Result << "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" TimeScale=\"1000\" Duration=\"" << metadata["lastms"].asInt() << "\">\n"; | ||||||
|       "<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n" |     if( metadata.isMember( "audio" ) ) { | ||||||
|       "<id>" + MovieId + "</id>\n" |       Result << "  <StreamIndex Type=\"audio\" QualityLevels=\"1\" TimeScale=\"1000\" Name=\"audio\" Chunks=\"" << metadata["keytime"].size() << "\" Url=\"Q({bitrate})/A({start time})\">\n"; | ||||||
|       "<width>" + metadata["video"]["width"].asString() + "</width>\n" |       Result << "    <QualityLevel Index=\"0\" Bitrate=\"" << metadata["audio"]["bps"].asInt()*8 << "\" CodecPrivateData=\""; | ||||||
|       "<height>" + metadata["video"]["height"].asString() + "</height>\n" |       Result << std::hex; | ||||||
|       "<duration>" + metadata["length"].asString() + ".000</duration>\n" |       for( int i = 0; i < metadata["audio"]["init"].asString().size(); i++ ) { | ||||||
|       "<mimeType>video/mp4</mimeType>\n" |         Result << (int)metadata["audio"]["init"].asString()[i]; | ||||||
|       "<streamType>recorded</streamType>\n" |       } | ||||||
|       "<deliveryType>streaming</deliveryType>\n" |       Result << std::dec; | ||||||
|       "<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0, 0)) + "</bootstrapInfo>\n" |       Result << "\" SamplingRate=\"" << metadata["audio"]["rate"].asInt() << "\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" FourCC=\"AACL\" />\n"; | ||||||
|       "<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\">\n" |       for( int i = 0; i < metadata["keytime"].size(); i++ ) { | ||||||
|       "<metadata>AgAKb25NZXRhRGF0YQgAAAAAAAl0cmFja2luZm8KAAAAAgMACXRpbWVzY2FsZQBA+GoAAAAAAAAGbGVuZ3RoAEGMcHoQAAAAAAhsYW5ndWFnZQIAA2VuZwARc2FtcGxlZGVzY3JpcHRpb24KAAAAAQMACnNhbXBsZXR5cGUCAARhdmMxAAAJAAAJAwAJdGltZXNjYWxlAEDncAAAAAAAAAZsZW5ndGgAQXtNvTAAAAAACGxhbmd1YWdlAgADZW5nABFzYW1wbGVkZXNjcmlwdGlvbgoAAAABAwAKc2FtcGxldHlwZQIABG1wNGEAAAkAAAkADWF1ZGlvY2hhbm5lbHMAQAAAAAAAAAAAD2F1ZGlvc2FtcGxlcmF0ZQBA53AAAAAAAAAOdmlkZW9mcmFtZXJhdGUAQDf/gi5SciUABmFhY2FvdABAAAAAAAAAAAAIYXZjbGV2ZWwAQD8AAAAAAAAACmF2Y3Byb2ZpbGUAQFNAAAAAAAAADGF1ZGlvY29kZWNpZAIABG1wNGEADHZpZGVvY29kZWNpZAIABGF2YzEABXdpZHRoAECQ4AAAAAAAAAZoZWlnaHQAQIMAAAAAAAAACmZyYW1lV2lkdGgAQJDgAAAAAAAAC2ZyYW1lSGVpZ2h0AECDAAAAAAAAAAxkaXNwbGF5V2lkdGgAQJDgAAAAAAAADWRpc3BsYXlIZWlnaHQAQIMAAAAAAAAADG1vb3Zwb3NpdGlvbgBBmxq2uAAAAAAIZHVyYXRpb24AQIKjqW3oyhIAAAk=</metadata>\n" |         Result << "      <c "; | ||||||
|       "</media>\n" |         if( i == 0 ) { Result << "t=\"0\" "; } | ||||||
|       "</manifest>\n"; |         Result << "d=\"" << metadata["keytime"][i].asInt() << "\"/>\n"; | ||||||
|     }else{ |       } | ||||||
|       Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" |       Result << "   </StreamIndex>\n"; | ||||||
|       "<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n" |  | ||||||
|       "<id>" + MovieId + "</id>\n" |  | ||||||
|       "<mimeType>video/mp4</mimeType>\n" |  | ||||||
|       "<streamType>live</streamType>\n" |  | ||||||
|       "<deliveryType>streaming</deliveryType>\n" |  | ||||||
|       "<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0, 0)) + "</bootstrapInfo>\n" |  | ||||||
|       "<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\"></media>\n" |  | ||||||
|       "</manifest>\n"; |  | ||||||
|     } |     } | ||||||
|  |     if( metadata.isMember( "video" ) ) { | ||||||
|  |       Result << "  <StreamIndex Type=\"video\" QualityLevels=\"1\" TimeScale=\"1000\" Name=\"video\" Chunks=\"" << metadata["keytime"].size() << "\" Url=\"Q({bitrate})/V({start time})\" MaxWidth=\"" << metadata["video"]["width"].asInt() << "\" MaxHeight=\"" << metadata["video"]["height"].asInt() << "\" DisplayWidth=\"" << metadata["video"]["width"].asInt() << "\" DisplayHeight=\"" << metadata["video"]["height"].asInt() << "\">\n"; | ||||||
|  |       Result << "    <QualityLevel Index=\"0\" Bitrate=\"" << metadata["video"]["bps"].asInt()*8 << "\" CodecPrivateData=\""; | ||||||
|  |       Result << std::hex; | ||||||
|  |       for( int i = 0; i < metadata["video"]["init"].asString().size(); i++ ) { | ||||||
|  |         Result << (int)metadata["video"]["init"].asString()[i]; | ||||||
|  |       } | ||||||
|  |       Result << std::dec; | ||||||
|  |       Result << "\" MaxWidth=\"" << metadata["video"]["width"].asInt() << "\" MaxHeight=\"" << metadata["video"]["height"].asInt() << "\" FourCC=\"AVC1\"/>\n"; | ||||||
|  |       for( int i = 0; i < metadata["keytime"].size(); i++ ) { | ||||||
|  |         Result << "      <c "; | ||||||
|  |         if( i == 0 ) { Result << "t=\"0\" "; } | ||||||
|  |         Result << "d=\"" << metadata["keytime"][i].asInt() << "\"/>\n"; | ||||||
|  |       } | ||||||
|  |       Result << "   </StreamIndex>\n"; | ||||||
|  |     } | ||||||
|  |     Result << "</SmoothStreamingMedia>\n"; | ||||||
|  |        | ||||||
|     #if DEBUG >= 8 |     #if DEBUG >= 8 | ||||||
|     std::cerr << "Sending this manifest:" << std::endl << Result << std::endl; |     std::cerr << "Sending this manifest:" << std::endl << Result << std::endl; | ||||||
|     #endif |     #endif | ||||||
|     return Result; |     return Result.str(); | ||||||
|   }//BuildManifest
 |   }//BuildManifest
 | ||||||
| 
 | 
 | ||||||
|   /// Main function for Connector_HTTP_Dynamic
 |   /// Main function for Connector_HTTP_Dynamic
 | ||||||
|   int Connector_HTTP_Dynamic(Socket::Connection conn){ |   int Connector_HTTP_Dynamic(Socket::Connection conn){ | ||||||
|     std::deque<std::string> FlashBuf; |     std::deque<std::string> FlashBuf; | ||||||
|  |     std::vector<int> Timestamps; | ||||||
|     int FlashBufSize = 0; |     int FlashBufSize = 0; | ||||||
|     long long int FlashBufTime = 0; |     long long int FlashBufTime = 0; | ||||||
|     FLV::Tag tmp;//temporary tag
 |     FLV::Tag tmp;//temporary tag
 | ||||||
|  | @ -170,10 +89,14 @@ namespace Connector_HTTP{ | ||||||
|     std::string streamname; |     std::string streamname; | ||||||
|     std::string recBuffer = ""; |     std::string recBuffer = ""; | ||||||
| 
 | 
 | ||||||
|  |     bool wantsVideo = false; | ||||||
|  |     bool wantsAudio = false; | ||||||
|  |      | ||||||
|     std::string Quality; |     std::string Quality; | ||||||
|     int Segment = -1; |     int Segment = -1; | ||||||
|     int ReqFragment = -1; |     int ReqFragment = -1; | ||||||
|     int temp; |     int temp; | ||||||
|  |     std::string tempStr; | ||||||
|     int Flash_RequestPending = 0; |     int Flash_RequestPending = 0; | ||||||
|     unsigned int lastStats = 0; |     unsigned int lastStats = 0; | ||||||
|     conn.setBlocking(false);//do not block on conn.spool() when no data is available
 |     conn.setBlocking(false);//do not block on conn.spool() when no data is available
 | ||||||
|  | @ -195,8 +118,8 @@ namespace Connector_HTTP{ | ||||||
|           std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; |           std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; | ||||||
|           #endif |           #endif | ||||||
|           conn.setHost(HTTP_R.GetHeader("X-Origin")); |           conn.setHost(HTTP_R.GetHeader("X-Origin")); | ||||||
|           if (HTTP_R.url.find("f4m") == std::string::npos){ |           if (HTTP_R.url.find("Manifest") == std::string::npos){ | ||||||
|             streamname = HTTP_R.url.substr(1,HTTP_R.url.find("/",1)-1); |             streamname = HTTP_R.url.substr(8,HTTP_R.url.find("/",8)-8); | ||||||
|             if (!ss){ |             if (!ss){ | ||||||
|               ss = Util::Stream::getStream(streamname); |               ss = Util::Stream::getStream(streamname); | ||||||
|               if (!ss.connected()){ |               if (!ss.connected()){ | ||||||
|  | @ -205,7 +128,7 @@ namespace Connector_HTTP{ | ||||||
|                 #endif |                 #endif | ||||||
|                 ss.close(); |                 ss.close(); | ||||||
|                 HTTP_S.Clean(); |                 HTTP_S.Clean(); | ||||||
|                 HTTP_S.SetBody("No such stream is available on the system. Please try again.\n"); |                 HTTP_S.SetBody("No such stream " + streamname + " is available on the system. Please try again.\n"); | ||||||
|                 conn.SendNow(HTTP_S.BuildResponse("404", "Not found")); |                 conn.SendNow(HTTP_S.BuildResponse("404", "Not found")); | ||||||
|                 ready4data = false; |                 ready4data = false; | ||||||
|                 continue; |                 continue; | ||||||
|  | @ -213,21 +136,22 @@ namespace Connector_HTTP{ | ||||||
|               ss.setBlocking(false); |               ss.setBlocking(false); | ||||||
|               inited = true; |               inited = true; | ||||||
|             } |             } | ||||||
|             Quality = HTTP_R.url.substr( HTTP_R.url.find("/",1)+1 ); |             Quality = HTTP_R.url.substr( HTTP_R.url.find("/Q(",8)+3 ); | ||||||
|             Quality = Quality.substr(0, Quality.find("Seg")); |             Quality = Quality.substr(0, Quality.find(")")); | ||||||
|             temp = HTTP_R.url.find("Seg") + 3; |             tempStr = HTTP_R.url.substr( HTTP_R.url.find(")/") + 2 ); | ||||||
|             Segment = atoi( HTTP_R.url.substr(temp,HTTP_R.url.find("-",temp)-temp).c_str()); |             if( tempStr[0] == 'A' ) { wantsAudio = true; } | ||||||
|             temp = HTTP_R.url.find("Frag") + 4; |             if( tempStr[0] == 'V' ) { wantsVideo = true; } | ||||||
|             ReqFragment = atoi( HTTP_R.url.substr(temp).c_str() ); |             tempStr = tempStr.find("(") + 1; | ||||||
|  |             ReqFragment = atoi( tempStr.substr(0,tempStr.find(")")).c_str() ); | ||||||
|             #if DEBUG >= 4 |             #if DEBUG >= 4 | ||||||
|             printf( "Quality: %s, Seg %d Frag %d\n", Quality.c_str(), Segment, ReqFragment); |             printf( "Quality: %s, Frag %d\n", Quality.c_str(), ReqFragment); | ||||||
|             #endif |             #endif | ||||||
|             std::stringstream sstream; |             std::stringstream sstream; | ||||||
|             sstream << "f " << ReqFragment << "\no \n"; |             sstream << "s " << ReqFragment << "\no \n"; | ||||||
|             ss.SendNow(sstream.str().c_str()); |             ss.SendNow(sstream.str().c_str()); | ||||||
|             Flash_RequestPending++; |             Flash_RequestPending++; | ||||||
|           }else{ |           }else{ | ||||||
|             streamname = HTTP_R.url.substr(1,HTTP_R.url.find("/",1)-1); |             streamname = HTTP_R.url.substr(8,HTTP_R.url.find("/",8)-8); | ||||||
|             if (!Strm.metadata.isNull()){ |             if (!Strm.metadata.isNull()){ | ||||||
|               HTTP_S.Clean(); |               HTTP_S.Clean(); | ||||||
|               HTTP_S.SetHeader("Content-Type","text/xml"); |               HTTP_S.SetHeader("Content-Type","text/xml"); | ||||||
|  | @ -264,7 +188,7 @@ namespace Connector_HTTP{ | ||||||
|             #endif |             #endif | ||||||
|             ss.close(); |             ss.close(); | ||||||
|             HTTP_S.Clean(); |             HTTP_S.Clean(); | ||||||
|             HTTP_S.SetBody("No such stream is available on the system. Please try again.\n"); |             HTTP_S.SetBody("No such stream " + streamname + " is available on the system. Please try again.\n"); | ||||||
|             conn.SendNow(HTTP_S.BuildResponse("404", "Not found")); |             conn.SendNow(HTTP_S.BuildResponse("404", "Not found")); | ||||||
|             ready4data = false; |             ready4data = false; | ||||||
|             continue; |             continue; | ||||||
|  | @ -278,7 +202,7 @@ namespace Connector_HTTP{ | ||||||
|         unsigned int now = Util::epoch(); |         unsigned int now = Util::epoch(); | ||||||
|         if (now != lastStats){ |         if (now != lastStats){ | ||||||
|           lastStats = now; |           lastStats = now; | ||||||
|           ss.SendNow(conn.getStats("HTTP_Dynamic").c_str()); |           ss.SendNow(conn.getStats("HTTP_Smooth").c_str()); | ||||||
|         } |         } | ||||||
|         if (ss.spool()){ |         if (ss.spool()){ | ||||||
|           while (Strm.parsePacket(ss.Received())){ |           while (Strm.parsePacket(ss.Received())){ | ||||||
|  | @ -306,6 +230,9 @@ namespace Connector_HTTP{ | ||||||
|               pending_manifest = false; |               pending_manifest = false; | ||||||
|             } |             } | ||||||
|             if (!receive_marks && Strm.metadata.isMember("length")){receive_marks = true;} |             if (!receive_marks && Strm.metadata.isMember("length")){receive_marks = true;} | ||||||
|  |             if ( Strm.lastType() == DTSC::PAUSEMARK ) { | ||||||
|  |               Timestamps.push_back( Strm.getPacket(0)["time"].asInt() ); | ||||||
|  |             } | ||||||
|             if ((Strm.getPacket(0).isMember("keyframe") && !receive_marks) || Strm.lastType() == DTSC::PAUSEMARK){ |             if ((Strm.getPacket(0).isMember("keyframe") && !receive_marks) || Strm.lastType() == DTSC::PAUSEMARK){ | ||||||
|               #if DEBUG >= 4 |               #if DEBUG >= 4 | ||||||
|               fprintf(stderr, "Received a %s fragment of %i bytes.\n", Strm.getPacket(0)["datatype"].asString().c_str(), FlashBufSize); |               fprintf(stderr, "Received a %s fragment of %i bytes.\n", Strm.getPacket(0)["datatype"].asString().c_str(), FlashBufSize); | ||||||
|  | @ -319,21 +246,51 @@ namespace Connector_HTTP{ | ||||||
|                 HTTP_S.Clean(); |                 HTTP_S.Clean(); | ||||||
|                 HTTP_S.SetHeader("Content-Type", "video/mp4"); |                 HTTP_S.SetHeader("Content-Type", "video/mp4"); | ||||||
|                 HTTP_S.SetBody(""); |                 HTTP_S.SetBody(""); | ||||||
|                 HTTP_S.SetHeader("Content-Length", FlashBufSize+8);//32+33+btstrp.size());
 |                  | ||||||
|  |                 MP4::MFHD mfhd_box; | ||||||
|  |                 mfhd_box.setSequenceNumber( 1 ); | ||||||
|  |                  | ||||||
|  |                 MP4::TFHD tfhd_box; | ||||||
|  |                 tfhd_box.setFlags( MP4::tfhdSampleFlag ); | ||||||
|  |                 tfhd_box.setTrackID( 1 ); | ||||||
|  |                 tfhd_box.setDefaultSampleFlags( MP4::noIPicture | MP4::noDisposable | MP4::noKeySample ); | ||||||
|  |                  | ||||||
|  |                 MP4::TRUN trun_box; | ||||||
|  |                 //maybe reinsert dataOffset
 | ||||||
|  |                 trun_box.setFlags( MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize ); | ||||||
|  |                 trun_box.setFirstSampleFlags( MP4::isIPicture | MP4::noDisposable | MP4::isKeySample ); | ||||||
|  |                 std::deque< std::string >::iterator FlashBufIter = FlashBuf.begin(); | ||||||
|  |                 for( int i = 0; i < FlashBuf.size(); i++ ) { | ||||||
|  |                   MP4::trunSampleInformation trunSample; | ||||||
|  |                   trunSample.sampleSize = (*FlashBufIter).size(); | ||||||
|  |                   trunSample.sampleDuration = Timestamps[i+1]-Timestamps[i]; | ||||||
|  |                   trun_box.setSampleInformation( trunSample, i ); | ||||||
|  |                   FlashBufIter ++; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 MP4::Box sdtp_box; | ||||||
|  |                 sdtp_box.setType( "sdtp" ); | ||||||
|  |                 sdtp_box.setInt32( 0, 0 ); | ||||||
|  |                 sdtp_box.setInt8( 0x24, 4 ); | ||||||
|  |                 for( int i = 1; i < FlashBuf.size(); i++ ) { | ||||||
|  |                   sdtp_box.setInt8( 0x14, i+4 ); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 MP4::TRAF traf_box; | ||||||
|  |                 traf_box.setContent( tfhd_box, 0 ); | ||||||
|  |                 traf_box.setContent( trun_box, 1 ); | ||||||
|  |                 traf_box.setContent( sdtp_box, 2 ); | ||||||
|  |                  | ||||||
|  |                 MP4::MOOF moof_box; | ||||||
|  |                 moof_box.setContent( mfhd_box, 0 ); | ||||||
|  |                 moof_box.setContent( traf_box, 1 ); | ||||||
|  |                  | ||||||
|  |                 HTTP_S.SetHeader("Content-Length", FlashBufSize+8+moof_box.boxedSize());//32+33+btstrp.size());
 | ||||||
|                 conn.SendNow(HTTP_S.BuildResponse("200", "OK")); |                 conn.SendNow(HTTP_S.BuildResponse("200", "OK")); | ||||||
|                 //conn.SendNow("\x00\x00\x00\x21" "afra\x00\x00\x00\x00\x00\x00\x00\x03\xE8\x00\x00\x00\x01", 21);
 |                  | ||||||
|                 //unsigned long tmptime = htonl(FlashBufTime << 32);
 |  | ||||||
|                 //conn.SendNow((char*)&tmptime, 4);
 |  | ||||||
|                 //tmptime = htonl(FlashBufTime & 0xFFFFFFFF);
 |  | ||||||
|                 //conn.SendNow((char*)&tmptime, 4);
 |  | ||||||
|                 //tmptime = htonl(65);
 |  | ||||||
|                 //conn.SendNow((char*)&tmptime, 4);
 |  | ||||||
| 
 | 
 | ||||||
|                 //conn.SendNow(btstrp);
 |                 conn.SendNow( moof_box.asBox(), moof_box.boxedSize() ); | ||||||
| 
 |                  | ||||||
|                 //conn.SendNow("\x00\x00\x00\x18moof\x00\x00\x00\x10mfhd\x00\x00\x00\x00", 20);
 |  | ||||||
|                 //unsigned long fragno = htonl(ReqFragment);
 |  | ||||||
|                 //conn.SendNow((char*)&fragno, 4);
 |  | ||||||
|                 unsigned long size = htonl(FlashBufSize+8); |                 unsigned long size = htonl(FlashBufSize+8); | ||||||
|                 conn.SendNow((char*)&size, 4); |                 conn.SendNow((char*)&size, 4); | ||||||
|                 conn.SendNow("mdat", 4); |                 conn.SendNow("mdat", 4); | ||||||
|  | @ -349,26 +306,15 @@ namespace Connector_HTTP{ | ||||||
|               FlashBuf.clear(); |               FlashBuf.clear(); | ||||||
|               FlashBufSize = 0; |               FlashBufSize = 0; | ||||||
|             } |             } | ||||||
|             if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){ |             if ( wantsVideo && Strm.lastType() == DTSC::VIDEO ) { | ||||||
|               if (FlashBufSize == 0){ |               FlashBuf.push_back( Strm.lastData() ); | ||||||
|                 //fill buffer with init data, if needed.
 |               FlashBufSize += Strm.lastData().size(); | ||||||
|                 if (Strm.metadata.isMember("audio") && Strm.metadata["audio"].isMember("init")){ |               Timestamps.push_back( Strm.getPacket(0)["time"].asInt() ); | ||||||
|                   tmp.DTSCAudioInit(Strm); |             } | ||||||
|                   tmp.tagTime(Strm.getPacket(0)["time"].asInt()); |             if ( wantsAudio && Strm.lastType() == DTSC::AUDIO ) { | ||||||
|                   FlashBuf.push_back(std::string(tmp.data, tmp.len)); |               FlashBuf.push_back( Strm.lastData() ); | ||||||
|                   FlashBufSize += tmp.len; |               FlashBufSize += Strm.lastData().size(); | ||||||
|                 } |               Timestamps.push_back( Strm.getPacket(0)["time"].asInt() ); | ||||||
|                 if (Strm.metadata.isMember("video") && Strm.metadata["video"].isMember("init")){ |  | ||||||
|                   tmp.DTSCVideoInit(Strm); |  | ||||||
|                   tmp.tagTime(Strm.getPacket(0)["time"].asInt()); |  | ||||||
|                   FlashBuf.push_back(std::string(tmp.data, tmp.len)); |  | ||||||
|                   FlashBufSize += tmp.len; |  | ||||||
|                 } |  | ||||||
|                 FlashBufTime = Strm.getPacket(0)["time"].asInt(); |  | ||||||
|               } |  | ||||||
|               tmp.DTSCLoader(Strm); |  | ||||||
|               FlashBuf.push_back(std::string(tmp.data, tmp.len)); |  | ||||||
|               FlashBufSize += tmp.len; |  | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|           if (pending_manifest && !Strm.metadata.isNull()){ |           if (pending_manifest && !Strm.metadata.isNull()){ | ||||||
|  | @ -389,7 +335,7 @@ namespace Connector_HTTP{ | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     conn.close(); |     conn.close(); | ||||||
|     ss.SendNow(conn.getStats("HTTP_Dynamic").c_str()); |     ss.SendNow(conn.getStats("HTTP_Smooth").c_str()); | ||||||
|     ss.close(); |     ss.close(); | ||||||
|     #if DEBUG >= 1 |     #if DEBUG >= 1 | ||||||
|     if (FLV::Parse_Error){fprintf(stderr, "FLV Parser Error: %s\n", FLV::Error_Str.c_str());} |     if (FLV::Parse_Error){fprintf(stderr, "FLV Parser Error: %s\n", FLV::Error_Str.c_str());} | ||||||
|  | @ -405,15 +351,15 @@ namespace Connector_HTTP{ | ||||||
|     } |     } | ||||||
|     #endif |     #endif | ||||||
|     return 0; |     return 0; | ||||||
|   }//Connector_HTTP_Dynamic main function
 |   }//Connector_HTTP_Smooth main function
 | ||||||
| 
 | 
 | ||||||
| };//Connector_HTTP_Dynamic namespace
 | };//Connector_HTTP_Smooth namespace
 | ||||||
| 
 | 
 | ||||||
| int main(int argc, char ** argv){ | int main(int argc, char ** argv){ | ||||||
|   Util::Config conf(argv[0], PACKAGE_VERSION); |   Util::Config conf(argv[0], PACKAGE_VERSION); | ||||||
|   conf.addConnectorOptions(1935); |   conf.addConnectorOptions(1935); | ||||||
|   conf.parseArgs(argc, argv); |   conf.parseArgs(argc, argv); | ||||||
|   Socket::Server server_socket = Socket::Server("/tmp/mist/http_dynamic"); |   Socket::Server server_socket = Socket::Server("/tmp/mist/http_smooth"); | ||||||
|   if (!server_socket.connected()){return 1;} |   if (!server_socket.connected()){return 1;} | ||||||
|   conf.activate(); |   conf.activate(); | ||||||
|    |    | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Erik Zandvliet
						Erik Zandvliet