Кодирование видео с помощью MediaCodec - пустой выходной буфер

Я хочу создать mp4 video из последовательности YUV images. Я тестирую этот код на своем Nexus 5, Android 4.4.

Проблема в том, что у меня нет выходных данных из encoder. Кодировщик дает мне данные только 2 раза

  • 2-й раз 3K закодированных данных?
  • Проблема в том, что я не вычисляю ptsUsec. Я просто добавляю ptsUsec=ptsUsec+33; и теперь все работает нормально.
    ptsUsec - время представления - это время текущего кадра.
    Когда ptsUsec не изменяется, кодек, думая, что это уже закодированный кадр, ничего не делает

И тогда encoder.dequeueOutputBuffer(info, TIMEOUT_USEC) всегда return -1INFO_TRY_AGAIN_LATER

КОД

    String type="video/avc";

    MediaCodecInfo codecInfo = selectCodec(type);
    int colorFormat = selectColorFormat(codecInfo, type); // This return 21

    MediaFormat format = MediaFormat.createVideoFormat(type,
            videowidth, videoheight); //"video/avc" 1280 720
    // Set some properties
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
    format.setInteger(MediaFormat.KEY_BIT_RATE, 17000000);
    format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
    format.setInteger(MediaFormat.KEY_WIDTH,videowidth);
    format.setInteger(MediaFormat.KEY_HEIGHT,videoheight);

    encoder = MediaCodec.createByCodecName(codecInfo.getName());
    encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    encoder.start(); //ок

    ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
    ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();

    BufferInfo info = new BufferInfo();
    int k = 0; // just counter
    int inputBufIndex;
    int encoderStatus=0;
    int col=20; // i want to encode 20 frames


    info = new BufferInfo();

    while (k < col) {
        k++;
            try {
                Thread.sleep(33); //some pause
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


            //input to buffer always works fine
            inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);

            if (inputBufIndex >= 0) {

                if (k == col) { //EOS
                    encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec,
                            MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    Log.v(TAG, "sent input EOS (with zero-length frame)");
                } else {

                    ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];

                    inputBuf.clear();

                    byte[] frameData = new byte[videowidth * videoheight * 3 / 2]; //1 plane w*h Y + 2 planes w*h/2 Cb Cr

                    Arrays.fill(frameData, (byte) 0); // zero for example 
                    inputBuf.put(frameData);
                    encoder.queueInputBuffer(inputBufIndex, 0,
                            frameData.length, ptsUsec, 0);
                    Log.v(TAG, "submitted frame " + k + " to enc");
                }

            } else {
                // either all in use, or we timed out during initial setup
                Log.v(TAG, "input buffer not available");
            }


            // output Buffer have problems
             info = new BufferInfo();
             encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
            // 1-st time encoderStatus =-2 INFO_OUTPUT_FORMAT_CHANGED
            // 2-nd time encoderStatus =0
            // 3 to 20 times encoderStatus =-1
            if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
                // no output available yet
                Log.v(TAG, "no output from encoder available");
            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                encoderOutputBuffers = encoder.getOutputBuffers();
                Log.v(TAG, "encoder output buffers changed");

            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                Log.v(TAG, "encoder output format changed: " +encoder.getOutputFormat() );
            } else if (encoderStatus < 0) {
                 Log.v(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
            } else { // encoderStatus >= 0
                ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
                if (encodedData == null) {
                     Log.v(TAG, "encoderOutputBuffer " + encoderStatus + " was null");
                } 
                else 
                {
                    Log.v(TAG, "encoderOutputBuffer " + info.size+" | "+encoderStatus+" | "+info );
                }




                encoder.releaseOutputBuffer(encoderStatus, false);
            } 

    }

    Log.d(TAG, "-finish-");

ЖУРНАЛ:

1-й раз 26 байт csd-0 csd-1


person ego    schedule 13.08.2014    source источник
comment
Спасибо за ваш ответ. Если я зацикливаюсь, пока не увижу EOS на выходе, я беру бесконечный цикл. EOS никогда не выходит на рынок. Я думаю, что задержка распространения в данном случае не имеет значения - у кодека достаточно времени для кодирования - более 1/30 секунды.   -  person fadden    schedule 13.08.2014
comment
Спасибо. Решено. Проблема в том, что я не вычисляю ptsUsec. Я просто добавляю ptsUsec=ptsUsec+33; и теперь все работает нормально.   -  person ego    schedule 14.08.2014
comment

