philipjscott / simple-thumbnail

A library that produces thumbnails from images, videos and URLs :mag_right:
https://www.npmjs.com/package/simple-thumbnail
MIT License
25 stars 14 forks source link

Performance Improvement #72

Open Astropilot opened 4 years ago

Astropilot commented 4 years ago

Having tried to generate a thumbnail of an MP4 video, I noticed that running ffmpeg took a lot of time to retrieve a thumbnail from a given time in the video. Upon inquiring, I found this comment interesting (https://superuser.com/a/821680)

Each invocation of above ffmpeg command takes a fraction of second (!) for ~1GB H.264. That is because it instantly jumps to

Currently in the creation of arguments for ffmpeg the argument -ss is placed after the definition of the source file. https://github.com/ScottyFillups/simple-thumbnail/blob/44379e88307c1aa2c8efee518dd2c1d4861eb566/index.js#L60-L68

I have therefore rearranged the order of the arguments to put the -ss before the -i as suggested in the comment above.

return [
  '-y',
  `-ss ${seek}`,
  `-i ${input}`,
  scaleArg,
  '-vframes 1',
  output
]

For the following test script with an MP4 file of 23m40s and 188Mb I give you the total execution time of this same script with the original order and the one I propose.

The script:

const ffmpeg = require('ffmpeg-static')
const genThumbnail = require('simple-thumbnail')

async function download () {
  await genThumbnail('test.mp4', 'test_s.jpg', '150x?', {
    path: ffmpeg,
    seek: '00:12:00'
  })
  console.log('Done!')
}

download()

The characteristics of the MP4 file (the return of ffprobe):

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.33.100
  Duration: 00:23:40.16, start: 0.000000, bitrate: 1113 kb/s
    Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 915 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 192 kb/s (default)
    Metadata:
      handler_name    : SoundHandler

The execution time of the script with the original order:

PS C:\Users\marti\Documents\test> Measure-Command {node .\index.js}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 18
Milliseconds      : 188
Ticks             : 181882832
TotalDays         : 0,000210512537037037
TotalHours        : 0,00505230088888889
TotalMinutes      : 0,303138053333333
TotalSeconds      : 18,1882832
TotalMilliseconds : 18188,2832

The execution time of the script with the proposed order:

PS C:\Users\marti\Documents\test> Measure-Command {node .\index.js}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 1
Milliseconds      : 480
Ticks             : 14806789
TotalDays         : 1,71374872685185E-05
TotalHours        : 0,000411299694444444
TotalMinutes      : 0,0246779816666667
TotalSeconds      : 1,4806789
TotalMilliseconds : 1480,6789

The time saving is huge for me, and I see the same time saving if I provide the MP4 file via a URL and not as a local file.

The execution time of the script with the file over the internet with the original order:

PS C:\Users\marti\Documents\test> Measure-Command {node .\index.js}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 26
Milliseconds      : 18
Ticks             : 260180286
TotalDays         : 0,000301134590277778
TotalHours        : 0,00722723016666667
TotalMinutes      : 0,43363381
TotalSeconds      : 26,0180286
TotalMilliseconds : 26018,0286

The execution time of the script with the file over the internet with the proposed order:

PS C:\Users\marti\Documents\test> Measure-Command {node .\index.js}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 2
Milliseconds      : 265
Ticks             : 22658406
TotalDays         : 2,62250069444444E-05
TotalHours        : 0,000629400166666667
TotalMinutes      : 0,03776401
TotalSeconds      : 2,2658406
TotalMilliseconds : 2265,8406

My tests were performed on a Windows 10 Pro 64bits with an Intel Core i7-10510U.

The order of the parameters definitely seems to have an importance on the performance of ffmpeg, unfortunately I don't have time to do more tests but I'll let you try on your side too.

This is my first issue and I hope I have respected the rules as much as possible 😢

Have a nice day !

philipjscott commented 4 years ago

This is honestly the most well-structured issue I have ever seen.

alexreal1314 commented 3 years ago

is this going to get fixed in the next release?