react:ffcreator中FFCreatorCenter视频队例

最近项目要求,一键生成房子的推荐视频,选几张图,加上联系人的方式就是一个简单的视频,因为有web端、小程序端,为了多端口用,决定放在服务器端生成。

目前用的是react中的nextjs来开发项目。

nextjs中怎样用ffcreator上一章有讲到过,这里不再详细说了,考虑多端口用,并发和处理视频合成等一系列对服务器压力过大的情况,这时候队列就有必要了。

一通了解后FFCreatorCenter能实现队列。官方有koa实现队列的例子。看过后怎样在nextjs中实现?

找准思路:

1.制作预设视频动画模板,意思是合成视频的模板提前预设好的,比如静态内容都提前准备好

2.用户选择想要的视频模板,然后根据视频模板添加动态内容,排队生成视频

3.查询视频生成情况

按照上述流程,我们开干:

1。制作预设视频模板,做一个模板比如相册视频,放到模板详情接口中调用AddTPL(id)


import { FFAlbum, FFScene, FFImage, FFCreator, FFRect, FFText, FFCreatorCenter } from 'ffcreator'
const path = require('path');
import colors from 'colors'
export default function AddTPL({ id }) {
 FFCreatorCenter.createTemplate(id, async ({ }) => {
//用官方图片例子
 const ROOT_PATH = process.cwd();

    const bg1 = path.join(ROOT_PATH, '/assets/imgs/bg/05.jpg');
    console.log(bg1)
    const bg2 = path.join(ROOT_PATH, '/assets/imgs/bg/04.jpeg');
    const logo2 = path.join(ROOT_PATH, '/assets/imgs/logo/logo2.png');
    const cloud = path.join(ROOT_PATH, '/assets/imgs/cloud.png');
    const mars = path.join(ROOT_PATH, '/assets/imgs/mars.png');
    const rock = path.join(ROOT_PATH, '/assets/imgs/rock.png');
    const title = path.join(ROOT_PATH, '/assets/imgs/title.png');
    const audio = path.join(ROOT_PATH, '/assets/audio/05.wav');
    const outputDir = path.join(ROOT_PATH, '/video/');
    const cacheDir = path.join(ROOT_PATH, '/cache/');
    FFCreator.setFFmpegPath('D:/nextAppV2/H5/ffmpeg-6.0-full_build/bin/ffmpeg.exe');
    // create creator instance
    const width = 576;
    const height = 1024;
    const creator = new FFCreator({
        cacheDir,
        outputDir,
        width,
        height,
        //log: true,
        highWaterMark: '3mb',
        parallel: 8,
        fps: 30,
        audio,
    });

    // create FFScene
    const scene1 = new FFScene();
    const scene2 = new FFScene();
    scene1.setBgColor('#0b0be6');
    scene2.setBgColor('#b33771');

    // add scene1 background
    const fbg1 = new FFImage({ path: bg1, x: width / 2, y: height / 2 });
    scene1.addChild(fbg1);

    // add bottom cloud
    const fcloud = new FFImage({ path: cloud, x: width });
    fcloud.setAnchor(1);
    fcloud.addAnimate({
        from: { y: height + 180 },
        to: { y: height },
        time: 0.8,
        ease: 'Back.Out',
    });
    scene1.addChild(fcloud);

    // add mars ball
    const fmars = new FFImage({ path: mars, x: width / 2, y: height / 2 });
    fmars.addEffect(['rollIn', 'zoomIn'], 1.8, 0.8);
    scene1.addChild(fmars);

    // add rock image
    const frock = new FFImage({ path: rock, x: width / 2 + 100 });
    frock.addAnimate({
        from: { y: height / 2 + 720 },
        to: { y: height / 2 + 80 },
        time: 1,
        delay: 2.3,
        ease: 'Cubic.InOut',
    });
    scene1.addChild(frock);

    // add rock image
    const ftitle = new FFImage({ path: title, x: width / 2, y: height / 2 - 300 });
    ftitle.addEffect('fadeInUp', 1, 4);
    scene1.addChild(ftitle);

    // add logo
    const flogo1 = new FFImage({ path: logo2, x: width / 2, y: 50 });
    flogo1.setScale(0.5);
    scene1.addChild(flogo1);

    scene1.setDuration(8);
    scene1.setTransition('InvertedPageCurl', 1.5);
    creator.addChild(scene1);

    // add scene2 background
    const fbg2 = new FFImage({ path: bg2, x: width / 2, y: height / 2 });
    scene2.addChild(fbg2);
    // add logo
    const flogo2 = new FFImage({ path: logo2, x: width / 2, y: height / 2 - 80 });
    flogo2.setScale(0.9);
    flogo2.addEffect('fadeInDown', 1, 1.2);
    // 9s remove
    flogo2.remove(9);
    scene2.addChild(flogo2);

    scene2.setDuration(5);
    creator.addChild(scene2);

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

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

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

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

    creator.on('complete', e => {
        console.log(
            colors.magenta(`FFCreator 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`));
        
    });
  return creator;
})
}

 2.添加队列,

