我正在尝试从android上的JPEG图像创建非常简短的视频。
我不想添加任何第三方API,因为这不是我的项目重点,因此我想使用api lvl 18上可用的任何标准库并使其尽可能简单
我实际上是在使用MediaCodec来尝试解决此问题:
//images dimensions
int width = 480;//944;
int heigth = 272;//672;
// We avoid the device-specific limitations on width and height by using values that
// are multiples of 16, which all tested devices seem to be able to handle.
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, heigth);
// Set some properties. Failing to specify some of these can cause the MediaCodec
// configure() call to throw an unhelpful exception.
MediaCodecInfo info = EncoderUtils.selectCodec("video/avc");
int colorFormat = EncoderUtils.selectColorFormat(info, "video/avc");
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
format.setInteger(MediaFormat.KEY_BIT_RATE, 512000);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 1);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
Log.d("a", "format: " + format);
// Create a MediaCodec for the desired codec, then configure it as an encoder with
// our desired properties.
MediaCodec encoder = MediaCodec.createByCodecName(info.getName());
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
encoder.start();
ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int generateIndex = 0;
long rawSize = 0;
long encodedSize = 0;
FileOutputStream outputStream = null;
String fileName = "/data/data/com.tomatedigital.lottogram/files/tmp.mp4" ;
try {
outputStream = new FileOutputStream(fileName);
Log.d(TAG, "encoded output will be saved as " + fileName);
} catch (IOException ioe) {
Log.w(TAG, "Unable to create debug output file " + fileName);
throw new RuntimeException(ioe);
}
boolean encoderDone = false;
for (File f : new File("/data/data/com.tomatedigital.lottogram/cache/1570712978785").listFiles()) {
int inputBufIndex = encoder.dequeueInputBuffer(-1);
if (inputBufIndex >= 0) {
long ptsUsec = computePresentationTime(generateIndex, 15);
Bitmap b = Picasso.get().load(f).get();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
byte[] frameData = byteArrayOutputStream.toByteArray();
ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];
inputBuf.clear();
inputBuf.put(frameData);
encoder.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0);
Log.d(TAG, "submitted frame " + generateIndex + " to enc");
generateIndex++;
} else {
// either all in use, or we timed out during initial setup
}
// Check for output from the encoder. If there's no output yet, we either need to
// provide more input, or we need to wait for the encoder to work its magic. We
// can't actually tell which is the case, so if we can't get an output buffer right
// away we loop around and see if it wants more input.
//
// Once we get EOS from the encoder, we don't need to do this anymore.
int encoderStatus = encoder.dequeueOutputBuffer(info, 0);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
Log.d(TAG, "no output from encoder available");
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
// not expected for an encoder
encoderOutputBuffers = encoder.getOutputBuffers();
Log.d(TAG, "encoder output buffers changed");
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// not expected for an encoder
MediaFormat newFormat = encoder.getOutputFormat();
Log.d(TAG, "encoder output format changed: " + newFormat);
} else if (encoderStatus < 0) {
Log.e(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
} else { // encoderStatus >= 0
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
if (encodedData == null) {
Log.e(TAG, "encoderOutputBuffer " + encoderStatus + " was null");
}
// It's usually necessary to adjust the ByteBuffer values to match BufferInfo.
encodedData.position(info.offset);
encodedData.limit(info.offset + info.size);
encodedSize += info.size;
byte[] data = new byte[info.size];
encodedData.get(data);
encodedData.position(info.offset);
try {
outputStream.write(data);
} catch (IOException ioe) {
Log.w(TAG, "failed writing debug data to file");
throw new RuntimeException(ioe);
}
encoder.releaseOutputBuffer(encoderStatus, false);
}
}
这是我在互联网上找到的示例代码的改编。我什至不尝试调整设置,只是得到任何结果
该文件夹:/data/data/com.tomatedigital.lottogram/cache/1570712978785
我已经可以访问该文件夹,并且其中包含的所有文件都是5个480x272的jpg文件
代码可以编译,但是会抛出此异常:
D/test: submitted frame 1 to enc
E/ACodec: [OMX.google.h264.encoder] ERROR(0x80001001)
signalError(omxError 0x80001001, internalError -2147483648)
E/MediaCodec: Codec reported err 0x80001001, actionCode 0, while in state 6
W/System.err: java.lang.IllegalStateException
W/System.err: at android.media.MediaCodec.getFormatNative(Native Method)
at android.media.MediaCodec.getOutputFormat(MediaCodec.java:2834)
at com.tomatedigital.lottogram.util.EncoderUtils.doEncodeDecodeVideoFromBuffer(EncoderUtils.java:174)
at com.tomatedigital.lottogram.activity.TestActivity.lambda$onCreate$0(TestActivity.java:50)
at com.tomatedigital.lottogram.activity.-$$Lambda$TestActivity$YElV7NVky_MxFWaZyAN3Pt4MLcg.run(Unknown Source:0)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
D/MediaCodec: [OMX.google.h264.decoder] setting dataspace on output surface to #104
此行引发了异常:int inputBufIndex = encoder.dequeueInputBuffer(-1);
有人可以告诉我我做错了什么还是提供一个实用的示例²