08-13 17:23:32.927: V/CAR_DVR(20874): выходной формат кодировщика: {частота кадров=30, битрейт=17000000, высота=720, mime=video/avc, color-format=21, i-frame-interval=10, width=1280} 08-13 17:23:35.347: V/CAR_DVR(20874): отправлен кадр 1 в enc 08-13 17:23:37.637: V/CAR_DVR(20874): кодировщик формат вывода изменен: {csd-1=java.nio.ByteArrayBuffer[position=0,limit=8,capacity=8], height=720, mime=video/avc, csd-0=java.nio.ByteArrayBuffer[position= 0,limit=18,capacity=18], what=1869968451, width=1280} 08-13 17:23:38.537: V/CAR_DVR(20874): отправил кадр 2 в enc 08-13 17:23:39.177: V /CAR_DVR(20874): encoderOutputBuffer 26 | 0 | android.media.MediaCodec$BufferInfo@4264dfb0 08-13 17:23:40.007: V/CAR_DVR(20874): отправил кадр 3 в enc 08-13 17:23:55.207: V/CAR_DVR(20874): encoderOutputBuffer 3625 | 1 | android.media.MediaCodec$BufferInfo@42654b60 08-13 17:23:57.067: V/CAR_DVR(20874): отправил кадр 4 в enc 08-13 17:24:03.187: V/CAR_DVR(20874): нет выходных данных от кодировщика доступно 08-13 17:24:10.167: V/CAR_DVR(20874): кадр 5 отправлен в enc 08-13 17:24:14.477: V/CAR_DVR(20874): нет выходных данных от кодировщика 08-13 17:24: 14.787: V/CAR_DVR(20874): кадр 6 отправлен в enc 08-13 17:24:14.787: V/CAR_DVR(20874): нет выходных данных кодера 08-13 17:24:15.047: V/CAR_DVR(20874) : кадр 7 отправлен в кодировщик 08-13 17:24:15.047: V/CAR_DVR(20874): нет выходных данных кодера 08-13 17:24:15.317: V/CAR_DVR(20874): отправлен кадр 8 в кодировщик 08- 13 17:24:15.317: V/CAR_DVR(20874): нет выходных данных кодировщика 08-13 17:24:15.577: V/CAR_DVR(20874): кадр 9 отправлен в enc 08-13 17:24:15.587: V /CAR_DVR(20874): нет выходных данных кодировщика 08-13 17:24:15.847: V/CAR_DVR(20874): отправлен кадр 10 в enc 08-13 17:24:15.847: V/CAR_DVR(20874): нет выходных данных из кодировать r доступно 08-13 17:24:16.107: V/CAR_DVR(20874): отправлен кадр 11 в enc 08-13 17:24:16.107: V/CAR_DVR(20874): нет выходных данных от кодировщика 08-13 17:24 :16.377: V/CAR_DVR(20874): отправлен кадр 12 в enc 08-13 17:24:16.377: V/CAR_DVR(20874): нет выходных данных от кодировщика 08-13 17:24:16.637: V/CAR_DVR(20874 ): кадр 13 отправлен в enc 08-13 17:24:16.637: V/CAR_DVR(20874): нет выходных данных кодера 08-13 17:24:16.897: V/CAR_DVR(20874): отправлен кадр 14 в enc 08 -13 17:24:16.897: V/CAR_DVR(20874): нет выходных данных кодировщика 08-13 17:24:17.157: V/CAR_DVR(20874): отправлен кадр 15 в enc 08-13 17:24:17. 157: V/CAR_DVR(20874): нет выходных данных кодировщика 08-13 17:24:17.427: V/CAR_DVR(20874): кадр 16 передан в enc 08-13 17:24:17.427: V/CAR_DVR(20874) : нет выходных данных кодера 08-13 17:24:17.697: V/CAR_DVR(20874): кадр 17 отправлен в кодировщик 08-13 17:24:17.697: V/CAR_DVR(20874): нет выходных данных кодера 08- 13 17:24:17.987: V/CAR_DVR(20874): кадр 18 отправлен в enc 08-13 17:24:17.987: V/CAR_DVR(20874): нет выходных данных кодера 08-13 17:24:18.257: V /CAR_DVR(20874): кадр 19 отправлен в enc 08-13 17:24:18.257: V/CAR_DVR(20874): нет выходных данных кодировщика 08-13 17:24:18.297: V/CAR_DVR(20874): отправлен ввод EOS (с кадром нулевой длины) 08-13 17:24:18.297: V/CAR_DVR(20874): нет выходных данных кодера 08-13 17:24:18.297: D/CAR_DVR(20874): -finish-   -  person ego    schedule 14.08.2014


Ответы (1)


Если вы выполняете цикл до тех пор, пока не увидите EOS на выходе, а не останавливаетесь сразу после подачи EOS на вход, это сработает? Мне интересно, буферизует ли он вывод, потому что ввод тривиален, и вы не видите фактический вывод, потому что задержка распространения через кодек означает, что вы выходите из цикла до того, как он сможет доставить вывод. Кроме того, вы должны избавиться от _1_ и вычислить _2_ на основе номера кадра.

person ego    schedule 14.08.2014