//添加队列
export function AddTask({  Templateid }) {
    const Taskid = FFCreatorCenter.addTaskByTemplate(Templateid, { });
            res.statusCode = 200
            res.json({
                code: 0,
                data: {
                    taskid: Taskid
                }
            })
}

3.查询成功接口,并下载mp4 

//下载
import { FFAlbum, FFScene, FFImage, FFCreator, FFRect, FFText, FFCreatorCenter } from 'ffcreator'
export default async (req, res) => {
const taskid = req.query.taskid
var fs = require('fs');

 FFCreatorCenter.onTaskError(taskid, function (err) {
            console.log("onTaskError", err)
          
        })
        FFCreatorCenter.onTaskComplete(taskid, function (e) {
            console.log("onTaskComplete", e)
            let { file, taskObj } = e
            let output = file ? file.replace(/\/\//g, "/") : ""
            fs.readFile(output, function (isErr, data) {
                    if (isErr) {
                        
                    } else {
                       
                        let file_name = new Date().getTime()
                 

                        let Disposition = "inline;";
                        if (scene == "pwa") {
                            Disposition = "attchment;";
                        }
                        if (scene == "mini") {
                            Disposition = "inline;";
                        }
                        res.setHeader('Content-Type', 'video/mp4; charset=utf-8');
                        res.setHeader('Content-Disposition', `${Disposition}filename=${encodeURIComponent(file_name)}.mp4`);
                        res.status(200)
                        res.end(data)
                        
                        
                    }





                })
        })

}

另附上视频转gif的方法:

let cp = require('child_process');

 let flie_gif = `${cacheDir}${taskid}.gif`
            const bb = `ffmpeg -ss 00:00:00 -to 00:00:${videoConfig.duration} -i ${output} -r 10 -vf scale=1050:-1 ${flie_gif}`
            cp.exec(bb,
                function (error, stdout, stderr) {

                    if (error) {
                        console.log('执行的结果error:', error)
                        
                    } else {
                        fs.readFile(flie_gif, function (isErr, data) {
                            if (isErr) {
                                console.log('执行的结果error:', isErr)
                            } else {
                               
                              let file_name = new Date().getTime()
                               

                                let Disposition = "inline;";
                                if (scene == "pwa") {
                                    Disposition = "attchment;";
                                }
                                if (scene == "mini") {
                                    Disposition = "inline;";
                                }
                                res.setHeader('Content-Type', 'image/gif; charset=utf-8');
                                res.setHeader('Content-Disposition', `${Disposition}filename=${encodeURIComponent(file_name)}.gif`);
                                res.status(200)
                                res.end(data)
                               
                            }





                        })
                    }
                    // console.log('执行的结果stdout:', stdout)
                    // console.log('执行的结果stderr:', stderr)


                })

你可能感兴趣的:(FFCreator,next.js,react-next,react.js,前端,前端框架)