FFCreator icon indicating copy to clipboard operation
FFCreator copied to clipboard

通过Lite版本,组合视频+图片,无法得到音频

Open haimang opened this issue 3 years ago • 4 comments

FFMPEG版本 4.4.1,Ubuntu 20.04,Node 14


我们用了Lite版本官方demo里面的video.js做参考,将视频和图片进行组合的时候。

sence1 = 原视频,有声音 sence2 = 原图片转的视频

视频合成是没有问题的。但cache中的sence1.mp4将原视频中的音频丢失掉了。

我们试图用API,FFVideo中提供的audio部分设置为true,但组合视频的时候,却又碰到这样的错误提示: TypeError: fvideo1.setAudio is not a function

然后我们就不知道怎么办了。随后我们把官方demo中的lite版本,下载到本地,在上述环境中运行,官方demo中的video.js生成出来的demo,同样没有音频。。。

请问这大概是什么原因造成的呢?是我们有什么库没有安装?还是Node或其他依赖库的版本问题?

---- 附注我们运行时的log

第一部分,视频准备: single: ffmpeg -loop 1 -i /webapp/agencyfolio/node_modules/ffcreatorlite/lib/assets/blank.png -i https://accelerate.1f.sale/publicProperty/video/HCPP1-Tm7A9OEvQr/6bcc58606e7e81b898c2ebc925cd5fba0b495421.mp4 -y -filter_complex color=c=#000000:d=30:size=600600[background1-0];[background1-0][0:v]overlay=x=-10:y=0[image1-1];[1:v]scale=iw0.47:ih*0.47[video1-1];[image1-1][video1-1]overlay=x=0:y=161.25[video1-2] -map [video1-2] -r 24 -t 30 -hide_banner -map_metadata -1 -map_chapters -1 -c:v libx264 -profile:v main -preset medium -crf 20 -movflags faststart -pix_fmt yuv420p -map 0 /webapp/agencyfolio/cache/r0rctr851qwppj2r/scene1.mp4

↑ 这个sence1.mp4,就是丢失了音频的原视频

single: ffmpeg -loop 1 -i /webapp/agencyfolio/node_modules/ffcreatorlite/lib/assets/blank.png -loop 1 -i /webapp/agencyfolio/public/video//fooHCUR-cMIyMJH68B.png -y -filter_complex color=c=#ffffff:d=999999:size=600*600[background3-0];[background3-0][0:v]overlay=x=-10:y=0[image2-1];[image2-1][1:v]overlay=x=0:y=0[image3-1] -map [image3-1] -r 24 -t 10 -hide_banner -map_metadata -1 -map_chapters -1 -c:v libx264 -profile:v main -preset medium -crf 20 -movflags faststart -pix_fmt yuv420p -map 0 /webapp/agencyfolio/cache/8o58riilrtamrcze/scene2.mp4

第二部分,视频合成 ffmpeg -i /webapp/agencyfolio/cache/pz679lk9c3gbyi2t/scene1.mp4 -i /webapp/agencyfolio/cache/5tvrgk046tfq8gj2/scene2.mp4 -y -filter_complex [0:v][1:v]xfade=transition=hlslice:duration=1.5:offset=28.5[scene-0] -map [scene-0] -hide_banner -map_metadata -1 -map_chapters -1 -c copy -c:v libx264 -profile:v main -preset medium -crf 20 -movflags faststart -pix_fmt yuv420p -r 24 /webapp/agencyfolio/public/video/videoHCPP1-Tm7A9OEvQr_HCUR-cMIyMJH68B.mp4

haimang avatar Feb 23 '22 09:02 haimang

setAudio is the api of ffcreator, not the api of the lite version. Are you using the standard version of ffmpeg?

drawcall avatar Feb 24 '22 03:02 drawcall

Maybe you can upload the project

drawcall avatar Feb 24 '22 03:02 drawcall

  1. we have tried setAudio on both FF and lite version, it reported the same error message
  2. we also tried using lite version official demo code (video.js), but running on our environment, result is also disappointing.
  3. FFMPEG was a direct apt-get from repository. and we are at FFMPEG 4.4.1

Here is our video.js code clip - USING FFcreator

