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