美文网首页
给你的mpv添加制作gif动图,截取音频,裁剪视频的功能

给你的mpv添加制作gif动图,截取音频,裁剪视频的功能

作者: mudssky | 来源:发表于2021-05-22 22:33 被阅读0次

    mpv是一个很强大的开源跨平台命令行播放器。虽然支持命令行和各种快捷键,但是mpv的gui也很不错,用户界面已经到了可用的水平,ui属于比较简洁的风格。

    个人来说使用这款播放器主要是通过快捷键操作,鼠标的用途是滚轮,可以用快进视频,还有右键是暂停视频,还有小窗时移动播放器的位置。

    mpv可以配置很多快捷键,也可以配置很多配置项。他最强大的地方是支持用户脚本,这样我们就可以自由地添加自己想要的功能。mpv支持lua和js两种用户脚本。

    它的js脚本支持到es5,个人来说更偏好js,因为我们可以用先进的typescript来编码,有很多新的语法糖可以用。而且生态上能用的库比lua多太多了。lua就只有运行快这一个优势了,但是在不用lua-jit的情况下性能差距并没有很明显。

    下面介绍的是我编写的mpv-gif.js脚本。

    mpv配置文件的最好使用方式是在目录下面创建 portable_config\scripts,然后脚本放进这个目录里面,作为绿色便携版使用。

    这是我存放脚本和配置文件的代码仓库,https://github.com/mudssky/mpv-config,脚本都放在scripts文件夹里。也有说明文档。

    本文后面是复制了仓库里的说明文档,并且把脚本的内容复制过来了。

    mpv-gif.js

    给你的mpv添加制作gif,webp动图的功能,除此之外,还能裁剪音频和视频。

    使用g指定开始时间,G指定结束时间。

    然后就可以用快捷键生成这段时间的gif,视频或是音频。

    个人更推荐使用webp动图,如果你上传的平台支持的话,webp动图体积更小画质也更好

    运行环境需求

    需要ffmepg的命令行工具,并且要放在环境变量里。

    feature

    • 截取gif或者webp动图,支持带字幕截取,支持外挂字幕。(注意可能有些字幕格式是不支持的。默认会截取第一个字幕或第一个外挂字幕,外挂字幕需要和文件名相同才会引入)
    • 无损截取音频
    • 无损截取视频

    配置说明

    你可以在js文件内进行配置。

    dir目前是没用的,本来是用来指定存放动图的目录,但是个人没有这个需求,就懒得做了。

    frameSize你也可以用1280*720这样来指定,我这里的默认设置是原视频的三分之一的长和宽,8帧

    其他选项下面有注释

    // 用户可配置的选项
    const userOptions = {
      dir: mp.get_property('working-directory'),
      //帧大小
      frameSize: 'iw/3:ih/3',
      //帧率 fps: 15,
      fps: 8,
      // 设置动图循环播放次数,0是无限循环播放
      loop: 0,
      // 是否带声音
      audio: false,
    }
    

    快捷键说明

    键位 作用
    g 设置起始时间
    G 设置结束时间
    Ctrl+g 生成gif动图
    Ctrl+G 生成带字幕的gif动图
    Ctrl+w 生成webp动图
    Ctrl+W 生成带字幕的webp动图
    Ctrl+a 截取音频
    Ctrl+v 截取视频
    "use strict";
    ;
    (function (mp) {
        var userOptions = {
            dir: mp.get_property('working-directory'),
            frameSize: 'iw/3:ih/3',
            fps: 8,
            loop: 0,
            audio: false,
        };
        var envOptions = {
            startTime: -1,
            endTime: -1,
            filename: '',
            basename: '',
            currentSubFilter: '',
            tracksList: [],
            audioCodec: '',
        };
        var animatePicType;
        (function (animatePicType) {
            animatePicType["webp"] = ".webp";
            animatePicType["gif"] = ".gif";
            animatePicType["png"] = ".png";
        })(animatePicType || (animatePicType = {}));
        function validateTime() {
            if (envOptions.startTime === -1 ||
                envOptions.endTime === -1 ||
                envOptions.startTime >= envOptions.endTime) {
                mp.osd_message('Invalid start/end time. ');
                return false;
            }
            return true;
        }
        function initEnvOptions() {
            envOptions.filename = mp.get_property('filename') || '';
            envOptions.basename = mp.get_property('filename/no-ext') || '';
            envOptions.tracksList = JSON.parse(mp.get_property('track-list') || '');
            dump('userOption:', userOptions);
            dump('envOptions', envOptions);
        }
        function setStartTime() {
            envOptions.startTime = mp.get_property_number('time-pos', -1);
            mp.osd_message("GIF Start: " + envOptions.startTime);
        }
        function setEndTime() {
            envOptions.endTime = mp.get_property_number('time-pos', -1);
            mp.osd_message("GIF End: " + envOptions.endTime);
        }
        function pathCorrect(path) {
            return path.replace(/\\/g, '/');
        }
        function getCurrentSub() {
            for (var index in envOptions.tracksList) {
                var currentObj = envOptions.tracksList[index];
                if (currentObj['selected'] && currentObj['type'] === 'sub') {
                    if (currentObj['external'] === true) {
                        envOptions.currentSubFilter = "subtitles='" + pathCorrect(currentObj['external-filename']) + "':si=0";
                    }
                    else {
                        envOptions.currentSubFilter = "subtitles='" + envOptions.filename + "'";
                    }
                }
            }
        }
        function getAudioType() {
            for (var index in envOptions.tracksList) {
                var currentObj = envOptions.tracksList[index];
                if (currentObj['selected'] &&
                    currentObj['type'] === 'audio' &&
                    currentObj['external'] !== true) {
                    envOptions.audioCodec = currentObj['codec'];
                    return currentObj['codec'];
                }
            }
            return '';
        }
        function geneRateAnimatedPic(picType, hasSubtitles) {
            if (!validateTime()) {
                return;
            }
            mp.osd_message('Creating GIF.');
            getCurrentSub();
            var commands = [];
            if (envOptions.currentSubFilter && hasSubtitles) {
                commands = [
                    'ffmpeg',
                    '-v',
                    'warning',
                    '-ss',
                    "" + envOptions.startTime,
                    '-i',
                    "" + envOptions.filename,
                    '-to',
                    "" + envOptions.endTime,
                    '-loop',
                    "" + userOptions.loop,
                    '-vf',
                    "fps=" + userOptions.fps + ",scale=" + userOptions.frameSize + "," + envOptions.currentSubFilter,
                    envOptions.basename + "[" + envOptions.startTime.toFixed() + "-" + envOptions.endTime.toFixed() + "]" + picType,
                ];
            }
            else {
                commands = [
                    'ffmpeg',
                    '-v',
                    'warning',
                    '-i',
                    "" + envOptions.filename,
                    '-ss',
                    "" + envOptions.startTime,
                    '-to',
                    "" + envOptions.endTime,
                    '-loop',
                    "" + userOptions.loop,
                    '-vf',
                    "fps=" + userOptions.fps + ",scale=" + userOptions.frameSize,
                    envOptions.basename + "[" + envOptions.startTime.toFixed() + "-" + envOptions.endTime.toFixed() + "]" + picType,
                ];
            }
            print(commands.join(' '));
            mp.command_native_async({
                name: 'subprocess',
                playback_only: false,
                args: commands,
                capture_stdout: true,
            }, function (success, result, err) {
                if (success) {
                    mp.msg.info("generate " + picType + ":" + envOptions.filename + " succeed");
                    mp.osd_message("generate " + picType + ":" + envOptions.filename + " succeed");
                }
                else {
                    mp.msg.warn("generate " + picType + ":" + envOptions.filename + " failed");
                    mp.osd_message("generate " + picType + ":" + envOptions.filename + " failed");
                }
            });
            if (userOptions.audio) {
                cutAudio();
            }
        }
        function getExt(filename) {
            var splitIndex = filename.lastIndexOf('.');
            var res = filename.substring(splitIndex + 1);
            dump('res', res);
            return res;
        }
        function cutAudio() {
            if (!validateTime()) {
                return;
            }
            var AudioType = getAudioType();
            var commands;
            commands = [
                'ffmpeg',
                '-v',
                'warning',
                '-i',
                "" + envOptions.filename,
                '-accurate_seek',
                '-ss',
                "" + envOptions.startTime,
                '-to',
                "" + envOptions.endTime,
                '-vn',
                '-acodec',
                'copy',
                envOptions.basename + ".mka",
            ];
            print(commands.join(' '));
            mp.command_native_async({
                name: 'subprocess',
                playback_only: false,
                args: commands,
                capture_stdout: true,
            }, function (success, result, err) {
                if (success) {
                    mp.msg.info("cut audio succeed");
                    mp.osd_message("Cut Audio Succeed.");
                }
                else {
                    mp.msg.warn("cut audio failed");
                    mp.osd_message("Cut Audio Failed.");
                }
            });
        }
        function cutVideo() {
            if (!validateTime()) {
                return;
            }
            var commands = [
                'ffmpeg',
                '-v',
                'warning',
                '-i',
                "" + envOptions.filename,
                '-accurate_seek',
                '-ss',
                "" + envOptions.startTime,
                '-to',
                "" + envOptions.endTime,
                '-c',
                'copy',
                envOptions.basename + "[" + envOptions.startTime.toFixed() + "-" + envOptions.endTime.toFixed() + "]." + getExt(envOptions.filename),
            ];
            print(commands.join(' '));
            mp.command_native_async({
                name: 'subprocess',
                playback_only: false,
                args: commands,
                capture_stdout: true,
            }, function (success, result, err) {
                if (success) {
                    mp.msg.info("cut video succeed");
                    mp.osd_message("Cut Video Succeed ");
                }
                else {
                    mp.msg.warn("cut video failed");
                    mp.osd_message("Cut Video failed ");
                }
            });
        }
        function generateGif() {
            geneRateAnimatedPic(animatePicType.gif, false);
        }
        function generateGifWithSub() {
            geneRateAnimatedPic(animatePicType.gif, true);
        }
        function generateWebp() {
            geneRateAnimatedPic(animatePicType.webp, false);
        }
        function generateWebpWithSub() {
            geneRateAnimatedPic(animatePicType.webp, true);
        }
        mp.add_key_binding('g', 'setStartTime', setStartTime);
        mp.add_key_binding('G', 'setEndTime', setEndTime);
        mp.add_key_binding('Ctrl+g', 'generateGif', generateGif);
        mp.add_key_binding('Ctrl+G', 'generateGifWithSub', generateGifWithSub);
        mp.add_key_binding('Ctrl+w', 'generateWebp', generateWebp);
        mp.add_key_binding('Ctrl+W', 'generateWebpWithSub', generateWebpWithSub);
        mp.add_key_binding('Ctrl+a', 'cutAudio', cutAudio);
        mp.add_key_binding('Ctrl+v', 'cutVideo', cutVideo);
        mp.register_event('file-loaded', initEnvOptions);
    })(mp);
    
    

    相关文章

      网友评论

          本文标题:给你的mpv添加制作gif动图,截取音频,裁剪视频的功能

          本文链接:https://www.haomeiwen.com/subject/vmoojltx.html