@@ -144,6 +144,8 @@ var Job = JobUtils.getDatabase().define('Job', {
144144 opts : { type : Sequelize . TEXT , defaultValue : null } ,
145145 thumbnails : { type : Sequelize . TEXT , defaultValue : null } ,
146146 message : { type : Sequelize . TEXT , defaultValue : null } ,
147+ playlist : { type : Sequelize . STRING , defaultValue : null } ,
148+ segments : { type : Sequelize . TEXT , defaultValue : null } ,
147149 createdAt : Sequelize . DATE ,
148150 updatedAt : Sequelize . DATE
149151} , {
@@ -274,35 +276,103 @@ var Job = JobUtils.getDatabase().define('Job', {
274276 }
275277 } ,
276278 didFinish : function ( code ) {
277- if ( code == 0 && this . parsedOpts ( ) [ 'thumbnail_options' ] ) {
278- this . processThumbnails ( ) ;
279- } else {
279+ if ( code != 0 ) {
280280 this . finalize ( code ) ;
281+ return ;
281282 }
283+
284+ this . processThumbnails ( {
285+ error : function ( job ) { job . finalize ( 1 ) ; } ,
286+ success : function ( job ) {
287+ job . processSegments ( {
288+ error : function ( job ) { job . finalize ( 1 ) ; } ,
289+ success : function ( job ) { job . finalize ( 0 ) ; }
290+ } )
291+ }
292+ } )
282293 } ,
283- processThumbnails : function ( ) {
294+
295+ processSegments : function ( callbacks ) {
296+ if ( ! this . parsedOpts ( ) [ 'segments_options' ] ) {
297+ callbacks . success ( this ) ;
298+ return ;
299+ }
300+
301+ logger . log ( "Processing segments for job " + this . internalId + "." ) ;
302+
303+ var job = this ;
304+ var args = [ ] ;
305+ var segmentsOpts = this . parsedOpts ( ) [ 'segments_options' ] ;
306+ var segmentTime = segmentsOpts [ 'segment_time' ] ;
307+ var destinationFile = this . parsedOpts ( ) [ 'destination_file' ] ;
308+ var playlistName = path . basename ( destinationFile , path . extname ( destinationFile ) ) ;
309+ var playlistDir = path . dirname ( destinationFile ) ;
310+ var playlistPath = [ playlistDir , playlistName ] . join ( path . sep ) + '.m3u8' ;
311+ var segmentsFormat = [ playlistDir , playlistName ] . join ( path . sep ) + '-%06d.ts'
312+
313+ args . push ( '-i' , job . tmpFile ,
314+ '-codec' , 'copy' , '-map' , '0' , '-f' , 'segment' ,
315+ '-vbsf' , 'h264_mp4toannexb' , '-flags' , '-global_header' ,
316+ '-segment_format' , 'mpegts' , '-segment_list' , playlistPath ,
317+ '-segment_time' , segmentTime , segmentsFormat ) ;
318+
319+ child_process . execFile ( config [ 'encoder' ] , args , function ( error , stdout , stderr ) {
320+ if ( error ) {
321+ job . lastMessage = 'Error while generating segments: ' + error . message ;
322+ callbacks . error ( job ) ;
323+ return ;
324+ }
325+
326+ fs . readdir ( playlistDir , function ( error , files ) {
327+ if ( error ) {
328+ job . lastMessage = 'Error while generating segments: ' + error . message ;
329+ callbacks . error ( job ) ;
330+ return ;
331+ }
332+
333+ job . segments = JSON . stringify ( files . filter (
334+ function ( file ) { return file . match ( new RegExp ( playlistName + "-\\d+\\.ts" ) ) }
335+ ) . map (
336+ function ( file ) { return path . join ( playlistDir , file ) }
337+ ) ) ;
338+
339+ job . playlist = playlistPath ;
340+
341+ callbacks . success ( job ) ;
342+ } ) ;
343+ } ) ;
344+ } ,
345+
346+ processThumbnails : function ( callbacks ) {
347+ if ( ! this . parsedOpts ( ) [ 'thumbnail_options' ] ) {
348+ callbacks . success ( this ) ;
349+ return ;
350+ }
351+
284352 logger . log ( "Processing thumbnails for job " + this . internalId + "." ) ;
285353 var thumbOpts = this . parsedOpts ( ) [ 'thumbnail_options' ] ;
286354 var range = JobUtils . generateRangeFromThumbOpts ( thumbOpts , this . duration ) ;
287-
288- if ( range ) {
289- var job = this ;
290- async . parallel (
291- range . map ( job . execThumbJob . bind ( job ) ) ,
292- function ( err , results ) {
293- if ( err ) {
294- job . lastMessage = err . message ;
295- job . finalize ( 1 ) ;
296- } else {
297- job . finalize ( 0 , results ) ;
298- }
299- }
300- ) ;
301- } else {
355+
356+ if ( ! range ) {
302357 // no valid range
303358 logger . log ( "No valid thumbnails to process for job " + this . internalId + ". Skipping..." ) ;
304- this . finalize ( 0 ) ;
359+ callbacks . success ( this ) ;
360+ return ;
305361 }
362+
363+ var job = this ;
364+ async . parallel (
365+ range . map ( job . execThumbJob . bind ( job ) ) ,
366+ function ( err , results ) {
367+ if ( err ) {
368+ job . lastMessage = err . message ;
369+ callbacks . error ( job ) ;
370+ } else {
371+ job . thumbnails = JSON . stringify ( results ) ;
372+ callbacks . success ( job ) ;
373+ }
374+ }
375+ ) ;
306376 } ,
307377 execThumbJob : function ( offset ) {
308378 var job = this ;
@@ -331,43 +401,44 @@ var Job = JobUtils.getDatabase().define('Job', {
331401 } ) ;
332402 }
333403 } ,
334- finalize : function ( code , thumbnails ) {
404+ finalize : function ( code ) {
335405 var job = this ;
336- if ( thumbnails ) job . thumbnails = JSON . stringify ( thumbnails ) ;
337-
338- if ( code == 0 ) {
339- if ( job . tmpFile ) {
340- fs . rename ( job . tmpFile , job . parsedOpts ( ) [ 'destination_file' ] , function ( err ) {
341- if ( err ) {
342- if ( ( err . message ) . match ( / E X D E V / ) ) {
343- /*
344- EXDEV fix, since util.pump is deprecated, using stream.pipe
345- example from http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js
346- */
347- try {
348- logger . log ( 'ffmpeg finished successfully, trying to copy across partitions' ) ;
349- fs . createReadStream ( job . tmpFile ) . pipe ( fs . createWriteStream ( job . parsedOpts ( ) [ 'destination_file' ] ) ) ;
350- job . exitHandler ( code , 'ffmpeg finished succesfully.' ) ;
351- } catch ( err ) {
352- logger . log ( err ) ;
353- job . exitHandler ( - 1 , 'ffmpeg finished succesfully, but unable to move file to different partition (' + job . parsedOpts ( ) [ 'destination_file' ] + ').' ) ;
354- }
355406
356- } else {
357- logger . log ( err ) ;
358- job . exitHandler ( - 1 , 'ffmpeg finished succesfully, but unable to move file to destination (' + job . parsedOpts ( ) [ 'destination_file' ] + ').' ) ;
359- }
360- } else {
407+ if ( code != 0 ) {
408+ job . exitHandler ( code , "ffmpeg finished with an error: '" + job . lastMessage + "' (" + code + ")." ) ;
409+ return ;
410+ }
411+
412+ if ( ! job . tmpFile ) {
413+ // No tmpFile, hence no transcoding, only thumbnails
414+ job . exitHandler ( code , 'finished thumbnail job.' ) ;
415+ return ;
416+ }
417+
418+ fs . rename ( job . tmpFile , job . parsedOpts ( ) [ 'destination_file' ] , function ( err ) {
419+ if ( err ) {
420+ if ( ( err . message ) . match ( / E X D E V / ) ) {
421+ /*
422+ EXDEV fix, since util.pump is deprecated, using stream.pipe
423+ example from http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js
424+ */
425+ try {
426+ logger . log ( 'ffmpeg finished successfully, trying to copy across partitions' ) ;
427+ fs . createReadStream ( job . tmpFile ) . pipe ( fs . createWriteStream ( job . parsedOpts ( ) [ 'destination_file' ] ) ) ;
361428 job . exitHandler ( code , 'ffmpeg finished succesfully.' ) ;
429+ } catch ( err ) {
430+ logger . log ( err ) ;
431+ job . exitHandler ( - 1 , 'ffmpeg finished succesfully, but unable to move file to different partition (' + job . parsedOpts ( ) [ 'destination_file' ] + ').' ) ;
362432 }
363- } ) ;
433+
434+ } else {
435+ logger . log ( err ) ;
436+ job . exitHandler ( - 1 , 'ffmpeg finished succesfully, but unable to move file to destination (' + job . parsedOpts ( ) [ 'destination_file' ] + ').' ) ;
437+ }
364438 } else {
365- // No tmpFile, hence no transcoding, only thumbnails
366- job . exitHandler ( code , 'finished thumbnail job.' ) ;
439+ job . exitHandler ( code , 'ffmpeg finished succesfully.' ) ;
367440 }
368- } else {
369- job . exitHandler ( code , "ffmpeg finished with an error: '" + job . lastMessage + "' (" + code + ")." )
370- }
441+ } ) ;
371442 } ,
372443 toJSON : function ( ) {
373444 var obj = {
@@ -377,13 +448,17 @@ var Job = JobUtils.getDatabase().define('Job', {
377448 'duration' : this . duration ,
378449 'filesize' : this . filesize ,
379450 'message' : this . message ,
380-
381451 } ;
382452
383453 if ( this . thumbnails ) {
384454 obj [ 'thumbnails' ] = JSON . parse ( this . thumbnails ) ;
385455 }
386-
456+
457+ if ( this . playlist ) { obj [ 'playlist' ] = this . playlist ; }
458+ if ( this . segments ) {
459+ obj [ 'segments' ] = JSON . parse ( this . segments ) ;
460+ }
461+
387462 return obj ;
388463 } ,
389464 progressHandler : function ( data ) {
@@ -448,4 +523,4 @@ var Job = JobUtils.getDatabase().define('Job', {
448523 }
449524} ) ;
450525
451- module . exports = Job ;
526+ module . exports = Job ;
0 commit comments