Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added support for ffprobe (Issue #10)

Extra endpoint /probe and extra config option "ffprobe".
  • Loading branch information...
commit 28752af576b72e212e3ae3ec6a0706defc6c157d 1 parent ed208d7
@tieleman tieleman authored
View
27 README.markdown
@@ -50,7 +50,8 @@ Configuration is done by specifying a CLI option (`-c`) and pointing to a file c
"interface": "127.0.0.1",
"encoder": "ffmpeg",
"scratch_dir": "/tmp",
- "use_scratch_dir": true
+ "use_scratch_dir": true,
+ "ffprobe": null
}
Configuration options:
@@ -63,6 +64,7 @@ Configuration options:
* `encoder`; path to the ffmpeg binary, if it is in your path specifying only `ffmpeg` is sufficient, defaults to `ffmpeg`
* `scratch_dir`; temporary files are written here and moved into the destination directory after transcoding, defaults to `/tmp`
* `use_scratch_dir`; if set to false temporary files will be written to the output directory of your job, for setups that don't require or are not able to use a separate `scratch_dir`. Defaults to `true` so if you don't want to disable the `scratch_dir` you can also omit this option from your config file.
+* `ffprobe`; path to the ffprobe binary, if it is in your path specifying only `ffprobe` is sufficient, defaults to `null`. Set this to a non-null value if you want to enable ffprobe support in the transcoder.
Note that the default config will put the access_log and job database in `/var/log` and `var/db/` respectively. If you wish to put these in a different location please supply your own config. You can start the transcoder with your custom config using:
@@ -118,6 +120,23 @@ Responses:
* `404 Not Found` - Job not found
* * *
+Request: `POST /probe`
+
+Probe a source file using `ffprobe` (if you have enabled it in the configuration). Output is a JSON object containing the `ffprobe` output.
+
+Parameters (HTTP POST data, should be valid JSON object):
+
+ {
+ "source_file": "/PATH/TO/INPUT/FILE.wmv"
+ }
+
+Responses:
+
+* `200 OK` - Returns `ffprobe` output JSON-formatted
+* `400 Bad Request` - Returned if you attempt to probe a file when there is no path set to the `ffprobe` binary
+* `500 Internal Server Error` - Returned if there was an error while trying to probe, the output from `ffprobe` will be returned as well
+
+* * *
## Examples
Create a new job, transcode "video.wmv" to "video.mp4" using the specified ffmpeg options (96kbit/s audio, 416kbit/s video, 320x180, use as much threads as possible). Requires libx264 support in your ffmpeg.
@@ -148,6 +167,12 @@ Get full status of one job with id "da56da6012bda2ce775fa028f056873bcb29cb3b".
Output: {"id":"da56da6012bda2ce775fa028f056873bcb29cb3b", "status":"processing", "progress":0.21800947867298578, "duration":633, "filesize":39191346, "opts":"{\"source_file\":\"/shared/videos/asf/video.asf\", \"destination_file\":\"/shared/videos/mp4/journaal.mp4\", \"encoder_options\":\"-acodec libfaac -ab 96k -ar 44100 -vcodec libx264 -vb 416k -s 320x180 -y -threads 0\"}", "message":null, "created_at":1304338160, "updated_at":1304338173}
+Probe a file using `ffprobe`.
+
+ # curl -d '{"source_file": "/tmp/video.wmv"}' http://localhost:8080/probe
+
+ Output: {"ffprobe":{"streams":[ ... stream info ... ],"format":{ ... format info ... }}}}
+
## Tests
All tests are written using jasmine (via jasmine-node). Running them is as easy as:
View
3  lib/config.js
@@ -11,7 +11,8 @@ var config = {
interface: "127.0.0.1",
encoder: "ffmpeg",
scratch_dir: "/tmp",
- use_scratch_dir: true
+ use_scratch_dir: true,
+ ffprobe: null
};
var loaded_config = null;
View
26 lib/probe-handler.js
@@ -0,0 +1,26 @@
+var os = require('os'),
+ util = require('util'),
+ config = require('./config').load(),
+ child_process = require('child_process');
+
+var slots = [];
+
+exports.doProbe = function(postData, callback) {
+ try {
+ var obj = JSON.parse(postData);
+ } catch(e) {
+ callback(new Error("HTTP POST data contains no valid JSON object."), null, null);
+ return;
+ }
+
+ var source_file = obj['source_file'];
+
+ if (source_file) {
+ var the_process = child_process.exec(
+ config['ffprobe'] + ' -print_format json -show_format -show_streams ' + source_file,
+ callback
+ );
+ } else {
+ callback(new Error("No source file was specified to probe."), null, null);
+ }
+}
View
68 lib/server.js
@@ -1,14 +1,18 @@
var config = require('./config').load(),
jobHandler = require('./job-handler'),
+ probeHandler = require('./probe-handler'),
fs = require('fs'),
util = require('util'),
express = require('express');
-var rejectMessage = 'The transcoder is not accepting jobs right now. Please try again later.';
-var acceptedMessage = 'The transcoder accepted your job.';
-var notImplementedMessage = 'This method is not yet implemented.';
-var badRequestMessage = 'The data supplied was not valid.';
-var notFoundMessage = 'The specified job could not be found.';
+var rejectMessage = 'The transcoder is not accepting jobs right now. Please try again later.';
+var acceptedMessage = 'The transcoder accepted your job.';
+var notImplementedMessage = 'This method is not yet implemented.';
+var badRequestMessage = 'The data supplied was not valid.';
+var notFoundMessage = 'The specified job could not be found.';
+var probeNotSupportedMessage = 'Probing files is not supported. Make sure you add the \'ffprobe\' configuration option.';
+var probeErrorMessage = 'An error occurred while probing the file.';
+var probeFfprobeError = 'ffprobe returned invalid JSON.';
var logfile = null;
var server = null;
@@ -22,6 +26,7 @@ exports.launch = function() {
server.post( '/jobs', postNewJob);
server.get( '/jobs/:id', getJobStatus);
server.delete('/jobs/:id', removeJob);
+ server.post( '/probe', probeFile);
server.listen(config['port'], config['interface']);
@@ -35,6 +40,14 @@ exports.relaunch = function() {
exports.launch();
}
+// POST /probe
+probeFile = function(request, response) {
+ var postData = "";
+
+ request.on('data', function(data) { postData += data; })
+ request.on('end', function() { processProbe(postData, response); } );
+}
+
// POST /jobs
postNewJob = function(request, response) {
var postData = "";
@@ -132,4 +145,49 @@ processPostedJob = function(postData, response) {
util.log("Error while posting new job: " + e + e.stack);
}
});
+}
+
+processProbe = function(postData, response) {
+ response.setHeader('Content-Type', 'application/json; charset=utf-8');
+ var body = {};
+
+ if (config['ffprobe']) {
+ // Do probe
+ probeHandler.doProbe(postData, function(error, stdout, stderr) {
+ if (error !== null) {
+ // something went wrong
+ response.statusCode = 500;
+ body['message'] = probeErrorMessage;
+ if (error.message) body['message'] += " " + error.message;
+ if (stderr) body['message'] += " " + stderr;
+ } else {
+ // everything's ok
+ response.statusCode = 200;
+ try {
+ body['ffprobe'] = JSON.parse(stdout);
+ } catch(e) {
+ response.statuscode = 500;
+ body['message'] = probeFfprobeError;
+ if (stdout) body['message'] += " ffprobe output: " + stdout;
+ }
+ }
+
+ try {
+ response.end(JSON.stringify(body), 'utf8');
+ } catch(e) {
+ util.log("Error while probing file: " + e + e.stack);
+ }
+
+ });
+ } else {
+ // Return not supported
+ response.statusCode = 400;
+ body['message'] = probeNotSupportedMessage;
+
+ try {
+ response.end(JSON.stringify(body), 'utf8');
+ } catch(e) {
+ util.log("Error while probing file: " + e + e.stack);
+ }
+ }
}
View
2  package.json
@@ -1,7 +1,7 @@
{
"name": "codem-transcode",
"description": "Offline video transcoding using ffmpeg, with a small HTTP API.",
- "version": "0.4.0",
+ "version": "0.4.1",
"keywords": ["transcoding", "ffmpeg", "video"],
"homepage": "http://www.transcodem.com/",
"repository": {
Please sign in to comment.
Something went wrong with that request. Please try again.