Индекс MediaCodecBufferedOutput отрицателен для Android MediaCodec

#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() еще раз.