NodeJS使用FFMPEG获取视频封面

2022-12-22 14:11:13 浏览数 (2)

前言

大多数获取视频的封面都是使用FFMpeg获取视频的第一帧,但是很多视频第一帧是纯黑的,我们就要取后面的帧,这时候我们就要知道视频本身有多长。

获取视频时长

容器时长(container duration)的获取方法:

代码语言:javascript复制
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 -i a.mp4

音视频流时长(stream duration)的获取方法:

代码语言:javascript复制
ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 a.mp4

一个媒体文件里边有多个音视频流,各个流的时长也未必一样,一般播放器会以video stream的时长作为播放时长。

生成封面

代码语言:javascript复制
ffmpeg -i a.mp4 -y -f image2 -ss 2 -frames 1 a001.jpg

方式2

代码语言:javascript复制
ffmpeg -i a.mp4 -y -f image2 -ss 2 -t 0.001 a002.jpg

-ss 从几秒开始

NodeJS调用

代码语言:javascript复制
let cp = require('child_process');

const execGetSec = (pathFile) => {
  const cmd = `ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 ${pathFile}`
  console.log('当前指令:', cmd)
  cp.exec(cmd, (err, stdout, errout) => {
    if (!err) {
      console.log('结果:', stdout)
    }
  })
}

const execJpg = (pathFile, saveFilePath) => {
  const cmd = `ffmpeg -i ${pathFile} -y -f image2 -ss 2 -frames 1 ${saveFilePath}`
  console.log('当前指令:', cmd)
  cp.exec(cmd, (err, stdout, errout) => {
    if (!err) {
      console.log(`${saveFilePath} success...`)
    }
  })
}

execGetSec("D:\Video\a.mp4");
// execJpg("D:\Video\a.mp4", "D:\Video\a002.jpg");

封装

代码语言:javascript复制
let cp = require('child_process');

const execGetSec = (pathFile) => {
  return new Promise(((resolve) => {
    const cmd = `ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 ${pathFile}`
    cp.exec(cmd, (err, stdout, errout) => {
      if (!err) {
        resolve(parseInt(stdout))
      } else {
        resolve(0);
      }
    })
  }))
}

const execJpg = (pathFile, saveFilePath) => {
  return new Promise(((resolve, reject) => {
    const cmd = `ffmpeg -i ${pathFile} -y -f image2 -ss 2 -frames 1 ${saveFilePath}`
    cp.exec(cmd, (err, stdout, errout) => {
      if (!err) {
        resolve(saveFilePath);
      } else {
        resolve("")
      }
    })
  }))
}

const execJpgByTime = (pathFile, saveFilePath) => {
  return new Promise((async (resolve, reject) => {
    let sec = await execGetSec(pathFile);
    let fromSec = 0;
    if (sec > 5) {
      fromSec = 5;
    } else {
      fromSec = sec / 2;
    }
    const cmd = `ffmpeg -i ${pathFile} -y -f image2 -ss ${fromSec} -frames 1 ${saveFilePath}`
    cp.exec(cmd, (err, stdout, errout) => {
      if (!err) {
        resolve(saveFilePath);
      } else {
        resolve("")
      }
    })
  }))
}

async function main() {
  let sec = await execGetSec("D:\Video\a.mp4");
  console.info(sec);

  let path = await execJpg("D:\Video\a.mp4", "D:\Video\a_001.jpg");
  console.info(path);

  let path2 = await execJpgByTime("D:\Video\a.mp4", "D:\Video\a_002.jpg");
  console.info(path2);
}

main();

导出/导入

代码语言:javascript复制
let cp = require('child_process');

const execGetSec = (pathFile) => {
  return new Promise(((resolve) => {
    const cmd = `ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 ${pathFile}`
    cp.exec(cmd, (err, stdout, errout) => {
      if (!err) {
        resolve(parseInt(stdout))
      } else {
        resolve(0);
      }
    })
  }))
}

const execJpgByTime = (pathFile, saveFilePath) => {
  return new Promise((async (resolve, reject) => {
    let sec = await execGetSec(pathFile);
    let fromSec = 0;
    if (sec > 5) {
      fromSec = 5;
    } else {
      fromSec = sec / 2;
    }
    const cmd = `ffmpeg -i ${pathFile} -y -f image2 -ss ${fromSec} -frames 1 ${saveFilePath}`
    cp.exec(cmd, (err, stdout, errout) => {
      if (!err) {
        resolve(saveFilePath);
      } else {
        resolve("");
      }
    })
  }))
}

exports.execJpgByTime = execJpgByTime;

导入

代码语言:javascript复制
const {
  execJpgByTime
} = require("./coverUtil.js")

CentOS安装ffmpeg

yum安装

首先更新系统。

代码语言:javascript复制
sudo yum install epel-release -y
sudo yum update -y

安装Nux Dextop Yum 源

由于CentOS没有官方FFmpeg rpm软件包。但是,我们可以使用第三方YUM源(Nux Dextop)完成此工作。

CentOS 7

代码语言:javascript复制
sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm

CentOS 6

代码语言:javascript复制
sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el6/x86_64/nux-dextop-release-0-2.el6.nux.noarch.rpm

安装FFmpeg 和 FFmpeg开发包

代码语言:javascript复制
sudo yum install ffmpeg ffmpeg-devel -y

测试是否安装成功

代码语言:javascript复制
ffmpeg
ffprobe

Docker内不要添加sudo

代码语言:javascript复制
# 安装ffmpeg
RUN yum install epel-release -y
RUN yum update -y
RUN rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
RUN rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
RUN yum install ffmpeg ffmpeg-devel -y

编译安装

先下载源码包:

代码语言:javascript复制
git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg

然后进入ffmpeg文件夹,依次执行下列语句,当然连起来也可以:

代码语言:javascript复制
cd ffmpeg
./configure
make && make install

时间较长,不出意外会正常安装好。

但是因为configure时候没有指定路径,所以直接ffmpeg会提示找不到。

所以要将编译好的ffmpeg复制到bin目录即可:

代码语言:javascript复制
cp ffmpeg /usr/bin/ffmpeg

然后检查版本。

代码语言:javascript复制
ffmpeg -version

0 人点赞