6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FFmpegを用いて音入り動画を作成できる無料アプリ

6
Last updated at Posted at 2021-12-22

9VAeきゅうべえ Windows / Linux /Android 版の欠点

フリーソフト9VAeきゅうべえは、下のような動画が簡単につくれるベクトルアニメーションアプリです。2Dグラフィックス作成機能があり、音も入れられます。

(new-sample).gif

しかし音入りの MP4動画を作ることは、Windows / Linux /Android 版ではできませんでした。(Mac / iPhone / iPad版は可能。上はアニメGIF)

今回、FFmpegで音入りアニメーション動画を作成する方法を見つけましたので紹介します。この方法をつかって、9VAeきゅうべえは、どのOSでも動画出力できるようになりました。

9VAe きゅうべえの音声の仕様

  • 9VAeには、効果音、音楽の2トラックがあり、2つの音を同時に鳴らすことができます。
  • 音が鳴っているトラックで別の音を鳴らすと前の音は停止します。
  • 音の開始時間はキーフレームからわかります。
  • 9VAeは音のファイルを指定時刻に鳴らすだけで、音を修正する機能はありません。

音声トラック.gif

FFmpeg の機能

  • FFmpeg は連番画像から動画を作成する機能があります。
  • 動画に音を入れる機能があります。
  • 動画や音をカットしたり、つないだりする機能があります。
  • オプションの説明

ただ、その記述方法がわかりにくく、試行錯誤を繰り返しました。結局、理解したこと。

  • 動画に音声を合成するときに、時間を指定して、そこに音を入れる機能はないみたい。途中から音を鳴らしたい場合は、音の前に無音をいれる。短い音をいれる場合、音の後ろに無音をいれなければならない。
  • そのため、鳴らす音の長さを正確にはかる必要がある。
  • 映像に2トラックの音をいれることもできるはずだが、うまくならなかった。結局、効果音トラック、音楽トラックの音を合成してひとつの音にした。

今回、FFmpegで使用した機能は以下です。いろんなOSで同じように動作します。

機能 命令
連番画像から映像作成 -vcodec mpeg4 -pix_fmt yuv420p
指定した時間の無音作成 -f lavfi -i aevalsrc
指定した時間で音をカット -t 秒
2つの音をつなぐ -filter_complex concat
作成した音の時間を取得 関数を自作
2トラックの音を重ねる -filter_complex
映像に音を追加する -c:v copy -c:a copy

これらの機能をつかって、効果音トラック、音楽トラックの音を無音をはさんで順番につなげていき、最後に、2つのトラックを合成して1トラックにし、映像に入れます。具体例を示します。

連番画像から映像作成

ffmpeg -y -r 1秒のフレーム数 -i %04d.jpg -b 6000k -vcodec mpeg4 -pix_fmt yuv420p video.mp4 

%04d.jpg は連番画像(%04d は、0001,0002,0003...)9VAeから指定したフレームレート、画像サイズで出力します。なお、画像サイズを奇数にするとスマホで再生できないようです。
video.mp4 は出力ファイル名
-y は同名ファイルがあったときの上書き指定

指定した時間(秒)の無音作成

ffmpeg -f lavfi -i aevalsrc=0:d=-ac 2 -strict -2  -c:a aac -ab 256k  out.m4a

秒は小数可能
-strict -2 がないとエラーになるときがある

指定した時間(秒)で音をカット

ffmpeg -i in.wav -t-c:a aac -ab 256k out.m4a

in.wav が 指定した時間より短い場合、out.m4a は、指定した時間より短い音になる。out.m4a の時間を調べ、必要なら、無音を追加しなければならない。
-ab 256k はビットレート指定で CD音質

2つの音をつなぎ、指定した時間(秒)で音をカット

ffmpeg -i in.m4a -i in.wav -t-filter_complex concat=n=2:v=0:a=1   -ab 256k out.m4a

in.m4a の後ろに in.wav をつなぐ

2トラックの音を重ねる

ffmpeg -y -i trk1.m4a -i trk2.m4a -filter_complex "[0:a][1:a]amix=inputs=2[a]" -map "[a]" -ab 256k out.m4a

