AwesomePlayer.cpp revision 1b78c4b1484c7d4c12b9a87329dc8d4b6e8c0c37
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 14163935113919a184122b8b3bd672ef08c8df65dcRomain Guy * limitations under the License. 15163935113919a184122b8b3bd672ef08c8df65dcRomain Guy */ 16163935113919a184122b8b3bd672ef08c8df65dcRomain Guy 17163935113919a184122b8b3bd672ef08c8df65dcRomain Guy#undef DEBUG_HDCP 181473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian 191473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian//#define LOG_NDEBUG 0 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "AwesomePlayer" 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define ATRACE_TAG ATRACE_TAG_VIDEO 22864c0d50cda714d73fa70e3600ec36b5db8a835aMathias Agopian#include <inttypes.h> 2366269ea6f68f2f25888ce1080c94ac782742fafcKenny Root#include <utils/Log.h> 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Trace.h> 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2669969e48f2bca9339662dddfacff0bbf6374ed7fDianne Hackborn#include <dlfcn.h> 276b1e838fc16d397359f82c3a4f5700f1ed7dd910Thomas Tafertshofer 281c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/AwesomePlayer.h" 291c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/DRMExtractor.h" 301c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/SoftwareRenderer.h" 311c4907ee77392afb768c2f088e0dedbe4239f6fbJack Palevich#include "include/NuCachedSource2.h" 32560814f6b11abe83ff0c4ed18cac015c276b3181Jack Palevich#include "include/ThrottledSource.h" 33d830e74ff4bc9aa015f746e54f6922bf5221f1baJesse Hall#include "include/MPEG2TSExtractor.h" 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "include/WVMExtractor.h" 35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown 36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <binder/IPCThreadState.h> 37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <binder/IServiceManager.h> 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/IMediaPlayerService.h> 39b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project#include <media/stagefright/foundation/hexdump.h> 400a0a1248cfc03940174cbd9af677bafd7280a3bcJeff Brown#include <media/stagefright/foundation/ADebug.h> 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/timedtext/TimedTextDriver.h> 423866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian#include <media/stagefright/AudioPlayer.h> 4364a55af0ac700baecb0877235eb42caac59a3560Jeff Brown#include <media/stagefright/ClockEstimator.h> 448f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy#include <media/stagefright/DataSource.h> 4546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <media/stagefright/FileSource.h> 469f25b7fdf216c9ef0bd2322cd223eeaf0d60f77fJeff Brown#include <media/stagefright/MediaBuffer.h> 4732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown#include <media/stagefright/MediaDefs.h> 48c28867a1d67121ce5963de135e3ae2b1dbd9a33dJeff Brown#include <media/stagefright/MediaExtractor.h> 4946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <media/stagefright/MediaSource.h> 5049ed71db425c5054e3ad9526496a7e116c89556bJeff Brown#include <media/stagefright/MetaData.h> 51a95826582773a194ed7fb66bc29c9b82fe9bb8d1Romain Guy#include <media/stagefright/OMXCodec.h> 52a1cff5043d0fbd78fcf9c48e7658e56a5b0c2de3Chet Haase#include <media/stagefright/Utils.h> 53e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy 5446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown#include <gui/IGraphicBufferProducer.h> 552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown#include <gui/Surface.h> 562ed2462aa29c564f5231f317c27b3188da875e52Jeff Brown 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/AMessage.h> 58dae8e94cce0881f3e10ef5e34b881f512bb52a75Doug Felt 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/properties.h> 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define USE_SURFACE_ALLOC 1 62fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate#define FRAME_DROP_FREQ 0 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 64d84e1ce0b535128f03416145554fb405f9fade3eJeff Sharkeynamespace android { 65c07fca3831baf4d812dd724f506b4ed23dcc39e0Stephen Smalley 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int64_t kLowWaterMarkUs = 2000000ll; // 2secs 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int64_t kHighWaterMarkUs = 5000000ll; // 5secs 68481c1570dc5cdf58265b53f657801709dd05d1dfJeff Brownstatic const size_t kLowWaterMarkBytes = 40000; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic const size_t kHighWaterMarkBytes = 200000; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer 722b4abcd0c7c4361af8ab6d5d7b073fb75ac6d219Dan Egnor// is destroyed to allow the audio DSP to power down. 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic int64_t kOffloadPauseMaxUs = 60000000ll; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct AwesomeEvent : public TimedEventQueue::Event { 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AwesomeEvent( 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AwesomePlayer *player, 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void (AwesomePlayer::*method)()) 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : mPlayer(player), 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMethod(method) { 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 84f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph Wenprotected: 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project virtual ~AwesomeEvent() {} 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) { 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (mPlayer->*mMethod)(); 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate: 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AwesomePlayer *mPlayer; 93aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien void (AwesomePlayer::*mMethod)(); 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AwesomeEvent(const AwesomeEvent &); 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AwesomeEvent &operator=(const AwesomeEvent &); 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct AwesomeLocalRenderer : public AwesomeRenderer { 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AwesomeLocalRenderer( 101a06d86ab8177ee9e631e0ee4e39688bf42179bdeLeon Scroggins const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta) 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : mTarget(new SoftwareRenderer(nativeWindow, meta)) { 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project virtual void render(MediaBuffer *buffer) { 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project render((const uint8_t *)buffer->data() + buffer->range_offset(), 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buffer->range_length()); 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1096b849e2123be98eb2a1a25b8abf0b13a279ce952Wei-Ta Chen 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void render(const void *data, size_t size) { 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTarget->render(data, size, NULL); 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1136714efc5e0c52953b65e774de0003e22377e7d39Jamie Gennis 114f7cb1f75fdaedf996cab7c4690b080adc7bc5b97Doug Feltprotected: 115d313c665e618af3194f504064bcd284fe5368682Fabrice Di Meglio virtual ~AwesomeLocalRenderer() { 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project delete mTarget; 1176b849e2123be98eb2a1a25b8abf0b13a279ce952Wei-Ta Chen mTarget = NULL; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 119bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate: 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SoftwareRenderer *mTarget; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AwesomeLocalRenderer(const AwesomeLocalRenderer &); 124cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);; 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct AwesomeNativeWindowRenderer : public AwesomeRenderer { 128b01e8bf57b7492b77e3445db51471edcbadda75eMike Lockwood AwesomeNativeWindowRenderer( 129e7d511e148bc901ef41ac44d7b3593e5d803f72fMike Lockwood const sp<ANativeWindow> &nativeWindow, 130acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood int32_t rotationDegrees) 131e7d511e148bc901ef41ac44d7b3593e5d803f72fMike Lockwood : mNativeWindow(nativeWindow) { 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project applyRotation(rotationDegrees); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project virtual void render(MediaBuffer *buffer) { 13698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall ATRACE_CALL(); 137ecaa7b41ca49154ceaa9a7504eb0a86b89a96026Christopher Tate int64_t timeUs; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000); 1401cf587496fcb1d652bab9fc6792fb106b6fefaa4Joe Onorato status_t err = mNativeWindow->queueBuffer( 141d2110dbce071a236b6176de344ca797b737542ebJoe Onorato mNativeWindow.get(), buffer->graphicBuffer().get(), -1); 1424ababd922eac5931e0222862ff082dc29e012816Joe Onorato if (err != 0) { 14302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root ALOGE("queueBuffer failed with error %s (%d)", strerror(-err), 1444a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate -err); 14508d5b8fad8d46ccb64db2fdcb4d66972ec87bf48Dianne Hackborn return; 1466e0ecb4eed5cd2e1f15766d7028467129974a12dChet Haase } 1479a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey 1489a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey sp<MetaData> metaData = buffer->meta_data(); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project metaData->setInt32(kKeyRendered, 1); 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprotected: 153e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy virtual ~AwesomeNativeWindowRenderer() {} 15408965ec67ada98f63f8ac879cc44c8b0e7ff046dMathias Agopian 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate: 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<ANativeWindow> mNativeWindow; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey void applyRotation(int32_t rotationDegrees) { 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uint32_t transform; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (rotationDegrees) { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 0: transform = 0; break; 162517f67fe4b70c5a1907cb503d62b906a1eed2e1eBilly Hewlett case 90: transform = HAL_TRANSFORM_ROT_90; break; 163ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger case 180: transform = HAL_TRANSFORM_ROT_180; break; 164d81ec456bb097a712bcbc093c5a1e0075434158eDerek Sollenberger case 270: transform = HAL_TRANSFORM_ROT_270; break; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: transform = 0; break; 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (transform) { 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK_EQ(0, native_window_set_buffers_transform( 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNativeWindow.get(), transform)); 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 173bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen 174aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &); 17566269ea6f68f2f25888ce1080c94ac782742fafcKenny Root AwesomeNativeWindowRenderer &operator=( 17669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes const AwesomeNativeWindowRenderer &); 17769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes}; 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// To collect the decoder usage 18083c64e6b624a876436d2ef5d2f173b10407e27b4Mathias Agopianvoid addBatteryData(uint32_t params) { 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<IBinder> binder = 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project defaultServiceManager()->getService(String16("media.player")); 183d685894212e6dbeac1fda4996903c1da115d49a6Ying Wang sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK(service.get() != NULL); 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18625ba5b6564224dceefa086b5c439ef28dad530caMathias Agopian service->addBatteryData(params); 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1891bf797857e025e8a71db86fb9e79765a767ec1ebMathias Agopian//////////////////////////////////////////////////////////////////////////////// 190000479f9e325b4e426a67033abd92d47da412725Mathias AgopianAwesomePlayer::AwesomePlayer() 191b5af325fb1d21a9295bf3009cc95e5ead4999247Mike Reed : mQueueStarted(false), 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUIDValid(false), 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTimeSource(NULL), 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoRenderingStarted(false), 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoRendererIsPreview(false), 196560814f6b11abe83ff0c4ed18cac015c276b3181Jack Palevich mMediaRenderingStartGeneration(0), 197a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich mStartGeneration(0), 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioPlayer(NULL), 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisplayWidth(0), 200c9a1aabc49d31370e3bf41f85b805499640230b1Kenny Root mDisplayHeight(0), 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFlags(0), 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mExtractorFlags(0), 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoBuffer(NULL), 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDecryptHandle(NULL), 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastVideoTimeUs(-1), 207bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen mTextDriver(NULL), 208cd0e839a2448deea50f79bddeba782c546b33893Nick Pelly mOffloadAudio(false), 209e7d511e148bc901ef41ac44d7b3593e5d803f72fMike Lockwood mAudioTearDown(false) { 210aaedde51b76901ff05f2a2348eb41f0f5323d954Raph Levien CHECK_EQ(mClient.connect(), (status_t)OK); 2117304c343821309dd15f769b18f1de2fa43751573Jeff Brown 212755fd617258d3f1731b2829d681cab680db0fdd5Mike Lockwood DataSource::RegisterDefaultSniffers(); 213163935113919a184122b8b3bd672ef08c8df65dcRomain Guy 214163935113919a184122b8b3bd672ef08c8df65dcRomain Guy mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); 215163935113919a184122b8b3bd672ef08c8df65dcRomain Guy mVideoEventPending = false; 216163935113919a184122b8b3bd672ef08c8df65dcRomain Guy mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStreamDoneEventPending = false; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate); 219bd882b1c8708686d373c56e07e6bb8b1cb6ffd9eJeff Brown mBufferingEventPending = false; 220bd882b1c8708686d373c56e07e6bb8b1cb6ffd9eJeff Brown mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); 221bd882b1c8708686d373c56e07e6bb8b1cb6ffd9eJeff Brown mVideoLagEventPending = false; 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCheckAudioStatusEvent = new AwesomeEvent( 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this, &AwesomePlayer::onCheckAudioStatus); 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioStatusEventPending = false; 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioTearDownEvent = new AwesomeEvent(this, 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project &AwesomePlayer::onAudioTearDownEvent); 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioTearDownEventPending = false; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mClockEstimator = new WindowedLinearFitEstimator(); 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 234 reset(); 235} 236 237AwesomePlayer::~AwesomePlayer() { 238 if (mQueueStarted) { 239 mQueue.stop(); 240 } 241 242 reset(); 243 244 mClient.disconnect(); 245} 246 247void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) { 248 mQueue.cancelEvent(mVideoEvent->eventID()); 249 mVideoEventPending = false; 250 mQueue.cancelEvent(mVideoLagEvent->eventID()); 251 mVideoLagEventPending = false; 252 253 if (mOffloadAudio) { 254 mQueue.cancelEvent(mAudioTearDownEvent->eventID()); 255 mAudioTearDownEventPending = false; 256 } 257 258 if (!keepNotifications) { 259 mQueue.cancelEvent(mStreamDoneEvent->eventID()); 260 mStreamDoneEventPending = false; 261 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID()); 262 mAudioStatusEventPending = false; 263 264 mQueue.cancelEvent(mBufferingEvent->eventID()); 265 mBufferingEventPending = false; 266 mAudioTearDown = false; 267 } 268} 269 270void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) { 271 Mutex::Autolock autoLock(mLock); 272 mListener = listener; 273} 274 275void AwesomePlayer::setUID(uid_t uid) { 276 ALOGV("AwesomePlayer running on behalf of uid %d", uid); 277 278 mUID = uid; 279 mUIDValid = true; 280} 281 282status_t AwesomePlayer::setDataSource( 283 const char *uri, const KeyedVector<String8, String8> *headers) { 284 Mutex::Autolock autoLock(mLock); 285 return setDataSource_l(uri, headers); 286} 287 288status_t AwesomePlayer::setDataSource_l( 289 const char *uri, const KeyedVector<String8, String8> *headers) { 290 reset_l(); 291 292 mUri = uri; 293 294 if (headers) { 295 mUriHeaders = *headers; 296 297 ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log")); 298 if (index >= 0) { 299 // Browser is in "incognito" mode, suppress logging URLs. 300 301 // This isn't something that should be passed to the server. 302 mUriHeaders.removeItemsAt(index); 303 304 modifyFlags(INCOGNITO, SET); 305 } 306 } 307 308 ALOGI("setDataSource_l(URL suppressed)"); 309 310 // The actual work will be done during preparation in the call to 311 // ::finishSetDataSource_l to avoid blocking the calling thread in 312 // setDataSource for any significant time. 313 314 { 315 Mutex::Autolock autoLock(mStatsLock); 316 mStats.mFd = -1; 317 mStats.mURI = mUri; 318 } 319 320 return OK; 321} 322 323status_t AwesomePlayer::setDataSource( 324 int fd, int64_t offset, int64_t length) { 325 Mutex::Autolock autoLock(mLock); 326 327 reset_l(); 328 329 sp<DataSource> dataSource = new FileSource(fd, offset, length); 330 331 status_t err = dataSource->initCheck(); 332 333 if (err != OK) { 334 return err; 335 } 336 337 mFileSource = dataSource; 338 339 { 340 Mutex::Autolock autoLock(mStatsLock); 341 mStats.mFd = fd; 342 mStats.mURI = String8(); 343 } 344 345 return setDataSource_l(dataSource); 346} 347 348status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) { 349 return INVALID_OPERATION; 350} 351 352status_t AwesomePlayer::setDataSource_l( 353 const sp<DataSource> &dataSource) { 354 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 355 356 if (extractor == NULL) { 357 return UNKNOWN_ERROR; 358 } 359 360 if (extractor->getDrmFlag()) { 361 checkDrmStatus(dataSource); 362 } 363 364 return setDataSource_l(extractor); 365} 366 367void AwesomePlayer::checkDrmStatus(const sp<DataSource>& dataSource) { 368 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 369 if (mDecryptHandle != NULL) { 370 CHECK(mDrmManagerClient); 371 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 372 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 373 } 374 } 375} 376 377status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { 378 // Attempt to approximate overall stream bitrate by summing all 379 // tracks' individual bitrates, if not all of them advertise bitrate, 380 // we have to fail. 381 382 int64_t totalBitRate = 0; 383 384 mExtractor = extractor; 385 for (size_t i = 0; i < extractor->countTracks(); ++i) { 386 sp<MetaData> meta = extractor->getTrackMetaData(i); 387 388 int32_t bitrate; 389 if (!meta->findInt32(kKeyBitRate, &bitrate)) { 390 const char *mime; 391 CHECK(meta->findCString(kKeyMIMEType, &mime)); 392 ALOGV("track of type '%s' does not publish bitrate", mime); 393 394 totalBitRate = -1; 395 break; 396 } 397 398 totalBitRate += bitrate; 399 } 400 401 mBitrate = totalBitRate; 402 403 ALOGV("mBitrate = %lld bits/sec", mBitrate); 404 405 { 406 Mutex::Autolock autoLock(mStatsLock); 407 mStats.mBitrate = mBitrate; 408 mStats.mTracks.clear(); 409 mStats.mAudioTrackIndex = -1; 410 mStats.mVideoTrackIndex = -1; 411 } 412 413 bool haveAudio = false; 414 bool haveVideo = false; 415 for (size_t i = 0; i < extractor->countTracks(); ++i) { 416 sp<MetaData> meta = extractor->getTrackMetaData(i); 417 418 const char *_mime; 419 CHECK(meta->findCString(kKeyMIMEType, &_mime)); 420 421 String8 mime = String8(_mime); 422 423 if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) { 424 setVideoSource(extractor->getTrack(i)); 425 haveVideo = true; 426 427 // Set the presentation/display size 428 int32_t displayWidth, displayHeight; 429 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth); 430 if (success) { 431 success = meta->findInt32(kKeyDisplayHeight, &displayHeight); 432 } 433 if (success) { 434 mDisplayWidth = displayWidth; 435 mDisplayHeight = displayHeight; 436 } 437 438 { 439 Mutex::Autolock autoLock(mStatsLock); 440 mStats.mVideoTrackIndex = mStats.mTracks.size(); 441 mStats.mTracks.push(); 442 TrackStat *stat = 443 &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 444 stat->mMIME = mime.string(); 445 } 446 } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) { 447 setAudioSource(extractor->getTrack(i)); 448 haveAudio = true; 449 mActiveAudioTrackIndex = i; 450 451 { 452 Mutex::Autolock autoLock(mStatsLock); 453 mStats.mAudioTrackIndex = mStats.mTracks.size(); 454 mStats.mTracks.push(); 455 TrackStat *stat = 456 &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 457 stat->mMIME = mime.string(); 458 } 459 460 if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) { 461 // Only do this for vorbis audio, none of the other audio 462 // formats even support this ringtone specific hack and 463 // retrieving the metadata on some extractors may turn out 464 // to be very expensive. 465 sp<MetaData> fileMeta = extractor->getMetaData(); 466 int32_t loop; 467 if (fileMeta != NULL 468 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 469 modifyFlags(AUTO_LOOPING, SET); 470 } 471 } 472 } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { 473 addTextSource_l(i, extractor->getTrack(i)); 474 } 475 } 476 477 if (!haveAudio && !haveVideo) { 478 if (mWVMExtractor != NULL) { 479 return mWVMExtractor->getError(); 480 } else { 481 return UNKNOWN_ERROR; 482 } 483 } 484 485 mExtractorFlags = extractor->flags(); 486 487 return OK; 488} 489 490void AwesomePlayer::reset() { 491 Mutex::Autolock autoLock(mLock); 492 reset_l(); 493} 494 495void AwesomePlayer::reset_l() { 496 mVideoRenderingStarted = false; 497 mActiveAudioTrackIndex = -1; 498 mDisplayWidth = 0; 499 mDisplayHeight = 0; 500 501 notifyListener_l(MEDIA_STOPPED); 502 503 if (mDecryptHandle != NULL) { 504 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 505 Playback::STOP, 0); 506 mDecryptHandle = NULL; 507 mDrmManagerClient = NULL; 508 } 509 510 if (mFlags & PLAYING) { 511 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 512 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 513 params |= IMediaPlayerService::kBatteryDataTrackAudio; 514 } 515 if (mVideoSource != NULL) { 516 params |= IMediaPlayerService::kBatteryDataTrackVideo; 517 } 518 addBatteryData(params); 519 } 520 521 if (mFlags & PREPARING) { 522 modifyFlags(PREPARE_CANCELLED, SET); 523 if (mConnectingDataSource != NULL) { 524 ALOGI("interrupting the connection process"); 525 mConnectingDataSource->disconnect(); 526 } 527 528 if (mFlags & PREPARING_CONNECTED) { 529 // We are basically done preparing, we're just buffering 530 // enough data to start playback, we can safely interrupt that. 531 finishAsyncPrepare_l(); 532 } 533 } 534 535 while (mFlags & PREPARING) { 536 mPreparedCondition.wait(mLock); 537 } 538 539 cancelPlayerEvents(); 540 541 mWVMExtractor.clear(); 542 mCachedSource.clear(); 543 mAudioTrack.clear(); 544 mVideoTrack.clear(); 545 mExtractor.clear(); 546 547 // Shutdown audio first, so that the response to the reset request 548 // appears to happen instantaneously as far as the user is concerned 549 // If we did this later, audio would continue playing while we 550 // shutdown the video-related resources and the player appear to 551 // not be as responsive to a reset request. 552 if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED)) 553 && mAudioSource != NULL) { 554 // If we had an audio player, it would have effectively 555 // taken possession of the audio source and stopped it when 556 // _it_ is stopped. Otherwise this is still our responsibility. 557 mAudioSource->stop(); 558 } 559 mAudioSource.clear(); 560 mOmxSource.clear(); 561 562 mTimeSource = NULL; 563 564 delete mAudioPlayer; 565 mAudioPlayer = NULL; 566 567 if (mTextDriver != NULL) { 568 delete mTextDriver; 569 mTextDriver = NULL; 570 } 571 572 mVideoRenderer.clear(); 573 574 if (mVideoSource != NULL) { 575 shutdownVideoDecoder_l(); 576 } 577 578 mDurationUs = -1; 579 modifyFlags(0, ASSIGN); 580 mExtractorFlags = 0; 581 mTimeSourceDeltaUs = 0; 582 mVideoTimeUs = 0; 583 584 mSeeking = NO_SEEK; 585 mSeekNotificationSent = true; 586 mSeekTimeUs = 0; 587 588 mUri.setTo(""); 589 mUriHeaders.clear(); 590 591 mFileSource.clear(); 592 593 mBitrate = -1; 594 mLastVideoTimeUs = -1; 595 596 { 597 Mutex::Autolock autoLock(mStatsLock); 598 mStats.mFd = -1; 599 mStats.mURI = String8(); 600 mStats.mBitrate = -1; 601 mStats.mAudioTrackIndex = -1; 602 mStats.mVideoTrackIndex = -1; 603 mStats.mNumVideoFramesDecoded = 0; 604 mStats.mNumVideoFramesDropped = 0; 605 mStats.mVideoWidth = -1; 606 mStats.mVideoHeight = -1; 607 mStats.mFlags = 0; 608 mStats.mTracks.clear(); 609 } 610 611 mWatchForAudioSeekComplete = false; 612 mWatchForAudioEOS = false; 613 614 mMediaRenderingStartGeneration = 0; 615 mStartGeneration = 0; 616} 617 618void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { 619 if ((mListener != NULL) && !mAudioTearDown) { 620 sp<MediaPlayerBase> listener = mListener.promote(); 621 622 if (listener != NULL) { 623 listener->sendEvent(msg, ext1, ext2); 624 } 625 } 626} 627 628bool AwesomePlayer::getBitrate(int64_t *bitrate) { 629 off64_t size; 630 if (mDurationUs > 0 && mCachedSource != NULL 631 && mCachedSource->getSize(&size) == OK) { 632 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec 633 return true; 634 } 635 636 if (mBitrate >= 0) { 637 *bitrate = mBitrate; 638 return true; 639 } 640 641 *bitrate = 0; 642 643 return false; 644} 645 646// Returns true iff cached duration is available/applicable. 647bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { 648 int64_t bitrate; 649 650 if (mCachedSource != NULL && getBitrate(&bitrate) && (bitrate > 0)) { 651 status_t finalStatus; 652 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 653 *durationUs = cachedDataRemaining * 8000000ll / bitrate; 654 *eos = (finalStatus != OK); 655 return true; 656 } else if (mWVMExtractor != NULL) { 657 status_t finalStatus; 658 *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); 659 *eos = (finalStatus != OK); 660 return true; 661 } 662 663 return false; 664} 665 666void AwesomePlayer::ensureCacheIsFetching_l() { 667 if (mCachedSource != NULL) { 668 mCachedSource->resumeFetchingIfNecessary(); 669 } 670} 671 672void AwesomePlayer::onVideoLagUpdate() { 673 Mutex::Autolock autoLock(mLock); 674 if (!mVideoLagEventPending) { 675 return; 676 } 677 mVideoLagEventPending = false; 678 679 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs(); 680 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs; 681 682 if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) { 683 ALOGV("video late by %lld ms.", videoLateByUs / 1000ll); 684 685 notifyListener_l( 686 MEDIA_INFO, 687 MEDIA_INFO_VIDEO_TRACK_LAGGING, 688 videoLateByUs / 1000ll); 689 } 690 691 postVideoLagEvent_l(); 692} 693 694void AwesomePlayer::onBufferingUpdate() { 695 Mutex::Autolock autoLock(mLock); 696 if (!mBufferingEventPending) { 697 return; 698 } 699 mBufferingEventPending = false; 700 701 if (mCachedSource != NULL) { 702 status_t finalStatus; 703 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 704 bool eos = (finalStatus != OK); 705 706 if (eos) { 707 if (finalStatus == ERROR_END_OF_STREAM) { 708 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 709 } 710 if (mFlags & PREPARING) { 711 ALOGV("cache has reached EOS, prepare is done."); 712 finishAsyncPrepare_l(); 713 } 714 } else { 715 int64_t bitrate; 716 if (getBitrate(&bitrate)) { 717 size_t cachedSize = mCachedSource->cachedSize(); 718 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; 719 720 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 721 if (percentage > 100) { 722 percentage = 100; 723 } 724 725 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 726 } else { 727 // We don't know the bitrate of the stream, use absolute size 728 // limits to maintain the cache. 729 730 if ((mFlags & PLAYING) && !eos 731 && (cachedDataRemaining < kLowWaterMarkBytes)) { 732 ALOGI("cache is running low (< %zu) , pausing.", 733 kLowWaterMarkBytes); 734 modifyFlags(CACHE_UNDERRUN, SET); 735 pause_l(); 736 ensureCacheIsFetching_l(); 737 sendCacheStats(); 738 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 739 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { 740 if (mFlags & CACHE_UNDERRUN) { 741 ALOGI("cache has filled up (> %zu), resuming.", 742 kHighWaterMarkBytes); 743 modifyFlags(CACHE_UNDERRUN, CLEAR); 744 play_l(); 745 } else if (mFlags & PREPARING) { 746 ALOGV("cache has filled up (> %zu), prepare is done", 747 kHighWaterMarkBytes); 748 finishAsyncPrepare_l(); 749 } 750 } 751 } 752 } 753 } else if (mWVMExtractor != NULL) { 754 status_t finalStatus; 755 756 int64_t cachedDurationUs 757 = mWVMExtractor->getCachedDurationUs(&finalStatus); 758 759 bool eos = (finalStatus != OK); 760 761 if (eos) { 762 if (finalStatus == ERROR_END_OF_STREAM) { 763 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 764 } 765 if (mFlags & PREPARING) { 766 ALOGV("cache has reached EOS, prepare is done."); 767 finishAsyncPrepare_l(); 768 } 769 } else { 770 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 771 if (percentage > 100) { 772 percentage = 100; 773 } 774 775 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 776 } 777 } 778 779 int64_t cachedDurationUs; 780 bool eos; 781 if (getCachedDuration_l(&cachedDurationUs, &eos)) { 782 ALOGV("cachedDurationUs = %.2f secs, eos=%d", 783 cachedDurationUs / 1E6, eos); 784 785 if ((mFlags & PLAYING) && !eos 786 && (cachedDurationUs < kLowWaterMarkUs)) { 787 modifyFlags(CACHE_UNDERRUN, SET); 788 ALOGI("cache is running low (%.2f secs) , pausing.", 789 cachedDurationUs / 1E6); 790 pause_l(); 791 ensureCacheIsFetching_l(); 792 sendCacheStats(); 793 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 794 } else if (eos || cachedDurationUs > kHighWaterMarkUs) { 795 if (mFlags & CACHE_UNDERRUN) { 796 modifyFlags(CACHE_UNDERRUN, CLEAR); 797 ALOGI("cache has filled up (%.2f secs), resuming.", 798 cachedDurationUs / 1E6); 799 play_l(); 800 } else if (mFlags & PREPARING) { 801 ALOGV("cache has filled up (%.2f secs), prepare is done", 802 cachedDurationUs / 1E6); 803 finishAsyncPrepare_l(); 804 } 805 } 806 } 807 808 if (mFlags & (PLAYING | PREPARING | CACHE_UNDERRUN)) { 809 postBufferingEvent_l(); 810 } 811} 812 813void AwesomePlayer::sendCacheStats() { 814 sp<MediaPlayerBase> listener = mListener.promote(); 815 if (listener != NULL) { 816 int32_t kbps = 0; 817 status_t err = UNKNOWN_ERROR; 818 if (mCachedSource != NULL) { 819 err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 820 } else if (mWVMExtractor != NULL) { 821 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); 822 } 823 if (err == OK) { 824 listener->sendEvent( 825 MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps); 826 } 827 } 828} 829 830void AwesomePlayer::onStreamDone() { 831 // Posted whenever any stream finishes playing. 832 ATRACE_CALL(); 833 834 Mutex::Autolock autoLock(mLock); 835 if (!mStreamDoneEventPending) { 836 return; 837 } 838 mStreamDoneEventPending = false; 839 840 if (mStreamDoneStatus != ERROR_END_OF_STREAM) { 841 ALOGV("MEDIA_ERROR %d", mStreamDoneStatus); 842 843 notifyListener_l( 844 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus); 845 846 pause_l(true /* at eos */); 847 848 modifyFlags(AT_EOS, SET); 849 return; 850 } 851 852 const bool allDone = 853 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS)) 854 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS)); 855 856 if (!allDone) { 857 return; 858 } 859 860 if ((mFlags & LOOPING) 861 || ((mFlags & AUTO_LOOPING) 862 && (mAudioSink == NULL || mAudioSink->realtime()))) { 863 // Don't AUTO_LOOP if we're being recorded, since that cannot be 864 // turned off and recording would go on indefinitely. 865 866 seekTo_l(0); 867 868 if (mVideoSource != NULL) { 869 postVideoEvent_l(); 870 } 871 } else { 872 ALOGV("MEDIA_PLAYBACK_COMPLETE"); 873 notifyListener_l(MEDIA_PLAYBACK_COMPLETE); 874 875 pause_l(true /* at eos */); 876 877 // If audio hasn't completed MEDIA_SEEK_COMPLETE yet, 878 // notify MEDIA_SEEK_COMPLETE to observer immediately for state persistence. 879 if (mWatchForAudioSeekComplete) { 880 notifyListener_l(MEDIA_SEEK_COMPLETE); 881 mWatchForAudioSeekComplete = false; 882 } 883 884 modifyFlags(AT_EOS, SET); 885 } 886} 887 888status_t AwesomePlayer::play() { 889 ATRACE_CALL(); 890 891 Mutex::Autolock autoLock(mLock); 892 893 modifyFlags(CACHE_UNDERRUN, CLEAR); 894 895 return play_l(); 896} 897 898status_t AwesomePlayer::play_l() { 899 modifyFlags(SEEK_PREVIEW, CLEAR); 900 901 if (mFlags & PLAYING) { 902 return OK; 903 } 904 905 mMediaRenderingStartGeneration = ++mStartGeneration; 906 907 if (!(mFlags & PREPARED)) { 908 status_t err = prepare_l(); 909 910 if (err != OK) { 911 return err; 912 } 913 } 914 915 modifyFlags(PLAYING, SET); 916 modifyFlags(FIRST_FRAME, SET); 917 918 if (mDecryptHandle != NULL) { 919 int64_t position; 920 getPosition(&position); 921 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 922 Playback::START, position / 1000); 923 } 924 925 if (mAudioSource != NULL) { 926 if (mAudioPlayer == NULL) { 927 createAudioPlayer_l(); 928 } 929 930 CHECK(!(mFlags & AUDIO_RUNNING)); 931 932 if (mVideoSource == NULL) { 933 934 // We don't want to post an error notification at this point, 935 // the error returned from MediaPlayer::start() will suffice. 936 937 status_t err = startAudioPlayer_l( 938 false /* sendErrorNotification */); 939 940 if ((err != OK) && mOffloadAudio) { 941 ALOGI("play_l() cannot create offload output, fallback to sw decode"); 942 int64_t curTimeUs; 943 getPosition(&curTimeUs); 944 945 delete mAudioPlayer; 946 mAudioPlayer = NULL; 947 // if the player was started it will take care of stopping the source when destroyed 948 if (!(mFlags & AUDIOPLAYER_STARTED)) { 949 mAudioSource->stop(); 950 } 951 modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR); 952 mOffloadAudio = false; 953 mAudioSource = mOmxSource; 954 if (mAudioSource != NULL) { 955 err = mAudioSource->start(); 956 957 if (err != OK) { 958 mAudioSource.clear(); 959 } else { 960 mSeekNotificationSent = true; 961 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 962 seekTo_l(curTimeUs); 963 } 964 createAudioPlayer_l(); 965 err = startAudioPlayer_l(false); 966 } 967 } 968 } 969 970 if (err != OK) { 971 delete mAudioPlayer; 972 mAudioPlayer = NULL; 973 974 modifyFlags((PLAYING | FIRST_FRAME), CLEAR); 975 976 if (mDecryptHandle != NULL) { 977 mDrmManagerClient->setPlaybackStatus( 978 mDecryptHandle, Playback::STOP, 0); 979 } 980 981 return err; 982 } 983 } 984 } 985 986 if (mTimeSource == NULL && mAudioPlayer == NULL) { 987 mTimeSource = &mSystemTimeSource; 988 } 989 990 if (mVideoSource != NULL) { 991 // Kick off video playback 992 postVideoEvent_l(); 993 994 if (mAudioSource != NULL && mVideoSource != NULL) { 995 postVideoLagEvent_l(); 996 } 997 } 998 999 if (mFlags & AT_EOS) { 1000 // Legacy behaviour, if a stream finishes playing and then 1001 // is started again, we play from the start... 1002 seekTo_l(0); 1003 } 1004 1005 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted 1006 | IMediaPlayerService::kBatteryDataTrackDecoder; 1007 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1008 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1009 } 1010 if (mVideoSource != NULL) { 1011 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1012 } 1013 addBatteryData(params); 1014 1015 if (isStreamingHTTP()) { 1016 postBufferingEvent_l(); 1017 } 1018 1019 return OK; 1020} 1021 1022void AwesomePlayer::createAudioPlayer_l() 1023{ 1024 uint32_t flags = 0; 1025 int64_t cachedDurationUs; 1026 bool eos; 1027 1028 if (mOffloadAudio) { 1029 flags |= AudioPlayer::USE_OFFLOAD; 1030 } else if (mVideoSource == NULL 1031 && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US || 1032 (getCachedDuration_l(&cachedDurationUs, &eos) && 1033 cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) { 1034 flags |= AudioPlayer::ALLOW_DEEP_BUFFERING; 1035 } 1036 if (isStreamingHTTP()) { 1037 flags |= AudioPlayer::IS_STREAMING; 1038 } 1039 if (mVideoSource != NULL) { 1040 flags |= AudioPlayer::HAS_VIDEO; 1041 } 1042 1043 mAudioPlayer = new AudioPlayer(mAudioSink, flags, this); 1044 mAudioPlayer->setSource(mAudioSource); 1045 1046 mTimeSource = mAudioPlayer; 1047 1048 // If there was a seek request before we ever started, 1049 // honor the request now. 1050 // Make sure to do this before starting the audio player 1051 // to avoid a race condition. 1052 seekAudioIfNecessary_l(); 1053} 1054 1055void AwesomePlayer::notifyIfMediaStarted_l() { 1056 if (mMediaRenderingStartGeneration == mStartGeneration) { 1057 mMediaRenderingStartGeneration = -1; 1058 notifyListener_l(MEDIA_STARTED); 1059 } 1060} 1061 1062status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) { 1063 CHECK(!(mFlags & AUDIO_RUNNING)); 1064 status_t err = OK; 1065 1066 if (mAudioSource == NULL || mAudioPlayer == NULL) { 1067 return OK; 1068 } 1069 1070 if (mOffloadAudio) { 1071 mQueue.cancelEvent(mAudioTearDownEvent->eventID()); 1072 mAudioTearDownEventPending = false; 1073 } 1074 1075 if (!(mFlags & AUDIOPLAYER_STARTED)) { 1076 bool wasSeeking = mAudioPlayer->isSeeking(); 1077 1078 // We've already started the MediaSource in order to enable 1079 // the prefetcher to read its data. 1080 err = mAudioPlayer->start( 1081 true /* sourceAlreadyStarted */); 1082 1083 if (err != OK) { 1084 if (sendErrorNotification) { 1085 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 1086 } 1087 1088 return err; 1089 } 1090 1091 modifyFlags(AUDIOPLAYER_STARTED, SET); 1092 1093 if (wasSeeking) { 1094 CHECK(!mAudioPlayer->isSeeking()); 1095 1096 // We will have finished the seek while starting the audio player. 1097 postAudioSeekComplete(); 1098 } else { 1099 notifyIfMediaStarted_l(); 1100 } 1101 } else { 1102 err = mAudioPlayer->resume(); 1103 } 1104 1105 if (err == OK) { 1106 modifyFlags(AUDIO_RUNNING, SET); 1107 1108 mWatchForAudioEOS = true; 1109 } 1110 1111 return err; 1112} 1113 1114void AwesomePlayer::notifyVideoSize_l() { 1115 ATRACE_CALL(); 1116 sp<MetaData> meta = mVideoSource->getFormat(); 1117 1118 int32_t cropLeft, cropTop, cropRight, cropBottom; 1119 if (!meta->findRect( 1120 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) { 1121 int32_t width, height; 1122 CHECK(meta->findInt32(kKeyWidth, &width)); 1123 CHECK(meta->findInt32(kKeyHeight, &height)); 1124 1125 cropLeft = cropTop = 0; 1126 cropRight = width - 1; 1127 cropBottom = height - 1; 1128 1129 ALOGV("got dimensions only %d x %d", width, height); 1130 } else { 1131 ALOGV("got crop rect %d, %d, %d, %d", 1132 cropLeft, cropTop, cropRight, cropBottom); 1133 } 1134 1135 int32_t displayWidth; 1136 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) { 1137 ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth); 1138 mDisplayWidth = displayWidth; 1139 } 1140 int32_t displayHeight; 1141 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) { 1142 ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight); 1143 mDisplayHeight = displayHeight; 1144 } 1145 1146 int32_t usableWidth = cropRight - cropLeft + 1; 1147 int32_t usableHeight = cropBottom - cropTop + 1; 1148 if (mDisplayWidth != 0) { 1149 usableWidth = mDisplayWidth; 1150 } 1151 if (mDisplayHeight != 0) { 1152 usableHeight = mDisplayHeight; 1153 } 1154 1155 { 1156 Mutex::Autolock autoLock(mStatsLock); 1157 mStats.mVideoWidth = usableWidth; 1158 mStats.mVideoHeight = usableHeight; 1159 } 1160 1161 int32_t rotationDegrees; 1162 if (!mVideoTrack->getFormat()->findInt32( 1163 kKeyRotation, &rotationDegrees)) { 1164 rotationDegrees = 0; 1165 } 1166 1167 if (rotationDegrees == 90 || rotationDegrees == 270) { 1168 notifyListener_l( 1169 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth); 1170 } else { 1171 notifyListener_l( 1172 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight); 1173 } 1174} 1175 1176void AwesomePlayer::initRenderer_l() { 1177 ATRACE_CALL(); 1178 1179 if (mNativeWindow == NULL) { 1180 return; 1181 } 1182 1183 sp<MetaData> meta = mVideoSource->getFormat(); 1184 1185 int32_t format; 1186 const char *component; 1187 int32_t decodedWidth, decodedHeight; 1188 CHECK(meta->findInt32(kKeyColorFormat, &format)); 1189 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 1190 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 1191 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 1192 1193 int32_t rotationDegrees; 1194 if (!mVideoTrack->getFormat()->findInt32( 1195 kKeyRotation, &rotationDegrees)) { 1196 rotationDegrees = 0; 1197 } 1198 1199 mVideoRenderer.clear(); 1200 1201 // Must ensure that mVideoRenderer's destructor is actually executed 1202 // before creating a new one. 1203 IPCThreadState::self()->flushCommands(); 1204 1205 // Even if set scaling mode fails, we will continue anyway 1206 setVideoScalingMode_l(mVideoScalingMode); 1207 if (USE_SURFACE_ALLOC 1208 && !strncmp(component, "OMX.", 4) 1209 && strncmp(component, "OMX.google.", 11)) { 1210 // Hardware decoders avoid the CPU color conversion by decoding 1211 // directly to ANativeBuffers, so we must use a renderer that 1212 // just pushes those buffers to the ANativeWindow. 1213 mVideoRenderer = 1214 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees); 1215 } else { 1216 // Other decoders are instantiated locally and as a consequence 1217 // allocate their buffers in local address space. This renderer 1218 // then performs a color conversion and copy to get the data 1219 // into the ANativeBuffer. 1220 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta); 1221 } 1222} 1223 1224status_t AwesomePlayer::pause() { 1225 ATRACE_CALL(); 1226 1227 Mutex::Autolock autoLock(mLock); 1228 1229 modifyFlags(CACHE_UNDERRUN, CLEAR); 1230 1231 return pause_l(); 1232} 1233 1234status_t AwesomePlayer::pause_l(bool at_eos) { 1235 if (!(mFlags & PLAYING)) { 1236 if (mAudioTearDown && mAudioTearDownWasPlaying) { 1237 ALOGV("pause_l() during teardown and finishSetDataSource_l() mFlags %x" , mFlags); 1238 mAudioTearDownWasPlaying = false; 1239 notifyListener_l(MEDIA_PAUSED); 1240 mMediaRenderingStartGeneration = ++mStartGeneration; 1241 } 1242 return OK; 1243 } 1244 1245 notifyListener_l(MEDIA_PAUSED); 1246 mMediaRenderingStartGeneration = ++mStartGeneration; 1247 1248 cancelPlayerEvents(true /* keepNotifications */); 1249 1250 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1251 // If we played the audio stream to completion we 1252 // want to make sure that all samples remaining in the audio 1253 // track's queue are played out. 1254 mAudioPlayer->pause(at_eos /* playPendingSamples */); 1255 // send us a reminder to tear down the AudioPlayer if paused for too long. 1256 if (mOffloadAudio) { 1257 postAudioTearDownEvent(kOffloadPauseMaxUs); 1258 } 1259 modifyFlags(AUDIO_RUNNING, CLEAR); 1260 } 1261 1262 if (mFlags & TEXTPLAYER_INITIALIZED) { 1263 mTextDriver->pause(); 1264 modifyFlags(TEXT_RUNNING, CLEAR); 1265 } 1266 1267 modifyFlags(PLAYING, CLEAR); 1268 1269 if (mDecryptHandle != NULL) { 1270 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1271 Playback::PAUSE, 0); 1272 } 1273 1274 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 1275 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1276 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1277 } 1278 if (mVideoSource != NULL) { 1279 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1280 } 1281 1282 addBatteryData(params); 1283 1284 return OK; 1285} 1286 1287bool AwesomePlayer::isPlaying() const { 1288 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN); 1289} 1290 1291status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) { 1292 Mutex::Autolock autoLock(mLock); 1293 1294 status_t err; 1295 if (bufferProducer != NULL) { 1296 err = setNativeWindow_l(new Surface(bufferProducer)); 1297 } else { 1298 err = setNativeWindow_l(NULL); 1299 } 1300 1301 return err; 1302} 1303 1304void AwesomePlayer::shutdownVideoDecoder_l() { 1305 if (mVideoBuffer) { 1306 mVideoBuffer->release(); 1307 mVideoBuffer = NULL; 1308 } 1309 1310 mVideoSource->stop(); 1311 1312 // The following hack is necessary to ensure that the OMX 1313 // component is completely released by the time we may try 1314 // to instantiate it again. 1315 wp<MediaSource> tmp = mVideoSource; 1316 mVideoSource.clear(); 1317 while (tmp.promote() != NULL) { 1318 usleep(1000); 1319 } 1320 IPCThreadState::self()->flushCommands(); 1321 ALOGV("video decoder shutdown completed"); 1322} 1323 1324status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) { 1325 mNativeWindow = native; 1326 1327 if (mVideoSource == NULL) { 1328 return OK; 1329 } 1330 1331 ALOGV("attempting to reconfigure to use new surface"); 1332 1333 bool wasPlaying = (mFlags & PLAYING) != 0; 1334 1335 pause_l(); 1336 mVideoRenderer.clear(); 1337 1338 shutdownVideoDecoder_l(); 1339 1340 status_t err = initVideoDecoder(); 1341 1342 if (err != OK) { 1343 ALOGE("failed to reinstantiate video decoder after surface change."); 1344 return err; 1345 } 1346 1347 if (mLastVideoTimeUs >= 0) { 1348 mSeeking = SEEK; 1349 mSeekTimeUs = mLastVideoTimeUs; 1350 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1351 } 1352 1353 if (wasPlaying) { 1354 play_l(); 1355 } 1356 1357 return OK; 1358} 1359 1360void AwesomePlayer::setAudioSink( 1361 const sp<MediaPlayerBase::AudioSink> &audioSink) { 1362 Mutex::Autolock autoLock(mLock); 1363 1364 mAudioSink = audioSink; 1365} 1366 1367status_t AwesomePlayer::setLooping(bool shouldLoop) { 1368 Mutex::Autolock autoLock(mLock); 1369 1370 modifyFlags(LOOPING, CLEAR); 1371 1372 if (shouldLoop) { 1373 modifyFlags(LOOPING, SET); 1374 } 1375 1376 return OK; 1377} 1378 1379status_t AwesomePlayer::getDuration(int64_t *durationUs) { 1380 Mutex::Autolock autoLock(mMiscStateLock); 1381 1382 if (mDurationUs < 0) { 1383 return UNKNOWN_ERROR; 1384 } 1385 1386 *durationUs = mDurationUs; 1387 1388 return OK; 1389} 1390 1391status_t AwesomePlayer::getPosition(int64_t *positionUs) { 1392 if (mSeeking != NO_SEEK) { 1393 *positionUs = mSeekTimeUs; 1394 } else if (mVideoSource != NULL 1395 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) { 1396 Mutex::Autolock autoLock(mMiscStateLock); 1397 *positionUs = mVideoTimeUs; 1398 } else if (mAudioPlayer != NULL) { 1399 *positionUs = mAudioPlayer->getMediaTimeUs(); 1400 } else { 1401 *positionUs = 0; 1402 } 1403 return OK; 1404} 1405 1406status_t AwesomePlayer::seekTo(int64_t timeUs) { 1407 ATRACE_CALL(); 1408 1409 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 1410 Mutex::Autolock autoLock(mLock); 1411 return seekTo_l(timeUs); 1412 } 1413 1414 return OK; 1415} 1416 1417status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 1418 if (mFlags & CACHE_UNDERRUN) { 1419 modifyFlags(CACHE_UNDERRUN, CLEAR); 1420 play_l(); 1421 } 1422 1423 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) { 1424 // Video playback completed before, there's no pending 1425 // video event right now. In order for this new seek 1426 // to be honored, we need to post one. 1427 1428 postVideoEvent_l(); 1429 } 1430 1431 mSeeking = SEEK; 1432 mSeekNotificationSent = false; 1433 mSeekTimeUs = timeUs; 1434 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1435 1436 if (mFlags & PLAYING) { 1437 notifyListener_l(MEDIA_PAUSED); 1438 mMediaRenderingStartGeneration = ++mStartGeneration; 1439 } 1440 1441 seekAudioIfNecessary_l(); 1442 1443 if (mFlags & TEXTPLAYER_INITIALIZED) { 1444 mTextDriver->seekToAsync(mSeekTimeUs); 1445 } 1446 1447 if (!(mFlags & PLAYING)) { 1448 ALOGV("seeking while paused, sending SEEK_COMPLETE notification" 1449 " immediately."); 1450 1451 notifyListener_l(MEDIA_SEEK_COMPLETE); 1452 mSeekNotificationSent = true; 1453 1454 if ((mFlags & PREPARED) && mVideoSource != NULL) { 1455 modifyFlags(SEEK_PREVIEW, SET); 1456 postVideoEvent_l(); 1457 } 1458 } 1459 1460 return OK; 1461} 1462 1463void AwesomePlayer::seekAudioIfNecessary_l() { 1464 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) { 1465 mAudioPlayer->seekTo(mSeekTimeUs); 1466 1467 mWatchForAudioSeekComplete = true; 1468 mWatchForAudioEOS = true; 1469 1470 if (mDecryptHandle != NULL) { 1471 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1472 Playback::PAUSE, 0); 1473 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1474 Playback::START, mSeekTimeUs / 1000); 1475 } 1476 } 1477} 1478 1479void AwesomePlayer::setAudioSource(sp<MediaSource> source) { 1480 CHECK(source != NULL); 1481 1482 mAudioTrack = source; 1483} 1484 1485void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) { 1486 CHECK(source != NULL); 1487 1488 if (mTextDriver == NULL) { 1489 mTextDriver = new TimedTextDriver(mListener); 1490 } 1491 1492 mTextDriver->addInBandTextSource(trackIndex, source); 1493} 1494 1495status_t AwesomePlayer::initAudioDecoder() { 1496 ATRACE_CALL(); 1497 1498 sp<MetaData> meta = mAudioTrack->getFormat(); 1499 1500 const char *mime; 1501 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1502 // Check whether there is a hardware codec for this stream 1503 // This doesn't guarantee that the hardware has a free stream 1504 // but it avoids us attempting to open (and re-open) an offload 1505 // stream to hardware that doesn't have the necessary codec 1506 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; 1507 if (mAudioSink != NULL) { 1508 streamType = mAudioSink->getAudioStreamType(); 1509 } 1510 1511 mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), 1512 isStreamingHTTP(), streamType); 1513 1514 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { 1515 ALOGV("createAudioPlayer: bypass OMX (raw)"); 1516 mAudioSource = mAudioTrack; 1517 } else { 1518 // If offloading we still create a OMX decoder as a fall-back 1519 // but we don't start it 1520 mOmxSource = OMXCodec::Create( 1521 mClient.interface(), mAudioTrack->getFormat(), 1522 false, // createEncoder 1523 mAudioTrack); 1524 1525 if (mOffloadAudio) { 1526 ALOGV("createAudioPlayer: bypass OMX (offload)"); 1527 mAudioSource = mAudioTrack; 1528 } else { 1529 mAudioSource = mOmxSource; 1530 } 1531 } 1532 1533 if (mAudioSource != NULL) { 1534 int64_t durationUs; 1535 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1536 Mutex::Autolock autoLock(mMiscStateLock); 1537 if (mDurationUs < 0 || durationUs > mDurationUs) { 1538 mDurationUs = durationUs; 1539 } 1540 } 1541 1542 status_t err = mAudioSource->start(); 1543 1544 if (err != OK) { 1545 mAudioSource.clear(); 1546 mOmxSource.clear(); 1547 return err; 1548 } 1549 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) { 1550 // For legacy reasons we're simply going to ignore the absence 1551 // of an audio decoder for QCELP instead of aborting playback 1552 // altogether. 1553 return OK; 1554 } 1555 1556 if (mAudioSource != NULL) { 1557 Mutex::Autolock autoLock(mStatsLock); 1558 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 1559 const char *component; 1560 if (!mAudioSource->getFormat() 1561 ->findCString(kKeyDecoderComponent, &component)) { 1562 component = "none"; 1563 } 1564 1565 stat->mDecoderName = component; 1566 } 1567 1568 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 1569} 1570 1571void AwesomePlayer::setVideoSource(sp<MediaSource> source) { 1572 CHECK(source != NULL); 1573 1574 mVideoTrack = source; 1575} 1576 1577status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 1578 ATRACE_CALL(); 1579 1580 // Either the application or the DRM system can independently say 1581 // that there must be a hardware-protected path to an external video sink. 1582 // For now we always require a hardware-protected path to external video sink 1583 // if content is DRMed, but eventually this could be optional per DRM agent. 1584 // When the application wants protection, then 1585 // (USE_SURFACE_ALLOC && (mSurface != 0) && 1586 // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp)) 1587 // will be true, but that part is already handled by SurfaceFlinger. 1588 1589#ifdef DEBUG_HDCP 1590 // For debugging, we allow a system property to control the protected usage. 1591 // In case of uninitialized or unexpected property, we default to "DRM only". 1592 bool setProtectionBit = false; 1593 char value[PROPERTY_VALUE_MAX]; 1594 if (property_get("persist.sys.hdcp_checking", value, NULL)) { 1595 if (!strcmp(value, "never")) { 1596 // nop 1597 } else if (!strcmp(value, "always")) { 1598 setProtectionBit = true; 1599 } else if (!strcmp(value, "drm-only")) { 1600 if (mDecryptHandle != NULL) { 1601 setProtectionBit = true; 1602 } 1603 // property value is empty, or unexpected value 1604 } else { 1605 if (mDecryptHandle != NULL) { 1606 setProtectionBit = true; 1607 } 1608 } 1609 // can' read property value 1610 } else { 1611 if (mDecryptHandle != NULL) { 1612 setProtectionBit = true; 1613 } 1614 } 1615 // note that usage bit is already cleared, so no need to clear it in the "else" case 1616 if (setProtectionBit) { 1617 flags |= OMXCodec::kEnableGrallocUsageProtected; 1618 } 1619#else 1620 if (mDecryptHandle != NULL) { 1621 flags |= OMXCodec::kEnableGrallocUsageProtected; 1622 } 1623#endif 1624 ALOGV("initVideoDecoder flags=0x%x", flags); 1625 mVideoSource = OMXCodec::Create( 1626 mClient.interface(), mVideoTrack->getFormat(), 1627 false, // createEncoder 1628 mVideoTrack, 1629 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL); 1630 1631 if (mVideoSource != NULL) { 1632 int64_t durationUs; 1633 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1634 Mutex::Autolock autoLock(mMiscStateLock); 1635 if (mDurationUs < 0 || durationUs > mDurationUs) { 1636 mDurationUs = durationUs; 1637 } 1638 } 1639 1640 status_t err = mVideoSource->start(); 1641 1642 if (err != OK) { 1643 ALOGE("failed to start video source"); 1644 mVideoSource.clear(); 1645 return err; 1646 } 1647 } 1648 1649 if (mVideoSource != NULL) { 1650 const char *componentName; 1651 CHECK(mVideoSource->getFormat() 1652 ->findCString(kKeyDecoderComponent, &componentName)); 1653 1654 { 1655 Mutex::Autolock autoLock(mStatsLock); 1656 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 1657 1658 stat->mDecoderName = componentName; 1659 } 1660 1661 static const char *kPrefix = "OMX.Nvidia."; 1662 static const char *kSuffix = ".decode"; 1663 static const size_t kSuffixLength = strlen(kSuffix); 1664 1665 size_t componentNameLength = strlen(componentName); 1666 1667 if (!strncmp(componentName, kPrefix, strlen(kPrefix)) 1668 && componentNameLength >= kSuffixLength 1669 && !strcmp(&componentName[ 1670 componentNameLength - kSuffixLength], kSuffix)) { 1671 modifyFlags(SLOW_DECODER_HACK, SET); 1672 } 1673 } 1674 1675 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 1676} 1677 1678void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { 1679 ATRACE_CALL(); 1680 1681 if (mSeeking == SEEK_VIDEO_ONLY) { 1682 mSeeking = NO_SEEK; 1683 return; 1684 } 1685 1686 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) { 1687 return; 1688 } 1689 1690 // If we paused, then seeked, then resumed, it is possible that we have 1691 // signaled SEEK_COMPLETE at a copmletely different media time than where 1692 // we are now resuming. Signal new position to media time provider. 1693 // Cannot signal another SEEK_COMPLETE, as existing clients may not expect 1694 // multiple SEEK_COMPLETE responses to a single seek() request. 1695 if (mSeekNotificationSent && abs(mSeekTimeUs - videoTimeUs) > 10000) { 1696 // notify if we are resuming more than 10ms away from desired seek time 1697 notifyListener_l(MEDIA_SKIPPED); 1698 } 1699 1700 if (mAudioPlayer != NULL) { 1701 ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); 1702 1703 // If we don't have a video time, seek audio to the originally 1704 // requested seek time instead. 1705 1706 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs); 1707 mWatchForAudioSeekComplete = true; 1708 mWatchForAudioEOS = true; 1709 } else if (!mSeekNotificationSent) { 1710 // If we're playing video only, report seek complete now, 1711 // otherwise audio player will notify us later. 1712 notifyListener_l(MEDIA_SEEK_COMPLETE); 1713 mSeekNotificationSent = true; 1714 } 1715 1716 modifyFlags(FIRST_FRAME, SET); 1717 mSeeking = NO_SEEK; 1718 1719 if (mDecryptHandle != NULL) { 1720 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1721 Playback::PAUSE, 0); 1722 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1723 Playback::START, videoTimeUs / 1000); 1724 } 1725} 1726 1727void AwesomePlayer::onVideoEvent() { 1728 ATRACE_CALL(); 1729 Mutex::Autolock autoLock(mLock); 1730 if (!mVideoEventPending) { 1731 // The event has been cancelled in reset_l() but had already 1732 // been scheduled for execution at that time. 1733 return; 1734 } 1735 mVideoEventPending = false; 1736 1737 if (mSeeking != NO_SEEK) { 1738 if (mVideoBuffer) { 1739 mVideoBuffer->release(); 1740 mVideoBuffer = NULL; 1741 } 1742 1743 if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL 1744 && !(mFlags & SEEK_PREVIEW)) { 1745 // We're going to seek the video source first, followed by 1746 // the audio source. 1747 // In order to avoid jumps in the DataSource offset caused by 1748 // the audio codec prefetching data from the old locations 1749 // while the video codec is already reading data from the new 1750 // locations, we'll "pause" the audio source, causing it to 1751 // stop reading input data until a subsequent seek. 1752 1753 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1754 mAudioPlayer->pause(); 1755 1756 modifyFlags(AUDIO_RUNNING, CLEAR); 1757 } 1758 mAudioSource->pause(); 1759 } 1760 } 1761 1762 if (!mVideoBuffer) { 1763 MediaSource::ReadOptions options; 1764 if (mSeeking != NO_SEEK) { 1765 ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 1766 1767 options.setSeekTo( 1768 mSeekTimeUs, 1769 mSeeking == SEEK_VIDEO_ONLY 1770 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC 1771 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); 1772 } 1773 for (;;) { 1774 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1775 options.clearSeekTo(); 1776 1777 if (err != OK) { 1778 CHECK(mVideoBuffer == NULL); 1779 1780 if (err == INFO_FORMAT_CHANGED) { 1781 ALOGV("VideoSource signalled format change."); 1782 1783 notifyVideoSize_l(); 1784 1785 if (mVideoRenderer != NULL) { 1786 mVideoRendererIsPreview = false; 1787 initRenderer_l(); 1788 } 1789 continue; 1790 } 1791 1792 // So video playback is complete, but we may still have 1793 // a seek request pending that needs to be applied 1794 // to the audio track. 1795 if (mSeeking != NO_SEEK) { 1796 ALOGV("video stream ended while seeking!"); 1797 } 1798 finishSeekIfNecessary(-1); 1799 1800 if (mAudioPlayer != NULL 1801 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1802 startAudioPlayer_l(); 1803 } 1804 1805 modifyFlags(VIDEO_AT_EOS, SET); 1806 postStreamDoneEvent_l(err); 1807 return; 1808 } 1809 1810 if (mVideoBuffer->range_length() == 0) { 1811 // Some decoders, notably the PV AVC software decoder 1812 // return spurious empty buffers that we just want to ignore. 1813 1814 mVideoBuffer->release(); 1815 mVideoBuffer = NULL; 1816 continue; 1817 } 1818 1819 break; 1820 } 1821 1822 { 1823 Mutex::Autolock autoLock(mStatsLock); 1824 ++mStats.mNumVideoFramesDecoded; 1825 } 1826 } 1827 1828 int64_t timeUs; 1829 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 1830 1831 mLastVideoTimeUs = timeUs; 1832 1833 if (mSeeking == SEEK_VIDEO_ONLY) { 1834 if (mSeekTimeUs > timeUs) { 1835 ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us", 1836 mSeekTimeUs, timeUs); 1837 } 1838 } 1839 1840 { 1841 Mutex::Autolock autoLock(mMiscStateLock); 1842 mVideoTimeUs = timeUs; 1843 } 1844 1845 SeekType wasSeeking = mSeeking; 1846 finishSeekIfNecessary(timeUs); 1847 1848 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1849 status_t err = startAudioPlayer_l(); 1850 if (err != OK) { 1851 ALOGE("Starting the audio player failed w/ err %d", err); 1852 return; 1853 } 1854 } 1855 1856 if ((mFlags & TEXTPLAYER_INITIALIZED) 1857 && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) { 1858 mTextDriver->start(); 1859 modifyFlags(TEXT_RUNNING, SET); 1860 } 1861 1862 TimeSource *ts = 1863 ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED)) 1864 ? &mSystemTimeSource : mTimeSource; 1865 int64_t systemTimeUs = mSystemTimeSource.getRealTimeUs(); 1866 1867 if (mFlags & FIRST_FRAME) { 1868 modifyFlags(FIRST_FRAME, CLEAR); 1869 mSinceLastDropped = 0; 1870 mClockEstimator->reset(); 1871 mTimeSourceDeltaUs = estimateRealTimeUs(ts, systemTimeUs) - timeUs; 1872 } 1873 1874 int64_t realTimeUs, mediaTimeUs; 1875 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL 1876 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 1877 ALOGV("updating TSdelta (%" PRId64 " => %" PRId64 " change %" PRId64 ")", 1878 mTimeSourceDeltaUs, realTimeUs - mediaTimeUs, 1879 mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)); 1880 ATRACE_INT("TS delta change (ms)", (mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)) / 1E3); 1881 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 1882 } 1883 1884 if (wasSeeking == SEEK_VIDEO_ONLY) { 1885 int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs; 1886 1887 int64_t latenessUs = nowUs - timeUs; 1888 1889 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1890 1891 if (latenessUs > 0) { 1892 ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6); 1893 } 1894 } 1895 1896 if (wasSeeking == NO_SEEK) { 1897 // Let's display the first frame after seeking right away. 1898 1899 int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs; 1900 1901 int64_t latenessUs = nowUs - timeUs; 1902 1903 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1904 1905 if (latenessUs > 500000ll 1906 && mAudioPlayer != NULL 1907 && mAudioPlayer->getMediaTimeMapping( 1908 &realTimeUs, &mediaTimeUs)) { 1909 if (mWVMExtractor == NULL) { 1910 ALOGI("we're much too late (%.2f secs), video skipping ahead", 1911 latenessUs / 1E6); 1912 1913 mVideoBuffer->release(); 1914 mVideoBuffer = NULL; 1915 1916 mSeeking = SEEK_VIDEO_ONLY; 1917 mSeekTimeUs = mediaTimeUs; 1918 1919 postVideoEvent_l(); 1920 return; 1921 } else { 1922 // The widevine extractor doesn't deal well with seeking 1923 // audio and video independently. We'll just have to wait 1924 // until the decoder catches up, which won't be long at all. 1925 ALOGI("we're very late (%.2f secs)", latenessUs / 1E6); 1926 } 1927 } 1928 1929 if (latenessUs > 40000) { 1930 // We're more than 40ms late. 1931 ALOGV("we're late by %lld us (%.2f secs)", 1932 latenessUs, latenessUs / 1E6); 1933 1934 if (!(mFlags & SLOW_DECODER_HACK) 1935 || mSinceLastDropped > FRAME_DROP_FREQ) 1936 { 1937 ALOGV("we're late by %lld us (%.2f secs) dropping " 1938 "one after %d frames", 1939 latenessUs, latenessUs / 1E6, mSinceLastDropped); 1940 1941 mSinceLastDropped = 0; 1942 mVideoBuffer->release(); 1943 mVideoBuffer = NULL; 1944 1945 { 1946 Mutex::Autolock autoLock(mStatsLock); 1947 ++mStats.mNumVideoFramesDropped; 1948 } 1949 1950 postVideoEvent_l(0); 1951 return; 1952 } 1953 } 1954 1955 if (latenessUs < -10000) { 1956 // We're more than 10ms early. Try to schedule at least 12ms 1957 // early (to hit this same check), or just on time. 1958 postVideoEvent_l(latenessUs < -22000 ? 10000 : -latenessUs); 1959 return; 1960 } 1961 } 1962 1963 if ((mNativeWindow != NULL) 1964 && (mVideoRendererIsPreview || mVideoRenderer == NULL)) { 1965 mVideoRendererIsPreview = false; 1966 1967 initRenderer_l(); 1968 } 1969 1970 if (mVideoRenderer != NULL) { 1971 mSinceLastDropped++; 1972 mVideoRenderer->render(mVideoBuffer); 1973 if (!mVideoRenderingStarted) { 1974 mVideoRenderingStarted = true; 1975 notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START); 1976 } 1977 1978 if (mFlags & PLAYING) { 1979 notifyIfMediaStarted_l(); 1980 } 1981 } 1982 1983 mVideoBuffer->release(); 1984 mVideoBuffer = NULL; 1985 1986 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) { 1987 modifyFlags(SEEK_PREVIEW, CLEAR); 1988 return; 1989 } 1990 1991 /* get next frame time */ 1992 if (wasSeeking == NO_SEEK) { 1993 MediaSource::ReadOptions options; 1994 for (;;) { 1995 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1996 if (err != OK) { 1997 // deal with any errors next time 1998 CHECK(mVideoBuffer == NULL); 1999 postVideoEvent_l(0); 2000 return; 2001 } 2002 2003 if (mVideoBuffer->range_length() != 0) { 2004 break; 2005 } 2006 2007 // Some decoders, notably the PV AVC software decoder 2008 // return spurious empty buffers that we just want to ignore. 2009 2010 mVideoBuffer->release(); 2011 mVideoBuffer = NULL; 2012 } 2013 2014 { 2015 Mutex::Autolock autoLock(mStatsLock); 2016 ++mStats.mNumVideoFramesDecoded; 2017 } 2018 2019 int64_t nextTimeUs; 2020 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs)); 2021 systemTimeUs = mSystemTimeSource.getRealTimeUs(); 2022 int64_t delayUs = nextTimeUs - estimateRealTimeUs(ts, systemTimeUs) + mTimeSourceDeltaUs; 2023 ATRACE_INT("Frame delta (ms)", (nextTimeUs - timeUs) / 1E3); 2024 ALOGV("next frame in %" PRId64, delayUs); 2025 // try to schedule at least 12ms before due time, or just on time 2026 postVideoEvent_l(delayUs > 22000 ? 10000 : delayUs < 0 ? 0 : delayUs); 2027 return; 2028 } 2029 2030 postVideoEvent_l(); 2031} 2032 2033int64_t AwesomePlayer::estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs) { 2034 if (ts == &mSystemTimeSource) { 2035 return systemTimeUs; 2036 } else { 2037 return (int64_t)mClockEstimator->estimate(systemTimeUs, ts->getRealTimeUs()); 2038 } 2039} 2040 2041void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 2042 ATRACE_CALL(); 2043 2044 if (mVideoEventPending) { 2045 return; 2046 } 2047 2048 mVideoEventPending = true; 2049 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 2050} 2051 2052void AwesomePlayer::postStreamDoneEvent_l(status_t status) { 2053 if (mStreamDoneEventPending) { 2054 return; 2055 } 2056 mStreamDoneEventPending = true; 2057 2058 mStreamDoneStatus = status; 2059 mQueue.postEvent(mStreamDoneEvent); 2060} 2061 2062void AwesomePlayer::postBufferingEvent_l() { 2063 if (mBufferingEventPending) { 2064 return; 2065 } 2066 mBufferingEventPending = true; 2067 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 2068} 2069 2070void AwesomePlayer::postVideoLagEvent_l() { 2071 if (mVideoLagEventPending) { 2072 return; 2073 } 2074 mVideoLagEventPending = true; 2075 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); 2076} 2077 2078void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) { 2079 Mutex::Autolock autoLock(mAudioLock); 2080 if (mAudioStatusEventPending) { 2081 return; 2082 } 2083 mAudioStatusEventPending = true; 2084 // Do not honor delay when looping in order to limit audio gap 2085 if (mFlags & (LOOPING | AUTO_LOOPING)) { 2086 delayUs = 0; 2087 } 2088 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs); 2089} 2090 2091void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) { 2092 Mutex::Autolock autoLock(mAudioLock); 2093 if (mAudioTearDownEventPending) { 2094 return; 2095 } 2096 mAudioTearDownEventPending = true; 2097 mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs); 2098} 2099 2100void AwesomePlayer::onCheckAudioStatus() { 2101 { 2102 Mutex::Autolock autoLock(mAudioLock); 2103 if (!mAudioStatusEventPending) { 2104 // Event was dispatched and while we were blocking on the mutex, 2105 // has already been cancelled. 2106 return; 2107 } 2108 2109 mAudioStatusEventPending = false; 2110 } 2111 2112 Mutex::Autolock autoLock(mLock); 2113 2114 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 2115 mWatchForAudioSeekComplete = false; 2116 2117 if (!mSeekNotificationSent) { 2118 notifyListener_l(MEDIA_SEEK_COMPLETE); 2119 mSeekNotificationSent = true; 2120 } 2121 2122 if (mVideoSource == NULL) { 2123 // For video the mSeeking flag is always reset in finishSeekIfNecessary 2124 mSeeking = NO_SEEK; 2125 } 2126 2127 notifyIfMediaStarted_l(); 2128 } 2129 2130 status_t finalStatus; 2131 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { 2132 mWatchForAudioEOS = false; 2133 modifyFlags(AUDIO_AT_EOS, SET); 2134 modifyFlags(FIRST_FRAME, SET); 2135 postStreamDoneEvent_l(finalStatus); 2136 } 2137} 2138 2139status_t AwesomePlayer::prepare() { 2140 ATRACE_CALL(); 2141 Mutex::Autolock autoLock(mLock); 2142 return prepare_l(); 2143} 2144 2145status_t AwesomePlayer::prepare_l() { 2146 if (mFlags & PREPARED) { 2147 return OK; 2148 } 2149 2150 if (mFlags & PREPARING) { 2151 return UNKNOWN_ERROR; 2152 } 2153 2154 mIsAsyncPrepare = false; 2155 status_t err = prepareAsync_l(); 2156 2157 if (err != OK) { 2158 return err; 2159 } 2160 2161 while (mFlags & PREPARING) { 2162 mPreparedCondition.wait(mLock); 2163 } 2164 2165 return mPrepareResult; 2166} 2167 2168status_t AwesomePlayer::prepareAsync() { 2169 ATRACE_CALL(); 2170 Mutex::Autolock autoLock(mLock); 2171 2172 if (mFlags & PREPARING) { 2173 return UNKNOWN_ERROR; // async prepare already pending 2174 } 2175 2176 mIsAsyncPrepare = true; 2177 return prepareAsync_l(); 2178} 2179 2180status_t AwesomePlayer::prepareAsync_l() { 2181 if (mFlags & PREPARING) { 2182 return UNKNOWN_ERROR; // async prepare already pending 2183 } 2184 2185 if (!mQueueStarted) { 2186 mQueue.start(); 2187 mQueueStarted = true; 2188 } 2189 2190 modifyFlags(PREPARING, SET); 2191 mAsyncPrepareEvent = new AwesomeEvent( 2192 this, &AwesomePlayer::onPrepareAsyncEvent); 2193 2194 mQueue.postEvent(mAsyncPrepareEvent); 2195 2196 return OK; 2197} 2198 2199status_t AwesomePlayer::finishSetDataSource_l() { 2200 ATRACE_CALL(); 2201 sp<DataSource> dataSource; 2202 2203 bool isWidevineStreaming = false; 2204 if (!strncasecmp("widevine://", mUri.string(), 11)) { 2205 isWidevineStreaming = true; 2206 2207 String8 newURI = String8("http://"); 2208 newURI.append(mUri.string() + 11); 2209 2210 mUri = newURI; 2211 } 2212 2213 AString sniffedMIME; 2214 2215 if (!strncasecmp("http://", mUri.string(), 7) 2216 || !strncasecmp("https://", mUri.string(), 8) 2217 || isWidevineStreaming) { 2218 mConnectingDataSource = HTTPBase::Create( 2219 (mFlags & INCOGNITO) 2220 ? HTTPBase::kFlagIncognito 2221 : 0); 2222 2223 if (mUIDValid) { 2224 mConnectingDataSource->setUID(mUID); 2225 } 2226 2227 String8 cacheConfig; 2228 bool disconnectAtHighwatermark; 2229 NuCachedSource2::RemoveCacheSpecificHeaders( 2230 &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark); 2231 2232 mLock.unlock(); 2233 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); 2234 mLock.lock(); 2235 2236 if (err != OK) { 2237 mConnectingDataSource.clear(); 2238 2239 ALOGI("mConnectingDataSource->connect() returned %d", err); 2240 return err; 2241 } 2242 2243 if (!isWidevineStreaming) { 2244 // The widevine extractor does its own caching. 2245 2246#if 0 2247 mCachedSource = new NuCachedSource2( 2248 new ThrottledSource( 2249 mConnectingDataSource, 50 * 1024 /* bytes/sec */)); 2250#else 2251 mCachedSource = new NuCachedSource2( 2252 mConnectingDataSource, 2253 cacheConfig.isEmpty() ? NULL : cacheConfig.string(), 2254 disconnectAtHighwatermark); 2255#endif 2256 2257 dataSource = mCachedSource; 2258 } else { 2259 dataSource = mConnectingDataSource; 2260 } 2261 2262 mConnectingDataSource.clear(); 2263 2264 String8 contentType = dataSource->getMIMEType(); 2265 2266 if (strncasecmp(contentType.string(), "audio/", 6)) { 2267 // We're not doing this for streams that appear to be audio-only 2268 // streams to ensure that even low bandwidth streams start 2269 // playing back fairly instantly. 2270 2271 // We're going to prefill the cache before trying to instantiate 2272 // the extractor below, as the latter is an operation that otherwise 2273 // could block on the datasource for a significant amount of time. 2274 // During that time we'd be unable to abort the preparation phase 2275 // without this prefill. 2276 if (mCachedSource != NULL) { 2277 // We're going to prefill the cache before trying to instantiate 2278 // the extractor below, as the latter is an operation that otherwise 2279 // could block on the datasource for a significant amount of time. 2280 // During that time we'd be unable to abort the preparation phase 2281 // without this prefill. 2282 2283 mLock.unlock(); 2284 2285 // Initially make sure we have at least 192 KB for the sniff 2286 // to complete without blocking. 2287 static const size_t kMinBytesForSniffing = 192 * 1024; 2288 2289 off64_t metaDataSize = -1ll; 2290 for (;;) { 2291 status_t finalStatus; 2292 size_t cachedDataRemaining = 2293 mCachedSource->approxDataRemaining(&finalStatus); 2294 2295 if (finalStatus != OK 2296 || (metaDataSize >= 0 2297 && cachedDataRemaining >= metaDataSize) 2298 || (mFlags & PREPARE_CANCELLED)) { 2299 break; 2300 } 2301 2302 ALOGV("now cached %d bytes of data", cachedDataRemaining); 2303 2304 if (metaDataSize < 0 2305 && cachedDataRemaining >= kMinBytesForSniffing) { 2306 String8 tmp; 2307 float confidence; 2308 sp<AMessage> meta; 2309 if (!dataSource->sniff(&tmp, &confidence, &meta)) { 2310 mLock.lock(); 2311 return UNKNOWN_ERROR; 2312 } 2313 2314 // We successfully identified the file's extractor to 2315 // be, remember this mime type so we don't have to 2316 // sniff it again when we call MediaExtractor::Create() 2317 // below. 2318 sniffedMIME = tmp.string(); 2319 2320 if (meta == NULL 2321 || !meta->findInt64("meta-data-size", 2322 reinterpret_cast<int64_t*>(&metaDataSize))) { 2323 metaDataSize = kHighWaterMarkBytes; 2324 } 2325 2326 CHECK_GE(metaDataSize, 0ll); 2327 ALOGV("metaDataSize = %lld bytes", metaDataSize); 2328 } 2329 2330 usleep(200000); 2331 } 2332 2333 mLock.lock(); 2334 } 2335 2336 if (mFlags & PREPARE_CANCELLED) { 2337 ALOGI("Prepare cancelled while waiting for initial cache fill."); 2338 return UNKNOWN_ERROR; 2339 } 2340 } 2341 } else { 2342 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); 2343 } 2344 2345 if (dataSource == NULL) { 2346 return UNKNOWN_ERROR; 2347 } 2348 2349 sp<MediaExtractor> extractor; 2350 2351 if (isWidevineStreaming) { 2352 String8 mimeType; 2353 float confidence; 2354 sp<AMessage> dummy; 2355 bool success; 2356 2357 // SniffWVM is potentially blocking since it may require network access. 2358 // Do not call it with mLock held. 2359 mLock.unlock(); 2360 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 2361 mLock.lock(); 2362 2363 if (!success 2364 || strcasecmp( 2365 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 2366 return ERROR_UNSUPPORTED; 2367 } 2368 2369 mWVMExtractor = new WVMExtractor(dataSource); 2370 mWVMExtractor->setAdaptiveStreamingMode(true); 2371 if (mUIDValid) 2372 mWVMExtractor->setUID(mUID); 2373 extractor = mWVMExtractor; 2374 } else { 2375 extractor = MediaExtractor::Create( 2376 dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); 2377 2378 if (extractor == NULL) { 2379 return UNKNOWN_ERROR; 2380 } 2381 } 2382 2383 if (extractor->getDrmFlag()) { 2384 checkDrmStatus(dataSource); 2385 } 2386 2387 status_t err = setDataSource_l(extractor); 2388 2389 if (err != OK) { 2390 mWVMExtractor.clear(); 2391 2392 return err; 2393 } 2394 2395 return OK; 2396} 2397 2398void AwesomePlayer::abortPrepare(status_t err) { 2399 CHECK(err != OK); 2400 2401 if (mIsAsyncPrepare) { 2402 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 2403 } 2404 2405 mPrepareResult = err; 2406 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2407 mAsyncPrepareEvent = NULL; 2408 mPreparedCondition.broadcast(); 2409 mAudioTearDown = false; 2410} 2411 2412// static 2413bool AwesomePlayer::ContinuePreparation(void *cookie) { 2414 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie); 2415 2416 return (me->mFlags & PREPARE_CANCELLED) == 0; 2417} 2418 2419void AwesomePlayer::onPrepareAsyncEvent() { 2420 Mutex::Autolock autoLock(mLock); 2421 beginPrepareAsync_l(); 2422} 2423 2424void AwesomePlayer::beginPrepareAsync_l() { 2425 if (mFlags & PREPARE_CANCELLED) { 2426 ALOGI("prepare was cancelled before doing anything"); 2427 abortPrepare(UNKNOWN_ERROR); 2428 return; 2429 } 2430 2431 if (mUri.size() > 0) { 2432 status_t err = finishSetDataSource_l(); 2433 2434 if (err != OK) { 2435 abortPrepare(err); 2436 return; 2437 } 2438 } 2439 2440 if (mVideoTrack != NULL && mVideoSource == NULL) { 2441 status_t err = initVideoDecoder(); 2442 2443 if (err != OK) { 2444 abortPrepare(err); 2445 return; 2446 } 2447 } 2448 2449 if (mAudioTrack != NULL && mAudioSource == NULL) { 2450 status_t err = initAudioDecoder(); 2451 2452 if (err != OK) { 2453 abortPrepare(err); 2454 return; 2455 } 2456 } 2457 2458 modifyFlags(PREPARING_CONNECTED, SET); 2459 2460 if (isStreamingHTTP()) { 2461 postBufferingEvent_l(); 2462 } else { 2463 finishAsyncPrepare_l(); 2464 } 2465} 2466 2467void AwesomePlayer::finishAsyncPrepare_l() { 2468 if (mIsAsyncPrepare) { 2469 if (mVideoSource == NULL) { 2470 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); 2471 } else { 2472 notifyVideoSize_l(); 2473 } 2474 2475 notifyListener_l(MEDIA_PREPARED); 2476 } 2477 2478 mPrepareResult = OK; 2479 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2480 modifyFlags(PREPARED, SET); 2481 mAsyncPrepareEvent = NULL; 2482 mPreparedCondition.broadcast(); 2483 2484 if (mAudioTearDown) { 2485 if (mPrepareResult == OK) { 2486 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 2487 seekTo_l(mAudioTearDownPosition); 2488 } 2489 2490 if (mAudioTearDownWasPlaying) { 2491 modifyFlags(CACHE_UNDERRUN, CLEAR); 2492 play_l(); 2493 } 2494 } 2495 mAudioTearDown = false; 2496 } 2497} 2498 2499uint32_t AwesomePlayer::flags() const { 2500 return mExtractorFlags; 2501} 2502 2503void AwesomePlayer::postAudioEOS(int64_t delayUs) { 2504 postCheckAudioStatusEvent(delayUs); 2505} 2506 2507void AwesomePlayer::postAudioSeekComplete() { 2508 postCheckAudioStatusEvent(0); 2509} 2510 2511void AwesomePlayer::postAudioTearDown() { 2512 postAudioTearDownEvent(0); 2513} 2514 2515status_t AwesomePlayer::setParameter(int key, const Parcel &request) { 2516 switch (key) { 2517 case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS: 2518 { 2519 return setCacheStatCollectFreq(request); 2520 } 2521 case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE: 2522 { 2523 if (mAudioPlayer != NULL) { 2524 return mAudioPlayer->setPlaybackRatePermille(request.readInt32()); 2525 } else { 2526 return NO_INIT; 2527 } 2528 } 2529 default: 2530 { 2531 return ERROR_UNSUPPORTED; 2532 } 2533 } 2534} 2535 2536status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) { 2537 if (mCachedSource != NULL) { 2538 int32_t freqMs = request.readInt32(); 2539 ALOGD("Request to keep cache stats in the past %d ms", 2540 freqMs); 2541 return mCachedSource->setCacheStatCollectFreq(freqMs); 2542 } 2543 return ERROR_UNSUPPORTED; 2544} 2545 2546status_t AwesomePlayer::getParameter(int key, Parcel *reply) { 2547 switch (key) { 2548 case KEY_PARAMETER_AUDIO_CHANNEL_COUNT: 2549 { 2550 int32_t channelCount; 2551 if (mAudioTrack == 0 || 2552 !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) { 2553 channelCount = 0; 2554 } 2555 reply->writeInt32(channelCount); 2556 } 2557 return OK; 2558 default: 2559 { 2560 return ERROR_UNSUPPORTED; 2561 } 2562 } 2563} 2564 2565status_t AwesomePlayer::getTrackInfo(Parcel *reply) const { 2566 Mutex::Autolock autoLock(mLock); 2567 size_t trackCount = mExtractor->countTracks(); 2568 if (mTextDriver != NULL) { 2569 trackCount += mTextDriver->countExternalTracks(); 2570 } 2571 2572 reply->writeInt32(trackCount); 2573 for (size_t i = 0; i < mExtractor->countTracks(); ++i) { 2574 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 2575 2576 const char *_mime; 2577 CHECK(meta->findCString(kKeyMIMEType, &_mime)); 2578 2579 String8 mime = String8(_mime); 2580 2581 reply->writeInt32(2); // 2 fields 2582 2583 if (!strncasecmp(mime.string(), "video/", 6)) { 2584 reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO); 2585 } else if (!strncasecmp(mime.string(), "audio/", 6)) { 2586 reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO); 2587 } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { 2588 reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT); 2589 } else { 2590 reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN); 2591 } 2592 2593 const char *lang; 2594 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 2595 lang = "und"; 2596 } 2597 reply->writeString16(String16(lang)); 2598 } 2599 2600 if (mTextDriver != NULL) { 2601 mTextDriver->getExternalTrackInfo(reply); 2602 } 2603 return OK; 2604} 2605 2606status_t AwesomePlayer::selectAudioTrack_l( 2607 const sp<MediaSource>& source, size_t trackIndex) { 2608 2609 ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags); 2610 2611 { 2612 Mutex::Autolock autoLock(mStatsLock); 2613 if ((ssize_t)trackIndex == mActiveAudioTrackIndex) { 2614 ALOGI("Track %zu is active. Does nothing.", trackIndex); 2615 return OK; 2616 } 2617 //mStats.mFlags = mFlags; 2618 } 2619 2620 if (mSeeking != NO_SEEK) { 2621 ALOGE("Selecting a track while seeking is not supported"); 2622 return ERROR_UNSUPPORTED; 2623 } 2624 2625 if ((mFlags & PREPARED) == 0) { 2626 ALOGE("Data source has not finished preparation"); 2627 return ERROR_UNSUPPORTED; 2628 } 2629 2630 CHECK(source != NULL); 2631 bool wasPlaying = (mFlags & PLAYING) != 0; 2632 2633 pause_l(); 2634 2635 int64_t curTimeUs; 2636 CHECK_EQ(getPosition(&curTimeUs), (status_t)OK); 2637 2638 if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED)) 2639 && mAudioSource != NULL) { 2640 // If we had an audio player, it would have effectively 2641 // taken possession of the audio source and stopped it when 2642 // _it_ is stopped. Otherwise this is still our responsibility. 2643 mAudioSource->stop(); 2644 } 2645 mAudioSource.clear(); 2646 mOmxSource.clear(); 2647 2648 mTimeSource = NULL; 2649 2650 delete mAudioPlayer; 2651 mAudioPlayer = NULL; 2652 2653 modifyFlags(AUDIOPLAYER_STARTED, CLEAR); 2654 2655 setAudioSource(source); 2656 2657 modifyFlags(AUDIO_AT_EOS, CLEAR); 2658 modifyFlags(AT_EOS, CLEAR); 2659 2660 status_t err; 2661 if ((err = initAudioDecoder()) != OK) { 2662 ALOGE("Failed to init audio decoder: 0x%x", err); 2663 return err; 2664 } 2665 2666 mSeekNotificationSent = true; 2667 seekTo_l(curTimeUs); 2668 2669 if (wasPlaying) { 2670 play_l(); 2671 } 2672 2673 mActiveAudioTrackIndex = trackIndex; 2674 2675 return OK; 2676} 2677 2678status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) { 2679 ATRACE_CALL(); 2680 ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select); 2681 Mutex::Autolock autoLock(mLock); 2682 size_t trackCount = mExtractor->countTracks(); 2683 if (mTextDriver != NULL) { 2684 trackCount += mTextDriver->countExternalTracks(); 2685 } 2686 if (trackIndex >= trackCount) { 2687 ALOGE("Track index (%zu) is out of range [0, %zu)", trackIndex, trackCount); 2688 return ERROR_OUT_OF_RANGE; 2689 } 2690 2691 bool isAudioTrack = false; 2692 if (trackIndex < mExtractor->countTracks()) { 2693 sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex); 2694 const char *mime; 2695 CHECK(meta->findCString(kKeyMIMEType, &mime)); 2696 isAudioTrack = !strncasecmp(mime, "audio/", 6); 2697 2698 if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) { 2699 ALOGE("Track %zu is not either audio or timed text", trackIndex); 2700 return ERROR_UNSUPPORTED; 2701 } 2702 } 2703 2704 if (isAudioTrack) { 2705 if (!select) { 2706 ALOGE("Deselect an audio track (%zu) is not supported", trackIndex); 2707 return ERROR_UNSUPPORTED; 2708 } 2709 return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex); 2710 } 2711 2712 // Timed text track handling 2713 if (mTextDriver == NULL) { 2714 return INVALID_OPERATION; 2715 } 2716 2717 status_t err = OK; 2718 if (select) { 2719 err = mTextDriver->selectTrack(trackIndex); 2720 if (err == OK) { 2721 modifyFlags(TEXTPLAYER_INITIALIZED, SET); 2722 if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) { 2723 mTextDriver->start(); 2724 modifyFlags(TEXT_RUNNING, SET); 2725 } 2726 } 2727 } else { 2728 err = mTextDriver->unselectTrack(trackIndex); 2729 if (err == OK) { 2730 modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR); 2731 modifyFlags(TEXT_RUNNING, CLEAR); 2732 } 2733 } 2734 return err; 2735} 2736 2737size_t AwesomePlayer::countTracks() const { 2738 return mExtractor->countTracks() + mTextDriver->countExternalTracks(); 2739} 2740 2741status_t AwesomePlayer::setVideoScalingMode(int32_t mode) { 2742 Mutex::Autolock lock(mLock); 2743 return setVideoScalingMode_l(mode); 2744} 2745 2746status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) { 2747 mVideoScalingMode = mode; 2748 if (mNativeWindow != NULL) { 2749 status_t err = native_window_set_scaling_mode( 2750 mNativeWindow.get(), mVideoScalingMode); 2751 if (err != OK) { 2752 ALOGW("Failed to set scaling mode: %d", err); 2753 } 2754 return err; 2755 } 2756 return OK; 2757} 2758 2759status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { 2760 ATRACE_CALL(); 2761 if (NULL == reply) { 2762 return android::BAD_VALUE; 2763 } 2764 int32_t methodId; 2765 status_t ret = request.readInt32(&methodId); 2766 if (ret != android::OK) { 2767 return ret; 2768 } 2769 switch(methodId) { 2770 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 2771 { 2772 int mode = request.readInt32(); 2773 return setVideoScalingMode(mode); 2774 } 2775 2776 case INVOKE_ID_GET_TRACK_INFO: 2777 { 2778 return getTrackInfo(reply); 2779 } 2780 case INVOKE_ID_ADD_EXTERNAL_SOURCE: 2781 { 2782 Mutex::Autolock autoLock(mLock); 2783 if (mTextDriver == NULL) { 2784 mTextDriver = new TimedTextDriver(mListener); 2785 } 2786 // String values written in Parcel are UTF-16 values. 2787 String8 uri(request.readString16()); 2788 String8 mimeType(request.readString16()); 2789 size_t nTracks = countTracks(); 2790 return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType); 2791 } 2792 case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD: 2793 { 2794 Mutex::Autolock autoLock(mLock); 2795 if (mTextDriver == NULL) { 2796 mTextDriver = new TimedTextDriver(mListener); 2797 } 2798 int fd = request.readFileDescriptor(); 2799 off64_t offset = request.readInt64(); 2800 off64_t length = request.readInt64(); 2801 String8 mimeType(request.readString16()); 2802 size_t nTracks = countTracks(); 2803 return mTextDriver->addOutOfBandTextSource( 2804 nTracks, fd, offset, length, mimeType); 2805 } 2806 case INVOKE_ID_SELECT_TRACK: 2807 { 2808 int trackIndex = request.readInt32(); 2809 return selectTrack(trackIndex, true /* select */); 2810 } 2811 case INVOKE_ID_UNSELECT_TRACK: 2812 { 2813 int trackIndex = request.readInt32(); 2814 return selectTrack(trackIndex, false /* select */); 2815 } 2816 default: 2817 { 2818 return ERROR_UNSUPPORTED; 2819 } 2820 } 2821 // It will not reach here. 2822 return OK; 2823} 2824 2825bool AwesomePlayer::isStreamingHTTP() const { 2826 return mCachedSource != NULL || mWVMExtractor != NULL; 2827} 2828 2829status_t AwesomePlayer::dump( 2830 int fd, const Vector<String16> & /* args */) const { 2831 Mutex::Autolock autoLock(mStatsLock); 2832 2833 FILE *out = fdopen(dup(fd), "w"); 2834 2835 fprintf(out, " AwesomePlayer\n"); 2836 if (mStats.mFd < 0) { 2837 fprintf(out, " URI(suppressed)"); 2838 } else { 2839 fprintf(out, " fd(%d)", mStats.mFd); 2840 } 2841 2842 fprintf(out, ", flags(0x%08x)", mStats.mFlags); 2843 2844 if (mStats.mBitrate >= 0) { 2845 fprintf(out, ", bitrate(%" PRId64 " bps)", mStats.mBitrate); 2846 } 2847 2848 fprintf(out, "\n"); 2849 2850 for (size_t i = 0; i < mStats.mTracks.size(); ++i) { 2851 const TrackStat &stat = mStats.mTracks.itemAt(i); 2852 2853 fprintf(out, " Track %zu\n", i + 1); 2854 fprintf(out, " MIME(%s)", stat.mMIME.string()); 2855 2856 if (!stat.mDecoderName.isEmpty()) { 2857 fprintf(out, ", decoder(%s)", stat.mDecoderName.string()); 2858 } 2859 2860 fprintf(out, "\n"); 2861 2862 if ((ssize_t)i == mStats.mVideoTrackIndex) { 2863 fprintf(out, 2864 " videoDimensions(%d x %d), " 2865 "numVideoFramesDecoded(%" PRId64 "), " 2866 "numVideoFramesDropped(%" PRId64 ")\n", 2867 mStats.mVideoWidth, 2868 mStats.mVideoHeight, 2869 mStats.mNumVideoFramesDecoded, 2870 mStats.mNumVideoFramesDropped); 2871 } 2872 } 2873 2874 fclose(out); 2875 out = NULL; 2876 2877 return OK; 2878} 2879 2880void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { 2881 switch (mode) { 2882 case SET: 2883 mFlags |= value; 2884 break; 2885 case CLEAR: 2886 if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) { 2887 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 2888 } 2889 mFlags &= ~value; 2890 break; 2891 case ASSIGN: 2892 mFlags = value; 2893 break; 2894 default: 2895 TRESPASS(); 2896 } 2897 2898 { 2899 Mutex::Autolock autoLock(mStatsLock); 2900 mStats.mFlags = mFlags; 2901 } 2902} 2903 2904void AwesomePlayer::onAudioTearDownEvent() { 2905 2906 Mutex::Autolock autoLock(mLock); 2907 if (!mAudioTearDownEventPending) { 2908 return; 2909 } 2910 mAudioTearDownEventPending = false; 2911 2912 ALOGV("onAudioTearDownEvent"); 2913 2914 // stream info is cleared by reset_l() so copy what we need 2915 mAudioTearDownWasPlaying = (mFlags & PLAYING); 2916 KeyedVector<String8, String8> uriHeaders(mUriHeaders); 2917 sp<DataSource> fileSource(mFileSource); 2918 2919 mStatsLock.lock(); 2920 String8 uri(mStats.mURI); 2921 mStatsLock.unlock(); 2922 2923 // get current position so we can start recreated stream from here 2924 getPosition(&mAudioTearDownPosition); 2925 2926 // Reset and recreate 2927 reset_l(); 2928 2929 status_t err; 2930 2931 if (fileSource != NULL) { 2932 mFileSource = fileSource; 2933 err = setDataSource_l(fileSource); 2934 } else { 2935 err = setDataSource_l(uri, &uriHeaders); 2936 } 2937 2938 mFlags |= PREPARING; 2939 if ( err != OK ) { 2940 // This will force beingPrepareAsync_l() to notify 2941 // a MEDIA_ERROR to the client and abort the prepare 2942 mFlags |= PREPARE_CANCELLED; 2943 } 2944 2945 mAudioTearDown = true; 2946 mIsAsyncPrepare = true; 2947 2948 // Call prepare for the host decoding 2949 beginPrepareAsync_l(); 2950} 2951 2952} // namespace android 2953