関数を呼び出して画像のリストからビデオを作成し、デバイスにローカルに保存したい:
public void CreateAndSaveVideoFile(List<Bitmap> MyBitmapArray)
{
// ..
}
試験:
Java/xuggle-画像の配列をムービーにエンコードする に続いて、答えのリンクはデッドリンクです
Java)で画像をビデオファイルにエンコードする方法? に従ってください。
上記の次の答えには、Androidユーザーに対するアプローチがありますが、その関数の入力と出力は明確ではありません(彼はどこで画像を提供しましたか?ビデオ?)-質問コメントを残しました
上記の次の答えはクラス全体を提供しますが、含まれる必要なライブラリには破損したファイルがあります(提供されたリンクからダウンロードしようとすると)-質問コメントを残しました
Java:画像の配列からムービーを作成するにはどうすればよいですか? に続いて、一番上の回答の推奨ライブラリは、私がよく知らないコマンドを使用しており、それらの使用方法さえ知りません。のような:
現在のディレクトリ内のすべてのJPEGファイルからMPEG-4ファイルを作成:
mencoder mf://*.jpg -mf w=800:h=600:fps=25:type=jpg -ovc lavc \ -lavcopts vcodec=mpeg4:mbd=2:trell -oac copy -o output.avi
Java/Androidプロジェクトで上記をどのように使用できるかわかりません。
誰でも私を導くのに役立つことができますか、そして/または私の仕事へのアプローチを提供しますか?前もって感謝します。
Jcodec SequenceEncoder
を使用して、画像のシーケンスをMP4ファイルに変換できます。
サンプルコード:
import org.jcodec.api.awt.SequenceEncoder;
...
SequenceEncoder enc = new SequenceEncoder(new File("filename"));
// GOP size will be supported in 0.2
// enc.getEncoder().setKeyInterval(25);
for(...) {
BufferedImage image = ... // Obtain an image to encode
enc.encodeImage(image);
}
enc.finish();
Javaライブラリであるため、Androidプロジェクトにインポートするのは簡単です。ffmpegとは異なり、NDKを使用する必要はありません。
サンプルコードとダウンロードについては、 http://jcodec.org/ を参照してください。
Stanislav Vitvitskyyが示すように JCodec を使用 here。
public static void main(String[] args) throws IOException { SequenceEncoder encoder = new SequenceEncoder(new File("video.mp4")); for (int i = 1; i < 100; i++) { BufferedImage bi = ImageIO.read(new File(String.format("img%08d.png", i))); encoder.encodeImage(bi); } encoder.finish();}
ビットマップをBufferedImageに変換するには、このクラスを使用できます。
import Java.awt.image.BufferedImage;
import Java.awt.image.DataBufferByte;
import Java.awt.image.DataBufferInt;
import Java.io.IOException;
import Java.io.InputStream;
/**
* Utility class for loading windows bitmap files
* <p>
* Based on code from author Abdul Bezrati and Pepijn Van Eeckhoudt
*/
public class BitmapLoader {
/**
* Static method to load a bitmap file based on the filename passed in.
* Based on the bit count, this method will either call the 8 or 24 bit
* bitmap reader methods
*
* @param file The name of the bitmap file to read
* @throws IOException
* @return A BufferedImage of the bitmap
*/
public static BufferedImage loadBitmap(String file) throws IOException {
BufferedImage image;
InputStream input = null;
try {
input = ResourceRetriever.getResourceAsStream(file);
int bitmapFileHeaderLength = 14;
int bitmapInfoHeaderLength = 40;
byte bitmapFileHeader[] = new byte[bitmapFileHeaderLength];
byte bitmapInfoHeader[] = new byte[bitmapInfoHeaderLength];
input.read(bitmapFileHeader, 0, bitmapFileHeaderLength);
input.read(bitmapInfoHeader, 0, bitmapInfoHeaderLength);
int nSize = bytesToInt(bitmapFileHeader, 2);
int nWidth = bytesToInt(bitmapInfoHeader, 4);
int nHeight = bytesToInt(bitmapInfoHeader, 8);
int nBiSize = bytesToInt(bitmapInfoHeader, 0);
int nPlanes = bytesToShort(bitmapInfoHeader, 12);
int nBitCount = bytesToShort(bitmapInfoHeader, 14);
int nSizeImage = bytesToInt(bitmapInfoHeader, 20);
int nCompression = bytesToInt(bitmapInfoHeader, 16);
int nColoursUsed = bytesToInt(bitmapInfoHeader, 32);
int nXPixelsMeter = bytesToInt(bitmapInfoHeader, 24);
int nYPixelsMeter = bytesToInt(bitmapInfoHeader, 28);
int nImportantColours = bytesToInt(bitmapInfoHeader, 36);
if (nBitCount == 24) {
image = read24BitBitmap(nSizeImage, nHeight, nWidth, input);
} else if (nBitCount == 8) {
image = read8BitBitmap(nColoursUsed, nBitCount, nSizeImage, nWidth, nHeight, input);
} else {
System.out.println("Not a 24-bit or 8-bit Windows Bitmap, aborting...");
image = null;
}
} finally {
try {
if (input != null)
input.close();
} catch (IOException e) {
}
}
return image;
}
/**
* Static method to read a 8 bit bitmap
*
* @param nColoursUsed Number of colors used
* @param nBitCount The bit count
* @param nSizeImage The size of the image in bytes
* @param nWidth The width of the image
* @param input The input stream corresponding to the image
* @throws IOException
* @return A BufferedImage of the bitmap
*/
private static BufferedImage read8BitBitmap(int nColoursUsed, int nBitCount, int nSizeImage, int nWidth, int nHeight, InputStream input) throws IOException {
int nNumColors = (nColoursUsed > 0) ? nColoursUsed : (1 & 0xff) << nBitCount;
if (nSizeImage == 0) {
nSizeImage = ((((nWidth * nBitCount) + 31) & ~31) >> 3);
nSizeImage *= nHeight;
}
int npalette[] = new int[nNumColors];
byte bpalette[] = new byte[nNumColors * 4];
readBuffer(input, bpalette);
int nindex8 = 0;
for (int n = 0; n < nNumColors; n++) {
npalette[n] = (255 & 0xff) << 24 |
(bpalette[nindex8 + 2] & 0xff) << 16 |
(bpalette[nindex8 + 1] & 0xff) << 8 |
(bpalette[nindex8 + 0] & 0xff);
nindex8 += 4;
}
int npad8 = (nSizeImage / nHeight) - nWidth;
BufferedImage bufferedImage = new BufferedImage(nWidth, nHeight, BufferedImage.TYPE_INT_ARGB);
DataBufferInt dataBufferByte = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer());
int[][] bankData = dataBufferByte.getBankData();
byte bdata[] = new byte[(nWidth + npad8) * nHeight];
readBuffer(input, bdata);
nindex8 = 0;
for (int j8 = nHeight - 1; j8 >= 0; j8--) {
for (int i8 = 0; i8 < nWidth; i8++) {
bankData[0][j8 * nWidth + i8] = npalette[((int) bdata[nindex8] & 0xff)];
nindex8++;
}
nindex8 += npad8;
}
return bufferedImage;
}
/**
* Static method to read a 24 bit bitmap
*
* @param nSizeImage size of the image in bytes
* @param nHeight The height of the image
* @param nWidth The width of the image
* @param input The input stream corresponding to the image
* @throws IOException
* @return A BufferedImage of the bitmap
*/
private static BufferedImage read24BitBitmap(int nSizeImage, int nHeight, int nWidth, InputStream input) throws IOException {
int npad = (nSizeImage / nHeight) - nWidth * 3;
if (npad == 4 || npad < 0)
npad = 0;
int nindex = 0;
BufferedImage bufferedImage = new BufferedImage(nWidth, nHeight, BufferedImage.TYPE_4BYTE_ABGR);
DataBufferByte dataBufferByte = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer());
byte[][] bankData = dataBufferByte.getBankData();
byte brgb[] = new byte[(nWidth + npad) * 3 * nHeight];
readBuffer(input, brgb);
for (int j = nHeight - 1; j >= 0; j--) {
for (int i = 0; i < nWidth; i++) {
int base = (j * nWidth + i) * 4;
bankData[0][base] = (byte) 255;
bankData[0][base + 1] = brgb[nindex];
bankData[0][base + 2] = brgb[nindex + 1];
bankData[0][base + 3] = brgb[nindex + 2];
nindex += 3;
}
nindex += npad;
}
return bufferedImage;
}
/**
* Converts bytes to an int
*
* @param bytes An array of bytes
* @param index
* @returns A int representation of the bytes
*/
private static int bytesToInt(byte[] bytes, int index) {
return (bytes[index + 3] & 0xff) << 24 |
(bytes[index + 2] & 0xff) << 16 |
(bytes[index + 1] & 0xff) << 8 |
bytes[index + 0] & 0xff;
}
/**
* Converts bytes to a short
*
* @param bytes An array of bytes
* @param index
* @returns A short representation of the bytes
*/
private static short bytesToShort(byte[] bytes, int index) {
return (short) (((bytes[index + 1] & 0xff) << 8) |
(bytes[index + 0] & 0xff));
}
/**
* Reads the buffer
*
* @param in An InputStream
* @param buffer An array of bytes
* @throws IOException
*/
private static void readBuffer(InputStream in, byte[] buffer) throws IOException {
int bytesRead = 0;
int bytesToRead = buffer.length;
while (bytesToRead > 0) {
int read = in.read(buffer, bytesRead, bytesToRead);
bytesRead += read;
bytesToRead -= read;
}
}
}
アプリケーションの最小バージョンAndroid SDKが16(Android 4.1)以上の場合)ビデオエンコーディングはuse Android Media Codec API です。
Android 4.3 API から。
ビデオをエンコードする場合、Android 4.1(SDK 16)では、メディアにByteBuffer配列を提供する必要がありましたが、Android 4.3(SDK 18)では、たとえば、Surfaceをエンコーダーへの入力として使用すると、既存のビデオファイルからの入力をエンコードしたり、OpenGL ESから生成されたフレームを使用したりできます。
Media Muxer にAndroid 4.3(SDK 18)に追加されたため、Media Muxerでmp4ファイルを作成する便利な方法のために、SDKが必要です。 > = 18。
Media Codec APIを使用すると、ハードウェアアクセラレーションエンコーディングを取得でき、最大60 FPSを簡単にエンコードできます。
1)から開始できます MediaCodecを使用してビットマップをビデオにエンコードする方法 または2)を使用します Google Grafika または3)Bigflake 。
Grafikaから始まる RecordFBOActivity.Java 。 Choreographerイベントを、エンコードするビットマップを含む独自のものに置き換え、画面上の描画を削除し、ビットマップをOpen GL Textureとしてロードし、Media Codec Input Surfaceに描画します。
jCodecはAndroidサポートを追加しました。
これらをグラドルに追加する必要があります...
compile 'org.jcodec:jcodec:0.2.3'
compile 'org.jcodec:jcodec-Android:0.2.3'
...そして
Android {
...
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.2'
}
}
期待どおりに動作することを確認できますが、注意が必要です。まず、フルサイズの画像をいくつか試し、ファイルに書き込みましたが、再生時にエラーが発生しました。 YUV420J色空間に2の倍数が必要なため、縮小したときに、画像の幅または高さが均等でない場合、エラーが発生します。
また、注目に値する、これはあなたのパッケージを重く、重くします。私の小さなプロジェクトは、これを追加することでdexの制限を超え、multidexを有効にする必要がありました。
FileChannelWrapper out = null;
File dir = what ever directory you use...
File file = new File(dir, "test.mp4");
try { out = NIOUtils.writableFileChannel(file.getAbsolutePath());
AndroidSequenceEncoder encoder = new AndroidSequenceEncoder(out, Rational.R(15, 1));
for (Bitmap bitmap : bitmaps) {
encoder.encodeImage(bitmap);
}
encoder.finish();
} finally {
NIOUtils.closeQuietly(out);
}
Bitmp4を使用して、画像のシーケンスをMP4ファイルに変換できます。
サンプルコード:
...
val encoder = MP4Encoder()
encoder.setFrameDelay(50)
encoder.setOutputFilePath(exportedFile.path)
encoder.setOutputSize(width, width)
startExport()
stopExport()
addFrame(bitmap) //called intervally
Javaライブラリであるため、Androidプロジェクトにインポートするのは簡単です。ffmpegとは異なり、NDKを使用する必要はありません。
サンプルコードとダウンロードについては、 https://github.com/dbof10/Bitmp4 を参照してください。
Abhishek Vは正しかった、jcodec SequenceEncoderの詳細: Androidは画像のリストから動画を作成する
最近、Raspberry PiとAndroidデバイスを使用して、あなたと同じ問題に遭遇しました。画像ファイルのリストを保存する代わりに、いくつかのリアルタイムストリーミングプロトコルを使用して、リアルタイムビデオシステムを構築しました。 RTP/RTCPのように、データストリームをユーザーに転送します。要件がこのようなものである場合は、戦略を変更できます。
別の提案として、NDK/JNIを使用してJavaの制限を打破し、C/C++ライブラリを調べることができます。
提案があなたにとって意味があることを願っています:)
ビットマップがあり、JCodecを使用してビデオに変換できます
これが画像シーケンスエンコーダのサンプルです。
BufferedImageをBitmapに置き換えることにより、目的に合わせて変更できます。
必要に応じてこれらの方法を使用してください。
public static Picture fromBitmap(Bitmap src) {
Picture dst = Picture.create((int)src.getWidth(), (int)src.getHeight(), RGB);
fromBitmap(src, dst);
return dst;
}
public static void fromBitmap(Bitmap src, Picture dst) {
int[] dstData = dst.getPlaneData(0);
int[] packed = new int[src.getWidth() * src.getHeight()];
src.getPixels(packed, 0, src.getWidth(), 0, 0, src.getWidth(), src.getHeight());
for (int i = 0, srcOff = 0, dstOff = 0; i < src.getHeight(); i++) {
for (int j = 0; j < src.getWidth(); j++, srcOff++, dstOff += 3) {
int rgb = packed[srcOff];
dstData[dstOff] = (rgb >> 16) & 0xff;
dstData[dstOff + 1] = (rgb >> 8) & 0xff;
dstData[dstOff + 2] = rgb & 0xff;
}
}
}
public static Bitmap toBitmap(Picture src) {
Bitmap dst = Bitmap.create(pic.getWidth(), pic.getHeight(), ARGB_8888);
toBitmap(src, dst);
return dst;
}
public static void toBitmap(Picture src, Bitmap dst) {
int[] srcData = src.getPlaneData(0);
int[] packed = new int[src.getWidth() * src.getHeight()];
for (int i = 0, dstOff = 0, srcOff = 0; i < src.getHeight(); i++) {
for (int j = 0; j < src.getWidth(); j++, dstOff++, srcOff += 3) {
packed[dstOff] = (srcData[srcOff] << 16) | (srcData[srcOff + 1] << 8) | srcData[srcOff + 2];
}
}
dst.setPixels(packed, 0, src.getWidth(), 0, 0, src.getWidth(), src.getHeight());
}
Ffmpegライブラリを使用して、画像の配列からビデオを作成できます。 FFMPEGライブラリは、ビデオの作成に非常に役立ちます。次のリンクが役立つかもしれません。 http://osric.com/chris/accidental-developer/2012/04/using-ffmpeg-to-programmatically-slice-and-splice-video/https:// groups .google.com/forum /#!topic/Android-ndk/sxDYlGYK-Xg