2つの音、trk1.m4a trk2.m4a を重ねて1トラックの音 out.m4a にする

映像に音をつける

ffmpeg -y -i video.mp4 -i add.m4a -c:v copy -c:a copy out.mp4

映像 video.mp4 に 音 add.m4a をつける

音 m4a の時間(msec)を取得

以下のようなプログラムを自作しました。エラーの場合、負の値が返ります。

#include <stdio.h>

#define CHis(a,b,c,d) ((a)==hd[4] && (b)==hd[5] && (c)==hd[6] && (d)==hd[7])
#define Int3(a) *(a)*0x10000   + *((a)+1)*0x100   + *((a)+2)
#define Int4(a) *(a)*0x1000000 + *((a)+1)*0x10000 + *((a)+2)*0x100 + *((a)+3)
//m4a 形式の音の再生時間(msec)を取得する
long AcGetM4aMsec(char *fileName)
{
    FILE *fp; int bb,cc; long ret=-1;
    unsigned char hd[8],work[1024]; 

    // ファイルオープン
    fp = fopen(fileName, "rb");
    for(;fp;){
        // 先頭フレームのヘッダ8Byteを読み込む
        if(fread(hd, 1, 8, fp) != 8) break;
        bb = Int4(hd);//チャンクサイズ
        bb-=8;
        if(CHis('m','o','o','v')){//メタデータ発見
            for(;bb>0;){
                if(fread(hd, 1, 8, fp) != 8) break; 
                bb-=8;
                cc = Int4(hd);//チャンクサイズ
                bb-=cc;
                for(;cc>0;cc-=1024){
                    if(fread(work, 1, cc>1024?1024:cc, fp) < 1024) break;
                }
                if(CHis('m','v','h','d')){//時間情報が入っている
                    int version=work[0];
                    int flags = Int3(work+1);
                    int creatTime = Int4(work+4);
                    int modifTime = Int4(work+8);
                    int timeScale = Int4(work+12);//秒60 の場合60
                    int duration  = Int4(work+16);//duration/timeScale=秒
                    ret = (long)((double)duration*1000/timeScale);
                    goto exit;
                }
            }
            continue;
        }
        for(;bb>0;bb-=1024){//データ読み飛ばし
            if(fread(work, 1, bb>1024?1024:bb, fp) < 1024) break;
        }
    }
exit:
    if(fp) fclose(fp);
    return ret;
}

FFmpeg バージョンアップ対応

FFmpegのバージョンをあげると、画像から動画作成はできるが、音の合成がうまくいかなくなった。AIに尋ねると以下のような仕様変更があるようです

-strict -2 はもう不要

以前のFFmpegでは、内蔵のAACエンコーダが「実験的」扱いだったためこのオプションが必要でした。しかし、2015年末(ver 3.0以降)からは正式版となり、この指定なしで動作します。

-ab は古い形式

オーディオビットレートを指定するパラメータですが、現在は -b:a と書くのが標準的です。-ab も互換性のために残っていますが、将来的に廃止される可能性があるため 推奨されません。(古)-ab 256k >(新)-b:a 256k

Android版FFmpegの注意

  • 16KBアラインメント対応ライブラリ「ffmpeg-kit-lts-full-16kb」を使わないとアプリストアに登録できません
  • Java(Android)からFFmpegKitを使用して、Storage Access Framework (SAF) で取得したURI(content://)のファイルに読み書きするには、FFmpegKit専用のSAFプロトコル文字列に変換する必要あり(StackOverFlow

読み込み(Read)

うまく動作しなかった

// URIをFFmpegKit用のSAFパスに変換し、-i の後ろに指定
String inputPath = FFmpegKitConfig.getSafParameterForRead(context, inputUri);
String command = "-i " + inputPath + " [出力オプション]";
FFmpegKit.execute(command);

## 書き込み(Write)

// URIをFFmpegKit用のSAFパスに変換し、出力先に指定
String outputPath = FFmpegKitConfig.getSafParameterForWrite(context, outputUri);
String command = "[入力オプション] " + outputPath;
FFmpegKit.execute(command);
6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?