Обработка MediaCodec видео с пропущенными кадрами - PullRequest
0 голосов
/ 27 августа 2018

В настоящее время я делаю быстрый точный поиск, используя 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

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

33 -> 66 -> 99 -> 132 -> 166

Переход от 132 к 16634 мс вместо 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 равно -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);
...