Skip to content

Commit

Permalink
more livestreaming tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
benvanik committed Nov 28, 2011
1 parent f1abd96 commit 5bc2d0f
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 27 deletions.
15 changes: 10 additions & 5 deletions README.md
Expand Up @@ -199,16 +199,21 @@ track events.
* [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
If you are targeting 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
things such as client-side stream switching (changing audio channels/etc).

// TODO: API for this... something like:
// (where target is used as a base filename for all the extra stuff)
var task = transcoding.createTask(source, target, profile, {
streaming: {
var task = transcoding.createTask(source, null, profile, {
liveStreaming: {
path: '/some/path/',
name: 'base_name',
segmentDuration: 10,
allowCaching: true
}
});

This will result in a playlist file and the MPEGTS segments being placed under
`/some/path/` with the name `base_name.m3u8`. The playlist file will be
automatically updated as new segments are generated, and files can be assumed to
be static once they are available.
29 changes: 26 additions & 3 deletions examples/transcode.js
Expand Up @@ -19,6 +19,14 @@ var opts = require('tav').set({
stream_output: {
note: 'Stream file output to test streaming',
value: false
},
livestreaming: {
note: 'Enable HTTP Live Streaming output',
value: false
},
segmentDuration: {
note: 'HTTP Live Streaming segment duration',
value: 10
}
});

Expand Down Expand Up @@ -86,6 +94,9 @@ if (inputFile == '-') {
}
}

var transcodeOptions = {
};

var target;
if (opts.args.length >= 2) {
var profile = transcoding.profiles[opts['profile']];
Expand All @@ -95,7 +106,20 @@ if (opts.args.length >= 2) {
}

var outputFile = opts.args[1];
if (outputFile == '-') {
if (opts['livestreaming']) {
// Must be a path
var outputPath = path.dirname(outputFile);
if (!path.existsSync(outputPath)) {
fs.mkdirSync(outputPath);
}
target = null;
transcodeOptions.liveStreaming = {
path: outputPath,
name: path.basename(outputFile),
segmentDuration: parseInt(opts['segmentDuration']),
allowCaching: true
};
} else if (outputFile == '-') {
// STDOUT
target = process.stdout;
} else if (outputFile == 'null') {
Expand Down Expand Up @@ -132,8 +156,7 @@ function processQuery(source) {
};

function processTranscode(source, target) {
var task = transcoding.createTask(source, target, profile, {
});
var task = transcoding.createTask(source, target, profile, transcodeOptions);
task.on('begin', function(sourceInfo, targetInfo) {
// Transcoding beginning
console.log('transcoding beginning...');
Expand Down
3 changes: 2 additions & 1 deletion src/hls/playlist.cpp
Expand Up @@ -4,7 +4,8 @@ using namespace std;
using namespace transcoding;
using namespace transcoding::hls;

Playlist::Playlist(string path, string name, double duration, bool allowCache) :
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,
Expand Down
2 changes: 1 addition & 1 deletion src/hls/playlist.h
Expand Up @@ -12,7 +12,7 @@ namespace hls {

class Playlist {
public:
Playlist(std::string path, std::string name, double duration,
Playlist(std::string& path, std::string& name, double duration,
bool allowCache);
~Playlist();

Expand Down
13 changes: 10 additions & 3 deletions src/task.cpp
Expand Up @@ -164,11 +164,18 @@ Handle<Value> Task::Start(const Arguments& args) {

assert(!task->context);

// Setup context
IOReader* input = IOReader::Create(task->source);
IOWriter* output = IOWriter::Create(task->target);
Profile* profile = new Profile(task->profile);
TaskOptions* options = new TaskOptions(task->options);
if (options->liveStreaming) {
// Must force to MPEGTS container
TC_LOG_D("Task::Start(): HTTP Live Streaming enabled, forcing to MPEGTS\n");
profile->container = "mpegts";
}

IOReader* input = IOReader::Create(task->source);
IOWriter* output = IOWriter::Create(task->target);

// Setup context
TaskContext* context = new TaskContext(input, output, profile, options);

// Prepare thread request
Expand Down
21 changes: 12 additions & 9 deletions src/taskoptions.cpp
Expand Up @@ -2,29 +2,32 @@

using namespace transcoding;

StreamingOptions::StreamingOptions(Handle<Object> source) {
LiveStreamingOptions::LiveStreamingOptions(Handle<Object> source) {
HandleScope scope;

this->path = V8GetString(source, "path", "/tmp/");
this->name = V8GetString(source, "name", "video");

this->segmentDuration = V8GetNumber(source, "segmentDuration", 10);
this->allowCaching = V8GetBoolean(source, "allowCaching", true);
}

StreamingOptions::~StreamingOptions() {
LiveStreamingOptions::~LiveStreamingOptions() {
}

TaskOptions::TaskOptions(Handle<Object> source) :
streaming(NULL) {
liveStreaming(NULL) {
HandleScope scope;

Local<Object> streaming =
Local<Object>::Cast(source->Get(String::New("streaming")));
if (!streaming.IsEmpty()) {
this->streaming = new StreamingOptions(streaming);
Local<Object> liveStreaming =
Local<Object>::Cast(source->Get(String::New("liveStreaming")));
if (!liveStreaming.IsEmpty()) {
this->liveStreaming = new LiveStreamingOptions(liveStreaming);
}
}

TaskOptions::~TaskOptions() {
if (this->streaming) {
delete this->streaming;
if (this->liveStreaming) {
delete this->liveStreaming;
}
}
11 changes: 7 additions & 4 deletions src/taskoptions.h
Expand Up @@ -11,10 +11,13 @@ using namespace v8;

namespace transcoding {

class StreamingOptions {
class LiveStreamingOptions {
public:
StreamingOptions(Handle<Object> source);
~StreamingOptions();
LiveStreamingOptions(Handle<Object> source);
~LiveStreamingOptions();

std::string path;
std::string name;

double segmentDuration;
bool allowCaching;
Expand All @@ -25,7 +28,7 @@ class TaskOptions {
TaskOptions(Handle<Object> source);
~TaskOptions();

StreamingOptions* streaming;
LiveStreamingOptions* liveStreaming;
};

}; // transcoding
Expand Down
2 changes: 1 addition & 1 deletion src/utils.h
Expand Up @@ -58,7 +58,7 @@ do { \
} while(0)

static std::string V8GetString(v8::Handle<v8::Object> obj, const char* name,
std::string& original) {
std::string original) {
v8::HandleScope scope;
v8::Local<v8::String> value =
v8::Local<v8::String>::Cast(obj->Get(v8::String::NewSymbol(name)));
Expand Down

0 comments on commit 5bc2d0f

Please sign in to comment.