mirror of
https://github.com/samsonjs/media.git
synced 2026-04-05 11:15:46 +00:00
commit
1c6149b4d7
27 changed files with 323 additions and 91 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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>"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ track 0:
|
|||
id = null
|
||||
containerMimeType = null
|
||||
sampleMimeType = audio/raw
|
||||
maxInputSize = -1
|
||||
maxInputSize = 16384
|
||||
width = -1
|
||||
height = -1
|
||||
frameRate = -1.0
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ track 0:
|
|||
id = null
|
||||
containerMimeType = null
|
||||
sampleMimeType = audio/raw
|
||||
maxInputSize = -1
|
||||
maxInputSize = 16384
|
||||
width = -1
|
||||
height = -1
|
||||
frameRate = -1.0
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ track 0:
|
|||
id = null
|
||||
containerMimeType = null
|
||||
sampleMimeType = audio/raw
|
||||
maxInputSize = -1
|
||||
maxInputSize = 16384
|
||||
width = -1
|
||||
height = -1
|
||||
frameRate = -1.0
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ track 0:
|
|||
id = null
|
||||
containerMimeType = null
|
||||
sampleMimeType = audio/raw
|
||||
maxInputSize = -1
|
||||
maxInputSize = 16384
|
||||
width = -1
|
||||
height = -1
|
||||
frameRate = -1.0
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
39
javadoc_util.gradle
Normal 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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
Loading…
Reference in a new issue