Обработка MediaCodec видео с пропущенными кадрами - программирование
Подтвердить что ты не робот

Обработка MediaCodec видео с пропущенными кадрами

В настоящее время я делаю быстрый точный поиск с использованием MediaCodec. То, что я сейчас делаю, чтобы пропустить кадр за кадром, я сначала получаю общее количество кадров:

mediaInfo.totalFrames = videoTrack.getSamples().size();

Тогда я получаю длину видео файла:

mediaInfo.durationUs = videoTrack.getDuration() * 1000 *1000 / timeScale;

//then calling:
public long getDuration() {
    if (mMediaInfo != null) {
        return (int) mMediaInfo.durationUs / 1000; // to millisecond
    }
    return -1;
}

Теперь, когда я хочу получить следующий кадр, я вызываю следующее:

mNextFrame.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            int frames = Integer.parseInt(String.valueOf(getTotalFrames));
            int intervals = Integer.parseInt(String.valueOf(mPlayer.getDuration() / frames));

            if (mPlayer.isPlaying()) {
                mPlayer.pause();
                mPlayer.seekTo(mPlayer.getCurrentPosition() + intervals);
            } else {
                mPlayer.seekTo(mPlayer.getCurrentPosition() + intervals);
            }

        }
    });

Вот информация о файле, с которым я тестирую:

Frames = 466 Duration = 15523

Таким образом, интервал между кадрами

33,311158798283262

Другими словами, каждый раз, когда я mPlayer.seekTo(mPlayer.getCurrentPosition() + 33 следующую кнопку, интервалы будут округляться до 33, когда я mPlayer.seekTo(mPlayer.getCurrentPosition() + 33 следующую кнопку, она вызывает mPlayer.seekTo(mPlayer.getCurrentPosition() + 33 означая, что некоторые кадры будут потеряны, или это что я думал. Я проверял и получал следующее при регистрации getCurrentPosition после каждого нажатия кнопки и вот результат:

33 → 66 → 99 → 132 → 166

Переход от 132 к 166 составляет 34 мс вместо 33, поэтому была компенсация за кадры, которые могли бы быть потеряны.


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

Принимая ту же логику, которую я использовал выше, я создал собственный RangeBar. Я создал метод setTickCount (он в основном такой же, как seekbar.setMax) и установил "TickCount" следующим образом:

int frames = Integer.parseInt(String.valueOf(getTotalFrames));
mrange_bar.setTickCount(frames);

Таким образом, максимальное значение моего RangeBar - это количество кадров в видео.

Когда значение "Tick" меняется, я вызываю следующее:

int frames = Integer.parseInt(String.valueOf(getTotalFrames));
int intervals = Integer.parseInt(String.valueOf(mPlayer.getDuration() / frames));
mPlayer.seekTo(intervals * TickPosition);

Таким образом, вышесказанное будет работать так, если моя позиция tickCount, скажем, 40:

mPlayer.seekTo(33 * 40);//1320ms

Я думаю, что вышеописанное будет работать нормально, потому что я использовал точно такую же логику, но вместо этого видео "переход/переход" возвращается к (что я предполагаю является ключевым кадром), и поиск продолжается.

Почему происходит и как я могу решить эту проблему?


РЕДАКТИРОВАТЬ 1:

Я упомянул выше, что он переходит к предыдущему ключевому кадру, но я снова посмотрел и при поиске вызывает конец потока (в особых моментах видео). Когда я достигаю конца потока, я освобождаю свой предыдущий буфер, чтобы можно было отобразить один кадр, чтобы избежать черного экрана, вызвав:

mDecoder.releaseOutputBuffer(prevBufferIndex, true);

Итак, по какой-то причине вызывается конец потока, где я затем перезагружаю медиа-кодек, вызывая эффект "задержки/скачка". Если я удаляю вышеупомянутое, я не получаю "скачок" кадра, но все еще есть задержка, в то время как медиа-кодек инициализируется.


РЕДАКТИРОВАТЬ 2:

readSampleData глубже, я обнаружил, что readSampleData - это -1:

ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
    int inIndex = mDecoder.dequeueInputBuffer(TIMEOUT_USEC);
    if (inIndex >= 0) {
        ByteBuffer buffer = inputBuffers[inIndex];
        int sampleSize = mExtractor.readSampleData(buffer, 0);
        if (sampleSize < 0) {
            mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            mIsExtractorReachedEOS = true;
        } else {
            mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
            mExtractor.advance();
        }
    }

По какой-то причине мой sampleSize находится в -1 в определенный момент во время поиска.


РЕДАКТИРОВАТЬ 3

Эта проблема определенно касается времени, которое я прохожу, я попробовал 2 разных подхода, первый:

mPlayer.seekTo(progress);

//position is retrieved by setting mSeekBar.setMax(mPlayer.getDuration); ....

и при втором подходе я определяю интервалы кадров:

//Total amount of frames in video
long TotalFramesInVideo = videoTrack.getSamples().size();
//Duration of file in milliseconds
int DurationOfVideoInMs = mPlayer.getDuration();

//Determine interval between frames
int frameIntervals = DurationOfVideoInMs / Integer.parseInt(String.valueOf(TotalFramesInVideo));

//Then I seek to the frames like this:
mPlayer.seekTo(position * frameIntervals);

Попробовав оба вышеупомянутых метода, я понял, что проблема связана с временем, передаваемым в mediaCodec, потому что "отставание/скачок" происходит в разных местах.

Я не уверен, почему этого не происходит, когда я звоню:

mPlayer.seekTo(mPlayer.getCurrentPosition() + intervals);
4b9b3361