Skip to content

Commit

Permalink
Merge pull request #7162 from google/dev-v2-r2.11.4
Browse files Browse the repository at this point in the history
r2.11.4
  • Loading branch information
ojw28 committed Apr 8, 2020
2 parents 49910fe + 76374d7 commit 7d3f54a
Show file tree
Hide file tree
Showing 85 changed files with 2,716 additions and 702 deletions.
54 changes: 54 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,59 @@
# Release notes #

### 2.11.4 (2020-04-08) ###

* Add `SimpleExoPlayer.setWakeMode` to allow automatic `WifiLock` and `WakeLock`
handling ([#6914](https://github.com/google/ExoPlayer/issues/6914)). To use
this feature, you must add the
[WAKE_LOCK](https://developer.android.com/reference/android/Manifest.permission.html#WAKE_LOCK)
permission to your application's manifest file.
* Text:
* Catch and log exceptions in `TextRenderer` rather than re-throwing. This
allows playback to continue even if subtitle decoding fails
([#6885](https://github.com/google/ExoPlayer/issues/6885)).
* Allow missing hours and milliseconds in SubRip (.srt) timecodes
([#7122](https://github.com/google/ExoPlayer/issues/7122)).
* Audio:
* Enable playback speed adjustment and silence skipping for floating point PCM
audio, via resampling to 16-bit integer PCM. To output the original floating
point audio without adjustment, pass `enableFloatOutput=true` to the
`DefaultAudioSink` constructor
([#7134](https://github.com/google/ExoPlayer/issues/7134)).
* Workaround issue that could cause slower than realtime playback of AAC on
Android 10 ([#6671](https://github.com/google/ExoPlayer/issues/6671).
* Fix case where another app spuriously holding transient audio focus could
prevent ExoPlayer from acquiring audio focus for an indefinite period of
time ([#7182](https://github.com/google/ExoPlayer/issues/7182).
* Fix case where the player volume could be permanently ducked if audio focus
was released whilst ducking.
* Fix playback of WAV files with trailing non-media bytes
([#7129](https://github.com/google/ExoPlayer/issues/7129)).
* Fix playback of ADTS files with mid-stream ID3 metadata.
* DRM:
* Fix stuck ad playbacks with DRM protected content
([#7188](https://github.com/google/ExoPlayer/issues/7188)).
* Fix playback of Widevine protected content that only provides V1 PSSH atoms
on API levels 21 and 22.
* Fix playback of PlayReady content on Fire TV Stick (Gen 2).
* DASH:
* Update the manifest URI to avoid repeated HTTP redirects
([#6907](https://github.com/google/ExoPlayer/issues/6907)).
* Parse period `AssetIdentifier` elements.
* HLS: Recognize IMSC subtitles
([#7185](https://github.com/google/ExoPlayer/issues/7185)).
* UI: Add an option to set whether to use the orientation sensor for rotation
in spherical playbacks
([#6761](https://github.com/google/ExoPlayer/issues/6761)).
* Analytics: Fix `PlaybackStatsListener` behavior when not keeping history
([#7160](https://github.com/google/ExoPlayer/issues/7160)).
* FFmpeg extension: Add support for `x86_64` architecture.
* Opus extension: Fix parsing of negative gain values
([#7046](https://github.com/google/ExoPlayer/issues/7046)).
* Cast extension: Upgrade `play-services-cast-framework` dependency to 18.1.0.
This fixes an issue where `RemoteServiceException` was thrown due to
`Context.startForegroundService()` not calling `Service.startForeground()`
([#7191](https://github.com/google/ExoPlayer/issues/7191)).

### 2.11.3 (2020-02-19) ###

* SmoothStreaming: Fix regression that broke playback in 2.11.2
Expand Down
4 changes: 2 additions & 2 deletions constants.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// limitations under the License.
project.ext {
// ExoPlayer version and version code.
releaseVersion = '2.11.3'
releaseVersionCode = 2011003
releaseVersion = '2.11.4'
releaseVersionCode = 2011004
minSdkVersion = 16
appTargetSdkVersion = 29
targetSdkVersion = 28 // TODO: Bump once b/143232359 is resolved
Expand Down
4 changes: 2 additions & 2 deletions demos/cast/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ dependencies {
implementation project(modulePrefix + 'library-ui')
implementation project(modulePrefix + 'extension-cast')
implementation 'androidx.appcompat:appcompat:' + androidxAppCompatVersion
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
}

apply plugin: 'com.google.android.gms.strict-version-matcher-plugin'
1 change: 1 addition & 0 deletions demos/cast/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

<uses-sdk/>

Expand Down
1 change: 1 addition & 0 deletions demos/gl/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

<activity
android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
Expand Down
2 changes: 1 addition & 1 deletion demos/main/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ android {
dependencies {
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
implementation 'androidx.appcompat:appcompat:' + androidxAppCompatVersion
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.google.android.material:material:1.1.0'
implementation project(modulePrefix + 'library-core')
implementation project(modulePrefix + 'library-dash')
implementation project(modulePrefix + 'library-hls')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.demo.Sample.UriSample;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmSessionManager;
Expand Down Expand Up @@ -380,6 +381,7 @@ private void initializePlayer() {
.setTrackSelector(trackSelector)
.build();
player.addListener(new PlayerEventListener());
player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
player.setPlayWhenReady(startAutoPlay);
player.addAnalyticsListener(new EventLogger(trackSelector));
playerView.setPlayer(player);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.AsyncTask;
Expand All @@ -34,6 +35,7 @@
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.exoplayer2.ParserException;
Expand Down Expand Up @@ -63,6 +65,7 @@ public class SampleChooserActivity extends AppCompatActivity

private static final String TAG = "SampleChooserActivity";

private String[] uris;
private boolean useExtensionRenderers;
private DownloadTracker downloadTracker;
private SampleAdapter sampleAdapter;
Expand All @@ -81,7 +84,6 @@ public void onCreate(Bundle savedInstanceState) {

Intent intent = getIntent();
String dataUri = intent.getDataString();
String[] uris;
if (dataUri != null) {
uris = new String[] {dataUri};
} else {
Expand All @@ -105,8 +107,7 @@ public void onCreate(Bundle savedInstanceState) {
DemoApplication application = (DemoApplication) getApplication();
useExtensionRenderers = application.useExtensionRenderers();
downloadTracker = application.getDownloadTracker();
SampleListLoader loaderTask = new SampleListLoader();
loaderTask.execute(uris);
loadSample();

// Start the download service if it should be running but it's not currently.
// Starting the service in the foreground causes notification flicker if there is no scheduled
Expand Down Expand Up @@ -157,6 +158,37 @@ public void onDownloadsChanged() {
sampleAdapter.notifyDataSetChanged();
}

@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length == 0) {
// Empty results are triggered if a permission is requested while another request was already
// pending and can be safely ignored in this case.
return;
}
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
loadSample();
} else {
Toast.makeText(getApplicationContext(), R.string.sample_list_load_error, Toast.LENGTH_LONG)
.show();
finish();
}
}

private void loadSample() {
Assertions.checkNotNull(uris);

for (int i = 0; i < uris.length; i++) {
Uri uri = Uri.parse(uris[i]);
if (Util.maybeRequestReadExternalStoragePermission(this, uri)) {
return;
}
}

SampleListLoader loaderTask = new SampleListLoader();
loaderTask.execute(uris);
}

private void onSampleGroups(final List<SampleGroup> groups, boolean sawError) {
if (sawError) {
Toast.makeText(getApplicationContext(), R.string.sample_list_load_error, Toast.LENGTH_LONG)
Expand Down
96 changes: 60 additions & 36 deletions extensions/av1/src/main/jni/gav1_jni.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#endif // CPU_FEATURES_COMPILED_ANY_ARM_NEON
#include <jni.h>

#include <cstdint>
#include <cstring>
#include <mutex> // NOLINT
#include <new>
Expand Down Expand Up @@ -121,18 +122,22 @@ const char* GetJniErrorMessage(JniStatusCode error_code) {
}
}

// Manages Libgav1FrameBuffer and reference information.
// Manages frame buffer and reference information.
class JniFrameBuffer {
public:
explicit JniFrameBuffer(int id) : id_(id), reference_count_(0) {
gav1_frame_buffer_.private_data = &id_;
}
explicit JniFrameBuffer(int id) : id_(id), reference_count_(0) {}
~JniFrameBuffer() {
for (int plane_index = kPlaneY; plane_index < kMaxPlanes; plane_index++) {
delete[] gav1_frame_buffer_.data[plane_index];
delete[] raw_buffer_[plane_index];
}
}

// Not copyable or movable.
JniFrameBuffer(const JniFrameBuffer&) = delete;
JniFrameBuffer(JniFrameBuffer&&) = delete;
JniFrameBuffer& operator=(const JniFrameBuffer&) = delete;
JniFrameBuffer& operator=(JniFrameBuffer&&) = delete;

void SetFrameData(const libgav1::DecoderBuffer& decoder_buffer) {
for (int plane_index = kPlaneY; plane_index < decoder_buffer.NumPlanes();
plane_index++) {
Expand Down Expand Up @@ -160,9 +165,8 @@ class JniFrameBuffer {
void RemoveReference() { reference_count_--; }
bool InUse() const { return reference_count_ != 0; }

const Libgav1FrameBuffer& GetGav1FrameBuffer() const {
return gav1_frame_buffer_;
}
uint8_t* RawBuffer(int plane_index) const { return raw_buffer_[plane_index]; }
void* BufferPrivateData() const { return const_cast<int*>(&id_); }

// Attempts to reallocate data planes if the existing ones don't have enough
// capacity. Returns true if the allocation was successful or wasn't needed,
Expand All @@ -172,15 +176,14 @@ class JniFrameBuffer {
for (int plane_index = kPlaneY; plane_index < kMaxPlanes; plane_index++) {
const int min_size =
(plane_index == kPlaneY) ? y_plane_min_size : uv_plane_min_size;
if (gav1_frame_buffer_.size[plane_index] >= min_size) continue;
delete[] gav1_frame_buffer_.data[plane_index];
gav1_frame_buffer_.data[plane_index] =
new (std::nothrow) uint8_t[min_size];
if (!gav1_frame_buffer_.data[plane_index]) {
gav1_frame_buffer_.size[plane_index] = 0;
if (raw_buffer_size_[plane_index] >= min_size) continue;
delete[] raw_buffer_[plane_index];
raw_buffer_[plane_index] = new (std::nothrow) uint8_t[min_size];
if (!raw_buffer_[plane_index]) {
raw_buffer_size_[plane_index] = 0;
return false;
}
gav1_frame_buffer_.size[plane_index] = min_size;
raw_buffer_size_[plane_index] = min_size;
}
return true;
}
Expand All @@ -190,9 +193,12 @@ class JniFrameBuffer {
uint8_t* plane_[kMaxPlanes];
int displayed_width_[kMaxPlanes];
int displayed_height_[kMaxPlanes];
int id_;
const int id_;
int reference_count_;
Libgav1FrameBuffer gav1_frame_buffer_ = {};
// Pointers to the raw buffers allocated for the data planes.
uint8_t* raw_buffer_[kMaxPlanes] = {};
// Sizes of the raw buffers in bytes.
size_t raw_buffer_size_[kMaxPlanes] = {};
};

// Manages frame buffers used by libgav1 decoder and ExoPlayer.
Expand All @@ -210,7 +216,7 @@ class JniBufferManager {
}

JniStatusCode GetBuffer(size_t y_plane_min_size, size_t uv_plane_min_size,
Libgav1FrameBuffer* frame_buffer) {
JniFrameBuffer** jni_buffer) {
std::lock_guard<std::mutex> lock(mutex_);

JniFrameBuffer* output_buffer;
Expand All @@ -230,7 +236,7 @@ class JniBufferManager {
}

output_buffer->AddReference();
*frame_buffer = output_buffer->GetGav1FrameBuffer();
*jni_buffer = output_buffer;

return kJniStatusOk;
}
Expand Down Expand Up @@ -316,29 +322,46 @@ struct JniContext {
JniStatusCode jni_status_code = kJniStatusOk;
};

int Libgav1GetFrameBuffer(void* private_data, size_t y_plane_min_size,
size_t uv_plane_min_size,
Libgav1FrameBuffer* frame_buffer) {
JniContext* const context = reinterpret_cast<JniContext*>(private_data);
Libgav1StatusCode Libgav1GetFrameBuffer(void* callback_private_data,
int bitdepth,
libgav1::ImageFormat image_format,
int width, int height, int left_border,
int right_border, int top_border,
int bottom_border, int stride_alignment,
libgav1::FrameBuffer* frame_buffer) {
libgav1::FrameBufferInfo info;
Libgav1StatusCode status = libgav1::ComputeFrameBufferInfo(
bitdepth, image_format, width, height, left_border, right_border,
top_border, bottom_border, stride_alignment, &info);
if (status != kLibgav1StatusOk) return status;

JniContext* const context = static_cast<JniContext*>(callback_private_data);
JniFrameBuffer* jni_buffer;
context->jni_status_code = context->buffer_manager.GetBuffer(
y_plane_min_size, uv_plane_min_size, frame_buffer);
info.y_buffer_size, info.uv_buffer_size, &jni_buffer);
if (context->jni_status_code != kJniStatusOk) {
LOGE("%s", GetJniErrorMessage(context->jni_status_code));
return -1;
return kLibgav1StatusOutOfMemory;
}
return 0;

uint8_t* const y_buffer = jni_buffer->RawBuffer(0);
uint8_t* const u_buffer =
(info.uv_buffer_size != 0) ? jni_buffer->RawBuffer(1) : nullptr;
uint8_t* const v_buffer =
(info.uv_buffer_size != 0) ? jni_buffer->RawBuffer(2) : nullptr;

return libgav1::SetFrameBuffer(&info, y_buffer, u_buffer, v_buffer,
jni_buffer->BufferPrivateData(), frame_buffer);
}

int Libgav1ReleaseFrameBuffer(void* private_data,
Libgav1FrameBuffer* frame_buffer) {
JniContext* const context = reinterpret_cast<JniContext*>(private_data);
const int buffer_id = *reinterpret_cast<int*>(frame_buffer->private_data);
void Libgav1ReleaseFrameBuffer(void* callback_private_data,
void* buffer_private_data) {
JniContext* const context = static_cast<JniContext*>(callback_private_data);
const int buffer_id = *static_cast<const int*>(buffer_private_data);
context->jni_status_code = context->buffer_manager.ReleaseBuffer(buffer_id);
if (context->jni_status_code != kJniStatusOk) {
LOGE("%s", GetJniErrorMessage(context->jni_status_code));
return -1;
}
return 0;
}

constexpr int AlignTo16(int value) { return (value + 15) & (~15); }
Expand Down Expand Up @@ -508,8 +531,8 @@ DECODER_FUNC(jlong, gav1Init, jint threads) {

libgav1::DecoderSettings settings;
settings.threads = threads;
settings.get = Libgav1GetFrameBuffer;
settings.release = Libgav1ReleaseFrameBuffer;
settings.get_frame_buffer = Libgav1GetFrameBuffer;
settings.release_frame_buffer = Libgav1ReleaseFrameBuffer;
settings.callback_private_data = context;

context->libgav1_status_code = context->decoder.Init(&settings);
Expand Down Expand Up @@ -544,7 +567,8 @@ DECODER_FUNC(jint, gav1Decode, jlong jContext, jobject encodedData,
const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(
env->GetDirectBufferAddress(encodedData));
context->libgav1_status_code =
context->decoder.EnqueueFrame(buffer, length, /*user_private_data=*/0);
context->decoder.EnqueueFrame(buffer, length, /*user_private_data=*/0,
/*buffer_private_data=*/nullptr);
if (context->libgav1_status_code != kLibgav1StatusOk) {
return kStatusError;
}
Expand Down Expand Up @@ -619,7 +643,7 @@ DECODER_FUNC(jint, gav1GetFrame, jlong jContext, jobject jOutputBuffer,
}

const int buffer_id =
*reinterpret_cast<int*>(decoder_buffer->buffer_private_data);
*static_cast<const int*>(decoder_buffer->buffer_private_data);
context->buffer_manager.AddBufferReference(buffer_id);
JniFrameBuffer* const jni_buffer =
context->buffer_manager.GetBuffer(buffer_id);
Expand Down

0 comments on commit 7d3f54a

Please sign in to comment.