MediaCode c Необработанная проблема декодирования H264 - истекло время ожидания, и decoder.dequeueOutputBuffer всегда возвращает -1 - PullRequest
0 голосов
/ 13 января 2020

Во-первых, спасибо, что нашли время прочитать это. Мне нужна помощь или понимание, поскольку я сталкиваюсь с проблемой декодирования кадров h264. Я публикую этот вопрос, так как большинство других связанных с ним сообщений не содержат четких шагов. Я поделился кодом для потока декодера, который получил основной лог c. Я получаю sps, pps и данные из сети, и, таким образом, я делаю этот флаг mConfigured как истинный, когда sps и pps принимаются и соответствующие массивы подаются. Я могу предоставить больше информации, если это необходимо. PS - Пожалуйста, извините за стандарты кодирования, поскольку это все еще PO C в разработке.

decoder.dequeueOutputBuffer >> всегда возвращает -1

// ниже функции, вызываемой из сети, когда новый пакет получен.

public void decodeAndPlayVideoFrame(byte[] encodedData, int frameType) {
    if (frameType == 1) {
        SPS = encodedData;
    } else if (frameType == 2) {
        PPS = encodedData;
    } else if (frameType == 0) {
        Log.d("EncodeDecode", "enqueueing frame no: " + (frameID));

        try {
            Frame frame = new Frame(frameID);
            int totalDataLength = encodedData.length + SPS.length + PPS.length;
            frame.frameData = new byte[totalDataLength];
            System.arraycopy(SPS, 0, frame.frameData, 0, SPS.length);
            System.arraycopy(PPS, 0, frame.frameData, SPS.length, PPS.length);
            System.arraycopy(encodedData, 0, frame.frameData, SPS.length + PPS.length, encodedData.length);

            queue.add(frame);
            frameID++;
        } catch (NullPointerException e) {
            Log.e("EncodeDecode", "frame is null");
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            Log.e("EncodeDecode", "problem inserting in the queue");
            e.printStackTrace();
        } catch (IllegalStateException e) {
            Log.e("EncodeDecode", "problem inserting in the queue");
            e.printStackTrace();
        }
        Log.d("EncodeDecode", "frame enqueued. queue size now: " + queue.size());

    }
}

