アイデア
1 つのビデオ トラックを 1 つ (または必要に応じて 2 つ) のオーディオ トラックと結合するムービー編集アプリケーション用に、デバイスへの保存機能を作成しています。
まず、 MP4Parser (リンク) を使用して1 つのビデオ トラックにマージする複数のビデオ クリップがあります。
次に、複数のオーディオ クリップを1 つのオーディオ トラックに結合したいと考えています。これらのクリップは追加するのではなく、特定の時間に 1 つのオーディオ トラックにマージする必要があります。たとえば、2 つのオーディオ クリップ (A1、A2) と 60 秒のビデオ トラック (V1) があります。これらのオーディオ クリップは、重複していたり、間にホワイト ノイズが含まれていたりする可能性があります。オーディオ トラック全体の長さはビデオ トラックと一致する必要があり、最大 60 秒まで可能です。オーディオ トラック 1 には、最大 100 個のオーディオ クリップを追加できます。
- V1 - 60.0 秒
- A1 - 0.3 秒
- A2 - 1.1秒
最後に、V1 ビデオ トラックに適合する、サウンドトラックも含むオプションの 2 番目のオーディオ トラックがある場合があります。
概要
これは次のようになります。
ビデオ トラック 1: [--------------------------------------------- -----------------------------------] 60秒
音声トラック 1: [-A1--A2---------------------------------------- ----------------------------] 60秒
オーディオ トラック 2: [--------------------------------------------- ----------------------------------] 60秒
問題
上記のように、音声トラックに x 秒のホワイト ノイズ (空の wav ファイル) を追加して完全な長さのトラックを取得することで問題にアプローチしようとしましたが、サウンドがオーバーラップしている場合は明らかに機能しません。この問題に取り組むには、他にどのような方法がありますか?
private static final String OUTPUT = "output.mp4";
private static final String STORED_LOCATION = "/storage/emulated/0/"
/**
* Merges two videos that are located in /storage/emulated/0/ and saves it to the same place with the given parameters. Uses the ffmpeg/javacv library. All this is done in an Async task, not blocking the UI thread but showing a progress bar and a toast at the end.
*
*/
private void mergeVideosAsync()
{
new AsyncTask<Void, Void, String>()
{
@Override
protected String doInBackground(Void... arg0)
{
try
{
List<Movie> movieList = new ArrayList<>();
for (int i = 0; i < mVideoPathList.size(); ++i)
{
movieList.add(MovieCreator.build(new File(mVideoPathList.get(i)).getAbsolutePath()));
}
List<Track> videoTracks = new LinkedList<>();
List<Track> audioTracks = new LinkedList<>();
for (Movie m : movieList)
{
for (Track t : m.getTracks())
{
if (t.getHandler().equals("soun"))
{
//TODO: Add audio tracks here to the merging process
// audioTracks.add(t);
}
if (t.getHandler().equals("vide"))
{
videoTracks.add(t);
}
}
}
Movie result = new Movie();
if (audioTracks.size() > 0)
{
result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
}
if (videoTracks.size() > 0)
{
result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
}
BasicContainer out = (BasicContainer) new DefaultMp4Builder().build(result);
mOutputPath = String.format(STORED_LOCATION + File.separator + OUTPUT_FILENAME);
WritableByteChannel fc = new RandomAccessFile(mOutputPath, "rw").getChannel();
out.writeContainer(fc);
fc.close();
}
catch (Exception e)
{
e.printStackTrace();
}
return mOutputPath;
}
}.execute();
}