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