#java #android #signal-processing #android-mediacodec #video-encoding
#java #Android #обработка сигналов #android-mediacodec #кодирование видео
Вопрос:
Ниже приведен фрагмент кода, который должен считывать все изображения из папки image и кодировать их в видео h.262 и сохранять на SD-карте. Я следовал документации Android (получить буфер, заполнить буфер, буфер очереди для кодирования, удалить выходной буфер из очереди, а затем записать в файл). Проблема в том, что когда я удаляю выходной буфер из очереди, я получаю отрицательный индекс, тогда как он должен возвращать индекс выходных данных. Выходной файл имеет размер 0 байт, и в него ничего не записано. Я в значительной степени новичок в MediaCodec. Любое предложение будет оценено.
MediaCodec mediaCodec=null;
byte[] input = new byte[2000];
BufferedOutputStream outputStream = null;
try {
//TODO
//adjust parameters by consulting with hari sir
mediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 320, 240);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 700000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
//not all phones support given color format, if color format is not supported app will crash with mediaCodec exception
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
//after the mediaCodec is started we don't have ownership of input or output buffers
Log.i("Codecinfo","" mediaCodec.getCodecInfo());
Log.i("Codecname","" mediaCodec.getName());
}
catch (Exception e)
{
Log.e("ExceptionMediaCodec","Some exception in media codec");
}
//reached here
System.out.println("mediacodec info=" mediaCodec.getCodecInfo());
try {
File ff = new File(Environment.getExternalStorageDirectory(), "Download/video_encoded.264");
if (!ff.exists()) ff.createNewFile();
System.out.println("H.264 output file initialized");
outputStream = new BufferedOutputStream(new FileOutputStream(ff));
Log.i("H264 avc Encoder", "outputStream initialized");
} catch (Exception e){
e.printStackTrace();
}
String path = Environment.getExternalStorageDirectory().toString() "/images";
File f = new File(path);
Log.i("ExternalFileInfo",path.toString());
//read image files onto an array
File[] files = f.listFiles();
System.out.println(files.getClass().getName());
int NUM_IMAGES = files.length;
String[] images = new String[NUM_IMAGES];
for (int i=0;i<NUM_IMAGES;i )
images[i]=files[i].getName();
for (String eachimage: images) {
System.out.println(eachimage);
byte[] eachByte = eachimage.getBytes();
input = eachByte; //demo
System.out.println("input byte initialized" input.toString());
try {
System.out.println("Following is the content of byte array input");
System.out.write(input);
}catch (Exception e)
{
e.printStackTrace();
}
}
//reached here
System.out.println("image byte size=" input.length);
//all images converted to bytearray
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
//System.out.println("inputBuffers=" (inputBuffers));
//System.out.println("outputBuffers=" (outputBuffers));
//reached here
//returns the index of input buffer to be filled for encoding
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1); //-1 => wait indefinitely
System.out.println("inputBufferedIndex=" inputBufferIndex); //0
if (inputBufferIndex >= 0) {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
System.out.println("input byte placed in input buffer");
inputBuffer.put(input);
System.out.println("inputBuffer after filling up" inputBuffer);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, System.nanoTime(), 0); //send each request with different timestamp
System.out.println("mediacodec input queued");
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
System.out.println("buffer info=" bufferInfo);
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, -1); //-ve value for indefinite waiting
//reached here
System.out.println("buffer info meta data=" bufferInfo);
System.out.println("outputBufferedIndex=" outputBufferIndex);
try {
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
outputStream.write(outData, 0, outData.length);
outputStream.flush();
Log.i("AvcEncoder", outData.length " bytes written");
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, -1);
}
} catch (Throwable t) {
t.printStackTrace();
}
try {
mediaCodec.stop();
mediaCodec.release();
outputStream.flush();
outputStream.close();
} catch (Exception e){
e.printStackTrace();
}
System.out.println("Mediacodec=" mediaCodec);
Ответ №1:
Пожалуйста, ознакомьтесь с документацией к MediaCodec.dequeueOutputBuffer()
методу, в которой говорится:
Возвращает индекс выходного буфера, который был успешно декодирован, или одну из констант INFO_*.
Отрицательными значениями являются константы INFO_ *, которые могут быть одной из следующих:
INFO_OUTPUT_BUFFERS_CHANGED
INFO_OUTPUT_FORMAT_CHANGED
INFO_TRY_AGAIN_LATER
Последнее не слишком вероятно, потому что вы ждете бесконечно.
Дополнительно: вы не всегда можете рассчитывать на ожидание одного выходного буфера после того, как вы предоставили один буфер в качестве входных данных. Вам нужно загружать входные буферы до тех пор, пока у кодировщика есть свободные входные буферы, и использовать любые выходные буферы, которые он вам предоставляет.
Последние несколько выходных буферов могут выводиться только после того, как вы подадите сигнал, что больше не будете отправлять входные буферы, установив флаг BUFFER_FLAG_END_OF_STREAM
.
Комментарии:
1. Я обнаружил, что INFO_OUTPUT_FORMAT_CHANGED — это то, что происходит в моем случае. Каким должен быть мой следующий шаг?
2. После этого вы должны вызвать
dequeueOutputBuffer()
еще раз.