ユーザーが任意のアプリから動画を選択できるようにしてから、動画を最大5秒にトリミングします。
Uriを選択するために、正常に機能しました(ソリューションが利用可能です here )。
トリミング自体に関しては、 "k4l-video-trimmer"と呼ばれるものを除いて、パーミッシブライセンスを持つ優れたライブラリは見つかりませんでした。 -) 。たとえば、ライブラリ「FFmpeg」はGPLv3を使用しているため、許可されていないと見なされます。GPLv3を使用するアプリは、オープンソースでもある必要があります。その上、私が読んだように、それはかなり多く(約9MB)かかります。
残念ながら、このライブラリ(k4l-video-trimmer)は非常に古く、何年も更新されていなかったため、適切に処理するためにフォーク( here )する必要がありました。 "mp4parser" というオープンソースのライブラリを使用してトリミングを行います。
問題は、このライブラリはUri
やInputStream
ではなくファイルのみを処理できるように見えるため、通常のファイルのように到達できないアイテムを選択すると、サンプルでさえクラッシュする可能性があることです。または、処理できないパスがある場合もあります。多くの場合、ファイルのパスを取得できることは知っていますが、そうでない場合も多く、ファイルをコピーすることも可能です( here )ですが、ファイルはすでにアクセス可能であるにもかかわらず、ファイルが大きくなり、多くのスペースを占める可能性があるため、これは適切な解決策ではありません。
ライブラリがファイルを使用する場所は2つあります。
「K4LVideoTrimmer」ファイルの「setVideoURI」関数で、表示するファイルサイズを取得するだけです。ここでの解決策は、 Googleのドキュメント に基づいて非常に簡単です。
public void setVideoURI(final Uri videoURI) {
mSrc = videoURI;
if (mOriginSizeFile == 0) {
final Cursor cursor = getContext().getContentResolver().query(videoURI, null, null, null, null);
if (cursor != null) {
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
cursor.moveToFirst();
mOriginSizeFile = cursor.getLong(sizeIndex);
cursor.close();
mTextSize.setText(Formatter.formatShortFileSize(getContext(), mOriginSizeFile));
}
}
...
「TrimVideoUtils」ファイルの「genVideoUsingMp4Parser」関数を呼び出す「startTrim」。そこで、以下を使用して「mp4parser」ライブラリを呼び出します。
Movie movie = MovieCreator.build(new FileDataSourceViaHeapImpl(src.getAbsolutePath()));
AndroidでOOMを回避するために(「mp4parser」ライブラリから)FileDataSourceViaHeapImpl
を使用すると書かれているので、そのまま使用することにしました。
つまり、4つのCTORがあり、すべてファイルのバリエーションが必要です:File、filePath、FileChannel、FileChannel + fileName。
たぶん、FileChannel
とContentResolver
を使用して、Uri
を実装し、実際のファイルをシミュレートしますか?必要なときにInputStreamを再度開くことを意味する場合でも、それは可能かもしれないと思います...
私が何を機能させたかを確認するために、プロジェクトのクローンを作成できます ここ 。 「K4LVideoTrimmer」ファイルのコードがコメント化されているため、トリミングは行われないことを知っておいてください。
//TODO handle trimming using Uri
//TrimVideoUtils.startTrim(file, getDestinationPath(), mStartPosition, mEndPosition, mOnTrimVideoListener);
編集:
自分自身をトリミングするために別の解決策を使用して解決策を見つけたと思い、それについて書きました ここ 、しかし悲しいことに一部の入力ビデオは処理できませんが、mp4parser
ライブラリはそれらを処理できます。
ファイルではなくURIからのものであっても、そのような入力ビデオを処理するようにmp4parser
を変更できるかどうかを教えてください(ビデオファイルにコピーするだけの回避策なしで)。
まず最初に注意点:私はmp4parserライブラリに精通していませんが、あなたの質問は面白そうだったので調べました。
コードコメントが言うクラスの1つを見る価値は、「主にテスト用」だと思います。 InMemRandomAccessSourceImpl
。任意のURIからムービーを作成するには、コードは次のようになります。
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
Log.e("InputStream Size","Size " + inputStream);
int bytesAvailable = inputStream.available();
int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
final byte[] buffer = new byte[bufferSize];
int read = 0;
int total = 0;
while ((read = inputStream.read(buffer)) !=-1 ) {
total += read;
}
if( total < bytesAvailable ){
Log.e(TAG, "Read from input stream failed")
return;
}
//or try inputStream.readAllBytes() if using Java 9
inputStream.close();
ByteBuffer bb = ByteBuffer.wrap(buffer);
Movie m2 = MovieCreator.build(new ByteBufferByteChannel(bb),
new InMemRandomAccessSourceImpl(bb), "inmem");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
しかし、私は、あなたが達成したいこととパーサーがとるアプローチとの間にいくらかの矛盾があるように見えると思います。大きなメモリオーバーヘッドを回避するためにローカルファイルに依存しており、バイトへのランダムアクセスは、ストリーミングアプローチとは異なり、データセット全体が利用可能な場合にのみ実行できます。
パーサーにバッファーが与えられる前に、少なくともクリップに必要な量のデータを一度にバッファーに入れる必要があります。あなたが短いセクションをつかむことを探していて、バッファリングがそれほど面倒ではないなら、それはあなたにとってうまくいくかもしれません。 InputStream
からの読み取りに問題がある場合、特にリモートコンテンツの場合は、IO例外などが発生する可能性がありますが、実際にはそれを予期していません。最新のシステムでファイルします。
MemoryFile
もあり、これはashmemでバックアップされたファイルのようなオブジェクトを提供します。どういうわけかそれはうまくいくと思います。