android - установка времени презентации медиакодека

Я использовал приведенный ниже код для кодирования необработанных данных в h264 для создания видео, и оно очень хорошо закодировано, но видео воспроизводится слишком быстро. Кажется, что есть проблема со временем презентации. когда начинается запись, я устанавливаю значение «tstart» и для каждого кадра вычисляю разницу текущего времени с tstart и передаю его в буфер ввода очереди, но ничего не изменилось. в какой части проблема? Я знаю, что в Android 4.3 я могу передать поверхность медиакодеку, но я хочу поддерживать Android 4.1. заранее спасибо.

 public void onPreviewFrame(final byte[] bytes, Camera camera) {
                    if (recording == true) {
                        long time = System.nanoTime();
                        time -= tstart;
                        if(mThread.isAlive()&&recording == true) {
                            encode(bytes, time );

                        }

                    }
 }

private synchronized void encode(byte[] dataInput,long time)
{
    byte[] data=new byte[dataInput.length];
    NV21toYUV420Planar(dataInput,data,640,480);

    inputBuffers = mMediaCodec.getInputBuffers();// here changes
    outputBuffers = mMediaCodec.getOutputBuffers();

    int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);

    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
        inputBuffer.clear();
        inputBuffer.put(data);
        time/=1000;
        mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, time, 0);

    } else {
        return;
    }

    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0);
    Log.i("tag", "outputBufferIndex-->" + outputBufferIndex);
    do {
        if (outputBufferIndex >= 0) {
            ByteBuffer outBuffer = outputBuffers[outputBufferIndex];
            byte[] outData = new byte[bufferInfo.size];
            outBuffer.get(outData);
            try {
                if (bufferInfo.offset != 0) {
                    fos.write(outData, bufferInfo.offset, outData.length
                            - bufferInfo.offset);
                } else {
                    fos.write(outData, 0, outData.length);
                }
                fos.flush();
                Log.i("camera", "out data -- > " + outData.length);
                mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo,
                        0);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            outputBuffers = mMediaCodec.getOutputBuffers();
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat format = mMediaCodec.getOutputFormat();
        }
    } while (outputBufferIndex >= 0);
}

person Sajad Norouzi    schedule 20.03.2016    source источник


Ответы (1)


Ваша проблема в том, что вы не записываете выходные кадры в контейнер, который вообще хранит временные метки. Вы пишете простой файл H264, который содержит только необработанные закодированные кадры, без индекса, без временных меток, без звука и ничего больше.

Чтобы получить правильные временные метки для файлов, вам нужно использовать MediaMuxer (которая появилась в 4.3) или аналогичную стороннюю библиотеку (например, libavformat или аналогичную) для записи закодированных пакетов в файл. Временная метка выходного пакета находится в bufferInfo.presentationTime, а в предложении if (outputBufferIndex >= 0) { вы ее вообще не используете — вы в основном выбрасываете временные метки.

person mstorsjo    schedule 20.03.2016
comment
так что же такое PresentationTimeUs, который является четвертым параметром функции queueinputbuffer? - person Sajad Norouzi; 20.03.2016
comment
Это время представления входного кадра. В большинстве/во всех случаях он фактически не включается в закодированные данные, он только переносится вместе с закодированным кадром, чтобы вы знали, какой временной метке соответствует закодированный пакет. При записи закодированного пакета в файл вам необходимо передать его (bufferInfo.presentationTimeUs) в файл (передать его API MediaMuxer или другой библиотеке, которую вы используете для записи видеофайлов). - person mstorsjo; 20.03.2016
comment
@SajadNorouzi Пакеты не должны выходить из кодировщика в том же порядке, в котором они поступали. Поэтому, если метка времени не была передана, у вас могут возникнуть проблемы с сопоставлением метки времени с выходным пакетом. - person fadden; 21.03.2016