Skip to content

Commit

Permalink
Add utility methods for inexact ceil/floor binary searches.
Browse files Browse the repository at this point in the history
This change also fixes issue #5
  • Loading branch information
ojw28 committed Jul 9, 2014
1 parent f1213a7 commit 1b95726
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
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;

Expand Down Expand Up @@ -170,8 +171,8 @@ public final void getChunkOperation(List<? extends MediaChunk> queue, long seekP

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;
}
Expand All @@ -196,7 +197,7 @@ public IOException getError() {
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
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;

Expand Down Expand Up @@ -151,8 +152,7 @@ public final void getChunkOperation(List<? extends MediaChunk> queue, long seekP

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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -195,9 +195,7 @@ public StreamElement(int type, String subType, long timeScale, String name,
* @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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -41,8 +40,7 @@ public long getStartTime() {

@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;
}

Expand Down
87 changes: 87 additions & 0 deletions library/src/main/java/com/google/android/exoplayer/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

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;
Expand Down Expand Up @@ -112,4 +115,88 @@ public static String toLowerInvariant(String text) {
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;
}

}

0 comments on commit 1b95726

Please sign in to comment.