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