// Поток проигрывателя запускается при запуске экрана и обрабатывает пакеты, поступающие в очередь.

  private class PlayerThread extends Thread {
    //private MediaExtractor extractor;
    private MediaCodec decoder;
    private Surface surface;
    private boolean mConfigured;

    public PlayerThread(Surface surface) {
        this.surface = surface;
    }

    private void initCodec() throws IOException {

        MediaFormat mediaFormat = null;

        decoder = MediaCodec.createDecoderByType("video/avc");
        mediaFormat = MediaFormat.createVideoFormat("video/avc",
                320,
                240);

        try {

            decoder.configure(mediaFormat,
                    surface,
                    null,
                    0);
            frameID = 0;
            mConfigured = true;
            decoder.start();
            Log.d("EncodeDecode", "DECODER_THREAD:: decoder.start() called");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        while (SPS == null || PPS == null || SPS.length == 0 || PPS.length == 0) {
            try {
                Log.d("EncodeDecode", "DECODER_THREAD:: sps,pps not ready yet");
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();

            }
        }

        if (!mConfigured) {
            try {
                initCodec();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
       int i = 0;
        ByteBuffer[] inputBuffers = decoder.getInputBuffers();
        ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
        while (!Thread.interrupted()) {
            Frame currentFrame = null;
            try {
                Log.d("EncodeDecode", "DECODER_THREAD:: calling queue.take(), if there is no frame in the queue it will wait");
                currentFrame = queue.take();
            } catch (InterruptedException e) {
                Log.e("EncodeDecode", "DECODER_THREAD:: interrupted while PlayerThread was waiting for the next frame");
                e.printStackTrace();
            }

            if (currentFrame == null)
                Log.e("EncodeDecode", "DECODER_THREAD:: null frame dequeued");
            else
                Log.d("EncodeDecode", "DECODER_THREAD:: " + currentFrame.id + " no frame dequeued");

            if (currentFrame != null && currentFrame.frameData != null && currentFrame.frameData.length != 0) {
                Log.d("EncodeDecode", "DECODER_THREAD:: decoding frame no: " + i + " , dataLength = " + currentFrame.frameData.length);

                int inIndex = decoder.dequeueInputBuffer(-1);

                if (inIndex >= 0) {
                    Log.d("EncodeDecode", "DECODER_THREAD:: sample size: " + currentFrame.frameData.length + "->" + currentFrame.frameData[0] +  "to" + currentFrame.frameData[currentFrame.frameData.length-1]);

                    ByteBuffer buffer = inputBuffers[inIndex];
                    buffer.clear();
                    buffer.put(currentFrame.frameData);
                    decoder.queueInputBuffer(inIndex, 0, currentFrame.frameData.length, 0, 0);

                    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                    int outIndex = decoder.dequeueOutputBuffer(info, 0);

                    switch (outIndex) {
                        case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                            Log.e("EncodeDecode", "DECODER_THREAD:: INFO_OUTPUT_BUFFERS_CHANGED");
                            outputBuffers = decoder.getOutputBuffers();
                            break;
                        case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                            Log.e("EncodeDecode", "DECODER_THREAD:: New format " + decoder.getOutputFormat());
                            break;
                        case MediaCodec.INFO_TRY_AGAIN_LATER:
                            Log.e("EncodeDecode", "DECODER_THREAD:: dequeueOutputBuffer timed out!");
                            break;
                        default:
                            Log.d("EncodeDecode", "DECODER_THREAD:: decoded SUCCESSFULLY!!!");
                            ByteBuffer outbuffer = outputBuffers[outIndex];
                            decoder.releaseOutputBuffer(outIndex, true);
                            break;
                    }

                    try {
                        Thread.sleep(250);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i++;
                }
            }
        }

        decoder.stop();
        decoder.release();
        mConfigured = false;

    }
}

1 Ответ

0 голосов
/ 15 января 2020

Я не знаю, как вы получаете SPS и PPS и как вы их проверяете ... в любом случае вам нужно настроить SPS и PPS на mediaformat перед началом декодирования c, в вашем коде вы можете сделать что-то вроде :

   ....
   while (SPS == null || PPS == null || SPS.length == 0 || PPS.length == 0) {
        try {
            Log.d("EncodeDecode", "DECODER_THREAD:: sps,pps not ready yet");
            sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();

        }
    }

   if (!mConfigured) {
        try {
            // init with SPS and PPS
            initCodec(sps,pps);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
   .....

И затем установите код c Speci c данных в initCodec перед началом декодирования c:

private void initCodec(byte[] sps, byte[] pps) throws IOException {

        MediaFormat mediaFormat = null;

        decoder = MediaCodec.createDecoderByType("video/avc");
        mediaFormat = MediaFormat.createVideoFormat("video/avc",
                320,
                240);
        // set the codec specific datas cds-0 = SPS, cds-1 = PPS
        mediaFormat.setByteBuffer("cds-0", ByteBuffer.wrap(sps));
        mediaFormat.setByteBuffer("cds-1", ByteBuffer.wrap(pps));
        try {

            decoder.configure(mediaFormat,
                    surface,
                    null,
                    0);
            frameID = 0;
            mConfigured = true;
            decoder.start();
            Log.d("EncodeDecode", "DECODER_THREAD:: decoder.start() called");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    ...........

Обновление: Из do c

... Многие декодеры требуют, чтобы фактическому сжатому потоку данных предшествовал «код c конкретный c данные», то есть данные настройки, используемые для инициализации кодек, такой как PPS / SPS в случае AV C видео или кодовые таблицы в случае аудио vorbis. Класс MediaExtractor предоставляет код c специфицирует c данные как часть возвращенного формата дорожки в записях с именами «csd-0», «csd-1» ...

Эти буферы могут быть отправлены непосредственно после start () или flu sh (), указав флаг BUFFER_FLAG_CODEC_CONFIG. Однако если вы сконфигурируете код c с MediaFormat, содержащим эти ключи, они будут автоматически отправлены MediaCode c сразу после запуска. > Поэтому использование флага BUFFER_FLAG_CODEC_CONFIG не рекомендуется и рекомендуется только для опытных пользователей .

...