import apis, { apilawyerAdd } from '../../../utils/apis' import utils from '../../../utils/utils' const path = require('path'); import colors from 'colors' import { FFCreatorCenter, FFScene, FFImage, FFCreator, FFVideo,FFAudio } from 'ffcreator' import pdf from 'html-pdf'; import { pageTPL } from '../../../theme/default/video/video' import withSession from '../../../utils/session' import getVideoWH from 'get-video-width-height' import store from "store"; import expirePlugin from 'store/plugins/expire' const getVideoDuration = require('node-video-duration'); export default withSession(async (req, res) => { const { hash, unit_hash, update_time, color, videourl } = req.query

const tphash = req.session.get('tphash'); const type = req.query.type && req.query.type != undefined ? parseInt(req.query.type) : 0 const isEn = req.query.isEn && req.query.isEn != undefined ? parseInt(req.query.isEn) : 0 //0中文 1英文 2繁体 const debug = req.query.debug && req.query.debug != undefined ? parseInt(req.query.debug) : 0; const quality = req.query.quality && req.query.quality != undefined ? parseInt(req.query.quality) : 0; const ROOT_PATH = process.cwd(); var fs = require('fs');

// const video1 = videourl && videourl != undefined ? videourl : path.join(ROOT_PATH, '/assets/video/video3.mp4'); const outputDir = path.join(ROOT_PATH, '/public/video/'); const cacheDir = path.join(ROOT_PATH, '/cache/');

if (tphash && tphash != undefined) { let tpname = utils.setthirdparty(apis, tphash) if (tpname) {

  const token = await utils.token(fs, apis, tpname);
  let authToken = await utils.authToken(apis, req, token);
  const body = await Promise.all([
    apiV2flowDetail_store(token, hash),
    utils.userinfo(apis, token, authToken)
    //apitphashpartysystemBottom(token)
  ])
  const [_details, _userinfo] = body
  if (_details.code == 0) {
    var details = _details.data
    var video1 = details.video
    if (details.video) {
      // const _userinfo = await utils.userinfo(apis, token, authToken)
      let usercard = {}
      if (_userinfo.code == 0) {
        let myinfo = _userinfo.data
        const userinfo = req.session.get('userinfo');
        usercard = userinfo;
        usercard.role_type = myinfo.portal_info.role_type
        usercard.is_company = myinfo.portal_info.is_company
        usercard.portal = {}
        usercard.portal.hash = myinfo.portal_info.hash
        usercard.portal.logo = myinfo.portal_info.primary_image.thumb.replace("/format/webp", "/format/png")
        usercard.portal.name = myinfo.portal_info.name_en
        usercard.portal.name_cn = myinfo.portal_info.name_cn
        usercard.name = userinfo.first_name ? userinfo.first_name : '';
        usercard.surname = userinfo.last_name ? userinfo.last_name : ''
        usercard.qrcode = myinfo.qrcode.replace("/format/webp", "/format/jpg")
        usercard.avatar = myinfo.avatar.replace("/format/webp", "/format/jpg");
 
        let imgpath = outputDir + '/foo' + usercard.hash + '.png';
        let img=await pdfIMG(fs,utils,req,imgpath,usercard);

        var number = details.hash+"_"+usercard.hash;
        let filename = "video" + number;
        let filetype="mp4";
        let filepath=filename+"."+filetype
        let videopath=outputDir + filepath
        console.log("videopath",videopath);
        console.log("videourl",video1);
        let video= await videoEdit(fs,cacheDir,outputDir,img,videopath,video1);
        res.statusCode = 200
        res.json({
          code:0,
          data:{
            filename,
            filename,
            fileurl:"/video/"+filepath
          }
        });
      }else{
        res.statusCode = 200
        res.json(_userinfo);
      }
      
    } else {
      res.statusCode = 200
      res.json({
        code: 404,
        message_cn: "找不到视频文件!",
        message_en: "Video file not found!"
      })
    }

  } else {
    res.statusCode = 200
    res.json(_details);
  }



} else {
  res.statusCode = 200
  res.json({
    code: 417,
    message: "第三方信息不对!"
  })
}

} else { res.statusCode = 200 res.json({ code: 417, message_cn: "登录过期,重新登录", message_en: "Your login credential has expired, please login agian." })

}

}) function apiV2flowDetail_store(token, hash) { return new Promise(async (resolve, reject) => { let details = store.get("detailsFlow_" + hash); //console.log("details_time",JSON.parse(details_time),JSON.parse(details).data.update_time,JSON.parse(details_time)==JSON.parse(details).data.update_time?1:2) if (details && details != undefined) { resolve(details) } else { const body = await apiV2flowDetail(token, hash); resolve(body) if (body.code == 0) { store.set("detailsFlow_" + hash, body) } }

}) } function apiV2flowDetail(token, hash) { var url = apis.apiBaseUrl + apis.apiV2flowDetail return utils._get(url, { token: token, scene: "pwa", hash: hash }) } function pdfIMG(fs,utils,req,imgpath,usercard){ return new Promise(async (resolve, reject) => { fs.exists(imgpath, (exists) => { if (exists) { console.log("图片文件已存在"); resolve(imgpath) } else { console.log("图片文件不存在"); let host = req.headers.host // let TPhost = utils.setTPhost(host, tpname, parseInt(isEn) ? "en" : "zh", "zh") // usercard.avatar=""; let H5url = "https://"+host var tpl = pageTPL(utils, usercard, H5url); const ROOT_PATH = process.cwd(); var Html = fs.readFileSync(ROOT_PATH + '/theme/default/video/video.html', 'utf8'); // console.log("tpl",tpl); var htmldata = Html.replace("{{page}}", tpl); var options = { height: 600 + "px", width: 600 + "px", phantomArgs: ['--ignore-ssl-errors=yes'], "localUrlAccess": true, type: "png", "quality": "100", };//"localUrlAccess": false, pdf.create(htmldata, options).toStream(async function (err, stream) {

        stream.pipe(fs.createWriteStream(imgpath));
        console.log("生成图片成功!");
        resolve(imgpath)
      })
 }

});

}) } async function videoEdit(fs,cacheDir,outputDir,img,videopath,videourl){ return new Promise(async (resolve, reject) => { fs.exists(videopath,async (exists) => { if (exists) { console.log("视频文件已存在"); resolve(videopath) } else { console.log("视频生成中"); const width = 600; const height = 600; // create creator instance const creator = new FFCreator({ cacheDir, outputDir, width: width, height: height, audioLoop: true, debug:true });

  creator.setOutput(videopath);
  //create FFScene
  const scene1 = new FFScene();
  // scene1.setBgColor('#9980fa');
  const scene2 = new FFScene();
  scene2.setBgColor('#ffffff');

  let video_info = await getVideoWH(videourl);
  console.log("video_info", video_info);
  let video_w = 0, video_h = 0;
  let pot = video_info.width / video_info.height
  console.log("aaa", Math.ceil(pot));
  let Scale = 1, x = 0, y = 0;
  if (Math.ceil(pot) > 1) {
    video_w = width;
    video_h = (width * video_info.height) / video_info.width
    Scale = width / video_info.width
    Scale = Scale.toFixed(2)
    y = (height - video_h) / 2
  } else {
    video_w = (width * video_info.width) / video_info.height;
    video_h = width
    Scale = width / video_info.height
  }
  console.log(video_w, video_h)

  const Duration= await getVideoDuration(videourl);
  console.log("Duration",Duration);

  const fvideo1 = new FFVideo({ path: videourl, y: y });
  fvideo1.setScale(Scale);
  // fvideo1.setAudio(true);

  scene1.addChild(fvideo1);
  scene1.setDuration(Duration);
  scene1.setTransition('hlslice', 1.5);
  
  creator.addChild(scene1);



  const fimg = new FFImage({ path: img, x: 0, y: 0 });
  fimg.setScale(1);
  // flogo.addEffect('fadeIn', 2.5, 1.5);    
  scene2.addChild(fimg);

  creator.addChild(scene2);

  creator.start();
  creator.openLog();

  creator.on('start', () => {
    console.log(`FFCreatorLite start`);
  });

  creator.on('error', e => {
    console.log(`FFCreatorLite error:: \n ${e.error}`);
  });

  creator.on('progress', e => {
    console.log(colors.yellow(`FFCreatorLite progress: ${(e.percent * 100) >> 0}%`));
  });

  creator.on('complete', e => {
    console.log(
      colors.magenta(`FFCreatorLite completed: \n USEAGE: ${e.useage} \n PATH: ${e.output} `),
    );

    console.log(colors.green(`\n --- You can press the s key or the w key to restart! --- \n`));
    const file = e.output;
    console.log("e11111", e)
    // res.setHeader('Content-Type', 'video/mp4; charset=utf-8');
    resolve(file)
  });
 }

});

}) }

haimang avatar Feb 24 '22 03:02 haimang

手动看看两个视频文件的编码 视频和音频 是不是一致的 输出的视频 codec和acodec编码是不是一致

wanghaisheng avatar Mar 04 '22 11:03 wanghaisheng