diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3162985f..cbf7be2e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -282,6 +282,7 @@ makeInput(MP3 mp3)
 makeInput(FLV flv)
 makeInput(OGG ogg)
 makeInput(Buffer buffer)
+makeInput(H264 h264)
 
 ########################################
 # MistServer - Outputs                 #
diff --git a/src/input/input_h264.cpp b/src/input/input_h264.cpp
new file mode 100644
index 00000000..0068008d
--- /dev/null
+++ b/src/input/input_h264.cpp
@@ -0,0 +1,127 @@
+#include "input_h264.h"
+#include <mist/h264.h>
+#include <mist/mp4_generic.h>
+
+namespace Mist{
+  InputH264::InputH264(Util::Config *cfg) : Input(cfg){
+    capa["name"] = "H264";
+    capa["desc"] = "H264 Annex B input";
+    capa["source_match"] = "h264-exec:*";
+    //May be set to always-on mode
+    capa["always_match"].append("h264-exec:*");
+    capa["priority"] = 0ll;
+    capa["codecs"][0u][0u].append("H264");
+    frameCount = 0;
+    startTime = Util::bootMS();
+    inputProcess = 0;
+  }
+
+  int InputH264::run(){
+    if (config->getString("input") != "-"){
+      std::string input = config->getString("input");
+      const char *argv[2];
+      input = input.substr(10);
+
+      char *args[128];
+      uint8_t argCnt = 0;
+      char *startCh = 0;
+      for (char *i = (char*)input.c_str(); i <= input.data() + input.size(); ++i){
+        if (!*i){
+          if (startCh){args[argCnt++] = startCh;}
+          break;
+        }
+        if (*i == ' '){
+          if (startCh){
+            args[argCnt++] = startCh;
+            startCh = 0;
+            *i = 0;
+          }
+        }else{
+          if (!startCh){startCh = i;}
+        }
+      }
+      args[argCnt] = 0;
+
+      int fin = -1, fout = -1, ferr = -1;
+      inputProcess = Util::Procs::StartPiped(args, &fin, &fout, &ferr);
+      myConn = Socket::Connection(-1, fout);
+    }else{
+      myConn = Socket::Connection(fileno(stdout), fileno(stdin));
+    }
+    myConn.Received().splitter.assign("\000\000\001", 3);
+    myMeta.vod = false;
+    myMeta.live = true;
+    myMeta.tracks[1].type = "video";
+    myMeta.tracks[1].codec = "H264";
+    myMeta.tracks[1].trackID = 1;
+    waitsSinceData = 0;
+    return Input::run();
+  }
+
+  bool InputH264::setup(){
+    std::string input = config->getString("input");
+    if (input != "-" && input.substr(0, 10) != "h264-exec:"){
+      FAIL_MSG("Unsupported input type: %s", input.c_str());
+      return false;
+    }
+    return true;
+  }
+
+  void InputH264::getNext(bool smart){
+    do{
+      if (!myConn.spool()){
+        Util::sleep(25);
+        ++waitsSinceData;
+        if (waitsSinceData > 5000 / 25 && (waitsSinceData % 40) == 0){
+          WARN_MSG("No H264 data received for > 5s, killing source process");
+          Util::Procs::Stop(inputProcess);
+        }
+        continue;
+      }
+      waitsSinceData = 0;
+      uint32_t bytesToRead = myConn.Received().bytesToSplit();
+      if (!bytesToRead){continue;}
+      std::string NAL = myConn.Received().remove(bytesToRead);
+      uint32_t nalSize = NAL.size() - 3;
+      while (nalSize && NAL.data()[nalSize - 1] == 0){--nalSize;}
+      if (!nalSize){continue;}
+      uint8_t nalType = NAL.data()[0] & 0x1F;
+      INSANE_MSG("NAL unit, type %u, size %lu", nalType, nalSize);
+      if (nalType == 7 || nalType == 8){
+        if (nalType == 7){spsInfo = NAL.substr(0, nalSize);}
+        if (nalType == 8){ppsInfo = NAL.substr(0, nalSize);}
+        if (!myMeta.tracks[1].init.size() && spsInfo.size() && ppsInfo.size()){
+          h264::sequenceParameterSet sps(spsInfo.data(), spsInfo.size());
+          h264::SPSMeta spsChar = sps.getCharacteristics();
+          myMeta.tracks[1].width = spsChar.width;
+          myMeta.tracks[1].height = spsChar.height;
+          myMeta.tracks[1].fpks = spsChar.fps * 1000;
+          if (myMeta.tracks[1].fpks < 100 || myMeta.tracks[1].fpks > 1000000){
+            myMeta.tracks[1].fpks = 0;
+          }
+          MP4::AVCC avccBox;
+          avccBox.setVersion(1);
+          avccBox.setProfile(spsInfo[1]);
+          avccBox.setCompatibleProfiles(spsInfo[2]);
+          avccBox.setLevel(spsInfo[3]);
+          avccBox.setSPSNumber(1);
+          avccBox.setSPS(spsInfo);
+          avccBox.setPPSNumber(1);
+          avccBox.setPPS(ppsInfo);
+          myMeta.tracks[1].init = std::string(avccBox.payload(), avccBox.payloadSize());
+        }
+        continue;
+      }
+      if (myMeta.tracks[1].init.size()){
+        uint64_t ts = Util::bootMS() - startTime;
+        if (myMeta.tracks[1].fpks){ts = frameCount * (1000000 / myMeta.tracks[1].fpks);}
+        thisPacket.genericFill(ts, 0, 1, 0, 0, 0, h264::isKeyframe(NAL.data(), nalSize));
+        thisPacket.appendNal(NAL.data(), nalSize, nalSize);
+        ++frameCount;
+        return;
+      }
+    }while (myConn && (inputProcess == 0 || Util::Procs::childRunning(inputProcess)));
+    if (inputProcess){myConn.close();}
+  }
+}
+
diff --git a/src/input/input_h264.h b/src/input/input_h264.h
new file mode 100644
index 00000000..7b2f7b3c
--- /dev/null
+++ b/src/input/input_h264.h
@@ -0,0 +1,33 @@
+#include "input.h"
+#include <mist/dtsc.h>
+#include <mist/procs.h>
+
+namespace Mist{
+  class InputH264 : public Input{
+  public:
+    InputH264(Util::Config *cfg);
+    int run();
+
+  protected:
+    bool setup();
+    void getNext(bool smart = true);
+    Socket::Connection myConn;
+    std::string ppsInfo;
+    std::string spsInfo;
+    uint64_t frameCount;
+    // Empty defaults
+    bool readHeader(){return true;}
+    bool openStreamSource(){return true;}
+    void closeStreamSource(){}
+    void parseStreamHeader(){}
+    void seek(int seekTime){}
+    void trackSelect(std::string trackSpec){}
+    bool needsLock(){return false;}
+    uint64_t startTime;
+    pid_t inputProcess;
+    uint32_t waitsSinceData;
+  };
+}
+
+typedef Mist::InputH264 mistIn;
+