Added more ISO639 support (2-letter codes and conversions), improved audio/video/subtitle selection through HTTP connectors
This commit is contained in:
		
							parent
							
								
									e09cd5308e
								
							
						
					
					
						commit
						307d14f901
					
				
					 7 changed files with 1332 additions and 607 deletions
				
			
		
							
								
								
									
										1728
									
								
								lib/langcodes.cpp
									
										
									
									
									
								
							
							
						
						
									
										1728
									
								
								lib/langcodes.cpp
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -5,6 +5,8 @@ namespace Encodings {
 | 
				
			||||||
  class ISO639{
 | 
					  class ISO639{
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
      static std::string decode(const std::string & lang);
 | 
					      static std::string decode(const std::string & lang);
 | 
				
			||||||
 | 
					      static std::string twoToThree(const std::string & lang);
 | 
				
			||||||
 | 
					      static std::string encode(const std::string & lang);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <netdb.h>
 | 
					#include <netdb.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <mist/langcodes.h>
 | 
				
			||||||
/*LTS-END*/
 | 
					/*LTS-END*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Mist{
 | 
					namespace Mist{
 | 
				
			||||||
| 
						 | 
					@ -392,11 +393,81 @@ namespace Mist{
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*LTS-START*/
 | 
				
			||||||
 | 
					  /// Selects a specific track or set of tracks of the given trackType, using trackVal to decide.
 | 
				
			||||||
 | 
					  /// trackVal may be a comma-separated list of numbers, codecs or the word "all" or an asterisk.
 | 
				
			||||||
 | 
					  /// Does not do any checks if the protocol supports these tracks, just selects blindly.
 | 
				
			||||||
 | 
					  /// It is necessary to follow up with a selectDefaultTracks() call to strip unsupported codecs/combinations.
 | 
				
			||||||
 | 
					  void Output::selectTrack(const std::string &trackType, const std::string &trackVal){
 | 
				
			||||||
 | 
					    if (!trackVal.size() || trackVal == "0"){return;}//don't select anything in particular
 | 
				
			||||||
 | 
					    if (trackVal.find(',') != std::string::npos){
 | 
				
			||||||
 | 
					      //Comma-separated list, recurse.
 | 
				
			||||||
 | 
					      std::stringstream ss(trackVal);
 | 
				
			||||||
 | 
					      std::string item;
 | 
				
			||||||
 | 
					      while (std::getline(ss, item, ',')){selectTrack(trackType, item);}
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    long long trackNo = JSON::Value(trackVal).asInt();
 | 
				
			||||||
 | 
					    if (trackVal == JSON::Value(trackNo).asString()){
 | 
				
			||||||
 | 
					      //It's an integer number
 | 
				
			||||||
 | 
					      if (!myMeta.tracks.count(trackNo)){
 | 
				
			||||||
 | 
					        WARN_MSG("Track %lld does not exist in stream, cannot select", trackNo);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const DTSC::Track & Trk = myMeta.tracks[trackNo];
 | 
				
			||||||
 | 
					      if (Trk.type != trackType && Trk.codec != trackType){
 | 
				
			||||||
 | 
					        WARN_MSG("Track %lld is not %s (%s/%s), cannot select", trackNo, trackType.c_str(), Trk.type.c_str(), Trk.codec.c_str());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      INFO_MSG("Selecting %s track %lld (%s/%s)", trackType.c_str(), trackNo, Trk.type.c_str(), Trk.codec.c_str());
 | 
				
			||||||
 | 
					      selectedTracks.insert(trackNo);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::string trackLow = trackVal;
 | 
				
			||||||
 | 
					    Util::stringToLower(trackLow);
 | 
				
			||||||
 | 
					    if (trackLow == "all" || trackLow == "*"){
 | 
				
			||||||
 | 
					      //select all tracks of this type
 | 
				
			||||||
 | 
					      for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
 | 
				
			||||||
 | 
					        const DTSC::Track & Trk = it->second;
 | 
				
			||||||
 | 
					        if (Trk.type == trackType || Trk.codec == trackType){
 | 
				
			||||||
 | 
					          selectedTracks.insert(it->first);
 | 
				
			||||||
 | 
					          INFO_MSG("Selecting %s track %lu (%s/%s)", trackType.c_str(), it->first, Trk.type.c_str(), Trk.codec.c_str());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //attempt to do language/codec matching
 | 
				
			||||||
 | 
					    //convert 2-character language codes into 3-character language codes
 | 
				
			||||||
 | 
					    if (trackLow.size() == 2){trackLow = Encodings::ISO639::twoToThree(trackLow);}
 | 
				
			||||||
 | 
					    for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
 | 
				
			||||||
 | 
					      const DTSC::Track & Trk = it->second;
 | 
				
			||||||
 | 
					      if (Trk.type == trackType || Trk.codec == trackType){
 | 
				
			||||||
 | 
					        std::string codecLow = Trk.codec;
 | 
				
			||||||
 | 
					        Util::stringToLower(codecLow);
 | 
				
			||||||
 | 
					        if (Trk.lang == trackLow || trackLow == codecLow){
 | 
				
			||||||
 | 
					          selectedTracks.insert(it->first);
 | 
				
			||||||
 | 
					          INFO_MSG("Selecting %s track %lu (%s/%s)", trackType.c_str(), it->first, Trk.type.c_str(), Trk.codec.c_str());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /*LTS-END*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Output::selectDefaultTracks(){
 | 
					  void Output::selectDefaultTracks(){
 | 
				
			||||||
    if (!isInitialized){
 | 
					    if (!isInitialized){
 | 
				
			||||||
      initialize();
 | 
					      initialize();
 | 
				
			||||||
      return;
 | 
					      if (!isInitialized){return;}
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    //First, wipe the existing selections, if any.
 | 
				
			||||||
 | 
					    selectedTracks.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*LTS-START*/
 | 
				
			||||||
 | 
					    //Then, select the tracks we've been asked to select.
 | 
				
			||||||
 | 
					    if (targetParams.count("audio")){selectTrack("audio", targetParams["audio"]);}
 | 
				
			||||||
 | 
					    if (targetParams.count("video")){selectTrack("video", targetParams["video"]);}
 | 
				
			||||||
 | 
					    if (targetParams.count("subtitle")){selectTrack("subtitle", targetParams["subtitle"]);}
 | 
				
			||||||
 | 
					    /*LTS-END*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //check which tracks don't actually exist
 | 
					    //check which tracks don't actually exist
 | 
				
			||||||
    std::set<unsigned long> toRemove;
 | 
					    std::set<unsigned long> toRemove;
 | 
				
			||||||
    for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
					    for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
				
			||||||
| 
						 | 
					@ -495,6 +566,38 @@ namespace Mist{
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
   
 | 
					   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*LTS-START*/
 | 
				
			||||||
 | 
					    //Finally, we strip anything unwanted that the above may have auto-selected.
 | 
				
			||||||
 | 
					    toRemove.clear();
 | 
				
			||||||
 | 
					    if (targetParams.count("subtitle") && targetParams["subtitle"] == "0"){
 | 
				
			||||||
 | 
					      for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
				
			||||||
 | 
					        if (myMeta.tracks.at(*it).codec=="subtitle"){
 | 
				
			||||||
 | 
					          toRemove.insert(*it);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (targetParams.count("video") && targetParams["video"] == "0"){
 | 
				
			||||||
 | 
					      for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
				
			||||||
 | 
					        if (myMeta.tracks.at(*it).type=="video"){
 | 
				
			||||||
 | 
					          toRemove.insert(*it);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (targetParams.count("audio") && targetParams["audio"] == "0"){
 | 
				
			||||||
 | 
					      for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
				
			||||||
 | 
					        if (myMeta.tracks.at(*it).type=="audio"){
 | 
				
			||||||
 | 
					          toRemove.insert(*it);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //remove those from selectedtracks
 | 
				
			||||||
 | 
					    for (std::set<unsigned long>::iterator it = toRemove.begin(); it != toRemove.end(); it++){
 | 
				
			||||||
 | 
					      selectedTracks.erase(*it);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /*LTS-END*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (Util::Config::printDebugLevel >= DLVL_MEDIUM){
 | 
					    if (Util::Config::printDebugLevel >= DLVL_MEDIUM){
 | 
				
			||||||
      //print the selected tracks
 | 
					      //print the selected tracks
 | 
				
			||||||
      std::stringstream selected;
 | 
					      std::stringstream selected;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,7 @@ namespace Mist {
 | 
				
			||||||
      void setBlocking(bool blocking);
 | 
					      void setBlocking(bool blocking);
 | 
				
			||||||
      long unsigned int getMainSelectedTrack();
 | 
					      long unsigned int getMainSelectedTrack();
 | 
				
			||||||
      void updateMeta();
 | 
					      void updateMeta();
 | 
				
			||||||
 | 
					      void selectTrack(const std::string &trackType, const std::string &trackVal); /*LTS*/
 | 
				
			||||||
      void selectDefaultTracks();
 | 
					      void selectDefaultTracks();
 | 
				
			||||||
      bool connectToFile(std::string file);
 | 
					      bool connectToFile(std::string file);
 | 
				
			||||||
      static bool listenMode(){return true;}
 | 
					      static bool listenMode(){return true;}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,8 @@
 | 
				
			||||||
#include "output_http.h"
 | 
					#include "output_http.h"
 | 
				
			||||||
#include <mist/stream.h>
 | 
					#include <mist/stream.h>
 | 
				
			||||||
#include <mist/checksum.h>
 | 
					#include <mist/checksum.h>
 | 
				
			||||||
 | 
					#include <mist/util.h>
 | 
				
			||||||
 | 
					#include <mist/langcodes.h>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Mist {
 | 
					namespace Mist {
 | 
				
			||||||
| 
						 | 
					@ -227,39 +229,11 @@ namespace Mist {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      INFO_MSG("Received request %s", H.getUrl().c_str());
 | 
					      INFO_MSG("Received request %s", H.getUrl().c_str());
 | 
				
			||||||
 | 
					      if (H.GetVar("audio") != ""){targetParams["audio"] = H.GetVar("audio");}
 | 
				
			||||||
 | 
					      if (H.GetVar("video") != ""){targetParams["video"] = H.GetVar("video");}
 | 
				
			||||||
 | 
					      if (H.GetVar("subtitle") != ""){targetParams["subtitle"] = H.GetVar("subtitle");}
 | 
				
			||||||
      initialize();
 | 
					      initialize();
 | 
				
			||||||
      if (H.GetVar("audio") != "" || H.GetVar("video") != ""){
 | 
					      selectDefaultTracks();
 | 
				
			||||||
        selectedTracks.clear();
 | 
					 | 
				
			||||||
        if (H.GetVar("audio") != ""){
 | 
					 | 
				
			||||||
          selectedTracks.insert(JSON::Value(H.GetVar("audio")).asInt());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (H.GetVar("video") != ""){
 | 
					 | 
				
			||||||
          selectedTracks.insert(JSON::Value(H.GetVar("video")).asInt());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        selectDefaultTracks();
 | 
					 | 
				
			||||||
        std::set<unsigned long> toRemove;
 | 
					 | 
				
			||||||
        if (H.GetVar("video") == "0"){
 | 
					 | 
				
			||||||
          for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
					 | 
				
			||||||
            if (myMeta.tracks.at(*it).type=="video"){
 | 
					 | 
				
			||||||
              toRemove.insert(*it);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (H.GetVar("audio") == "0"){
 | 
					 | 
				
			||||||
          for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
					 | 
				
			||||||
            if (myMeta.tracks.at(*it).type=="audio"){
 | 
					 | 
				
			||||||
              toRemove.insert(*it);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //remove those from selectedtracks
 | 
					 | 
				
			||||||
        for (std::set<unsigned long>::iterator it = toRemove.begin(); it != toRemove.end(); it++){
 | 
					 | 
				
			||||||
          selectedTracks.erase(*it);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }else{
 | 
					 | 
				
			||||||
        selectDefaultTracks();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      onHTTP();
 | 
					      onHTTP();
 | 
				
			||||||
      if (!H.bufferChunks){
 | 
					      if (!H.bufferChunks){
 | 
				
			||||||
        H.Clean();
 | 
					        H.Clean();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,10 +44,6 @@ namespace Mist{
 | 
				
			||||||
          streamOut = streamName;
 | 
					          streamOut = streamName;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      std::string origTarget = config->getOption("target", true)[0u].asStringRef();
 | 
					 | 
				
			||||||
      if (origTarget.rfind('?') != std::string::npos){
 | 
					 | 
				
			||||||
        parseVars(origTarget.substr(origTarget.rfind('?') + 1));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      initialize();
 | 
					      initialize();
 | 
				
			||||||
      INFO_MSG("About to push stream %s out. Host: %s, port: %d, app: %s, stream: %s", streamName.c_str(), host.c_str(), port, app.c_str(), streamOut.c_str());
 | 
					      INFO_MSG("About to push stream %s out. Host: %s, port: %d, app: %s, stream: %s", streamName.c_str(), host.c_str(), port, app.c_str(), streamOut.c_str());
 | 
				
			||||||
      myConn = Socket::Connection(host, port, false);
 | 
					      myConn = Socket::Connection(host, port, false);
 | 
				
			||||||
| 
						 | 
					@ -172,60 +168,6 @@ namespace Mist{
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void OutRTMP::parseVars(std::string data){
 | 
					 | 
				
			||||||
    std::string varname;
 | 
					 | 
				
			||||||
    std::string varval;
 | 
					 | 
				
			||||||
    bool trackSwitch = false;
 | 
					 | 
				
			||||||
    // position where a part start (e.g. after &)
 | 
					 | 
				
			||||||
    size_t pos = 0;
 | 
					 | 
				
			||||||
    while (pos < data.length()){
 | 
					 | 
				
			||||||
      size_t nextpos = data.find('&', pos);
 | 
					 | 
				
			||||||
      if (nextpos == std::string::npos){
 | 
					 | 
				
			||||||
        nextpos = data.length();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      size_t eq_pos = data.find('=', pos);
 | 
					 | 
				
			||||||
      if (eq_pos < nextpos){
 | 
					 | 
				
			||||||
        // there is a key and value
 | 
					 | 
				
			||||||
        varname = data.substr(pos, eq_pos - pos);
 | 
					 | 
				
			||||||
        varval = data.substr(eq_pos + 1, nextpos - eq_pos - 1);
 | 
					 | 
				
			||||||
      }else{
 | 
					 | 
				
			||||||
        // no value, only a key
 | 
					 | 
				
			||||||
        varname = data.substr(pos, nextpos - pos);
 | 
					 | 
				
			||||||
        varval.clear();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (varname == "track" || varname == "audio" || varname == "video"){
 | 
					 | 
				
			||||||
        long long int selTrack = JSON::Value(varval).asInt();
 | 
					 | 
				
			||||||
        if (myMeta){
 | 
					 | 
				
			||||||
          if (myMeta.tracks.count(selTrack)){
 | 
					 | 
				
			||||||
            std::string & delThis = myMeta.tracks[selTrack].type;
 | 
					 | 
				
			||||||
            for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
 | 
					 | 
				
			||||||
              if (myMeta.tracks[*it].type == delThis){
 | 
					 | 
				
			||||||
                selectedTracks.erase(it);
 | 
					 | 
				
			||||||
                trackSwitch = true;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            selectedTracks.insert(selTrack);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }else{
 | 
					 | 
				
			||||||
          selectedTracks.insert(selTrack);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (nextpos == std::string::npos){
 | 
					 | 
				
			||||||
        // in case the string is gigantic
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      // erase &
 | 
					 | 
				
			||||||
      pos = nextpos + 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (trackSwitch && thisPacket){
 | 
					 | 
				
			||||||
      seek(thisPacket.getTime());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void OutRTMP::init(Util::Config * cfg){
 | 
					  void OutRTMP::init(Util::Config * cfg){
 | 
				
			||||||
    Output::init(cfg);
 | 
					    Output::init(cfg);
 | 
				
			||||||
    capa["name"] = "RTMP";
 | 
					    capa["name"] = "RTMP";
 | 
				
			||||||
| 
						 | 
					@ -812,7 +754,7 @@ namespace Mist{
 | 
				
			||||||
      if (streamName.find('?') != std::string::npos){
 | 
					      if (streamName.find('?') != std::string::npos){
 | 
				
			||||||
        std::string tmpVars = streamName.substr(streamName.find('?') + 1);
 | 
					        std::string tmpVars = streamName.substr(streamName.find('?') + 1);
 | 
				
			||||||
        streamName = streamName.substr(0, streamName.find('?'));
 | 
					        streamName = streamName.substr(0, streamName.find('?'));
 | 
				
			||||||
        parseVars(tmpVars);
 | 
					        HTTP::parseVars(tmpVars, targetParams);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      size_t colonPos = streamName.find(':');
 | 
					      size_t colonPos = streamName.find(':');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,6 @@ namespace Mist {
 | 
				
			||||||
      int64_t rtmpOffset;
 | 
					      int64_t rtmpOffset;
 | 
				
			||||||
      uint64_t lastOutTime;
 | 
					      uint64_t lastOutTime;
 | 
				
			||||||
      unsigned int maxbps;
 | 
					      unsigned int maxbps;
 | 
				
			||||||
      void parseVars(std::string data);
 | 
					 | 
				
			||||||
      std::string app_name;
 | 
					      std::string app_name;
 | 
				
			||||||
      void parseChunk(Socket::Buffer & inputBuffer);
 | 
					      void parseChunk(Socket::Buffer & inputBuffer);
 | 
				
			||||||
      void parseAMFCommand(AMF::Object & amfData, int messageType, int streamId);
 | 
					      void parseAMFCommand(AMF::Object & amfData, int messageType, int streamId);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue