Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/179.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Android中从一系列图像创建视频?_Android_Image_Video - Fatal编程技术网

如何在Android中从一系列图像创建视频?

如何在Android中从一系列图像创建视频?,android,image,video,Android,Image,Video,我想调用一个函数,从图像列表中生成视频,然后将其本地保存在设备上: public void CreateAndSaveVideoFile(List<Bitmap> MyBitmapArray) { // .. } public void CreateAndSaveVideoFile(列出MyBitmapArray) { // .. } 试验: 接下来,答案中的链接是死链接 下面,接受答案中的建议库不支持Android 上面的下一个答案是针对Android用户的方法,但我不

我想调用一个函数,从图像列表中生成视频,然后将其本地保存在设备上:

public void CreateAndSaveVideoFile(List<Bitmap> MyBitmapArray)
{
   // ..
}
public void CreateAndSaveVideoFile(列出MyBitmapArray)
{
// ..
}
试验:

  • 接下来,答案中的链接是死链接

  • 下面,接受答案中的建议库不支持Android

  • 上面的下一个答案是针对Android用户的方法,但我不清楚该功能的输入和输出(他在哪里提供图像?他从哪里获得视频?)-我留下了一个问题评论

  • 上面的下一个答案提供了一个完整的类,但是需要包含的库有一个损坏的文件(当我尝试从提供的链接下载它时)-我留下了一个问题注释

  • 下面,顶部答案中建议的库使用我不熟悉的命令,我甚至不知道如何使用它们。比如:

从当前文件中的所有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


参考示例代码和下载。

阿披实V是正确的,关于jcodec SequenceEncoder的更多信息: 看

最近,我用raspberry pi和Android设备构建了一个实时视频系统,遇到了与您相同的问题。我没有保存图像文件列表,而是使用了一些实时流协议,如RTP/RTCP将数据流传输给用户。如果你的需求是这样的,也许你可以改变你的策略

另一个建议是,您可以探索一些C/C++库,使用NDK/JNI来打破Java的限制


希望这些建议对您有意义:)

您可以使用ffmpeg库从图像阵列制作视频。 FFMPEG库对于制作视频非常有用。 也许下面的链接会对你有所帮助。

如果应用程序Android SDK的最低版本大于或等于16(Android 4.1),则最好使用视频编码

编码视频时,要求您提供Android 4.1(SDK 16) 媒体使用ByteBuffer阵列,但Android 4.3(SDK 18)现在允许 您需要使用曲面作为编码器的输入。比如说这个, 允许您从现有视频文件或使用帧对输入进行编码 从OpenGLES生成

添加到Android 4.3(SDK 18)中,因此为了方便使用Media Muxer编写mp4文件,您应该具有SDK>=18。

使用媒体编解码器API的方式,您将得到硬件加速编码,您很容易编码高达60 FPS

你可以从1)开始 或者使用2)或3)


从格拉菲卡开始。将Choreographer事件替换为您自己的包含要编码的位图,删除屏幕上的绘图,将位图加载为Open GL纹理并在媒体编解码器输入表面上绘制。

您有位图,可以使用JCodec将其翻转为视频

下面是一个图像序列编码器示例:

您可以通过将BuffereImage替换为位图来修改它

根据需要使用这些方法

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());
}
位图中的公共静态图片(位图src){
Picture dst=Picture.create((int)src.getWidth(),(int)src.getHeight(),RGB);
fromBitmap(src、dst);
返回dst;
}
位图中的公共静态无效(位图src、图片dst){
int[]dstData=dst.getPlaneData(0);
int[]packed=new int[src.getWidth()*src.getHeight()];
src.getPixels(压缩,0,src.getWidth(),0,0,src.getWidth(),src.getHeight());
for(inti=0,srcOff=0,dstOff=0;i>16)和0xff;
dstData[dstOff+1]=(rgb>>8)&0xff;
dstData[dstOff+2]=rgb&0xff;
}
}
}
公共静态位图toBitmap(图片src){
位图dst=Bitmap.create(pic.getWidth(),pic.getHeight(),ARGB_8888);
toBitmap(src、dst);
返回dst;
}
公共静态无效toBitmap(图片src、位图dst){
int[]srcData=src.getPlaneData(0);
int[]packed=new int[src.getWidth()*src.getHeight()];
for(inti=0,dstOff=0,srcOff=0;i
publicstaticvoidmain(字符串[]args)引发IOException{
SequenceEncoder=新的SequenceEncoder(新文件(“video.mp4”);
对于(int i=1;i<100;i++){
BuffereImage bi=ImageIO.read(新文件(String.format(“img%08d.png”,i));
编码器。编码图像(bi);
}
encoder.finish();}
现在,要将位图转换为BuffereImage,可以使用以下类:

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;
    }
}
}
导入java.awt.image.buffereImage;
导入java.awt.image.DataBufferByte;
导入java.awt.image.DataBufferInt;
导入java.io.IOException;
导入java.io.InputStream;
/**
*用于加载windows位图文件的实用程序类
*
*基于作者Abdul Bezrati和Pepijn Van Eeckhoudt的代码
*/
公共类位图加载器{
/**
*静态方法,根据传入的文件名加载位图文件。
*基于位计数,此方法将调用8位或24位
*位图读取器方法
*
*@param
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;
    }
}
}
implementation 'org.jcodec:jcodec:0.2.3'
implementation 'org.jcodec:jcodec-android:0.2.3'
android {
    ...
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.2'
    }
}
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);
}
val encoder = MP4Encoder()
     encoder.setFrameDelay(50)
     encoder.setOutputFilePath(exportedFile.path)
     encoder.setOutputSize(width, width)

 startExport()

 stopExport()

 addFrame(bitmap) //called intervally