Merge pull request #4054 from google/dev-v2-r2.7.2

r2.7.2
This commit is contained in:
ojw28 2018-03-29 21:58:39 +01:00 committed by GitHub
commit 1c6149b4d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 323 additions and 91 deletions

View file

@ -1,5 +1,19 @@
# Release notes #
### 2.7.2 ###
* Gradle: Upgrade Gradle version from 4.1 to 4.4 so it can work with Android
Studio 3.1 ([#3708](https://github.com/google/ExoPlayer/issues/3708)).
* Match codecs starting with "mp4a" to different Audio MimeTypes
([#3779](https://github.com/google/ExoPlayer/issues/3779)).
* Fix ANR issue on Redmi 4X and Redmi Note 4
([#4006](https://github.com/google/ExoPlayer/issues/4006)).
* Fix handling of zero padded strings when parsing Matroska streams
([#4010](https://github.com/google/ExoPlayer/issues/4010)).
* Fix "Decoder input buffer too small" error when playing some FLAC streams.
* MediaSession extension: Omit fast forward and rewind actions when media is not
seekable ([#4001](https://github.com/google/ExoPlayer/issues/4001)).
### 2.7.1 ###
* Gradle: Replaced 'compile' (deprecated) with 'implementation' and

View file

@ -17,8 +17,8 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.novoda:bintray-release:0.5.0'
classpath 'com.android.tools.build:gradle:3.1.0'
classpath 'com.novoda:bintray-release:0.8.1'
}
// Workaround for the following test coverage issue. Remove when fixed:
// https://code.google.com/p/android/issues/detail?id=226070

View file

@ -13,8 +13,8 @@
// limitations under the License.
project.ext {
// ExoPlayer version and version code.
releaseVersion = '2.7.1'
releaseVersionCode = 2701
releaseVersion = '2.7.2'
releaseVersionCode = 2702
// Important: ExoPlayer specifies a minSdkVersion of 14 because various
// components provided by the library may be of use on older devices.
// However, please note that the core media playback functionality provided
@ -22,7 +22,7 @@ project.ext {
minSdkVersion = 14
targetSdkVersion = 27
compileSdkVersion = 27
buildToolsVersion = '26.0.2'
buildToolsVersion = '27.0.3'
testSupportLibraryVersion = '0.5'
supportLibraryVersion = '27.0.0'
playServicesLibraryVersion = '11.4.2'

View file

@ -29,7 +29,8 @@ EXOPLAYER_ROOT="$(pwd)"
FFMPEG_EXT_PATH="${EXOPLAYER_ROOT}/extensions/ffmpeg/src/main"
```
* Download the [Android NDK][] and set its location in an environment variable:
* Download the [Android NDK][] and set its location in an environment variable.
Only versions up to NDK 15c are supported currently.
```
NDK_PATH="<path to Android NDK>"

View file

@ -9,7 +9,7 @@ track 0:
id = null
containerMimeType = null
sampleMimeType = audio/raw
maxInputSize = -1
maxInputSize = 16384
width = -1
height = -1
frameRate = -1.0

View file

@ -9,7 +9,7 @@ track 0:
id = null
containerMimeType = null
sampleMimeType = audio/raw
maxInputSize = -1
maxInputSize = 16384
width = -1
height = -1
frameRate = -1.0

View file

@ -9,7 +9,7 @@ track 0:
id = null
containerMimeType = null
sampleMimeType = audio/raw
maxInputSize = -1
maxInputSize = 16384
width = -1
height = -1
frameRate = -1.0

View file

@ -9,7 +9,7 @@ track 0:
id = null
containerMimeType = null
sampleMimeType = audio/raw
maxInputSize = -1
maxInputSize = 16384
width = -1
height = -1
frameRate = -1.0

View file

@ -116,7 +116,7 @@ public final class FlacExtractor implements Extractor {
MimeTypes.AUDIO_RAW,
null,
streamInfo.bitRate(),
Format.NO_VALUE,
streamInfo.maxDecodedFrameSize(),
streamInfo.channels,
streamInfo.sampleRate,
getPcmEncoding(streamInfo.bitsPerSample),

View file

@ -77,11 +77,10 @@ public class DefaultPlaybackController implements MediaSessionConnector.Playback
public long getSupportedPlaybackActions(Player player) {
if (player == null || player.getCurrentTimeline().isEmpty()) {
return 0;
} else if (!player.isCurrentWindowSeekable()) {
return BASE_ACTIONS;
}
long actions = BASE_ACTIONS;
if (player.isCurrentWindowSeekable()) {
actions |= PlaybackStateCompat.ACTION_SEEK_TO;
}
long actions = BASE_ACTIONS | PlaybackStateCompat.ACTION_SEEK_TO;
if (fastForwardIncrementMs > 0) {
actions |= PlaybackStateCompat.ACTION_FAST_FORWARD;
}

View file

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

View file

@ -11,6 +11,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
apply from: "${rootDir}/javadoc_util.gradle"
class CombinedJavadocPlugin implements Plugin<Project> {
static final String TASK_NAME = "generateCombinedJavadoc"
@ -20,22 +22,32 @@ class CombinedJavadocPlugin implements Plugin<Project> {
project.gradle.projectsEvaluated {
Set<Project> libraryModules = getLibraryModules(project)
if (!libraryModules.isEmpty()) {
String sdkDirectory = getSdkDirectory(libraryModules)
project.task(TASK_NAME, type: Javadoc) {
description = "Generates combined Javadoc."
title = "ExoPlayer library"
source = libraryModules.generateJavadoc.source
classpath = project.files(libraryModules.generateJavadoc.classpath)
classpath = project.files([])
destinationDir = project.file("$project.buildDir/docs/javadoc")
options {
links "http://docs.oracle.com/javase/7/docs/api/"
linksOffline "https://developer.android.com/reference",
"${sdkDirectory}/docs/reference"
links "https://docs.oracle.com/javase/7/docs/api/",
"https://developer.android.com/reference"
encoding = "UTF-8"
}
exclude "**/BuildConfig.java"
exclude "**/R.java"
destinationDir project.file("$project.buildDir/docs/javadoc")
doFirst {
libraryModules.each { libraryModule ->
libraryModule.android.libraryVariants.all { variant ->
def name = variant.buildType.name
if (name.equals("release")) {
classpath +=
libraryModule.project.files(
variant.javaCompile.classpath.files,
libraryModule.project.android.getBootClasspath())
}
}
}
}
doLast {
libraryModules.each { libraryModule ->
project.copy {
@ -43,6 +55,7 @@ class CombinedJavadocPlugin implements Plugin<Project> {
into "${project.buildDir}/docs/javadoc"
}
}
project.fixJavadoc()
}
}
}
@ -57,12 +70,6 @@ class CombinedJavadocPlugin implements Plugin<Project> {
}
}
// Returns the Android SDK directory given a set of Android library modules.
private String getSdkDirectory(Set<Project> libraryModules) {
// We can retrieve the Android SDK directory from any module.
return libraryModules.iterator().next().android.sdkDirectory
}
}
apply plugin: CombinedJavadocPlugin

View file

@ -11,6 +11,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
apply from: "${rootDir}/javadoc_util.gradle"
android.libraryVariants.all { variant ->
def name = variant.buildType.name
if (!name.equals("release")) {
@ -20,21 +22,26 @@ android.libraryVariants.all { variant ->
description = "Generates Javadoc for the ${javadocTitle}."
title = "ExoPlayer ${javadocTitle}"
source = variant.javaCompile.source
classpath = files(variant.javaCompile.classpath.files,
project.android.getBootClasspath())
options {
links "http://docs.oracle.com/javase/7/docs/api/"
linksOffline "https://developer.android.com/reference",
"${android.sdkDirectory}/docs/reference"
"${android.sdkDirectory}/docs/reference"
encoding = "UTF-8"
}
exclude "**/BuildConfig.java"
exclude "**/R.java"
doFirst {
classpath =
files(
variant.javaCompile.classpath.files,
project.android.getBootClasspath())
}
doLast {
copy {
from "src/main/javadoc"
into "$buildDir/docs/javadoc"
}
project.fixJavadoc()
}
}
}

39
javadoc_util.gradle Normal file
View file

@ -0,0 +1,39 @@
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
ext.fixJavadoc = {
def javadocPath = "${project.buildDir}/docs/javadoc"
// Fix external Android links to target the top frame.
def androidRoot = "https://developer.android.com/reference/"
def androidLink = "<a href=\"(${androidRoot}.*?)\\?is-external=true\""
def androidFixed = "<a href=\"\\1\" target=\"_top\""
ant.replaceregexp(match:androidLink, replace:androidFixed, flags:'g') {
fileset(dir: "${javadocPath}", includes: "**/*.html")
}
// Fix external Oracle links to use frames and target the top frame.
def oracleRoot = "https://docs.oracle.com/javase/7/docs/api/"
def oracleLink = "<a href=\"(${oracleRoot})(.*?)\\?is-external=true\""
def oracleFixed = "<a href=\"\\1index.html\\?\\2\" target=\"_top\""
ant.replaceregexp(match:oracleLink, replace:oracleFixed, flags:'g') {
fileset(dir: "${javadocPath}", includes: "**/*.html")
}
// Remove date metadata that changes every time Javadoc is generated.
def javadocGeneratedBy = "<!-- Generated by javadoc.*?-->\n"
ant.replaceregexp(match:javadocGeneratedBy, replace:"") {
fileset(dir: "${javadocPath}", includes: "**/*.html")
}
def dateMeta = "<meta name=\"date\".*?>\n"
ant.replaceregexp(match:dateMeta, replace:"") {
fileset(dir: "${javadocPath}", includes: "**/*.html")
}
}

View file

@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
/** The version of the library expressed as a string, for example "1.2.3". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public static final String VERSION = "2.7.1";
public static final String VERSION = "2.7.2";
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final String VERSION_SLASHY = "ExoPlayerLib/2.7.1";
public static final String VERSION_SLASHY = "ExoPlayerLib/2.7.2";
/**
* The version of the library expressed as an integer, for example 1002003.
@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final int VERSION_INT = 2007001;
public static final int VERSION_INT = 2007002;
/**
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}

View file

@ -202,10 +202,11 @@ import java.util.Stack;
}
/**
* Reads and returns a string of length {@code byteLength} from the {@link ExtractorInput}.
* Reads a string of length {@code byteLength} from the {@link ExtractorInput}. Zero padding is
* removed, so the returned string may be shorter than {@code byteLength}.
*
* @param input The {@link ExtractorInput} from which to read.
* @param byteLength The length of the float being read.
* @param byteLength The length of the string being read, including zero padding.
* @return The read string value.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread is interrupted.
@ -217,7 +218,12 @@ import java.util.Stack;
}
byte[] stringBytes = new byte[byteLength];
input.readFully(stringBytes, 0, byteLength);
return new String(stringBytes);
// Remove zero padding.
int trimmedLength = byteLength;
while (trimmedLength > 0 && stringBytes[trimmedLength - 1] == 0) {
trimmedLength--;
}
return new String(stringBytes, 0, trimmedLength);
}
/**

View file

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.extractor.mp4;
import static com.google.android.exoplayer2.util.MimeTypes.getMimeTypeFromMp4ObjectType;
import android.util.Log;
import android.util.Pair;
import com.google.android.exoplayer2.C;
@ -1030,47 +1032,11 @@ import java.util.List;
// Set the MIME type based on the object type indication (14496-1 table 5).
int objectTypeIndication = parent.readUnsignedByte();
String mimeType;
switch (objectTypeIndication) {
case 0x60:
case 0x61:
mimeType = MimeTypes.VIDEO_MPEG2;
break;
case 0x20:
mimeType = MimeTypes.VIDEO_MP4V;
break;
case 0x21:
mimeType = MimeTypes.VIDEO_H264;
break;
case 0x23:
mimeType = MimeTypes.VIDEO_H265;
break;
case 0x6B:
mimeType = MimeTypes.AUDIO_MPEG;
return Pair.create(mimeType, null);
case 0x40:
case 0x66:
case 0x67:
case 0x68:
mimeType = MimeTypes.AUDIO_AAC;
break;
case 0xA5:
mimeType = MimeTypes.AUDIO_AC3;
break;
case 0xA6:
mimeType = MimeTypes.AUDIO_E_AC3;
break;
case 0xA9:
case 0xAC:
mimeType = MimeTypes.AUDIO_DTS;
return Pair.create(mimeType, null);
case 0xAA:
case 0xAB:
mimeType = MimeTypes.AUDIO_DTS_HD;
return Pair.create(mimeType, null);
default:
mimeType = null;
break;
String mimeType = getMimeTypeFromMp4ObjectType(objectTypeIndication);
if (MimeTypes.AUDIO_MPEG.equals(mimeType)
|| MimeTypes.AUDIO_DTS.equals(mimeType)
|| MimeTypes.AUDIO_DTS_HD.equals(mimeType)) {
return Pair.create(mimeType, null);
}
parent.skipBytes(12);

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.util;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.google.android.exoplayer2.C;
@ -194,7 +195,20 @@ public final class MimeTypes {
} else if (codec.startsWith("vp8") || codec.startsWith("vp08")) {
return MimeTypes.VIDEO_VP8;
} else if (codec.startsWith("mp4a")) {
return MimeTypes.AUDIO_AAC;
String mimeType = null;
if (codec.startsWith("mp4a.")) {
String objectTypeString = codec.substring(5); // remove the 'mp4a.' prefix
if (objectTypeString.length() >= 2) {
try {
String objectTypeHexString = Util.toUpperInvariant(objectTypeString.substring(0, 2));
int objectTypeInt = Integer.parseInt(objectTypeHexString, 16);
mimeType = getMimeTypeFromMp4ObjectType(objectTypeInt);
} catch (NumberFormatException ignored) {
// ignored
}
}
}
return mimeType == null ? MimeTypes.AUDIO_AAC : mimeType;
} else if (codec.startsWith("ac-3") || codec.startsWith("dac3")) {
return MimeTypes.AUDIO_AC3;
} else if (codec.startsWith("ec-3") || codec.startsWith("dec3")) {
@ -213,6 +227,50 @@ public final class MimeTypes {
return null;
}
/**
* Derives a mimeType from MP4 object type identifier, as defined in RFC 6381 and
* http://www.mp4ra.org/object.html.
*
* @param objectType The objectType identifier to derive.
* @return The mimeType, or null if it could not be derived.
*/
@Nullable
public static String getMimeTypeFromMp4ObjectType(int objectType) {
switch (objectType) {
case 0x60:
case 0x61:
return MimeTypes.VIDEO_MPEG2;
case 0x20:
return MimeTypes.VIDEO_MP4V;
case 0x21:
return MimeTypes.VIDEO_H264;
case 0x23:
return MimeTypes.VIDEO_H265;
case 0x69:
case 0x6B:
return MimeTypes.AUDIO_MPEG;
case 0x40:
case 0x66:
case 0x67:
case 0x68:
return MimeTypes.AUDIO_AAC;
case 0xA5:
return MimeTypes.AUDIO_AC3;
case 0xA6:
return MimeTypes.AUDIO_E_AC3;
case 0xA9:
case 0xAC:
return MimeTypes.AUDIO_DTS;
case 0xAA:
case 0xAB:
return MimeTypes.AUDIO_DTS_HD;
case 0xAD:
return MimeTypes.AUDIO_OPUS;
default:
return null;
}
}
/**
* Returns the {@link C}{@code .TRACK_TYPE_*} constant that corresponds to a specified MIME type.
* {@link C#TRACK_TYPE_UNKNOWN} if the MIME type is not known or the mapping cannot be

View file

@ -306,6 +306,16 @@ public final class Util {
return text == null ? null : text.toLowerCase(Locale.US);
}
/**
* Converts text to upper case using {@link Locale#US}.
*
* @param text The text to convert.
* @return The upper case text, or null if {@code text} is null.
*/
public static String toUpperInvariant(String text) {
return text == null ? null : text.toUpperCase(Locale.US);
}
/**
* Divides a {@code numerator} by a {@code denominator}, returning the ceiled result.
*

View file

@ -1102,9 +1102,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// Work around https://github.com/google/ExoPlayer/issues/3236,
// https://github.com/google/ExoPlayer/issues/3355,
// https://github.com/google/ExoPlayer/issues/3439,
// https://github.com/google/ExoPlayer/issues/3724 and
// https://github.com/google/ExoPlayer/issues/3835.
return (("deb".equals(Util.DEVICE) || "flo".equals(Util.DEVICE)) // Nexus 7 (2013)
// https://github.com/google/ExoPlayer/issues/3724,
// https://github.com/google/ExoPlayer/issues/3835 and
// https://github.com/google/ExoPlayer/issues/4006.
return (("deb".equals(Util.DEVICE) // Nexus 7 (2013)
|| "flo".equals(Util.DEVICE) // Nexus 7 (2013)
|| "mido".equals(Util.DEVICE) // Redmi Note 4
|| "santoni".equals(Util.DEVICE)) // Redmi 4X
&& "OMX.qcom.video.decoder.avc".equals(name))
|| (("tcl_eu".equals(Util.DEVICE) // TCL Percee TV
|| "SVP-DTV15".equals(Util.DEVICE) // Sony Bravia 4K 2015

View file

@ -89,6 +89,14 @@ public class DefaultEbmlReaderTest {
assertEvents(input, expected.events);
}
@Test
public void testStringElementWithZeroPadding() throws IOException, InterruptedException {
ExtractorInput input = createTestInput(0x42, 0x82, 0x86, 0x41, 0x62, 0x63, 0x00, 0x00, 0x00);
TestOutput expected = new TestOutput();
expected.stringElement(TestOutput.ID_DOC_TYPE, "Abc");
assertEvents(input, expected.events);
}
@Test
public void testStringElementEmpty() throws IOException, InterruptedException {
ExtractorInput input = createTestInput(0x42, 0x82, 0x80);

View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.util;
import static com.google.common.truth.Truth.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Unit test for {@link MimeTypes}. */
@RunWith(RobolectricTestRunner.class)
public final class MimeTypesTest {
@Test
public void testGetMediaMimeType_fromValidCodecs_returnsCorrectMimeType() {
assertThat(MimeTypes.getMediaMimeType("avc1")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc1.42E01E")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc1.42E01F")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc1.4D401F")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc1.4D4028")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc1.640028")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc1.640029")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("avc3")).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMediaMimeType("hev1")).isEqualTo(MimeTypes.VIDEO_H265);
assertThat(MimeTypes.getMediaMimeType("hvc1")).isEqualTo(MimeTypes.VIDEO_H265);
assertThat(MimeTypes.getMediaMimeType("vp08")).isEqualTo(MimeTypes.VIDEO_VP8);
assertThat(MimeTypes.getMediaMimeType("vp8")).isEqualTo(MimeTypes.VIDEO_VP8);
assertThat(MimeTypes.getMediaMimeType("vp09")).isEqualTo(MimeTypes.VIDEO_VP9);
assertThat(MimeTypes.getMediaMimeType("vp9")).isEqualTo(MimeTypes.VIDEO_VP9);
assertThat(MimeTypes.getMediaMimeType("ac-3")).isEqualTo(MimeTypes.AUDIO_AC3);
assertThat(MimeTypes.getMediaMimeType("dac3")).isEqualTo(MimeTypes.AUDIO_AC3);
assertThat(MimeTypes.getMediaMimeType("dec3")).isEqualTo(MimeTypes.AUDIO_E_AC3);
assertThat(MimeTypes.getMediaMimeType("ec-3")).isEqualTo(MimeTypes.AUDIO_E_AC3);
assertThat(MimeTypes.getMediaMimeType("ec+3")).isEqualTo(MimeTypes.AUDIO_E_AC3_JOC);
assertThat(MimeTypes.getMediaMimeType("dtsc")).isEqualTo(MimeTypes.AUDIO_DTS);
assertThat(MimeTypes.getMediaMimeType("dtse")).isEqualTo(MimeTypes.AUDIO_DTS);
assertThat(MimeTypes.getMediaMimeType("dtsh")).isEqualTo(MimeTypes.AUDIO_DTS_HD);
assertThat(MimeTypes.getMediaMimeType("dtsl")).isEqualTo(MimeTypes.AUDIO_DTS_HD);
assertThat(MimeTypes.getMediaMimeType("opus")).isEqualTo(MimeTypes.AUDIO_OPUS);
assertThat(MimeTypes.getMediaMimeType("vorbis")).isEqualTo(MimeTypes.AUDIO_VORBIS);
assertThat(MimeTypes.getMediaMimeType("mp4a")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.40.02")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.40.05")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.40.2")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.40.5")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.40.29")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.66")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.67")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.68")).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMediaMimeType("mp4a.69")).isEqualTo(MimeTypes.AUDIO_MPEG);
assertThat(MimeTypes.getMediaMimeType("mp4a.6B")).isEqualTo(MimeTypes.AUDIO_MPEG);
assertThat(MimeTypes.getMediaMimeType("mp4a.a5")).isEqualTo(MimeTypes.AUDIO_AC3);
assertThat(MimeTypes.getMediaMimeType("mp4a.A5")).isEqualTo(MimeTypes.AUDIO_AC3);
assertThat(MimeTypes.getMediaMimeType("mp4a.a6")).isEqualTo(MimeTypes.AUDIO_E_AC3);
assertThat(MimeTypes.getMediaMimeType("mp4a.A6")).isEqualTo(MimeTypes.AUDIO_E_AC3);
assertThat(MimeTypes.getMediaMimeType("mp4a.A9")).isEqualTo(MimeTypes.AUDIO_DTS);
assertThat(MimeTypes.getMediaMimeType("mp4a.AC")).isEqualTo(MimeTypes.AUDIO_DTS);
assertThat(MimeTypes.getMediaMimeType("mp4a.AA")).isEqualTo(MimeTypes.AUDIO_DTS_HD);
assertThat(MimeTypes.getMediaMimeType("mp4a.AB")).isEqualTo(MimeTypes.AUDIO_DTS_HD);
assertThat(MimeTypes.getMediaMimeType("mp4a.AD")).isEqualTo(MimeTypes.AUDIO_OPUS);
}
@Test
public void testGetMimeTypeFromMp4ObjectType_forValidObjectType_returnsCorrectMimeType() {
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x60)).isEqualTo(MimeTypes.VIDEO_MPEG2);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x61)).isEqualTo(MimeTypes.VIDEO_MPEG2);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x20)).isEqualTo(MimeTypes.VIDEO_MP4V);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x21)).isEqualTo(MimeTypes.VIDEO_H264);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x23)).isEqualTo(MimeTypes.VIDEO_H265);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x6B)).isEqualTo(MimeTypes.AUDIO_MPEG);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x40)).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x66)).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x67)).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x68)).isEqualTo(MimeTypes.AUDIO_AAC);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0xA5)).isEqualTo(MimeTypes.AUDIO_AC3);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0xA6)).isEqualTo(MimeTypes.AUDIO_E_AC3);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0xA9)).isEqualTo(MimeTypes.AUDIO_DTS);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0xAC)).isEqualTo(MimeTypes.AUDIO_DTS);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0xAA)).isEqualTo(MimeTypes.AUDIO_DTS_HD);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0xAB)).isEqualTo(MimeTypes.AUDIO_DTS_HD);
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0xAD)).isEqualTo(MimeTypes.AUDIO_OPUS);
}
@Test
public void testGetMimeTypeFromMp4ObjectType_forInvalidObjectType_returnsNull() {
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0)).isNull();
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x600)).isNull();
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(0x01)).isNull();
assertThat(MimeTypes.getMimeTypeFromMp4ObjectType(-1)).isNull();
}
}

