Add utility methods for inexact ceil/floor binary searches.

This change also fixes issue #5
This commit is contained in:
Oliver Woodman 2014-07-09 15:34:42 +01:00
parent f1213a7656
commit 1b957268a6
5 changed files with 97 additions and 13 deletions

View File

@ -33,6 +33,7 @@ import com.google.android.exoplayer.parser.mp4.FragmentedMp4Extractor;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.NonBlockingInputStream;
import com.google.android.exoplayer.util.Util;
import android.util.Log;
@ -170,8 +171,8 @@ public class DashMp4ChunkSource implements ChunkSource {
int nextIndex;
if (queue.isEmpty()) {
nextIndex = Arrays.binarySearch(extractor.getSegmentIndex().timesUs, seekPositionUs);
nextIndex = nextIndex < 0 ? -nextIndex - 2 : nextIndex;
nextIndex = Util.binarySearchFloor(extractor.getSegmentIndex().timesUs, seekPositionUs,
true, true);
} else {
nextIndex = queue.get(out.queueSize - 1).nextChunkIndex;
}
@ -196,7 +197,7 @@ public class DashMp4ChunkSource implements ChunkSource {
public void onChunkLoadError(Chunk chunk, Exception e) {
// Do nothing.
}
private static Chunk newInitializationChunk(Representation representation,
FragmentedMp4Extractor extractor, DataSource dataSource, int trigger) {
DataSpec dataSpec = new DataSpec(representation.uri, 0, representation.indexEnd + 1,

View File

@ -33,6 +33,7 @@ import com.google.android.exoplayer.parser.webm.WebmExtractor;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.upstream.NonBlockingInputStream;
import com.google.android.exoplayer.util.Util;
import android.util.Log;
@ -151,8 +152,7 @@ public class DashWebmChunkSource implements ChunkSource {
int nextIndex;
if (queue.isEmpty()) {
nextIndex = Arrays.binarySearch(extractor.getCues().timesUs, seekPositionUs);
nextIndex = nextIndex < 0 ? -nextIndex - 2 : nextIndex;
nextIndex = Util.binarySearchFloor(extractor.getCues().timesUs, seekPositionUs, true, true);
} else {
nextIndex = queue.get(out.queueSize - 1).nextChunkIndex;
}

View File

@ -16,8 +16,8 @@
package com.google.android.exoplayer.smoothstreaming;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;
import java.util.Arrays;
import java.util.UUID;
/**
@ -195,9 +195,7 @@ public class SmoothStreamingManifest {
* @return The index of the corresponding chunk.
*/
public int getChunkIndex(long timeUs) {
long time = (timeUs * timeScale) / 1000000L;
int chunkIndex = Arrays.binarySearch(chunkStartTimes, time);
return chunkIndex < 0 ? -chunkIndex - 2 : chunkIndex;
return Util.binarySearchFloor(chunkStartTimes, (timeUs * timeScale) / 1000000L, true, true);
}
/**

View File

@ -16,8 +16,7 @@
package com.google.android.exoplayer.text.ttml;
import com.google.android.exoplayer.text.Subtitle;
import java.util.Arrays;
import com.google.android.exoplayer.util.Util;
/**
* A representation of a TTML subtitle.
@ -41,8 +40,7 @@ public final class TtmlSubtitle implements Subtitle {
@Override
public int getNextEventTimeIndex(long timeUs) {
int index = Arrays.binarySearch(eventTimesUs, timeUs - startTimeUs);
index = index >= 0 ? index + 1 : ~index;
int index = Util.binarySearchCeil(eventTimesUs, timeUs - startTimeUs, false, false);
return index < eventTimesUs.length ? index : -1;
}

View File

@ -19,6 +19,9 @@ import com.google.android.exoplayer.upstream.DataSource;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -112,4 +115,88 @@ public final class Util {
return text == null ? null : text.toLowerCase(Locale.US);
}
/**
* Returns the index of the largest value in an array that is less than (or optionally equal to)
* a specified key.
* <p>
* The search is performed using a binary search algorithm, and so the array must be sorted.
*
* @param a The array to search.
* @param key The key being searched for.
* @param inclusive If the key is present in the array, whether to return the corresponding index.
* If false then the returned index corresponds to the largest value in the array that is
* strictly less than the key.
* @param stayInBounds If true, then 0 will be returned in the case that the key is smaller than
* the smallest value in the array. If false then -1 will be returned.
*/
public static int binarySearchFloor(long[] a, long key, boolean inclusive, boolean stayInBounds) {
int index = Arrays.binarySearch(a, key);
index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1));
return stayInBounds ? Math.max(0, index) : index;
}
/**
* Returns the index of the smallest value in an array that is greater than (or optionally equal
* to) a specified key.
* <p>
* The search is performed using a binary search algorithm, and so the array must be sorted.
*
* @param a The array to search.
* @param key The key being searched for.
* @param inclusive If the key is present in the array, whether to return the corresponding index.
* If false then the returned index corresponds to the smallest value in the array that is
* strictly greater than the key.
* @param stayInBounds If true, then {@code (a.length - 1)} will be returned in the case that the
* key is greater than the largest value in the array. If false then {@code a.length} will be
* returned.
*/
public static int binarySearchCeil(long[] a, long key, boolean inclusive, boolean stayInBounds) {
int index = Arrays.binarySearch(a, key);
index = index < 0 ? ~index : (inclusive ? index : (index + 1));
return stayInBounds ? Math.min(a.length - 1, index) : index;
}
/**
* Returns the index of the largest value in an list that is less than (or optionally equal to)
* a specified key.
* <p>
* The search is performed using a binary search algorithm, and so the list must be sorted.
*
* @param list The list to search.
* @param key The key being searched for.
* @param inclusive If the key is present in the list, whether to return the corresponding index.
* If false then the returned index corresponds to the largest value in the list that is
* strictly less than the key.
* @param stayInBounds If true, then 0 will be returned in the case that the key is smaller than
* the smallest value in the list. If false then -1 will be returned.
*/
public static<T> int binarySearchFloor(List<? extends Comparable<? super T>> list, T key,
boolean inclusive, boolean stayInBounds) {
int index = Collections.binarySearch(list, key);
index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1));
return stayInBounds ? Math.max(0, index) : index;
}
/**
* Returns the index of the smallest value in an list that is greater than (or optionally equal
* to) a specified key.
* <p>
* The search is performed using a binary search algorithm, and so the list must be sorted.
*
* @param list The list to search.
* @param key The key being searched for.
* @param inclusive If the key is present in the list, whether to return the corresponding index.
* If false then the returned index corresponds to the smallest value in the list that is
* strictly greater than the key.
* @param stayInBounds If true, then {@code (list.size() - 1)} will be returned in the case that
* the key is greater than the largest value in the list. If false then {@code list.size()}
* will be returned.
*/
public static<T> int binarySearchCeil(List<? extends Comparable<? super T>> list, T key,
boolean inclusive, boolean stayInBounds) {
int index = Collections.binarySearch(list, key);
index = index < 0 ? ~index : (inclusive ? index : (index + 1));
return stayInBounds ? Math.min(list.size() - 1, index) : index;
}
}