AwesomePlayer.cpp revision d1fa3ca0eee42ffd450d579b357f39163a716ee3
1e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter/* 2e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * Copyright (C) 2009 The Android Open Source Project 3e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * 4e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * Licensed under the Apache License, Version 2.0 (the "License"); 5e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * you may not use this file except in compliance with the License. 6e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * You may obtain a copy of the License at 7e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * 8e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * http://www.apache.org/licenses/LICENSE-2.0 9e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * 10e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * Unless required by applicable law or agreed to in writing, software 11e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * distributed under the License is distributed on an "AS IS" BASIS, 12e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * See the License for the specific language governing permissions and 14e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter * limitations under the License. 15e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter */ 16e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 174bb8118816874c696d9f1adab48490df1da365f7Eino-Ville Talvala#undef DEBUG_HDCP 184bb8118816874c696d9f1adab48490df1da365f7Eino-Ville Talvala 19e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter//#define LOG_NDEBUG 0 20e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#define LOG_TAG "AwesomePlayer" 21e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <utils/Log.h> 22e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 23e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <dlfcn.h> 24e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 25e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "include/AwesomePlayer.h" 26e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "include/DRMExtractor.h" 27e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "include/SoftwareRenderer.h" 28e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "include/NuCachedSource2.h" 29e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "include/ThrottledSource.h" 30e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "include/MPEG2TSExtractor.h" 31e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "include/WVMExtractor.h" 32e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 33e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include "timedtext/TimedTextPlayer.h" 34e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 35e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <binder/IPCThreadState.h> 36e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <binder/IServiceManager.h> 37e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/IMediaPlayerService.h> 38e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/foundation/hexdump.h> 39e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/foundation/ADebug.h> 40e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/AudioPlayer.h> 41e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/DataSource.h> 42e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/FileSource.h> 43e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/MediaBuffer.h> 44e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/MediaDefs.h> 45e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/MediaExtractor.h> 46e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/MediaSource.h> 47e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/MetaData.h> 48e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/OMXCodec.h> 49e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 50e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <surfaceflinger/Surface.h> 51e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <gui/ISurfaceTexture.h> 52e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <gui/SurfaceTextureClient.h> 53e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <surfaceflinger/ISurfaceComposer.h> 54e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 55e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <media/stagefright/foundation/AMessage.h> 56e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 57e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#include <cutils/properties.h> 58e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 59e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#define USE_SURFACE_ALLOC 1 60e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter#define FRAME_DROP_FREQ 0 61e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 62e538206d15282afbc5b168d60b1026a5dfcd13c0James Painternamespace android { 63e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 64e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterstatic int64_t kLowWaterMarkUs = 2000000ll; // 2secs 65e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterstatic int64_t kHighWaterMarkUs = 5000000ll; // 5secs 66e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterstatic const size_t kLowWaterMarkBytes = 40000; 67e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterstatic const size_t kHighWaterMarkBytes = 200000; 68e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 69e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterstruct AwesomeEvent : public TimedEventQueue::Event { 70e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeEvent( 71e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomePlayer *player, 72e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter void (AwesomePlayer::*method)()) 73e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter : mPlayer(player), 74e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mMethod(method) { 75e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 76e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 77e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterprotected: 78e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter virtual ~AwesomeEvent() {} 79e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 80e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { 81e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter (mPlayer->*mMethod)(); 82e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 83e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 84e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterprivate: 85e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomePlayer *mPlayer; 86e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter void (AwesomePlayer::*mMethod)(); 87e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 88e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeEvent(const AwesomeEvent &); 89e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeEvent &operator=(const AwesomeEvent &); 90e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter}; 91e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 92e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterstruct AwesomeLocalRenderer : public AwesomeRenderer { 93e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeLocalRenderer( 94e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta) 95e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter : mTarget(new SoftwareRenderer(nativeWindow, meta)) { 96e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 97e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 98e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter virtual void render(MediaBuffer *buffer) { 99e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter render((const uint8_t *)buffer->data() + buffer->range_offset(), 100e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter buffer->range_length()); 101e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 102e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 103e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter void render(const void *data, size_t size) { 104e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mTarget->render(data, size, NULL); 105e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 106e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 107e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterprotected: 108e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter virtual ~AwesomeLocalRenderer() { 109e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter delete mTarget; 110e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mTarget = NULL; 111e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 112e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 113e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterprivate: 114e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter SoftwareRenderer *mTarget; 115e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 116e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeLocalRenderer(const AwesomeLocalRenderer &); 117e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);; 118e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter}; 119e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 120e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterstruct AwesomeNativeWindowRenderer : public AwesomeRenderer { 121e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeNativeWindowRenderer( 122e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter const sp<ANativeWindow> &nativeWindow, 123e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter int32_t rotationDegrees) 124e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter : mNativeWindow(nativeWindow) { 125e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter applyRotation(rotationDegrees); 126e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 127e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 128e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter virtual void render(MediaBuffer *buffer) { 129e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter int64_t timeUs; 130e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 131e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000); 132e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter status_t err = mNativeWindow->queueBuffer( 133e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mNativeWindow.get(), buffer->graphicBuffer().get()); 134e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter if (err != 0) { 135e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter LOGE("queueBuffer failed with error %s (%d)", strerror(-err), 136e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter -err); 137e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter return; 138e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 139e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 140e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter sp<MetaData> metaData = buffer->meta_data(); 141e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter metaData->setInt32(kKeyRendered, 1); 142e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 143e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 144e538206d15282afbc5b168d60b1026a5dfcd13c0James Painterprotected: 145e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter virtual ~AwesomeNativeWindowRenderer() {} 146e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 147ddf3c5025e2f6f35a4c188c19f30142c64a092c4Igor Murashkinprivate: 148e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter sp<ANativeWindow> mNativeWindow; 149e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 150e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter void applyRotation(int32_t rotationDegrees) { 151e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter uint32_t transform; 152e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter switch (rotationDegrees) { 153e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter case 0: transform = 0; break; 154e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter case 90: transform = HAL_TRANSFORM_ROT_90; break; 155e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter case 180: transform = HAL_TRANSFORM_ROT_180; break; 156e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter case 270: transform = HAL_TRANSFORM_ROT_270; break; 157e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter default: transform = 0; break; 158e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 159e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 160e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter if (transform) { 161e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter CHECK_EQ(0, native_window_set_buffers_transform( 162e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mNativeWindow.get(), transform)); 163e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 164e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 165e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 166e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &); 167e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter AwesomeNativeWindowRenderer &operator=( 168e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter const AwesomeNativeWindowRenderer &); 169e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter}; 170e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 171e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter// To collect the decoder usage 172e538206d15282afbc5b168d60b1026a5dfcd13c0James Paintervoid addBatteryData(uint32_t params) { 173e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter sp<IBinder> binder = 174e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter defaultServiceManager()->getService(String16("media.player")); 175e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 176e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter CHECK(service.get() != NULL); 177e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 178e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter service->addBatteryData(params); 179e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter} 180e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 181e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter//////////////////////////////////////////////////////////////////////////////// 182e538206d15282afbc5b168d60b1026a5dfcd13c0James PainterAwesomePlayer::AwesomePlayer() 183e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter : mQueueStarted(false), 184e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mUIDValid(false), 185e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mTimeSource(NULL), 186e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mVideoRendererIsPreview(false), 187e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mAudioPlayer(NULL), 188e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mDisplayWidth(0), 189e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mDisplayHeight(0), 190e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mFlags(0), 191e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mExtractorFlags(0), 192e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mVideoBuffer(NULL), 193e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mDecryptHandle(NULL), 194e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mLastVideoTimeUs(-1), 195e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mTextPlayer(NULL) { 196e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter CHECK_EQ(mClient.connect(), (status_t)OK); 197e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 198e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter DataSource::RegisterDefaultSniffers(); 199e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 200e5729fac81c8a984e984fefc90afc64135817d4fColin Cross mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); 201e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mVideoEventPending = false; 202e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone); 203e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mStreamDoneEventPending = false; 204e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate); 205e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mBufferingEventPending = false; 206ddf3c5025e2f6f35a4c188c19f30142c64a092c4Igor Murashkin mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); 207e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mVideoEventPending = false; 208e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 209e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mCheckAudioStatusEvent = new AwesomeEvent( 210e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter this, &AwesomePlayer::onCheckAudioStatus); 211e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 212e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mAudioStatusEventPending = false; 213608cff22d70a0eabb7e01ef39f13b4d6db5ba48aAlex Ray 214608cff22d70a0eabb7e01ef39f13b4d6db5ba48aAlex Ray reset(); 215e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter} 216e5729fac81c8a984e984fefc90afc64135817d4fColin Cross 217e538206d15282afbc5b168d60b1026a5dfcd13c0James PainterAwesomePlayer::~AwesomePlayer() { 218e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter if (mQueueStarted) { 219e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter mQueue.stop(); 220e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter } 221e538206d15282afbc5b168d60b1026a5dfcd13c0James Painter 222 reset(); 223 224 mClient.disconnect(); 225} 226 227void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) { 228 mQueue.cancelEvent(mVideoEvent->eventID()); 229 mVideoEventPending = false; 230 mQueue.cancelEvent(mVideoLagEvent->eventID()); 231 mVideoLagEventPending = false; 232 233 if (!keepNotifications) { 234 mQueue.cancelEvent(mStreamDoneEvent->eventID()); 235 mStreamDoneEventPending = false; 236 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID()); 237 mAudioStatusEventPending = false; 238 239 mQueue.cancelEvent(mBufferingEvent->eventID()); 240 mBufferingEventPending = false; 241 } 242} 243 244void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) { 245 Mutex::Autolock autoLock(mLock); 246 mListener = listener; 247} 248 249void AwesomePlayer::setUID(uid_t uid) { 250 LOGV("AwesomePlayer running on behalf of uid %d", uid); 251 252 mUID = uid; 253 mUIDValid = true; 254} 255 256status_t AwesomePlayer::setDataSource( 257 const char *uri, const KeyedVector<String8, String8> *headers) { 258 Mutex::Autolock autoLock(mLock); 259 return setDataSource_l(uri, headers); 260} 261 262status_t AwesomePlayer::setDataSource_l( 263 const char *uri, const KeyedVector<String8, String8> *headers) { 264 reset_l(); 265 266 mUri = uri; 267 268 if (headers) { 269 mUriHeaders = *headers; 270 271 ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log")); 272 if (index >= 0) { 273 // Browser is in "incognito" mode, suppress logging URLs. 274 275 // This isn't something that should be passed to the server. 276 mUriHeaders.removeItemsAt(index); 277 278 modifyFlags(INCOGNITO, SET); 279 } 280 } 281 282 if (!(mFlags & INCOGNITO)) { 283 LOGI("setDataSource_l('%s')", mUri.string()); 284 } else { 285 LOGI("setDataSource_l(URL suppressed)"); 286 } 287 288 // The actual work will be done during preparation in the call to 289 // ::finishSetDataSource_l to avoid blocking the calling thread in 290 // setDataSource for any significant time. 291 292 { 293 Mutex::Autolock autoLock(mStatsLock); 294 mStats.mFd = -1; 295 mStats.mURI = mUri; 296 } 297 298 return OK; 299} 300 301status_t AwesomePlayer::setDataSource( 302 int fd, int64_t offset, int64_t length) { 303 Mutex::Autolock autoLock(mLock); 304 305 reset_l(); 306 307 sp<DataSource> dataSource = new FileSource(fd, offset, length); 308 309 status_t err = dataSource->initCheck(); 310 311 if (err != OK) { 312 return err; 313 } 314 315 mFileSource = dataSource; 316 317 { 318 Mutex::Autolock autoLock(mStatsLock); 319 mStats.mFd = fd; 320 mStats.mURI = String8(); 321 } 322 323 return setDataSource_l(dataSource); 324} 325 326status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) { 327 return INVALID_OPERATION; 328} 329 330status_t AwesomePlayer::setDataSource_l( 331 const sp<DataSource> &dataSource) { 332 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 333 334 if (extractor == NULL) { 335 return UNKNOWN_ERROR; 336 } 337 338 if (extractor->getDrmFlag()) { 339 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 340 if (mDecryptHandle != NULL) { 341 CHECK(mDrmManagerClient); 342 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 343 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 344 } 345 } 346 } 347 348 return setDataSource_l(extractor); 349} 350 351status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { 352 // Attempt to approximate overall stream bitrate by summing all 353 // tracks' individual bitrates, if not all of them advertise bitrate, 354 // we have to fail. 355 356 int64_t totalBitRate = 0; 357 358 for (size_t i = 0; i < extractor->countTracks(); ++i) { 359 sp<MetaData> meta = extractor->getTrackMetaData(i); 360 361 int32_t bitrate; 362 if (!meta->findInt32(kKeyBitRate, &bitrate)) { 363 const char *mime; 364 CHECK(meta->findCString(kKeyMIMEType, &mime)); 365 LOGV("track of type '%s' does not publish bitrate", mime); 366 367 totalBitRate = -1; 368 break; 369 } 370 371 totalBitRate += bitrate; 372 } 373 374 mBitrate = totalBitRate; 375 376 LOGV("mBitrate = %lld bits/sec", mBitrate); 377 378 { 379 Mutex::Autolock autoLock(mStatsLock); 380 mStats.mBitrate = mBitrate; 381 mStats.mTracks.clear(); 382 mStats.mAudioTrackIndex = -1; 383 mStats.mVideoTrackIndex = -1; 384 } 385 386 bool haveAudio = false; 387 bool haveVideo = false; 388 for (size_t i = 0; i < extractor->countTracks(); ++i) { 389 sp<MetaData> meta = extractor->getTrackMetaData(i); 390 391 const char *_mime; 392 CHECK(meta->findCString(kKeyMIMEType, &_mime)); 393 394 String8 mime = String8(_mime); 395 396 if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) { 397 setVideoSource(extractor->getTrack(i)); 398 haveVideo = true; 399 400 // Set the presentation/display size 401 int32_t displayWidth, displayHeight; 402 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth); 403 if (success) { 404 success = meta->findInt32(kKeyDisplayHeight, &displayHeight); 405 } 406 if (success) { 407 mDisplayWidth = displayWidth; 408 mDisplayHeight = displayHeight; 409 } 410 411 { 412 Mutex::Autolock autoLock(mStatsLock); 413 mStats.mVideoTrackIndex = mStats.mTracks.size(); 414 mStats.mTracks.push(); 415 TrackStat *stat = 416 &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 417 stat->mMIME = mime.string(); 418 } 419 } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) { 420 setAudioSource(extractor->getTrack(i)); 421 haveAudio = true; 422 423 { 424 Mutex::Autolock autoLock(mStatsLock); 425 mStats.mAudioTrackIndex = mStats.mTracks.size(); 426 mStats.mTracks.push(); 427 TrackStat *stat = 428 &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 429 stat->mMIME = mime.string(); 430 } 431 432 if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) { 433 // Only do this for vorbis audio, none of the other audio 434 // formats even support this ringtone specific hack and 435 // retrieving the metadata on some extractors may turn out 436 // to be very expensive. 437 sp<MetaData> fileMeta = extractor->getMetaData(); 438 int32_t loop; 439 if (fileMeta != NULL 440 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 441 modifyFlags(AUTO_LOOPING, SET); 442 } 443 } 444 } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { 445 addTextSource(extractor->getTrack(i)); 446 } 447 } 448 449 if (!haveAudio && !haveVideo) { 450 return UNKNOWN_ERROR; 451 } 452 453 mExtractorFlags = extractor->flags(); 454 455 return OK; 456} 457 458void AwesomePlayer::reset() { 459 Mutex::Autolock autoLock(mLock); 460 reset_l(); 461} 462 463void AwesomePlayer::reset_l() { 464 mDisplayWidth = 0; 465 mDisplayHeight = 0; 466 467 if (mDecryptHandle != NULL) { 468 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 469 Playback::STOP, 0); 470 mDecryptHandle = NULL; 471 mDrmManagerClient = NULL; 472 } 473 474 if (mFlags & PLAYING) { 475 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 476 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 477 params |= IMediaPlayerService::kBatteryDataTrackAudio; 478 } 479 if (mVideoSource != NULL) { 480 params |= IMediaPlayerService::kBatteryDataTrackVideo; 481 } 482 addBatteryData(params); 483 } 484 485 if (mFlags & PREPARING) { 486 modifyFlags(PREPARE_CANCELLED, SET); 487 if (mConnectingDataSource != NULL) { 488 LOGI("interrupting the connection process"); 489 mConnectingDataSource->disconnect(); 490 } 491 492 if (mFlags & PREPARING_CONNECTED) { 493 // We are basically done preparing, we're just buffering 494 // enough data to start playback, we can safely interrupt that. 495 finishAsyncPrepare_l(); 496 } 497 } 498 499 while (mFlags & PREPARING) { 500 mPreparedCondition.wait(mLock); 501 } 502 503 cancelPlayerEvents(); 504 505 mWVMExtractor.clear(); 506 mCachedSource.clear(); 507 mAudioTrack.clear(); 508 mVideoTrack.clear(); 509 510 // Shutdown audio first, so that the respone to the reset request 511 // appears to happen instantaneously as far as the user is concerned 512 // If we did this later, audio would continue playing while we 513 // shutdown the video-related resources and the player appear to 514 // not be as responsive to a reset request. 515 if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED)) 516 && mAudioSource != NULL) { 517 // If we had an audio player, it would have effectively 518 // taken possession of the audio source and stopped it when 519 // _it_ is stopped. Otherwise this is still our responsibility. 520 mAudioSource->stop(); 521 } 522 mAudioSource.clear(); 523 524 mTimeSource = NULL; 525 526 delete mAudioPlayer; 527 mAudioPlayer = NULL; 528 529 if (mTextPlayer != NULL) { 530 delete mTextPlayer; 531 mTextPlayer = NULL; 532 } 533 534 mVideoRenderer.clear(); 535 536 if (mVideoSource != NULL) { 537 shutdownVideoDecoder_l(); 538 } 539 540 mDurationUs = -1; 541 modifyFlags(0, ASSIGN); 542 mExtractorFlags = 0; 543 mTimeSourceDeltaUs = 0; 544 mVideoTimeUs = 0; 545 546 mSeeking = NO_SEEK; 547 mSeekNotificationSent = true; 548 mSeekTimeUs = 0; 549 550 mUri.setTo(""); 551 mUriHeaders.clear(); 552 553 mFileSource.clear(); 554 555 mBitrate = -1; 556 mLastVideoTimeUs = -1; 557 558 { 559 Mutex::Autolock autoLock(mStatsLock); 560 mStats.mFd = -1; 561 mStats.mURI = String8(); 562 mStats.mBitrate = -1; 563 mStats.mAudioTrackIndex = -1; 564 mStats.mVideoTrackIndex = -1; 565 mStats.mNumVideoFramesDecoded = 0; 566 mStats.mNumVideoFramesDropped = 0; 567 mStats.mVideoWidth = -1; 568 mStats.mVideoHeight = -1; 569 mStats.mFlags = 0; 570 mStats.mTracks.clear(); 571 } 572 573 mWatchForAudioSeekComplete = false; 574 mWatchForAudioEOS = false; 575} 576 577void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { 578 if (mListener != NULL) { 579 sp<MediaPlayerBase> listener = mListener.promote(); 580 581 if (listener != NULL) { 582 listener->sendEvent(msg, ext1, ext2); 583 } 584 } 585} 586 587bool AwesomePlayer::getBitrate(int64_t *bitrate) { 588 off64_t size; 589 if (mDurationUs >= 0 && mCachedSource != NULL 590 && mCachedSource->getSize(&size) == OK) { 591 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec 592 return true; 593 } 594 595 if (mBitrate >= 0) { 596 *bitrate = mBitrate; 597 return true; 598 } 599 600 *bitrate = 0; 601 602 return false; 603} 604 605// Returns true iff cached duration is available/applicable. 606bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { 607 int64_t bitrate; 608 609 if (mCachedSource != NULL && getBitrate(&bitrate)) { 610 status_t finalStatus; 611 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 612 *durationUs = cachedDataRemaining * 8000000ll / bitrate; 613 *eos = (finalStatus != OK); 614 return true; 615 } else if (mWVMExtractor != NULL) { 616 status_t finalStatus; 617 *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); 618 *eos = (finalStatus != OK); 619 return true; 620 } 621 622 return false; 623} 624 625void AwesomePlayer::ensureCacheIsFetching_l() { 626 if (mCachedSource != NULL) { 627 mCachedSource->resumeFetchingIfNecessary(); 628 } 629} 630 631void AwesomePlayer::onVideoLagUpdate() { 632 Mutex::Autolock autoLock(mLock); 633 if (!mVideoLagEventPending) { 634 return; 635 } 636 mVideoLagEventPending = false; 637 638 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs(); 639 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs; 640 641 if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) { 642 LOGV("video late by %lld ms.", videoLateByUs / 1000ll); 643 644 notifyListener_l( 645 MEDIA_INFO, 646 MEDIA_INFO_VIDEO_TRACK_LAGGING, 647 videoLateByUs / 1000ll); 648 } 649 650 postVideoLagEvent_l(); 651} 652 653void AwesomePlayer::onBufferingUpdate() { 654 Mutex::Autolock autoLock(mLock); 655 if (!mBufferingEventPending) { 656 return; 657 } 658 mBufferingEventPending = false; 659 660 if (mCachedSource != NULL) { 661 status_t finalStatus; 662 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 663 bool eos = (finalStatus != OK); 664 665 if (eos) { 666 if (finalStatus == ERROR_END_OF_STREAM) { 667 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 668 } 669 if (mFlags & PREPARING) { 670 LOGV("cache has reached EOS, prepare is done."); 671 finishAsyncPrepare_l(); 672 } 673 } else { 674 int64_t bitrate; 675 if (getBitrate(&bitrate)) { 676 size_t cachedSize = mCachedSource->cachedSize(); 677 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; 678 679 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 680 if (percentage > 100) { 681 percentage = 100; 682 } 683 684 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 685 } else { 686 // We don't know the bitrate of the stream, use absolute size 687 // limits to maintain the cache. 688 689 if ((mFlags & PLAYING) && !eos 690 && (cachedDataRemaining < kLowWaterMarkBytes)) { 691 LOGI("cache is running low (< %d) , pausing.", 692 kLowWaterMarkBytes); 693 modifyFlags(CACHE_UNDERRUN, SET); 694 pause_l(); 695 ensureCacheIsFetching_l(); 696 sendCacheStats(); 697 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 698 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { 699 if (mFlags & CACHE_UNDERRUN) { 700 LOGI("cache has filled up (> %d), resuming.", 701 kHighWaterMarkBytes); 702 modifyFlags(CACHE_UNDERRUN, CLEAR); 703 play_l(); 704 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 705 } else if (mFlags & PREPARING) { 706 LOGV("cache has filled up (> %d), prepare is done", 707 kHighWaterMarkBytes); 708 finishAsyncPrepare_l(); 709 } 710 } 711 } 712 } 713 } else if (mWVMExtractor != NULL) { 714 status_t finalStatus; 715 716 int64_t cachedDurationUs 717 = mWVMExtractor->getCachedDurationUs(&finalStatus); 718 719 bool eos = (finalStatus != OK); 720 721 if (eos) { 722 if (finalStatus == ERROR_END_OF_STREAM) { 723 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 724 } 725 if (mFlags & PREPARING) { 726 LOGV("cache has reached EOS, prepare is done."); 727 finishAsyncPrepare_l(); 728 } 729 } else { 730 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 731 if (percentage > 100) { 732 percentage = 100; 733 } 734 735 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 736 } 737 } 738 739 int64_t cachedDurationUs; 740 bool eos; 741 if (getCachedDuration_l(&cachedDurationUs, &eos)) { 742 LOGV("cachedDurationUs = %.2f secs, eos=%d", 743 cachedDurationUs / 1E6, eos); 744 745 if ((mFlags & PLAYING) && !eos 746 && (cachedDurationUs < kLowWaterMarkUs)) { 747 LOGI("cache is running low (%.2f secs) , pausing.", 748 cachedDurationUs / 1E6); 749 modifyFlags(CACHE_UNDERRUN, SET); 750 pause_l(); 751 ensureCacheIsFetching_l(); 752 sendCacheStats(); 753 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 754 } else if (eos || cachedDurationUs > kHighWaterMarkUs) { 755 if (mFlags & CACHE_UNDERRUN) { 756 LOGI("cache has filled up (%.2f secs), resuming.", 757 cachedDurationUs / 1E6); 758 modifyFlags(CACHE_UNDERRUN, CLEAR); 759 play_l(); 760 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 761 } else if (mFlags & PREPARING) { 762 LOGV("cache has filled up (%.2f secs), prepare is done", 763 cachedDurationUs / 1E6); 764 finishAsyncPrepare_l(); 765 } 766 } 767 } 768 769 postBufferingEvent_l(); 770} 771 772void AwesomePlayer::sendCacheStats() { 773 sp<MediaPlayerBase> listener = mListener.promote(); 774 if (listener != NULL && mCachedSource != NULL) { 775 int32_t kbps = 0; 776 status_t err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 777 if (err == OK) { 778 listener->sendEvent( 779 MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps); 780 } 781 } 782} 783 784void AwesomePlayer::onStreamDone() { 785 // Posted whenever any stream finishes playing. 786 787 Mutex::Autolock autoLock(mLock); 788 if (!mStreamDoneEventPending) { 789 return; 790 } 791 mStreamDoneEventPending = false; 792 793 if (mStreamDoneStatus != ERROR_END_OF_STREAM) { 794 LOGV("MEDIA_ERROR %d", mStreamDoneStatus); 795 796 notifyListener_l( 797 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus); 798 799 pause_l(true /* at eos */); 800 801 modifyFlags(AT_EOS, SET); 802 return; 803 } 804 805 const bool allDone = 806 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS)) 807 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS)); 808 809 if (!allDone) { 810 return; 811 } 812 813 if ((mFlags & LOOPING) 814 || ((mFlags & AUTO_LOOPING) 815 && (mAudioSink == NULL || mAudioSink->realtime()))) { 816 // Don't AUTO_LOOP if we're being recorded, since that cannot be 817 // turned off and recording would go on indefinitely. 818 819 seekTo_l(0); 820 821 if (mVideoSource != NULL) { 822 postVideoEvent_l(); 823 } 824 } else { 825 LOGV("MEDIA_PLAYBACK_COMPLETE"); 826 notifyListener_l(MEDIA_PLAYBACK_COMPLETE); 827 828 pause_l(true /* at eos */); 829 830 modifyFlags(AT_EOS, SET); 831 } 832} 833 834status_t AwesomePlayer::play() { 835 Mutex::Autolock autoLock(mLock); 836 837 modifyFlags(CACHE_UNDERRUN, CLEAR); 838 839 return play_l(); 840} 841 842status_t AwesomePlayer::play_l() { 843 modifyFlags(SEEK_PREVIEW, CLEAR); 844 845 if (mFlags & PLAYING) { 846 return OK; 847 } 848 849 if (!(mFlags & PREPARED)) { 850 status_t err = prepare_l(); 851 852 if (err != OK) { 853 return err; 854 } 855 } 856 857 modifyFlags(PLAYING, SET); 858 modifyFlags(FIRST_FRAME, SET); 859 860 if (mDecryptHandle != NULL) { 861 int64_t position; 862 getPosition(&position); 863 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 864 Playback::START, position / 1000); 865 } 866 867 if (mAudioSource != NULL) { 868 if (mAudioPlayer == NULL) { 869 if (mAudioSink != NULL) { 870 mAudioPlayer = new AudioPlayer(mAudioSink, this); 871 mAudioPlayer->setSource(mAudioSource); 872 873 mTimeSource = mAudioPlayer; 874 875 // If there was a seek request before we ever started, 876 // honor the request now. 877 // Make sure to do this before starting the audio player 878 // to avoid a race condition. 879 seekAudioIfNecessary_l(); 880 } 881 } 882 883 CHECK(!(mFlags & AUDIO_RUNNING)); 884 885 if (mVideoSource == NULL) { 886 // We don't want to post an error notification at this point, 887 // the error returned from MediaPlayer::start() will suffice. 888 889 status_t err = startAudioPlayer_l( 890 false /* sendErrorNotification */); 891 892 if (err != OK) { 893 delete mAudioPlayer; 894 mAudioPlayer = NULL; 895 896 modifyFlags((PLAYING | FIRST_FRAME), CLEAR); 897 898 if (mDecryptHandle != NULL) { 899 mDrmManagerClient->setPlaybackStatus( 900 mDecryptHandle, Playback::STOP, 0); 901 } 902 903 return err; 904 } 905 } 906 } 907 908 if (mTimeSource == NULL && mAudioPlayer == NULL) { 909 mTimeSource = &mSystemTimeSource; 910 } 911 912 if (mVideoSource != NULL) { 913 // Kick off video playback 914 postVideoEvent_l(); 915 916 if (mAudioSource != NULL && mVideoSource != NULL) { 917 postVideoLagEvent_l(); 918 } 919 } 920 921 if (mFlags & AT_EOS) { 922 // Legacy behaviour, if a stream finishes playing and then 923 // is started again, we play from the start... 924 seekTo_l(0); 925 } 926 927 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted 928 | IMediaPlayerService::kBatteryDataTrackDecoder; 929 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 930 params |= IMediaPlayerService::kBatteryDataTrackAudio; 931 } 932 if (mVideoSource != NULL) { 933 params |= IMediaPlayerService::kBatteryDataTrackVideo; 934 } 935 addBatteryData(params); 936 937 return OK; 938} 939 940status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) { 941 CHECK(!(mFlags & AUDIO_RUNNING)); 942 943 if (mAudioSource == NULL || mAudioPlayer == NULL) { 944 return OK; 945 } 946 947 if (!(mFlags & AUDIOPLAYER_STARTED)) { 948 modifyFlags(AUDIOPLAYER_STARTED, SET); 949 950 bool wasSeeking = mAudioPlayer->isSeeking(); 951 952 // We've already started the MediaSource in order to enable 953 // the prefetcher to read its data. 954 status_t err = mAudioPlayer->start( 955 true /* sourceAlreadyStarted */); 956 957 if (err != OK) { 958 if (sendErrorNotification) { 959 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 960 } 961 962 return err; 963 } 964 965 if (wasSeeking) { 966 CHECK(!mAudioPlayer->isSeeking()); 967 968 // We will have finished the seek while starting the audio player. 969 postAudioSeekComplete(); 970 } 971 } else { 972 mAudioPlayer->resume(); 973 } 974 975 modifyFlags(AUDIO_RUNNING, SET); 976 977 mWatchForAudioEOS = true; 978 979 return OK; 980} 981 982void AwesomePlayer::notifyVideoSize_l() { 983 sp<MetaData> meta = mVideoSource->getFormat(); 984 985 int32_t cropLeft, cropTop, cropRight, cropBottom; 986 if (!meta->findRect( 987 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) { 988 int32_t width, height; 989 CHECK(meta->findInt32(kKeyWidth, &width)); 990 CHECK(meta->findInt32(kKeyHeight, &height)); 991 992 cropLeft = cropTop = 0; 993 cropRight = width - 1; 994 cropBottom = height - 1; 995 996 LOGV("got dimensions only %d x %d", width, height); 997 } else { 998 LOGV("got crop rect %d, %d, %d, %d", 999 cropLeft, cropTop, cropRight, cropBottom); 1000 } 1001 1002 int32_t displayWidth; 1003 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) { 1004 LOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth); 1005 mDisplayWidth = displayWidth; 1006 } 1007 int32_t displayHeight; 1008 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) { 1009 LOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight); 1010 mDisplayHeight = displayHeight; 1011 } 1012 1013 int32_t usableWidth = cropRight - cropLeft + 1; 1014 int32_t usableHeight = cropBottom - cropTop + 1; 1015 if (mDisplayWidth != 0) { 1016 usableWidth = mDisplayWidth; 1017 } 1018 if (mDisplayHeight != 0) { 1019 usableHeight = mDisplayHeight; 1020 } 1021 1022 { 1023 Mutex::Autolock autoLock(mStatsLock); 1024 mStats.mVideoWidth = usableWidth; 1025 mStats.mVideoHeight = usableHeight; 1026 } 1027 1028 int32_t rotationDegrees; 1029 if (!mVideoTrack->getFormat()->findInt32( 1030 kKeyRotation, &rotationDegrees)) { 1031 rotationDegrees = 0; 1032 } 1033 1034 if (rotationDegrees == 90 || rotationDegrees == 270) { 1035 notifyListener_l( 1036 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth); 1037 } else { 1038 notifyListener_l( 1039 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight); 1040 } 1041} 1042 1043void AwesomePlayer::initRenderer_l() { 1044 if (mNativeWindow == NULL) { 1045 return; 1046 } 1047 1048 sp<MetaData> meta = mVideoSource->getFormat(); 1049 1050 int32_t format; 1051 const char *component; 1052 int32_t decodedWidth, decodedHeight; 1053 CHECK(meta->findInt32(kKeyColorFormat, &format)); 1054 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 1055 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 1056 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 1057 1058 int32_t rotationDegrees; 1059 if (!mVideoTrack->getFormat()->findInt32( 1060 kKeyRotation, &rotationDegrees)) { 1061 rotationDegrees = 0; 1062 } 1063 1064 mVideoRenderer.clear(); 1065 1066 // Must ensure that mVideoRenderer's destructor is actually executed 1067 // before creating a new one. 1068 IPCThreadState::self()->flushCommands(); 1069 1070 if (USE_SURFACE_ALLOC 1071 && !strncmp(component, "OMX.", 4) 1072 && strncmp(component, "OMX.google.", 11) 1073 && strcmp(component, "OMX.Nvidia.mpeg2v.decode")) { 1074 // Hardware decoders avoid the CPU color conversion by decoding 1075 // directly to ANativeBuffers, so we must use a renderer that 1076 // just pushes those buffers to the ANativeWindow. 1077 mVideoRenderer = 1078 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees); 1079 } else { 1080 // Other decoders are instantiated locally and as a consequence 1081 // allocate their buffers in local address space. This renderer 1082 // then performs a color conversion and copy to get the data 1083 // into the ANativeBuffer. 1084 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta); 1085 } 1086} 1087 1088status_t AwesomePlayer::pause() { 1089 Mutex::Autolock autoLock(mLock); 1090 1091 modifyFlags(CACHE_UNDERRUN, CLEAR); 1092 1093 return pause_l(); 1094} 1095 1096status_t AwesomePlayer::pause_l(bool at_eos) { 1097 if (!(mFlags & PLAYING)) { 1098 return OK; 1099 } 1100 1101 cancelPlayerEvents(true /* keepNotifications */); 1102 1103 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1104 if (at_eos) { 1105 // If we played the audio stream to completion we 1106 // want to make sure that all samples remaining in the audio 1107 // track's queue are played out. 1108 mAudioPlayer->pause(true /* playPendingSamples */); 1109 } else { 1110 mAudioPlayer->pause(); 1111 } 1112 1113 modifyFlags(AUDIO_RUNNING, CLEAR); 1114 } 1115 1116 if (mFlags & TEXTPLAYER_STARTED) { 1117 mTextPlayer->pause(); 1118 modifyFlags(TEXT_RUNNING, CLEAR); 1119 } 1120 1121 modifyFlags(PLAYING, CLEAR); 1122 1123 if (mDecryptHandle != NULL) { 1124 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1125 Playback::PAUSE, 0); 1126 } 1127 1128 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 1129 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1130 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1131 } 1132 if (mVideoSource != NULL) { 1133 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1134 } 1135 1136 addBatteryData(params); 1137 1138 return OK; 1139} 1140 1141bool AwesomePlayer::isPlaying() const { 1142 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN); 1143} 1144 1145status_t AwesomePlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 1146 Mutex::Autolock autoLock(mLock); 1147 1148 status_t err; 1149 if (surfaceTexture != NULL) { 1150 err = setNativeWindow_l(new SurfaceTextureClient(surfaceTexture)); 1151 } else { 1152 err = setNativeWindow_l(NULL); 1153 } 1154 1155 return err; 1156} 1157 1158void AwesomePlayer::shutdownVideoDecoder_l() { 1159 if (mVideoBuffer) { 1160 mVideoBuffer->release(); 1161 mVideoBuffer = NULL; 1162 } 1163 1164 mVideoSource->stop(); 1165 1166 // The following hack is necessary to ensure that the OMX 1167 // component is completely released by the time we may try 1168 // to instantiate it again. 1169 wp<MediaSource> tmp = mVideoSource; 1170 mVideoSource.clear(); 1171 while (tmp.promote() != NULL) { 1172 usleep(1000); 1173 } 1174 IPCThreadState::self()->flushCommands(); 1175 LOGV("video decoder shutdown completed"); 1176} 1177 1178status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) { 1179 mNativeWindow = native; 1180 1181 if (mVideoSource == NULL) { 1182 return OK; 1183 } 1184 1185 LOGV("attempting to reconfigure to use new surface"); 1186 1187 bool wasPlaying = (mFlags & PLAYING) != 0; 1188 1189 pause_l(); 1190 mVideoRenderer.clear(); 1191 1192 shutdownVideoDecoder_l(); 1193 1194 status_t err = initVideoDecoder(); 1195 1196 if (err != OK) { 1197 LOGE("failed to reinstantiate video decoder after surface change."); 1198 return err; 1199 } 1200 1201 if (mLastVideoTimeUs >= 0) { 1202 mSeeking = SEEK; 1203 mSeekTimeUs = mLastVideoTimeUs; 1204 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1205 } 1206 1207 if (wasPlaying) { 1208 play_l(); 1209 } 1210 1211 return OK; 1212} 1213 1214void AwesomePlayer::setAudioSink( 1215 const sp<MediaPlayerBase::AudioSink> &audioSink) { 1216 Mutex::Autolock autoLock(mLock); 1217 1218 mAudioSink = audioSink; 1219} 1220 1221status_t AwesomePlayer::setLooping(bool shouldLoop) { 1222 Mutex::Autolock autoLock(mLock); 1223 1224 modifyFlags(LOOPING, CLEAR); 1225 1226 if (shouldLoop) { 1227 modifyFlags(LOOPING, SET); 1228 } 1229 1230 return OK; 1231} 1232 1233status_t AwesomePlayer::getDuration(int64_t *durationUs) { 1234 Mutex::Autolock autoLock(mMiscStateLock); 1235 1236 if (mDurationUs < 0) { 1237 return UNKNOWN_ERROR; 1238 } 1239 1240 *durationUs = mDurationUs; 1241 1242 return OK; 1243} 1244 1245status_t AwesomePlayer::getPosition(int64_t *positionUs) { 1246 if (mSeeking != NO_SEEK) { 1247 *positionUs = mSeekTimeUs; 1248 } else if (mVideoSource != NULL 1249 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) { 1250 Mutex::Autolock autoLock(mMiscStateLock); 1251 *positionUs = mVideoTimeUs; 1252 } else if (mAudioPlayer != NULL) { 1253 *positionUs = mAudioPlayer->getMediaTimeUs(); 1254 } else { 1255 *positionUs = 0; 1256 } 1257 1258 return OK; 1259} 1260 1261status_t AwesomePlayer::seekTo(int64_t timeUs) { 1262 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 1263 Mutex::Autolock autoLock(mLock); 1264 return seekTo_l(timeUs); 1265 } 1266 1267 return OK; 1268} 1269 1270status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) { 1271 if (mTextPlayer != NULL) { 1272 if (index >= 0) { // to turn on a text track 1273 status_t err = mTextPlayer->setTimedTextTrackIndex(index); 1274 if (err != OK) { 1275 return err; 1276 } 1277 1278 modifyFlags(TEXT_RUNNING, SET); 1279 modifyFlags(TEXTPLAYER_STARTED, SET); 1280 return OK; 1281 } else { // to turn off the text track display 1282 if (mFlags & TEXT_RUNNING) { 1283 modifyFlags(TEXT_RUNNING, CLEAR); 1284 } 1285 if (mFlags & TEXTPLAYER_STARTED) { 1286 modifyFlags(TEXTPLAYER_STARTED, CLEAR); 1287 } 1288 1289 return mTextPlayer->setTimedTextTrackIndex(index); 1290 } 1291 } else { 1292 return INVALID_OPERATION; 1293 } 1294} 1295 1296status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 1297 if (mFlags & CACHE_UNDERRUN) { 1298 modifyFlags(CACHE_UNDERRUN, CLEAR); 1299 play_l(); 1300 } 1301 1302 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) { 1303 // Video playback completed before, there's no pending 1304 // video event right now. In order for this new seek 1305 // to be honored, we need to post one. 1306 1307 postVideoEvent_l(); 1308 } 1309 1310 mSeeking = SEEK; 1311 mSeekNotificationSent = false; 1312 mSeekTimeUs = timeUs; 1313 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1314 1315 seekAudioIfNecessary_l(); 1316 1317 if (mFlags & TEXTPLAYER_STARTED) { 1318 mTextPlayer->seekTo(mSeekTimeUs); 1319 } 1320 1321 if (!(mFlags & PLAYING)) { 1322 LOGV("seeking while paused, sending SEEK_COMPLETE notification" 1323 " immediately."); 1324 1325 notifyListener_l(MEDIA_SEEK_COMPLETE); 1326 mSeekNotificationSent = true; 1327 1328 if ((mFlags & PREPARED) && mVideoSource != NULL) { 1329 modifyFlags(SEEK_PREVIEW, SET); 1330 postVideoEvent_l(); 1331 } 1332 } 1333 1334 return OK; 1335} 1336 1337void AwesomePlayer::seekAudioIfNecessary_l() { 1338 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) { 1339 mAudioPlayer->seekTo(mSeekTimeUs); 1340 1341 mWatchForAudioSeekComplete = true; 1342 mWatchForAudioEOS = true; 1343 1344 if (mDecryptHandle != NULL) { 1345 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1346 Playback::PAUSE, 0); 1347 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1348 Playback::START, mSeekTimeUs / 1000); 1349 } 1350 } 1351} 1352 1353void AwesomePlayer::setAudioSource(sp<MediaSource> source) { 1354 CHECK(source != NULL); 1355 1356 mAudioTrack = source; 1357} 1358 1359void AwesomePlayer::addTextSource(sp<MediaSource> source) { 1360 Mutex::Autolock autoLock(mTimedTextLock); 1361 CHECK(source != NULL); 1362 1363 if (mTextPlayer == NULL) { 1364 mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue); 1365 } 1366 1367 mTextPlayer->addTextSource(source); 1368} 1369 1370status_t AwesomePlayer::initAudioDecoder() { 1371 sp<MetaData> meta = mAudioTrack->getFormat(); 1372 1373 const char *mime; 1374 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1375 1376 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { 1377 mAudioSource = mAudioTrack; 1378 } else { 1379 mAudioSource = OMXCodec::Create( 1380 mClient.interface(), mAudioTrack->getFormat(), 1381 false, // createEncoder 1382 mAudioTrack); 1383 } 1384 1385 if (mAudioSource != NULL) { 1386 int64_t durationUs; 1387 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1388 Mutex::Autolock autoLock(mMiscStateLock); 1389 if (mDurationUs < 0 || durationUs > mDurationUs) { 1390 mDurationUs = durationUs; 1391 } 1392 } 1393 1394 status_t err = mAudioSource->start(); 1395 1396 if (err != OK) { 1397 mAudioSource.clear(); 1398 return err; 1399 } 1400 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) { 1401 // For legacy reasons we're simply going to ignore the absence 1402 // of an audio decoder for QCELP instead of aborting playback 1403 // altogether. 1404 return OK; 1405 } 1406 1407 if (mAudioSource != NULL) { 1408 Mutex::Autolock autoLock(mStatsLock); 1409 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 1410 1411 const char *component; 1412 if (!mAudioSource->getFormat() 1413 ->findCString(kKeyDecoderComponent, &component)) { 1414 component = "none"; 1415 } 1416 1417 stat->mDecoderName = component; 1418 } 1419 1420 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 1421} 1422 1423void AwesomePlayer::setVideoSource(sp<MediaSource> source) { 1424 CHECK(source != NULL); 1425 1426 mVideoTrack = source; 1427} 1428 1429status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 1430 1431 // Either the application or the DRM system can independently say 1432 // that there must be a hardware-protected path to an external video sink. 1433 // For now we always require a hardware-protected path to external video sink 1434 // if content is DRMed, but eventually this could be optional per DRM agent. 1435 // When the application wants protection, then 1436 // (USE_SURFACE_ALLOC && (mSurface != 0) && 1437 // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp)) 1438 // will be true, but that part is already handled by SurfaceFlinger. 1439 1440#ifdef DEBUG_HDCP 1441 // For debugging, we allow a system property to control the protected usage. 1442 // In case of uninitialized or unexpected property, we default to "DRM only". 1443 bool setProtectionBit = false; 1444 char value[PROPERTY_VALUE_MAX]; 1445 if (property_get("persist.sys.hdcp_checking", value, NULL)) { 1446 if (!strcmp(value, "never")) { 1447 // nop 1448 } else if (!strcmp(value, "always")) { 1449 setProtectionBit = true; 1450 } else if (!strcmp(value, "drm-only")) { 1451 if (mDecryptHandle != NULL) { 1452 setProtectionBit = true; 1453 } 1454 // property value is empty, or unexpected value 1455 } else { 1456 if (mDecryptHandle != NULL) { 1457 setProtectionBit = true; 1458 } 1459 } 1460 // can' read property value 1461 } else { 1462 if (mDecryptHandle != NULL) { 1463 setProtectionBit = true; 1464 } 1465 } 1466 // note that usage bit is already cleared, so no need to clear it in the "else" case 1467 if (setProtectionBit) { 1468 flags |= OMXCodec::kEnableGrallocUsageProtected; 1469 } 1470#else 1471 if (mDecryptHandle != NULL) { 1472 flags |= OMXCodec::kEnableGrallocUsageProtected; 1473 } 1474#endif 1475 LOGV("initVideoDecoder flags=0x%x", flags); 1476 mVideoSource = OMXCodec::Create( 1477 mClient.interface(), mVideoTrack->getFormat(), 1478 false, // createEncoder 1479 mVideoTrack, 1480 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL); 1481 1482 if (mVideoSource != NULL) { 1483 int64_t durationUs; 1484 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1485 Mutex::Autolock autoLock(mMiscStateLock); 1486 if (mDurationUs < 0 || durationUs > mDurationUs) { 1487 mDurationUs = durationUs; 1488 } 1489 } 1490 1491 status_t err = mVideoSource->start(); 1492 1493 if (err != OK) { 1494 mVideoSource.clear(); 1495 return err; 1496 } 1497 } 1498 1499 if (mVideoSource != NULL) { 1500 const char *componentName; 1501 CHECK(mVideoSource->getFormat() 1502 ->findCString(kKeyDecoderComponent, &componentName)); 1503 1504 { 1505 Mutex::Autolock autoLock(mStatsLock); 1506 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 1507 1508 stat->mDecoderName = componentName; 1509 } 1510 1511 static const char *kPrefix = "OMX.Nvidia."; 1512 static const char *kSuffix = ".decode"; 1513 static const size_t kSuffixLength = strlen(kSuffix); 1514 1515 size_t componentNameLength = strlen(componentName); 1516 1517 if (!strncmp(componentName, kPrefix, strlen(kPrefix)) 1518 && componentNameLength >= kSuffixLength 1519 && !strcmp(&componentName[ 1520 componentNameLength - kSuffixLength], kSuffix)) { 1521 modifyFlags(SLOW_DECODER_HACK, SET); 1522 } 1523 } 1524 1525 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 1526} 1527 1528void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { 1529 if (mSeeking == SEEK_VIDEO_ONLY) { 1530 mSeeking = NO_SEEK; 1531 return; 1532 } 1533 1534 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) { 1535 return; 1536 } 1537 1538 if (mAudioPlayer != NULL) { 1539 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); 1540 1541 // If we don't have a video time, seek audio to the originally 1542 // requested seek time instead. 1543 1544 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs); 1545 mWatchForAudioSeekComplete = true; 1546 mWatchForAudioEOS = true; 1547 } else if (!mSeekNotificationSent) { 1548 // If we're playing video only, report seek complete now, 1549 // otherwise audio player will notify us later. 1550 notifyListener_l(MEDIA_SEEK_COMPLETE); 1551 mSeekNotificationSent = true; 1552 } 1553 1554 modifyFlags(FIRST_FRAME, SET); 1555 mSeeking = NO_SEEK; 1556 1557 if (mDecryptHandle != NULL) { 1558 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1559 Playback::PAUSE, 0); 1560 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1561 Playback::START, videoTimeUs / 1000); 1562 } 1563} 1564 1565void AwesomePlayer::onVideoEvent() { 1566 Mutex::Autolock autoLock(mLock); 1567 if (!mVideoEventPending) { 1568 // The event has been cancelled in reset_l() but had already 1569 // been scheduled for execution at that time. 1570 return; 1571 } 1572 mVideoEventPending = false; 1573 1574 if (mSeeking != NO_SEEK) { 1575 if (mVideoBuffer) { 1576 mVideoBuffer->release(); 1577 mVideoBuffer = NULL; 1578 } 1579 1580 if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL 1581 && !(mFlags & SEEK_PREVIEW)) { 1582 // We're going to seek the video source first, followed by 1583 // the audio source. 1584 // In order to avoid jumps in the DataSource offset caused by 1585 // the audio codec prefetching data from the old locations 1586 // while the video codec is already reading data from the new 1587 // locations, we'll "pause" the audio source, causing it to 1588 // stop reading input data until a subsequent seek. 1589 1590 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1591 mAudioPlayer->pause(); 1592 1593 modifyFlags(AUDIO_RUNNING, CLEAR); 1594 } 1595 mAudioSource->pause(); 1596 } 1597 } 1598 1599 if (!mVideoBuffer) { 1600 MediaSource::ReadOptions options; 1601 if (mSeeking != NO_SEEK) { 1602 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 1603 1604 options.setSeekTo( 1605 mSeekTimeUs, 1606 mSeeking == SEEK_VIDEO_ONLY 1607 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC 1608 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); 1609 } 1610 for (;;) { 1611 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1612 options.clearSeekTo(); 1613 1614 if (err != OK) { 1615 CHECK(mVideoBuffer == NULL); 1616 1617 if (err == INFO_FORMAT_CHANGED) { 1618 LOGV("VideoSource signalled format change."); 1619 1620 notifyVideoSize_l(); 1621 1622 if (mVideoRenderer != NULL) { 1623 mVideoRendererIsPreview = false; 1624 initRenderer_l(); 1625 } 1626 continue; 1627 } 1628 1629 // So video playback is complete, but we may still have 1630 // a seek request pending that needs to be applied 1631 // to the audio track. 1632 if (mSeeking != NO_SEEK) { 1633 LOGV("video stream ended while seeking!"); 1634 } 1635 finishSeekIfNecessary(-1); 1636 1637 if (mAudioPlayer != NULL 1638 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1639 startAudioPlayer_l(); 1640 } 1641 1642 modifyFlags(VIDEO_AT_EOS, SET); 1643 postStreamDoneEvent_l(err); 1644 return; 1645 } 1646 1647 if (mVideoBuffer->range_length() == 0) { 1648 // Some decoders, notably the PV AVC software decoder 1649 // return spurious empty buffers that we just want to ignore. 1650 1651 mVideoBuffer->release(); 1652 mVideoBuffer = NULL; 1653 continue; 1654 } 1655 1656 break; 1657 } 1658 1659 { 1660 Mutex::Autolock autoLock(mStatsLock); 1661 ++mStats.mNumVideoFramesDecoded; 1662 } 1663 } 1664 1665 int64_t timeUs; 1666 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 1667 1668 mLastVideoTimeUs = timeUs; 1669 1670 if (mSeeking == SEEK_VIDEO_ONLY) { 1671 if (mSeekTimeUs > timeUs) { 1672 LOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us", 1673 mSeekTimeUs, timeUs); 1674 } 1675 } 1676 1677 { 1678 Mutex::Autolock autoLock(mMiscStateLock); 1679 mVideoTimeUs = timeUs; 1680 } 1681 1682 SeekType wasSeeking = mSeeking; 1683 finishSeekIfNecessary(timeUs); 1684 1685 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1686 status_t err = startAudioPlayer_l(); 1687 if (err != OK) { 1688 LOGE("Starting the audio player failed w/ err %d", err); 1689 return; 1690 } 1691 } 1692 1693 if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) { 1694 mTextPlayer->resume(); 1695 modifyFlags(TEXT_RUNNING, SET); 1696 } 1697 1698 TimeSource *ts = 1699 ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED)) 1700 ? &mSystemTimeSource : mTimeSource; 1701 1702 if (mFlags & FIRST_FRAME) { 1703 modifyFlags(FIRST_FRAME, CLEAR); 1704 mSinceLastDropped = 0; 1705 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs; 1706 } 1707 1708 int64_t realTimeUs, mediaTimeUs; 1709 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL 1710 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 1711 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 1712 } 1713 1714 if (wasSeeking == SEEK_VIDEO_ONLY) { 1715 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; 1716 1717 int64_t latenessUs = nowUs - timeUs; 1718 1719 if (latenessUs > 0) { 1720 LOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6); 1721 } 1722 } 1723 1724 if (wasSeeking == NO_SEEK) { 1725 // Let's display the first frame after seeking right away. 1726 1727 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; 1728 1729 int64_t latenessUs = nowUs - timeUs; 1730 1731 if (latenessUs > 500000ll 1732 && mAudioPlayer != NULL 1733 && mAudioPlayer->getMediaTimeMapping( 1734 &realTimeUs, &mediaTimeUs)) { 1735 LOGI("we're much too late (%.2f secs), video skipping ahead", 1736 latenessUs / 1E6); 1737 1738 mVideoBuffer->release(); 1739 mVideoBuffer = NULL; 1740 1741 mSeeking = SEEK_VIDEO_ONLY; 1742 mSeekTimeUs = mediaTimeUs; 1743 1744 postVideoEvent_l(); 1745 return; 1746 } 1747 1748 if (latenessUs > 40000) { 1749 // We're more than 40ms late. 1750 LOGV("we're late by %lld us (%.2f secs)", 1751 latenessUs, latenessUs / 1E6); 1752 1753 if (!(mFlags & SLOW_DECODER_HACK) 1754 || mSinceLastDropped > FRAME_DROP_FREQ) 1755 { 1756 LOGV("we're late by %lld us (%.2f secs) dropping " 1757 "one after %d frames", 1758 latenessUs, latenessUs / 1E6, mSinceLastDropped); 1759 1760 mSinceLastDropped = 0; 1761 mVideoBuffer->release(); 1762 mVideoBuffer = NULL; 1763 1764 { 1765 Mutex::Autolock autoLock(mStatsLock); 1766 ++mStats.mNumVideoFramesDropped; 1767 } 1768 1769 postVideoEvent_l(); 1770 return; 1771 } 1772 } 1773 1774 if (latenessUs < -10000) { 1775 // We're more than 10ms early. 1776 1777 postVideoEvent_l(10000); 1778 return; 1779 } 1780 } 1781 1782 if ((mNativeWindow != NULL) 1783 && (mVideoRendererIsPreview || mVideoRenderer == NULL)) { 1784 mVideoRendererIsPreview = false; 1785 1786 initRenderer_l(); 1787 } 1788 1789 if (mVideoRenderer != NULL) { 1790 mSinceLastDropped++; 1791 mVideoRenderer->render(mVideoBuffer); 1792 } 1793 1794 mVideoBuffer->release(); 1795 mVideoBuffer = NULL; 1796 1797 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) { 1798 modifyFlags(SEEK_PREVIEW, CLEAR); 1799 return; 1800 } 1801 1802 postVideoEvent_l(); 1803} 1804 1805void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 1806 if (mVideoEventPending) { 1807 return; 1808 } 1809 1810 mVideoEventPending = true; 1811 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 1812} 1813 1814void AwesomePlayer::postStreamDoneEvent_l(status_t status) { 1815 if (mStreamDoneEventPending) { 1816 return; 1817 } 1818 mStreamDoneEventPending = true; 1819 1820 mStreamDoneStatus = status; 1821 mQueue.postEvent(mStreamDoneEvent); 1822} 1823 1824void AwesomePlayer::postBufferingEvent_l() { 1825 if (mBufferingEventPending) { 1826 return; 1827 } 1828 mBufferingEventPending = true; 1829 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 1830} 1831 1832void AwesomePlayer::postVideoLagEvent_l() { 1833 if (mVideoLagEventPending) { 1834 return; 1835 } 1836 mVideoLagEventPending = true; 1837 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); 1838} 1839 1840void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) { 1841 Mutex::Autolock autoLock(mAudioLock); 1842 if (mAudioStatusEventPending) { 1843 return; 1844 } 1845 mAudioStatusEventPending = true; 1846 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs); 1847} 1848 1849void AwesomePlayer::onCheckAudioStatus() { 1850 { 1851 Mutex::Autolock autoLock(mAudioLock); 1852 if (!mAudioStatusEventPending) { 1853 // Event was dispatched and while we were blocking on the mutex, 1854 // has already been cancelled. 1855 return; 1856 } 1857 1858 mAudioStatusEventPending = false; 1859 } 1860 1861 Mutex::Autolock autoLock(mLock); 1862 1863 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 1864 mWatchForAudioSeekComplete = false; 1865 1866 if (!mSeekNotificationSent) { 1867 notifyListener_l(MEDIA_SEEK_COMPLETE); 1868 mSeekNotificationSent = true; 1869 } 1870 1871 mSeeking = NO_SEEK; 1872 } 1873 1874 status_t finalStatus; 1875 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { 1876 mWatchForAudioEOS = false; 1877 modifyFlags(AUDIO_AT_EOS, SET); 1878 modifyFlags(FIRST_FRAME, SET); 1879 postStreamDoneEvent_l(finalStatus); 1880 } 1881} 1882 1883status_t AwesomePlayer::prepare() { 1884 Mutex::Autolock autoLock(mLock); 1885 return prepare_l(); 1886} 1887 1888status_t AwesomePlayer::prepare_l() { 1889 if (mFlags & PREPARED) { 1890 return OK; 1891 } 1892 1893 if (mFlags & PREPARING) { 1894 return UNKNOWN_ERROR; 1895 } 1896 1897 mIsAsyncPrepare = false; 1898 status_t err = prepareAsync_l(); 1899 1900 if (err != OK) { 1901 return err; 1902 } 1903 1904 while (mFlags & PREPARING) { 1905 mPreparedCondition.wait(mLock); 1906 } 1907 1908 return mPrepareResult; 1909} 1910 1911status_t AwesomePlayer::prepareAsync() { 1912 Mutex::Autolock autoLock(mLock); 1913 1914 if (mFlags & PREPARING) { 1915 return UNKNOWN_ERROR; // async prepare already pending 1916 } 1917 1918 mIsAsyncPrepare = true; 1919 return prepareAsync_l(); 1920} 1921 1922status_t AwesomePlayer::prepareAsync_l() { 1923 if (mFlags & PREPARING) { 1924 return UNKNOWN_ERROR; // async prepare already pending 1925 } 1926 1927 if (!mQueueStarted) { 1928 mQueue.start(); 1929 mQueueStarted = true; 1930 } 1931 1932 modifyFlags(PREPARING, SET); 1933 mAsyncPrepareEvent = new AwesomeEvent( 1934 this, &AwesomePlayer::onPrepareAsyncEvent); 1935 1936 mQueue.postEvent(mAsyncPrepareEvent); 1937 1938 return OK; 1939} 1940 1941status_t AwesomePlayer::finishSetDataSource_l() { 1942 sp<DataSource> dataSource; 1943 1944 bool isWidevineStreaming = false; 1945 if (!strncasecmp("widevine://", mUri.string(), 11)) { 1946 isWidevineStreaming = true; 1947 1948 String8 newURI = String8("http://"); 1949 newURI.append(mUri.string() + 11); 1950 1951 mUri = newURI; 1952 } 1953 1954 AString sniffedMIME; 1955 1956 if (!strncasecmp("http://", mUri.string(), 7) 1957 || !strncasecmp("https://", mUri.string(), 8) 1958 || isWidevineStreaming) { 1959 mConnectingDataSource = HTTPBase::Create( 1960 (mFlags & INCOGNITO) 1961 ? HTTPBase::kFlagIncognito 1962 : 0); 1963 1964 if (mUIDValid) { 1965 mConnectingDataSource->setUID(mUID); 1966 } 1967 1968 String8 cacheConfig; 1969 bool disconnectAtHighwatermark; 1970 NuCachedSource2::RemoveCacheSpecificHeaders( 1971 &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark); 1972 1973 mLock.unlock(); 1974 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); 1975 mLock.lock(); 1976 1977 if (err != OK) { 1978 mConnectingDataSource.clear(); 1979 1980 LOGI("mConnectingDataSource->connect() returned %d", err); 1981 return err; 1982 } 1983 1984 if (!isWidevineStreaming) { 1985 // The widevine extractor does its own caching. 1986 1987#if 0 1988 mCachedSource = new NuCachedSource2( 1989 new ThrottledSource( 1990 mConnectingDataSource, 50 * 1024 /* bytes/sec */)); 1991#else 1992 mCachedSource = new NuCachedSource2( 1993 mConnectingDataSource, 1994 cacheConfig.isEmpty() ? NULL : cacheConfig.string(), 1995 disconnectAtHighwatermark); 1996#endif 1997 1998 dataSource = mCachedSource; 1999 } else { 2000 dataSource = mConnectingDataSource; 2001 } 2002 2003 mConnectingDataSource.clear(); 2004 2005 String8 contentType = dataSource->getMIMEType(); 2006 2007 if (strncasecmp(contentType.string(), "audio/", 6)) { 2008 // We're not doing this for streams that appear to be audio-only 2009 // streams to ensure that even low bandwidth streams start 2010 // playing back fairly instantly. 2011 2012 // We're going to prefill the cache before trying to instantiate 2013 // the extractor below, as the latter is an operation that otherwise 2014 // could block on the datasource for a significant amount of time. 2015 // During that time we'd be unable to abort the preparation phase 2016 // without this prefill. 2017 if (mCachedSource != NULL) { 2018 // We're going to prefill the cache before trying to instantiate 2019 // the extractor below, as the latter is an operation that otherwise 2020 // could block on the datasource for a significant amount of time. 2021 // During that time we'd be unable to abort the preparation phase 2022 // without this prefill. 2023 2024 mLock.unlock(); 2025 2026 // Initially make sure we have at least 192 KB for the sniff 2027 // to complete without blocking. 2028 static const size_t kMinBytesForSniffing = 192 * 1024; 2029 2030 off64_t metaDataSize = -1ll; 2031 for (;;) { 2032 status_t finalStatus; 2033 size_t cachedDataRemaining = 2034 mCachedSource->approxDataRemaining(&finalStatus); 2035 2036 if (finalStatus != OK 2037 || (metaDataSize >= 0 2038 && cachedDataRemaining >= metaDataSize) 2039 || (mFlags & PREPARE_CANCELLED)) { 2040 break; 2041 } 2042 2043 LOGV("now cached %d bytes of data", cachedDataRemaining); 2044 2045 if (metaDataSize < 0 2046 && cachedDataRemaining >= kMinBytesForSniffing) { 2047 String8 tmp; 2048 float confidence; 2049 sp<AMessage> meta; 2050 if (!dataSource->sniff(&tmp, &confidence, &meta)) { 2051 mLock.lock(); 2052 return UNKNOWN_ERROR; 2053 } 2054 2055 // We successfully identified the file's extractor to 2056 // be, remember this mime type so we don't have to 2057 // sniff it again when we call MediaExtractor::Create() 2058 // below. 2059 sniffedMIME = tmp.string(); 2060 2061 if (meta == NULL 2062 || !meta->findInt64( 2063 "meta-data-size", &metaDataSize)) { 2064 metaDataSize = kHighWaterMarkBytes; 2065 } 2066 2067 CHECK_GE(metaDataSize, 0ll); 2068 LOGV("metaDataSize = %lld bytes", metaDataSize); 2069 } 2070 2071 usleep(200000); 2072 } 2073 2074 mLock.lock(); 2075 } 2076 2077 if (mFlags & PREPARE_CANCELLED) { 2078 LOGI("Prepare cancelled while waiting for initial cache fill."); 2079 return UNKNOWN_ERROR; 2080 } 2081 } 2082 } else { 2083 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); 2084 } 2085 2086 if (dataSource == NULL) { 2087 return UNKNOWN_ERROR; 2088 } 2089 2090 sp<MediaExtractor> extractor; 2091 2092 if (isWidevineStreaming) { 2093 String8 mimeType; 2094 float confidence; 2095 sp<AMessage> dummy; 2096 bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 2097 2098 if (!success 2099 || strcasecmp( 2100 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 2101 return ERROR_UNSUPPORTED; 2102 } 2103 2104 dataSource->DrmInitialization(); 2105 2106 mWVMExtractor = new WVMExtractor(dataSource); 2107 mWVMExtractor->setAdaptiveStreamingMode(true); 2108 extractor = mWVMExtractor; 2109 } else { 2110 extractor = MediaExtractor::Create( 2111 dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); 2112 2113 if (extractor == NULL) { 2114 return UNKNOWN_ERROR; 2115 } 2116 } 2117 2118 if (extractor->getDrmFlag()) { 2119 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 2120 2121 if (mDecryptHandle != NULL) { 2122 CHECK(mDrmManagerClient); 2123 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 2124 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 2125 } 2126 } 2127 } 2128 2129 status_t err = setDataSource_l(extractor); 2130 2131 if (err != OK) { 2132 mWVMExtractor.clear(); 2133 2134 return err; 2135 } 2136 2137 return OK; 2138} 2139 2140void AwesomePlayer::abortPrepare(status_t err) { 2141 CHECK(err != OK); 2142 2143 if (mIsAsyncPrepare) { 2144 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 2145 } 2146 2147 mPrepareResult = err; 2148 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2149 mAsyncPrepareEvent = NULL; 2150 mPreparedCondition.broadcast(); 2151} 2152 2153// static 2154bool AwesomePlayer::ContinuePreparation(void *cookie) { 2155 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie); 2156 2157 return (me->mFlags & PREPARE_CANCELLED) == 0; 2158} 2159 2160void AwesomePlayer::onPrepareAsyncEvent() { 2161 Mutex::Autolock autoLock(mLock); 2162 2163 if (mFlags & PREPARE_CANCELLED) { 2164 LOGI("prepare was cancelled before doing anything"); 2165 abortPrepare(UNKNOWN_ERROR); 2166 return; 2167 } 2168 2169 if (mUri.size() > 0) { 2170 status_t err = finishSetDataSource_l(); 2171 2172 if (err != OK) { 2173 abortPrepare(err); 2174 return; 2175 } 2176 } 2177 2178 if (mVideoTrack != NULL && mVideoSource == NULL) { 2179 status_t err = initVideoDecoder(); 2180 2181 if (err != OK) { 2182 abortPrepare(err); 2183 return; 2184 } 2185 } 2186 2187 if (mAudioTrack != NULL && mAudioSource == NULL) { 2188 status_t err = initAudioDecoder(); 2189 2190 if (err != OK) { 2191 abortPrepare(err); 2192 return; 2193 } 2194 } 2195 2196 modifyFlags(PREPARING_CONNECTED, SET); 2197 2198 if (isStreamingHTTP()) { 2199 postBufferingEvent_l(); 2200 } else { 2201 finishAsyncPrepare_l(); 2202 } 2203} 2204 2205void AwesomePlayer::finishAsyncPrepare_l() { 2206 if (mIsAsyncPrepare) { 2207 if (mVideoSource == NULL) { 2208 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); 2209 } else { 2210 notifyVideoSize_l(); 2211 } 2212 2213 notifyListener_l(MEDIA_PREPARED); 2214 } 2215 2216 mPrepareResult = OK; 2217 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2218 modifyFlags(PREPARED, SET); 2219 mAsyncPrepareEvent = NULL; 2220 mPreparedCondition.broadcast(); 2221} 2222 2223uint32_t AwesomePlayer::flags() const { 2224 return mExtractorFlags; 2225} 2226 2227void AwesomePlayer::postAudioEOS(int64_t delayUs) { 2228 postCheckAudioStatusEvent(delayUs); 2229} 2230 2231void AwesomePlayer::postAudioSeekComplete() { 2232 postCheckAudioStatusEvent(0); 2233} 2234 2235status_t AwesomePlayer::setParameter(int key, const Parcel &request) { 2236 switch (key) { 2237 case KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX: 2238 { 2239 Mutex::Autolock autoLock(mTimedTextLock); 2240 return setTimedTextTrackIndex(request.readInt32()); 2241 } 2242 case KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE: 2243 { 2244 Mutex::Autolock autoLock(mTimedTextLock); 2245 if (mTextPlayer == NULL) { 2246 mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue); 2247 } 2248 2249 return mTextPlayer->setParameter(key, request); 2250 } 2251 case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS: 2252 { 2253 return setCacheStatCollectFreq(request); 2254 } 2255 default: 2256 { 2257 return ERROR_UNSUPPORTED; 2258 } 2259 } 2260} 2261 2262status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) { 2263 if (mCachedSource != NULL) { 2264 int32_t freqMs = request.readInt32(); 2265 LOGD("Request to keep cache stats in the past %d ms", 2266 freqMs); 2267 return mCachedSource->setCacheStatCollectFreq(freqMs); 2268 } 2269 return ERROR_UNSUPPORTED; 2270} 2271 2272status_t AwesomePlayer::getParameter(int key, Parcel *reply) { 2273 switch (key) { 2274 case KEY_PARAMETER_AUDIO_CHANNEL_COUNT: 2275 { 2276 int32_t channelCount; 2277 if (mAudioTrack == 0 || 2278 !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) { 2279 channelCount = 0; 2280 } 2281 reply->writeInt32(channelCount); 2282 } 2283 return OK; 2284 default: 2285 { 2286 return ERROR_UNSUPPORTED; 2287 } 2288 } 2289} 2290 2291bool AwesomePlayer::isStreamingHTTP() const { 2292 return mCachedSource != NULL || mWVMExtractor != NULL; 2293} 2294 2295status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const { 2296 Mutex::Autolock autoLock(mStatsLock); 2297 2298 FILE *out = fdopen(dup(fd), "w"); 2299 2300 fprintf(out, " AwesomePlayer\n"); 2301 if (mStats.mFd < 0) { 2302 fprintf(out, " URI(%s)", mStats.mURI.string()); 2303 } else { 2304 fprintf(out, " fd(%d)", mStats.mFd); 2305 } 2306 2307 fprintf(out, ", flags(0x%08x)", mStats.mFlags); 2308 2309 if (mStats.mBitrate >= 0) { 2310 fprintf(out, ", bitrate(%lld bps)", mStats.mBitrate); 2311 } 2312 2313 fprintf(out, "\n"); 2314 2315 for (size_t i = 0; i < mStats.mTracks.size(); ++i) { 2316 const TrackStat &stat = mStats.mTracks.itemAt(i); 2317 2318 fprintf(out, " Track %d\n", i + 1); 2319 fprintf(out, " MIME(%s)", stat.mMIME.string()); 2320 2321 if (!stat.mDecoderName.isEmpty()) { 2322 fprintf(out, ", decoder(%s)", stat.mDecoderName.string()); 2323 } 2324 2325 fprintf(out, "\n"); 2326 2327 if ((ssize_t)i == mStats.mVideoTrackIndex) { 2328 fprintf(out, 2329 " videoDimensions(%d x %d), " 2330 "numVideoFramesDecoded(%lld), " 2331 "numVideoFramesDropped(%lld)\n", 2332 mStats.mVideoWidth, 2333 mStats.mVideoHeight, 2334 mStats.mNumVideoFramesDecoded, 2335 mStats.mNumVideoFramesDropped); 2336 } 2337 } 2338 2339 fclose(out); 2340 out = NULL; 2341 2342 return OK; 2343} 2344 2345void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { 2346 switch (mode) { 2347 case SET: 2348 mFlags |= value; 2349 break; 2350 case CLEAR: 2351 mFlags &= ~value; 2352 break; 2353 case ASSIGN: 2354 mFlags = value; 2355 break; 2356 default: 2357 TRESPASS(); 2358 } 2359 2360 { 2361 Mutex::Autolock autoLock(mStatsLock); 2362 mStats.mFlags = mFlags; 2363 } 2364} 2365 2366} // namespace android 2367