View file

@ -117,7 +117,8 @@ public final class DashDownloader extends SegmentDownloader<DashManifest, Repres
}
}
int segmentCount = index.getSegmentCount(C.TIME_UNSET);
long periodDurationUs = manifest.getPeriodDurationUs(key.periodIndex);
int segmentCount = index.getSegmentCount(periodDurationUs);
if (segmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
throw new DownloadException("Unbounded index for representation: " + key);
}

View file

@ -52,6 +52,9 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
Format format, List<Format> muxedCaptionFormats, DrmInitData drmInitData,
TimestampAdjuster timestampAdjuster) {
String lastPathSegment = uri.getLastPathSegment();
if (lastPathSegment == null) {
lastPathSegment = "";
}
boolean isPackedAudioExtractor = false;
Extractor extractor;
if (MimeTypes.TEXT_VTT.equals(format.sampleMimeType)

View file

@ -20,12 +20,12 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment;
import com.google.android.exoplayer2.util.Util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Locale;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@ -122,7 +122,7 @@ public class HlsMediaPlaylistParserTest {
.isEqualTo("https://priv.example.com/key.php?r=2682");
// 0xA7A == 2682.
assertThat(segment.encryptionIV).isNotNull();
assertThat(segment.encryptionIV.toUpperCase(Locale.getDefault())).isEqualTo("A7A");
assertThat(Util.toUpperInvariant(segment.encryptionIV)).isEqualTo("A7A");
assertThat(segment.byterangeLength).isEqualTo(51740);
assertThat(segment.byterangeOffset).isEqualTo(2147586650L);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2682.ts");
@ -134,7 +134,7 @@ public class HlsMediaPlaylistParserTest {
.isEqualTo("https://priv.example.com/key.php?r=2682");
// 0xA7B == 2683.
assertThat(segment.encryptionIV).isNotNull();
assertThat(segment.encryptionIV.toUpperCase(Locale.getDefault())).isEqualTo("A7B");
assertThat(Util.toUpperInvariant(segment.encryptionIV)).isEqualTo("A7B");
assertThat(segment.byterangeLength).isEqualTo(C.LENGTH_UNSET);
assertThat(segment.byterangeOffset).isEqualTo(0);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts");

View file

@ -250,7 +250,7 @@ public class DefaultTimeBar extends View implements TimeBar {
try {
scrubberDrawable = a.getDrawable(R.styleable.DefaultTimeBar_scrubber_drawable);
if (scrubberDrawable != null) {
setDrawableLayoutDirection(scrubberDrawable, getLayoutDirection());
setDrawableLayoutDirection(scrubberDrawable);
defaultTouchTargetHeight =
Math.max(scrubberDrawable.getMinimumHeight(), defaultTouchTargetHeight);
}
@ -747,8 +747,8 @@ public class DefaultTimeBar extends View implements TimeBar {
return true;
}
private static int dpToPx(DisplayMetrics displayMetrics, int dps) {
return (int) (dps * displayMetrics.density + 0.5f);
private boolean setDrawableLayoutDirection(Drawable drawable) {
return Util.SDK_INT >= 23 && setDrawableLayoutDirection(drawable, getLayoutDirection());
}
private static boolean setDrawableLayoutDirection(Drawable drawable, int layoutDirection) {
@ -771,4 +771,7 @@ public class DefaultTimeBar extends View implements TimeBar {
return 0x33000000 | (adMarkerColor & 0x00FFFFFF);
}
private static int dpToPx(DisplayMetrics displayMetrics, int dps) {
return (int) (dps * displayMetrics.density + 0.5f);
}
}

View file

@ -16,8 +16,8 @@ if (project.ext.has("exoplayerPublishEnabled")
apply plugin: 'bintray-release'
publish {
artifactId = releaseArtifact
description = releaseDescription
version = releaseVersion
desc = releaseDescription
publishVersion = releaseVersion
repoName = getBintrayRepo()
userOrg = 'google'
groupId = 'com.google.android.exoplayer'