Permalink
Browse files

starting HTTP live streaming support

  • Loading branch information...
1 parent f4a938d commit 751ee72f742b4fb5fc301e75ac13d4ed426e6f6b @benvanik committed Nov 28, 2011
Showing with 115 additions and 0 deletions.
  1. +3 −0 README.md
  2. +4 −0 TODO.md
  3. +70 −0 src/hls/playlist.cpp
  4. +36 −0 src/hls/playlist.h
  5. +1 −0 src/utils.h
  6. +1 −0 wscript
View
@@ -196,6 +196,9 @@ track events.
### HTTP Live Streaming
+* [IETF Spec](http://tools.ietf.org/html/draft-pantos-http-live-streaming-07)
+* [Apple Docs](http://developer.apple.com/library/ios/#documentation/networkinginternet/conceptual/streamingmediaguide/Introduction/Introduction.html)
+
If you are targetting devices that support HTTP Live Streaming (like iOS), you
can have the transcoder build the output in realtime as it processes. This
enables playback while the transcoding is occuring, as well as some other fancy
View
@@ -15,3 +15,7 @@ of the segment generation/writing/etc.
* HLSWriter IOHandle type for streaming info (manifest file, path, etc)
* Rework TaskContext to either support segmenting or subclass it
+
+// path/name.m3u8
+// /name.0.ts
+// /name.1.ts
View
@@ -0,0 +1,70 @@
+#include "playlist.h"
+
+using namespace std;
+using namespace transcoding;
+using namespace transcoding::hls;
+
+Playlist::Playlist(string path, string name, double duration, bool allowCache) :
+ path(path), name(name), duration(duration) {
+ TC_LOG_D("Playlist::Playlist(%s, %s, %d, %s)\n",
+ path.c_str(), name.c_str(), (int)duration,
+ allowCache ? "cache" : "no-cache");
+
+ this->playlistFile = this->path + this->name + ".m3u8";
+
+ char str[1024];
+ sprintf(str,
+ "#EXTM3U\n"
+ "#EXT-X-VERSION:1\n"
+ "#EXT-X-PLAYLIST-TYPE:EVENT\n"
+ "#EXT-X-TARGETDURATION:%d\n"
+ "#EXT-X-MEDIA-SEQUENCE:1\n"
+ "#EXT-X-ALLOW-CACHE:%s\n",
+ (int)duration, allowCache ? "YES" : "NO");
+ this->AppendString(str, false);
+}
+
+Playlist::~Playlist() {
+ TC_LOG_D("Playlist::~Playlist()\n");
+}
+
+int Playlist::AppendString(const char* str, bool append) {
+ int r = 0;
+
+ int flags = O_WRONLY | O_EXLOCK;
+ if (append) {
+ flags |= O_APPEND;
+ } else {
+ flags |= O_CREAT | O_TRUNC;
+ }
+ uv_fs_t openReq;
+ r = uv_fs_open(uv_default_loop(),
+ &openReq, this->playlistFile.c_str(),
+ flags, S_IWRITE | S_IREAD, NULL);
+
+ uv_fs_t writeReq;
+ r = uv_fs_write(uv_default_loop(),
+ &writeReq, openReq.result,
+ (void*)str, strlen(str), -1, NULL);
+
+ uv_fs_t closeReq;
+ r = uv_fs_close(uv_default_loop(),
+ &closeReq, openReq.result, NULL);
+
+ return r;
+}
+
+int Playlist::AddSegment(int id) {
+ TC_LOG_D("Playlist::AddSegment(%d)\n", id);
+
+ char str[1024];
+ sprintf(str, "#EXTINF:%d,\n%s-%d.ts\n",
+ (int)this->duration, this->name.c_str(), id);
+ return this->AppendString(str);
+}
+
+int Playlist::Complete() {
+ TC_LOG_D("Playlist::Complete()\n");
+
+ return this->AppendString("#EXT-X-ENDLIST\n");
+}
View
@@ -0,0 +1,36 @@
+#include <node.h>
+#include <v8.h>
+#include "../utils.h"
+
+#ifndef NODE_TRANSCODING_HLS_PLAYLIST
+#define NODE_TRANSCODING_HLS_PLAYLIST
+
+using namespace v8;
+
+namespace transcoding {
+namespace hls {
+
+class Playlist {
+public:
+ Playlist(std::string path, std::string name, double duration,
+ bool allowCache);
+ ~Playlist();
+
+ int AddSegment(int id);
+ int Complete();
+
+private:
+ int AppendString(const char* str, bool append = true);
+
+private:
+ std::string path;
+ std::string name;
+ std::string playlistFile;
+
+ double duration;
+};
+
+}; // hls
+}; // transcoding
+
+#endif // NODE_TRANSCODING_HLS_PLAYLIST
View
@@ -1,5 +1,6 @@
#include <node.h>
#include <v8.h>
+#include <fcntl.h>
#include <string>
extern "C" {
View
@@ -41,6 +41,7 @@ def build(bld):
'src/querycontext.cpp',
'src/task.cpp',
'src/taskcontext.cpp',
+ 'src/hls/playlist.cpp',
'src/io/filereader.cpp',
'src/io/filewriter.cpp',
'src/io/io.cpp',

0 comments on commit 751ee72

Please sign in to comment.