Remove MediaPlayer2
Bug: 141546997
Test: build, boot
Change-Id: Ie2a94aace8286a1fad4e9f59232f761bcab0cc5e
Merged-In: Ie2a94aace8286a1fad4e9f59232f761bcab0cc5e
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
deleted file mode 100644
index dca6bb6..0000000
--- a/media/libmediaplayer2/Android.bp
+++ /dev/null
@@ -1,129 +0,0 @@
-cc_library_headers {
- name: "libmediaplayer2_headers",
- vendor_available: true,
- export_include_dirs: ["include"],
-}
-
-cc_library_static {
- name: "libmediaplayer2",
-
- srcs: [
- "MediaPlayer2AudioOutput.cpp",
- "mediaplayer2.cpp",
- ],
-
- shared_libs: [
- "libandroid_runtime",
- "libaudioclient",
- "libbinder",
- "libbinder_ndk",
- "libcutils",
- "libgui",
- "liblog",
- "libmedia_omx",
- "libui",
- "libutils",
-
- "libcrypto",
- "libmediametrics",
- "libmediandk",
- "libmediandk_utils",
- "libmediautils",
- "libmemunreachable",
- "libnativewindow",
- "libpowermanager",
- "libstagefright_httplive",
- ],
-
- export_shared_lib_headers: [
- "libaudioclient",
- "libbinder",
- "libgui",
- "libmedia_omx",
- ],
-
- header_libs: [
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/base/core/jni",
- ],
-
- static_libs: [
- "libmedia_helper",
- "libmediaplayer2-protos",
- "libmedia_player2_util",
- "libprotobuf-cpp-lite",
- "libstagefright_foundation_without_imemory",
- "libstagefright_nuplayer2",
- "libstagefright_player2",
- "libstagefright_rtsp",
- "libstagefright_timedtext2",
- "libmedia2_jni_core",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-}
-
-cc_library {
- name: "libmedia2_jni_core",
-
- srcs: [
- "JavaVMHelper.cpp",
- "JAudioTrack.cpp",
- "JMedia2HTTPService.cpp",
- "JMedia2HTTPConnection.cpp",
- ],
-
- header_libs: [
- "libbinder_headers",
- "libnativehelper_header_only",
- ],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libdl",
- ],
-
- include_dirs: [
- "frameworks/av/media/libmedia/include",
- "frameworks/base/core/jni",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-
-}
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
deleted file mode 100644
index fab6c64..0000000
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "JAudioTrack"
-
-#include "media/JAudioAttributes.h"
-#include "media/JAudioFormat.h"
-#include "mediaplayer2/JAudioTrack.h"
-
-#include <android_media_AudioErrors.h>
-#include <mediaplayer2/JavaVMHelper.h>
-
-namespace android {
-
-// TODO: Store Java class/methodID as a member variable in the class.
-// TODO: Add NULL && Exception checks after every JNI call.
-JAudioTrack::JAudioTrack( // < Usages of the arguments are below >
- uint32_t sampleRate, // AudioFormat && bufferSizeInBytes
- audio_format_t format, // AudioFormat && bufferSizeInBytes
- audio_channel_mask_t channelMask, // AudioFormat && bufferSizeInBytes
- callback_t cbf, // Offload
- void* user, // Offload
- size_t frameCount, // bufferSizeInBytes
- int32_t sessionId, // AudioTrack
- const jobject attributes, // AudioAttributes
- float maxRequiredSpeed) { // bufferSizeInBytes
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
- mAudioTrackCls = reinterpret_cast<jclass>(env->NewGlobalRef(jAudioTrackCls));
- env->DeleteLocalRef(jAudioTrackCls);
-
- maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
-
- int bufferSizeInBytes = 0;
- if (sampleRate == 0 || frameCount > 0) {
- // Manually calculate buffer size.
- bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
- * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
- } else if (sampleRate > 0) {
- // Call Java AudioTrack::getMinBufferSize().
- jmethodID jGetMinBufferSize =
- env->GetStaticMethodID(mAudioTrackCls, "getMinBufferSize", "(III)I");
- bufferSizeInBytes = env->CallStaticIntMethod(mAudioTrackCls, jGetMinBufferSize,
- sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
- }
- bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);
-
- // Create a Java AudioTrack object through its Builder.
- jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- {
- sp<JObjectHolder> audioAttributesObj;
- if (attributes != NULL) {
- audioAttributesObj = new JObjectHolder(attributes);
- } else {
- audioAttributesObj = new JObjectHolder(
- JAudioAttributes::createAudioAttributesObj(env, NULL));
- }
- jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
- "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj,
- jSetAudioAttributes, audioAttributesObj->getJObject());
- }
-
- jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
- "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
- JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
-
- jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
-
- // We only use streaming mode of Java AudioTrack.
- jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
- jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
- jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
- transferMode /* Java AudioTrack::MODE_STREAM */);
-
- if (sessionId != 0) {
- jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
- }
-
- mFlags = AUDIO_OUTPUT_FLAG_NONE;
- if (cbf != NULL) {
- jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
- "(Z)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
- mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- }
-
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
- jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
- mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
- env->DeleteLocalRef(jBuilderObj);
-
- if (cbf != NULL) {
- // Set offload mode callback
- jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
- jobject jExecutorObj = createCallbackExecutor();
- jmethodID jSetStreamEventCallback = env->GetMethodID(
- jAudioTrackCls,
- "setStreamEventCallback",
- "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
- env->CallVoidMethod(
- mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
- }
-}
-
-JAudioTrack::~JAudioTrack() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mAudioTrackCls);
- env->DeleteGlobalRef(mAudioTrackObj);
-}
-
-size_t JAudioTrack::frameCount() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetBufferSizeInFrames = env->GetMethodID(
- mAudioTrackCls, "getBufferSizeInFrames", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
-}
-
-size_t JAudioTrack::channelCount() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
-}
-
-uint32_t JAudioTrack::latency() {
- // TODO: Currently hard-coded as returning zero.
- return 0;
-}
-
-status_t JAudioTrack::getPosition(uint32_t *position) {
- if (position == NULL) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
- mAudioTrackCls, "getPlaybackHeadPosition", "()I");
- *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
- jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
-
- jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
- jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
-
- jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
- "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
- bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
-
- if (!success) {
- return NO_INIT;
- }
-
- long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
- long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
-
- struct timespec ts;
- const long long secondToNano = 1000000000LL; // 1E9
- ts.tv_sec = nanoTime / secondToNano;
- ts.tv_nsec = nanoTime % secondToNano;
- timestamp.mTime = ts;
- timestamp.mPosition = (uint32_t) framePosition;
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
- // TODO: Implement this after appropriate Java AudioTrack method is available.
- return NO_ERROR;
-}
-
-status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
- // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
- // Should we do the same thing?
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
- jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
- jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
-
- jmethodID jSetAudioFallbackMode = env->GetMethodID(
- jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(
- jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
-
- jmethodID jSetAudioStretchMode = env->GetMethodID(
- jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(
- jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
-
- jmethodID jSetPitch = env->GetMethodID(
- jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
-
- jmethodID jSetSpeed = env->GetMethodID(
- jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
-
-
- // Set this Java PlaybackParams object into Java AudioTrack.
- jmethodID jSetPlaybackParams = env->GetMethodID(
- mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
- env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
- // TODO: Should we catch the Java IllegalArgumentException?
-
- return NO_ERROR;
-}
-
-const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jmethodID jGetPlaybackParams = env->GetMethodID(
- mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
- jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
-
- AudioPlaybackRate playbackRate;
- jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
-
- jmethodID jGetAudioFallbackMode = env->GetMethodID(
- jPlaybackParamsCls, "getAudioFallbackMode", "()I");
- // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
- // The enum is internal only, so it is not defined in PlaybackParmas.java.
- // TODO: Is this right way to convert an int to an enum?
- playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
- env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
-
- jmethodID jGetAudioStretchMode = env->GetMethodID(
- jPlaybackParamsCls, "getAudioStretchMode", "()I");
- playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
- env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
-
- jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
- playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
-
- jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
- playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
-
- return playbackRate;
-}
-
-media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
- const sp<media::VolumeShaper::Configuration>& configuration,
- const sp<media::VolumeShaper::Operation>& operation) {
-
- jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
- jobject jOperationObj = createVolumeShaperOperationObj(operation);
-
- if (jConfigurationObj == NULL || jOperationObj == NULL) {
- return media::VolumeShaper::Status(BAD_VALUE);
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
- "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
- jobject jVolumeShaperObj = env->CallObjectMethod(
- mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
-
- jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
- jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
- "(Landroid/media/VolumeShaper$Operation;)V");
- env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
-
- return media::VolumeShaper::Status(NO_ERROR);
-}
-
-status_t JAudioTrack::setAuxEffectSendLevel(float level) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
- mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::attachAuxEffect(int effectId) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
- int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::setVolume(float left, float right) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- // TODO: Java setStereoVolume is deprecated. Do we really need this method?
- jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::setVolume(float volume) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::start() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
- // TODO: Should we catch the Java IllegalStateException from play()?
- env->CallVoidMethod(mAudioTrackObj, jPlay);
- return NO_ERROR;
-}
-
-ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
- if (buffer == NULL) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jbyteArray jAudioData = env->NewByteArray(size);
- env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
-
- jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
- jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
- jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
-
- int writeMode = 0;
- if (blocking) {
- jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
- writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
- } else {
- jfieldID jWriteNonBlocking = env->GetStaticFieldID(
- mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
- writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
- }
-
- jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
- int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
-
- if (result >= 0) {
- return result;
- } else {
- return javaToNativeStatus(result);
- }
-}
-
-void JAudioTrack::stop() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
- env->CallVoidMethod(mAudioTrackObj, jStop);
- // TODO: Should we catch IllegalStateException?
-}
-
-// TODO: Is the right implementation?
-bool JAudioTrack::stopped() const {
- return !isPlaying();
-}
-
-void JAudioTrack::flush() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
- env->CallVoidMethod(mAudioTrackObj, jFlush);
-}
-
-void JAudioTrack::pause() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
- env->CallVoidMethod(mAudioTrackObj, jPause);
- // TODO: Should we catch IllegalStateException?
-}
-
-bool JAudioTrack::isPlaying() const {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
- int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
-
- // TODO: In Java AudioTrack, there is no STOPPING state.
- // This means while stopping, isPlaying() will return different value in two class.
- // - in existing native AudioTrack: true
- // - in JAudioTrack: false
- // If not okay, also modify the implementation of stopped().
- jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
- int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
- return currentPlayState == statePlaying;
-}
-
-uint32_t JAudioTrack::getSampleRate() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
-}
-
-status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
- if (duration == nullptr) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetBufferSizeInFrames = env->GetMethodID(
- mAudioTrackCls, "getBufferSizeInFrames", "()I");
- int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
-
- const double secondToMicro = 1000000LL; // 1E6
- int sampleRate = JAudioTrack::getSampleRate();
- float speed = JAudioTrack::getPlaybackRate().mSpeed;
-
- *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
- return NO_ERROR;
-}
-
-audio_format_t JAudioTrack::format() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
- int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
- return audioFormatToNative(javaFormat);
-}
-
-size_t JAudioTrack::frameSize() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetFormat = env->GetMethodID(mAudioTrackCls,
- "getFormat", "()Landroid/media/AudioFormat;");
- jobject jAudioFormatObj = env->CallObjectMethod(mAudioTrackObj, jGetFormat);
-
- jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
- jmethodID jGetFrameSizeInBytes = env->GetMethodID(
- jAudioFormatCls, "getFrameSizeInBytes", "()I");
- jint javaFrameSizeInBytes = env->CallIntMethod(jAudioFormatObj, jGetFrameSizeInBytes);
-
- return (size_t)javaFrameSizeInBytes;
-}
-
-status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
-{
- String8 result;
-
- result.append(" JAudioTrack::dump\n");
-
- // TODO: Remove logs that includes unavailable information from below.
-// result.appendFormat(" status(%d), state(%d), session Id(%d), flags(%#x)\n",
-// mStatus, mState, mSessionId, mFlags);
-// result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
-// format(), mChannelMask, channelCount());
-// result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
-// getSampleRate(), mOriginalSampleRate, mPlaybackRate.mSpeed);
-// result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
-// frameCount(), mReqFrameCount);
-// result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
-// " req. notif. per buff(%u)\n",
-// mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
-// result.appendFormat(" latency (%d), selected device Id(%d), routed device Id(%d)\n",
-// latency(), mSelectedDeviceId, getRoutedDeviceId());
-// result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
-// mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
- ::write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-jobject JAudioTrack::getRoutedDevice() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
- "()Landroid/media/AudioDeviceInfo;");
- return env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
-}
-
-int32_t JAudioTrack::getAudioSessionId() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
- jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
- return sessionId;
-}
-
-status_t JAudioTrack::setPreferredDevice(jobject device) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetPreferredDeviceId = env->GetMethodID(mAudioTrackCls, "setPreferredDevice",
- "(Landroid/media/AudioDeviceInfo;)Z");
- jboolean result = env->CallBooleanMethod(mAudioTrackObj, jSetPreferredDeviceId, device);
- return result == true ? NO_ERROR : BAD_VALUE;
-}
-
-audio_stream_type_t JAudioTrack::getAudioStreamType() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioAttributes = env->GetMethodID(mAudioTrackCls, "getAudioAttributes",
- "()Landroid/media/AudioAttributes;");
- jobject jAudioAttributes = env->CallObjectMethod(mAudioTrackObj, jGetAudioAttributes);
- jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
- jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
- "getVolumeControlStream", "()I");
- int javaAudioStreamType = env->CallIntMethod(jAudioAttributes, jGetVolumeControlStream);
- return (audio_stream_type_t)javaAudioStreamType;
-}
-
-status_t JAudioTrack::pendingDuration(int32_t *msec) {
- if (msec == nullptr) {
- return BAD_VALUE;
- }
-
- bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
- if (!isPurePcmData) {
- return INVALID_OPERATION;
- }
-
- // TODO: Need to know the difference btw. client and server time.
- // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
- // (copied from AudioTrack.cpp)
-
-// ExtendedTimestamp ets;
-// ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
-// if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
-// int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
-// - ets.mPosition[location];
-// if (diff < 0) {
-// *msec = 0;
-// } else {
-// // ms is the playback time by frames
-// int64_t ms = (int64_t)((double)diff * 1000 /
-// ((double)mSampleRate * mPlaybackRate.mSpeed));
-// // clockdiff is the timestamp age (negative)
-// int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
-// ets.mTimeNs[location]
-// + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
-// - systemTime(SYSTEM_TIME_MONOTONIC);
-//
-// //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
-// static const int NANOS_PER_MILLIS = 1000000;
-// *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
-// }
-// return NO_ERROR;
-// }
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
- "addOnRoutingChangedListener",
- "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
- env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
- return NO_ERROR;
-}
-
-status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
- "removeOnRoutingChangedListener",
- "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
- env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
- return NO_ERROR;
-}
-
-void JAudioTrack::registerRoutingDelegates(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates) {
- for (auto it = routingDelegates.begin(); it != routingDelegates.end(); it++) {
- addAudioDeviceCallback(it->second->getJObject(), getHandler(it->second->getJObject()));
- }
-}
-
-/////////////////////////////////////////////////////////////
-/// Static methods begin ///
-/////////////////////////////////////////////////////////////
-jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
- jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
- "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
- return env->CallObjectMethod(routingDelegateObj, jGetListener);
-}
-
-jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
- jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
- "getHandler", "()Landroid/os/Handler;");
- return env->CallObjectMethod(routingDelegateObj, jGetHandler);
-}
-
-jobject JAudioTrack::findByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (auto it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first->getJObject(), key)) {
- return it->second->getJObject();
- }
- }
- return nullptr;
-}
-
-void JAudioTrack::eraseByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (auto it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first->getJObject(), key)) {
- mp.erase(it);
- return;
- }
- }
-}
-
-/////////////////////////////////////////////////////////////
-/// Private method begins ///
-/////////////////////////////////////////////////////////////
-
-jobject JAudioTrack::createVolumeShaperConfigurationObj(
- const sp<media::VolumeShaper::Configuration>& config) {
-
- // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
- if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
- return NULL;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- // Referenced "android_media_VolumeShaper.h".
- jfloatArray xarray = nullptr;
- jfloatArray yarray = nullptr;
- if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
- // convert curve arrays
- xarray = env->NewFloatArray(config->size());
- yarray = env->NewFloatArray(config->size());
- float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
- float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
- float *xptr = x, *yptr = y;
- for (const auto &pt : *config.get()) {
- *xptr++ = pt.first;
- *yptr++ = pt.second;
- }
- env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
- env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
- }
-
- jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
- "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
-
- jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
- "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
- config->getInterpolatorType());
-
- jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
- "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
-
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
- "()Landroid/media/VolumeShaper$Configuration;");
- return env->CallObjectMethod(jBuilderObj, jBuild);
-}
-
-jobject JAudioTrack::createVolumeShaperOperationObj(
- const sp<media::VolumeShaper::Operation>& operation) {
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- // Set XOffset
- jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
- "(F)Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
-
- int32_t flags = operation->getFlags();
-
- if (operation->getReplaceId() >= 0) {
- jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
- "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
- bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
- jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
- }
-
- // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
- if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
- jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
- jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
- jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
- }
-
- // TODO: Handle error case (can it be NULL?)
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
- "()Landroid/media/VolumeShaper$Operation;");
- return env->CallObjectMethod(jBuilderObj, jBuild);
-}
-
-jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2$StreamEventCallback");
- jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
- jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
- return jCallbackObj;
-}
-
-jobject JAudioTrack::createCallbackExecutor() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
- jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
- "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
- jobject jSingleThreadExecutorObj =
- env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
- return jSingleThreadExecutorObj;
-}
-
-status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
- switch (javaStatus) {
- case AUDIO_JAVA_SUCCESS:
- return NO_ERROR;
- case AUDIO_JAVA_BAD_VALUE:
- return BAD_VALUE;
- case AUDIO_JAVA_INVALID_OPERATION:
- return INVALID_OPERATION;
- case AUDIO_JAVA_PERMISSION_DENIED:
- return PERMISSION_DENIED;
- case AUDIO_JAVA_NO_INIT:
- return NO_INIT;
- case AUDIO_JAVA_WOULD_BLOCK:
- return WOULD_BLOCK;
- case AUDIO_JAVA_DEAD_OBJECT:
- return DEAD_OBJECT;
- default:
- return UNKNOWN_ERROR;
- }
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPConnection.cpp b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
deleted file mode 100644
index e1baa10..0000000
--- a/media/libmediaplayer2/JMedia2HTTPConnection.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMedia2HTTPConnection"
-#include <utils/Log.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPConnection.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/scoped_local_ref.h>
-
-#include "log/log.h"
-#include "jni.h"
-
-namespace android {
-
-static const size_t kBufferSize = 32768;
-
-JMedia2HTTPConnection::JMedia2HTTPConnection(JNIEnv *env, jobject thiz) {
- mMedia2HTTPConnectionObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPConnectionObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPConnectionClass(
- env, env->GetObjectClass(mMedia2HTTPConnectionObj));
- CHECK(media2HTTPConnectionClass.get() != NULL);
-
- mConnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "connect",
- "(Ljava/lang/String;Ljava/lang/String;)Z");
- CHECK(mConnectMethod != NULL);
-
- mDisconnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "disconnect",
- "()V");
- CHECK(mDisconnectMethod != NULL);
-
- mReadAtMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "readAt",
- "(J[BI)I");
- CHECK(mReadAtMethod != NULL);
-
- mGetSizeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getSize",
- "()J");
- CHECK(mGetSizeMethod != NULL);
-
- mGetMIMETypeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getMIMEType",
- "()Ljava/lang/String;");
- CHECK(mGetMIMETypeMethod != NULL);
-
- mGetUriMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getUri",
- "()Ljava/lang/String;");
- CHECK(mGetUriMethod != NULL);
-
- ScopedLocalRef<jbyteArray> tmp(
- env, env->NewByteArray(kBufferSize));
- mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
- CHECK(mByteArrayObj != NULL);
-}
-
-JMedia2HTTPConnection::~JMedia2HTTPConnection() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPConnectionObj);
- env->DeleteGlobalRef(mByteArrayObj);
-}
-
-bool JMedia2HTTPConnection::connect(
- const char *uri, const KeyedVector<String8, String8> *headers) {
- String8 tmp("");
- if (headers != NULL) {
- for (size_t i = 0; i < headers->size(); ++i) {
- tmp.append(headers->keyAt(i));
- tmp.append(String8(": "));
- tmp.append(headers->valueAt(i));
- tmp.append(String8("\r\n"));
- }
- }
-
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = env->NewStringUTF(uri);
- jstring jheaders = env->NewStringUTF(tmp.string());
-
- jboolean ret =
- env->CallBooleanMethod(mMedia2HTTPConnectionObj, mConnectMethod, juri, jheaders);
-
- env->DeleteLocalRef(juri);
- env->DeleteLocalRef(jheaders);
-
- return (bool)ret;
-}
-
-void JMedia2HTTPConnection::disconnect() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- env->CallVoidMethod(mMedia2HTTPConnectionObj, mDisconnectMethod);
-}
-
-ssize_t JMedia2HTTPConnection::readAt(off64_t offset, void *data, size_t size) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
-
- if (size > kBufferSize) {
- size = kBufferSize;
- }
-
- jint n = env->CallIntMethod(
- mMedia2HTTPConnectionObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)size);
-
- if (n > 0) {
- env->GetByteArrayRegion(
- mByteArrayObj,
- 0,
- n,
- (jbyte *)data);
- }
-
- return n;
-}
-
-off64_t JMedia2HTTPConnection::getSize() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- return (off64_t)(env->CallLongMethod(mMedia2HTTPConnectionObj, mGetSizeMethod));
-}
-
-status_t JMedia2HTTPConnection::getMIMEType(String8 *mimeType) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring jmime = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetMIMETypeMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(jmime, 0);
- if (str != NULL) {
- *mimeType = String8(str);
- } else {
- *mimeType = "application/octet-stream";
- }
- env->ReleaseStringUTFChars(jmime, str);
- return OK;
-}
-
-status_t JMedia2HTTPConnection::getUri(String8 *uri) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetUriMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(juri, 0);
- *uri = String8(str);
- env->ReleaseStringUTFChars(juri, str);
- return OK;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPService.cpp b/media/libmediaplayer2/JMedia2HTTPService.cpp
deleted file mode 100644
index 20e3573..0000000
--- a/media/libmediaplayer2/JMedia2HTTPService.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMedia2HTTPService"
-#include <utils/Log.h>
-
-#include <jni.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPService.h>
-#include <mediaplayer2/JMedia2HTTPConnection.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <nativehelper/scoped_local_ref.h>
-
-namespace android {
-
-JMedia2HTTPService::JMedia2HTTPService(JNIEnv *env, jobject thiz) {
- mMedia2HTTPServiceObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPServiceObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPServiceClass(env, env->GetObjectClass(mMedia2HTTPServiceObj));
- CHECK(media2HTTPServiceClass.get() != NULL);
-
- mMakeHTTPConnectionMethod = env->GetMethodID(
- media2HTTPServiceClass.get(),
- "makeHTTPConnection",
- "()Landroid/media/Media2HTTPConnection;");
- CHECK(mMakeHTTPConnectionMethod != NULL);
-}
-
-JMedia2HTTPService::~JMedia2HTTPService() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPServiceObj);
-}
-
-sp<MediaHTTPConnection> JMedia2HTTPService::makeHTTPConnection() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jobject media2HTTPConnectionObj =
- env->CallObjectMethod(mMedia2HTTPServiceObj, mMakeHTTPConnectionMethod);
-
- return new JMedia2HTTPConnection(env, media2HTTPConnectionObj);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JavaVMHelper.cpp b/media/libmediaplayer2/JavaVMHelper.cpp
deleted file mode 100644
index 8d03ed0..0000000
--- a/media/libmediaplayer2/JavaVMHelper.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "JavaVMHelper"
-
-#include "mediaplayer2/JavaVMHelper.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <utils/threads.h>
-
-#include <stdlib.h>
-
-namespace android {
-
-// static
-std::atomic<JavaVM *> JavaVMHelper::sJavaVM(NULL);
-
-/*
- * Makes the current thread visible to the VM.
- *
- * The JNIEnv pointer returned is only valid for the current thread, and
- * thus must be tucked into thread-local storage.
- */
-static int javaAttachThread(const char* threadName, JNIEnv** pEnv) {
- JavaVMAttachArgs args;
- JavaVM* vm;
- jint result;
-
- vm = JavaVMHelper::getJavaVM();
- if (vm == NULL) {
- return JNI_ERR;
- }
-
- args.version = JNI_VERSION_1_4;
- args.name = (char*) threadName;
- args.group = NULL;
-
- result = vm->AttachCurrentThread(pEnv, (void*) &args);
- if (result != JNI_OK) {
- ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
- }
-
- return result;
-}
-
-/*
- * Detach the current thread from the set visible to the VM.
- */
-static int javaDetachThread(void) {
- JavaVM* vm;
- jint result;
-
- vm = JavaVMHelper::getJavaVM();
- if (vm == NULL) {
- return JNI_ERR;
- }
-
- result = vm->DetachCurrentThread();
- if (result != JNI_OK) {
- ALOGE("ERROR: thread detach failed\n");
- }
- return result;
-}
-
-/*
- * When starting a native thread that will be visible from the VM, we
- * bounce through this to get the right attach/detach action.
- * Note that this function calls free(args)
- */
-static int javaThreadShell(void* args) {
- void* start = ((void**)args)[0];
- void* userData = ((void **)args)[1];
- char* name = (char*) ((void **)args)[2]; // we own this storage
- free(args);
- JNIEnv* env;
- int result;
-
- /* hook us into the VM */
- if (javaAttachThread(name, &env) != JNI_OK) {
- return -1;
- }
-
- /* start the thread running */
- result = (*(android_thread_func_t)start)(userData);
-
- /* unhook us */
- javaDetachThread();
- free(name);
-
- return result;
-}
-
-/*
- * This is invoked from androidCreateThreadEtc() via the callback
- * set with androidSetCreateThreadFunc().
- *
- * We need to create the new thread in such a way that it gets hooked
- * into the VM before it really starts executing.
- */
-static int javaCreateThreadEtc(
- android_thread_func_t entryFunction,
- void* userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t* threadId) {
- void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free
- int result;
-
- LOG_ALWAYS_FATAL_IF(threadName == nullptr, "threadName not provided to javaCreateThreadEtc");
-
- args[0] = (void*) entryFunction;
- args[1] = userData;
- args[2] = (void*) strdup(threadName); // javaThreadShell must free
-
- result = androidCreateRawThreadEtc(javaThreadShell, args,
- threadName, threadPriority, threadStackSize, threadId);
- return result;
-}
-
-// static
-JNIEnv *JavaVMHelper::getJNIEnv() {
- JNIEnv *env;
- JavaVM *vm = sJavaVM.load();
- CHECK(vm != NULL);
-
- if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
- return NULL;
- }
-
- return env;
-}
-
-//static
-JavaVM *JavaVMHelper::getJavaVM() {
- return sJavaVM.load();
-}
-
-// static
-void JavaVMHelper::setJavaVM(JavaVM *vm) {
- sJavaVM.store(vm);
-
- // Ensure that Thread(/*canCallJava*/ true) in libutils is attached to the VM.
- // This is supposed to be done by runtime, but when libutils is used with linker
- // namespace, CreateThreadFunc should be initialized separately within the namespace.
- androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
deleted file mode 100644
index b4fa0c1..0000000
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2AudioOutput"
-#include <mediaplayer2/MediaPlayer2AudioOutput.h>
-
-#include <cutils/properties.h> // for property_get
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace {
-
-const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
-
-} // anonymous namespace
-
-namespace android {
-
-// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
-/* static */ int MediaPlayer2AudioOutput::mMinBufferCount = 4;
-/* static */ bool MediaPlayer2AudioOutput::mIsOnEmulator = false;
-
-status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) const {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- result.append(" MediaPlayer2AudioOutput\n");
- snprintf(buffer, 255, " volume(%f)\n", mVolume);
- result.append(buffer);
- snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
- mMsecsPerFrame, (mJAudioTrack != nullptr) ? mJAudioTrack->latency() : -1);
- result.append(buffer);
- snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
- mAuxEffectId, mSendLevel);
- result.append(buffer);
-
- ::write(fd, result.string(), result.size());
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->dump(fd, args);
- }
- return NO_ERROR;
-}
-
-MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(int32_t sessionId, uid_t uid, int pid,
- const jobject attributes)
- : mCallback(nullptr),
- mCallbackCookie(nullptr),
- mCallbackData(nullptr),
- mVolume(1.0),
- mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
- mSampleRateHz(0),
- mMsecsPerFrame(0),
- mFrameSize(0),
- mSessionId(sessionId),
- mUid(uid),
- mPid(pid),
- mSendLevel(0.0),
- mAuxEffectId(0),
- mFlags(AUDIO_OUTPUT_FLAG_NONE) {
- ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
-
- if (attributes != nullptr) {
- mAttributes = new JObjectHolder(attributes);
- }
-
- setMinBufferCount();
- mRoutingDelegates.clear();
-}
-
-MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
- close();
- delete mCallbackData;
-}
-
-//static
-void MediaPlayer2AudioOutput::setMinBufferCount() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("ro.kernel.qemu", value, 0)) {
- mIsOnEmulator = true;
- mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
- }
-}
-
-// static
-bool MediaPlayer2AudioOutput::isOnEmulator() {
- setMinBufferCount(); // benign race wrt other threads
- return mIsOnEmulator;
-}
-
-// static
-int MediaPlayer2AudioOutput::getMinBufferCount() {
- setMinBufferCount(); // benign race wrt other threads
- return mMinBufferCount;
-}
-
-ssize_t MediaPlayer2AudioOutput::bufferSize() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->frameCount() * mFrameSize;
-}
-
-ssize_t MediaPlayer2AudioOutput::frameCount() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->frameCount();
-}
-
-ssize_t MediaPlayer2AudioOutput::channelCount() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->channelCount();
-}
-
-ssize_t MediaPlayer2AudioOutput::frameSize() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mFrameSize;
-}
-
-uint32_t MediaPlayer2AudioOutput::latency () const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return 0;
- }
- return mJAudioTrack->latency();
-}
-
-float MediaPlayer2AudioOutput::msecsPerFrame() const {
- Mutex::Autolock lock(mLock);
- return mMsecsPerFrame;
-}
-
-status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->getPosition(position);
-}
-
-status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->getTimestamp(ts);
-}
-
-// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr || mSampleRateHz == 0) {
- return 0;
- }
-
- uint32_t numFramesPlayed;
- int64_t numFramesPlayedAtUs;
- AudioTimestamp ts;
-
- status_t res = mJAudioTrack->getTimestamp(ts);
-
- if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
- numFramesPlayed = ts.mPosition;
- numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
- } else { // case 2: transitory state on start of a new track
- // case 3: transitory at new track or audio fast tracks.
- numFramesPlayed = 0;
- numFramesPlayedAtUs = nowUs;
- //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAtUs);
- }
-
- // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
- int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
- + nowUs - numFramesPlayedAtUs;
- if (durationUs < 0) {
- // Occurs when numFramesPlayed position is very small and the following:
- // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
- // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
- // (2) In case 3, using getPosition and adding mAudioSink->latency() to
- // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
- //
- // Both of these are transitory conditions.
- ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
- durationUs = 0;
- }
- ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
- (long long)durationUs, (long long)nowUs,
- numFramesPlayed, (long long)numFramesPlayedAtUs);
- return durationUs;
-}
-
-status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- ExtendedTimestamp ets;
- status_t status = mJAudioTrack->getTimestamp(&ets);
- if (status == OK || status == WOULD_BLOCK) {
- *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
- }
- return status;
-}
-
-void MediaPlayer2AudioOutput::setAudioAttributes(const jobject attributes) {
- Mutex::Autolock lock(mLock);
- mAttributes = (attributes == nullptr) ? nullptr : new JObjectHolder(attributes);
-}
-
-audio_stream_type_t MediaPlayer2AudioOutput::getAudioStreamType() const {
- ALOGV("getAudioStreamType");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return AUDIO_STREAM_DEFAULT;
- }
- return mJAudioTrack->getAudioStreamType();
-}
-
-void MediaPlayer2AudioOutput::close_l() {
- mJAudioTrack.clear();
-}
-
-status_t MediaPlayer2AudioOutput::open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo,
- uint32_t suggestedFrameCount) {
- ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
- format, mSessionId, flags);
-
- // offloading is only supported in callback mode for now.
- // offloadInfo must be present if offload flag is set
- if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
- ((cb == nullptr) || (offloadInfo == nullptr))) {
- return BAD_VALUE;
- }
-
- // compute frame count for the AudioTrack internal buffer
- const size_t frameCount =
- ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) ? 0 : suggestedFrameCount;
-
- if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
- channelMask = audio_channel_out_mask_from_count(channelCount);
- if (0 == channelMask) {
- ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
- return NO_INIT;
- }
- }
-
- Mutex::Autolock lock(mLock);
- mCallback = cb;
- mCallbackCookie = cookie;
-
- sp<JAudioTrack> jT;
- CallbackData *newcbd = nullptr;
-
- ALOGV("creating new JAudioTrack");
-
- if (mCallback != nullptr) {
- newcbd = new CallbackData(this);
- jT = new JAudioTrack(
- sampleRate,
- format,
- channelMask,
- CallbackWrapper,
- newcbd,
- frameCount,
- mSessionId,
- mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
- 1.0f); // default value for maxRequiredSpeed
- } else {
- // TODO: Due to buffer memory concerns, we use a max target playback speed
- // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
- // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
- const float targetSpeed =
- std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
- ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
- "track target speed:%f clamped from playback speed:%f",
- targetSpeed, mPlaybackRate.mSpeed);
- jT = new JAudioTrack(
- sampleRate,
- format,
- channelMask,
- nullptr,
- nullptr,
- frameCount,
- mSessionId,
- mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
- targetSpeed);
- }
-
- if (jT == 0) {
- ALOGE("Unable to create audio track");
- delete newcbd;
- // t goes out of scope, so reference count drops to zero
- return NO_INIT;
- }
-
- CHECK((jT != nullptr) && ((mCallback == nullptr) || (newcbd != nullptr)));
-
- mCallbackData = newcbd;
- ALOGV("setVolume");
- jT->setVolume(mVolume);
-
- mSampleRateHz = sampleRate;
- mFlags = flags;
- mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
- mFrameSize = jT->frameSize();
- mJAudioTrack = jT;
-
- return updateTrack_l();
-}
-
-status_t MediaPlayer2AudioOutput::updateTrack_l() {
- if (mJAudioTrack == nullptr) {
- return NO_ERROR;
- }
-
- status_t res = NO_ERROR;
- // Note some output devices may give us a direct track even though we don't specify it.
- // Example: Line application b/17459982.
- if ((mJAudioTrack->getFlags()
- & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
- res = mJAudioTrack->setPlaybackRate(mPlaybackRate);
- if (res == NO_ERROR) {
- mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
- res = mJAudioTrack->attachAuxEffect(mAuxEffectId);
- }
- }
- if (mPreferredDevice != nullptr) {
- mJAudioTrack->setPreferredDevice(mPreferredDevice->getJObject());
- }
-
- mJAudioTrack->registerRoutingDelegates(mRoutingDelegates);
-
- ALOGV("updateTrack_l() DONE status %d", res);
- return res;
-}
-
-status_t MediaPlayer2AudioOutput::start() {
- ALOGV("start");
- Mutex::Autolock lock(mLock);
- if (mCallbackData != nullptr) {
- mCallbackData->endTrackSwitch();
- }
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->setVolume(mVolume);
- mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
- status_t status = mJAudioTrack->start();
- return status;
- }
- return NO_INIT;
-}
-
-ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
- Mutex::Autolock lock(mLock);
- LOG_ALWAYS_FATAL_IF(mCallback != nullptr, "Don't call write if supplying a callback.");
-
- //ALOGV("write(%p, %u)", buffer, size);
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->write(buffer, size, blocking);
- }
- return NO_INIT;
-}
-
-void MediaPlayer2AudioOutput::stop() {
- ALOGV("stop");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->stop();
- }
-}
-
-void MediaPlayer2AudioOutput::flush() {
- ALOGV("flush");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->flush();
- }
-}
-
-void MediaPlayer2AudioOutput::pause() {
- ALOGV("pause");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->pause();
- }
-}
-
-void MediaPlayer2AudioOutput::close() {
- ALOGV("close");
- sp<JAudioTrack> track;
- {
- Mutex::Autolock lock(mLock);
- track = mJAudioTrack;
- close_l(); // clears mJAudioTrack
- }
- // destruction of the track occurs outside of mutex.
-}
-
-void MediaPlayer2AudioOutput::setVolume(float volume) {
- ALOGV("setVolume(%f)", volume);
- Mutex::Autolock lock(mLock);
- mVolume = volume;
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->setVolume(volume);
- }
-}
-
-status_t MediaPlayer2AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) {
- ALOGV("setPlaybackRate(%f %f %d %d)",
- rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- // remember rate so that we can set it when the track is opened
- mPlaybackRate = rate;
- return OK;
- }
- status_t res = mJAudioTrack->setPlaybackRate(rate);
- if (res != NO_ERROR) {
- return res;
- }
- // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
- CHECK_GT(rate.mSpeed, 0.f);
- mPlaybackRate = rate;
- if (mSampleRateHz != 0) {
- mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
- }
- return res;
-}
-
-status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
- ALOGV("getPlaybackRate");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return NO_INIT;
- }
- *rate = mJAudioTrack->getPlaybackRate();
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::setAuxEffectSendLevel(float level) {
- ALOGV("setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock lock(mLock);
- mSendLevel = level;
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->setAuxEffectSendLevel(level);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::attachAuxEffect(int effectId) {
- ALOGV("attachAuxEffect(%d)", effectId);
- Mutex::Autolock lock(mLock);
- mAuxEffectId = effectId;
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->attachAuxEffect(effectId);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::setPreferredDevice(jobject device) {
- ALOGV("setPreferredDevice");
- Mutex::Autolock lock(mLock);
- status_t ret = NO_ERROR;
- if (mJAudioTrack != nullptr) {
- ret = mJAudioTrack->setPreferredDevice(device);
- }
- if (ret == NO_ERROR) {
- mPreferredDevice = new JObjectHolder(device);
- }
- return ret;
-}
-
-jobject MediaPlayer2AudioOutput::getRoutedDevice() {
- ALOGV("getRoutedDevice");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->getRoutedDevice();
- }
- return nullptr;
-}
-
-status_t MediaPlayer2AudioOutput::addAudioDeviceCallback(jobject jRoutingDelegate) {
- ALOGV("addAudioDeviceCallback");
- Mutex::Autolock lock(mLock);
- jobject listener = JAudioTrack::getListener(jRoutingDelegate);
- if (JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
- sp<JObjectHolder> listenerHolder = new JObjectHolder(listener);
- jobject handler = JAudioTrack::getHandler(jRoutingDelegate);
- sp<JObjectHolder> routingDelegateHolder = new JObjectHolder(jRoutingDelegate);
-
- mRoutingDelegates.push_back(std::pair<sp<JObjectHolder>, sp<JObjectHolder>>(
- listenerHolder, routingDelegateHolder));
-
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->addAudioDeviceCallback(
- routingDelegateHolder->getJObject(), handler);
- }
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::removeAudioDeviceCallback(jobject listener) {
- ALOGV("removeAudioDeviceCallback");
- Mutex::Autolock lock(mLock);
- jobject routingDelegate = nullptr;
- if ((routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
- }
- JAudioTrack::eraseByKey(mRoutingDelegates, listener);
- }
- return NO_ERROR;
-}
-
-// static
-void MediaPlayer2AudioOutput::CallbackWrapper(
- int event, void *cookie, void *info) {
- //ALOGV("callbackwrapper");
- CallbackData *data = (CallbackData*)cookie;
- // lock to ensure we aren't caught in the middle of a track switch.
- data->lock();
- MediaPlayer2AudioOutput *me = data->getOutput();
- JAudioTrack::Buffer *buffer = (JAudioTrack::Buffer *)info;
- if (me == nullptr) {
- // no output set, likely because the track was scheduled to be reused
- // by another player, but the format turned out to be incompatible.
- data->unlock();
- if (buffer != nullptr) {
- buffer->mSize = 0;
- }
- return;
- }
-
- switch(event) {
- case JAudioTrack::EVENT_MORE_DATA: {
- size_t actualSize = (*me->mCallback)(
- me, buffer->mData, buffer->mSize, me->mCallbackCookie,
- CB_EVENT_FILL_BUFFER);
-
- // Log when no data is returned from the callback.
- // (1) We may have no data (especially with network streaming sources).
- // (2) We may have reached the EOS and the audio track is not stopped yet.
- // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
- // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
- //
- // This is a benign busy-wait, with the next data request generated 10 ms or more later;
- // nevertheless for power reasons, we don't want to see too many of these.
-
- ALOGV_IF(actualSize == 0 && buffer->mSize > 0, "callbackwrapper: empty buffer returned");
-
- buffer->mSize = actualSize;
- } break;
-
- case JAudioTrack::EVENT_STREAM_END:
- // currently only occurs for offloaded callbacks
- ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_STREAM_END);
- break;
-
- case JAudioTrack::EVENT_NEW_IAUDIOTRACK :
- ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
- break;
-
- case JAudioTrack::EVENT_UNDERRUN:
- // This occurs when there is no data available, typically
- // when there is a failure to supply data to the AudioTrack. It can also
- // occur in non-offloaded mode when the audio device comes out of standby.
- //
- // If an AudioTrack underruns it outputs silence. Since this happens suddenly
- // it may sound like an audible pop or glitch.
- //
- // The underrun event is sent once per track underrun; the condition is reset
- // when more data is sent to the AudioTrack.
- ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
- break;
-
- default:
- ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
- }
-
- data->unlock();
-}
-
-int32_t MediaPlayer2AudioOutput::getSessionId() const {
- Mutex::Autolock lock(mLock);
- return mSessionId;
-}
-
-void MediaPlayer2AudioOutput::setSessionId(const int32_t sessionId) {
- Mutex::Autolock lock(mLock);
- mSessionId = sessionId;
-}
-
-uint32_t MediaPlayer2AudioOutput::getSampleRate() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return 0;
- }
- return mJAudioTrack->getSampleRate();
-}
-
-int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return 0;
- }
- int64_t duration;
- if (mJAudioTrack->getBufferDurationInUs(&duration) != OK) {
- return 0;
- }
- return duration;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
deleted file mode 100644
index 2ed4632..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_JAUDIOTRACK_H
-#define ANDROID_JAUDIOTRACK_H
-
-#include <utility>
-#include <jni.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
-#include <media/VolumeShaper.h>
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <mediaplayer2/JObjectHolder.h>
-#include <media/AudioTimestamp.h> // It has dependency on audio.h/Errors.h, but doesn't
- // include them in it. Therefore it is included here at last.
-
-namespace android {
-
-class JAudioTrack : public RefBase {
-public:
-
- /* Events used by AudioTrack callback function (callback_t).
- * Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
- */
- enum event_type {
- EVENT_MORE_DATA = 0, // Request to write more data to buffer.
- EVENT_UNDERRUN = 1, // Buffer underrun occurred. This will not occur for
- // static tracks.
- EVENT_NEW_IAUDIOTRACK = 6, // IAudioTrack was re-created, either due to re-routing and
- // voluntary invalidation by mediaserver, or mediaserver crash.
- EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played
- // back (after stop is called) for an offloaded track.
- };
-
- class Buffer
- {
- public:
- size_t mSize; // input/output in bytes.
- void* mData; // pointer to the audio data.
- };
-
- /* As a convenience, if a callback is supplied, a handler thread
- * is automatically created with the appropriate priority. This thread
- * invokes the callback when a new buffer becomes available or various conditions occur.
- *
- * Parameters:
- *
- * event: type of event notified (see enum AudioTrack::event_type).
- * user: Pointer to context for use by the callback receiver.
- * info: Pointer to optional parameter according to event type:
- * - EVENT_MORE_DATA: pointer to JAudioTrack::Buffer struct. The callback must not
- * write more bytes than indicated by 'size' field and update 'size' if fewer bytes
- * are written.
- * - EVENT_NEW_IAUDIOTRACK: unused.
- * - EVENT_STREAM_END: unused.
- */
-
- typedef void (*callback_t)(int event, void* user, void *info);
-
- /* Creates an JAudioTrack object for non-offload mode.
- * Once created, the track needs to be started before it can be used.
- * Unspecified values are set to appropriate default values.
- *
- * Parameters:
- *
- * streamType: Select the type of audio stream this track is attached to
- * (e.g. AUDIO_STREAM_MUSIC).
- * sampleRate: Data source sampling rate in Hz. Zero means to use the sink sample rate.
- * A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
- * 0 will not work with current policy implementation for direct output
- * selection where an exact match is needed for sampling rate.
- * (TODO: Check direct output after flags can be used in Java AudioTrack.)
- * format: Audio format. For mixed tracks, any PCM format supported by server is OK.
- * For direct and offloaded tracks, the possible format(s) depends on the
- * output sink.
- * (TODO: How can we check whether a format is supported?)
- * channelMask: Channel mask, such that audio_is_output_channel(channelMask) is true.
- * cbf: Callback function. If not null, this function is called periodically
- * to provide new data and inform of marker, position updates, etc.
- * user: Context for use by the callback receiver.
- * frameCount: Minimum size of track PCM buffer in frames. This defines the
- * application's contribution to the latency of the track.
- * The actual size selected by the JAudioTrack could be larger if the
- * requested size is not compatible with current audio HAL configuration.
- * Zero means to use a default value.
- * sessionId: Specific session ID, or zero to use default.
- * pAttributes: If not NULL, supersedes streamType for use case selection.
- * maxRequiredSpeed: For PCM tracks, this creates an appropriate buffer size that will allow
- * maxRequiredSpeed playback. Values less than 1.0f and greater than
- * AUDIO_TIMESTRETCH_SPEED_MAX will be clamped. For non-PCM tracks
- * and direct or offloaded tracks, this parameter is ignored.
- * (TODO: Handle this after offload / direct track is supported.)
- *
- * TODO: Revive removed arguments after offload mode is supported.
- */
- JAudioTrack(uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- callback_t cbf,
- void* user,
- size_t frameCount = 0,
- int32_t sessionId = AUDIO_SESSION_ALLOCATE,
- const jobject pAttributes = NULL,
- float maxRequiredSpeed = 1.0f);
-
- /*
- // Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
- audio_port_handle_t selectedDeviceId,
-
- // TODO: No place to use these values.
- int32_t notificationFrames,
- const audio_offload_info_t *offloadInfo,
- */
-
- virtual ~JAudioTrack();
-
- size_t frameCount();
- size_t channelCount();
-
- /* Returns this track's estimated latency in milliseconds.
- * This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
- * and audio hardware driver.
- */
- uint32_t latency();
-
- /* Return the total number of frames played since playback start.
- * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
- * It is reset to zero by flush(), reload(), and stop().
- *
- * Parameters:
- *
- * position: Address where to return play head position.
- *
- * Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful operation
- * - BAD_VALUE: position is NULL
- */
- status_t getPosition(uint32_t *position);
-
- // TODO: Does this comment apply same to Java AudioTrack::getTimestamp?
- // Changed the return type from status_t to bool, since Java AudioTrack::getTimestamp returns
- // boolean. Will Java getTimestampWithStatus() be public?
- /* Poll for a timestamp on demand.
- * Use if EVENT_NEW_TIMESTAMP is not delivered often enough for your needs,
- * or if you need to get the most recent timestamp outside of the event callback handler.
- * Caution: calling this method too often may be inefficient;
- * if you need a high resolution mapping between frame position and presentation time,
- * consider implementing that at application level, based on the low resolution timestamps.
- * Returns NO_ERROR if timestamp is valid.
- * NO_INIT if finds error, and timestamp parameter will be undefined on return.
- */
- status_t getTimestamp(AudioTimestamp& timestamp);
-
- // TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
- /* Return the extended timestamp, with additional timebase info and improved drain behavior.
- *
- * This is similar to the AudioTrack.java API:
- * getTimestamp(@NonNull AudioTimestamp timestamp, @AudioTimestamp.Timebase int timebase)
- *
- * Some differences between this method and the getTimestamp(AudioTimestamp& timestamp) method
- *
- * 1. stop() by itself does not reset the frame position.
- * A following start() resets the frame position to 0.
- * 2. flush() by itself does not reset the frame position.
- * The frame position advances by the number of frames flushed,
- * when the first frame after flush reaches the audio sink.
- * 3. BOOTTIME clock offsets are provided to help synchronize with
- * non-audio streams, e.g. sensor data.
- * 4. Position is returned with 64 bits of resolution.
- *
- * Parameters:
- * timestamp: A pointer to the caller allocated ExtendedTimestamp.
- *
- * Returns NO_ERROR on success; timestamp is filled with valid data.
- * BAD_VALUE if timestamp is NULL.
- * WOULD_BLOCK if called immediately after start() when the number
- * of frames consumed is less than the
- * overall hardware latency to physical output. In WOULD_BLOCK cases,
- * one might poll again, or use getPosition(), or use 0 position and
- * current time for the timestamp.
- * If WOULD_BLOCK is returned, the timestamp is still
- * modified with the LOCATION_CLIENT portion filled.
- * DEAD_OBJECT if AudioFlinger dies or the output device changes and
- * the track cannot be automatically restored.
- * The application needs to recreate the AudioTrack
- * because the audio device changed or AudioFlinger died.
- * This typically occurs for direct or offloaded tracks
- * or if mDoNotReconnect is true.
- * INVALID_OPERATION if called on a offloaded or direct track.
- * Use getTimestamp(AudioTimestamp& timestamp) instead.
- */
- status_t getTimestamp(ExtendedTimestamp *timestamp);
-
- /* Set source playback rate for timestretch
- * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
- * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
- *
- * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX
- * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX
- *
- * Speed increases the playback rate of media, but does not alter pitch.
- * Pitch increases the "tonal frequency" of media, but does not affect the playback rate.
- */
- status_t setPlaybackRate(const AudioPlaybackRate &playbackRate);
-
- /* Return current playback rate */
- const AudioPlaybackRate getPlaybackRate();
-
- /* Sets the volume shaper object */
- media::VolumeShaper::Status applyVolumeShaper(
- const sp<media::VolumeShaper::Configuration>& configuration,
- const sp<media::VolumeShaper::Operation>& operation);
-
- /* Set the send level for this track. An auxiliary effect should be attached
- * to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
- */
- status_t setAuxEffectSendLevel(float level);
-
- /* Attach track auxiliary output to specified effect. Use effectId = 0
- * to detach track from effect.
- *
- * Parameters:
- *
- * effectId: effectId obtained from AudioEffect::id().
- *
- * Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful operation
- * - INVALID_OPERATION: The effect is not an auxiliary effect.
- * - BAD_VALUE: The specified effect ID is invalid.
- */
- status_t attachAuxEffect(int effectId);
-
- /* Set volume for this track, mostly used for games' sound effects
- * left and right volumes. Levels must be >= 0.0 and <= 1.0.
- * This is the older API. New applications should use setVolume(float) when possible.
- */
- status_t setVolume(float left, float right);
-
- /* Set volume for all channels. This is the preferred API for new applications,
- * especially for multi-channel content.
- */
- status_t setVolume(float volume);
-
- // TODO: Does this comment equally apply to the Java AudioTrack::play()?
- /* After it's created the track is not active. Call start() to
- * make it active. If set, the callback will start being called.
- * If the track was previously paused, volume is ramped up over the first mix buffer.
- */
- status_t start();
-
- // TODO: Does this comment still applies? It seems not. (obtainBuffer, AudioFlinger, ...)
- /* As a convenience we provide a write() interface to the audio buffer.
- * Input parameter 'size' is in byte units.
- * This is implemented on top of obtainBuffer/releaseBuffer. For best
- * performance use callbacks. Returns actual number of bytes written >= 0,
- * or one of the following negative status codes:
- * INVALID_OPERATION AudioTrack is configured for static buffer or streaming mode
- * BAD_VALUE size is invalid
- * WOULD_BLOCK when obtainBuffer() returns same, or
- * AudioTrack was stopped during the write
- * DEAD_OBJECT when AudioFlinger dies or the output device changes and
- * the track cannot be automatically restored.
- * The application needs to recreate the AudioTrack
- * because the audio device changed or AudioFlinger died.
- * This typically occurs for direct or offload tracks
- * or if mDoNotReconnect is true.
- * or any other error code returned by IAudioTrack::start() or restoreTrack_l().
- * Default behavior is to only return when all data has been transferred. Set 'blocking' to
- * false for the method to return immediately without waiting to try multiple times to write
- * the full content of the buffer.
- */
- ssize_t write(const void* buffer, size_t size, bool blocking = true);
-
- // TODO: Does this comment equally apply to the Java AudioTrack::stop()?
- /* Stop a track.
- * In static buffer mode, the track is stopped immediately.
- * In streaming mode, the callback will cease being called. Note that obtainBuffer() still
- * works and will fill up buffers until the pool is exhausted, and then will return WOULD_BLOCK.
- * In streaming mode the stop does not occur immediately: any data remaining in the buffer
- * is first drained, mixed, and output, and only then is the track marked as stopped.
- */
- void stop();
- bool stopped() const;
-
- // TODO: Does this comment equally apply to the Java AudioTrack::flush()?
- /* Flush a stopped or paused track. All previously buffered data is discarded immediately.
- * This has the effect of draining the buffers without mixing or output.
- * Flush is intended for streaming mode, for example before switching to non-contiguous content.
- * This function is a no-op if the track is not stopped or paused, or uses a static buffer.
- */
- void flush();
-
- // TODO: Does this comment equally apply to the Java AudioTrack::pause()?
- // At least we are not using obtainBuffer.
- /* Pause a track. After pause, the callback will cease being called and
- * obtainBuffer returns WOULD_BLOCK. Note that obtainBuffer() still works
- * and will fill up buffers until the pool is exhausted.
- * Volume is ramped down over the next mix buffer following the pause request,
- * and then the track is marked as paused. It can be resumed with ramp up by start().
- */
- void pause();
-
- bool isPlaying() const;
-
- /* Return current source sample rate in Hz.
- * If specified as zero in constructor, this will be the sink sample rate.
- */
- uint32_t getSampleRate();
-
- /* Returns the buffer duration in microseconds at current playback rate. */
- status_t getBufferDurationInUs(int64_t *duration);
-
- audio_format_t format();
-
- size_t frameSize();
-
- /*
- * Dumps the state of an audio track.
- * Not a general-purpose API; intended only for use by media player service to dump its tracks.
- */
- status_t dump(int fd, const Vector<String16>& args) const;
-
- /* Returns the AudioDeviceInfo used by the output to which this AudioTrack is
- * attached.
- */
- jobject getRoutedDevice();
-
- /* Returns the ID of the audio session this AudioTrack belongs to. */
- int32_t getAudioSessionId();
-
- /* Sets the preferred audio device to use for output of this AudioTrack.
- *
- * Parameters:
- * Device: an AudioDeviceInfo object.
- *
- * Returned value:
- * - NO_ERROR: successful operation
- * - BAD_VALUE: failed to set the device
- */
- status_t setPreferredDevice(jobject device);
-
- // TODO: Add AUDIO_OUTPUT_FLAG_DIRECT when it is possible to check.
- // TODO: Add AUDIO_FLAG_HW_AV_SYNC when it is possible to check.
- /* Returns the flags */
- audio_output_flags_t getFlags() const { return mFlags; }
-
- /* We don't keep stream type here,
- * instead, we keep attributes and call getVolumeControlStream() to get stream type
- */
- audio_stream_type_t getAudioStreamType();
-
- /* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
- * AudioTrack.
- *
- * Returns NO_ERROR if successful.
- * INVALID_OPERATION if the AudioTrack does not contain pure PCM data.
- * BAD_VALUE if msec is nullptr.
- */
- status_t pendingDuration(int32_t *msec);
-
- /* Adds an AudioDeviceCallback. The caller will be notified when the audio device to which this
- * AudioTrack is routed is updated.
- * Replaces any previously installed callback.
- *
- * Parameters:
- * Listener: the listener to receive notification of rerouting events.
- * Handler: the handler to handler the rerouting events.
- *
- * Returns NO_ERROR if successful.
- * (TODO) INVALID_OPERATION if the same callback is already installed.
- * (TODO) NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
- * (TODO) BAD_VALUE if the callback is NULL
- */
- status_t addAudioDeviceCallback(jobject listener, jobject rd);
-
- /* Removes an AudioDeviceCallback.
- *
- * Parameters:
- * Listener: the listener to receive notification of rerouting events.
- *
- * Returns NO_ERROR if successful.
- * (TODO) INVALID_OPERATION if the callback is not installed
- * (TODO) BAD_VALUE if the callback is NULL
- */
- status_t removeAudioDeviceCallback(jobject listener);
-
- /* Register all backed-up routing delegates.
- *
- * Parameters:
- * routingDelegates: backed-up routing delegates
- *
- */
- void registerRoutingDelegates(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates);
-
- /* get listener from RoutingDelegate object
- */
- static jobject getListener(const jobject routingDelegateObj);
-
- /* get handler from RoutingDelegate object
- */
- static jobject getHandler(const jobject routingDelegateObj);
-
- /*
- * Parameters:
- * map and key
- *
- * Returns value if key is in the map
- * nullptr if key is not in the map
- */
- static jobject findByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
-
- /*
- * Parameters:
- * map and key
- */
- static void eraseByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
-
-private:
- audio_output_flags_t mFlags;
-
- jclass mAudioTrackCls;
- jobject mAudioTrackObj;
-
- /* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
- jobject createVolumeShaperConfigurationObj(
- const sp<media::VolumeShaper::Configuration>& config);
-
- /* Creates a Java VolumeShaper.Operation object from VolumeShaper::Operation */
- jobject createVolumeShaperOperationObj(
- const sp<media::VolumeShaper::Operation>& operation);
-
- /* Creates a Java StreamEventCallback object */
- jobject createStreamEventCallback(callback_t cbf, void* user);
-
- /* Creates a Java Executor object for running a callback */
- jobject createCallbackExecutor();
-
- status_t javaToNativeStatus(int javaStatus);
-};
-
-}; // namespace android
-
-#endif // ANDROID_JAUDIOTRACK_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
deleted file mode 100644
index 15f7f83..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIA2_HTTP_CONNECTION_H_
-#define _J_MEDIA2_HTTP_CONNECTION_H_
-
-#include "jni.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPConnection : public MediaHTTPConnection {
- JMedia2HTTPConnection(JNIEnv *env, jobject thiz);
-
- virtual bool connect(
- const char *uri, const KeyedVector<String8, String8> *headers) override;
-
- virtual void disconnect() override;
- virtual ssize_t readAt(off64_t offset, void *data, size_t size) override;
- virtual off64_t getSize() override;
- virtual status_t getMIMEType(String8 *mimeType) override;
- virtual status_t getUri(String8 *uri) override;
-
-protected:
- virtual ~JMedia2HTTPConnection();
-
-private:
- jobject mMedia2HTTPConnectionObj;
- jmethodID mConnectMethod;
- jmethodID mDisconnectMethod;
- jmethodID mReadAtMethod;
- jmethodID mGetSizeMethod;
- jmethodID mGetMIMETypeMethod;
- jmethodID mGetUriMethod;
-
- jbyteArray mByteArrayObj;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPConnection);
-};
-
-} // namespace android
-
-#endif // _J_MEDIA2_HTTP_CONNECTION_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
deleted file mode 100644
index bf61a7f..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIA2_HTTP_SERVICE_H_
-#define _J_MEDIA2_HTTP_SERVICE_H_
-
-#include <jni.h>
-#include <utils/RefBase.h>
-
-#include <media/MediaHTTPService.h>
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPService : public MediaHTTPService {
- JMedia2HTTPService(JNIEnv *env, jobject thiz);
-
- virtual sp<MediaHTTPConnection> makeHTTPConnection() override;
-
-protected:
- virtual ~JMedia2HTTPService();
-
-private:
- jobject mMedia2HTTPServiceObj;
-
- jmethodID mMakeHTTPConnectionMethod;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPService);
-};
-
-} // namespace android
-
-#endif // _J_MEDIA2_HTTP_SERVICE_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h b/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h
deleted file mode 100644
index 93d8b40..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JOBJECT_HOLDER_H_
-
-#define JOBJECT_HOLDER_H_
-
-#include "jni.h"
-#include <mediaplayer2/JavaVMHelper.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-// Helper class for managing global reference of jobject.
-struct JObjectHolder : public RefBase {
- JObjectHolder(jobject obj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- mJObject = reinterpret_cast<jobject>(env->NewGlobalRef(obj));
- }
-
- virtual ~JObjectHolder() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mJObject);
- }
-
- jobject getJObject() { return mJObject; }
-
-private:
- jobject mJObject;
-};
-
-} //" android
-
-#endif // JOBJECT_HOLDER_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h b/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
deleted file mode 100644
index 4b56aca..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef JAVA_VM_HELPER_H_
-
-#define JAVA_VM_HELPER_H_
-
-#include "jni.h"
-
-#include <atomic>
-
-namespace android {
-
-struct JavaVMHelper {
- static JNIEnv *getJNIEnv();
- static JavaVM *getJavaVM();
- static void setJavaVM(JavaVM *vm);
-
-private:
- // Once a valid JavaVM has been set, it should never be reset or changed.
- // However, as it may be accessed from multiple threads, access needs to be
- // synchronized.
- static std::atomic<JavaVM *> sJavaVM;
-};
-
-} // namespace android
-
-#endif // JAVA_VM_HELPER_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
deleted file mode 100644
index f38b7cc..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
-#define ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/JAudioTrack.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include <utility>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-#include "jni.h"
-
-namespace android {
-
-class AudioTrack;
-
-class MediaPlayer2AudioOutput : public MediaPlayer2Interface::AudioSink
-{
- class CallbackData;
-
-public:
- MediaPlayer2AudioOutput(int32_t sessionId,
- uid_t uid,
- int pid,
- const jobject attributes);
- virtual ~MediaPlayer2AudioOutput();
-
- virtual bool ready() const {
- return mJAudioTrack != nullptr;
- }
- virtual ssize_t bufferSize() const;
- virtual ssize_t frameCount() const;
- virtual ssize_t channelCount() const;
- virtual ssize_t frameSize() const;
- virtual uint32_t latency() const;
- virtual float msecsPerFrame() const;
- virtual status_t getPosition(uint32_t *position) const;
- virtual status_t getTimestamp(AudioTimestamp &ts) const;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const;
- virtual int32_t getSessionId() const;
- virtual void setSessionId(const int32_t id);
- virtual uint32_t getSampleRate() const;
- virtual int64_t getBufferDurationInUs() const;
-
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL,
- uint32_t suggestedFrameCount = 0);
-
- virtual status_t start();
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true);
- virtual void stop();
- virtual void flush();
- virtual void pause();
- virtual void close();
- void setAudioAttributes(const jobject attributes);
- virtual audio_stream_type_t getAudioStreamType() const;
-
- void setVolume(float volume);
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
-
- status_t setAuxEffectSendLevel(float level);
- status_t attachAuxEffect(int effectId);
- virtual status_t dump(int fd, const Vector<String16>& args) const;
-
- static bool isOnEmulator();
- static int getMinBufferCount();
- virtual bool needsTrailingPadding() {
- return true;
- // TODO: return correct value.
- //return mNextOutput == NULL;
- }
- // AudioRouting
- virtual status_t setPreferredDevice(jobject device);
- virtual jobject getRoutedDevice();
- virtual status_t addAudioDeviceCallback(jobject routingDelegate);
- virtual status_t removeAudioDeviceCallback(jobject listener);
-
-private:
- static void setMinBufferCount();
- static void CallbackWrapper(int event, void *me, void *info);
- void deleteRecycledTrack_l();
- void close_l();
- status_t updateTrack_l();
-
- sp<JAudioTrack> mJAudioTrack;
- AudioCallback mCallback;
- void * mCallbackCookie;
- CallbackData * mCallbackData;
- sp<JObjectHolder> mAttributes;
- float mVolume;
- AudioPlaybackRate mPlaybackRate;
- uint32_t mSampleRateHz; // sample rate of the content, as set in open()
- float mMsecsPerFrame;
- size_t mFrameSize;
- int32_t mSessionId;
- uid_t mUid;
- int mPid;
- float mSendLevel;
- int mAuxEffectId;
- audio_output_flags_t mFlags;
- sp<JObjectHolder> mPreferredDevice;
- mutable Mutex mLock;
-
- // <listener, routingDelegate>
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>> mRoutingDelegates;
-
- // static variables below not protected by mutex
- static bool mIsOnEmulator;
- static int mMinBufferCount; // 12 for emulator; otherwise 4
-
- // CallbackData is what is passed to the AudioTrack as the "user" data.
- // We need to be able to target this to a different Output on the fly,
- // so we can't use the Output itself for this.
- class CallbackData {
- friend MediaPlayer2AudioOutput;
- public:
- explicit CallbackData(MediaPlayer2AudioOutput *cookie) {
- mData = cookie;
- mSwitching = false;
- }
- MediaPlayer2AudioOutput *getOutput() const {
- return mData;
- }
- void setOutput(MediaPlayer2AudioOutput* newcookie) {
- mData = newcookie;
- }
- // lock/unlock are used by the callback before accessing the payload of this object
- void lock() const {
- mLock.lock();
- }
- void unlock() const {
- mLock.unlock();
- }
-
- // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
- // to the next sink.
-
- // tryBeginTrackSwitch() returns true only if it obtains the lock.
- bool tryBeginTrackSwitch() {
- LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
- if (mLock.tryLock() != OK) {
- return false;
- }
- mSwitching = true;
- return true;
- }
- void endTrackSwitch() {
- if (mSwitching) {
- mLock.unlock();
- }
- mSwitching = false;
- }
-
- private:
- MediaPlayer2AudioOutput *mData;
- mutable Mutex mLock; // a recursive mutex might make this unnecessary.
- bool mSwitching;
- DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
- };
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
deleted file mode 100644
index 7804a62..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2INTERFACE_H
-#define ANDROID_MEDIAPLAYER2INTERFACE_H
-
-#ifdef __cplusplus
-
-#include <sys/types.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/RefBase.h>
-#include <jni.h>
-
-#include <media/AVSyncSettings.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
-#include <media/AudioTimestamp.h>
-#include <media/BufferingSettings.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <mediaplayer2/MediaPlayer2Types.h>
-
-#include "jni.h"
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
-// global, and not in android::
-struct sockaddr_in;
-
-namespace android {
-
-struct DataSourceDesc;
-class Parcel;
-struct ANativeWindowWrapper;
-
-#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
-#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
-
-// when the channel mask isn't known, use the channel count to derive a mask in AudioSink::open()
-#define CHANNEL_MASK_USE_CHANNEL_ORDER 0
-
-// duration below which we do not allow deep audio buffering
-#define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
-
-class MediaPlayer2InterfaceListener: public RefBase
-{
-public:
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj) = 0;
-};
-
-class MediaPlayer2Interface : public AHandler {
-public:
- // AudioSink: abstraction layer for audio output
- class AudioSink : public RefBase {
- public:
- enum cb_event_t {
- CB_EVENT_FILL_BUFFER, // Request to write more data to buffer.
- CB_EVENT_STREAM_END, // Sent after all the buffers queued in AF and HW are played
- // back (after stop is called)
- CB_EVENT_TEAR_DOWN // The AudioTrack was invalidated due to use case change:
- // Need to re-evaluate offloading options
- };
-
- // Callback returns the number of bytes actually written to the buffer.
- typedef size_t (*AudioCallback)(
- AudioSink *audioSink, void *buffer, size_t size, void *cookie, cb_event_t event);
-
- virtual ~AudioSink() {}
- virtual bool ready() const = 0; // audio output is open and ready
- virtual ssize_t bufferSize() const = 0;
- virtual ssize_t frameCount() const = 0;
- virtual ssize_t channelCount() const = 0;
- virtual ssize_t frameSize() const = 0;
- virtual uint32_t latency() const = 0;
- virtual float msecsPerFrame() const = 0;
- virtual status_t getPosition(uint32_t *position) const = 0;
- virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
- virtual int32_t getSessionId() const = 0;
- virtual audio_stream_type_t getAudioStreamType() const = 0;
- virtual uint32_t getSampleRate() const = 0;
- virtual int64_t getBufferDurationInUs() const = 0;
-
- // If no callback is specified, use the "write" API below to submit
- // audio data.
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
- AudioCallback cb = NULL,
- void *cookie = NULL,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL,
- uint32_t suggestedFrameCount = 0) = 0;
-
- virtual status_t start() = 0;
-
- /* Input parameter |size| is in byte units stored in |buffer|.
- * Data is copied over and actual number of bytes written (>= 0)
- * is returned, or no data is copied and a negative status code
- * is returned (even when |blocking| is true).
- * When |blocking| is false, AudioSink will immediately return after
- * part of or full |buffer| is copied over.
- * When |blocking| is true, AudioSink will wait to copy the entire
- * buffer, unless an error occurs or the copy operation is
- * prematurely stopped.
- */
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true) = 0;
-
- virtual void stop() = 0;
- virtual void flush() = 0;
- virtual void pause() = 0;
- virtual void close() = 0;
-
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0;
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
- virtual bool needsTrailingPadding() {
- return true;
- }
-
- virtual status_t setParameters(const String8& /* keyValuePairs */) {
- return NO_ERROR;
- }
- virtual String8 getParameters(const String8& /* keys */) {
- return String8::empty();
- }
-
- // AudioRouting
- virtual status_t setPreferredDevice(jobject device);
- virtual jobject getRoutedDevice();
- virtual status_t addAudioDeviceCallback(jobject routingDelegate);
- virtual status_t removeAudioDeviceCallback(jobject listener);
- };
-
- MediaPlayer2Interface() : mListener(NULL) { }
- virtual ~MediaPlayer2Interface() { }
- virtual status_t initCheck() = 0;
-
- virtual void setAudioSink(const sp<AudioSink>& audioSink) {
- mAudioSink = audioSink;
- }
-
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) = 0;
-
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) = 0;
-
- virtual status_t playNextDataSource(int64_t srcId) = 0;
-
- // pass the buffered native window to the media player service
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
-
- virtual status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
- *buffering = BufferingSettings();
- return OK;
- }
- virtual status_t setBufferingSettings(const BufferingSettings& /* buffering */) {
- return OK;
- }
-
- virtual status_t prepareAsync() = 0;
- virtual status_t start() = 0;
- virtual status_t pause() = 0;
- virtual bool isPlaying() = 0;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
- // by default, players only support setting rate to the default
- if (!isAudioPlaybackRateEqual(rate, AUDIO_PLAYBACK_RATE_DEFAULT)) {
- return BAD_VALUE;
- }
- return OK;
- }
- virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
- *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
- return OK;
- }
- virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
- // By default, players only support setting sync source to default; all other sync
- // settings are ignored. There is no requirement for getters to return set values.
- if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
- return BAD_VALUE;
- }
- return OK;
- }
- virtual status_t getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
- *sync = AVSyncSettings();
- *videoFps = -1.f;
- return OK;
- }
- virtual status_t seekTo(
- int64_t msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
- virtual status_t getCurrentPosition(int64_t *msec) = 0;
- virtual status_t getDuration(int64_t *msec) = 0;
- virtual status_t reset() = 0;
- virtual status_t notifyAt(int64_t /* mediaTimeUs */) {
- return INVALID_OPERATION;
- }
- virtual status_t setLooping(int loop) = 0;
- virtual status_t setParameter(int key, const Parcel &request) = 0;
- virtual status_t getParameter(int key, Parcel *reply) = 0;
-
- virtual status_t getMetrics(char **buffer, size_t *length) = 0;
-
- // Invoke a generic method on the player by using opaque parcels
- // for the request and reply.
- //
- // @param request Parcel that is positioned at the start of the
- // data sent by the java layer.
- // @param[out] reply Parcel to hold the reply data. Cannot be null.
- // @return OK if the call was successful.
- virtual status_t invoke(const PlayerMessage &request, PlayerMessage *reply) = 0;
-
- void setListener(const sp<MediaPlayer2InterfaceListener> &listener) {
- Mutex::Autolock autoLock(mListenerLock);
- mListener = listener;
- }
-
- void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0, const PlayerMessage *obj=NULL) {
- sp<MediaPlayer2InterfaceListener> listener;
- {
- Mutex::Autolock autoLock(mListenerLock);
- listener = mListener;
- }
-
- if (listener) {
- listener->notify(srcId, msg, ext1, ext2, obj);
- }
- }
-
- virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
- return INVALID_OPERATION;
- }
-
- virtual void onMessageReceived(const sp<AMessage> & /* msg */) override { }
-
- // Modular DRM
- virtual status_t prepareDrm(int64_t /*srcId*/, const uint8_t /* uuid */[16],
- const Vector<uint8_t>& /* drmSessionId */) {
- return INVALID_OPERATION;
- }
- virtual status_t releaseDrm(int64_t /*srcId*/) {
- return INVALID_OPERATION;
- }
-
-protected:
- sp<AudioSink> mAudioSink;
-
-private:
- Mutex mListenerLock;
- sp<MediaPlayer2InterfaceListener> mListener;
-};
-
-}; // namespace android
-
-#endif // __cplusplus
-
-
-#endif // ANDROID_MEDIAPLAYER2INTERFACE_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
deleted file mode 100644
index 2430289..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2_TYPES_H
-#define ANDROID_MEDIAPLAYER2_TYPES_H
-
-#include <media/mediaplayer_common.h>
-
-#include <media/MediaSource.h>
-
-namespace android {
-
-typedef MediaSource::ReadOptions::SeekMode MediaPlayer2SeekMode;
-
-enum media2_event_type {
- MEDIA2_NOP = 0, // interface test message
- MEDIA2_PREPARED = 1,
- MEDIA2_PLAYBACK_COMPLETE = 2,
- MEDIA2_BUFFERING_UPDATE = 3,
- MEDIA2_SEEK_COMPLETE = 4,
- MEDIA2_SET_VIDEO_SIZE = 5,
- MEDIA2_STARTED = 6,
- MEDIA2_PAUSED = 7,
- MEDIA2_SKIPPED = 8,
- MEDIA2_NOTIFY_TIME = 98,
- MEDIA2_TIMED_TEXT = 99,
- MEDIA2_ERROR = 100,
- MEDIA2_INFO = 200,
- MEDIA2_SUBTITLE_DATA = 201,
- MEDIA2_META_DATA = 202,
- MEDIA2_DRM_INFO = 210,
-};
-
-// Generic error codes for the media player framework. Errors are fatal, the
-// playback must abort.
-//
-// Errors are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below.
-// In this situation, 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_ERROR.
-// 'ext1' should be a value from the enum media2_error_type.
-// 'ext2' contains an implementation dependant error code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 1xx: Android Player errors. Something went wrong inside the MediaPlayer2.
-// 2xx: Media errors (e.g Codec not supported). There is a problem with the
-// media itself.
-// 3xx: Runtime errors. Some extraordinary condition arose making the playback
-// impossible.
-//
-enum media2_error_type {
- // 0xx
- MEDIA2_ERROR_UNKNOWN = 1,
- // 1xx
- // MEDIA2_ERROR_SERVER_DIED = 100,
- // 2xx
- MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
- // 3xx
- MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
-};
-
-
-// Info and warning codes for the media player framework. These are non fatal,
-// the playback is going on but there might be some user visible issues.
-//
-// Info and warning messages are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below. In this situation,
-// 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_INFO.
-// 'ext1' should be a value from the enum media2_info_type.
-// 'ext2' contains an implementation dependant info code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 7xx: Android Player info/warning (e.g player lagging behind.)
-// 8xx: Media info/warning (e.g media badly interleaved.)
-//
-enum media2_info_type {
- // 0xx
- MEDIA2_INFO_UNKNOWN = 1,
- // The player just started the playback of this data source.
- MEDIA2_INFO_DATA_SOURCE_START = 2,
- // The player just pushed the very first video frame for rendering
- MEDIA2_INFO_VIDEO_RENDERING_START = 3,
- // The player just pushed the very first audio frame for rendering
- MEDIA2_INFO_AUDIO_RENDERING_START = 4,
- // The player just completed the playback of this data source
- MEDIA2_INFO_DATA_SOURCE_END = 5,
- // The player just completed the playback of all data sources.
- // But this is not visible in native code. Just keep this entry for completeness.
- MEDIA2_INFO_DATA_SOURCE_LIST_END = 6,
- // The player just completed an iteration of playback loop. This event is sent only when
- // looping is enabled.
- MEDIA2_INFO_DATA_SOURCE_REPEAT = 7,
-
- //1xx
- // The player just prepared a data source.
- MEDIA2_INFO_PREPARED = 100,
- // The player just completed a call play().
- MEDIA2_INFO_COMPLETE_CALL_PLAY = 101,
- // The player just completed a call pause().
- MEDIA2_INFO_COMPLETE_CALL_PAUSE = 102,
- // The player just completed a call seekTo.
- MEDIA2_INFO_COMPLETE_CALL_SEEK = 103,
-
- // 7xx
- // The video is too complex for the decoder: it can't decode frames fast
- // enough. Possibly only the audio plays fine at this stage.
- MEDIA2_INFO_VIDEO_TRACK_LAGGING = 700,
- // MediaPlayer2 is temporarily pausing playback internally in order to
- // buffer more data.
- MEDIA2_INFO_BUFFERING_START = 701,
- // MediaPlayer2 is resuming playback after filling buffers.
- MEDIA2_INFO_BUFFERING_END = 702,
- // Bandwidth in recent past
- MEDIA2_INFO_NETWORK_BANDWIDTH = 703,
-
- // 8xx
- // Bad interleaving means that a media has been improperly interleaved or not
- // interleaved at all, e.g has all the video samples first then all the audio
- // ones. Video is playing but a lot of disk seek may be happening.
- MEDIA2_INFO_BAD_INTERLEAVING = 800,
- // The media is not seekable (e.g live stream).
- MEDIA2_INFO_NOT_SEEKABLE = 801,
- // New media metadata is available.
- MEDIA2_INFO_METADATA_UPDATE = 802,
- // Audio can not be played.
- MEDIA2_INFO_PLAY_AUDIO_ERROR = 804,
- // Video can not be played.
- MEDIA2_INFO_PLAY_VIDEO_ERROR = 805,
-
- //9xx
- MEDIA2_INFO_TIMED_TEXT_ERROR = 900,
-};
-
-// Do not change these values without updating their counterparts in MediaPlayer2.java
-enum mediaplayer2_states {
- MEDIAPLAYER2_STATE_IDLE = 1001,
- MEDIAPLAYER2_STATE_PREPARED = 1002,
- MEDIAPLAYER2_STATE_PAUSED = 1003,
- MEDIAPLAYER2_STATE_PLAYING = 1004,
- MEDIAPLAYER2_STATE_ERROR = 1005,
-};
-
-enum media_player2_internal_states {
- MEDIA_PLAYER2_STATE_ERROR = 0,
- MEDIA_PLAYER2_IDLE = 1 << 0,
- MEDIA_PLAYER2_INITIALIZED = 1 << 1,
- MEDIA_PLAYER2_PREPARING = 1 << 2,
- MEDIA_PLAYER2_PREPARED = 1 << 3,
- MEDIA_PLAYER2_STARTED = 1 << 4,
- MEDIA_PLAYER2_PAUSED = 1 << 5,
- MEDIA_PLAYER2_PLAYBACK_COMPLETE = 1 << 6
-};
-
-// Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
-// The same enum space is used for both set and get, in case there are future keys that
-// can be both set and get. But as of now, all parameters are either set only or get only.
-enum media2_parameter_keys {
- // Streaming/buffering parameters
- MEDIA2_KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100, // set only
-
- // Return a Parcel containing a single int, which is the channel count of the
- // audio track, or zero for error (e.g. no audio track) or unknown.
- MEDIA2_KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200, // get only
-
- // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
- // values used for rewinding or reverse playback.
- MEDIA2_KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only
-
- // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
- MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400 // set only
-};
-
-// Keep INVOKE_ID_* in sync with MediaPlayer2.java.
-enum media_player2_invoke_ids {
- MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO = 1,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
- MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK = 4,
- MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK = 5,
- MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
- MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK = 7
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2_TYPES_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
deleted file mode 100644
index 1e8a1d5..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2_H
-#define ANDROID_MEDIAPLAYER2_H
-
-#include <media/AVSyncSettings.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/BufferingSettings.h>
-#include <media/mediaplayer_common.h>
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/MediaPlayer2Types.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include <jni.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <system/audio-base.h>
-
-#include "jni.h"
-
-namespace android {
-
-struct ANativeWindowWrapper;
-struct DataSourceDesc;
-class MediaPlayer2AudioOutput;
-
-// ref-counted object for callbacks
-class MediaPlayer2Listener: virtual public RefBase
-{
-public:
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj = NULL) = 0;
-};
-
-class MediaPlayer2 : public MediaPlayer2InterfaceListener
-{
-public:
- ~MediaPlayer2();
-
- static sp<MediaPlayer2> Create(int32_t sessionId, jobject context);
- static status_t DumpAll(int fd, const Vector<String16>& args);
-
- void disconnect();
-
- status_t getSrcId(int64_t *srcId);
- status_t setDataSource(const sp<DataSourceDesc> &dsd);
- status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd);
- status_t playNextDataSource(int64_t srcId);
- status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
- status_t setListener(const sp<MediaPlayer2Listener>& listener);
- status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings& buffering);
- status_t prepareAsync();
- status_t start();
- status_t pause();
- bool isPlaying();
- mediaplayer2_states getState();
- status_t setPlaybackSettings(const AudioPlaybackRate& rate);
- status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint);
- status_t getSyncSettings(
- AVSyncSettings* sync /* nonnull */,
- float* videoFps /* nonnull */);
- status_t getVideoWidth(int *w);
- status_t getVideoHeight(int *h);
- status_t seekTo(
- int64_t msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
- status_t notifyAt(int64_t mediaTimeUs);
- status_t getCurrentPosition(int64_t *msec);
- status_t getDuration(int64_t srcId, int64_t *msec);
- status_t reset();
- status_t setAudioStreamType(audio_stream_type_t type);
- status_t getAudioStreamType(audio_stream_type_t *type);
- status_t setLooping(int loop);
- bool isLooping();
- status_t setVolume(float volume);
- void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj = NULL);
- status_t invoke(const PlayerMessage &request, PlayerMessage *reply);
- status_t setAudioSessionId(int32_t sessionId);
- int32_t getAudioSessionId();
- status_t setAuxEffectSendLevel(float level);
- status_t attachAuxEffect(int effectId);
- status_t setAudioAttributes(const jobject attributes);
- jobject getAudioAttributes();
- status_t getParameter(int key, Parcel* reply);
- status_t getMetrics(char **buffer, size_t *length);
-
- // Modular DRM
- status_t prepareDrm(int64_t srcId,
- const uint8_t uuid[16],
- const Vector<uint8_t>& drmSessionId);
- status_t releaseDrm(int64_t srcId);
- // AudioRouting
- status_t setPreferredDevice(jobject device);
- jobject getRoutedDevice();
- status_t addAudioDeviceCallback(jobject routingDelegate);
- status_t removeAudioDeviceCallback(jobject listener);
-
- status_t dump(int fd, const Vector<String16>& args);
-
-private:
- MediaPlayer2(int32_t sessionId, jobject context);
- bool init();
-
- // Disconnect from the currently connected ANativeWindow.
- void disconnectNativeWindow_l();
-
- status_t setAudioAttributes_l(const jobject attributes);
-
- void clear_l();
- status_t seekTo_l(int64_t msec, MediaPlayer2SeekMode mode);
- status_t prepareAsync_l();
- status_t getDuration_l(int64_t *msec);
- status_t reset_l();
- status_t checkState_l();
-
- pid_t mPid;
- uid_t mUid;
- sp<MediaPlayer2Interface> mPlayer;
- sp<MediaPlayer2AudioOutput> mAudioOutput;
- int64_t mSrcId;
- thread_id_t mLockThreadId;
- mutable Mutex mLock;
- Mutex mNotifyLock;
- sp<MediaPlayer2Listener> mListener;
- media_player2_internal_states mCurrentState;
- bool mTransitionToNext;
- int64_t mCurrentPosition;
- MediaPlayer2SeekMode mCurrentSeekMode;
- int64_t mSeekPosition;
- MediaPlayer2SeekMode mSeekMode;
- audio_stream_type_t mStreamType;
- bool mLoop;
- float mVolume;
- int mVideoWidth;
- int mVideoHeight;
- int32_t mAudioSessionId;
- sp<JObjectHolder> mAudioAttributes;
- sp<JObjectHolder> mContext;
- float mSendLevel;
- sp<ANativeWindowWrapper> mConnectedWindow;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2_H
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
deleted file mode 100644
index de65f8d..0000000
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ /dev/null
@@ -1,1261 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2Native"
-
-#include <android/binder_ibinder.h>
-#include <media/AudioSystem.h>
-#include <media/DataSourceDesc.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <mediaplayer2/MediaPlayer2AudioOutput.h>
-#include <mediaplayer2/mediaplayer2.h>
-
-#include <utils/Log.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
-#include <system/audio.h>
-#include <system/window.h>
-
-#include <nuplayer2/NuPlayer2Driver.h>
-
-#include <dirent.h>
-#include <sys/stat.h>
-
-namespace android {
-
-extern ALooperRoster gLooperRoster;
-
-namespace {
-
-const int kDumpLockRetries = 50;
-const int kDumpLockSleepUs = 20000;
-
-class proxyListener : public MediaPlayer2InterfaceListener {
-public:
- proxyListener(const wp<MediaPlayer2> &player)
- : mPlayer(player) { }
-
- ~proxyListener() { };
-
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj) override {
- sp<MediaPlayer2> player = mPlayer.promote();
- if (player != NULL) {
- player->notify(srcId, msg, ext1, ext2, obj);
- }
- }
-
-private:
- wp<MediaPlayer2> mPlayer;
-};
-
-Mutex sRecordLock;
-SortedVector<wp<MediaPlayer2> > *sPlayers;
-
-void ensureInit_l() {
- if (sPlayers == NULL) {
- sPlayers = new SortedVector<wp<MediaPlayer2> >();
- }
-}
-
-void addPlayer(const wp<MediaPlayer2>& player) {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- sPlayers->add(player);
-}
-
-void removePlayer(const wp<MediaPlayer2>& player) {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- sPlayers->remove(player);
-}
-
-/**
- * The only arguments this understands right now are -c, -von and -voff,
- * which are parsed by ALooperRoster::dump()
- */
-status_t dumpPlayers(int fd, const Vector<String16>& args) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- SortedVector< sp<MediaPlayer2> > players; //to serialise the mutex unlock & client destruction.
-
- {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- for (int i = 0, n = sPlayers->size(); i < n; ++i) {
- sp<MediaPlayer2> p = (*sPlayers)[i].promote();
- if (p != 0) {
- p->dump(fd, args);
- }
- players.add(p);
- }
- }
-
- result.append(" Files opened and/or mapped:\n");
- snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
- FILE *f = fopen(buffer, "r");
- if (f) {
- while (!feof(f)) {
- fgets(buffer, SIZE, f);
- if (strstr(buffer, " /storage/") ||
- strstr(buffer, " /system/sounds/") ||
- strstr(buffer, " /data/") ||
- strstr(buffer, " /system/media/")) {
- result.append(" ");
- result.append(buffer);
- }
- }
- fclose(f);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
- DIR *d = opendir(buffer);
- if (d) {
- struct dirent *ent;
- while((ent = readdir(d)) != NULL) {
- if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
- snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
- struct stat s;
- if (lstat(buffer, &s) == 0) {
- if ((s.st_mode & S_IFMT) == S_IFLNK) {
- char linkto[256];
- int len = readlink(buffer, linkto, sizeof(linkto));
- if(len > 0) {
- if(len > 255) {
- linkto[252] = '.';
- linkto[253] = '.';
- linkto[254] = '.';
- linkto[255] = 0;
- } else {
- linkto[len] = 0;
- }
- if (strstr(linkto, "/storage/") == linkto ||
- strstr(linkto, "/system/sounds/") == linkto ||
- strstr(linkto, "/data/") == linkto ||
- strstr(linkto, "/system/media/") == linkto) {
- result.append(" ");
- result.append(buffer);
- result.append(" -> ");
- result.append(linkto);
- result.append("\n");
- }
- }
- } else {
- result.append(" unexpected type for ");
- result.append(buffer);
- result.append("\n");
- }
- }
- }
- }
- closedir(d);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- gLooperRoster.dump(fd, args);
-
- bool dumpMem = false;
- bool unreachableMemory = false;
- for (size_t i = 0; i < args.size(); i++) {
- if (args[i] == String16("-m")) {
- dumpMem = true;
- } else if (args[i] == String16("--unreachable")) {
- unreachableMemory = true;
- }
- }
- if (dumpMem) {
- result.append("\nDumping memory:\n");
- std::string s = dumpMemoryAddresses(100 /* limit */);
- result.append(s.c_str(), s.size());
- }
- if (unreachableMemory) {
- result.append("\nDumping unreachable memory:\n");
- // TODO - should limit be an argument parameter?
- // TODO: enable GetUnreachableMemoryString if it's part of stable API
- //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
- //result.append(s.c_str(), s.size());
- }
-
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-} // anonymous namespace
-
-//static
-sp<MediaPlayer2> MediaPlayer2::Create(int32_t sessionId, jobject context) {
- sp<MediaPlayer2> player = new MediaPlayer2(sessionId, context);
-
- if (!player->init()) {
- return NULL;
- }
-
- ALOGV("Create new player(%p)", player.get());
-
- addPlayer(player);
- return player;
-}
-
-// static
-status_t MediaPlayer2::DumpAll(int fd, const Vector<String16>& args) {
- return dumpPlayers(fd, args);
-}
-
-MediaPlayer2::MediaPlayer2(int32_t sessionId, jobject context) {
- ALOGV("constructor");
- mSrcId = 0;
- mLockThreadId = 0;
- mListener = NULL;
- mStreamType = AUDIO_STREAM_MUSIC;
- mAudioAttributes = NULL;
- mContext = new JObjectHolder(context);
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- mLoop = false;
- mVolume = 1.0;
- mVideoWidth = mVideoHeight = 0;
- mSendLevel = 0;
-
- mPid = AIBinder_getCallingPid();
- mUid = AIBinder_getCallingUid();
-
- mAudioOutput = new MediaPlayer2AudioOutput(sessionId, mUid, mPid, NULL /*attributes*/);
-}
-
-MediaPlayer2::~MediaPlayer2() {
- ALOGV("destructor");
- disconnect();
- removePlayer(this);
-}
-
-bool MediaPlayer2::init() {
- // TODO: after merge with NuPlayer2Driver, MediaPlayer2 will have its own
- // looper for notification.
- return true;
-}
-
-void MediaPlayer2::disconnect() {
- ALOGV("disconnect");
- sp<MediaPlayer2Interface> p;
- {
- Mutex::Autolock _l(mLock);
- p = mPlayer;
- mPlayer.clear();
- }
-
- if (p != 0) {
- p->setListener(NULL);
- p->reset();
- }
-
- {
- Mutex::Autolock _l(mLock);
- disconnectNativeWindow_l();
- }
-}
-
-void MediaPlayer2::clear_l() {
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mVideoWidth = mVideoHeight = 0;
-}
-
-status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener) {
- ALOGV("setListener");
- Mutex::Autolock _l(mLock);
- mListener = listener;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getSrcId(int64_t *srcId) {
- if (srcId == NULL) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mLock);
- *srcId = mSrcId;
- return OK;
-}
-
-status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- // Microsecond is used in NuPlayer2.
- if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- if (dsd->mEndPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mEndPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
-
- sp<MediaPlayer2Interface> oldPlayer;
-
- {
- Mutex::Autolock _l(mLock);
- if (!((mCurrentState & MEDIA_PLAYER2_IDLE)
- || mCurrentState == MEDIA_PLAYER2_STATE_ERROR)) {
- ALOGE("setDataSource called in wrong state %d", mCurrentState);
- return INVALID_OPERATION;
- }
-
- sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid, mContext);
- status_t err = player->initCheck();
- if (err != NO_ERROR) {
- ALOGE("Failed to create player object, initCheck failed(%d)", err);
- return err;
- }
-
- clear_l();
-
- player->setListener(new proxyListener(this));
- player->setAudioSink(mAudioOutput);
-
- err = player->setDataSource(dsd);
- if (err != OK) {
- ALOGE("setDataSource error: %d", err);
- return err;
- }
-
- sp<MediaPlayer2Interface> oldPlayer = mPlayer;
- mPlayer = player;
- mSrcId = dsd->mId;
- mCurrentState = MEDIA_PLAYER2_INITIALIZED;
- }
-
- if (oldPlayer != NULL) {
- oldPlayer->setListener(NULL);
- oldPlayer->reset();
- }
-
- return OK;
-}
-
-status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- return mPlayer->prepareNextDataSource(dsd);
-}
-
-status_t MediaPlayer2::playNextDataSource(int64_t srcId) {
- ALOGV("playNextDataSource srcId(%lld)", (long long)srcId);
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- mSrcId = srcId;
- mTransitionToNext = true;
- return mPlayer->playNextDataSource(srcId);
-}
-
-status_t MediaPlayer2::invoke(const PlayerMessage &request, PlayerMessage *reply) {
- Mutex::Autolock _l(mLock);
- const bool hasBeenInitialized =
- (mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
- ((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
- if ((mPlayer == NULL) || !hasBeenInitialized) {
- ALOGE("invoke() failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- return mPlayer->invoke(request, reply);
-}
-
-void MediaPlayer2::disconnectNativeWindow_l() {
- if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
- status_t err = native_window_api_disconnect(
- mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
- mConnectedWindow.clear();
-}
-
-status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) {
- ANativeWindow *anw = (nww == NULL ? NULL : nww->getANativeWindow());
- ALOGV("setVideoSurfaceTexture(%p)", anw);
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
-
- if (anw != NULL) {
- if (mConnectedWindow != NULL
- && mConnectedWindow->getANativeWindow() == anw) {
- return OK;
- }
- status_t err = native_window_api_connect(anw, NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGE("setVideoSurfaceTexture failed: %d", err);
- // Note that we must do the reset before disconnecting from the ANW.
- // Otherwise queue/dequeue calls could be made on the disconnected
- // ANW, which may result in errors.
- mPlayer->reset();
- disconnectNativeWindow_l();
- return err;
- }
- }
-
- // Note that we must set the player's new GraphicBufferProducer before
- // disconnecting the old one. Otherwise queue/dequeue calls could be made
- // on the disconnected ANW, which may result in errors.
- status_t err = mPlayer->setVideoSurfaceTexture(nww);
-
- disconnectNativeWindow_l();
-
- if (err == OK) {
- mConnectedWindow = nww;
- mLock.unlock();
- } else if (anw != NULL) {
- mLock.unlock();
- status_t err = native_window_api_disconnect(anw, NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
-
- return err;
-}
-
-status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
- ALOGV("getBufferingSettings");
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
-
- status_t ret = mPlayer->getBufferingSettings(buffering);
- if (ret == NO_ERROR) {
- ALOGV("getBufferingSettings{%s}", buffering->toString().string());
- } else {
- ALOGE("getBufferingSettings returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings{%s}", buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
- return mPlayer->setBufferingSettings(buffering);
-}
-
-status_t MediaPlayer2::setAudioAttributes_l(const jobject attributes) {
- if (mAudioOutput != NULL) {
- mAudioOutput->setAudioAttributes(attributes);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::prepareAsync() {
- ALOGV("prepareAsync");
- Mutex::Autolock _l(mLock);
- if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_INITIALIZED)) {
- if (mAudioAttributes != NULL) {
- status_t err = setAudioAttributes_l(mAudioAttributes->getJObject());
- if (err != OK) {
- return err;
- }
- }
- mCurrentState = MEDIA_PLAYER2_PREPARING;
- return mPlayer->prepareAsync();
- }
- ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
-}
-
-status_t MediaPlayer2::start() {
- ALOGV("start");
-
- status_t ret = NO_ERROR;
- Mutex::Autolock _l(mLock);
-
- mLockThreadId = getThreadId();
-
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- ret = NO_ERROR;
- } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE | MEDIA_PLAYER2_PAUSED ) ) ) {
- mPlayer->setLooping(mLoop);
-
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(mVolume);
- }
-
- if (mAudioOutput != 0) {
- mAudioOutput->setAuxEffectSendLevel(mSendLevel);
- }
- mCurrentState = MEDIA_PLAYER2_STARTED;
- ret = mPlayer->start();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- if (mCurrentState == MEDIA_PLAYER2_PLAYBACK_COMPLETE) {
- ALOGV("playback completed immediately following start()");
- }
- }
- } else {
- ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- ret = INVALID_OPERATION;
- }
-
- mLockThreadId = 0;
-
- return ret;
-}
-
-status_t MediaPlayer2::pause() {
- ALOGV("pause");
- Mutex::Autolock _l(mLock);
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
- return NO_ERROR;
- if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED))) {
- status_t ret = mPlayer->pause();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- mTransitionToNext = false;
- }
- return ret;
- }
- ALOGE("pause called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
-}
-
-bool MediaPlayer2::isPlaying() {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- bool temp = mPlayer->isPlaying();
- ALOGV("isPlaying: %d", temp);
- if ((mCurrentState & MEDIA_PLAYER2_STARTED) && ! temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- } else if ((mCurrentState & MEDIA_PLAYER2_PAUSED) && temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_STARTED;
- }
- return temp;
- }
- ALOGV("isPlaying: no active player");
- return false;
-}
-
-mediaplayer2_states MediaPlayer2::getState() {
- Mutex::Autolock _l(mLock);
- if (mCurrentState & MEDIA_PLAYER2_STATE_ERROR) {
- return MEDIAPLAYER2_STATE_ERROR;
- }
- if (mPlayer == 0
- || (mCurrentState &
- (MEDIA_PLAYER2_IDLE | MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_PREPARING))) {
- return MEDIAPLAYER2_STATE_IDLE;
- }
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- return MEDIAPLAYER2_STATE_PLAYING;
- }
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE)) {
- return MEDIAPLAYER2_STATE_PAUSED;
- }
- // now only mCurrentState & MEDIA_PLAYER2_PREPARED is true
- return MEDIAPLAYER2_STATE_PREPARED;
-}
-
-status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate) {
- ALOGV("setPlaybackSettings: %f %f %d %d",
- rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- // Negative speed and pitch does not make sense. Further validation will
- // be done by the respective mediaplayers.
- if (rate.mSpeed <= 0.f || rate.mPitch < 0.f) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
-
- status_t err = mPlayer->setPlaybackSettings(rate);
- return err;
-}
-
-status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- status_t ret = mPlayer->getPlaybackSettings(rate);
- if (ret == NO_ERROR) {
- ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
- rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
- } else {
- ALOGV("getPlaybackSettings returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) {
- ALOGV("setSyncSettings: %u %u %f %f",
- sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
- return mPlayer->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t MediaPlayer2::getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- status_t ret = mPlayer->getSyncSettings(sync, videoFps);
- if (ret == NO_ERROR) {
- ALOGV("getSyncSettings(%u, %u, %f, %f)",
- sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
- } else {
- ALOGV("getSyncSettings returned %d", ret);
- }
- return ret;
-
-}
-
-status_t MediaPlayer2::getVideoWidth(int *w) {
- ALOGV("getVideoWidth");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *w = mVideoWidth;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getVideoHeight(int *h) {
- ALOGV("getVideoHeight");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *h = mVideoHeight;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getCurrentPosition(int64_t *msec) {
- ALOGV("getCurrentPosition");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- if (mCurrentPosition >= 0) {
- ALOGV("Using cached seek position: %lld", (long long)mCurrentPosition);
- *msec = mCurrentPosition;
- return NO_ERROR;
- }
- status_t ret = mPlayer->getCurrentPosition(msec);
- if (ret == NO_ERROR) {
- ALOGV("getCurrentPosition = %lld", (long long)*msec);
- } else {
- ALOGE("getCurrentPosition returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::getDuration(int64_t srcId, int64_t *msec) {
- Mutex::Autolock _l(mLock);
- // TODO: cache duration for currentSrcId and nextSrcId, and return correct
- // value for nextSrcId.
- if (srcId != mSrcId) {
- *msec = -1;
- return OK;
- }
-
- ALOGV("getDuration_l");
- bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
- if (mPlayer == 0 || !isValidState) {
- ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- int64_t durationMs;
- status_t ret = mPlayer->getDuration(&durationMs);
-
- if (ret == NO_ERROR) {
- ALOGV("getDuration = %lld", (long long)durationMs);
- } else {
- ALOGE("getDuration returned %d", ret);
- // Do not enter error state just because no duration was available.
- durationMs = -1;
- }
-
- if (msec) {
- *msec = durationMs;
- }
- return OK;
-}
-
-status_t MediaPlayer2::seekTo_l(int64_t msec, MediaPlayer2SeekMode mode) {
- ALOGV("seekTo (%lld, %d)", (long long)msec, mode);
- if ((mPlayer == 0) || !(mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
- ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- if (msec < 0) {
- ALOGW("Attempt to seek to invalid position: %lld", (long long)msec);
- msec = 0;
- }
-
- int64_t durationMs;
- status_t err = mPlayer->getDuration(&durationMs);
-
- if (err != OK) {
- ALOGW("Stream has no duration and is therefore not seekable.");
- return err;
- }
-
- if (msec > durationMs) {
- ALOGW("Attempt to seek to past end of file: request = %lld, durationMs = %lld",
- (long long)msec, (long long)durationMs);
-
- msec = durationMs;
- }
-
- // cache duration
- mCurrentPosition = msec;
- mCurrentSeekMode = mode;
- if (mSeekPosition < 0) {
- mSeekPosition = msec;
- mSeekMode = mode;
- return mPlayer->seekTo(msec, mode);
- }
- ALOGV("Seek in progress - queue up seekTo[%lld, %d]", (long long)msec, mode);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = seekTo_l(msec, mode);
- mLockThreadId = 0;
-
- return result;
-}
-
-status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs) {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return INVALID_OPERATION;
- }
-
- return mPlayer->notifyAt(mediaTimeUs);
-}
-
-status_t MediaPlayer2::reset_l() {
- mLoop = false;
- if (mCurrentState == MEDIA_PLAYER2_IDLE) {
- return NO_ERROR;
- }
- if (mPlayer != 0) {
- status_t ret = mPlayer->reset();
- if (ret != NO_ERROR) {
- ALOGE("reset() failed with return code (%d)", ret);
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- mPlayer->setListener(NULL);
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- }
- // setDataSource has to be called again to create a
- // new mediaplayer.
- mPlayer = 0;
- return ret;
- }
- clear_l();
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::reset() {
- ALOGV("reset");
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = reset_l();
- mLockThreadId = 0;
-
- return result;
-}
-
-status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type) {
- ALOGV("MediaPlayer2::setAudioStreamType");
- Mutex::Autolock _l(mLock);
- if (mStreamType == type) return NO_ERROR;
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE ) ) {
- // Can't change the stream type after prepare
- ALOGE("setAudioStream called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- // cache
- mStreamType = type;
- return OK;
-}
-
-status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type) {
- ALOGV("getAudioStreamType");
- Mutex::Autolock _l(mLock);
- *type = mStreamType;
- return OK;
-}
-
-status_t MediaPlayer2::setLooping(int loop) {
- ALOGV("MediaPlayer2::setLooping");
- Mutex::Autolock _l(mLock);
- mLoop = (loop != 0);
- if (mPlayer != 0) {
- return mPlayer->setLooping(loop);
- }
- return OK;
-}
-
-bool MediaPlayer2::isLooping() {
- ALOGV("isLooping");
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return mLoop;
- }
- ALOGV("isLooping: no active player");
- return false;
-}
-
-status_t MediaPlayer2::setVolume(float volume) {
- ALOGV("MediaPlayer2::setVolume(%f)", volume);
- Mutex::Autolock _l(mLock);
- mVolume = volume;
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(volume);
- }
- return OK;
-}
-
-status_t MediaPlayer2::setAudioSessionId(int32_t sessionId) {
- ALOGV("MediaPlayer2::setAudioSessionId(%d)", sessionId);
- Mutex::Autolock _l(mLock);
- if (!(mCurrentState & MEDIA_PLAYER2_IDLE)) {
- ALOGE("setAudioSessionId called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- if (sessionId < 0) {
- return BAD_VALUE;
- }
- if (mAudioOutput != NULL && sessionId != mAudioOutput->getSessionId()) {
- mAudioOutput->setSessionId(sessionId);
- }
- return NO_ERROR;
-}
-
-int32_t MediaPlayer2::getAudioSessionId() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput != NULL) {
- return mAudioOutput->getSessionId();
- }
- return 0;
-}
-
-status_t MediaPlayer2::setAuxEffectSendLevel(float level) {
- ALOGV("MediaPlayer2::setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock _l(mLock);
- mSendLevel = level;
- if (mAudioOutput != 0) {
- return mAudioOutput->setAuxEffectSendLevel(level);
- }
- return OK;
-}
-
-status_t MediaPlayer2::attachAuxEffect(int effectId) {
- ALOGV("MediaPlayer2::attachAuxEffect(%d)", effectId);
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == 0 ||
- (mCurrentState & MEDIA_PLAYER2_IDLE) ||
- (mCurrentState == MEDIA_PLAYER2_STATE_ERROR )) {
- ALOGE("attachAuxEffect called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
-
- return mAudioOutput->attachAuxEffect(effectId);
-}
-
-// always call with lock held
-status_t MediaPlayer2::checkState_l() {
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) {
- // Can't change the audio attributes after prepare
- ALOGE("trying to set audio attributes called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- return OK;
-}
-
-status_t MediaPlayer2::setAudioAttributes(const jobject attributes) {
- ALOGV("MediaPlayer2::setAudioAttributes");
- status_t status = INVALID_OPERATION;
- Mutex::Autolock _l(mLock);
- if (checkState_l() != OK) {
- return status;
- }
- mAudioAttributes = new JObjectHolder(attributes);
- status = setAudioAttributes_l(attributes);
- return status;
-}
-
-jobject MediaPlayer2::getAudioAttributes() {
- ALOGV("MediaPlayer2::getAudioAttributes)");
- Mutex::Autolock _l(mLock);
- return mAudioAttributes != NULL ? mAudioAttributes->getJObject() : NULL;
-}
-
-status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
- ALOGV("MediaPlayer2::getParameter(%d)", key);
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getParameter: no active player");
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->getParameter(key, reply);
- if (status != OK) {
- ALOGD("getParameter returns %d", status);
- }
- return status;
-}
-
-// for mediametrics
-status_t MediaPlayer2::getMetrics(char **buffer, size_t *length) {
- ALOGD("MediaPlayer2::getMetrics()");
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getMetrics: no active player");
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->getMetrics(buffer, length);
- if (status != OK) {
- ALOGD("getMetrics returns %d", status);
- }
- return status;
-}
-
-void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *obj) {
- ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
- (long long)srcId, msg, ext1, ext2);
-
- bool send = true;
- bool locked = false;
-
- // TODO: In the future, we might be on the same thread if the app is
- // running in the same process as the media server. In that case,
- // this will deadlock.
- //
- // The threadId hack below works around this for the care of prepare,
- // seekTo, start, and reset within the same process.
- // FIXME: Remember, this is a hack, it's not even a hack that is applied
- // consistently for all use-cases, this needs to be revisited.
- if (mLockThreadId != getThreadId()) {
- mLock.lock();
- locked = true;
- }
-
- // Allows calls from JNI in idle state to notify errors
- if (!(msg == MEDIA2_ERROR && mCurrentState == MEDIA_PLAYER2_IDLE) && mPlayer == 0) {
- ALOGV("notify(%lld, %d, %d, %d) callback on disconnected mediaplayer",
- (long long)srcId, msg, ext1, ext2);
- if (locked) mLock.unlock(); // release the lock when done.
- return;
- }
-
- switch (msg) {
- case MEDIA2_NOP: // interface test message
- break;
- case MEDIA2_PREPARED:
- ALOGV("MediaPlayer2::notify() prepared, srcId=%lld", (long long)srcId);
- if (srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PREPARED;
- }
- break;
- case MEDIA2_DRM_INFO:
- ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
- (long long)srcId, msg, ext1, ext2, obj);
- break;
- case MEDIA2_PLAYBACK_COMPLETE:
- ALOGV("playback complete");
- if (mCurrentState == MEDIA_PLAYER2_IDLE) {
- ALOGE("playback complete in idle state");
- }
- if (!mLoop && srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PLAYBACK_COMPLETE;
- }
- break;
- case MEDIA2_ERROR:
- // Always log errors.
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- ALOGE("error (%d, %d)", ext1, ext2);
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- break;
- case MEDIA2_INFO:
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- if (ext1 != MEDIA2_INFO_VIDEO_TRACK_LAGGING) {
- ALOGW("info/warning (%d, %d)", ext1, ext2);
-
- if (ext1 == MEDIA2_INFO_DATA_SOURCE_START && srcId == mSrcId && mTransitionToNext) {
- mCurrentState = MEDIA_PLAYER2_STARTED;
- mTransitionToNext = false;
- }
- }
- break;
- case MEDIA2_SEEK_COMPLETE:
- ALOGV("Received seek complete");
- if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
- ALOGV("Executing queued seekTo(%lld, %d)",
- (long long)mCurrentPosition, mCurrentSeekMode);
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- seekTo_l(mCurrentPosition, mCurrentSeekMode);
- }
- else {
- ALOGV("All seeks complete - return to regularly scheduled program");
- mCurrentPosition = mSeekPosition = -1;
- mCurrentSeekMode = mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- }
- break;
- case MEDIA2_BUFFERING_UPDATE:
- ALOGV("buffering %d", ext1);
- break;
- case MEDIA2_SET_VIDEO_SIZE:
- ALOGV("New video size %d x %d", ext1, ext2);
- mVideoWidth = ext1;
- mVideoHeight = ext2;
- break;
- case MEDIA2_NOTIFY_TIME:
- ALOGV("Received notify time message");
- break;
- case MEDIA2_TIMED_TEXT:
- ALOGV("Received timed text message");
- break;
- case MEDIA2_SUBTITLE_DATA:
- ALOGV("Received subtitle data message");
- break;
- case MEDIA2_META_DATA:
- ALOGV("Received timed metadata message");
- break;
- default:
- ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
- break;
- }
-
- sp<MediaPlayer2Listener> listener = mListener;
- if (locked) mLock.unlock();
-
- // this prevents re-entrant calls into client code
- if ((listener != 0) && send) {
- Mutex::Autolock _l(mNotifyLock);
- ALOGV("callback application");
- listener->notify(srcId, msg, ext1, ext2, obj);
- ALOGV("back from callback");
- }
-}
-
-// Modular DRM
-status_t MediaPlayer2::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
- // TODO change to ALOGV
- ALOGD("prepareDrm: uuid: %p drmSessionId: %p(%zu)", uuid,
- drmSessionId.array(), drmSessionId.size());
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- // Only allowed it in player's preparing/prepared state.
- // We get here only if MEDIA_DRM_INFO has already arrived (e.g., prepare is half-way through or
- // completed) so the state change to "prepared" might not have happened yet (e.g., buffering).
- // Still, we can allow prepareDrm for the use case of being called in OnDrmInfoListener.
- if (!(mCurrentState & (MEDIA_PLAYER2_PREPARING | MEDIA_PLAYER2_PREPARED))) {
- ALOGW("prepareDrm(%lld) called in non-prepare state(%d)", (long long)srcId, mCurrentState);
- if (srcId == mSrcId) {
- return INVALID_OPERATION;
- }
- }
-
- if (drmSessionId.isEmpty()) {
- ALOGE("prepareDrm: Unexpected. Can't proceed with crypto. Empty drmSessionId.");
- return INVALID_OPERATION;
- }
-
- // Passing down to mediaserver mainly for creating the crypto
- status_t status = mPlayer->prepareDrm(srcId, uuid, drmSessionId);
- ALOGE_IF(status != OK, "prepareDrm: Failed at mediaserver with ret: %d", status);
-
- // TODO change to ALOGV
- ALOGD("prepareDrm: mediaserver::prepareDrm ret=%d", status);
-
- return status;
-}
-
-status_t MediaPlayer2::releaseDrm(int64_t srcId) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- // Not allowing releaseDrm in an active/resumable state
- if (mCurrentState & (MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE |
- MEDIA_PLAYER2_STATE_ERROR)) {
- ALOGE("releaseDrm Unexpected state %d. Can only be called in stopped/idle.", mCurrentState);
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->releaseDrm(srcId);
- // TODO change to ALOGV
- ALOGD("releaseDrm: mediaserver::releaseDrm ret: %d", status);
- if (status != OK) {
- ALOGE("releaseDrm: Failed at mediaserver with ret: %d", status);
- // Overriding to OK so the client proceed with its own cleanup
- // Client can't do more cleanup. mediaserver release its crypto at end of session anyway.
- status = OK;
- }
-
- return status;
-}
-
-status_t MediaPlayer2::setPreferredDevice(jobject device) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("setPreferredDevice: audio sink not init");
- return NO_INIT;
- }
- return mAudioOutput->setPreferredDevice(device);
-}
-
-jobject MediaPlayer2::getRoutedDevice() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("getRoutedDevice: audio sink not init");
- return nullptr;
- }
- return mAudioOutput->getRoutedDevice();
-}
-
-status_t MediaPlayer2::addAudioDeviceCallback(jobject routingDelegate) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->addAudioDeviceCallback(routingDelegate);
-}
-
-status_t MediaPlayer2::removeAudioDeviceCallback(jobject listener) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->removeAudioDeviceCallback(listener);
-}
-
-status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- result.append(" MediaPlayer2\n");
- snprintf(buffer, 255, " pid(%d), looping(%s)\n", mPid, mLoop?"true": "false");
- result.append(buffer);
-
- sp<MediaPlayer2Interface> player;
- sp<MediaPlayer2AudioOutput> audioOutput;
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleepUs);
- }
-
- if (locked) {
- player = mPlayer;
- audioOutput = mAudioOutput;
- mLock.unlock();
- } else {
- result.append(" lock is taken, no dump from player and audio output\n");
- }
- write(fd, result.string(), result.size());
-
- if (player != NULL) {
- player->dump(fd, args);
- }
- if (audioOutput != 0) {
- audioOutput->dump(fd, args);
- }
- write(fd, "\n", 1);
- return NO_ERROR;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
deleted file mode 100644
index 0f69b2e..0000000
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-cc_library_static {
-
- srcs: [
- "JMediaPlayer2Utils.cpp",
- "JWakeLock.cpp",
- "GenericSource2.cpp",
- "HTTPLiveSource2.cpp",
- "NuPlayer2.cpp",
- "NuPlayer2CCDecoder.cpp",
- "NuPlayer2Decoder.cpp",
- "NuPlayer2DecoderBase.cpp",
- "NuPlayer2DecoderPassThrough.cpp",
- "NuPlayer2Driver.cpp",
- "NuPlayer2Drm.cpp",
- "NuPlayer2Renderer.cpp",
- "RTSPSource2.cpp",
- ],
-
- header_libs: [
- "libbase_headers",
- "libmediaplayer2_headers",
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/httplive",
- "frameworks/av/media/libstagefright/include",
- "frameworks/av/media/libstagefright/mpeg2ts",
- "frameworks/av/media/libstagefright/rtsp",
- "frameworks/av/media/libstagefright/timedtext",
- "frameworks/av/media/ndk",
- "frameworks/base/core/jni",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-
- product_variables: {
- debuggable: {
- cflags: [
- "-DENABLE_STAGEFRIGHT_EXPERIMENTS",
- ],
- }
- },
-
- shared_libs: [
- "libbinder",
- "libui",
- "libgui",
- "libmedia",
- "libmediametrics",
- "libmediandk",
- "libmediandk_utils",
- "libpowermanager",
- ],
-
- static_libs: [
- "libmedia_helper",
- "libmediaplayer2-protos",
- "libmedia2_jni_core",
- ],
-
- name: "libstagefright_nuplayer2",
-
- sanitize: {
- cfi: true,
- },
-
-}
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
deleted file mode 100644
index 9552580..0000000
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ /dev/null
@@ -1,1547 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "GenericSource2"
-
-#include "GenericSource2.h"
-#include "NuPlayer2Drm.h"
-
-#include "AnotherPacketSource.h"
-#include <cutils/properties.h>
-#include <media/DataSource.h>
-#include <media/MediaBufferHolder.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/NdkUtils.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-static const int kInitialMarkMs = 5000; // 5secs
-
-//static const int kPausePlaybackMarkMs = 2000; // 2secs
-static const int kResumePlaybackMarkMs = 15000; // 15secs
-
-NuPlayer2::GenericSource2::GenericSource2(
- const sp<AMessage> ¬ify,
- uid_t uid,
- const sp<MediaClock> &mediaClock)
- : Source(notify),
- mAudioTimeUs(0),
- mAudioLastDequeueTimeUs(0),
- mVideoTimeUs(0),
- mVideoLastDequeueTimeUs(0),
- mPrevBufferPercentage(-1),
- mPollBufferingGeneration(0),
- mSentPauseOnBuffering(false),
- mAudioDataGeneration(0),
- mVideoDataGeneration(0),
- mFetchSubtitleDataGeneration(0),
- mFetchTimedTextDataGeneration(0),
- mDurationUs(-1ll),
- mAudioIsVorbis(false),
- mIsSecure(false),
- mIsStreaming(false),
- mUID(uid),
- mMediaClock(mediaClock),
- mFd(-1),
- mBitrate(-1ll),
- mPendingReadBufferTypes(0) {
- ALOGV("GenericSource2");
- CHECK(mediaClock != NULL);
-
- mBufferingSettings.mInitialMarkMs = kInitialMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs;
- resetDataSource();
-}
-
-void NuPlayer2::GenericSource2::resetDataSource() {
- ALOGV("resetDataSource");
-
- mDisconnected = false;
- mUri.clear();
- mUriHeaders.clear();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
- mOffset = 0;
- mLength = 0;
- mStarted = false;
- mPreparing = false;
-
- mIsDrmProtected = false;
- mIsDrmReleased = false;
- mIsSecure = false;
- mMimes.clear();
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource url: %s", url);
-
- resetDataSource();
-
- mUri = url;
-
- if (headers) {
- mUriHeaders = *headers;
- }
-
- // delay data source creation to prepareAsync() to avoid blocking
- // the calling thread in setDataSource for any significant time.
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(
- int fd, int64_t offset, int64_t length) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
-
- resetDataSource();
-
- mFd = dup(fd);
- mOffset = offset;
- mLength = length;
-
- // delay data source creation to prepareAsync() to avoid blocking
- // the calling thread in setDataSource for any significant time.
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(const sp<DataSource>& source) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource (source: %p)", source.get());
-
- resetDataSource();
- mDataSourceWrapper = new AMediaDataSourceWrapper(source);
- return OK;
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFileFormatMeta() const {
- Mutex::Autolock _l(mLock);
- return mFileMeta;
-}
-
-status_t NuPlayer2::GenericSource2::initFromDataSource() {
- mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- CHECK(mFd >=0 || mDataSourceWrapper != NULL);
- sp<AMediaDataSourceWrapper> aSourceWrapper = mDataSourceWrapper;
- const int fd = mFd;
-
- mLock.unlock();
- // This might take long time if data source is not reliable.
- status_t err;
- if (aSourceWrapper != NULL) {
- err = mExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
- } else {
- err = mExtractor->setDataSource(fd, mOffset, mLength);
- }
-
- if (err != OK) {
- ALOGE("initFromDataSource, failed to set extractor data source!");
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- size_t numtracks = mExtractor->getTrackCount();
- if (numtracks == 0) {
- ALOGE("initFromDataSource, source has no track!");
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
- mLock.lock();
- if (mFileMeta != NULL) {
- int64_t duration;
- if (mFileMeta->findInt64(kKeyDuration, &duration)) {
- mDurationUs = duration;
- }
- }
-
- int32_t totalBitrate = 0;
-
- mMimes.clear();
-
- for (size_t i = 0; i < numtracks; ++i) {
-
- sp<AMediaFormatWrapper> trackFormat = mExtractor->getTrackFormat(i);
- if (trackFormat == NULL) {
- ALOGE("no metadata for track %zu", i);
- return UNKNOWN_ERROR;
- }
-
- sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- if (aSourceWrapper != NULL) {
- trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
- } else {
- trackExtractor->setDataSource(fd, mOffset, mLength);
- }
-
- const char *mime;
- sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- ALOGV("initFromDataSource track[%zu]: %s", i, mime);
-
- // Do the string compare immediately with "mime",
- // we can't assume "mime" would stay valid after another
- // extractor operation, some extractors might modify meta
- // during getTrack() and make it invalid.
- if (!strncasecmp(mime, "audio/", 6)) {
- if (mAudioTrack.mExtractor == NULL) {
- mAudioTrack.mIndex = i;
- mAudioTrack.mExtractor = trackExtractor;
- mAudioTrack.mExtractor->selectTrack(i);
- mAudioTrack.mPackets = new AnotherPacketSource(meta);
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
- mAudioIsVorbis = true;
- } else {
- mAudioIsVorbis = false;
- }
-
- mMimes.add(String8(mime));
- }
- } else if (!strncasecmp(mime, "video/", 6)) {
- if (mVideoTrack.mExtractor == NULL) {
- mVideoTrack.mIndex = i;
- mVideoTrack.mExtractor = trackExtractor;
- mVideoTrack.mExtractor->selectTrack(i);
- mVideoTrack.mPackets = new AnotherPacketSource(meta);
-
- // video always at the beginning
- mMimes.insertAt(String8(mime), 0);
- }
- }
-
- mExtractors.push(trackExtractor);
- int64_t durationUs;
- if (meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- int32_t bitrate;
- if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitrate += bitrate;
- } else {
- totalBitrate = -1;
- }
- }
-
- ALOGV("initFromDataSource mExtractors.size(): %zu mIsSecure: %d mime[0]: %s", mExtractors.size(),
- mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
-
- if (mExtractors.size() == 0) {
- ALOGE("b/23705695");
- return UNKNOWN_ERROR;
- }
-
- // Modular DRM: The return value doesn't affect source initialization.
- (void)checkDrmInfo();
-
- mBitrate = totalBitrate;
-
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- {
- Mutex::Autolock _l(mLock);
- *buffering = mBufferingSettings;
- }
-
- ALOGV("getBufferingSettings{%s}", buffering->toString().string());
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings{%s}", buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- mBufferingSettings = buffering;
- return OK;
-}
-
-int64_t NuPlayer2::GenericSource2::getLastReadPosition() {
- if (mAudioTrack.mExtractor != NULL) {
- return mAudioTimeUs;
- } else if (mVideoTrack.mExtractor != NULL) {
- return mVideoTimeUs;
- } else {
- return 0;
- }
-}
-
-bool NuPlayer2::GenericSource2::isStreaming() const {
- Mutex::Autolock _l(mLock);
- return mIsStreaming;
-}
-
-NuPlayer2::GenericSource2::~GenericSource2() {
- ALOGV("~GenericSource2");
- if (mLooper != NULL) {
- mLooper->unregisterHandler(id());
- mLooper->stop();
- }
- if (mDataSourceWrapper != NULL) {
- mDataSourceWrapper->close();
- }
- resetDataSource();
-}
-
-void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
- Mutex::Autolock _l(mLock);
- ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
-
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("generic2");
- mLooper->start(false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_DEFAULT);
-
- mLooper->registerHandler(this);
- }
-
- sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
- msg->setInt64("startTimeUs", startTimeUs);
-
- msg->post();
-}
-
-void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
- ALOGV("onPrepareAsync: mFd %d mUri %s mDataSourceWrapper: %p",
- mFd, mUri.c_str(), mDataSourceWrapper.get());
-
- if (!mUri.empty()) {
- const char* uri = mUri.c_str();
- size_t numheaders = mUriHeaders.size();
- const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
- for (size_t i = 0; i < numheaders; ++i) {
- key_values[i * 2] = mUriHeaders.keyAt(i).c_str();
- key_values[i * 2 + 1] = mUriHeaders.valueAt(i).c_str();
- }
- mLock.unlock();
- AMediaDataSource *aSource = AMediaDataSource_newUri(uri, numheaders, key_values);
- mLock.lock();
- mDataSourceWrapper = aSource ? new AMediaDataSourceWrapper(aSource) : NULL;
- delete[] key_values;
- // For cached streaming cases, we need to wait for enough
- // buffering before reporting prepared.
- mIsStreaming = !strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8);
- }
-
- if (mDisconnected || (mFd < 0 && mDataSourceWrapper == NULL)) {
- ALOGE("mDisconnected(%d) or Failed to create data source!", mDisconnected);
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- return;
- }
-
- // init extractor from data source
- status_t err = initFromDataSource();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
-
- if (err != OK) {
- ALOGE("Failed to init from data source!");
- notifyPreparedAndCleanup(err);
- return;
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- sp<MetaData> meta = getFormatMeta_l(false /* audio */);
- sp<AMessage> msg = new AMessage;
- err = convertMetaDataToMessage(meta, &msg);
- if(err != OK) {
- notifyPreparedAndCleanup(err);
- return;
- }
- notifyVideoSizeChanged(msg);
- }
-
- notifyFlagsChanged(
- // FLAG_SECURE will be known if/when prepareDrm is called by the app
- // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
- FLAG_CAN_PAUSE |
- FLAG_CAN_SEEK_BACKWARD |
- FLAG_CAN_SEEK_FORWARD |
- FLAG_CAN_SEEK);
-
- doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
- finishPrepareAsync();
-
- ALOGV("onPrepareAsync: Done");
-}
-
-void NuPlayer2::GenericSource2::finishPrepareAsync() {
- ALOGV("finishPrepareAsync");
-
- if (mIsStreaming) {
- mPreparing = true;
- ++mPollBufferingGeneration;
- schedulePollBuffering();
- } else {
- notifyPrepared();
- }
-
- if (mAudioTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
- }
-}
-
-void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) {
- if (err != OK) {
- mDataSourceWrapper.clear();
-
- mBitrate = -1;
- mPrevBufferPercentage = -1;
- ++mPollBufferingGeneration;
- }
- notifyPrepared(err);
-}
-
-void NuPlayer2::GenericSource2::start() {
- Mutex::Autolock _l(mLock);
- ALOGI("start");
-
- if (mAudioTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
- }
-
- mStarted = true;
-}
-
-void NuPlayer2::GenericSource2::stop() {
- Mutex::Autolock _l(mLock);
- mStarted = false;
-}
-
-void NuPlayer2::GenericSource2::pause() {
- Mutex::Autolock _l(mLock);
- mStarted = false;
-}
-
-void NuPlayer2::GenericSource2::resume() {
- Mutex::Autolock _l(mLock);
- mStarted = true;
-}
-
-void NuPlayer2::GenericSource2::disconnect() {
- {
- Mutex::Autolock _l(mLock);
- mDisconnected = true;
- }
- if (mDataSourceWrapper != NULL) {
- mDataSourceWrapper->close();
- }
-}
-
-status_t NuPlayer2::GenericSource2::feedMoreTSData() {
- return OK;
-}
-
-void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) {
- Mutex::Autolock _l(mLock);
- switch (msg->what()) {
- case kWhatPrepareAsync:
- {
- int64_t startTimeUs;
- CHECK(msg->findInt64("startTimeUs", &startTimeUs));
- onPrepareAsync(startTimeUs);
- break;
- }
- case kWhatFetchSubtitleData:
- {
- fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
- mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
- break;
- }
-
- case kWhatFetchTimedTextData:
- {
- fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
- mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
- break;
- }
-
- case kWhatSendSubtitleData:
- {
- sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
- mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
- break;
- }
-
- case kWhatSendGlobalTimedTextData:
- {
- sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
- break;
- }
- case kWhatSendTimedTextData:
- {
- sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
- mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
- break;
- }
-
- case kWhatChangeAVSource:
- {
- int32_t trackIndex;
- CHECK(msg->findInt32("trackIndex", &trackIndex));
- const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
-
- Track* track;
- AString mime;
- media_track_type trackType, counterpartType;
- sp<AMediaFormatWrapper> format = extractor->getTrackFormat(trackIndex);
- format->getString(AMEDIAFORMAT_KEY_MIME, &mime);
- if (!strncasecmp(mime.c_str(), "audio/", 6)) {
- track = &mAudioTrack;
- trackType = MEDIA_TRACK_TYPE_AUDIO;
- counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
- } else {
- CHECK(!strncasecmp(mime.c_str(), "video/", 6));
- track = &mVideoTrack;
- trackType = MEDIA_TRACK_TYPE_VIDEO;
- counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
- }
-
-
- track->mExtractor = extractor;
- track->mExtractor->selectSingleTrack(trackIndex);
- track->mIndex = trackIndex;
- ++mAudioDataGeneration;
- ++mVideoDataGeneration;
-
- int64_t timeUs, actualTimeUs;
- const bool formatChange = true;
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- timeUs = mAudioLastDequeueTimeUs;
- } else {
- timeUs = mVideoLastDequeueTimeUs;
- }
- readBuffer(trackType, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
- &actualTimeUs, formatChange);
- readBuffer(counterpartType, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
- NULL, !formatChange);
- ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
-
- break;
- }
-
- case kWhatSeek:
- {
- onSeek(msg);
- break;
- }
-
- case kWhatReadBuffer:
- {
- onReadBuffer(msg);
- break;
- }
-
- case kWhatPollBuffering:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation == mPollBufferingGeneration) {
- onPollBuffering();
- }
- break;
- }
-
- default:
- Source::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::GenericSource2::fetchTextData(
- uint32_t sendWhat,
- media_track_type type,
- int32_t curGen,
- const sp<AnotherPacketSource>& packets,
- const sp<AMessage>& msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- int32_t avail;
- if (packets->hasBufferAvailable(&avail)) {
- return;
- }
-
- int64_t timeUs;
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- int64_t subTimeUs = 0;
- readBuffer(type, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs);
-
- status_t eosResult;
- if (!packets->hasBufferAvailable(&eosResult)) {
- return;
- }
-
- if (msg->what() == kWhatFetchSubtitleData) {
- subTimeUs -= 1000000ll; // send subtile data one second earlier
- }
- sp<AMessage> msg2 = new AMessage(sendWhat, this);
- msg2->setInt32("generation", msgGeneration);
- mMediaClock->addTimer(msg2, subTimeUs);
-}
-
-void NuPlayer2::GenericSource2::sendTextData(
- uint32_t what,
- media_track_type type,
- int32_t curGen,
- const sp<AnotherPacketSource>& packets,
- const sp<AMessage>& msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- int64_t subTimeUs;
- if (packets->nextBufferTime(&subTimeUs) != OK) {
- return;
- }
-
- int64_t nextSubTimeUs;
- readBuffer(type, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
-
- sp<ABuffer> buffer;
- status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
- if (dequeueStatus == OK) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", what);
- notify->setBuffer("buffer", buffer);
- notify->post();
-
- if (msg->what() == kWhatSendSubtitleData) {
- nextSubTimeUs -= 1000000ll; // send subtile data one second earlier
- }
- mMediaClock->addTimer(msg, nextSubTimeUs);
- }
-}
-
-void NuPlayer2::GenericSource2::sendGlobalTextData(
- uint32_t what,
- int32_t curGen,
- sp<AMessage> msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- void *data = NULL;
- size_t size = 0;
- if (mTimedTextTrack.mExtractor->getTrackFormat(mTimedTextTrack.mIndex)->getBuffer(
- "text", &data, &size)) {
- mGlobalTimedText = new ABuffer(size);
- if (mGlobalTimedText->data()) {
- memcpy(mGlobalTimedText->data(), data, size);
- sp<AMessage> globalMeta = mGlobalTimedText->meta();
- globalMeta->setInt64("timeUs", 0);
- globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
- globalMeta->setInt32("global", 1);
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", what);
- notify->setBuffer("buffer", mGlobalTimedText);
- notify->post();
- }
- }
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getFormat(bool audio) {
- Mutex::Autolock _l(mLock);
- return getFormat_l(audio);
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta(bool audio) {
- Mutex::Autolock _l(mLock);
- return getFormatMeta_l(audio);
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getFormat_l(bool audio) {
- sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
- size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
-
- if (extractor == NULL) {
- return NULL;
- }
-
- return extractor->getTrackFormat(trackIndex)->toAMessage();
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta_l(bool audio) {
- sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
- size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
-
- if (extractor == NULL) {
- return NULL;
- }
-
- return convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
-}
-
-status_t NuPlayer2::GenericSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- Mutex::Autolock _l(mLock);
- // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
- // the codec's crypto object has gone away (b/37960096).
- // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
- if (!mStarted && mIsDrmReleased) {
- return -EWOULDBLOCK;
- }
-
- Track *track = audio ? &mAudioTrack : &mVideoTrack;
-
- if (track->mExtractor == NULL) {
- return -EWOULDBLOCK;
- }
-
- status_t finalResult;
- if (!track->mPackets->hasBufferAvailable(&finalResult)) {
- if (finalResult == OK) {
- postReadBuffer(
- audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- return -EWOULDBLOCK;
- }
- return finalResult;
- }
-
- status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
-
- // start pulling in more buffers if cache is running low
- // so that decoder has less chance of being starved
- if (!mIsStreaming) {
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- }
- } else {
- int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
- // TODO: maxRebufferingMarkMs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs
- int64_t restartBufferingMarkUs =
- mBufferingSettings.mResumePlaybackMarkMs * 1000ll / 2;
- if (finalResult == OK) {
- if (durationUs < restartBufferingMarkUs) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- }
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
- && !mSentPauseOnBuffering && !mPreparing) {
- mSentPauseOnBuffering = true;
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
- }
- }
-
- if (result != OK) {
- if (mSubtitleTrack.mExtractor != NULL) {
- mSubtitleTrack.mPackets->clear();
- mFetchSubtitleDataGeneration++;
- }
- if (mTimedTextTrack.mExtractor != NULL) {
- mTimedTextTrack.mPackets->clear();
- mFetchTimedTextDataGeneration++;
- }
- return result;
- }
-
- int64_t timeUs;
- status_t eosResult; // ignored
- CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
- if (audio) {
- mAudioLastDequeueTimeUs = timeUs;
- } else {
- mVideoLastDequeueTimeUs = timeUs;
- }
-
- if (mSubtitleTrack.mExtractor != NULL
- && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchSubtitleDataGeneration);
- msg->post();
- }
-
- if (mTimedTextTrack.mExtractor != NULL
- && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchTimedTextDataGeneration);
- msg->post();
- }
-
- return result;
-}
-
-status_t NuPlayer2::GenericSource2::getDuration(int64_t *durationUs) {
- Mutex::Autolock _l(mLock);
- *durationUs = mDurationUs;
- return OK;
-}
-
-size_t NuPlayer2::GenericSource2::getTrackCount() const {
- Mutex::Autolock _l(mLock);
- return mExtractors.size();
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getTrackInfo(size_t trackIndex) const {
- Mutex::Autolock _l(mLock);
- size_t trackCount = mExtractors.size();
- if (trackIndex >= trackCount) {
- return NULL;
- }
-
- sp<AMessage> format = mExtractors.itemAt(trackIndex)->getTrackFormat(trackIndex)->toAMessage();
- if (format == NULL) {
- ALOGE("no metadata for track %zu", trackIndex);
- return NULL;
- }
-
- AString mime;
- CHECK(format->findString(AMEDIAFORMAT_KEY_MIME, &mime));
-
- int32_t trackType;
- if (!strncasecmp(mime.c_str(), "video/", 6)) {
- trackType = MEDIA_TRACK_TYPE_VIDEO;
- } else if (!strncasecmp(mime.c_str(), "audio/", 6)) {
- trackType = MEDIA_TRACK_TYPE_AUDIO;
- } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP)) {
- trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
- } else {
- trackType = MEDIA_TRACK_TYPE_UNKNOWN;
- }
- format->setInt32("type", trackType);
-
- AString lang;
- if (!format->findString("language", &lang)) {
- format->setString("language", "und");
- }
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
- format->findInt32(AMEDIAFORMAT_KEY_IS_AUTOSELECT, &isAutoselect);
- format->findInt32(AMEDIAFORMAT_KEY_IS_DEFAULT, &isDefault);
- format->findInt32(AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE, &isForced);
-
- format->setInt32("auto", !!isAutoselect);
- format->setInt32("default", !!isDefault);
- format->setInt32("forced", !!isForced);
- }
-
- return format;
-}
-
-ssize_t NuPlayer2::GenericSource2::getSelectedTrack(media_track_type type) const {
- Mutex::Autolock _l(mLock);
- const Track *track = NULL;
- switch (type) {
- case MEDIA_TRACK_TYPE_VIDEO:
- track = &mVideoTrack;
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- track = &mAudioTrack;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- track = &mTimedTextTrack;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- track = &mSubtitleTrack;
- break;
- default:
- break;
- }
-
- if (track != NULL && track->mExtractor != NULL) {
- return track->mIndex;
- }
-
- return -1;
-}
-
-status_t NuPlayer2::GenericSource2::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
- Mutex::Autolock _l(mLock);
- ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
-
- if (trackIndex >= mExtractors.size()) {
- return BAD_INDEX;
- }
-
- if (!select) {
- Track* track = NULL;
- if (mSubtitleTrack.mExtractor != NULL && trackIndex == mSubtitleTrack.mIndex) {
- track = &mSubtitleTrack;
- mFetchSubtitleDataGeneration++;
- } else if (mTimedTextTrack.mExtractor != NULL && trackIndex == mTimedTextTrack.mIndex) {
- track = &mTimedTextTrack;
- mFetchTimedTextDataGeneration++;
- }
- if (track == NULL) {
- return INVALID_OPERATION;
- }
- track->mExtractor = NULL;
- track->mPackets->clear();
- return OK;
- }
-
- const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
- sp<MetaData> meta = convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- if (!strncasecmp(mime, "text/", 5)) {
- bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
- Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
- if (track->mExtractor != NULL && track->mIndex == trackIndex) {
- return OK;
- }
- track->mIndex = trackIndex;
- track->mExtractor = mExtractors.itemAt(trackIndex);
- track->mExtractor->selectSingleTrack(trackIndex);
- if (track->mPackets == NULL) {
- track->mPackets = new AnotherPacketSource(meta);
- } else {
- track->mPackets->clear();
- track->mPackets->setFormat(meta);
-
- }
-
- if (isSubtitle) {
- mFetchSubtitleDataGeneration++;
- } else {
- mFetchTimedTextDataGeneration++;
- }
-
- status_t eosResult; // ignored
- if (mSubtitleTrack.mExtractor != NULL
- && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchSubtitleDataGeneration);
- msg->post();
- }
-
- sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
- msg2->setInt32("generation", mFetchTimedTextDataGeneration);
- msg2->post();
-
- if (mTimedTextTrack.mExtractor != NULL
- && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchTimedTextDataGeneration);
- msg->post();
- }
-
- return OK;
- } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
- bool audio = !strncasecmp(mime, "audio/", 6);
- Track *track = audio ? &mAudioTrack : &mVideoTrack;
- if (track->mExtractor != NULL && track->mIndex == trackIndex) {
- return OK;
- }
-
- sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
- msg->setInt32("trackIndex", trackIndex);
- msg->post();
- return OK;
- }
-
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2::GenericSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("mode", mode);
-
- // Need to call readBuffer on |mLooper| to ensure the calls to
- // IMediaSource::read* are serialized. Note that IMediaSource::read*
- // is called without |mLock| acquired and MediaSource is not thread safe.
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer2::GenericSource2::onSeek(const sp<AMessage>& msg) {
- int64_t seekTimeUs;
- int32_t mode;
- CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
-
- sp<AMessage> response = new AMessage;
- status_t err = doSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-status_t NuPlayer2::GenericSource2::doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- if (mVideoTrack.mExtractor != NULL) {
- ++mVideoDataGeneration;
-
- int64_t actualTimeUs;
- readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
-
- if (mode != MediaPlayer2SeekMode::SEEK_CLOSEST) {
- seekTimeUs = actualTimeUs;
- }
- mVideoLastDequeueTimeUs = actualTimeUs;
- }
-
- if (mAudioTrack.mExtractor != NULL) {
- ++mAudioDataGeneration;
- readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
- mAudioLastDequeueTimeUs = seekTimeUs;
- }
-
- if (mSubtitleTrack.mExtractor != NULL) {
- mSubtitleTrack.mPackets->clear();
- mFetchSubtitleDataGeneration++;
- }
-
- if (mTimedTextTrack.mExtractor != NULL) {
- mTimedTextTrack.mPackets->clear();
- mFetchTimedTextDataGeneration++;
- }
-
- ++mPollBufferingGeneration;
- schedulePollBuffering();
- return OK;
-}
-
-sp<ABuffer> NuPlayer2::GenericSource2::mediaBufferToABuffer(
- MediaBufferBase* mb,
- media_track_type trackType) {
- bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
- size_t outLength = mb->range_length();
-
- if (audio && mAudioIsVorbis) {
- outLength += sizeof(int32_t);
- }
-
- sp<ABuffer> ab;
-
- if (mIsDrmProtected) {
- // Modular DRM
- // Enabled for both video/audio so 1) media buffer is reused without extra copying
- // 2) meta data can be retrieved in onInputBufferFetched for calling queueSecureInputBuffer.
-
- // data is already provided in the buffer
- ab = new ABuffer(NULL, mb->range_length());
- ab->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mb));
-
- // Modular DRM: Required b/c of the above add_ref.
- // If ref>0, there must be an observer, or it'll crash at release().
- // TODO: MediaBuffer might need to be revised to ease such need.
- mb->setObserver(this);
- // setMediaBufferBase() interestingly doesn't increment the ref count on its own.
- // Extra increment (since we want to keep mb alive and attached to ab beyond this function
- // call. This is to counter the effect of mb->release() towards the end.
- mb->add_ref();
-
- } else {
- ab = new ABuffer(outLength);
- memcpy(ab->data(),
- (const uint8_t *)mb->data() + mb->range_offset(),
- mb->range_length());
- }
-
- if (audio && mAudioIsVorbis) {
- int32_t numPageSamples;
- if (!mb->meta_data().findInt32(kKeyValidSamples, &numPageSamples)) {
- numPageSamples = -1;
- }
-
- uint8_t* abEnd = ab->data() + mb->range_length();
- memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
- }
-
- sp<AMessage> meta = ab->meta();
-
- int64_t timeUs;
- CHECK(mb->meta_data().findInt64(kKeyTime, &timeUs));
- meta->setInt64("timeUs", timeUs);
-
- if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- int32_t layerId;
- if (mb->meta_data().findInt32(kKeyTemporalLayerId, &layerId)) {
- meta->setInt32("temporal-layer-id", layerId);
- }
- }
-
- if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- AString mime;
- sp<AMediaExtractorWrapper> extractor = mTimedTextTrack.mExtractor;
- size_t trackIndex = mTimedTextTrack.mIndex;
- CHECK(extractor != NULL
- && extractor->getTrackFormat(trackIndex)->getString(AMEDIAFORMAT_KEY_MIME, &mime));
- meta->setString("mime", mime.c_str());
- }
-
- int64_t durationUs;
- if (mb->meta_data().findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64("durationUs", durationUs);
- }
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- meta->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, mSubtitleTrack.mIndex);
- }
-
- uint32_t dataType; // unused
- const void *seiData;
- size_t seiLength;
- if (mb->meta_data().findData(kKeySEI, &dataType, &seiData, &seiLength)) {
- sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
- meta->setBuffer("sei", sei);
- }
-
- const void *mpegUserDataPointer;
- size_t mpegUserDataLength;
- if (mb->meta_data().findData(
- kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
- sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
- meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData);
- }
-
- mb->release();
- mb = NULL;
-
- return ab;
-}
-
-int32_t NuPlayer2::GenericSource2::getDataGeneration(media_track_type type) const {
- int32_t generation = -1;
- switch (type) {
- case MEDIA_TRACK_TYPE_VIDEO:
- generation = mVideoDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- generation = mAudioDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- generation = mFetchTimedTextDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- generation = mFetchSubtitleDataGeneration;
- break;
- default:
- break;
- }
-
- return generation;
-}
-
-void NuPlayer2::GenericSource2::postReadBuffer(media_track_type trackType) {
- if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
- mPendingReadBufferTypes |= (1 << trackType);
- sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
- msg->setInt32("trackType", trackType);
- msg->post();
- }
-}
-
-void NuPlayer2::GenericSource2::onReadBuffer(const sp<AMessage>& msg) {
- int32_t tmpType;
- CHECK(msg->findInt32("trackType", &tmpType));
- media_track_type trackType = (media_track_type)tmpType;
- mPendingReadBufferTypes &= ~(1 << trackType);
- readBuffer(trackType);
-}
-
-void NuPlayer2::GenericSource2::readBuffer(
- media_track_type trackType, int64_t seekTimeUs, MediaPlayer2SeekMode mode,
- int64_t *actualTimeUs, bool formatChange) {
- Track *track;
- size_t maxBuffers = 1;
- switch (trackType) {
- case MEDIA_TRACK_TYPE_VIDEO:
- track = &mVideoTrack;
- maxBuffers = 8; // too large of a number may influence seeks
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- track = &mAudioTrack;
- maxBuffers = 64;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- track = &mSubtitleTrack;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- track = &mTimedTextTrack;
- break;
- default:
- TRESPASS();
- }
-
- if (track->mExtractor == NULL) {
- return;
- }
-
- if (actualTimeUs) {
- *actualTimeUs = seekTimeUs;
- }
-
-
- bool seeking = false;
- sp<AMediaExtractorWrapper> extractor = track->mExtractor;
- if (seekTimeUs >= 0) {
- extractor->seekTo(seekTimeUs, mode);
- seeking = true;
- }
-
- int32_t generation = getDataGeneration(trackType);
- for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
- Vector<sp<ABuffer> > aBuffers;
-
- mLock.unlock();
-
- sp<AMediaFormatWrapper> format;
- ssize_t sampleSize = -1;
- status_t err = extractor->getSampleFormat(format);
- if (err == OK) {
- sampleSize = extractor->getSampleSize();
- }
-
- if (err != OK || sampleSize < 0) {
- mLock.lock();
- track->mPackets->signalEOS(err != OK ? err : ERROR_END_OF_STREAM);
- break;
- }
-
- sp<ABuffer> abuf = new ABuffer(sampleSize);
- sampleSize = extractor->readSampleData(abuf);
- mLock.lock();
-
- // in case track has been changed since we don't have lock for some time.
- if (generation != getDataGeneration(trackType)) {
- break;
- }
-
- int64_t timeUs = extractor->getSampleTime();
- if (timeUs < 0) {
- track->mPackets->signalEOS(ERROR_MALFORMED);
- break;
- }
-
- sp<AMessage> meta = abuf->meta();
- format->writeToAMessage(meta);
- meta->setInt64("timeUs", timeUs);
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- mAudioTimeUs = timeUs;
- } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- mVideoTimeUs = timeUs;
- }
-
- sp<AMediaCodecCryptoInfoWrapper> cryptInfo = extractor->getSampleCryptoInfo();
- if (cryptInfo != NULL) {
- meta->setObject("cryptInfo", cryptInfo);
- }
-
- queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
-
- if (numBuffers == 0 && actualTimeUs != nullptr) {
- *actualTimeUs = timeUs;
- }
- if (seeking) {
- if (meta != nullptr && mode == MediaPlayer2SeekMode::SEEK_CLOSEST
- && seekTimeUs > timeUs) {
- sp<AMessage> extra = new AMessage;
- extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
- meta->setMessage("extra", extra);
- }
- }
-
- track->mPackets->queueAccessUnit(abuf);
- formatChange = false;
- seeking = false;
- ++numBuffers;
- extractor->advance();
-
- }
-
- if (mIsStreaming
- && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
- status_t finalResult;
- int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
-
- // TODO: maxRebufferingMarkMs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs
- int64_t markUs = (mPreparing ? mBufferingSettings.mInitialMarkMs
- : mBufferingSettings.mResumePlaybackMarkMs) * 1000ll;
- if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
- if (mPreparing || mSentPauseOnBuffering) {
- Track *counterTrack =
- (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
- if (counterTrack->mExtractor != NULL) {
- durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
- }
- if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
- if (mPreparing) {
- notifyPrepared();
- mPreparing = false;
- } else {
- mSentPauseOnBuffering = false;
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
- }
- }
- return;
- }
-
- postReadBuffer(trackType);
- }
-}
-
-void NuPlayer2::GenericSource2::queueDiscontinuityIfNeeded(
- bool seeking, bool formatChange, media_track_type trackType, Track *track) {
- // formatChange && seeking: track whose source is changed during selection
- // formatChange && !seeking: track whose source is not changed during selection
- // !formatChange: normal seek
- if ((seeking || formatChange)
- && (trackType == MEDIA_TRACK_TYPE_AUDIO
- || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
- ATSParser::DiscontinuityType type = (formatChange && seeking)
- ? ATSParser::DISCONTINUITY_FORMATCHANGE
- : ATSParser::DISCONTINUITY_NONE;
- track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
- }
-}
-
-void NuPlayer2::GenericSource2::notifyBufferingUpdate(int32_t percentage) {
- // Buffering percent could go backward as it's estimated from remaining
- // data and last access time. This could cause the buffering position
- // drawn on media control to jitter slightly. Remember previously reported
- // percentage and don't allow it to go backward.
- if (percentage < mPrevBufferPercentage) {
- percentage = mPrevBufferPercentage;
- } else if (percentage > 100) {
- percentage = 100;
- }
-
- mPrevBufferPercentage = percentage;
-
- ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatBufferingUpdate);
- notify->setInt32("percentage", percentage);
- notify->post();
-}
-
-void NuPlayer2::GenericSource2::schedulePollBuffering() {
- if (mIsStreaming) {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->setInt32("generation", mPollBufferingGeneration);
- // Enquires buffering status every second.
- msg->post(1000000ll);
- }
-}
-
-void NuPlayer2::GenericSource2::onPollBuffering() {
- int64_t cachedDurationUs = -1ll;
-
- sp<AMediaExtractorWrapper> extractor;
- if (mVideoTrack.mExtractor != NULL) {
- extractor = mVideoTrack.mExtractor;
- } else if (mAudioTrack.mExtractor != NULL) {
- extractor = mAudioTrack.mExtractor;
- }
-
- if (extractor != NULL) {
- cachedDurationUs = extractor->getCachedDuration();
- }
-
- if (cachedDurationUs >= 0ll) {
- ssize_t sampleSize = extractor->getSampleSize();
- if (sampleSize >= 0ll) {
- int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
- int percentage = 100.0 * cachedPosUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyBufferingUpdate(percentage);
- ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
- } else {
- notifyBufferingUpdate(100);
- ALOGV("onPollBuffering: EOS");
- }
- }
-
- schedulePollBuffering();
-}
-
-// Modular DRM
-status_t NuPlayer2::GenericSource2::prepareDrm(
- const uint8_t uuid[16],
- const Vector<uint8_t> &drmSessionId,
- sp<AMediaCryptoWrapper> *outCrypto) {
- Mutex::Autolock _l(mLock);
- ALOGV("prepareDrm");
-
- mIsDrmProtected = false;
- mIsDrmReleased = false;
- mIsSecure = false;
-
- status_t status = OK;
- sp<AMediaCryptoWrapper> crypto =
- new AMediaCryptoWrapper(uuid, drmSessionId.array(), drmSessionId.size());
- if (crypto == NULL) {
- ALOGE("prepareDrm: failed to create crypto.");
- return UNKNOWN_ERROR;
- }
- ALOGV("prepareDrm: crypto created for uuid: %s",
- DrmUUID::toHexString(uuid).string());
-
- *outCrypto = crypto;
- // as long a there is an active crypto
- mIsDrmProtected = true;
-
- if (mMimes.size() == 0) {
- status = UNKNOWN_ERROR;
- ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
- return status;
- }
-
- // first mime in this list is either the video track, or the first audio track
- const char *mime = mMimes[0].string();
- mIsSecure = crypto->requiresSecureDecoderComponent(mime);
- ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
- mime, mIsSecure);
-
- // Checking the member flags while in the looper to send out the notification.
- // The legacy mDecryptHandle!=NULL check (for FLAG_PROTECTED) is equivalent to mIsDrmProtected.
- notifyFlagsChanged(
- (mIsSecure ? FLAG_SECURE : 0) |
- // Setting "protected screen" only for L1: b/38390836
- (mIsSecure ? FLAG_PROTECTED : 0) |
- FLAG_CAN_PAUSE |
- FLAG_CAN_SEEK_BACKWARD |
- FLAG_CAN_SEEK_FORWARD |
- FLAG_CAN_SEEK);
-
- if (status == OK) {
- ALOGV("prepareDrm: mCrypto: %p", outCrypto->get());
- ALOGD("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
- return status;
-}
-
-status_t NuPlayer2::GenericSource2::releaseDrm() {
- Mutex::Autolock _l(mLock);
- ALOGV("releaseDrm");
-
- if (mIsDrmProtected) {
- mIsDrmProtected = false;
- // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
- mIsDrmReleased = true;
- ALOGV("releaseDrm: mIsDrmProtected is reset.");
- } else {
- ALOGE("releaseDrm: mIsDrmProtected is already false.");
- }
-
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::checkDrmInfo()
-{
- // clearing the flag at prepare in case the player is reused after stop/releaseDrm with the
- // same source without being reset (called by prepareAsync/initFromDataSource)
- mIsDrmReleased = false;
-
- if (mExtractor == NULL) {
- ALOGV("checkDrmInfo: No extractor");
- return OK; // letting the caller responds accordingly
- }
-
- PsshInfo *psshInfo = mExtractor->getPsshInfo();
- if (psshInfo == NULL) {
- ALOGV("checkDrmInfo: No PSSH");
- return OK; // source without DRM info
- }
-
- PlayerMessage playerMsg;
- status_t ret = NuPlayer2Drm::retrieveDrmInfo(psshInfo, &playerMsg);
- ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH drm info size: %d", (int)playerMsg.ByteSize());
-
- if (ret != OK) {
- ALOGE("checkDrmInfo: failed to retrive DrmInfo %d", ret);
- return UNKNOWN_ERROR;
- }
-
- int size = playerMsg.ByteSize();
- sp<ABuffer> drmInfoBuf = new ABuffer(size);
- playerMsg.SerializeToArray(drmInfoBuf->data(), size);
- drmInfoBuf->setRange(0, size);
- notifyDrmInfo(drmInfoBuf);
-
- return OK;
-}
-
-void NuPlayer2::GenericSource2::signalBufferReturned(MediaBufferBase *buffer)
-{
- //ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount());
-
- buffer->setObserver(NULL);
- buffer->release(); // this leads to delete since that there is no observor
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
deleted file mode 100644
index ade1aa3..0000000
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef GENERIC_SOURCE2_H_
-
-#define GENERIC_SOURCE2_H_
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include "ATSParser.h"
-
-#include <media/stagefright/MediaBuffer.h>
-#include <mediaplayer2/mediaplayer2.h>
-#include <media/NdkMediaDataSource.h>
-#include <media/NdkMediaExtractor.h>
-#include <media/NdkWrapper.h>
-
-namespace android {
-
-class DecryptHandle;
-struct AnotherPacketSource;
-struct ARTSPController;
-class DataSource;
-class IDataSource;
-class IMediaSource;
-struct MediaSource;
-class MediaBuffer;
-struct MediaClock;
-
-struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
- public MediaBufferObserver // Modular DRM
-{
- GenericSource2(const sp<AMessage> ¬ify, uid_t uid,
- const sp<MediaClock> &mediaClock);
-
- status_t setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- status_t setDataSource(const sp<DataSource>& dataSource);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
-
- virtual void start();
- virtual void stop();
- virtual void pause();
- virtual void resume();
-
- virtual void disconnect();
-
- virtual status_t feedMoreTSData();
-
- virtual sp<MetaData> getFileFormatMeta() const;
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
-
- virtual status_t getDuration(int64_t *durationUs);
- virtual size_t getTrackCount() const;
- virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
- virtual ssize_t getSelectedTrack(media_track_type type) const;
- virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
- virtual bool isStreaming() const;
-
- // Modular DRM
- virtual void signalBufferReturned(MediaBufferBase *buffer);
-
- virtual status_t prepareDrm(
- const uint8_t uuid[16],
- const Vector<uint8_t> &drmSessionId,
- sp<AMediaCryptoWrapper> *outCrypto);
-
- virtual status_t releaseDrm();
-
-
-protected:
- virtual ~GenericSource2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual sp<AMessage> getFormat(bool audio);
- virtual sp<MetaData> getFormatMeta(bool audio);
-
-private:
- enum {
- kWhatPrepareAsync,
- kWhatFetchSubtitleData,
- kWhatFetchTimedTextData,
- kWhatSendSubtitleData,
- kWhatSendGlobalTimedTextData,
- kWhatSendTimedTextData,
- kWhatChangeAVSource,
- kWhatPollBuffering,
- kWhatSeek,
- kWhatReadBuffer,
- kWhatStart,
- kWhatResume,
- kWhatSecureDecodersInstantiated,
- };
-
- struct Track {
- size_t mIndex;
- sp<AMediaExtractorWrapper> mExtractor;
- sp<AnotherPacketSource> mPackets;
- };
-
- int64_t mAudioTimeUs;
- int64_t mAudioLastDequeueTimeUs;
- int64_t mVideoTimeUs;
- int64_t mVideoLastDequeueTimeUs;
-
- BufferingSettings mBufferingSettings;
- int32_t mPrevBufferPercentage;
- int32_t mPollBufferingGeneration;
- bool mSentPauseOnBuffering;
-
- int32_t mAudioDataGeneration;
- int32_t mVideoDataGeneration;
- int32_t mFetchSubtitleDataGeneration;
- int32_t mFetchTimedTextDataGeneration;
- int64_t mDurationUs;
- bool mAudioIsVorbis;
- // Secure codec is required.
- bool mIsSecure;
- bool mIsStreaming;
- uid_t mUID;
- const sp<MediaClock> mMediaClock;
- AString mUri;
- KeyedVector<String8, String8> mUriHeaders;
- int mFd;
- int64_t mOffset;
- int64_t mLength;
-
- bool mDisconnected;
- sp<MetaData> mFileMeta;
- sp<AMediaDataSourceWrapper> mDataSourceWrapper;
- sp<AMediaExtractorWrapper> mExtractor;
- Vector<sp<AMediaExtractorWrapper> > mExtractors;
- bool mStarted;
- bool mPreparing;
- int64_t mBitrate;
- uint32_t mPendingReadBufferTypes;
- sp<ABuffer> mGlobalTimedText;
-
- Track mVideoTrack;
- Track mAudioTrack;
- Track mSubtitleTrack;
- Track mTimedTextTrack;
-
- mutable Mutex mLock;
-
- sp<ALooper> mLooper;
-
- void resetDataSource();
-
- status_t initFromDataSource();
- int64_t getLastReadPosition();
-
- void notifyPreparedAndCleanup(status_t err);
- void onSecureDecodersInstantiated(status_t err);
- void finishPrepareAsync();
- status_t startSources();
-
- void onSeek(const sp<AMessage>& msg);
- status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
-
- void onPrepareAsync(int64_t startTimeUs);
-
- void fetchTextData(
- uint32_t what, media_track_type type,
- int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
-
- void sendGlobalTextData(
- uint32_t what,
- int32_t curGen, sp<AMessage> msg);
-
- void sendTextData(
- uint32_t what, media_track_type type,
- int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
-
- sp<ABuffer> mediaBufferToABuffer(
- MediaBufferBase *mbuf,
- media_track_type trackType);
-
- void postReadBuffer(media_track_type trackType);
- void onReadBuffer(const sp<AMessage>& msg);
- // When |mode| is MediaPlayer2SeekMode::SEEK_CLOSEST, the buffer read shall
- // include an item indicating skipping rendering all buffers with timestamp
- // earlier than |seekTimeUs|.
- // For other modes, the buffer read will not include the item as above in order
- // to facilitate fast seek operation.
- void readBuffer(
- media_track_type trackType,
- int64_t seekTimeUs = -1ll,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
- int64_t *actualTimeUs = NULL, bool formatChange = false);
-
- void queueDiscontinuityIfNeeded(
- bool seeking, bool formatChange, media_track_type trackType, Track *track);
-
- void schedulePollBuffering();
- void onPollBuffering();
- void notifyBufferingUpdate(int32_t percentage);
-
- sp<AMessage> getFormat_l(bool audio);
- sp<MetaData> getFormatMeta_l(bool audio);
- int32_t getDataGeneration(media_track_type type) const;
-
- // Modular DRM
- // The source is DRM protected and is prepared for DRM.
- bool mIsDrmProtected;
- // releaseDrm has been processed.
- bool mIsDrmReleased;
- Vector<String8> mMimes;
-
- status_t checkDrmInfo();
-
- DISALLOW_EVIL_CONSTRUCTORS(GenericSource2);
-};
-
-} // namespace android
-
-#endif // GENERIC_SOURCE2_H_
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
deleted file mode 100644
index e53900b..0000000
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "HTTPLiveSource2"
-#include <utils/Log.h>
-
-#include "HTTPLiveSource2.h"
-
-#include "AnotherPacketSource.h"
-#include "LiveDataSource.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/Utils.h>
-
-// default buffer prepare/ready/underflow marks
-static const int kReadyMarkMs = 5000; // 5 seconds
-static const int kPrepareMarkMs = 1500; // 1.5 seconds
-
-namespace android {
-
-NuPlayer2::HTTPLiveSource2::HTTPLiveSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers)
- : Source(notify),
- mHTTPService(httpService),
- mURL(url),
- mFlags(0),
- mFinalResult(OK),
- mOffset(0),
- mFetchSubtitleDataGeneration(0),
- mFetchMetaDataGeneration(0),
- mHasMetadata(false),
- mMetadataSelected(false) {
- mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kReadyMarkMs;
- if (headers) {
- mExtraHeaders = *headers;
-
- ssize_t index =
- mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
-
- if (index >= 0) {
- mFlags |= kFlagIncognito;
-
- mExtraHeaders.removeItemsAt(index);
- }
- }
-}
-
-NuPlayer2::HTTPLiveSource2::~HTTPLiveSource2() {
- if (mLiveSession != NULL) {
- mLiveSession->disconnect();
-
- mLiveLooper->unregisterHandler(mLiveSession->id());
- mLiveLooper->unregisterHandler(id());
- mLiveLooper->stop();
-
- mLiveSession.clear();
- mLiveLooper.clear();
- }
-}
-
-status_t NuPlayer2::HTTPLiveSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- *buffering = mBufferingSettings;
-
- return OK;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::setBufferingSettings(const BufferingSettings& buffering) {
- mBufferingSettings = buffering;
-
- if (mLiveSession != NULL) {
- mLiveSession->setBufferingSettings(mBufferingSettings);
- }
-
- return OK;
-}
-
-// TODO: fetch data starting from |startTimeUs|
-void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
- if (mLiveLooper == NULL) {
- mLiveLooper = new ALooper;
- mLiveLooper->setName("http live2");
- mLiveLooper->start(false, /* runOnCallingThread */
- true /* canCallJava */);
-
- mLiveLooper->registerHandler(this);
- }
-
- sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
-
- mLiveSession = new LiveSession(
- notify,
- (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
- mHTTPService);
-
- mLiveLooper->registerHandler(mLiveSession);
-
- mLiveSession->setBufferingSettings(mBufferingSettings);
- mLiveSession->connectAsync(
- mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
-}
-
-void NuPlayer2::HTTPLiveSource2::start() {
-}
-
-sp<MetaData> NuPlayer2::HTTPLiveSource2::getFormatMeta(bool audio) {
- sp<MetaData> meta;
- if (mLiveSession != NULL) {
- mLiveSession->getStreamFormatMeta(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &meta);
- }
-
- return meta;
-}
-
-sp<AMessage> NuPlayer2::HTTPLiveSource2::getFormat(bool audio) {
- sp<MetaData> meta;
- status_t err = -EWOULDBLOCK;
- if (mLiveSession != NULL) {
- err = mLiveSession->getStreamFormatMeta(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &meta);
- }
-
- sp<AMessage> format;
- if (err == -EWOULDBLOCK) {
- format = new AMessage();
- format->setInt32("err", err);
- return format;
- }
-
- if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
- return NULL;
- }
- return format;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::feedMoreTSData() {
- return OK;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- return mLiveSession->dequeueAccessUnit(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- accessUnit);
-}
-
-status_t NuPlayer2::HTTPLiveSource2::getDuration(int64_t *durationUs) {
- return mLiveSession->getDuration(durationUs);
-}
-
-size_t NuPlayer2::HTTPLiveSource2::getTrackCount() const {
- return mLiveSession->getTrackCount();
-}
-
-sp<AMessage> NuPlayer2::HTTPLiveSource2::getTrackInfo(size_t trackIndex) const {
- return mLiveSession->getTrackInfo(trackIndex);
-}
-
-ssize_t NuPlayer2::HTTPLiveSource2::getSelectedTrack(media_track_type type) const {
- if (mLiveSession == NULL) {
- return -1;
- } else if (type == MEDIA_TRACK_TYPE_METADATA) {
- // MEDIA_TRACK_TYPE_METADATA is always last track
- // mMetadataSelected can only be true when mHasMetadata is true
- return mMetadataSelected ? (mLiveSession->getTrackCount() - 1) : -1;
- } else {
- return mLiveSession->getSelectedTrack(type);
- }
-}
-
-status_t NuPlayer2::HTTPLiveSource2::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) {
- if (mLiveSession == NULL) {
- return INVALID_OPERATION;
- }
-
- status_t err = INVALID_OPERATION;
- bool postFetchMsg = false, isSub = false;
- if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) {
- err = mLiveSession->selectTrack(trackIndex, select);
- postFetchMsg = select;
- isSub = true;
- } else {
- // metadata track; i.e. (mHasMetadata && trackIndex == mLiveSession->getTrackCount() - 1)
- if (mMetadataSelected && !select) {
- err = OK;
- } else if (!mMetadataSelected && select) {
- postFetchMsg = true;
- err = OK;
- } else {
- err = BAD_VALUE; // behave as LiveSession::selectTrack
- }
-
- mMetadataSelected = select;
- }
-
- if (err == OK) {
- int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration;
- generation++;
- if (postFetchMsg) {
- int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData;
- sp<AMessage> msg = new AMessage(what, this);
- msg->setInt32("generation", generation);
- msg->post();
- }
- }
-
- // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
- // selected track, or unselecting a non-selected track. In this case it's an
- // no-op so we return OK.
- return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- if (mLiveSession->isSeekable()) {
- return mLiveSession->seekTo(seekTimeUs, mode);
- } else {
- return INVALID_OPERATION;
- }
-}
-
-void NuPlayer2::HTTPLiveSource2::pollForRawData(
- const sp<AMessage> &msg, int32_t currentGeneration,
- LiveSession::StreamType fetchType, int32_t pushWhat) {
-
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != currentGeneration) {
- return;
- }
-
- sp<ABuffer> buffer;
- while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) {
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", pushWhat);
- notify->setBuffer("buffer", buffer);
-
- int64_t timeUs, baseUs, delayUs;
- CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- delayUs = baseUs + timeUs - ALooper::GetNowUs();
-
- if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) {
- notify->post();
- msg->post(delayUs > 0LL ? delayUs : 0LL);
- return;
- } else if (fetchType == LiveSession::STREAMTYPE_METADATA) {
- if (delayUs < -1000000LL) { // 1 second
- continue;
- }
- notify->post();
- // push all currently available metadata buffers in each invocation of pollForRawData
- // continue;
- } else {
- TRESPASS();
- }
- }
-
- // try again in 1 second
- msg->post(1000000LL);
-}
-
-void NuPlayer2::HTTPLiveSource2::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatSessionNotify:
- {
- onSessionNotify(msg);
- break;
- }
-
- case kWhatFetchSubtitleData:
- {
- pollForRawData(
- msg, mFetchSubtitleDataGeneration,
- /* fetch */ LiveSession::STREAMTYPE_SUBTITLES,
- /* push */ kWhatSubtitleData);
-
- break;
- }
-
- case kWhatFetchMetaData:
- {
- if (!mMetadataSelected) {
- break;
- }
-
- pollForRawData(
- msg, mFetchMetaDataGeneration,
- /* fetch */ LiveSession::STREAMTYPE_METADATA,
- /* push */ kWhatTimedMetaData);
-
- break;
- }
-
- default:
- Source::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::HTTPLiveSource2::onSessionNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case LiveSession::kWhatPrepared:
- {
- // notify the current size here if we have it, otherwise report an initial size of (0,0)
- sp<AMessage> format = getFormat(false /* audio */);
- int32_t width;
- int32_t height;
- if (format != NULL &&
- format->findInt32("width", &width) && format->findInt32("height", &height)) {
- notifyVideoSizeChanged(format);
- } else {
- notifyVideoSizeChanged();
- }
-
- uint32_t flags = 0;
- if (mLiveSession->isSeekable()) {
- flags |= FLAG_CAN_PAUSE;
- flags |= FLAG_CAN_SEEK;
- flags |= FLAG_CAN_SEEK_BACKWARD;
- flags |= FLAG_CAN_SEEK_FORWARD;
- }
-
- if (mLiveSession->hasDynamicDuration()) {
- flags |= FLAG_DYNAMIC_DURATION;
- }
-
- notifyFlagsChanged(flags);
-
- notifyPrepared();
- break;
- }
-
- case LiveSession::kWhatPreparationFailed:
- {
- status_t err;
- CHECK(msg->findInt32("err", &err));
-
- notifyPrepared(err);
- break;
- }
-
- case LiveSession::kWhatStreamsChanged:
- {
- uint32_t changedMask;
- CHECK(msg->findInt32(
- "changedMask", (int32_t *)&changedMask));
-
- bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
- bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
-
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatQueueDecoderShutdown);
- notify->setInt32("audio", audio);
- notify->setInt32("video", video);
- notify->setMessage("reply", reply);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatBufferingStart:
- {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatBufferingEnd:
- {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- break;
- }
-
-
- case LiveSession::kWhatBufferingUpdate:
- {
- sp<AMessage> notify = dupNotify();
- int32_t percentage;
- CHECK(msg->findInt32("percentage", &percentage));
- notify->setInt32("what", kWhatBufferingUpdate);
- notify->setInt32("percentage", percentage);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatMetadataDetected:
- {
- if (!mHasMetadata) {
- mHasMetadata = true;
-
- sp<AMessage> notify = dupNotify();
- // notification without buffer triggers MEDIA2_INFO_METADATA_UPDATE
- notify->setInt32("what", kWhatTimedMetaData);
- notify->post();
- }
- break;
- }
-
- case LiveSession::kWhatError:
- {
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
deleted file mode 100644
index 8fc71e2..0000000
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HTTP_LIVE_SOURCE2_H_
-
-#define HTTP_LIVE_SOURCE2_H_
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include "LiveSession.h"
-
-namespace android {
-
-struct LiveSession;
-
-struct NuPlayer2::HTTPLiveSource2 : public NuPlayer2::Source {
- HTTPLiveSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
- virtual void start();
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
- virtual sp<MetaData> getFormatMeta(bool audio);
- virtual sp<AMessage> getFormat(bool audio);
-
- virtual status_t feedMoreTSData();
- virtual status_t getDuration(int64_t *durationUs);
- virtual size_t getTrackCount() const;
- virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
- virtual ssize_t getSelectedTrack(media_track_type /* type */) const;
- virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
-protected:
- virtual ~HTTPLiveSource2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1,
- };
-
- enum {
- kWhatSessionNotify,
- kWhatFetchSubtitleData,
- kWhatFetchMetaData,
- };
-
- sp<MediaHTTPService> mHTTPService;
- AString mURL;
- KeyedVector<String8, String8> mExtraHeaders;
- uint32_t mFlags;
- status_t mFinalResult;
- off64_t mOffset;
- sp<ALooper> mLiveLooper;
- sp<LiveSession> mLiveSession;
- int32_t mFetchSubtitleDataGeneration;
- int32_t mFetchMetaDataGeneration;
- bool mHasMetadata;
- bool mMetadataSelected;
- BufferingSettings mBufferingSettings;
-
- void onSessionNotify(const sp<AMessage> &msg);
- void pollForRawData(
- const sp<AMessage> &msg, int32_t currentGeneration,
- LiveSession::StreamType fetchType, int32_t pushWhat);
-
- DISALLOW_EVIL_CONSTRUCTORS(HTTPLiveSource2);
-};
-
-} // namespace android
-
-#endif // HTTP_LIVE_SOURCE2_H_
diff --git a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
deleted file mode 100644
index 89703de..0000000
--- a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMediaPlayer2Utils"
-
-#include "JMediaPlayer2Utils.h"
-#include <mediaplayer2/JavaVMHelper.h>
-
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/Utils.h>
-#include <utils/Log.h>
-
-#include "log/log.h"
-
-namespace android {
-
-static const int64_t kOffloadMinDurationSec = 60;
-
-// static
-bool JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- const sp<MetaData>& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType)
-{
- if (hasVideo || streamType != AUDIO_STREAM_MUSIC) {
- return false;
- }
-
- audio_offload_info_t info = AUDIO_INFO_INITIALIZER;
- if (OK != getAudioOffloadInfo(meta, hasVideo, isStreaming, streamType, &info)) {
- return false;
- }
-
- if (info.duration_us < kOffloadMinDurationSec * 1000000) {
- return false;
- }
-
- int32_t audioFormat = audioFormatFromNative(info.format);
- int32_t channelMask = outChannelMaskFromNative(info.channel_mask);
- if (audioFormat == ENCODING_INVALID || channelMask == CHANNEL_INVALID) {
- return false;
- }
-
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jclass jMP2UtilsCls = env->FindClass("android/media/MediaPlayer2Utils");
- jmethodID jSetAudioOutputDeviceById = env->GetStaticMethodID(
- jMP2UtilsCls, "isOffloadedAudioPlaybackSupported", "(III)Z");
- jboolean result = env->CallStaticBooleanMethod(
- jMP2UtilsCls, jSetAudioOutputDeviceById, audioFormat, info.sample_rate, channelMask);
- return result;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h
deleted file mode 100644
index fcbd43c..0000000
--- a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIAPLAYER2_UTILS2_H_
-#define _J_MEDIAPLAYER2_UTILS2_H_
-
-#include <media/stagefright/MetaData.h>
-
-#include "jni.h"
-#include "android_media_AudioFormat.h"
-
-namespace android {
-
-struct JMediaPlayer2Utils {
- static bool isOffloadedAudioPlaybackSupported(
- const sp<MetaData>& meta, bool hasVideo, bool isStreaming,
- audio_stream_type_t streamType);
-};
-
-} // namespace android
-
-#endif // _J_MEDIAPLAYER2_UTILS2_H_
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp b/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
deleted file mode 100644
index 983d77e..0000000
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JWakeLock"
-#include <utils/Log.h>
-
-#include "JWakeLock.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-JWakeLock::JWakeLock(const sp<JObjectHolder> &context) :
- mWakeLockCount(0),
- mWakeLock(NULL),
- mContext(context) {}
-
-JWakeLock::~JWakeLock() {
- clearJavaWakeLock();
-}
-
-bool JWakeLock::acquire() {
- if (mWakeLockCount == 0) {
- if (mWakeLock == NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jContextCls = env->FindClass("android/content/Context");
- jclass jPowerManagerCls = env->FindClass("android/os/PowerManager");
-
- jmethodID jGetSystemService = env->GetMethodID(jContextCls,
- "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
- jobject javaPowerManagerObj = env->CallObjectMethod(mContext->getJObject(),
- jGetSystemService, env->NewStringUTF("power"));
-
- jfieldID jPARTIAL_WAKE_LOCK = env->GetStaticFieldID(jPowerManagerCls,
- "PARTIAL_WAKE_LOCK", "I");
- jint PARTIAL_WAKE_LOCK = env->GetStaticIntField(jPowerManagerCls, jPARTIAL_WAKE_LOCK);
-
- jmethodID jNewWakeLock = env->GetMethodID(jPowerManagerCls,
- "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;");
- jobject javaWakeLock = env->CallObjectMethod(javaPowerManagerObj,
- jNewWakeLock, PARTIAL_WAKE_LOCK, env->NewStringUTF("JWakeLock"));
- mWakeLock = new JObjectHolder(javaWakeLock);
- env->DeleteLocalRef(javaPowerManagerObj);
- env->DeleteLocalRef(javaWakeLock);
- }
- if (mWakeLock != NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
- jmethodID jAcquire = env->GetMethodID(wakeLockCls, "acquire", "()V");
- env->CallVoidMethod(mWakeLock->getJObject(), jAcquire);
- mWakeLockCount++;
- return true;
- }
- } else {
- mWakeLockCount++;
- return true;
- }
- return false;
-}
-
-void JWakeLock::release(bool force) {
- if (mWakeLockCount == 0) {
- return;
- }
- if (force) {
- // Force wakelock release below by setting reference count to 1.
- mWakeLockCount = 1;
- }
- if (--mWakeLockCount == 0) {
- if (mWakeLock != NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
- jmethodID jRelease = env->GetMethodID(wakeLockCls, "release", "()V");
- env->CallVoidMethod(mWakeLock->getJObject(), jRelease);
- }
- }
-}
-
-void JWakeLock::clearJavaWakeLock() {
- release(true);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.h b/media/libmediaplayer2/nuplayer2/JWakeLock.h
deleted file mode 100644
index 36c542e..0000000
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef J_WAKELOCK_H_
-#define J_WAKELOCK_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/JObjectHolder.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class JWakeLock : public RefBase {
-
-public:
- JWakeLock(const sp<JObjectHolder> &context);
-
- // NOTE: acquire and release are not thread safe
-
- // returns true if wakelock was acquired
- bool acquire();
- void release(bool force = false);
-
- virtual ~JWakeLock();
-
-private:
- uint32_t mWakeLockCount;
- sp<JObjectHolder> mWakeLock;
- const sp<JObjectHolder> mContext;
-
- void clearJavaWakeLock();
-
- DISALLOW_EVIL_CONSTRUCTORS(JWakeLock);
-};
-
-} // namespace android
-
-#endif // J_WAKELOCK_H_
diff --git a/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2 b/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/media/libmediaplayer2/nuplayer2/NOTICE b/media/libmediaplayer2/nuplayer2/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/media/libmediaplayer2/nuplayer2/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
deleted file mode 100644
index d608d4a..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ /dev/null
@@ -1,3308 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2"
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-
-#include "NuPlayer2.h"
-
-#include "HTTPLiveSource2.h"
-#include "JMediaPlayer2Utils.h"
-#include "NuPlayer2CCDecoder.h"
-#include "NuPlayer2Decoder.h"
-#include "NuPlayer2DecoderBase.h"
-#include "NuPlayer2DecoderPassThrough.h"
-#include "NuPlayer2Driver.h"
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-#include "RTSPSource2.h"
-#include "GenericSource2.h"
-#include "TextDescriptions2.h"
-
-#include "ATSParser.h"
-
-#include <cutils/properties.h>
-
-#include <media/AudioParameter.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AVSyncSettings.h>
-#include <media/DataSourceDesc.h>
-#include <media/MediaCodecBuffer.h>
-#include <media/NdkWrapper.h>
-
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-#include "ESDS.h"
-#include <media/stagefright/Utils.h>
-
-#include <system/window.h>
-
-namespace android {
-
-static status_t sendMetaDataToHal(sp<MediaPlayer2Interface::AudioSink>& sink,
- const sp<MetaData>& meta) {
- int32_t sampleRate = 0;
- int32_t bitRate = 0;
- int32_t channelMask = 0;
- int32_t delaySamples = 0;
- int32_t paddingSamples = 0;
-
- AudioParameter param = AudioParameter();
-
- if (meta->findInt32(kKeySampleRate, &sampleRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_SAMPLE_RATE), sampleRate);
- }
- if (meta->findInt32(kKeyChannelMask, &channelMask)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_NUM_CHANNEL), channelMask);
- }
- if (meta->findInt32(kKeyBitRate, &bitRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate);
- }
- if (meta->findInt32(kKeyEncoderDelay, &delaySamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
- }
- if (meta->findInt32(kKeyEncoderPadding, &paddingSamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
- }
-
- ALOGV("sendMetaDataToHal: bitRate %d, sampleRate %d, chanMask %d,"
- "delaySample %d, paddingSample %d", bitRate, sampleRate,
- channelMask, delaySamples, paddingSamples);
-
- sink->setParameters(param.toString());
- return OK;
-}
-
-
-struct NuPlayer2::Action : public RefBase {
- Action() {}
-
- virtual void execute(NuPlayer2 *player) = 0;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(Action);
-};
-
-struct NuPlayer2::SeekAction : public Action {
- explicit SeekAction(int64_t seekTimeUs, MediaPlayer2SeekMode mode)
- : mSeekTimeUs(seekTimeUs),
- mMode(mode) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performSeek(mSeekTimeUs, mMode);
- }
-
-private:
- int64_t mSeekTimeUs;
- MediaPlayer2SeekMode mMode;
-
- DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
-};
-
-struct NuPlayer2::ResumeDecoderAction : public Action {
- explicit ResumeDecoderAction(bool needNotify)
- : mNeedNotify(needNotify) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performResumeDecoders(mNeedNotify);
- }
-
-private:
- bool mNeedNotify;
-
- DISALLOW_EVIL_CONSTRUCTORS(ResumeDecoderAction);
-};
-
-struct NuPlayer2::SetSurfaceAction : public Action {
- explicit SetSurfaceAction(const sp<ANativeWindowWrapper> &nww)
- : mNativeWindow(nww) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performSetSurface(mNativeWindow);
- }
-
-private:
- sp<ANativeWindowWrapper> mNativeWindow;
-
- DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction);
-};
-
-struct NuPlayer2::FlushDecoderAction : public Action {
- FlushDecoderAction(FlushCommand audio, FlushCommand video)
- : mAudio(audio),
- mVideo(video) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performDecoderFlush(mAudio, mVideo);
- }
-
-private:
- FlushCommand mAudio;
- FlushCommand mVideo;
-
- DISALLOW_EVIL_CONSTRUCTORS(FlushDecoderAction);
-};
-
-struct NuPlayer2::PostMessageAction : public Action {
- explicit PostMessageAction(const sp<AMessage> &msg)
- : mMessage(msg) {
- }
-
- virtual void execute(NuPlayer2 *) {
- mMessage->post();
- }
-
-private:
- sp<AMessage> mMessage;
-
- DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction);
-};
-
-// Use this if there's no state necessary to save in order to execute
-// the action.
-struct NuPlayer2::SimpleAction : public Action {
- typedef void (NuPlayer2::*ActionFunc)();
-
- explicit SimpleAction(ActionFunc func)
- : mFunc(func) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- (player->*mFunc)();
- }
-
-private:
- ActionFunc mFunc;
-
- DISALLOW_EVIL_CONSTRUCTORS(SimpleAction);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-NuPlayer2::NuPlayer2(
- pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context)
- : mPID(pid),
- mUID(uid),
- mMediaClock(mediaClock),
- mOffloadAudio(false),
- mAudioDecoderGeneration(0),
- mVideoDecoderGeneration(0),
- mRendererGeneration(0),
- mEOSMonitorGeneration(0),
- mLastStartedPlayingTimeNs(0),
- mPreviousSeekTimeUs(0),
- mAudioEOS(false),
- mVideoEOS(false),
- mScanSourcesPending(false),
- mScanSourcesGeneration(0),
- mPollDurationGeneration(0),
- mTimedTextGeneration(0),
- mFlushingAudio(NONE),
- mFlushingVideo(NONE),
- mResumePending(false),
- mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
- mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
- mVideoFpsHint(-1.f),
- mStarted(false),
- mPrepared(false),
- mResetting(false),
- mSourceStarted(false),
- mAudioDecoderError(false),
- mVideoDecoderError(false),
- mPaused(false),
- mPausedByClient(true),
- mPausedForBuffering(false),
- mContext(context) {
- CHECK(mediaClock != NULL);
- clearFlushComplete();
-}
-
-NuPlayer2::~NuPlayer2() {
-}
-
-void NuPlayer2::setDriver(const wp<NuPlayer2Driver> &driver) {
- mDriver = driver;
-}
-
-static bool IsHTTPLiveURL(const char *url) {
- if (!strncasecmp("http://", url, 7)
- || !strncasecmp("https://", url, 8)
- || !strncasecmp("file://", url, 7)) {
- size_t len = strlen(url);
- if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
- return true;
- }
-
- if (strstr(url,"m3u8")) {
- return true;
- }
- }
-
- return false;
-}
-
-status_t NuPlayer2::createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
- sp<Source> *source,
- DATA_SOURCE_TYPE *dataSourceType) {
- status_t err = NO_ERROR;
- sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
- notify->setInt64("srcId", dsd->mId);
-
- switch (dsd->mType) {
- case DataSourceDesc::TYPE_URL:
- {
- const char *url = dsd->mUrl.c_str();
- size_t len = strlen(url);
-
- const sp<MediaHTTPService> &httpService = dsd->mHttpService;
- KeyedVector<String8, String8> *headers = &(dsd->mHeaders);
-
- if (IsHTTPLiveURL(url)) {
- *source = new HTTPLiveSource2(notify, httpService, url, headers);
- ALOGV("createNuPlayer2Source HTTPLiveSource2 %s", url);
- *dataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
- } else if (!strncasecmp(url, "rtsp://", 7)) {
- *source = new RTSPSource2(
- notify, httpService, url, headers, mUID);
- ALOGV("createNuPlayer2Source RTSPSource2 %s", url);
- *dataSourceType = DATA_SOURCE_TYPE_RTSP;
- } else if ((!strncasecmp(url, "http://", 7)
- || !strncasecmp(url, "https://", 8))
- && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
- || strstr(url, ".sdp?"))) {
- *source = new RTSPSource2(
- notify, httpService, url, headers, mUID, true);
- ALOGV("createNuPlayer2Source RTSPSource2 http/https/.sdp %s", url);
- *dataSourceType = DATA_SOURCE_TYPE_RTSP;
- } else {
- ALOGV("createNuPlayer2Source GenericSource2 %s", url);
-
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
-
- err = genericSource->setDataSource(url, headers);
-
- if (err == OK) {
- *source = genericSource;
- } else {
- *source = NULL;
- ALOGE("Failed to create NuPlayer2Source!");
- }
-
- // regardless of success/failure
- *dataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
- }
- break;
- }
-
- case DataSourceDesc::TYPE_FD:
- {
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
-
- ALOGV("createNuPlayer2Source fd %d/%lld/%lld source: %p",
- dsd->mFD, (long long)dsd->mFDOffset, (long long)dsd->mFDLength,
- genericSource.get());
-
- err = genericSource->setDataSource(dsd->mFD, dsd->mFDOffset, dsd->mFDLength);
-
- if (err != OK) {
- ALOGE("Failed to create NuPlayer2Source!");
- *source = NULL;
- } else {
- *source = genericSource;
- }
-
- *dataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
- break;
- }
-
- case DataSourceDesc::TYPE_CALLBACK:
- {
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
- err = genericSource->setDataSource(dsd->mCallbackSource);
-
- if (err != OK) {
- ALOGE("Failed to create NuPlayer2Source!");
- *source = NULL;
- } else {
- *source = genericSource;
- }
-
- *dataSourceType = DATA_SOURCE_TYPE_MEDIA;
- break;
- }
-
- default:
- err = BAD_TYPE;
- *source = NULL;
- *dataSourceType = DATA_SOURCE_TYPE_NONE;
- ALOGE("invalid data source type!");
- break;
- }
-
- return err;
-}
-
-void NuPlayer2::setDataSourceAsync(const sp<DataSourceDesc> &dsd) {
- DATA_SOURCE_TYPE dataSourceType;
- sp<Source> source;
- createNuPlayer2Source(dsd, &source, &dataSourceType);
-
- // TODO: currently NuPlayer2Driver makes blocking call to setDataSourceAsync
- // and expects notifySetDataSourceCompleted regardless of success or failure.
- // This will be changed since setDataSource should be asynchronous at JAVA level.
- // When it succeeds, app will get onInfo notification. Otherwise, onError
- // will be called.
- /*
- if (err != OK) {
- notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
- return;
- }
-
- // Now, source != NULL.
- */
-
- mCurrentSourceInfo.mDataSourceType = dataSourceType;
-
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
- msg->setObject("source", source);
- msg->setInt64("srcId", dsd->mId);
- msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
- msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
- msg->post();
-}
-
-void NuPlayer2::prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd) {
- DATA_SOURCE_TYPE dataSourceType;
- sp<Source> source;
- createNuPlayer2Source(dsd, &source, &dataSourceType);
-
- /*
- if (err != OK) {
- notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
- return;
- }
-
- // Now, source != NULL.
- */
-
- mNextSourceInfo.mDataSourceType = dataSourceType;
-
- sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
- msg->setObject("source", source);
- msg->setInt64("srcId", dsd->mId);
- msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
- msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
- msg->post();
-}
-
-void NuPlayer2::playNextDataSource(int64_t srcId) {
- disconnectSource();
-
- sp<AMessage> msg = new AMessage(kWhatPlayNextDataSource, this);
- msg->setInt64("srcId", srcId);
- msg->post();
-}
-
-status_t NuPlayer2::getBufferingSettings(
- BufferingSettings *buffering /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetBufferingSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, buffering);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
- sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
- writeToAMessage(msg, buffering);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-void NuPlayer2::prepareAsync() {
- ALOGV("prepareAsync");
-
- (new AMessage(kWhatPrepare, this))->post();
-}
-
-void NuPlayer2::setVideoSurfaceTextureAsync(const sp<ANativeWindowWrapper> &nww) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);
-
- if (nww == NULL || nww->getANativeWindow() == NULL) {
- msg->setObject("surface", NULL);
- } else {
- msg->setObject("surface", nww);
- }
-
- msg->post();
-}
-
-void NuPlayer2::setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink) {
- sp<AMessage> msg = new AMessage(kWhatSetAudioSink, this);
- msg->setObject("sink", sink);
- msg->post();
-}
-
-void NuPlayer2::start() {
- (new AMessage(kWhatStart, this))->post();
-}
-
-status_t NuPlayer2::setPlaybackSettings(const AudioPlaybackRate &rate) {
- // do some cursory validation of the settings here. audio modes are
- // only validated when set on the audiosink.
- if (rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
- || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
- return BAD_VALUE;
- }
- sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
- writeToAMessage(msg, rate);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, rate);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
- writeToAMessage(msg, sync, videoFpsHint);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::getSyncSettings(
- AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, sync, videoFps);
- }
- }
- return err;
-}
-
-void NuPlayer2::pause() {
- (new AMessage(kWhatPause, this))->post();
-}
-
-void NuPlayer2::resetAsync() {
- disconnectSource();
- (new AMessage(kWhatReset, this))->post();
-}
-
-void NuPlayer2::disconnectSource() {
- sp<Source> source;
- {
- Mutex::Autolock autoLock(mSourceLock);
- source = mCurrentSourceInfo.mSource;
- }
-
- if (source != NULL) {
- // During a reset, the data source might be unresponsive already, we need to
- // disconnect explicitly so that reads exit promptly.
- // We can't queue the disconnect request to the looper, as it might be
- // queued behind a stuck read and never gets processed.
- // Doing a disconnect outside the looper to allows the pending reads to exit
- // (either successfully or with error).
- source->disconnect();
- }
-
-}
-
-status_t NuPlayer2::notifyAt(int64_t mediaTimeUs) {
- sp<AMessage> notify = new AMessage(kWhatNotifyTime, this);
- notify->setInt64("timerUs", mediaTimeUs);
- mMediaClock->addTimer(notify, mediaTimeUs);
- return OK;
-}
-
-void NuPlayer2::seekToAsync(int64_t seekTimeUs, MediaPlayer2SeekMode mode, bool needNotify) {
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("mode", mode);
- msg->setInt32("needNotify", needNotify);
- msg->post();
-}
-
-void NuPlayer2::rewind() {
- sp<AMessage> msg = new AMessage(kWhatRewind, this);
- msg->post();
-}
-
-void NuPlayer2::writeTrackInfo(
- PlayerMessage* reply, const sp<AMessage>& format) const {
- if (format == NULL) {
- ALOGE("NULL format");
- return;
- }
- int32_t trackType;
- if (!format->findInt32("type", &trackType)) {
- ALOGE("no track type");
- return;
- }
-
- AString mime;
- if (!format->findString("mime", &mime)) {
- // Java MediaPlayer only uses mimetype for subtitle and timedtext tracks.
- // If we can't find the mimetype here it means that we wouldn't be needing
- // the mimetype on the Java end. We still write a placeholder mime to keep the
- // (de)serialization logic simple.
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- mime = "audio/";
- } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- mime = "video/";
- } else {
- ALOGE("unknown track type: %d", trackType);
- return;
- }
- }
-
- AString lang;
- if (!format->findString("language", &lang)) {
- ALOGE("no language");
- return;
- }
-
- reply->add_values()->set_int32_value(trackType);
- reply->add_values()->set_string_value(mime.c_str());
- reply->add_values()->set_string_value(lang.c_str());
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- int32_t isAuto, isDefault, isForced;
- CHECK(format->findInt32("auto", &isAuto));
- CHECK(format->findInt32("default", &isDefault));
- CHECK(format->findInt32("forced", &isForced));
-
- reply->add_values()->set_int32_value(isAuto);
- reply->add_values()->set_int32_value(isDefault);
- reply->add_values()->set_int32_value(isForced);
- }
-}
-
-void NuPlayer2::onMessageReceived(const sp<AMessage> &msg) {
-
- switch (msg->what()) {
- case kWhatSetDataSource:
- {
- ALOGV("kWhatSetDataSource");
-
- CHECK(mCurrentSourceInfo.mSource == NULL);
-
- status_t err = OK;
- sp<RefBase> obj;
- CHECK(msg->findObject("source", &obj));
- if (obj != NULL) {
- Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
- CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
- CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
- mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
- } else {
- err = UNKNOWN_ERROR;
- ALOGE("kWhatSetDataSource, source should not be NULL");
- }
-
- CHECK(mDriver != NULL);
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySetDataSourceCompleted(mCurrentSourceInfo.mSrcId, err);
- }
- break;
- }
-
- case kWhatPrepareNextDataSource:
- {
- ALOGV("kWhatPrepareNextDataSource");
-
- status_t err = OK;
- sp<RefBase> obj;
- CHECK(msg->findObject("source", &obj));
- if (obj != NULL) {
- Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mNextSourceInfo.mSrcId));
- CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
- CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
- mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
- mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
- } else {
- err = UNKNOWN_ERROR;
- }
-
- break;
- }
-
- case kWhatPlayNextDataSource:
- {
- ALOGV("kWhatPlayNextDataSource");
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- if (srcId != mNextSourceInfo.mSrcId) {
- notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
- return;
- }
-
- mResetting = true;
- stopPlaybackTimer("kWhatPlayNextDataSource");
- stopRebufferingTimer(true);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performPlayNextDataSource));
-
- processDeferredActions();
- break;
- }
-
- case kWhatEOSMonitor:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
-
- if (generation != mEOSMonitorGeneration || reason != MediaClock::TIMER_REASON_REACHED) {
- break; // stale or reset
- }
-
- ALOGV("kWhatEOSMonitor");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- break;
- }
-
- case kWhatGetBufferingSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatGetBufferingSettings");
- BufferingSettings buffering;
- status_t err = OK;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
- } else {
- err = INVALID_OPERATION;
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, buffering);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatSetBufferingSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatSetBufferingSettings");
- BufferingSettings buffering;
- readFromAMessage(msg, &buffering);
- status_t err = OK;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
- } else {
- err = INVALID_OPERATION;
- }
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatPrepare:
- {
- ALOGV("onMessageReceived kWhatPrepare");
-
- mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
- break;
- }
-
- case kWhatGetTrackInfo:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- int64_t srcId;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
-
- PlayerMessage* reply;
- CHECK(msg->findPointer("reply", (void**)&reply));
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
-
- size_t ccTracks = 0;
- if (mCCDecoder != NULL) {
- ccTracks = mCCDecoder->getTrackCount();
- }
-
- // total track count
- reply->add_values()->set_int32_value(inbandTracks + ccTracks);
-
- // write inband tracks
- for (size_t i = 0; i < inbandTracks; ++i) {
- writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
- }
-
- // write CC track
- for (size_t i = 0; i < ccTracks; ++i) {
- writeTrackInfo(reply, mCCDecoder->getTrackInfo(i));
- }
-
- sp<AMessage> response = new AMessage;
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSelectedTrack:
- {
- int64_t srcId;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
-
- int32_t type32;
- CHECK(msg->findInt32("type", (int32_t*)&type32));
- media_track_type type = (media_track_type)type32;
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- status_t err = INVALID_OPERATION;
- ssize_t selectedTrack = -1;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = OK;
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
- }
-
- if (selectedTrack == -1 && mCCDecoder != NULL) {
- err = OK;
- selectedTrack = mCCDecoder->getSelectedTrack(type);
- if (selectedTrack != -1) {
- selectedTrack += inbandTracks;
- }
- }
-
- PlayerMessage* reply;
- CHECK(msg->findPointer("reply", (void**)&reply));
- reply->add_values()->set_int32_value(selectedTrack);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- case kWhatSelectTrack:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- int64_t srcId;
- size_t trackIndex;
- int32_t select;
- int64_t timeUs;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK(msg->findInt32("select", &select));
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- status_t err = INVALID_OPERATION;
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
- size_t ccTracks = 0;
- if (mCCDecoder != NULL) {
- ccTracks = mCCDecoder->getTrackCount();
- }
-
- if (trackIndex < inbandTracks) {
- err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
-
- if (!select && err == OK) {
- int32_t type;
- sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
- if (info != NULL
- && info->findInt32("type", &type)
- && type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- ++mTimedTextGeneration;
- }
- }
- } else {
- trackIndex -= inbandTracks;
-
- if (trackIndex < ccTracks) {
- err = mCCDecoder->selectTrack(trackIndex, select);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
-
- response->postReply(replyID);
- break;
- }
-
- case kWhatPollDuration:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mPollDurationGeneration) {
- // stale
- break;
- }
-
- int64_t durationUs;
- if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
- }
- }
-
- msg->post(1000000LL); // poll again in a second.
- break;
- }
-
- case kWhatSetVideoSurface:
- {
-
- sp<RefBase> obj;
- CHECK(msg->findObject("surface", &obj));
- sp<ANativeWindowWrapper> nww = static_cast<ANativeWindowWrapper *>(obj.get());
-
- ALOGD("onSetVideoSurface(%p, %s video decoder)",
- (nww == NULL ? NULL : nww->getANativeWindow()),
- (mCurrentSourceInfo.mSource != NULL && mStarted
- && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
- && mVideoDecoder != NULL) ? "have" : "no");
-
- // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
- // because NuPlayer2 might be in preparing state and it could take long time.
- // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
- if (mCurrentSourceInfo.mSource == NULL || !mStarted
- || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
- // NOTE: mVideoDecoder's mNativeWindow is always non-null
- || (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
- performSetSurface(nww);
- break;
- }
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- (obj != NULL ? FLUSH_CMD_FLUSH : FLUSH_CMD_NONE) /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(new SetSurfaceAction(nww));
-
- if (obj != NULL) {
- if (mStarted) {
- // Issue a seek to refresh the video screen only if started otherwise
- // the extractor may not yet be started and will assert.
- // If the video decoder is not set (perhaps audio only in this case)
- // do not perform a seek as it is not needed.
- int64_t currentPositionUs = 0;
- if (getCurrentPosition(¤tPositionUs) == OK) {
- mDeferredActions.push_back(
- new SeekAction(currentPositionUs,
- MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */));
- }
- }
-
- // If there is a new surface texture, instantiate decoders
- // again if possible.
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(false /* needNotify */));
- }
-
- processDeferredActions();
- break;
- }
-
- case kWhatSetAudioSink:
- {
- ALOGV("kWhatSetAudioSink");
-
- sp<RefBase> obj;
- CHECK(msg->findObject("sink", &obj));
-
- mAudioSink = static_cast<MediaPlayer2Interface::AudioSink *>(obj.get());
- break;
- }
-
- case kWhatStart:
- {
- ALOGV("kWhatStart");
- if (mStarted) {
- // do not resume yet if the source is still buffering
- if (!mPausedForBuffering) {
- onResume();
- }
- } else {
- onStart(true /* play */);
- }
- mPausedByClient = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
- break;
- }
-
- case kWhatConfigPlayback:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate /* sanitized */;
- readFromAMessage(msg, &rate);
- status_t err = OK;
- if (mRenderer != NULL) {
- // AudioSink allows only 1.f and 0.f for offload mode.
- // For other speed, switch to non-offload mode.
- if (mOffloadAudio && (rate.mSpeed != 1.f || rate.mPitch != 1.f)) {
- int64_t currentPositionUs;
- if (getCurrentPosition(¤tPositionUs) != OK) {
- currentPositionUs = mPreviousSeekTimeUs;
- }
-
- // Set mPlaybackSettings so that the new audio decoder can
- // be created correctly.
- mPlaybackSettings = rate;
- if (!mPaused) {
- mRenderer->pause();
- }
- restartAudio(
- currentPositionUs, true /* forceNonOffload */,
- true /* needsToCreateAudioDecoder */);
- if (!mPaused) {
- mRenderer->resume();
- }
- }
-
- err = mRenderer->setPlaybackSettings(rate);
- }
- if (err == OK) {
- mPlaybackSettings = rate;
-
- if (mVideoDecoder != NULL) {
- sp<AMessage> params = new AMessage();
- params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
- mVideoDecoder->setParameters(params);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetPlaybackSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate = mPlaybackSettings;
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->getPlaybackSettings(&rate);
- }
- if (err == OK) {
- // get playback settings used by renderer, as it may be
- // slightly off due to audiosink not taking small changes.
- mPlaybackSettings = rate;
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, rate);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatConfigSync:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatConfigSync");
- AVSyncSettings sync;
- float videoFpsHint;
- readFromAMessage(msg, &sync, &videoFpsHint);
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->setSyncSettings(sync, videoFpsHint);
- }
- if (err == OK) {
- mSyncSettings = sync;
- mVideoFpsHint = videoFpsHint;
- }
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSyncSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AVSyncSettings sync = mSyncSettings;
- float videoFps = mVideoFpsHint;
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->getSyncSettings(&sync, &videoFps);
- if (err == OK) {
- mSyncSettings = sync;
- mVideoFpsHint = videoFps;
- }
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, sync, videoFps);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatScanSources:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mScanSourcesGeneration) {
- // Drop obsolete msg.
- break;
- }
-
- mScanSourcesPending = false;
-
- ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
- mAudioDecoder != NULL, mVideoDecoder != NULL);
-
- bool mHadAnySourcesBefore =
- (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
- bool rescan = false;
-
- // initialize video before audio because successful initialization of
- // video may change deep buffer mode of audio.
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) {
- rescan = true;
- }
- }
-
- // Don't try to re-open audio sink if there's an existing decoder.
- if (mAudioSink != NULL && mAudioDecoder == NULL) {
- if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) {
- rescan = true;
- }
- }
-
- if (!mHadAnySourcesBefore
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- // This is the first time we've found anything playable.
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
- schedulePollDuration();
- }
- }
-
- status_t err;
- if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
- if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
- // We're not currently decoding anything (no audio or
- // video tracks found) and we just ran out of input data.
-
- if (err == ERROR_END_OF_STREAM) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- } else {
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
- }
- break;
- }
-
- if (rescan) {
- msg->post(100000LL);
- mScanSourcesPending = true;
- }
- break;
- }
-
- case kWhatVideoNotify:
- case kWhatAudioNotify:
- {
- bool audio = msg->what() == kWhatAudioNotify;
-
- int32_t currentDecoderGeneration =
- (audio? mAudioDecoderGeneration : mVideoDecoderGeneration);
- int32_t requesterGeneration = currentDecoderGeneration - 1;
- CHECK(msg->findInt32("generation", &requesterGeneration));
-
- if (requesterGeneration != currentDecoderGeneration) {
- ALOGV("got message from old %s decoder, generation(%d:%d)",
- audio ? "audio" : "video", requesterGeneration,
- currentDecoderGeneration);
- sp<AMessage> reply;
- if (!(msg->findMessage("reply", &reply))) {
- return;
- }
-
- reply->setInt32("err", INFO_DISCONTINUITY);
- reply->post();
- return;
- }
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- if (what == DecoderBase::kWhatInputDiscontinuity) {
- int32_t formatChange;
- CHECK(msg->findInt32("formatChange", &formatChange));
-
- ALOGV("%s discontinuity: formatChange %d",
- audio ? "audio" : "video", formatChange);
-
- if (formatChange) {
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
- }
-
- mDeferredActions.push_back(
- new SimpleAction(
- &NuPlayer2::performScanSources));
-
- processDeferredActions();
- } else if (what == DecoderBase::kWhatEOS) {
- int32_t err;
- CHECK(msg->findInt32("err", &err));
-
- if (err == ERROR_END_OF_STREAM) {
- ALOGV("got %s decoder EOS", audio ? "audio" : "video");
- } else {
- ALOGV("got %s decoder EOS w/ error %d",
- audio ? "audio" : "video",
- err);
- }
-
- mRenderer->queueEOS(audio, err);
- } else if (what == DecoderBase::kWhatFlushCompleted) {
- ALOGV("decoder %s flush completed", audio ? "audio" : "video");
-
- handleFlushComplete(audio, true /* isDecoder */);
- finishFlushIfPossible();
- } else if (what == DecoderBase::kWhatVideoSizeChanged) {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- sp<AMessage> inputFormat =
- mCurrentSourceInfo.mSource->getFormat(false /* audio */);
-
- setVideoScalingMode(mVideoScalingMode);
- updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
- } else if (what == DecoderBase::kWhatShutdownCompleted) {
- ALOGV("%s shutdown completed", audio ? "audio" : "video");
- if (audio) {
- Mutex::Autolock autoLock(mDecoderLock);
- mAudioDecoder.clear();
- mAudioDecoderError = false;
- ++mAudioDecoderGeneration;
-
- CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
- mFlushingAudio = SHUT_DOWN;
- } else {
- Mutex::Autolock autoLock(mDecoderLock);
- mVideoDecoder.clear();
- mVideoDecoderError = false;
- ++mVideoDecoderGeneration;
-
- CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
- mFlushingVideo = SHUT_DOWN;
- }
-
- finishFlushIfPossible();
- } else if (what == DecoderBase::kWhatResumeCompleted) {
- finishResume();
- } else if (what == DecoderBase::kWhatError) {
- status_t err;
- if (!msg->findInt32("err", &err) || err == OK) {
- err = UNKNOWN_ERROR;
- }
-
- // Decoder errors can be due to Source (e.g. from streaming),
- // or from decoding corrupted bitstreams, or from other decoder
- // MediaCodec operations (e.g. from an ongoing reset or seek).
- // They may also be due to openAudioSink failure at
- // decoder start or after a format change.
- //
- // We try to gracefully shut down the affected decoder if possible,
- // rather than trying to force the shutdown with something
- // similar to performReset(). This method can lead to a hang
- // if MediaCodec functions block after an error, but they should
- // typically return INVALID_OPERATION instead of blocking.
-
- FlushStatus *flushing = audio ? &mFlushingAudio : &mFlushingVideo;
- ALOGE("received error(%#x) from %s decoder, flushing(%d), now shutting down",
- err, audio ? "audio" : "video", *flushing);
-
- switch (*flushing) {
- case NONE:
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
- processDeferredActions();
- break;
- case FLUSHING_DECODER:
- *flushing = FLUSHING_DECODER_SHUTDOWN; // initiate shutdown after flush.
- break; // Wait for flush to complete.
- case FLUSHING_DECODER_SHUTDOWN:
- break; // Wait for flush to complete.
- case SHUTTING_DOWN_DECODER:
- break; // Wait for shutdown to complete.
- case FLUSHED:
- getDecoder(audio)->initiateShutdown(); // In the middle of a seek.
- *flushing = SHUTTING_DOWN_DECODER; // Shut down.
- break;
- case SHUT_DOWN:
- finishFlushIfPossible(); // Should not occur.
- break; // Finish anyways.
- }
- if (mCurrentSourceInfo.mSource != nullptr) {
- if (audio) {
- if (mVideoDecoderError
- || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
- || mNativeWindow == NULL
- || mNativeWindow->getANativeWindow() == NULL
- || mVideoDecoder == NULL) {
- // When both audio and video have error, or this stream has only audio
- // which has error, notify client of error.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, err);
- } else {
- // Only audio track has error. Video track could be still good to play.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
- }
- mAudioDecoderError = true;
- } else {
- if (mAudioDecoderError
- || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
- || mAudioSink == NULL || mAudioDecoder == NULL) {
- // When both audio and video have error, or this stream has only video
- // which has error, notify client of error.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, err);
- } else {
- // Only video track has error. Audio track could be still good to play.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
- }
- mVideoDecoderError = true;
- }
- }
- } else {
- ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
- what,
- what >> 24,
- (what >> 16) & 0xff,
- (what >> 8) & 0xff,
- what & 0xff);
- }
-
- break;
- }
-
- case kWhatRendererNotify:
- {
- int32_t requesterGeneration = mRendererGeneration - 1;
- CHECK(msg->findInt32("generation", &requesterGeneration));
- if (requesterGeneration != mRendererGeneration) {
- ALOGV("got message from old renderer, generation(%d:%d)",
- requesterGeneration, mRendererGeneration);
- return;
- }
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- if (what == Renderer::kWhatEOS) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
-
- if (audio) {
- mAudioEOS = true;
- } else {
- mVideoEOS = true;
- }
-
- if (finalResult == ERROR_END_OF_STREAM) {
- ALOGV("reached %s EOS", audio ? "audio" : "video");
- } else {
- ALOGE("%s track encountered an error (%d)",
- audio ? "audio" : "video", finalResult);
-
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, finalResult);
- }
-
- if ((mAudioEOS || mAudioDecoder == NULL)
- && (mVideoEOS || mVideoDecoder == NULL)) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- }
- } else if (what == Renderer::kWhatFlushComplete) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (audio) {
- mAudioEOS = false;
- } else {
- mVideoEOS = false;
- }
-
- ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
- if (audio && (mFlushingAudio == NONE || mFlushingAudio == FLUSHED
- || mFlushingAudio == SHUT_DOWN)) {
- // Flush has been handled by tear down.
- break;
- }
- handleFlushComplete(audio, false /* isDecoder */);
- finishFlushIfPossible();
- } else if (what == Renderer::kWhatVideoRenderingStart) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_VIDEO_RENDERING_START, 0);
- } else if (what == Renderer::kWhatMediaRenderingStart) {
- ALOGV("media rendering started");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
- } else if (what == Renderer::kWhatAudioTearDown) {
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
- ALOGV("Tear down audio with reason %d.", reason);
- if (reason == Renderer::kDueToTimeout && !(mPaused && mOffloadAudio)) {
- // TimeoutWhenPaused is only for offload mode.
- ALOGW("Receive a stale message for teardown.");
- break;
- }
- int64_t positionUs;
- if (!msg->findInt64("positionUs", &positionUs)) {
- positionUs = mPreviousSeekTimeUs;
- }
-
- restartAudio(
- positionUs, reason == Renderer::kForceNonOffload /* forceNonOffload */,
- reason != Renderer::kDueToTimeout /* needsToCreateAudioDecoder */);
- }
- break;
- }
-
- case kWhatMoreDataQueued:
- {
- break;
- }
-
- case kWhatReset:
- {
- ALOGV("kWhatReset");
-
- mResetting = true;
- stopPlaybackTimer("kWhatReset");
- stopRebufferingTimer(true);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performReset));
-
- processDeferredActions();
- break;
- }
-
- case kWhatNotifyTime:
- {
- ALOGV("kWhatNotifyTime");
- int64_t timerUs;
- CHECK(msg->findInt64("timerUs", &timerUs));
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
- break;
- }
-
- case kWhatSeek:
- {
- int64_t seekTimeUs;
- int32_t mode;
- int32_t needNotify;
- CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
- CHECK(msg->findInt32("needNotify", &needNotify));
-
- ALOGV("kWhatSeek seekTimeUs=%lld us, mode=%d, needNotify=%d",
- (long long)seekTimeUs, mode, needNotify);
-
- if (!mStarted) {
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
- if (seekTimeUs > 0) {
- performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- }
-
- if (needNotify) {
- notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
- }
- break;
- }
-
- // seeks can take a while, so we essentially paused
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
- FLUSH_CMD_FLUSH /* video */));
-
- mDeferredActions.push_back(
- new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(needNotify));
-
- processDeferredActions();
- break;
- }
-
- case kWhatRewind:
- {
- ALOGV("kWhatRewind");
-
- int64_t seekTimeUs = mCurrentSourceInfo.mStartTimeUs;
- int32_t mode = MediaPlayer2SeekMode::SEEK_CLOSEST;
-
- if (!mStarted) {
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
- performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- break;
- }
-
- // seeks can take a while, so we essentially paused
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
- FLUSH_CMD_FLUSH /* video */));
-
- mDeferredActions.push_back(
- new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(false /* needNotify */));
-
- processDeferredActions();
- break;
- }
-
- case kWhatPause:
- {
- if (!mStarted) {
- onStart(false /* play */);
- }
- onPause();
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
- mPausedByClient = true;
- break;
- }
-
- case kWhatSourceNotify:
- {
- onSourceNotify(msg);
- break;
- }
-
- case kWhatClosedCaptionNotify:
- {
- onClosedCaptionNotify(msg);
- break;
- }
-
- case kWhatPrepareDrm:
- {
- status_t status = onPrepareDrm(msg);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- case kWhatReleaseDrm:
- {
- status_t status = onReleaseDrm(msg);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::onResume() {
- if (!mPaused || mResetting) {
- ALOGD_IF(mResetting, "resetting, onResume discarded");
- return;
- }
- mPaused = false;
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->resume();
- } else {
- ALOGW("resume called when source is gone or not set");
- }
- // |mAudioDecoder| may have been released due to the pause timeout, so re-create it if
- // needed.
- if (audioDecoderStillNeeded() && mAudioDecoder == NULL) {
- instantiateDecoder(true /* audio */, &mAudioDecoder);
- }
- if (mRenderer != NULL) {
- mRenderer->resume();
- } else {
- ALOGW("resume called when renderer is gone or not set");
- }
-
- startPlaybackTimer("onresume");
-}
-
-void NuPlayer2::onStart(bool play) {
- ALOGV("onStart: mCrypto: %p", mCurrentSourceInfo.mCrypto.get());
-
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
-
- mOffloadAudio = false;
- mAudioEOS = false;
- mVideoEOS = false;
- mStarted = true;
- mPaused = false;
-
- uint32_t flags = 0;
-
- if (mCurrentSourceInfo.mSource->isRealTime()) {
- flags |= Renderer::FLAG_REAL_TIME;
- }
-
- bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
- bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
- if (!hasAudio && !hasVideo) {
- ALOGE("no metadata for either audio or video source");
- mCurrentSourceInfo.mSource->stop();
- mSourceStarted = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
- return;
- }
- ALOGV_IF(!hasAudio, "no metadata for audio source"); // video only stream
-
- sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
-
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
-
- mOffloadAudio =
- JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
- && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
-
- // Modular DRM: Disabling audio offload if the source is protected
- if (mOffloadAudio && mCurrentSourceInfo.mIsDrmProtected) {
- mOffloadAudio = false;
- ALOGV("onStart: Disabling mOffloadAudio now that the source is protected.");
- }
-
- if (mOffloadAudio) {
- flags |= Renderer::FLAG_OFFLOAD_AUDIO;
- }
-
- sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
- ++mRendererGeneration;
- notify->setInt32("generation", mRendererGeneration);
- mRenderer = new Renderer(mAudioSink, mMediaClock, notify, mContext, flags);
- mRendererLooper = new ALooper;
- mRendererLooper->setName("NuPlayer2Renderer");
- mRendererLooper->start(false, true, ANDROID_PRIORITY_AUDIO);
- mRendererLooper->registerHandler(mRenderer);
-
- status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
- if (err != OK) {
- mCurrentSourceInfo.mSource->stop();
- mSourceStarted = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- return;
- }
-
- float rate = getFrameRate();
- if (rate > 0) {
- mRenderer->setVideoFrameRate(rate);
- }
-
- addEndTimeMonitor();
- // Renderer is created in paused state.
- if (play) {
- mRenderer->resume();
- }
-
- if (mVideoDecoder != NULL) {
- mVideoDecoder->setRenderer(mRenderer);
- }
- if (mAudioDecoder != NULL) {
- mAudioDecoder->setRenderer(mRenderer);
- }
-
- startPlaybackTimer("onstart");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
-
- postScanSources();
-}
-
-void NuPlayer2::addEndTimeMonitor() {
- ++mEOSMonitorGeneration;
-
- if (mCurrentSourceInfo.mEndTimeUs == DataSourceDesc::kMaxTimeUs) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatEOSMonitor, this);
- msg->setInt32("generation", mEOSMonitorGeneration);
- mMediaClock->addTimer(msg, mCurrentSourceInfo.mEndTimeUs);
-}
-
-void NuPlayer2::startPlaybackTimer(const char *where) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
- if (mLastStartedPlayingTimeNs == 0) {
- mLastStartedPlayingTimeNs = systemTime();
- ALOGV("startPlaybackTimer() time %20" PRId64 " (%s)", mLastStartedPlayingTimeNs, where);
- }
-}
-
-void NuPlayer2::stopPlaybackTimer(const char *where) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
-
- ALOGV("stopPlaybackTimer() time %20" PRId64 " (%s)", mLastStartedPlayingTimeNs, where);
-
- if (mLastStartedPlayingTimeNs != 0) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int64_t now = systemTime();
- int64_t played = now - mLastStartedPlayingTimeNs;
- ALOGV("stopPlaybackTimer() log %20" PRId64 "", played);
-
- if (played > 0) {
- driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
- }
- }
- mLastStartedPlayingTimeNs = 0;
- }
-}
-
-void NuPlayer2::startRebufferingTimer() {
- Mutex::Autolock autoLock(mPlayingTimeLock);
- if (mLastStartedRebufferingTimeNs == 0) {
- mLastStartedRebufferingTimeNs = systemTime();
- ALOGV("startRebufferingTimer() time %20" PRId64 "", mLastStartedRebufferingTimeNs);
- }
-}
-
-void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
-
- ALOGV("stopRebufferTimer() time %20" PRId64 " (exiting %d)",
- mLastStartedRebufferingTimeNs, exitingPlayback);
-
- if (mLastStartedRebufferingTimeNs != 0) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int64_t now = systemTime();
- int64_t rebuffered = now - mLastStartedRebufferingTimeNs;
- ALOGV("stopRebufferingTimer() log %20" PRId64 "", rebuffered);
-
- if (rebuffered > 0) {
- driver->notifyMoreRebufferingTimeUs(
- mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
- if (exitingPlayback) {
- driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
- }
- }
- }
- mLastStartedRebufferingTimeNs = 0;
- }
-}
-
-void NuPlayer2::onPause() {
-
- stopPlaybackTimer("onPause");
-
- if (mPaused) {
- return;
- }
- mPaused = true;
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->pause();
- } else {
- ALOGW("pause called when source is gone or not set");
- }
- if (mRenderer != NULL) {
- mRenderer->pause();
- } else {
- ALOGW("pause called when renderer is gone or not set");
- }
-
-}
-
-bool NuPlayer2::audioDecoderStillNeeded() {
- // Audio decoder is no longer needed if it's in shut/shutting down status.
- return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER));
-}
-
-void NuPlayer2::handleFlushComplete(bool audio, bool isDecoder) {
- // We wait for both the decoder flush and the renderer flush to complete
- // before entering either the FLUSHED or the SHUTTING_DOWN_DECODER state.
-
- mFlushComplete[audio][isDecoder] = true;
- if (!mFlushComplete[audio][!isDecoder]) {
- return;
- }
-
- FlushStatus *state = audio ? &mFlushingAudio : &mFlushingVideo;
- switch (*state) {
- case FLUSHING_DECODER:
- {
- *state = FLUSHED;
- break;
- }
-
- case FLUSHING_DECODER_SHUTDOWN:
- {
- *state = SHUTTING_DOWN_DECODER;
-
- ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
- getDecoder(audio)->initiateShutdown();
- break;
- }
-
- default:
- // decoder flush completes only occur in a flushing state.
- LOG_ALWAYS_FATAL_IF(isDecoder, "decoder flush in invalid state %d", *state);
- break;
- }
-}
-
-void NuPlayer2::finishFlushIfPossible() {
- if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED
- && mFlushingAudio != SHUT_DOWN) {
- return;
- }
-
- if (mFlushingVideo != NONE && mFlushingVideo != FLUSHED
- && mFlushingVideo != SHUT_DOWN) {
- return;
- }
-
- ALOGV("both audio and video are flushed now.");
-
- mFlushingAudio = NONE;
- mFlushingVideo = NONE;
-
- clearFlushComplete();
-
- processDeferredActions();
-}
-
-void NuPlayer2::postScanSources() {
- if (mScanSourcesPending) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatScanSources, this);
- msg->setInt32("generation", mScanSourcesGeneration);
- msg->post();
-
- mScanSourcesPending = true;
-}
-
-void NuPlayer2::tryOpenAudioSinkForOffload(
- const sp<AMessage> &format, const sp<MetaData> &audioMeta, bool hasVideo) {
- // Note: This is called early in NuPlayer2 to determine whether offloading
- // is possible; otherwise the decoders call the renderer openAudioSink directly.
-
- status_t err = mRenderer->openAudioSink(
- format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
- if (err != OK) {
- // Any failure we turn off mOffloadAudio.
- mOffloadAudio = false;
- } else if (mOffloadAudio) {
- sendMetaDataToHal(mAudioSink, audioMeta);
- }
-}
-
-void NuPlayer2::closeAudioSink() {
- mRenderer->closeAudioSink();
-}
-
-void NuPlayer2::restartAudio(
- int64_t currentPositionUs, bool forceNonOffload, bool needsToCreateAudioDecoder) {
- if (mAudioDecoder != NULL) {
- mAudioDecoder->pause();
- Mutex::Autolock autoLock(mDecoderLock);
- mAudioDecoder.clear();
- mAudioDecoderError = false;
- ++mAudioDecoderGeneration;
- }
- if (mFlushingAudio == FLUSHING_DECODER) {
- mFlushComplete[1 /* audio */][1 /* isDecoder */] = true;
- mFlushingAudio = FLUSHED;
- finishFlushIfPossible();
- } else if (mFlushingAudio == FLUSHING_DECODER_SHUTDOWN
- || mFlushingAudio == SHUTTING_DOWN_DECODER) {
- mFlushComplete[1 /* audio */][1 /* isDecoder */] = true;
- mFlushingAudio = SHUT_DOWN;
- finishFlushIfPossible();
- needsToCreateAudioDecoder = false;
- }
- if (mRenderer == NULL) {
- return;
- }
- closeAudioSink();
- mRenderer->flush(true /* audio */, false /* notifyComplete */);
- if (mVideoDecoder != NULL) {
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_NONE /* audio */,
- FLUSH_CMD_FLUSH /* video */));
- mDeferredActions.push_back(
- new SeekAction(currentPositionUs,
- MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */));
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(new ResumeDecoderAction(false));
- processDeferredActions();
- } else {
- performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
- }
-
- if (forceNonOffload) {
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
- }
- if (needsToCreateAudioDecoder) {
- instantiateDecoder(true /* audio */, &mAudioDecoder, !forceNonOffload);
- }
-}
-
-void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
- if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
- return;
- }
-
- if (mRenderer == NULL) {
- ALOGW("No renderer can be used to determine audio mode. Use non-offload for safety.");
- mOffloadAudio = false;
- return;
- }
-
- sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
- sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
- audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
- const bool hasVideo = (videoFormat != NULL);
- bool canOffload = JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
- && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
-
- // Modular DRM: Disabling audio offload if the source is protected
- if (canOffload && mCurrentSourceInfo.mIsDrmProtected) {
- canOffload = false;
- ALOGV("determineAudioModeChange: Disabling mOffloadAudio b/c the source is protected.");
- }
-
- if (canOffload) {
- if (!mOffloadAudio) {
- mRenderer->signalEnableOffloadAudio();
- }
- // open audio sink early under offload mode.
- tryOpenAudioSinkForOffload(audioFormat, audioMeta, hasVideo);
- } else {
- if (mOffloadAudio) {
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
- }
- }
-}
-
-status_t NuPlayer2::instantiateDecoder(
- bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange) {
- // The audio decoder could be cleared by tear down. If still in shut down
- // process, no need to create a new audio decoder.
- if (*decoder != NULL || (audio && mFlushingAudio == SHUT_DOWN)) {
- return OK;
- }
-
- sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
-
- if (format == NULL) {
- return UNKNOWN_ERROR;
- } else {
- status_t err;
- if (format->findInt32("err", &err) && err) {
- return err;
- }
- }
-
- format->setInt32("priority", 0 /* realtime */);
-
- if (!audio) {
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, this);
- if (mCCDecoder == NULL) {
- mCCDecoder = new CCDecoder(ccNotify);
- }
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
- format->setInt32("secure", true);
- }
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
- format->setInt32("protected", true);
- }
-
- float rate = getFrameRate();
- if (rate > 0) {
- format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
- }
- }
-
- Mutex::Autolock autoLock(mDecoderLock);
-
- if (audio) {
- sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
- ++mAudioDecoderGeneration;
- notify->setInt32("generation", mAudioDecoderGeneration);
-
- if (checkAudioModeChange) {
- determineAudioModeChange(format);
- }
- if (mOffloadAudio) {
- mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
-
- const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
- format->setInt32("has-video", hasVideo);
- *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
- ALOGV("instantiateDecoder audio DecoderPassThrough hasVideo: %d", hasVideo);
- } else {
- mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
-
- *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
- ALOGV("instantiateDecoder audio Decoder");
- }
- mAudioDecoderError = false;
- } else {
- sp<AMessage> notify = new AMessage(kWhatVideoNotify, this);
- ++mVideoDecoderGeneration;
- notify->setInt32("generation", mVideoDecoderGeneration);
-
- *decoder = new Decoder(
- notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
- mCCDecoder);
- mVideoDecoderError = false;
-
- // enable FRC if high-quality AV sync is requested, even if not
- // directly queuing to display, as this will even improve textureview
- // playback.
- {
- if (property_get_bool("persist.sys.media.avsync", false)) {
- format->setInt32("auto-frc", 1);
- }
- }
- }
- (*decoder)->init();
-
- // Modular DRM
- if (mCurrentSourceInfo.mIsDrmProtected) {
- format->setObject("crypto", mCurrentSourceInfo.mCrypto);
- ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
- mCurrentSourceInfo.mCrypto.get(),
- (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
- }
-
- (*decoder)->configure(format);
-
- if (!audio) {
- sp<AMessage> params = new AMessage();
- float rate = getFrameRate();
- if (rate > 0) {
- params->setFloat("frame-rate-total", rate);
- }
-
- sp<MetaData> fileMeta = getFileMeta();
- if (fileMeta != NULL) {
- int32_t videoTemporalLayerCount;
- if (fileMeta->findInt32(kKeyTemporalLayerCount, &videoTemporalLayerCount)
- && videoTemporalLayerCount > 0) {
- params->setInt32("temporal-layer-count", videoTemporalLayerCount);
- }
- }
-
- if (params->countEntries() > 0) {
- (*decoder)->setParameters(params);
- }
- }
- return OK;
-}
-
-void NuPlayer2::updateVideoSize(
- int64_t srcId,
- const sp<AMessage> &inputFormat,
- const sp<AMessage> &outputFormat) {
- if (inputFormat == NULL) {
- ALOGW("Unknown video size, reporting 0x0!");
- notifyListener(srcId, MEDIA2_SET_VIDEO_SIZE, 0, 0);
- return;
- }
- int32_t err = OK;
- inputFormat->findInt32("err", &err);
- if (err == -EWOULDBLOCK) {
- ALOGW("Video meta is not available yet!");
- return;
- }
- if (err != OK) {
- ALOGW("Something is wrong with video meta!");
- return;
- }
-
- int32_t displayWidth, displayHeight;
- if (outputFormat != NULL) {
- int32_t width, height;
- CHECK(outputFormat->findInt32("width", &width));
- CHECK(outputFormat->findInt32("height", &height));
-
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- CHECK(outputFormat->findRect(
- "crop",
- &cropLeft, &cropTop, &cropRight, &cropBottom));
-
- displayWidth = cropRight - cropLeft + 1;
- displayHeight = cropBottom - cropTop + 1;
-
- ALOGV("Video output format changed to %d x %d "
- "(crop: %d x %d @ (%d, %d))",
- width, height,
- displayWidth,
- displayHeight,
- cropLeft, cropTop);
- } else {
- CHECK(inputFormat->findInt32("width", &displayWidth));
- CHECK(inputFormat->findInt32("height", &displayHeight));
-
- ALOGV("Video input format %d x %d", displayWidth, displayHeight);
- }
-
- // Take into account sample aspect ratio if necessary:
- int32_t sarWidth, sarHeight;
- if (inputFormat->findInt32("sar-width", &sarWidth)
- && inputFormat->findInt32("sar-height", &sarHeight)
- && sarWidth > 0 && sarHeight > 0) {
- ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight);
-
- displayWidth = (displayWidth * sarWidth) / sarHeight;
-
- ALOGV("display dimensions %d x %d", displayWidth, displayHeight);
- } else {
- int32_t width, height;
- if (inputFormat->findInt32("display-width", &width)
- && inputFormat->findInt32("display-height", &height)
- && width > 0 && height > 0
- && displayWidth > 0 && displayHeight > 0) {
- if (displayHeight * (int64_t)width / height > (int64_t)displayWidth) {
- displayHeight = (int32_t)(displayWidth * (int64_t)height / width);
- } else {
- displayWidth = (int32_t)(displayHeight * (int64_t)width / height);
- }
- ALOGV("Video display width and height are overridden to %d x %d",
- displayWidth, displayHeight);
- }
- }
-
- int32_t rotationDegrees;
- if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- if (rotationDegrees == 90 || rotationDegrees == 270) {
- int32_t tmp = displayWidth;
- displayWidth = displayHeight;
- displayHeight = tmp;
- }
-
- notifyListener(
- srcId,
- MEDIA2_SET_VIDEO_SIZE,
- displayWidth,
- displayHeight);
-}
-
-void NuPlayer2::notifyListener(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- if (mDriver == NULL) {
- return;
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
-
- if (driver == NULL) {
- return;
- }
-
- driver->notifyListener(srcId, msg, ext1, ext2, in);
-}
-
-void NuPlayer2::flushDecoder(bool audio, bool needShutdown) {
- ALOGV("[%s] flushDecoder needShutdown=%d",
- audio ? "audio" : "video", needShutdown);
-
- const sp<DecoderBase> &decoder = getDecoder(audio);
- if (decoder == NULL) {
- ALOGI("flushDecoder %s without decoder present",
- audio ? "audio" : "video");
- return;
- }
-
- // Make sure we don't continue to scan sources until we finish flushing.
- ++mScanSourcesGeneration;
- if (mScanSourcesPending) {
- if (!needShutdown) {
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
- }
- mScanSourcesPending = false;
- }
-
- decoder->signalFlush();
-
- FlushStatus newStatus =
- needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
-
- mFlushComplete[audio][false /* isDecoder */] = (mRenderer == NULL);
- mFlushComplete[audio][true /* isDecoder */] = false;
- if (audio) {
- ALOGE_IF(mFlushingAudio != NONE,
- "audio flushDecoder() is called in state %d", mFlushingAudio);
- mFlushingAudio = newStatus;
- } else {
- ALOGE_IF(mFlushingVideo != NONE,
- "video flushDecoder() is called in state %d", mFlushingVideo);
- mFlushingVideo = newStatus;
- }
-}
-
-void NuPlayer2::queueDecoderShutdown(
- bool audio, bool video, const sp<AMessage> &reply) {
- ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- video ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
-
- mDeferredActions.push_back(new PostMessageAction(reply));
-
- processDeferredActions();
-}
-
-status_t NuPlayer2::setVideoScalingMode(int32_t mode) {
- mVideoScalingMode = mode;
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- status_t ret = native_window_set_scaling_mode(
- mNativeWindow->getANativeWindow(), mVideoScalingMode);
- if (ret != OK) {
- ALOGE("Failed to set scaling mode (%d): %s",
- -ret, strerror(-ret));
- return ret;
- }
- }
- return OK;
-}
-
-status_t NuPlayer2::getTrackInfo(int64_t srcId, PlayerMessage* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
- msg->setInt64("srcId", srcId);
- msg->setPointer("reply", reply);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- return err;
-}
-
-status_t NuPlayer2::getSelectedTrack(int64_t srcId, int32_t type, PlayerMessage* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
- msg->setPointer("reply", reply);
- msg->setInt64("srcId", srcId);
- msg->setInt32("type", type);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::selectTrack(int64_t srcId, size_t trackIndex, bool select, int64_t timeUs) {
- sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
- msg->setInt64("srcId", srcId);
- msg->setSize("trackIndex", trackIndex);
- msg->setInt32("select", select);
- msg->setInt64("timeUs", timeUs);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
-
- if (err != OK) {
- return err;
- }
-
- if (!response->findInt32("err", &err)) {
- err = OK;
- }
-
- return err;
-}
-
-status_t NuPlayer2::getCurrentPosition(int64_t *mediaUs) {
- sp<Renderer> renderer = mRenderer;
- if (renderer == NULL) {
- return NO_INIT;
- }
-
- return renderer->getCurrentPosition(mediaUs);
-}
-
-void NuPlayer2::getStats(Vector<sp<AMessage> > *mTrackStats) {
- CHECK(mTrackStats != NULL);
-
- mTrackStats->clear();
-
- Mutex::Autolock autoLock(mDecoderLock);
- if (mVideoDecoder != NULL) {
- mTrackStats->push_back(mVideoDecoder->getStats());
- }
- if (mAudioDecoder != NULL) {
- mTrackStats->push_back(mAudioDecoder->getStats());
- }
-}
-
-sp<MetaData> NuPlayer2::getFileMeta() {
- return mCurrentSourceInfo.mSource->getFileFormatMeta();
-}
-
-float NuPlayer2::getFrameRate() {
- sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
- if (meta == NULL) {
- return 0;
- }
- int32_t rate;
- if (!meta->findInt32(kKeyFrameRate, &rate)) {
- // fall back to try file meta
- sp<MetaData> fileMeta = getFileMeta();
- if (fileMeta == NULL) {
- ALOGW("source has video meta but not file meta");
- return -1;
- }
- int32_t fileMetaRate;
- if (!fileMeta->findInt32(kKeyFrameRate, &fileMetaRate)) {
- return -1;
- }
- return fileMetaRate;
- }
- return rate;
-}
-
-void NuPlayer2::schedulePollDuration() {
- sp<AMessage> msg = new AMessage(kWhatPollDuration, this);
- msg->setInt32("generation", mPollDurationGeneration);
- msg->post();
-}
-
-void NuPlayer2::cancelPollDuration() {
- ++mPollDurationGeneration;
-}
-
-void NuPlayer2::processDeferredActions() {
- while (!mDeferredActions.empty()) {
- // We won't execute any deferred actions until we're no longer in
- // an intermediate state, i.e. one more more decoders are currently
- // flushing or shutting down.
-
- if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
- // We're currently flushing, postpone the reset until that's
- // completed.
-
- ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d",
- mFlushingAudio, mFlushingVideo);
-
- break;
- }
-
- sp<Action> action = *mDeferredActions.begin();
- mDeferredActions.erase(mDeferredActions.begin());
-
- action->execute(this);
- }
-}
-
-void NuPlayer2::performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
- (long long)seekTimeUs, seekTimeUs / 1E6, mode);
-
- if (mCurrentSourceInfo.mSource == NULL) {
- // This happens when reset occurs right before the loop mode
- // asynchronously seeks to the start of the stream.
- LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
- "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
- mAudioDecoder.get(), mVideoDecoder.get());
- return;
- }
- mPreviousSeekTimeUs = seekTimeUs;
- mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
- ++mTimedTextGeneration;
-
- // everything's flushed, continue playback.
-}
-
-void NuPlayer2::performDecoderFlush(FlushCommand audio, FlushCommand video) {
- ALOGV("performDecoderFlush audio=%d, video=%d", audio, video);
-
- if ((audio == FLUSH_CMD_NONE || mAudioDecoder == NULL)
- && (video == FLUSH_CMD_NONE || mVideoDecoder == NULL)) {
- return;
- }
-
- if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) {
- flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN));
- }
-
- if (video != FLUSH_CMD_NONE && mVideoDecoder != NULL) {
- flushDecoder(false /* audio */, (video == FLUSH_CMD_SHUTDOWN));
- }
-}
-
-void NuPlayer2::performReset() {
- ALOGV("performReset");
-
- CHECK(mAudioDecoder == NULL);
- CHECK(mVideoDecoder == NULL);
-
- stopPlaybackTimer("performReset");
- stopRebufferingTimer(true);
-
- cancelPollDuration();
-
- ++mScanSourcesGeneration;
- mScanSourcesPending = false;
-
- if (mRendererLooper != NULL) {
- if (mRenderer != NULL) {
- mRendererLooper->unregisterHandler(mRenderer->id());
- }
- mRendererLooper->stop();
- mRendererLooper.clear();
- }
- mRenderer.clear();
- ++mRendererGeneration;
-
- resetSourceInfo(mCurrentSourceInfo);
- resetSourceInfo(mNextSourceInfo);
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
- }
- }
-
- mStarted = false;
- mPrepared = false;
- mResetting = false;
- mSourceStarted = false;
-
-}
-
-void NuPlayer2::performPlayNextDataSource() {
- ALOGV("performPlayNextDataSource");
-
- CHECK(mAudioDecoder == NULL);
- CHECK(mVideoDecoder == NULL);
-
- stopPlaybackTimer("performPlayNextDataSource");
- stopRebufferingTimer(true);
-
- cancelPollDuration();
-
- ++mScanSourcesGeneration;
- mScanSourcesPending = false;
-
- ++mRendererGeneration;
-
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->stop();
- }
-
- long previousSrcId;
- {
- Mutex::Autolock autoLock(mSourceLock);
- previousSrcId = mCurrentSourceInfo.mSrcId;
-
- mCurrentSourceInfo = mNextSourceInfo;
- mNextSourceInfo = SourceInfo();
- mNextSourceInfo.mSrcId = ~mCurrentSourceInfo.mSrcId; // to distinguish the two sources.
- }
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
-
- int64_t durationUs;
- if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
- }
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
- }
- }
-
- mStarted = false;
- mPrepared = true; // TODO: what if it's not prepared
- mResetting = false;
- mSourceStarted = false;
-
- addEndTimeMonitor();
-
- if (mRenderer != NULL) {
- mRenderer->resume();
- }
-
- onStart(true /* play */);
- mPausedByClient = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
-}
-
-void NuPlayer2::performScanSources() {
- ALOGV("performScanSources");
-
- if (!mStarted) {
- return;
- }
-
- if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
- postScanSources();
- }
-}
-
-void NuPlayer2::performSetSurface(const sp<ANativeWindowWrapper> &nww) {
- ALOGV("performSetSurface");
-
- mNativeWindow = nww;
-
- // XXX - ignore error from setVideoScalingMode for now
- setVideoScalingMode(mVideoScalingMode);
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
- }
- }
-}
-
-void NuPlayer2::performResumeDecoders(bool needNotify) {
- if (needNotify) {
- mResumePending = true;
- if (mVideoDecoder == NULL) {
- // if audio-only, we can notify seek complete now,
- // as the resume operation will be relatively fast.
- finishResume();
- }
- }
-
- if (mVideoDecoder != NULL) {
- // When there is continuous seek, MediaPlayer will cache the seek
- // position, and send down new seek request when previous seek is
- // complete. Let's wait for at least one video output frame before
- // notifying seek complete, so that the video thumbnail gets updated
- // when seekbar is dragged.
- mVideoDecoder->signalResume(needNotify);
- }
-
- if (mAudioDecoder != NULL) {
- mAudioDecoder->signalResume(false /* needNotify */);
- }
-}
-
-void NuPlayer2::finishResume() {
- if (mResumePending) {
- mResumePending = false;
- notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
- }
-}
-
-void NuPlayer2::notifyDriverSeekComplete(int64_t srcId) {
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySeekComplete(srcId);
- }
- }
-}
-
-void NuPlayer2::onSourceNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- switch (what) {
- case Source::kWhatPrepared:
- {
- ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source:%p, Id(%lld)",
- mCurrentSourceInfo.mSource.get(), (long long)srcId);
- if (srcId == mCurrentSourceInfo.mSrcId) {
- if (mCurrentSourceInfo.mSource == NULL) {
- // This is a stale notification from a source that was
- // asynchronously preparing when the client called reset().
- // We handled the reset, the source is gone.
- break;
- }
-
- int32_t err;
- CHECK(msg->findInt32("err", &err));
-
- if (err != OK) {
- // shut down potential secure codecs in case client never calls reset
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
- processDeferredActions();
- } else {
- mPrepared = true;
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- // notify duration first, so that it's definitely set when
- // the app received the "prepare complete" callback.
- int64_t durationUs;
- if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(srcId, durationUs);
- }
- driver->notifyPrepareCompleted(srcId, err);
- }
- } else if (srcId == mNextSourceInfo.mSrcId) {
- if (mNextSourceInfo.mSource == NULL) {
- break; // stale
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int32_t err;
- CHECK(msg->findInt32("err", &err));
- driver->notifyPrepareCompleted(srcId, err);
- }
- }
-
- break;
- }
-
- // Modular DRM
- case Source::kWhatDrmInfo:
- {
- PlayerMessage playerMsg;
- sp<ABuffer> drmInfo;
- CHECK(msg->findBuffer("drmInfo", &drmInfo));
- playerMsg.ParseFromArray(drmInfo->data(), drmInfo->size());
-
- ALOGV("onSourceNotify() kWhatDrmInfo MEDIA2_DRM_INFO drmInfo: %p playerMsg size: %d",
- drmInfo.get(), playerMsg.ByteSize());
-
- notifyListener(srcId, MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &playerMsg);
-
- break;
- }
-
- case Source::kWhatFlagsChanged:
- {
- uint32_t flags;
- CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
-
- ALOGV("onSourceNotify() kWhatFlagsChanged FLAG_CAN_PAUSE: %d "
- "FLAG_CAN_SEEK_BACKWARD: %d \n\t\t\t\t FLAG_CAN_SEEK_FORWARD: %d "
- "FLAG_CAN_SEEK: %d FLAG_DYNAMIC_DURATION: %d \n"
- "\t\t\t\t FLAG_SECURE: %d FLAG_PROTECTED: %d",
- (flags & Source::FLAG_CAN_PAUSE) != 0,
- (flags & Source::FLAG_CAN_SEEK_BACKWARD) != 0,
- (flags & Source::FLAG_CAN_SEEK_FORWARD) != 0,
- (flags & Source::FLAG_CAN_SEEK) != 0,
- (flags & Source::FLAG_DYNAMIC_DURATION) != 0,
- (flags & Source::FLAG_SECURE) != 0,
- (flags & Source::FLAG_PROTECTED) != 0);
-
- if ((flags & NuPlayer2::Source::FLAG_CAN_SEEK) == 0) {
- driver->notifyListener(
- srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
- }
- if (srcId == mCurrentSourceInfo.mSrcId) {
- driver->notifyFlagsChanged(srcId, flags);
- }
- }
-
- if (srcId == mCurrentSourceInfo.mSrcId) {
- if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
- cancelPollDuration();
- } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (flags & Source::FLAG_DYNAMIC_DURATION)
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- schedulePollDuration();
- }
-
- mCurrentSourceInfo.mSourceFlags = flags;
- } else if (srcId == mNextSourceInfo.mSrcId) {
- // TODO: handle duration polling for next source.
- mNextSourceInfo.mSourceFlags = flags;
- }
- break;
- }
-
- case Source::kWhatVideoSizeChanged:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- updateVideoSize(srcId, format);
- break;
- }
-
- case Source::kWhatBufferingUpdate:
- {
- int32_t percentage;
- CHECK(msg->findInt32("percentage", &percentage));
-
- notifyListener(srcId, MEDIA2_BUFFERING_UPDATE, percentage, 0);
- break;
- }
-
- case Source::kWhatPauseOnBufferingStart:
- {
- // ignore if not playing
- if (mStarted) {
- ALOGI("buffer low, pausing...");
-
- startRebufferingTimer();
- mPausedForBuffering = true;
- onPause();
- }
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_START, 0);
- break;
- }
-
- case Source::kWhatResumeOnBufferingEnd:
- {
- // ignore if not playing
- if (mStarted) {
- ALOGI("buffer ready, resuming...");
-
- stopRebufferingTimer(false);
- mPausedForBuffering = false;
-
- // do not resume yet if client didn't unpause
- if (!mPausedByClient) {
- onResume();
- }
- }
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_END, 0);
- break;
- }
-
- case Source::kWhatCacheStats:
- {
- int32_t kbps;
- CHECK(msg->findInt32("bandwidth", &kbps));
-
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_NETWORK_BANDWIDTH, kbps);
- break;
- }
-
- case Source::kWhatSubtitleData:
- {
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- sendSubtitleData(buffer, 0 /* baseIndex */);
- break;
- }
-
- case Source::kWhatTimedMetaData:
- {
- sp<ABuffer> buffer;
- if (!msg->findBuffer("buffer", &buffer)) {
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
- } else {
- sendTimedMetaData(buffer);
- }
- break;
- }
-
- case Source::kWhatTimedTextData:
- {
- int32_t generation;
- if (msg->findInt32("generation", &generation)
- && generation != mTimedTextGeneration) {
- break;
- }
-
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver == NULL) {
- break;
- }
-
- int64_t posMs;
- int64_t timeUs, posUs;
- driver->getCurrentPosition(&posMs);
- posUs = posMs * 1000LL;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- if (posUs < timeUs) {
- if (!msg->findInt32("generation", &generation)) {
- msg->setInt32("generation", mTimedTextGeneration);
- }
- msg->post(timeUs - posUs);
- } else {
- sendTimedTextData(buffer);
- }
- break;
- }
-
- case Source::kWhatQueueDecoderShutdown:
- {
- int32_t audio, video;
- CHECK(msg->findInt32("audio", &audio));
- CHECK(msg->findInt32("video", &video));
-
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
-
- queueDecoderShutdown(audio, video, reply);
- break;
- }
-
- case Source::kWhatDrmNoLicense:
- {
- notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-void NuPlayer2::onClosedCaptionNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case NuPlayer2::CCDecoder::kWhatClosedCaptionData:
- {
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
-
- sendSubtitleData(buffer, inbandTracks);
- break;
- }
-
- case NuPlayer2::CCDecoder::kWhatTrackAdded:
- {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
-
- break;
- }
-
- default:
- TRESPASS();
- }
-
-
-}
-
-void NuPlayer2::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) {
- int32_t trackIndex;
- int64_t timeUs, durationUs;
- CHECK(buffer->meta()->findInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, &trackIndex));
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
-
- PlayerMessage playerMsg;
- playerMsg.add_values()->set_int32_value(trackIndex + baseIndex);
- playerMsg.add_values()->set_int64_value(timeUs);
- playerMsg.add_values()->set_int64_value(durationUs);
- playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
-}
-
-void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
- int64_t timeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- PlayerMessage playerMsg;
- playerMsg.add_values()->set_int64_value(timeUs);
- playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
-}
-
-void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
- const void *data;
- size_t size = 0;
- int64_t timeUs;
- int32_t flag = TextDescriptions2::IN_BAND_TEXT_3GPP;
-
- AString mime;
- CHECK(buffer->meta()->findString("mime", &mime));
- CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0);
-
- data = buffer->data();
- size = buffer->size();
-
- PlayerMessage playerMsg;
- if (size > 0) {
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- int32_t global = 0;
- if (buffer->meta()->findInt32("global", &global) && global) {
- flag |= TextDescriptions2::GLOBAL_DESCRIPTIONS;
- } else {
- flag |= TextDescriptions2::LOCAL_DESCRIPTIONS;
- }
- TextDescriptions2::getPlayerMessageOfDescriptions(
- (const uint8_t *)data, size, flag, timeUs / 1000, &playerMsg);
- }
-
- if (playerMsg.values_size() > 0) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
- } else { // send an empty timed text
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
- }
-}
-
-const char *NuPlayer2::getDataSourceType() {
- switch (mCurrentSourceInfo.mDataSourceType) {
- case DATA_SOURCE_TYPE_HTTP_LIVE:
- return "HTTPLive";
-
- case DATA_SOURCE_TYPE_RTSP:
- return "RTSP";
-
- case DATA_SOURCE_TYPE_GENERIC_URL:
- return "GenURL";
-
- case DATA_SOURCE_TYPE_GENERIC_FD:
- return "GenFD";
-
- case DATA_SOURCE_TYPE_MEDIA:
- return "Media";
-
- case DATA_SOURCE_TYPE_NONE:
- default:
- return "None";
- }
- }
-
-NuPlayer2::SourceInfo* NuPlayer2::getSourceInfoByIdInMsg(const sp<AMessage> &msg) {
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- if (mCurrentSourceInfo.mSrcId == srcId) {
- return &mCurrentSourceInfo;
- } else if (mNextSourceInfo.mSrcId == srcId) {
- return &mNextSourceInfo;
- } else {
- return NULL;
- }
-}
-
-void NuPlayer2::resetSourceInfo(NuPlayer2::SourceInfo &srcInfo) {
- if (srcInfo.mSource != NULL) {
- srcInfo.mSource->stop();
-
- Mutex::Autolock autoLock(mSourceLock);
- srcInfo.mSource.clear();
- }
- // Modular DRM
- ALOGD("performReset mCrypto: %p", srcInfo.mCrypto.get());
- srcInfo.mCrypto.clear();
- srcInfo.mIsDrmProtected = false;
-}
-
-// Modular DRM begin
-status_t NuPlayer2::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
-{
- ALOGV("prepareDrm ");
-
- // Passing to the looper anyway; called in a pre-config prepared state so no race on mCrypto
- sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
- // synchronous call so just passing the address but with local copies of "const" args
- uint8_t UUID[16];
- memcpy(UUID, uuid, sizeof(UUID));
- Vector<uint8_t> sessionId = drmSessionId;
- msg->setInt64("srcId", srcId);
- msg->setPointer("uuid", (void*)UUID);
- msg->setPointer("drmSessionId", (void*)&sessionId);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer2::releaseDrm(int64_t srcId)
-{
- ALOGV("releaseDrm ");
-
- sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
- msg->setInt64("srcId", srcId);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("releaseDrm ret: %d ", status);
- } else {
- ALOGE("releaseDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer2::onPrepareDrm(const sp<AMessage> &msg)
-{
- // TODO change to ALOGV
- ALOGD("onPrepareDrm ");
-
- status_t status = INVALID_OPERATION;
- SourceInfo *srcInfo = getSourceInfoByIdInMsg(msg);
- if (srcInfo == NULL) {
- return status;
- }
-
- int64_t srcId = srcInfo->mSrcId;
- if (srcInfo->mSource == NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld) No source. onPrepareDrm failed with %d.",
- (long long)srcId, status);
- return status;
- }
-
- uint8_t *uuid;
- Vector<uint8_t> *drmSessionId;
- CHECK(msg->findPointer("uuid", (void**)&uuid));
- CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
-
- status = OK;
- sp<AMediaCryptoWrapper> crypto = NULL;
-
- status = srcInfo->mSource->prepareDrm(uuid, *drmSessionId, &crypto);
- if (crypto == NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld).mSource->prepareDrm failed. status: %d",
- (long long)srcId, status);
- return status;
- }
- ALOGV("onPrepareDrm: srcInfo(%lld).mSource->prepareDrm succeeded", (long long)srcId);
-
- if (srcInfo->mCrypto != NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld) Unexpected. Already having mCrypto: %p",
- (long long)srcId, srcInfo->mCrypto.get());
- srcInfo->mCrypto.clear();
- }
-
- srcInfo->mCrypto = crypto;
- srcInfo->mIsDrmProtected = true;
- // TODO change to ALOGV
- ALOGD("onPrepareDrm: mCrypto: %p", srcInfo->mCrypto.get());
-
- return status;
-}
-
-status_t NuPlayer2::onReleaseDrm(const sp<AMessage> &msg)
-{
- // TODO change to ALOGV
- ALOGD("onReleaseDrm ");
- SourceInfo *srcInfo = getSourceInfoByIdInMsg(msg);;
- if (srcInfo == NULL) {
- return INVALID_OPERATION;
- }
-
- int64_t srcId = srcInfo->mSrcId;
- if (!srcInfo->mIsDrmProtected) {
- ALOGW("onReleaseDrm: srcInfo(%lld) Unexpected. mIsDrmProtected is already false.",
- (long long)srcId);
- }
-
- srcInfo->mIsDrmProtected = false;
-
- status_t status;
- if (srcInfo->mCrypto != NULL) {
- // notifying the source first before removing crypto from codec
- if (srcInfo->mSource != NULL) {
- srcInfo->mSource->releaseDrm();
- }
-
- status=OK;
- // first making sure the codecs have released their crypto reference
- const sp<DecoderBase> &videoDecoder = getDecoder(false/*audio*/);
- if (videoDecoder != NULL) {
- status = videoDecoder->releaseCrypto();
- ALOGV("onReleaseDrm: video decoder ret: %d", status);
- }
-
- const sp<DecoderBase> &audioDecoder = getDecoder(true/*audio*/);
- if (audioDecoder != NULL) {
- status_t status_audio = audioDecoder->releaseCrypto();
- if (status == OK) { // otherwise, returning the first error
- status = status_audio;
- }
- ALOGV("onReleaseDrm: audio decoder ret: %d", status_audio);
- }
-
- // TODO change to ALOGV
- ALOGD("onReleaseDrm: mCrypto: %p", srcInfo->mCrypto.get());
- srcInfo->mCrypto.clear();
- } else { // srcInfo->mCrypto == NULL
- ALOGE("onReleaseDrm: Unexpected. There is no crypto.");
- status = INVALID_OPERATION;
- }
-
- return status;
-}
-// Modular DRM end
-////////////////////////////////////////////////////////////////////////////////
-
-sp<AMessage> NuPlayer2::Source::getFormat(bool audio) {
- sp<MetaData> meta = getFormatMeta(audio);
-
- if (meta == NULL) {
- return NULL;
- }
-
- sp<AMessage> msg = new AMessage;
-
- if(convertMetaDataToMessage(meta, &msg) == OK) {
- return msg;
- }
- return NULL;
-}
-
-void NuPlayer2::Source::notifyFlagsChanged(uint32_t flags) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatFlagsChanged);
- notify->setInt32("flags", flags);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyVideoSizeChanged(const sp<AMessage> &format) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatVideoSizeChanged);
- notify->setMessage("format", format);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyPrepared(status_t err) {
- ALOGV("Source::notifyPrepared %d", err);
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPrepared);
- notify->setInt32("err", err);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyDrmInfo(const sp<ABuffer> &drmInfoBuffer)
-{
- ALOGV("Source::notifyDrmInfo");
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatDrmInfo);
- notify->setBuffer("drmInfo", drmInfoBuffer);
-
- notify->post();
-}
-
-void NuPlayer2::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
- TRESPASS();
-}
-
-NuPlayer2::SourceInfo::SourceInfo()
- : mDataSourceType(DATA_SOURCE_TYPE_NONE),
- mSrcId(0),
- mSourceFlags(0),
- mStartTimeUs(0),
- mEndTimeUs(DataSourceDesc::kMaxTimeUs) {
-}
-
-NuPlayer2::SourceInfo & NuPlayer2::SourceInfo::operator=(const NuPlayer2::SourceInfo &other) {
- mSource = other.mSource;
- mCrypto = other.mCrypto;
- mDataSourceType = (DATA_SOURCE_TYPE)other.mDataSourceType;
- mSrcId = other.mSrcId;
- mSourceFlags = other.mSourceFlags;
- mStartTimeUs = other.mStartTimeUs;
- mEndTimeUs = other.mEndTimeUs;
- mIsDrmProtected = other.mIsDrmProtected;
- return *this;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
deleted file mode 100644
index b8fb988..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NU_PLAYER2_H_
-
-#define NU_PLAYER2_H_
-
-#include <media/AudioResamplerPublic.h>
-#include <media/stagefright/foundation/AHandler.h>
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
-struct ABuffer;
-struct AMediaCryptoWrapper;
-struct AMessage;
-struct ANativeWindowWrapper;
-struct AudioPlaybackRate;
-struct AVSyncSettings;
-struct DataSourceDesc;
-struct MediaClock;
-struct MediaHTTPService;
-class MetaData;
-struct NuPlayer2Driver;
-
-struct NuPlayer2 : public AHandler {
- explicit NuPlayer2(pid_t pid, uid_t uid,
- const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context);
-
- void setDriver(const wp<NuPlayer2Driver> &driver);
-
- void setDataSourceAsync(const sp<DataSourceDesc> &dsd);
- void prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd);
- void playNextDataSource(int64_t srcId);
-
- status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings& buffering);
-
- void prepareAsync();
-
- void setVideoSurfaceTextureAsync(const sp<ANativeWindowWrapper> &nww);
-
- void setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink);
- status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
- status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void start();
-
- void pause();
-
- // Will notify the driver through "notifyResetComplete" once finished.
- void resetAsync();
-
- // Request a notification when specified media time is reached.
- status_t notifyAt(int64_t mediaTimeUs);
-
- // Will notify the driver through "notifySeekComplete" once finished
- // and needNotify is true.
- void seekToAsync(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
- bool needNotify = false);
- void rewind();
-
- status_t setVideoScalingMode(int32_t mode);
- status_t getTrackInfo(int64_t srcId, PlayerMessage* reply) const;
- status_t getSelectedTrack(int64_t srcId, int32_t type, PlayerMessage* reply) const;
- status_t selectTrack(int64_t srcId, size_t trackIndex, bool select, int64_t timeUs);
- status_t getCurrentPosition(int64_t *mediaUs);
- void getStats(Vector<sp<AMessage> > *mTrackStats);
-
- sp<MetaData> getFileMeta();
- float getFrameRate();
-
- // Modular DRM
- status_t prepareDrm(int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
- status_t releaseDrm(int64_t srcId);
-
- const char *getDataSourceType();
-
-protected:
- virtual ~NuPlayer2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-public:
- struct StreamListener;
- struct Source;
-
-private:
- struct Decoder;
- struct DecoderBase;
- struct DecoderPassThrough;
- struct CCDecoder;
- struct GenericSource2;
- struct HTTPLiveSource2;
- struct Renderer;
- struct RTSPSource2;
- struct Action;
- struct SeekAction;
- struct SetSurfaceAction;
- struct ResumeDecoderAction;
- struct FlushDecoderAction;
- struct PostMessageAction;
- struct SimpleAction;
-
- enum {
- kWhatSetDataSource = '=DaS',
- kWhatPrepare = 'prep',
- kWhatPrepareNextDataSource = 'pNDS',
- kWhatPlayNextDataSource = 'plNS',
- kWhatSetVideoSurface = '=VSu',
- kWhatSetAudioSink = '=AuS',
- kWhatMoreDataQueued = 'more',
- kWhatConfigPlayback = 'cfPB',
- kWhatConfigSync = 'cfSy',
- kWhatGetPlaybackSettings = 'gPbS',
- kWhatGetSyncSettings = 'gSyS',
- kWhatStart = 'strt',
- kWhatScanSources = 'scan',
- kWhatVideoNotify = 'vidN',
- kWhatAudioNotify = 'audN',
- kWhatClosedCaptionNotify = 'capN',
- kWhatRendererNotify = 'renN',
- kWhatReset = 'rset',
- kWhatNotifyTime = 'nfyT',
- kWhatSeek = 'seek',
- kWhatPause = 'paus',
- kWhatResume = 'rsme',
- kWhatPollDuration = 'polD',
- kWhatSourceNotify = 'srcN',
- kWhatGetTrackInfo = 'gTrI',
- kWhatGetSelectedTrack = 'gSel',
- kWhatSelectTrack = 'selT',
- kWhatGetBufferingSettings = 'gBus',
- kWhatSetBufferingSettings = 'sBuS',
- kWhatPrepareDrm = 'pDrm',
- kWhatReleaseDrm = 'rDrm',
- kWhatRewind = 'reWd',
- kWhatEOSMonitor = 'eosM',
- };
-
- typedef enum {
- DATA_SOURCE_TYPE_NONE,
- DATA_SOURCE_TYPE_HTTP_LIVE,
- DATA_SOURCE_TYPE_RTSP,
- DATA_SOURCE_TYPE_GENERIC_URL,
- DATA_SOURCE_TYPE_GENERIC_FD,
- DATA_SOURCE_TYPE_MEDIA,
- } DATA_SOURCE_TYPE;
-
- struct SourceInfo {
- SourceInfo();
- SourceInfo &operator=(const SourceInfo &);
-
- sp<Source> mSource;
- std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
- int64_t mSrcId;
- uint32_t mSourceFlags;
- int64_t mStartTimeUs;
- int64_t mEndTimeUs;
- // Modular DRM
- sp<AMediaCryptoWrapper> mCrypto;
- bool mIsDrmProtected = false;
- };
-
- wp<NuPlayer2Driver> mDriver;
- pid_t mPID;
- uid_t mUID;
- const sp<MediaClock> mMediaClock;
- Mutex mSourceLock; // guard |mSource|.
- SourceInfo mCurrentSourceInfo;
- SourceInfo mNextSourceInfo;
- sp<ANativeWindowWrapper> mNativeWindow;
- sp<MediaPlayer2Interface::AudioSink> mAudioSink;
- sp<DecoderBase> mVideoDecoder;
- bool mOffloadAudio;
- sp<DecoderBase> mAudioDecoder;
- Mutex mDecoderLock; // guard |mAudioDecoder| and |mVideoDecoder|.
- sp<CCDecoder> mCCDecoder;
- sp<Renderer> mRenderer;
- sp<ALooper> mRendererLooper;
- int32_t mAudioDecoderGeneration;
- int32_t mVideoDecoderGeneration;
- int32_t mRendererGeneration;
- int32_t mEOSMonitorGeneration;
-
- Mutex mPlayingTimeLock;
- int64_t mLastStartedPlayingTimeNs;
- void stopPlaybackTimer(const char *where);
- void startPlaybackTimer(const char *where);
-
- int64_t mLastStartedRebufferingTimeNs;
- void startRebufferingTimer();
- void stopRebufferingTimer(bool exitingPlayback);
-
- int64_t mPreviousSeekTimeUs;
-
- List<sp<Action> > mDeferredActions;
-
- bool mAudioEOS;
- bool mVideoEOS;
-
- bool mScanSourcesPending;
- int32_t mScanSourcesGeneration;
-
- int32_t mPollDurationGeneration;
- int32_t mTimedTextGeneration;
-
- enum FlushStatus {
- NONE,
- FLUSHING_DECODER,
- FLUSHING_DECODER_SHUTDOWN,
- SHUTTING_DOWN_DECODER,
- FLUSHED,
- SHUT_DOWN,
- };
-
- enum FlushCommand {
- FLUSH_CMD_NONE,
- FLUSH_CMD_FLUSH,
- FLUSH_CMD_SHUTDOWN,
- };
-
- // Status of flush responses from the decoder and renderer.
- bool mFlushComplete[2][2];
-
- FlushStatus mFlushingAudio;
- FlushStatus mFlushingVideo;
-
- // Status of flush responses from the decoder and renderer.
- bool mResumePending;
-
- int32_t mVideoScalingMode;
-
- AudioPlaybackRate mPlaybackSettings;
- AVSyncSettings mSyncSettings;
- float mVideoFpsHint;
- bool mStarted;
- bool mPrepared;
- bool mResetting;
- bool mSourceStarted;
- bool mAudioDecoderError;
- bool mVideoDecoderError;
-
- // Actual pause state, either as requested by client or due to buffering.
- bool mPaused;
-
- // Pause state as requested by client. Note that if mPausedByClient is
- // true, mPaused is always true; if mPausedByClient is false, mPaused could
- // still become true, when we pause internally due to buffering.
- bool mPausedByClient;
-
- // Pause state as requested by source (internally) due to buffering
- bool mPausedForBuffering;
-
- // Passed from JAVA
- const sp<JObjectHolder> mContext;
-
- inline const sp<DecoderBase> &getDecoder(bool audio) {
- return audio ? mAudioDecoder : mVideoDecoder;
- }
-
- inline void clearFlushComplete() {
- mFlushComplete[0][0] = false;
- mFlushComplete[0][1] = false;
- mFlushComplete[1][0] = false;
- mFlushComplete[1][1] = false;
- }
-
- void disconnectSource();
-
- status_t createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
- sp<Source> *source,
- DATA_SOURCE_TYPE *dataSourceType);
-
- void tryOpenAudioSinkForOffload(
- const sp<AMessage> &format, const sp<MetaData> &audioMeta, bool hasVideo);
- void closeAudioSink();
- void restartAudio(
- int64_t currentPositionUs, bool forceNonOffload, bool needsToCreateAudioDecoder);
- void determineAudioModeChange(const sp<AMessage> &audioFormat);
-
- status_t instantiateDecoder(
- bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange = true);
-
- void updateVideoSize(
- int64_t srcId,
- const sp<AMessage> &inputFormat,
- const sp<AMessage> &outputFormat = NULL);
-
- void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in = NULL);
-
- void addEndTimeMonitor();
-
- void handleFlushComplete(bool audio, bool isDecoder);
- void finishFlushIfPossible();
-
- void onStart(bool play);
- void onResume();
- void onPause();
-
- bool audioDecoderStillNeeded();
-
- void flushDecoder(bool audio, bool needShutdown);
-
- void finishResume();
- void notifyDriverSeekComplete(int64_t srcId);
-
- void postScanSources();
-
- void schedulePollDuration();
- void cancelPollDuration();
-
- void processDeferredActions();
-
- void performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
- void performDecoderFlush(FlushCommand audio, FlushCommand video);
- void performReset();
- void performPlayNextDataSource();
- void performScanSources();
- void performSetSurface(const sp<ANativeWindowWrapper> &nw);
- void performResumeDecoders(bool needNotify);
-
- void onSourceNotify(const sp<AMessage> &msg);
- void onClosedCaptionNotify(const sp<AMessage> &msg);
-
- void queueDecoderShutdown(
- bool audio, bool video, const sp<AMessage> &reply);
-
- void sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex);
- void sendTimedMetaData(const sp<ABuffer> &buffer);
- void sendTimedTextData(const sp<ABuffer> &buffer);
-
- void writeTrackInfo(PlayerMessage* reply, const sp<AMessage>& format) const;
-
- status_t onPrepareDrm(const sp<AMessage> &msg);
- status_t onReleaseDrm(const sp<AMessage> &msg);
-
- SourceInfo* getSourceInfoByIdInMsg(const sp<AMessage> &msg);
- void resetSourceInfo(SourceInfo &srcInfo);
-
- DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2);
-};
-
-} // namespace android
-
-#endif // NU_PLAYER2_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
deleted file mode 100644
index 98c3403..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2CCDecoder"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2CCDecoder.h"
-
-#include <media/NdkMediaFormat.h>
-#include <media/stagefright/foundation/ABitReader.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaDefs.h>
-
-namespace android {
-
-// In CEA-708B, the maximum bandwidth of CC is set to 9600bps.
-static const size_t kMaxBandwithSizeBytes = 9600 / 8;
-
-struct CCData {
- CCData(uint8_t type, uint8_t data1, uint8_t data2)
- : mType(type), mData1(data1), mData2(data2) {
- }
- bool getChannel(size_t *channel) const {
- if (mData1 >= 0x10 && mData1 <= 0x1f) {
- *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0);
- return true;
- }
- return false;
- }
-
- uint8_t mType;
- uint8_t mData1;
- uint8_t mData2;
-};
-
-static bool isNullPad(CCData *cc) {
- return cc->mData1 < 0x10 && cc->mData2 < 0x10;
-}
-
-static void dumpBytePair(const sp<ABuffer> &ccBuf) __attribute__ ((unused));
-static void dumpBytePair(const sp<ABuffer> &ccBuf) {
- size_t offset = 0;
- AString out;
-
- while (offset < ccBuf->size()) {
- char tmp[128];
-
- CCData *cc = (CCData *) (ccBuf->data() + offset);
-
- if (isNullPad(cc)) {
- // 1 null pad or XDS metadata, ignore
- offset += sizeof(CCData);
- continue;
- }
-
- if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
- // 2 basic chars
- snprintf(tmp, sizeof(tmp), "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
- && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
- // 1 special char
- snprintf(tmp, sizeof(tmp), "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
- // 1 Spanish/French char
- snprintf(tmp, sizeof(tmp), "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
- // 1 Portuguese/German/Danish char
- snprintf(tmp, sizeof(tmp), "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
- // Mid-Row Codes (Table 69)
- snprintf(tmp, sizeof(tmp), "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
- ||
- ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
- && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
- // Misc Control Codes (Table 70)
- snprintf(tmp, sizeof(tmp), "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 & 0x70) == 0x10
- && (cc->mData2 & 0x40) == 0x40
- && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
- // Preamble Address Codes (Table 71)
- snprintf(tmp, sizeof(tmp), "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else {
- snprintf(tmp, sizeof(tmp), "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- }
-
- if (out.size() > 0) {
- out.append(", ");
- }
-
- out.append(tmp);
-
- offset += sizeof(CCData);
- }
-
- ALOGI("%s", out.c_str());
-}
-
-NuPlayer2::CCDecoder::CCDecoder(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mSelectedTrack(-1),
- mDTVCCPacket(new ABuffer(kMaxBandwithSizeBytes)) {
- mDTVCCPacket->setRange(0, 0);
-
- // In CEA-608, streams from packets which have the value 0 of cc_type contain CC1 and CC2, and
- // streams from packets which have the value 1 of cc_type contain CC3 and CC4.
- // The following array indicates the current transmitting channels for each value of cc_type.
- mLine21Channels[0] = 0; // CC1
- mLine21Channels[1] = 2; // CC3
-}
-
-size_t NuPlayer2::CCDecoder::getTrackCount() const {
- return mTracks.size();
-}
-
-sp<AMessage> NuPlayer2::CCDecoder::getTrackInfo(size_t index) const {
- if (!isTrackValid(index)) {
- return NULL;
- }
-
- sp<AMessage> format = new AMessage();
-
- CCTrack track = mTracks[index];
-
- format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
- format->setString("language", "und");
-
- switch (track.mTrackType) {
- case kTrackTypeCEA608:
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
- break;
- case kTrackTypeCEA708:
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_708);
- break;
- default:
- ALOGE("Unknown track type: %d", track.mTrackType);
- return NULL;
- }
-
- // For CEA-608 CC1, field 0 channel 0
- bool isDefaultAuto = track.mTrackType == kTrackTypeCEA608
- && track.mTrackChannel == 0;
- // For CEA-708, Primary Caption Service.
- bool isDefaultOnly = track.mTrackType == kTrackTypeCEA708
- && track.mTrackChannel == 1;
- format->setInt32("auto", isDefaultAuto);
- format->setInt32("default", isDefaultAuto || isDefaultOnly);
- format->setInt32("forced", 0);
-
- return format;
-}
-
-status_t NuPlayer2::CCDecoder::selectTrack(size_t index, bool select) {
- if (!isTrackValid(index)) {
- return BAD_VALUE;
- }
-
- if (select) {
- if (mSelectedTrack == (ssize_t)index) {
- ALOGE("track %zu already selected", index);
- return BAD_VALUE;
- }
- ALOGV("selected track %zu", index);
- mSelectedTrack = index;
- } else {
- if (mSelectedTrack != (ssize_t)index) {
- ALOGE("track %zu is not selected", index);
- return BAD_VALUE;
- }
- ALOGV("unselected track %zu", index);
- mSelectedTrack = -1;
- }
-
- // Clear the previous track payloads
- mCCMap.clear();
-
- return OK;
-}
-
-ssize_t NuPlayer2::CCDecoder::getSelectedTrack(media_track_type type) const {
- if (mSelectedTrack != -1) {
- CCTrack track = mTracks[mSelectedTrack];
- if (track.mTrackType == kTrackTypeCEA608 || track.mTrackType == kTrackTypeCEA708) {
- return (type == MEDIA_TRACK_TYPE_SUBTITLE ? mSelectedTrack : -1);
- }
- return (type == MEDIA_TRACK_TYPE_UNKNOWN ? mSelectedTrack : -1);
- }
-
- return -1;
-}
-
-bool NuPlayer2::CCDecoder::isSelected() const {
- return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)getTrackCount();
-}
-
-bool NuPlayer2::CCDecoder::isTrackValid(size_t index) const {
- return index < getTrackCount();
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
- sp<ABuffer> sei;
- if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
- return false;
- }
-
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
- bool trackAdded = false;
-
- const NALPosition *nal = (NALPosition *)sei->data();
-
- for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
- trackAdded |= parseSEINalUnit(
- timeUs, accessUnit->data() + nal->nalOffset, nal->nalSize);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size) {
- unsigned nalType = data[0] & 0x1f;
-
- // the buffer should only have SEI in it
- if (nalType != 6) {
- return false;
- }
-
- bool trackAdded = false;
- NALBitReader br(data + 1, size - 1);
-
- // sei_message()
- while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
- uint32_t payload_type = 0;
- size_t payload_size = 0;
- uint8_t last_byte;
-
- do {
- last_byte = br.getBits(8);
- payload_type += last_byte;
- } while (last_byte == 0xFF);
-
- do {
- last_byte = br.getBits(8);
- payload_size += last_byte;
- } while (last_byte == 0xFF);
-
- if (payload_size > SIZE_MAX / 8
- || !br.atLeastNumBitsLeft(payload_size * 8)) {
- ALOGV("Malformed SEI payload");
- break;
- }
-
- // sei_payload()
- if (payload_type == 4) {
- bool isCC = false;
- if (payload_size > 1 + 2 + 4 + 1) {
- // user_data_registered_itu_t_t35()
-
- // ATSC A/72: 6.4.2
- uint8_t itu_t_t35_country_code = br.getBits(8);
- uint16_t itu_t_t35_provider_code = br.getBits(16);
- uint32_t user_identifier = br.getBits(32);
- uint8_t user_data_type_code = br.getBits(8);
-
- payload_size -= 1 + 2 + 4 + 1;
-
- isCC = itu_t_t35_country_code == 0xB5
- && itu_t_t35_provider_code == 0x0031
- && user_identifier == 'GA94'
- && user_data_type_code == 0x3;
- }
-
- if (isCC && payload_size > 2) {
- trackAdded |= parseMPEGCCData(timeUs, br.data(), br.numBitsLeft() / 8);
- } else {
- ALOGV("Malformed SEI payload type 4");
- }
- } else {
- ALOGV("Unsupported SEI payload type %d", payload_type);
- }
-
- // skipping remaining bits of this payload
- br.skipBits(payload_size * 8);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) {
- sp<ABuffer> mpegUserData;
- if (!accessUnit->meta()->findBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, &mpegUserData)
- || mpegUserData == NULL) {
- return false;
- }
-
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
- bool trackAdded = false;
-
- const size_t *userData = (size_t *)mpegUserData->data();
-
- for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
- trackAdded |= parseMPEGUserDataUnit(
- timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
- ABitReader br(data + 4, 5);
-
- uint32_t user_identifier = br.getBits(32);
- uint8_t user_data_type = br.getBits(8);
-
- if (user_identifier == 'GA94' && user_data_type == 0x3) {
- return parseMPEGCCData(timeUs, data + 9, size - 9);
- }
-
- return false;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size) {
- bool trackAdded = false;
-
- // MPEG_cc_data()
- // ATSC A/53 Part 4: 6.2.3.1
- ABitReader br(data, size);
-
- if (br.numBitsLeft() <= 16) {
- return false;
- }
-
- br.skipBits(1);
- bool process_cc_data_flag = br.getBits(1);
- br.skipBits(1);
- size_t cc_count = br.getBits(5);
- br.skipBits(8);
-
- if (!process_cc_data_flag || 3 * 8 * cc_count >= br.numBitsLeft()) {
- return false;
- }
-
- sp<ABuffer> line21CCBuf = NULL;
-
- for (size_t i = 0; i < cc_count; ++i) {
- br.skipBits(5);
- bool cc_valid = br.getBits(1);
- uint8_t cc_type = br.getBits(2);
-
- if (cc_valid) {
- if (cc_type == 3) {
- if (mDTVCCPacket->size() > 0) {
- trackAdded |= parseDTVCCPacket(
- timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
- mDTVCCPacket->setRange(0, 0);
- }
- if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
- return false;
- }
- memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
- mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
- br.skipBits(16);
- } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
- if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
- return false;
- }
- memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
- mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
- br.skipBits(16);
- } else if (cc_type == 0 || cc_type == 1) {
- uint8_t cc_data_1 = br.getBits(8) & 0x7f;
- uint8_t cc_data_2 = br.getBits(8) & 0x7f;
-
- CCData cc(cc_type, cc_data_1, cc_data_2);
-
- if (isNullPad(&cc)) {
- continue;
- }
-
- size_t channel;
- if (cc.getChannel(&channel)) {
- mLine21Channels[cc_type] = channel;
-
- // create a new track if it does not exist.
- getTrackIndex(kTrackTypeCEA608, channel, &trackAdded);
- }
-
- if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
- && mTracks[mSelectedTrack].mTrackChannel == mLine21Channels[cc_type]) {
- if (line21CCBuf == NULL) {
- line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
- line21CCBuf->setRange(0, 0);
- }
- if (line21CCBuf->size() + sizeof(cc) > line21CCBuf->capacity()) {
- return false;
- }
- memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
- line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
- }
- } else {
- br.skipBits(16);
- }
- } else {
- if ((cc_type == 3 || cc_type == 2) && mDTVCCPacket->size() > 0) {
- trackAdded |= parseDTVCCPacket(timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
- mDTVCCPacket->setRange(0, 0);
- }
- br.skipBits(16);
- }
- }
-
- if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
- && line21CCBuf != NULL && line21CCBuf->size() > 0) {
- mCCMap.add(timeUs, line21CCBuf);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size) {
- // CEA-708B 5 DTVCC Packet Layer.
- ABitReader br(data, size);
- br.skipBits(2);
-
- size_t packet_size = br.getBits(6);
- if (packet_size == 0) packet_size = 64;
- packet_size *= 2;
-
- if (size != packet_size) {
- return false;
- }
-
- bool trackAdded = false;
-
- while (br.numBitsLeft() >= 16) {
- // CEA-708B Figure 5 and 6.
- uint8_t service_number = br.getBits(3);
- size_t block_size = br.getBits(5);
-
- if (service_number == 64) {
- br.skipBits(2);
- service_number = br.getBits(6);
-
- if (service_number < 64) {
- return trackAdded;
- }
- }
-
- if (br.numBitsLeft() < block_size * 8) {
- return trackAdded;
- }
-
- if (block_size > 0) {
- size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
- if (mSelectedTrack == (ssize_t)trackIndex) {
- sp<ABuffer> ccPacket = new ABuffer(block_size);
- if (ccPacket->capacity() == 0) {
- return false;
- }
- memcpy(ccPacket->data(), br.data(), block_size);
- mCCMap.add(timeUs, ccPacket);
- }
- }
- br.skipBits(block_size * 8);
- }
-
- return trackAdded;
-}
-
-// return the track index for a given type and channel.
-// if the track does not exist, creates a new one.
-size_t NuPlayer2::CCDecoder::getTrackIndex(
- int32_t trackType, size_t channel, bool *trackAdded) {
- CCTrack track(trackType, channel);
- ssize_t index = mTrackIndices.indexOfKey(track);
-
- if (index < 0) {
- // A new track is added.
- index = mTracks.size();
- mTrackIndices.add(track, index);
- mTracks.add(track);
- *trackAdded = true;
- return index;
- }
-
- return mTrackIndices.valueAt(index);
-}
-
-void NuPlayer2::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
- if (extractFromMPEGUserData(accessUnit) || extractFromSEI(accessUnit)) {
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatTrackAdded);
- msg->post();
- }
- // TODO: extract CC from other sources
-}
-
-void NuPlayer2::CCDecoder::display(int64_t timeUs) {
- if (!isSelected()) {
- return;
- }
-
- ssize_t index = mCCMap.indexOfKey(timeUs);
- if (index < 0) {
- ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
- return;
- }
-
- sp<ABuffer> ccBuf;
-
- if (index == 0) {
- ccBuf = mCCMap.valueAt(index);
- } else {
- size_t size = 0;
-
- for (ssize_t i = 0; i <= index; ++i) {
- size += mCCMap.valueAt(i)->size();
- }
-
- ccBuf = new ABuffer(size);
- ccBuf->setRange(0, 0);
-
- if (ccBuf->capacity() > 0) {
- for (ssize_t i = 0; i <= index; ++i) {
- sp<ABuffer> buf = mCCMap.valueAt(i);
- memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
- ccBuf->setRange(0, ccBuf->size() + buf->size());
- }
- }
- }
-
- if (ccBuf->size() > 0) {
-#if 0
- dumpBytePair(ccBuf);
-#endif
-
- ccBuf->meta()->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, mSelectedTrack);
- ccBuf->meta()->setInt64("timeUs", timeUs);
- ccBuf->meta()->setInt64("durationUs", 0LL);
-
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatClosedCaptionData);
- msg->setBuffer("buffer", ccBuf);
- msg->post();
- }
-
- // remove all entries before timeUs
- mCCMap.removeItemsAt(0, index + 1);
-}
-
-void NuPlayer2::CCDecoder::flush() {
- mCCMap.clear();
- mDTVCCPacket->setRange(0, 0);
-}
-
-int32_t NuPlayer2::CCDecoder::CCTrack::compare(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- int32_t cmp = mTrackType - rhs.mTrackType;
- if (cmp != 0) return cmp;
- return mTrackChannel - rhs.mTrackChannel;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator<(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) < 0;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator==(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) == 0;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator!=(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) != 0;
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
deleted file mode 100644
index 97834d1..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_CCDECODER_H_
-
-#define NUPLAYER2_CCDECODER_H_
-
-#include "NuPlayer2.h"
-
-namespace android {
-
-struct NuPlayer2::CCDecoder : public RefBase {
- enum {
- kWhatClosedCaptionData,
- kWhatTrackAdded,
- };
-
- enum {
- kTrackTypeCEA608,
- kTrackTypeCEA708,
- };
-
- explicit CCDecoder(const sp<AMessage> ¬ify);
-
- size_t getTrackCount() const;
- sp<AMessage> getTrackInfo(size_t index) const;
- status_t selectTrack(size_t index, bool select);
- ssize_t getSelectedTrack(media_track_type type) const;
- bool isSelected() const;
- void decode(const sp<ABuffer> &accessUnit);
- void display(int64_t timeUs);
- void flush();
-
-private:
- // CC track identifier.
- struct CCTrack {
- CCTrack() : mTrackType(0), mTrackChannel(0) { }
-
- CCTrack(const int32_t trackType, const size_t trackChannel)
- : mTrackType(trackType), mTrackChannel(trackChannel) { }
-
- int32_t mTrackType;
- size_t mTrackChannel;
-
- // The ordering of CCTracks is to build a map of track to index.
- // It is necessary to find the index of the matched CCTrack when CC data comes.
- int compare(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator<(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator==(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator!=(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- };
-
- sp<AMessage> mNotify;
- KeyedVector<int64_t, sp<ABuffer> > mCCMap;
- ssize_t mSelectedTrack;
- KeyedVector<CCTrack, size_t> mTrackIndices;
- Vector<CCTrack> mTracks;
-
- // CEA-608 closed caption
- size_t mLine21Channels[2]; // The current channels of NTSC_CC_FIELD_{1, 2}
-
- // CEA-708 closed caption
- sp<ABuffer> mDTVCCPacket;
-
- bool isTrackValid(size_t index) const;
- size_t getTrackIndex(int32_t trackType, size_t channel, bool *trackAdded);
-
- // Extract from H.264 SEIs
- bool extractFromSEI(const sp<ABuffer> &accessUnit);
- bool parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size);
-
- // Extract from MPEG user data
- bool extractFromMPEGUserData(const sp<ABuffer> &accessUnit);
- bool parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size);
-
- // Extract CC tracks from MPEG_cc_data
- bool parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size);
- bool parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size);
-
- DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_CCDECODER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
deleted file mode 100644
index 66bfae5..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ /dev/null
@@ -1,1315 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Decoder"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include <algorithm>
-
-#include "NuPlayer2CCDecoder.h"
-#include "NuPlayer2Decoder.h"
-#include "NuPlayer2Drm.h"
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-
-#include <cutils/properties.h>
-#include <media/MediaBufferHolder.h>
-#include <media/MediaCodecBuffer.h>
-#include <media/NdkMediaCodec.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/SurfaceUtils.h>
-
-#include <system/window.h>
-#include "ATSParser.h"
-
-namespace android {
-
-static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
-
-// The default total video frame rate of a stream when that info is not available from
-// the source.
-static float kDefaultVideoFrameRateTotal = 30.f;
-
-static inline bool getAudioDeepBufferSetting() {
- return property_get_bool("media.stagefright.audio.deep", false /* default_value */);
-}
-
-NuPlayer2::Decoder::Decoder(
- const sp<AMessage> ¬ify,
- const sp<Source> &source,
- pid_t pid,
- uid_t uid,
- const sp<Renderer> &renderer,
- const sp<ANativeWindowWrapper> &nww,
- const sp<CCDecoder> &ccDecoder)
- : DecoderBase(notify),
- mNativeWindow(nww),
- mSource(source),
- mRenderer(renderer),
- mCCDecoder(ccDecoder),
- mPid(pid),
- mUid(uid),
- mSkipRenderingUntilMediaTimeUs(-1LL),
- mNumFramesTotal(0LL),
- mNumInputFramesDropped(0LL),
- mNumOutputFramesDropped(0LL),
- mVideoWidth(0),
- mVideoHeight(0),
- mIsAudio(true),
- mIsVideoAVC(false),
- mIsSecure(false),
- mIsEncrypted(false),
- mIsEncryptedObservedEarlier(false),
- mFormatChangePending(false),
- mTimeChangePending(false),
- mFrameRateTotal(kDefaultVideoFrameRateTotal),
- mPlaybackSpeed(1.0f),
- mNumVideoTemporalLayerTotal(1), // decode all layers
- mNumVideoTemporalLayerAllowed(1),
- mCurrentMaxVideoTemporalLayerId(0),
- mResumePending(false),
- mComponentName("decoder") {
- mVideoTemporalLayerAggregateFps[0] = mFrameRateTotal;
-}
-
-NuPlayer2::Decoder::~Decoder() {
- // Need to stop looper first since mCodec could be accessed on the mDecoderLooper.
- stopLooper();
- if (mCodec != NULL) {
- mCodec->release();
- }
- releaseAndResetMediaBuffers();
-}
-
-sp<AMessage> NuPlayer2::Decoder::getStats() const {
- mStats->setInt64("frames-total", mNumFramesTotal);
- mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
- mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
- mStats->setFloat("frame-rate-total", mFrameRateTotal);
-
- // i'm mutexed right now.
- // make our own copy, so we aren't victim to any later changes.
- sp<AMessage> copiedStats = mStats->dup();
- return copiedStats;
-}
-
-status_t NuPlayer2::Decoder::setVideoSurface(const sp<ANativeWindowWrapper> &nww) {
- if (nww == NULL || nww->getANativeWindow() == NULL
- || ADebug::isExperimentEnabled("legacy-setsurface")) {
- return BAD_VALUE;
- }
-
- sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);
-
- msg->setObject("surface", nww);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-void NuPlayer2::Decoder::onMessageReceived(const sp<AMessage> &msg) {
- ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
-
- switch (msg->what()) {
- case kWhatCodecNotify:
- {
- int32_t cbID;
- CHECK(msg->findInt32("callbackID", &cbID));
-
- ALOGV("[%s] kWhatCodecNotify: cbID = %d, paused = %d",
- mIsAudio ? "audio" : "video", cbID, mPaused);
-
- if (mPaused) {
- break;
- }
-
- switch (cbID) {
- case AMediaCodecWrapper::CB_INPUT_AVAILABLE:
- {
- int32_t index;
- CHECK(msg->findInt32("index", &index));
-
- handleAnInputBuffer(index);
- break;
- }
-
- case AMediaCodecWrapper::CB_OUTPUT_AVAILABLE:
- {
- int32_t index;
- size_t offset;
- size_t size;
- int64_t timeUs;
- int32_t flags;
-
- CHECK(msg->findInt32("index", &index));
- CHECK(msg->findSize("offset", &offset));
- CHECK(msg->findSize("size", &size));
- CHECK(msg->findInt64("timeUs", &timeUs));
- CHECK(msg->findInt32("flags", &flags));
-
- handleAnOutputBuffer(index, offset, size, timeUs, flags);
- break;
- }
-
- case AMediaCodecWrapper::CB_OUTPUT_FORMAT_CHANGED:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- handleOutputFormatChange(format);
- break;
- }
-
- case AMediaCodecWrapper::CB_ERROR:
- {
- status_t err;
- CHECK(msg->findInt32("err", &err));
- ALOGE("Decoder (%s) reported error : 0x%x",
- mIsAudio ? "audio" : "video", err);
-
- handleError(err);
- break;
- }
-
- default:
- {
- TRESPASS();
- break;
- }
- }
-
- break;
- }
-
- case kWhatRenderBuffer:
- {
- if (!isStaleReply(msg)) {
- onRenderBuffer(msg);
- }
- break;
- }
-
- case kWhatAudioOutputFormatChanged:
- {
- if (!isStaleReply(msg)) {
- status_t err;
- if (msg->findInt32("err", &err) && err != OK) {
- ALOGE("Renderer reported 0x%x when changing audio output format", err);
- handleError(err);
- }
- }
- break;
- }
-
- case kWhatSetVideoSurface:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- sp<RefBase> obj;
- CHECK(msg->findObject("surface", &obj));
- sp<ANativeWindowWrapper> nww =
- static_cast<ANativeWindowWrapper *>(obj.get()); // non-null
- if (nww == NULL || nww->getANativeWindow() == NULL) {
- break;
- }
- int32_t err = INVALID_OPERATION;
- // NOTE: in practice mNativeWindow is always non-null,
- // but checking here for completeness
- if (mCodec != NULL
- && mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // TODO: once AwesomePlayer is removed, remove this automatic connecting
- // to the surface by MediaPlayerService.
- //
- // at this point MediaPlayer2Manager::client has already connected to the
- // surface, which MediaCodec does not expect
- err = native_window_api_disconnect(nww->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- if (err == OK) {
- err = mCodec->setOutputSurface(nww);
- ALOGI_IF(err, "codec setOutputSurface returned: %d", err);
- if (err == OK) {
- // reconnect to the old surface as MPS::Client will expect to
- // be able to disconnect from it.
- (void)native_window_api_connect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
-
- mNativeWindow = nww;
- }
- }
- if (err != OK) {
- // reconnect to the new surface on error as MPS::Client will expect to
- // be able to disconnect from it.
- (void)native_window_api_connect(nww->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatDrmReleaseCrypto:
- {
- ALOGV("kWhatDrmReleaseCrypto");
- onReleaseCrypto(msg);
- break;
- }
-
- default:
- DecoderBase::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::Decoder::onConfigure(const sp<AMessage> &format) {
- ALOGV("[%s] onConfigure (format=%s)", mComponentName.c_str(), format->debugString().c_str());
- CHECK(mCodec == NULL);
-
- mFormatChangePending = false;
- mTimeChangePending = false;
-
- ++mBufferGeneration;
-
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- mIsAudio = !strncasecmp("audio/", mime.c_str(), 6);
- mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
-
- mComponentName = mime;
- mComponentName.append(" decoder");
- ALOGV("[%s] onConfigure (nww=%p)", mComponentName.c_str(),
- (mNativeWindow == NULL ? NULL : mNativeWindow->getANativeWindow()));
-
- mCodec = AMediaCodecWrapper::CreateDecoderByType(mime);
- int32_t secure = 0;
- if (format->findInt32("secure", &secure) && secure != 0) {
- if (mCodec != NULL) {
- if (mCodec->getName(&mComponentName) == OK) {
- mComponentName.append(".secure");
- mCodec->release();
- ALOGI("[%s] creating", mComponentName.c_str());
- mCodec = AMediaCodecWrapper::CreateCodecByName(mComponentName);
- } else {
- mCodec = NULL;
- }
- }
- }
- if (mCodec == NULL) {
- ALOGE("Failed to create %s%s decoder",
- (secure ? "secure " : ""), mime.c_str());
- handleError(NO_INIT);
- return;
- }
- mIsSecure = secure;
-
- mCodec->getName(&mComponentName);
-
- status_t err;
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // disconnect from surface as MediaCodec will reconnect
- err = native_window_api_disconnect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- // We treat this as a warning, as this is a preparatory step.
- // Codec will try to connect to the surface, which is where
- // any error signaling will occur.
- ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
- }
-
- // Modular DRM
- sp<RefBase> objCrypto;
- format->findObject("crypto", &objCrypto);
- sp<AMediaCryptoWrapper> crypto = static_cast<AMediaCryptoWrapper *>(objCrypto.get());
- // non-encrypted source won't have a crypto
- mIsEncrypted = (crypto != NULL);
- // configure is called once; still using OR in case the behavior changes.
- mIsEncryptedObservedEarlier = mIsEncryptedObservedEarlier || mIsEncrypted;
- ALOGV("onConfigure mCrypto: %p, mIsSecure: %d", crypto.get(), mIsSecure);
-
- err = mCodec->configure(
- AMediaFormatWrapper::Create(format),
- mNativeWindow,
- crypto,
- 0 /* flags */);
-
- if (err != OK) {
- ALOGE("Failed to configure [%s] decoder (err=%d)", mComponentName.c_str(), err);
- mCodec->release();
- mCodec.clear();
- handleError(err);
- return;
- }
- rememberCodecSpecificData(format);
-
- // the following should work in configured state
- sp<AMediaFormatWrapper> outputFormat = mCodec->getOutputFormat();
- if (outputFormat == NULL) {
- handleError(INVALID_OPERATION);
- return;
- }
- mInputFormat = mCodec->getInputFormat();
- if (mInputFormat == NULL) {
- handleError(INVALID_OPERATION);
- return;
- }
-
- mStats->setString("mime", mime.c_str());
- mStats->setString("component-name", mComponentName.c_str());
-
- if (!mIsAudio) {
- int32_t width, height;
- if (outputFormat->getInt32("width", &width)
- && outputFormat->getInt32("height", &height)) {
- mStats->setInt32("width", width);
- mStats->setInt32("height", height);
- }
- }
-
- sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
- mCodec->setCallback(reply);
-
- err = mCodec->start();
- if (err != OK) {
- ALOGE("Failed to start [%s] decoder (err=%d)", mComponentName.c_str(), err);
- mCodec->release();
- mCodec.clear();
- handleError(err);
- return;
- }
-
- releaseAndResetMediaBuffers();
-
- mPaused = false;
- mResumePending = false;
-}
-
-void NuPlayer2::Decoder::onSetParameters(const sp<AMessage> ¶ms) {
- bool needAdjustLayers = false;
- float frameRateTotal;
- if (params->findFloat("frame-rate-total", &frameRateTotal)
- && mFrameRateTotal != frameRateTotal) {
- needAdjustLayers = true;
- mFrameRateTotal = frameRateTotal;
- }
-
- int32_t numVideoTemporalLayerTotal;
- if (params->findInt32("temporal-layer-count", &numVideoTemporalLayerTotal)
- && numVideoTemporalLayerTotal >= 0
- && numVideoTemporalLayerTotal <= kMaxNumVideoTemporalLayers
- && mNumVideoTemporalLayerTotal != numVideoTemporalLayerTotal) {
- needAdjustLayers = true;
- mNumVideoTemporalLayerTotal = std::max(numVideoTemporalLayerTotal, 1);
- }
-
- if (needAdjustLayers && mNumVideoTemporalLayerTotal > 1) {
- // TODO: For now, layer fps is calculated for some specific architectures.
- // But it really should be extracted from the stream.
- mVideoTemporalLayerAggregateFps[0] =
- mFrameRateTotal / (float)(1LL << (mNumVideoTemporalLayerTotal - 1));
- for (int32_t i = 1; i < mNumVideoTemporalLayerTotal; ++i) {
- mVideoTemporalLayerAggregateFps[i] =
- mFrameRateTotal / (float)(1LL << (mNumVideoTemporalLayerTotal - i))
- + mVideoTemporalLayerAggregateFps[i - 1];
- }
- }
-
- float playbackSpeed;
- if (params->findFloat("playback-speed", &playbackSpeed)
- && mPlaybackSpeed != playbackSpeed) {
- needAdjustLayers = true;
- mPlaybackSpeed = playbackSpeed;
- }
-
- if (needAdjustLayers) {
- float decodeFrameRate = mFrameRateTotal;
- // enable temporal layering optimization only if we know the layering depth
- if (mNumVideoTemporalLayerTotal > 1) {
- int32_t layerId;
- for (layerId = 0; layerId < mNumVideoTemporalLayerTotal - 1; ++layerId) {
- if (mVideoTemporalLayerAggregateFps[layerId] * mPlaybackSpeed
- >= kDisplayRefreshingRate * 0.9) {
- break;
- }
- }
- mNumVideoTemporalLayerAllowed = layerId + 1;
- decodeFrameRate = mVideoTemporalLayerAggregateFps[layerId];
- }
- ALOGV("onSetParameters: allowed layers=%d, decodeFps=%g",
- mNumVideoTemporalLayerAllowed, decodeFrameRate);
-
- if (mCodec == NULL) {
- ALOGW("onSetParameters called before codec is created.");
- return;
- }
-
- sp<AMediaFormatWrapper> codecParams = new AMediaFormatWrapper();
- codecParams->setFloat("operating-rate", decodeFrameRate * mPlaybackSpeed);
- mCodec->setParameters(codecParams);
- }
-}
-
-void NuPlayer2::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
- mRenderer = renderer;
-}
-
-void NuPlayer2::Decoder::onResume(bool notifyComplete) {
- mPaused = false;
-
- if (notifyComplete) {
- mResumePending = true;
- }
-
- if (mCodec == NULL) {
- ALOGE("[%s] onResume without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return;
- }
- mCodec->start();
-}
-
-void NuPlayer2::Decoder::doFlush(bool notifyComplete) {
- if (mCCDecoder != NULL) {
- mCCDecoder->flush();
- }
-
- if (mRenderer != NULL) {
- mRenderer->flush(mIsAudio, notifyComplete);
- mRenderer->signalTimeDiscontinuity();
- }
-
- status_t err = OK;
- if (mCodec != NULL) {
- err = mCodec->flush();
- mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
- ++mBufferGeneration;
- }
-
- if (err != OK) {
- ALOGE("failed to flush [%s] (err=%d)", mComponentName.c_str(), err);
- handleError(err);
- // finish with posting kWhatFlushCompleted.
- // we attempt to release the buffers even if flush fails.
- }
- releaseAndResetMediaBuffers();
- mPaused = true;
-}
-
-
-void NuPlayer2::Decoder::onFlush() {
- doFlush(true);
-
- if (isDiscontinuityPending()) {
- // This could happen if the client starts seeking/shutdown
- // after we queued an EOS for discontinuities.
- // We can consider discontinuity handled.
- finishHandleDiscontinuity(false /* flushOnTimeChange */);
- }
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
-}
-
-void NuPlayer2::Decoder::onShutdown(bool notifyComplete) {
- status_t err = OK;
-
- // if there is a pending resume request, notify complete now
- notifyResumeCompleteIfNecessary();
-
- if (mCodec != NULL) {
- err = mCodec->release();
- mCodec = NULL;
- ++mBufferGeneration;
-
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // reconnect to surface as MediaCodec disconnected from it
- status_t error = native_window_api_connect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- ALOGW_IF(error != NO_ERROR,
- "[%s] failed to connect to native window, error=%d",
- mComponentName.c_str(), error);
- }
- mComponentName = "decoder";
- }
-
- releaseAndResetMediaBuffers();
-
- if (err != OK) {
- ALOGE("failed to release [%s] (err=%d)", mComponentName.c_str(), err);
- handleError(err);
- // finish with posting kWhatShutdownCompleted.
- }
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatShutdownCompleted);
- notify->post();
- mPaused = true;
- }
-}
-
-/*
- * returns true if we should request more data
- */
-bool NuPlayer2::Decoder::doRequestBuffers() {
- if (isDiscontinuityPending()) {
- return false;
- }
- status_t err = OK;
- while (err == OK && !mDequeuedInputBuffers.empty()) {
- size_t bufferIx = *mDequeuedInputBuffers.begin();
- sp<AMessage> msg = new AMessage();
- msg->setSize("buffer-ix", bufferIx);
- err = fetchInputData(msg);
- if (err != OK && err != ERROR_END_OF_STREAM) {
- // if EOS, need to queue EOS buffer
- break;
- }
- mDequeuedInputBuffers.erase(mDequeuedInputBuffers.begin());
-
- if (!mPendingInputMessages.empty()
- || !onInputBufferFetched(msg)) {
- mPendingInputMessages.push_back(msg);
- }
- }
-
- return err == -EWOULDBLOCK
- && mSource->feedMoreTSData() == OK;
-}
-
-void NuPlayer2::Decoder::handleError(int32_t err)
-{
- // We cannot immediately release the codec due to buffers still outstanding
- // in the renderer. We signal to the player the error so it can shutdown/release the
- // decoder after flushing and increment the generation to discard unnecessary messages.
-
- ++mBufferGeneration;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatError);
- notify->setInt32("err", err);
- notify->post();
-}
-
-status_t NuPlayer2::Decoder::releaseCrypto()
-{
- ALOGV("releaseCrypto");
-
- sp<AMessage> msg = new AMessage(kWhatDrmReleaseCrypto, this);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("releaseCrypto ret: %d ", status);
- } else {
- ALOGE("releaseCrypto err: %d", status);
- }
-
- return status;
-}
-
-void NuPlayer2::Decoder::onReleaseCrypto(const sp<AMessage>& msg)
-{
- status_t status = INVALID_OPERATION;
- if (mCodec != NULL) {
- status = mCodec->releaseCrypto();
- } else {
- // returning OK if the codec has been already released
- status = OK;
- ALOGE("onReleaseCrypto No mCodec. err: %d", status);
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- // Clearing the state as it's tied to crypto. mIsEncryptedObservedEarlier is sticky though
- // and lasts for the lifetime of this codec. See its use in fetchInputData.
- mIsEncrypted = false;
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-bool NuPlayer2::Decoder::handleAnInputBuffer(size_t index) {
- if (isDiscontinuityPending()) {
- return false;
- }
-
- if (mCodec == NULL) {
- ALOGE("[%s] handleAnInputBuffer without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
- size_t bufferSize = 0;
- uint8_t *bufferBase = mCodec->getInputBuffer(index, &bufferSize);
-
- if (bufferBase == NULL) {
- ALOGE("[%s] handleAnInputBuffer, failed to get input buffer", mComponentName.c_str());
- handleError(UNKNOWN_ERROR);
- return false;
- }
-
- sp<MediaCodecBuffer> buffer =
- new MediaCodecBuffer(NULL /* format */, new ABuffer(bufferBase, bufferSize));
-
- if (index >= mInputBuffers.size()) {
- for (size_t i = mInputBuffers.size(); i <= index; ++i) {
- mInputBuffers.add();
- mMediaBuffers.add();
- mInputBufferIsDequeued.add();
- mMediaBuffers.editItemAt(i) = NULL;
- mInputBufferIsDequeued.editItemAt(i) = false;
- }
- }
- mInputBuffers.editItemAt(index) = buffer;
-
- //CHECK_LT(bufferIx, mInputBuffers.size());
-
- if (mMediaBuffers[index] != NULL) {
- mMediaBuffers[index]->release();
- mMediaBuffers.editItemAt(index) = NULL;
- }
- mInputBufferIsDequeued.editItemAt(index) = true;
-
- if (!mCSDsToSubmit.isEmpty()) {
- sp<AMessage> msg = new AMessage();
- msg->setSize("buffer-ix", index);
-
- sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
- ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
- msg->setBuffer("buffer", buffer);
- mCSDsToSubmit.removeAt(0);
- if (!onInputBufferFetched(msg)) {
- handleError(UNKNOWN_ERROR);
- return false;
- }
- return true;
- }
-
- while (!mPendingInputMessages.empty()) {
- sp<AMessage> msg = *mPendingInputMessages.begin();
- if (!onInputBufferFetched(msg)) {
- break;
- }
- mPendingInputMessages.erase(mPendingInputMessages.begin());
- }
-
- if (!mInputBufferIsDequeued.editItemAt(index)) {
- return true;
- }
-
- mDequeuedInputBuffers.push_back(index);
-
- onRequestInputBuffers();
- return true;
-}
-
-bool NuPlayer2::Decoder::handleAnOutputBuffer(
- size_t index,
- size_t offset,
- size_t size,
- int64_t timeUs,
- int32_t flags) {
- if (mCodec == NULL) {
- ALOGE("[%s] handleAnOutputBuffer without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
-// CHECK_LT(bufferIx, mOutputBuffers.size());
-
- size_t bufferSize = 0;
- uint8_t *bufferBase = mCodec->getOutputBuffer(index, &bufferSize);
-
- if (bufferBase == NULL) {
- ALOGE("[%s] handleAnOutputBuffer, failed to get output buffer", mComponentName.c_str());
- handleError(UNKNOWN_ERROR);
- return false;
- }
-
- sp<MediaCodecBuffer> buffer =
- new MediaCodecBuffer(NULL /* format */, new ABuffer(bufferBase, bufferSize));
-
- if (index >= mOutputBuffers.size()) {
- for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
- mOutputBuffers.add();
- }
- }
-
- mOutputBuffers.editItemAt(index) = buffer;
-
- buffer->setRange(offset, size);
- buffer->meta()->clear();
- buffer->meta()->setInt64("timeUs", timeUs);
-
- bool eos = flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- // we do not expect CODECCONFIG or SYNCFRAME for decoder
-
- sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
- reply->setSize("buffer-ix", index);
- reply->setInt32("generation", mBufferGeneration);
-
- if (eos) {
- ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
-
- buffer->meta()->setInt32("eos", true);
- reply->setInt32("eos", true);
- }
-
- mNumFramesTotal += !mIsAudio;
-
- if (mSkipRenderingUntilMediaTimeUs >= 0) {
- if (timeUs < mSkipRenderingUntilMediaTimeUs) {
- ALOGV("[%s] dropping buffer at time %lld as requested.",
- mComponentName.c_str(), (long long)timeUs);
-
- reply->post();
- if (eos) {
- notifyResumeCompleteIfNecessary();
- if (mRenderer != NULL && !isDiscontinuityPending()) {
- mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
- }
- }
- return true;
- }
-
- mSkipRenderingUntilMediaTimeUs = -1;
- }
-
- // wait until 1st frame comes out to signal resume complete
- notifyResumeCompleteIfNecessary();
-
- if (mRenderer != NULL) {
- // send the buffer to renderer.
- mRenderer->queueBuffer(mIsAudio, buffer, reply);
- if (eos && !isDiscontinuityPending()) {
- mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
- }
- }
-
- return true;
-}
-
-void NuPlayer2::Decoder::handleOutputFormatChange(const sp<AMessage> &format) {
- if (!mIsAudio) {
- int32_t width, height;
- if (format->findInt32("width", &width)
- && format->findInt32("height", &height)) {
- mStats->setInt32("width", width);
- mStats->setInt32("height", height);
- }
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatVideoSizeChanged);
- notify->setMessage("format", format);
- notify->post();
- } else if (mRenderer != NULL) {
- uint32_t flags;
- int64_t durationUs;
- bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
- if (getAudioDeepBufferSetting() // override regardless of source duration
- || (mSource->getDuration(&durationUs) == OK
- && durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US)) {
- flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- } else {
- flags = AUDIO_OUTPUT_FLAG_NONE;
- }
-
- sp<AMessage> reply = new AMessage(kWhatAudioOutputFormatChanged, this);
- reply->setInt32("generation", mBufferGeneration);
- mRenderer->changeAudioFormat(
- format, false /* offloadOnly */, hasVideo,
- flags, mSource->isStreaming(), reply);
- }
-}
-
-void NuPlayer2::Decoder::releaseAndResetMediaBuffers() {
- for (size_t i = 0; i < mMediaBuffers.size(); i++) {
- if (mMediaBuffers[i] != NULL) {
- mMediaBuffers[i]->release();
- mMediaBuffers.editItemAt(i) = NULL;
- }
- }
- mMediaBuffers.resize(mInputBuffers.size());
- for (size_t i = 0; i < mMediaBuffers.size(); i++) {
- mMediaBuffers.editItemAt(i) = NULL;
- }
- mInputBufferIsDequeued.clear();
- mInputBufferIsDequeued.resize(mInputBuffers.size());
- for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
- mInputBufferIsDequeued.editItemAt(i) = false;
- }
-
- mPendingInputMessages.clear();
- mDequeuedInputBuffers.clear();
- mSkipRenderingUntilMediaTimeUs = -1;
-}
-
-bool NuPlayer2::Decoder::isStaleReply(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- return generation != mBufferGeneration;
-}
-
-status_t NuPlayer2::Decoder::fetchInputData(sp<AMessage> &reply) {
- sp<ABuffer> accessUnit;
- bool dropAccessUnit = true;
- do {
- status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
-
- if (err == -EWOULDBLOCK) {
- return err;
- } else if (err != OK) {
- if (err == INFO_DISCONTINUITY) {
- int32_t type;
- CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
-
- bool formatChange =
- (mIsAudio &&
- (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
- || (!mIsAudio &&
- (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
-
- bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
-
- ALOGI("%s discontinuity (format=%d, time=%d)",
- mIsAudio ? "audio" : "video", formatChange, timeChange);
-
- bool seamlessFormatChange = false;
- sp<AMessage> newFormat = mSource->getFormat(mIsAudio);
- if (formatChange) {
- seamlessFormatChange =
- supportsSeamlessFormatChange(newFormat);
- // treat seamless format change separately
- formatChange = !seamlessFormatChange;
- }
-
- // For format or time change, return EOS to queue EOS input,
- // then wait for EOS on output.
- if (formatChange /* not seamless */) {
- mFormatChangePending = true;
- err = ERROR_END_OF_STREAM;
- } else if (timeChange) {
- rememberCodecSpecificData(newFormat);
- mTimeChangePending = true;
- err = ERROR_END_OF_STREAM;
- } else if (seamlessFormatChange) {
- // reuse existing decoder and don't flush
- rememberCodecSpecificData(newFormat);
- continue;
- } else {
- // This stream is unaffected by the discontinuity
- return -EWOULDBLOCK;
- }
- }
-
- // reply should only be returned without a buffer set
- // when there is an error (including EOS)
- CHECK(err != OK);
-
- reply->setInt32("err", err);
- return ERROR_END_OF_STREAM;
- }
-
- dropAccessUnit = false;
- if (!mIsAudio && !mIsEncrypted) {
- // Extra safeguard if higher-level behavior changes. Otherwise, not required now.
- // Preventing the buffer from being processed (and sent to codec) if this is a later
- // round of playback but this time without prepareDrm. Or if there is a race between
- // stop (which is not blocking) and releaseDrm allowing buffers being processed after
- // Crypto has been released (GenericSource currently prevents this race though).
- // Particularly doing this check before IsAVCReferenceFrame call to prevent parsing
- // of encrypted data.
- if (mIsEncryptedObservedEarlier) {
- ALOGE("fetchInputData: mismatched mIsEncrypted/mIsEncryptedObservedEarlier (0/1)");
-
- return INVALID_OPERATION;
- }
-
- int32_t layerId = 0;
- bool haveLayerId = accessUnit->meta()->findInt32("temporal-layer-id", &layerId);
- if (mRenderer->getVideoLateByUs() > 100000LL
- && mIsVideoAVC
- && !IsAVCReferenceFrame(accessUnit)) {
- dropAccessUnit = true;
- } else if (haveLayerId && mNumVideoTemporalLayerTotal > 1) {
- // Add only one layer each time.
- if (layerId > mCurrentMaxVideoTemporalLayerId + 1
- || layerId >= mNumVideoTemporalLayerAllowed) {
- dropAccessUnit = true;
- ALOGV("dropping layer(%d), speed=%g, allowed layer count=%d, max layerId=%d",
- layerId, mPlaybackSpeed, mNumVideoTemporalLayerAllowed,
- mCurrentMaxVideoTemporalLayerId);
- } else if (layerId > mCurrentMaxVideoTemporalLayerId) {
- mCurrentMaxVideoTemporalLayerId = layerId;
- } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1
- && IsIDR(accessUnit->data(), accessUnit->size())) {
- mCurrentMaxVideoTemporalLayerId = mNumVideoTemporalLayerTotal - 1;
- }
- }
- if (dropAccessUnit) {
- if (layerId <= mCurrentMaxVideoTemporalLayerId && layerId > 0) {
- mCurrentMaxVideoTemporalLayerId = layerId - 1;
- }
- ++mNumInputFramesDropped;
- }
- }
- } while (dropAccessUnit);
-
- // ALOGV("returned a valid buffer of %s data", mIsAudio ? "mIsAudio" : "video");
-#if 0
- int64_t mediaTimeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("[%s] feeding input buffer at media time %.3f",
- mIsAudio ? "audio" : "video",
- mediaTimeUs / 1E6);
-#endif
-
- if (mCCDecoder != NULL) {
- mCCDecoder->decode(accessUnit);
- }
-
- reply->setBuffer("buffer", accessUnit);
-
- return OK;
-}
-
-bool NuPlayer2::Decoder::onInputBufferFetched(const sp<AMessage> &msg) {
- if (mCodec == NULL) {
- ALOGE("[%s] onInputBufferFetched without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
- size_t bufferIx;
- CHECK(msg->findSize("buffer-ix", &bufferIx));
- CHECK_LT(bufferIx, mInputBuffers.size());
- sp<MediaCodecBuffer> codecBuffer = mInputBuffers[bufferIx];
-
- sp<ABuffer> buffer;
- bool hasBuffer = msg->findBuffer("buffer", &buffer);
- bool needsCopy = true;
-
- if (buffer == NULL /* includes !hasBuffer */) {
- int32_t streamErr = ERROR_END_OF_STREAM;
- CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
-
- CHECK(streamErr != OK);
-
- // attempt to queue EOS
- status_t err = mCodec->queueInputBuffer(
- bufferIx,
- 0,
- 0,
- 0,
- AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
- if (err == OK) {
- mInputBufferIsDequeued.editItemAt(bufferIx) = false;
- } else if (streamErr == ERROR_END_OF_STREAM) {
- streamErr = err;
- // err will not be ERROR_END_OF_STREAM
- }
-
- if (streamErr != ERROR_END_OF_STREAM) {
- ALOGE("Stream error for [%s] (err=%d), EOS %s queued",
- mComponentName.c_str(),
- streamErr,
- err == OK ? "successfully" : "unsuccessfully");
- handleError(streamErr);
- }
- } else {
- sp<AMessage> extra;
- if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
- int64_t resumeAtMediaTimeUs;
- if (extra->findInt64(
- "resume-at-mediaTimeUs", &resumeAtMediaTimeUs)) {
- ALOGI("[%s] suppressing rendering until %lld us",
- mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
- mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
- }
- }
-
- int64_t timeUs = 0;
- uint32_t flags = 0;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- int32_t eos, csd;
- // we do not expect SYNCFRAME for decoder
- if (buffer->meta()->findInt32("eos", &eos) && eos) {
- flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- } else if (buffer->meta()->findInt32("csd", &csd) && csd) {
- flags |= AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
- }
-
- // Modular DRM
- MediaBufferBase *mediaBuf = NULL;
- sp<AMediaCodecCryptoInfoWrapper> cryptInfo;
-
- // copy into codec buffer
- if (needsCopy) {
- if (buffer->size() > codecBuffer->capacity()) {
- handleError(ERROR_BUFFER_TOO_SMALL);
- mDequeuedInputBuffers.push_back(bufferIx);
- return false;
- }
-
- if (buffer->data() != NULL) {
- codecBuffer->setRange(0, buffer->size());
- memcpy(codecBuffer->data(), buffer->data(), buffer->size());
- } else { // No buffer->data()
- //Modular DRM
- sp<RefBase> holder;
- if (buffer->meta()->findObject("mediaBufferHolder", &holder)) {
- mediaBuf = (holder != nullptr) ?
- static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
- }
- if (mediaBuf != NULL) {
- if (mediaBuf->size() > codecBuffer->capacity()) {
- handleError(ERROR_BUFFER_TOO_SMALL);
- mDequeuedInputBuffers.push_back(bufferIx);
- return false;
- }
-
- codecBuffer->setRange(0, mediaBuf->size());
- memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
-
- MetaDataBase &meta_data = mediaBuf->meta_data();
- cryptInfo = AMediaCodecCryptoInfoWrapper::Create(meta_data);
- } else { // No mediaBuf
- ALOGE("onInputBufferFetched: buffer->data()/mediaBuf are NULL for %p",
- buffer.get());
- handleError(UNKNOWN_ERROR);
- return false;
- }
- } // buffer->data()
- } // needsCopy
-
- sp<RefBase> cryptInfoObj;
- if (buffer->meta()->findObject("cryptInfo", &cryptInfoObj)) {
- cryptInfo = static_cast<AMediaCodecCryptoInfoWrapper *>(cryptInfoObj.get());
- }
-
- status_t err;
- if (cryptInfo != NULL) {
- err = mCodec->queueSecureInputBuffer(
- bufferIx,
- codecBuffer->offset(),
- cryptInfo,
- timeUs,
- flags);
- // synchronous call so done with cryptInfo here
- } else {
- err = mCodec->queueInputBuffer(
- bufferIx,
- codecBuffer->offset(),
- codecBuffer->size(),
- timeUs,
- flags);
- } // no cryptInfo
-
- if (err != OK) {
- ALOGE("onInputBufferFetched: queue%sInputBuffer failed for [%s] (err=%d)",
- (cryptInfo != NULL ? "Secure" : ""),
- mComponentName.c_str(), err);
- handleError(err);
- } else {
- mInputBufferIsDequeued.editItemAt(bufferIx) = false;
- }
-
- } // buffer != NULL
- return true;
-}
-
-void NuPlayer2::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
- status_t err;
- int32_t render;
- size_t bufferIx;
- int32_t eos;
- CHECK(msg->findSize("buffer-ix", &bufferIx));
-
- if (!mIsAudio) {
- int64_t timeUs;
- sp<MediaCodecBuffer> buffer = mOutputBuffers[bufferIx];
- buffer->meta()->findInt64("timeUs", &timeUs);
-
- if (mCCDecoder != NULL && mCCDecoder->isSelected()) {
- mCCDecoder->display(timeUs);
- }
- }
-
- if (mCodec == NULL) {
- err = NO_INIT;
- } else if (msg->findInt32("render", &render) && render) {
- int64_t timestampNs;
- CHECK(msg->findInt64("timestampNs", ×tampNs));
- err = mCodec->releaseOutputBufferAtTime(bufferIx, timestampNs);
- } else {
- mNumOutputFramesDropped += !mIsAudio;
- err = mCodec->releaseOutputBuffer(bufferIx, false /* render */);
- }
- if (err != OK) {
- ALOGE("failed to release output buffer for [%s] (err=%d)",
- mComponentName.c_str(), err);
- handleError(err);
- }
- if (msg->findInt32("eos", &eos) && eos
- && isDiscontinuityPending()) {
- finishHandleDiscontinuity(true /* flushOnTimeChange */);
- }
-}
-
-bool NuPlayer2::Decoder::isDiscontinuityPending() const {
- return mFormatChangePending || mTimeChangePending;
-}
-
-void NuPlayer2::Decoder::finishHandleDiscontinuity(bool flushOnTimeChange) {
- ALOGV("finishHandleDiscontinuity: format %d, time %d, flush %d",
- mFormatChangePending, mTimeChangePending, flushOnTimeChange);
-
- // If we have format change, pause and wait to be killed;
- // If we have time change only, flush and restart fetching.
-
- if (mFormatChangePending) {
- mPaused = true;
- } else if (mTimeChangePending) {
- if (flushOnTimeChange) {
- doFlush(false /* notifyComplete */);
- signalResume(false /* notifyComplete */);
- }
- }
-
- // Notify NuPlayer2 to either shutdown decoder, or rescan sources
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatInputDiscontinuity);
- msg->setInt32("formatChange", mFormatChangePending);
- msg->post();
-
- mFormatChangePending = false;
- mTimeChangePending = false;
-}
-
-bool NuPlayer2::Decoder::supportsSeamlessAudioFormatChange(
- const sp<AMessage> &targetFormat) const {
- if (targetFormat == NULL) {
- return true;
- }
-
- AString mime;
- if (!targetFormat->findString("mime", &mime)) {
- return false;
- }
-
- if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
- // field-by-field comparison
- const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
- for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
- int32_t oldVal, newVal;
- if (!mInputFormat->getInt32(keys[i], &oldVal) ||
- !targetFormat->findInt32(keys[i], &newVal) ||
- oldVal != newVal) {
- return false;
- }
- }
-
- sp<ABuffer> newBuf;
- uint8_t *oldBufData = NULL;
- size_t oldBufSize = 0;
- if (mInputFormat->getBuffer("csd-0", (void**)&oldBufData, &oldBufSize) &&
- targetFormat->findBuffer("csd-0", &newBuf)) {
- if (oldBufSize != newBuf->size()) {
- return false;
- }
- return !memcmp(oldBufData, newBuf->data(), oldBufSize);
- }
- }
- return false;
-}
-
-bool NuPlayer2::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
- if (mInputFormat == NULL) {
- return false;
- }
-
- if (targetFormat == NULL) {
- return true;
- }
-
- AString oldMime, newMime;
- if (!mInputFormat->getString("mime", &oldMime)
- || !targetFormat->findString("mime", &newMime)
- || !(oldMime == newMime)) {
- return false;
- }
-
- bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
- bool seamless;
- if (audio) {
- seamless = supportsSeamlessAudioFormatChange(targetFormat);
- } else {
- int32_t isAdaptive;
- seamless = (mCodec != NULL &&
- mInputFormat->getInt32("adaptive-playback", &isAdaptive) &&
- isAdaptive);
- }
-
- ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
- return seamless;
-}
-
-void NuPlayer2::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) {
- if (format == NULL) {
- return;
- }
- mCSDsForCurrentFormat.clear();
- for (int32_t i = 0; ; ++i) {
- AString tag = "csd-";
- tag.append(i);
- sp<ABuffer> buffer;
- if (!format->findBuffer(tag.c_str(), &buffer)) {
- break;
- }
- mCSDsForCurrentFormat.push(buffer);
- }
-}
-
-void NuPlayer2::Decoder::notifyResumeCompleteIfNecessary() {
- if (mResumePending) {
- mResumePending = false;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeCompleted);
- notify->post();
- }
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
deleted file mode 100644
index fdfb10e..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_H_
-#define NUPLAYER2_DECODER_H_
-
-#include "NuPlayer2.h"
-
-#include "NuPlayer2DecoderBase.h"
-
-namespace android {
-
-class MediaCodecBuffer;
-
-struct AMediaCodecWrapper;
-struct AMediaFormatWrapper;
-
-struct NuPlayer2::Decoder : public DecoderBase {
- Decoder(const sp<AMessage> ¬ify,
- const sp<Source> &source,
- pid_t pid,
- uid_t uid,
- const sp<Renderer> &renderer = NULL,
- const sp<ANativeWindowWrapper> &nww = NULL,
- const sp<CCDecoder> &ccDecoder = NULL);
-
- virtual sp<AMessage> getStats() const;
-
- // sets the output surface of video decoders.
- virtual status_t setVideoSurface(const sp<ANativeWindowWrapper> &nww);
-
- virtual status_t releaseCrypto();
-
-protected:
- virtual ~Decoder();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format);
- virtual void onSetParameters(const sp<AMessage> ¶ms);
- virtual void onSetRenderer(const sp<Renderer> &renderer);
- virtual void onResume(bool notifyComplete);
- virtual void onFlush();
- virtual void onShutdown(bool notifyComplete);
- virtual bool doRequestBuffers();
-
-private:
- enum {
- kWhatCodecNotify = 'cdcN',
- kWhatRenderBuffer = 'rndr',
- kWhatSetVideoSurface = 'sSur',
- kWhatAudioOutputFormatChanged = 'aofc',
- kWhatDrmReleaseCrypto = 'rDrm',
- };
-
- enum {
- kMaxNumVideoTemporalLayers = 32,
- };
-
- sp<ANativeWindowWrapper> mNativeWindow;
-
- sp<Source> mSource;
- sp<Renderer> mRenderer;
- sp<CCDecoder> mCCDecoder;
-
- sp<AMediaFormatWrapper> mInputFormat;
- sp<AMediaCodecWrapper> mCodec;
-
- List<sp<AMessage> > mPendingInputMessages;
-
- Vector<sp<MediaCodecBuffer> > mInputBuffers;
- Vector<sp<MediaCodecBuffer> > mOutputBuffers;
- Vector<sp<ABuffer> > mCSDsForCurrentFormat;
- Vector<sp<ABuffer> > mCSDsToSubmit;
- Vector<bool> mInputBufferIsDequeued;
- Vector<MediaBuffer *> mMediaBuffers;
- Vector<size_t> mDequeuedInputBuffers;
-
- const pid_t mPid;
- const uid_t mUid;
- int64_t mSkipRenderingUntilMediaTimeUs;
- int64_t mNumFramesTotal;
- int64_t mNumInputFramesDropped;
- int64_t mNumOutputFramesDropped;
- int32_t mVideoWidth;
- int32_t mVideoHeight;
- bool mIsAudio;
- bool mIsVideoAVC;
- bool mIsSecure;
- bool mIsEncrypted;
- bool mIsEncryptedObservedEarlier;
- bool mFormatChangePending;
- bool mTimeChangePending;
- float mFrameRateTotal;
- float mPlaybackSpeed;
- int32_t mNumVideoTemporalLayerTotal;
- int32_t mNumVideoTemporalLayerAllowed;
- int32_t mCurrentMaxVideoTemporalLayerId;
- float mVideoTemporalLayerAggregateFps[kMaxNumVideoTemporalLayers];
-
- bool mResumePending;
- AString mComponentName;
-
- void handleError(int32_t err);
- bool handleAnInputBuffer(size_t index);
- bool handleAnOutputBuffer(
- size_t index,
- size_t offset,
- size_t size,
- int64_t timeUs,
- int32_t flags);
- void handleOutputFormatChange(const sp<AMessage> &format);
-
- void releaseAndResetMediaBuffers();
- bool isStaleReply(const sp<AMessage> &msg);
-
- void doFlush(bool notifyComplete);
- status_t fetchInputData(sp<AMessage> &reply);
- bool onInputBufferFetched(const sp<AMessage> &msg);
- void onRenderBuffer(const sp<AMessage> &msg);
-
- bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
- bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
- void rememberCodecSpecificData(const sp<AMessage> &format);
- bool isDiscontinuityPending() const;
- void finishHandleDiscontinuity(bool flushOnTimeChange);
-
- void notifyResumeCompleteIfNecessary();
-
- void onReleaseCrypto(const sp<AMessage>& msg);
-
- DISALLOW_EVIL_CONSTRUCTORS(Decoder);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
deleted file mode 100644
index 914f29f..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2DecoderBase"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2DecoderBase.h"
-
-#include "NuPlayer2Renderer.h"
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-namespace android {
-
-NuPlayer2::DecoderBase::DecoderBase(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mBufferGeneration(0),
- mPaused(false),
- mStats(new AMessage),
- mRequestInputBuffersPending(false) {
- // Every decoder has its own looper because MediaCodec operations
- // are blocking, but NuPlayer2 needs asynchronous operations.
- mDecoderLooper = new ALooper;
- mDecoderLooper->setName("NP2Decoder");
- mDecoderLooper->start(false, /* runOnCallingThread */
- true, /* canCallJava */
- ANDROID_PRIORITY_AUDIO);
-}
-
-NuPlayer2::DecoderBase::~DecoderBase() {
- stopLooper();
-}
-
-static
-status_t PostAndAwaitResponse(
- const sp<AMessage> &msg, sp<AMessage> *response) {
- status_t err = msg->postAndAwaitResponse(response);
-
- if (err != OK) {
- return err;
- }
-
- if (!(*response)->findInt32("err", &err)) {
- err = OK;
- }
-
- return err;
-}
-
-void NuPlayer2::DecoderBase::configure(const sp<AMessage> &format) {
- sp<AMessage> msg = new AMessage(kWhatConfigure, this);
- msg->setMessage("format", format);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::init() {
- mDecoderLooper->registerHandler(this);
-}
-
-void NuPlayer2::DecoderBase::stopLooper() {
- mDecoderLooper->unregisterHandler(id());
- mDecoderLooper->stop();
-}
-
-void NuPlayer2::DecoderBase::setParameters(const sp<AMessage> ¶ms) {
- sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
- msg->setMessage("params", params);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::setRenderer(const sp<Renderer> &renderer) {
- sp<AMessage> msg = new AMessage(kWhatSetRenderer, this);
- msg->setObject("renderer", renderer);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::pause() {
- sp<AMessage> msg = new AMessage(kWhatPause, this);
-
- sp<AMessage> response;
- PostAndAwaitResponse(msg, &response);
-}
-
-void NuPlayer2::DecoderBase::signalFlush() {
- (new AMessage(kWhatFlush, this))->post();
-}
-
-void NuPlayer2::DecoderBase::signalResume(bool notifyComplete) {
- sp<AMessage> msg = new AMessage(kWhatResume, this);
- msg->setInt32("notifyComplete", notifyComplete);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::initiateShutdown() {
- (new AMessage(kWhatShutdown, this))->post();
-}
-
-void NuPlayer2::DecoderBase::onRequestInputBuffers() {
- if (mRequestInputBuffersPending) {
- return;
- }
-
- // doRequestBuffers() return true if we should request more data
- if (doRequestBuffers()) {
- mRequestInputBuffersPending = true;
-
- sp<AMessage> msg = new AMessage(kWhatRequestInputBuffers, this);
- msg->post(10 * 1000LL);
- }
-}
-
-void NuPlayer2::DecoderBase::onMessageReceived(const sp<AMessage> &msg) {
-
- switch (msg->what()) {
- case kWhatConfigure:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
- onConfigure(format);
- break;
- }
-
- case kWhatSetParameters:
- {
- sp<AMessage> params;
- CHECK(msg->findMessage("params", ¶ms));
- onSetParameters(params);
- break;
- }
-
- case kWhatSetRenderer:
- {
- sp<RefBase> obj;
- CHECK(msg->findObject("renderer", &obj));
- onSetRenderer(static_cast<Renderer *>(obj.get()));
- break;
- }
-
- case kWhatPause:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- mPaused = true;
-
- (new AMessage)->postReply(replyID);
- break;
- }
-
- case kWhatRequestInputBuffers:
- {
- mRequestInputBuffersPending = false;
- onRequestInputBuffers();
- break;
- }
-
- case kWhatFlush:
- {
- onFlush();
- break;
- }
-
- case kWhatResume:
- {
- int32_t notifyComplete;
- CHECK(msg->findInt32("notifyComplete", ¬ifyComplete));
-
- onResume(notifyComplete);
- break;
- }
-
- case kWhatShutdown:
- {
- onShutdown(true);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::DecoderBase::handleError(int32_t err)
-{
- // We cannot immediately release the codec due to buffers still outstanding
- // in the renderer. We signal to the player the error so it can shutdown/release the
- // decoder after flushing and increment the generation to discard unnecessary messages.
-
- ++mBufferGeneration;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatError);
- notify->setInt32("err", err);
- notify->post();
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
deleted file mode 100644
index 1e57f0d..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_BASE_H_
-
-#define NUPLAYER2_DECODER_BASE_H_
-
-#include "NuPlayer2.h"
-
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct ABuffer;
-struct ANativeWindowWrapper;
-struct MediaCodec;
-class MediaBuffer;
-class MediaCodecBuffer;
-
-struct NuPlayer2::DecoderBase : public AHandler {
- explicit DecoderBase(const sp<AMessage> ¬ify);
-
- void configure(const sp<AMessage> &format);
- void init();
- void setParameters(const sp<AMessage> ¶ms);
-
- // Synchronous call to ensure decoder will not request or send out data.
- void pause();
-
- void setRenderer(const sp<Renderer> &renderer);
- virtual status_t setVideoSurface(const sp<ANativeWindowWrapper> &) { return INVALID_OPERATION; }
-
- void signalFlush();
- void signalResume(bool notifyComplete);
- void initiateShutdown();
-
- virtual sp<AMessage> getStats() const {
- return mStats;
- }
-
- virtual status_t releaseCrypto() {
- return INVALID_OPERATION;
- }
-
- enum {
- kWhatInputDiscontinuity = 'inDi',
- kWhatVideoSizeChanged = 'viSC',
- kWhatFlushCompleted = 'flsC',
- kWhatShutdownCompleted = 'shDC',
- kWhatResumeCompleted = 'resC',
- kWhatEOS = 'eos ',
- kWhatError = 'err ',
- };
-
-protected:
-
- virtual ~DecoderBase();
-
- void stopLooper();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format) = 0;
- virtual void onSetParameters(const sp<AMessage> ¶ms) = 0;
- virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
- virtual void onResume(bool notifyComplete) = 0;
- virtual void onFlush() = 0;
- virtual void onShutdown(bool notifyComplete) = 0;
-
- void onRequestInputBuffers();
- virtual bool doRequestBuffers() = 0;
- virtual void handleError(int32_t err);
-
- sp<AMessage> mNotify;
- int32_t mBufferGeneration;
- bool mPaused;
- sp<AMessage> mStats;
-
-private:
- enum {
- kWhatConfigure = 'conf',
- kWhatSetParameters = 'setP',
- kWhatSetRenderer = 'setR',
- kWhatPause = 'paus',
- kWhatRequestInputBuffers = 'reqB',
- kWhatFlush = 'flus',
- kWhatShutdown = 'shuD',
- };
-
- sp<ALooper> mDecoderLooper;
- bool mRequestInputBuffersPending;
-
- DISALLOW_EVIL_CONSTRUCTORS(DecoderBase);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_BASE_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
deleted file mode 100644
index 0514e88..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2DecoderPassThrough"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2DecoderPassThrough.h"
-
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include "ATSParser.h"
-
-namespace android {
-
-// TODO optimize buffer size for power consumption
-// The offload read buffer size is 32 KB but 24 KB uses less power.
-static const size_t kAggregateBufferSizeBytes = 24 * 1024;
-static const size_t kMaxCachedBytes = 200000;
-
-NuPlayer2::DecoderPassThrough::DecoderPassThrough(
- const sp<AMessage> ¬ify,
- const sp<Source> &source,
- const sp<Renderer> &renderer)
- : DecoderBase(notify),
- mSource(source),
- mRenderer(renderer),
- mSkipRenderingUntilMediaTimeUs(-1LL),
- mReachedEOS(true),
- mPendingAudioErr(OK),
- mPendingBuffersToDrain(0),
- mCachedBytes(0),
- mComponentName("pass through decoder") {
- ALOGW_IF(renderer == NULL, "expect a non-NULL renderer");
-}
-
-NuPlayer2::DecoderPassThrough::~DecoderPassThrough() {
-}
-
-void NuPlayer2::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
- ALOGV("[%s] onConfigure", mComponentName.c_str());
- mCachedBytes = 0;
- mPendingBuffersToDrain = 0;
- mReachedEOS = false;
- ++mBufferGeneration;
-
- onRequestInputBuffers();
-
- int32_t hasVideo = 0;
- format->findInt32("has-video", &hasVideo);
-
- // The audio sink is already opened before the PassThrough decoder is created.
- // Opening again might be relevant if decoder is instantiated after shutdown and
- // format is different.
- status_t err = mRenderer->openAudioSink(
- format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE /* flags */, NULL /* isOffloaded */, mSource->isStreaming());
- if (err != OK) {
- handleError(err);
- }
-}
-
-void NuPlayer2::DecoderPassThrough::onSetParameters(const sp<AMessage> &/*params*/) {
- ALOGW("onSetParameters() called unexpectedly");
-}
-
-void NuPlayer2::DecoderPassThrough::onSetRenderer(
- const sp<Renderer> &renderer) {
- // renderer can't be changed during offloading
- ALOGW_IF(renderer != mRenderer,
- "ignoring request to change renderer");
-}
-
-bool NuPlayer2::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- return generation != mBufferGeneration;
-}
-
-bool NuPlayer2::DecoderPassThrough::isDoneFetching() const {
- ALOGV("[%s] mCachedBytes = %zu, mReachedEOS = %d mPaused = %d",
- mComponentName.c_str(), mCachedBytes, mReachedEOS, mPaused);
-
- return mCachedBytes >= kMaxCachedBytes || mReachedEOS || mPaused;
-}
-
-/*
- * returns true if we should request more data
- */
-bool NuPlayer2::DecoderPassThrough::doRequestBuffers() {
- status_t err = OK;
- while (!isDoneFetching()) {
- sp<AMessage> msg = new AMessage();
-
- err = fetchInputData(msg);
- if (err != OK) {
- break;
- }
-
- onInputBufferFetched(msg);
- }
-
- return err == -EWOULDBLOCK
- && mSource->feedMoreTSData() == OK;
-}
-
-status_t NuPlayer2::DecoderPassThrough::dequeueAccessUnit(sp<ABuffer> *accessUnit) {
- status_t err;
-
- // Did we save an accessUnit earlier because of a discontinuity?
- if (mPendingAudioAccessUnit != NULL) {
- *accessUnit = mPendingAudioAccessUnit;
- mPendingAudioAccessUnit.clear();
- err = mPendingAudioErr;
- ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit");
- } else {
- err = mSource->dequeueAccessUnit(true /* audio */, accessUnit);
- }
-
- if (err == INFO_DISCONTINUITY || err == ERROR_END_OF_STREAM) {
- if (mAggregateBuffer != NULL) {
- // We already have some data so save this for later.
- mPendingAudioErr = err;
- mPendingAudioAccessUnit = *accessUnit;
- (*accessUnit).clear();
- ALOGD("return aggregated buffer and save err(=%d) for later", err);
- err = OK;
- }
- }
-
- return err;
-}
-
-sp<ABuffer> NuPlayer2::DecoderPassThrough::aggregateBuffer(
- const sp<ABuffer> &accessUnit) {
- sp<ABuffer> aggregate;
-
- if (accessUnit == NULL) {
- // accessUnit is saved to mPendingAudioAccessUnit
- // return current mAggregateBuffer
- aggregate = mAggregateBuffer;
- mAggregateBuffer.clear();
- return aggregate;
- }
-
- size_t smallSize = accessUnit->size();
- if ((mAggregateBuffer == NULL)
- // Don't bother if only room for a few small buffers.
- && (smallSize < (kAggregateBufferSizeBytes / 3))) {
- // Create a larger buffer for combining smaller buffers from the extractor.
- mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
- mAggregateBuffer->setRange(0, 0); // start empty
- }
-
- if (mAggregateBuffer != NULL) {
- int64_t timeUs;
- int64_t dummy;
- bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
- bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
- // Will the smaller buffer fit?
- size_t bigSize = mAggregateBuffer->size();
- size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
- // Should we save this small buffer for the next big buffer?
- // If the first small buffer did not have a timestamp then save
- // any buffer that does have a timestamp until the next big buffer.
- if ((smallSize > roomLeft)
- || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
- mPendingAudioErr = OK;
- mPendingAudioAccessUnit = accessUnit;
- aggregate = mAggregateBuffer;
- mAggregateBuffer.clear();
- } else {
- // Grab time from first small buffer if available.
- if ((bigSize == 0) && smallTimestampValid) {
- mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
- }
- // Append small buffer to the bigger buffer.
- memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
- bigSize += smallSize;
- mAggregateBuffer->setRange(0, bigSize);
-
- ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
- smallSize, bigSize, mAggregateBuffer->capacity());
- }
- } else {
- // decided not to aggregate
- aggregate = accessUnit;
- }
-
- return aggregate;
-}
-
-status_t NuPlayer2::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) {
- sp<ABuffer> accessUnit;
-
- do {
- status_t err = dequeueAccessUnit(&accessUnit);
-
- if (err == -EWOULDBLOCK) {
- // Flush out the aggregate buffer to try to avoid underrun.
- accessUnit = aggregateBuffer(NULL /* accessUnit */);
- if (accessUnit != NULL) {
- break;
- }
- return err;
- } else if (err != OK) {
- if (err == INFO_DISCONTINUITY) {
- int32_t type;
- CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
-
- bool formatChange =
- (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
-
- bool timeChange =
- (type & ATSParser::DISCONTINUITY_TIME) != 0;
-
- ALOGI("audio discontinuity (formatChange=%d, time=%d)",
- formatChange, timeChange);
-
- if (formatChange || timeChange) {
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatInputDiscontinuity);
- // will perform seamless format change,
- // only notify NuPlayer2 to scan sources
- msg->setInt32("formatChange", false);
- msg->post();
- }
-
- if (timeChange) {
- doFlush(false /* notifyComplete */);
- err = OK;
- } else if (formatChange) {
- // do seamless format change
- err = OK;
- } else {
- // This stream is unaffected by the discontinuity
- return -EWOULDBLOCK;
- }
- }
-
- reply->setInt32("err", err);
- return OK;
- }
-
- accessUnit = aggregateBuffer(accessUnit);
- } while (accessUnit == NULL);
-
-#if 0
- int64_t mediaTimeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("feeding audio input buffer at media time %.2f secs",
- mediaTimeUs / 1E6);
-#endif
-
- reply->setBuffer("buffer", accessUnit);
-
- return OK;
-}
-
-void NuPlayer2::DecoderPassThrough::onInputBufferFetched(
- const sp<AMessage> &msg) {
- if (mReachedEOS) {
- return;
- }
-
- sp<ABuffer> buffer;
- bool hasBuffer = msg->findBuffer("buffer", &buffer);
- if (buffer == NULL) {
- int32_t streamErr = ERROR_END_OF_STREAM;
- CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
- if (streamErr == OK) {
- return;
- }
-
- if (streamErr != ERROR_END_OF_STREAM) {
- handleError(streamErr);
- }
- mReachedEOS = true;
- if (mRenderer != NULL) {
- mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
- }
- return;
- }
-
- sp<AMessage> extra;
- if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
- int64_t resumeAtMediaTimeUs;
- if (extra->findInt64(
- "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
- ALOGI("[%s] suppressing rendering until %lld us",
- mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
- mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
- }
- }
-
- int32_t bufferSize = buffer->size();
- mCachedBytes += bufferSize;
-
- int64_t timeUs = 0;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- if (mSkipRenderingUntilMediaTimeUs >= 0) {
- if (timeUs < mSkipRenderingUntilMediaTimeUs) {
- ALOGV("[%s] dropping buffer at time %lld as requested.",
- mComponentName.c_str(), (long long)timeUs);
-
- onBufferConsumed(bufferSize);
- return;
- }
-
- mSkipRenderingUntilMediaTimeUs = -1;
- }
-
- if (mRenderer == NULL) {
- onBufferConsumed(bufferSize);
- return;
- }
-
- sp<AMessage> reply = new AMessage(kWhatBufferConsumed, this);
- reply->setInt32("generation", mBufferGeneration);
- reply->setInt32("size", bufferSize);
-
- sp<MediaCodecBuffer> mcBuffer = new MediaCodecBuffer(nullptr, buffer);
- mcBuffer->meta()->setInt64("timeUs", timeUs);
-
- mRenderer->queueBuffer(true /* audio */, mcBuffer, reply);
-
- ++mPendingBuffersToDrain;
- ALOGV("onInputBufferFilled: #ToDrain = %zu, cachedBytes = %zu",
- mPendingBuffersToDrain, mCachedBytes);
-}
-
-void NuPlayer2::DecoderPassThrough::onBufferConsumed(int32_t size) {
- --mPendingBuffersToDrain;
- mCachedBytes -= size;
- ALOGV("onBufferConsumed: #ToDrain = %zu, cachedBytes = %zu",
- mPendingBuffersToDrain, mCachedBytes);
- onRequestInputBuffers();
-}
-
-void NuPlayer2::DecoderPassThrough::onResume(bool notifyComplete) {
- mPaused = false;
-
- onRequestInputBuffers();
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeCompleted);
- notify->post();
- }
-}
-
-void NuPlayer2::DecoderPassThrough::doFlush(bool notifyComplete) {
- ++mBufferGeneration;
- mSkipRenderingUntilMediaTimeUs = -1;
- mPendingAudioAccessUnit.clear();
- mPendingAudioErr = OK;
- mAggregateBuffer.clear();
-
- if (mRenderer != NULL) {
- mRenderer->flush(true /* audio */, notifyComplete);
- mRenderer->signalTimeDiscontinuity();
- }
-
- mPendingBuffersToDrain = 0;
- mCachedBytes = 0;
- mReachedEOS = false;
-}
-
-void NuPlayer2::DecoderPassThrough::onFlush() {
- doFlush(true /* notifyComplete */);
-
- mPaused = true;
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
-
-}
-
-void NuPlayer2::DecoderPassThrough::onShutdown(bool notifyComplete) {
- ++mBufferGeneration;
- mSkipRenderingUntilMediaTimeUs = -1;
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatShutdownCompleted);
- notify->post();
- }
-
- mReachedEOS = true;
-}
-
-void NuPlayer2::DecoderPassThrough::onMessageReceived(const sp<AMessage> &msg) {
- ALOGV("[%s] onMessage: %s", mComponentName.c_str(),
- msg->debugString().c_str());
-
- switch (msg->what()) {
- case kWhatBufferConsumed:
- {
- if (!isStaleReply(msg)) {
- int32_t size;
- CHECK(msg->findInt32("size", &size));
- onBufferConsumed(size);
- }
- break;
- }
-
- default:
- DecoderBase::onMessageReceived(msg);
- break;
- }
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
deleted file mode 100644
index 838c60a..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_PASS_THROUGH_H_
-
-#define NUPLAYER2_DECODER_PASS_THROUGH_H_
-
-#include "NuPlayer2.h"
-
-#include "NuPlayer2DecoderBase.h"
-
-namespace android {
-
-struct NuPlayer2::DecoderPassThrough : public DecoderBase {
- DecoderPassThrough(const sp<AMessage> ¬ify,
- const sp<Source> &source,
- const sp<Renderer> &renderer);
-
-protected:
-
- virtual ~DecoderPassThrough();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format);
- virtual void onSetParameters(const sp<AMessage> ¶ms);
- virtual void onSetRenderer(const sp<Renderer> &renderer);
- virtual void onResume(bool notifyComplete);
- virtual void onFlush();
- virtual void onShutdown(bool notifyComplete);
- virtual bool doRequestBuffers();
-
-private:
- enum {
- kWhatBufferConsumed = 'bufC',
- };
-
- sp<Source> mSource;
- sp<Renderer> mRenderer;
- int64_t mSkipRenderingUntilMediaTimeUs;
-
- bool mReachedEOS;
-
- // Used by feedDecoderInputData to aggregate small buffers into
- // one large buffer.
- sp<ABuffer> mPendingAudioAccessUnit;
- status_t mPendingAudioErr;
- sp<ABuffer> mAggregateBuffer;
-
- // mPendingBuffersToDrain are only for debugging. It can be removed
- // when the power investigation is done.
- size_t mPendingBuffersToDrain;
- size_t mCachedBytes;
- AString mComponentName;
-
- bool isStaleReply(const sp<AMessage> &msg);
- bool isDoneFetching() const;
-
- status_t dequeueAccessUnit(sp<ABuffer> *accessUnit);
- sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit);
- status_t fetchInputData(sp<AMessage> &reply);
- void doFlush(bool notifyComplete);
-
- void onInputBufferFetched(const sp<AMessage> &msg);
- void onBufferConsumed(int32_t size);
-
- DISALLOW_EVIL_CONSTRUCTORS(DecoderPassThrough);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_PASS_THROUGH_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
deleted file mode 100644
index 1876496..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Driver"
-#include <inttypes.h>
-#include <android-base/macros.h>
-#include <utils/Log.h>
-#include <cutils/properties.h>
-
-#include "NuPlayer2Driver.h"
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include <media/DataSourceDesc.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include <media/IMediaAnalyticsService.h>
-
-using google::protobuf::RepeatedPtrField;
-using android::media::MediaPlayer2Proto::Value;
-
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleepUs = 20000;
-
-namespace android {
-
-struct PlayerMessageWrapper : public RefBase {
- static sp<PlayerMessageWrapper> Create(const PlayerMessage *p) {
- if (p != NULL) {
- sp<PlayerMessageWrapper> pw = new PlayerMessageWrapper();
- pw->copyFrom(p);
- return pw;
- }
- return NULL;
- }
-
- const PlayerMessage *getPlayerMessage() {
- return mPlayerMessage;
- }
-
-protected:
- virtual ~PlayerMessageWrapper() {
- if (mPlayerMessage != NULL) {
- delete mPlayerMessage;
- }
- }
-
-private:
- PlayerMessageWrapper()
- : mPlayerMessage(NULL) { }
-
- void copyFrom(const PlayerMessage *p) {
- if (mPlayerMessage == NULL) {
- mPlayerMessage = new PlayerMessage;
- }
- mPlayerMessage->CopyFrom(*p);
- }
-
- PlayerMessage *mPlayerMessage;
-};
-
-// key for media statistics
-static const char *kKeyPlayer = "nuplayer2";
-// attrs for media statistics
- // NB: these are matched with public Java API constants defined
- // in frameworks/base/media/java/android/media/MediaPlayer2.java
- // These must be kept synchronized with the constants there.
-static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
-static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
-static const char *kPlayerWidth = "android.media.mediaplayer.width";
-static const char *kPlayerHeight = "android.media.mediaplayer.height";
-static const char *kPlayerFrames = "android.media.mediaplayer.frames";
-static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
-static const char *kPlayerFrameRate = "android.media.mediaplayer.fps";
-static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
-static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
-static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
-static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
-static const char *kPlayerError = "android.media.mediaplayer.err";
-static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
-
-// NB: These are not yet exposed as public Java API constants.
-static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
-static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
-//
-static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
-static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
-static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
-
-static const char *kPlayerVersion = "android.media.mediaplayer.version";
-
-
-NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context)
- : mState(STATE_IDLE),
- mAsyncResult(UNKNOWN_ERROR),
- mSrcId(0),
- mSetSurfaceInProgress(false),
- mDurationUs(-1),
- mPositionUs(-1),
- mSeekInProgress(false),
- mPlayingTimeUs(0),
- mRebufferingTimeUs(0),
- mRebufferingEvents(0),
- mRebufferingAtExit(false),
- mLooper(new ALooper),
- mNuPlayer2Looper(new ALooper),
- mMediaClock(new MediaClock),
- mPlayer(new NuPlayer2(pid, uid, mMediaClock, context)),
- mPlayerFlags(0),
- mMetricsHandle(0),
- mPlayerVersion(0),
- mClientUid(uid),
- mAtEOS(false),
- mLooping(false),
- mAutoLoop(false) {
- ALOGD("NuPlayer2Driver(%p) created, clientPid(%d)", this, pid);
- mLooper->setName("NuPlayer2Driver Looper");
- mNuPlayer2Looper->setName("NuPlayer2 Looper");
-
- mMediaClock->init();
-
- // XXX: what version are we?
- // Ideally, this ticks with the apk version info for the APEX packaging
-
- // set up media metrics record
- mMetricsHandle = mediametrics_create(kKeyPlayer);
- mediametrics_setUid(mMetricsHandle, mClientUid);
- mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
-
- mNuPlayer2Looper->start(
- false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_AUDIO);
-
- mNuPlayer2Looper->registerHandler(mPlayer);
-
- mPlayer->setDriver(this);
-}
-
-NuPlayer2Driver::~NuPlayer2Driver() {
- ALOGV("~NuPlayer2Driver(%p)", this);
- mNuPlayer2Looper->stop();
- mLooper->stop();
-
- // finalize any pending metrics, usually a no-op.
- updateMetrics("destructor");
- logMetrics("destructor");
-
- mediametrics_delete(mMetricsHandle);
-}
-
-status_t NuPlayer2Driver::initCheck() {
- mLooper->start(
- false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_AUDIO);
-
- mLooper->registerHandler(this);
- return OK;
-}
-
-status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
- ALOGV("setDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- if (mState != STATE_IDLE) {
- return INVALID_OPERATION;
- }
-
- mSrcId = dsd->mId;
- mState = STATE_SET_DATASOURCE_PENDING;
-
- mPlayer->setDataSourceAsync(dsd);
-
- while (mState == STATE_SET_DATASOURCE_PENDING) {
- mCondition.wait(mLock);
- }
-
- return mAsyncResult;
-}
-
-status_t NuPlayer2Driver::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
- ALOGV("prepareNextDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- mPlayer->prepareNextDataSourceAsync(dsd);
-
- return OK;
-}
-
-status_t NuPlayer2Driver::playNextDataSource(int64_t srcId) {
- ALOGV("playNextDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- mSrcId = srcId;
- mPlayer->playNextDataSource(srcId);
-
- return OK;
-}
-
-status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
- ALOGV("setVideoSurfaceTexture(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- if (mSetSurfaceInProgress) {
- return INVALID_OPERATION;
- }
-
- switch (mState) {
- case STATE_SET_DATASOURCE_PENDING:
- case STATE_RESET_IN_PROGRESS:
- return INVALID_OPERATION;
-
- default:
- break;
- }
-
- mSetSurfaceInProgress = true;
-
- mPlayer->setVideoSurfaceTextureAsync(nww);
-
- while (mSetSurfaceInProgress) {
- mCondition.wait(mLock);
- }
-
- return OK;
-}
-
-status_t NuPlayer2Driver::getBufferingSettings(BufferingSettings* buffering) {
- ALOGV("getBufferingSettings(%p)", this);
- {
- Mutex::Autolock autoLock(mLock);
- if (mState == STATE_IDLE) {
- return INVALID_OPERATION;
- }
- }
-
- return mPlayer->getBufferingSettings(buffering);
-}
-
-status_t NuPlayer2Driver::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings(%p)", this);
- {
- Mutex::Autolock autoLock(mLock);
- if (mState == STATE_IDLE) {
- return INVALID_OPERATION;
- }
- }
-
- return mPlayer->setBufferingSettings(buffering);
-}
-
-status_t NuPlayer2Driver::prepareAsync() {
- ALOGV("prepareAsync(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_UNPREPARED:
- mState = STATE_PREPARING;
- mPlayer->prepareAsync();
- return OK;
- default:
- return INVALID_OPERATION;
- };
-}
-
-status_t NuPlayer2Driver::start() {
- ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
- Mutex::Autolock autoLock(mLock);
- return start_l();
-}
-
-status_t NuPlayer2Driver::start_l() {
- switch (mState) {
- case STATE_PAUSED:
- case STATE_PREPARED:
- {
- mPlayer->start();
- FALLTHROUGH_INTENDED;
- }
-
- case STATE_RUNNING:
- {
- if (mAtEOS) {
- mPlayer->rewind();
- mAtEOS = false;
- mPositionUs = -1;
- }
- break;
- }
-
- default:
- return INVALID_OPERATION;
- }
-
- mState = STATE_RUNNING;
-
- return OK;
-}
-
-status_t NuPlayer2Driver::pause() {
- ALOGD("pause(%p)", this);
- // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
- // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
- // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
- // getCurrentPosition here.
- int64_t unused;
- getCurrentPosition(&unused);
-
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_PAUSED:
- return OK;
-
- case STATE_PREPARED:
- case STATE_RUNNING:
- mState = STATE_PAUSED;
- mPlayer->pause();
- break;
-
- default:
- return INVALID_OPERATION;
- }
-
- return OK;
-}
-
-bool NuPlayer2Driver::isPlaying() {
- return mState == STATE_RUNNING && !mAtEOS;
-}
-
-status_t NuPlayer2Driver::setPlaybackSettings(const AudioPlaybackRate &rate) {
- status_t err = mPlayer->setPlaybackSettings(rate);
- if (err == OK) {
- // try to update position
- int64_t unused;
- getCurrentPosition(&unused);
- }
- return err;
-}
-
-status_t NuPlayer2Driver::getPlaybackSettings(AudioPlaybackRate *rate) {
- return mPlayer->getPlaybackSettings(rate);
-}
-
-status_t NuPlayer2Driver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- return mPlayer->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t NuPlayer2Driver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
- return mPlayer->getSyncSettings(sync, videoFps);
-}
-
-status_t NuPlayer2Driver::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
- ALOGD("seekTo(%p) (%lld ms, %d) at state %d", this, (long long)msec, mode, mState);
- Mutex::Autolock autoLock(mLock);
-
- int64_t seekTimeUs = msec * 1000LL;
-
- switch (mState) {
- case STATE_PREPARED:
- case STATE_PAUSED:
- case STATE_RUNNING:
- {
- mAtEOS = false;
- mSeekInProgress = true;
- mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
- break;
- }
-
- default:
- return INVALID_OPERATION;
- }
-
- mPositionUs = seekTimeUs;
- return OK;
-}
-
-status_t NuPlayer2Driver::getCurrentPosition(int64_t *msec) {
- int64_t tempUs = 0;
- {
- Mutex::Autolock autoLock(mLock);
- if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
- tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
- *msec = divRound(tempUs, (int64_t)(1000));
- return OK;
- }
- }
-
- status_t ret = mPlayer->getCurrentPosition(&tempUs);
-
- Mutex::Autolock autoLock(mLock);
- // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
- // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
- // position value that's different the seek to position.
- if (ret != OK) {
- tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
- } else {
- mPositionUs = tempUs;
- }
- *msec = divRound(tempUs, (int64_t)(1000));
- return OK;
-}
-
-status_t NuPlayer2Driver::getDuration(int64_t *msec) {
- Mutex::Autolock autoLock(mLock);
-
- if (mDurationUs < 0) {
- return UNKNOWN_ERROR;
- }
-
- *msec = (mDurationUs + 500LL) / 1000;
-
- return OK;
-}
-
-void NuPlayer2Driver::updateMetrics(const char *where) {
- if (where == NULL) {
- where = "unknown";
- }
- ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
-
- // gather the final stats for this record
- Vector<sp<AMessage>> trackStats;
- mPlayer->getStats(&trackStats);
-
- if (trackStats.size() > 0) {
- for (size_t i = 0; i < trackStats.size(); ++i) {
- const sp<AMessage> &stats = trackStats.itemAt(i);
-
- AString mime;
- stats->findString("mime", &mime);
-
- AString name;
- stats->findString("component-name", &name);
-
- if (mime.startsWith("video/")) {
- int32_t width, height;
- mediametrics_setCString(mMetricsHandle, kPlayerVMime, mime.c_str());
- if (!name.empty()) {
- mediametrics_setCString(mMetricsHandle, kPlayerVCodec, name.c_str());
- }
-
- if (stats->findInt32("width", &width)
- && stats->findInt32("height", &height)) {
- mediametrics_setInt32(mMetricsHandle, kPlayerWidth, width);
- mediametrics_setInt32(mMetricsHandle, kPlayerHeight, height);
- }
-
- int64_t numFramesTotal = 0;
- int64_t numFramesDropped = 0;
- stats->findInt64("frames-total", &numFramesTotal);
- stats->findInt64("frames-dropped-output", &numFramesDropped);
-
- mediametrics_setInt64(mMetricsHandle, kPlayerFrames, numFramesTotal);
- mediametrics_setInt64(mMetricsHandle, kPlayerFramesDropped, numFramesDropped);
-
- float frameRate = 0;
- if (stats->findFloat("frame-rate-output", &frameRate)) {
- mediametrics_setInt64(mMetricsHandle, kPlayerFrameRate, frameRate);
- }
-
- } else if (mime.startsWith("audio/")) {
- mediametrics_setCString(mMetricsHandle, kPlayerAMime, mime.c_str());
- if (!name.empty()) {
- mediametrics_setCString(mMetricsHandle, kPlayerACodec, name.c_str());
- }
- }
- }
- }
-
- // always provide duration and playing time, even if they have 0/unknown values.
-
- // getDuration() uses mLock for mutex -- careful where we use it.
- int64_t duration_ms = -1;
- getDuration(&duration_ms);
- mediametrics_setInt64(mMetricsHandle, kPlayerDuration, duration_ms);
-
- mediametrics_setInt64(mMetricsHandle, kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
-
- if (mRebufferingEvents != 0) {
- mediametrics_setInt64(mMetricsHandle, kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
- mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingCount, mRebufferingEvents);
- mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingAtExit, mRebufferingAtExit);
- }
-
- mediametrics_setCString(mMetricsHandle, kPlayerDataSourceType, mPlayer->getDataSourceType());
-}
-
-
-void NuPlayer2Driver::logMetrics(const char *where) {
- if (where == NULL) {
- where = "unknown";
- }
- ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
-
- if (mMetricsHandle == 0 || mediametrics_isEnabled() == false) {
- return;
- }
-
- // log only non-empty records
- // we always updateMetrics() before we get here
- // and that always injects 3 fields (duration, playing time, and
- // datasource) into the record.
- // So the canonical "empty" record has 3 elements in it.
- if (mediametrics_count(mMetricsHandle) > 3) {
- mediametrics_selfRecord(mMetricsHandle);
- // re-init in case we prepare() and start() again.
- mediametrics_delete(mMetricsHandle);
- mMetricsHandle = mediametrics_create(kKeyPlayer);
- mediametrics_setUid(mMetricsHandle, mClientUid);
- mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
- } else {
- ALOGV("did not have anything to record");
- }
-}
-
-status_t NuPlayer2Driver::reset() {
- ALOGD("reset(%p) at state %d", this, mState);
-
- updateMetrics("reset");
- logMetrics("reset");
-
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_IDLE:
- return OK;
-
- case STATE_SET_DATASOURCE_PENDING:
- case STATE_RESET_IN_PROGRESS:
- return INVALID_OPERATION;
-
- case STATE_PREPARING:
- {
- notifyListener_l(mSrcId, MEDIA2_PREPARED);
- break;
- }
-
- default:
- break;
- }
-
- mState = STATE_RESET_IN_PROGRESS;
- mPlayer->resetAsync();
-
- while (mState == STATE_RESET_IN_PROGRESS) {
- mCondition.wait(mLock);
- }
-
- mDurationUs = -1;
- mPositionUs = -1;
- mLooping = false;
- mPlayingTimeUs = 0;
- mRebufferingTimeUs = 0;
- mRebufferingEvents = 0;
- mRebufferingAtExit = false;
-
- return OK;
-}
-
-status_t NuPlayer2Driver::notifyAt(int64_t mediaTimeUs) {
- ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
- return mPlayer->notifyAt(mediaTimeUs);
-}
-
-status_t NuPlayer2Driver::setLooping(int loop) {
- mLooping = loop != 0;
- return OK;
-}
-
-status_t NuPlayer2Driver::invoke(const PlayerMessage &request, PlayerMessage *response) {
- if (response == NULL) {
- ALOGE("reply is a NULL pointer");
- return BAD_VALUE;
- }
-
- RepeatedPtrField<const Value>::const_iterator it = request.values().cbegin();
- int32_t methodId = (it++)->int32_value();
-
- switch (methodId) {
- case MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE:
- {
- int mode = (it++)->int32_value();
- return mPlayer->setVideoScalingMode(mode);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO:
- {
- int64_t srcId = (it++)->int64_value();
- return mPlayer->getTrackInfo(srcId, response);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int trackIndex = (it++)->int32_value();
- int64_t msec = 0;
- // getCurrentPosition should always return OK
- getCurrentPosition(&msec);
- return mPlayer->selectTrack(srcId, trackIndex, true /* select */, msec * 1000LL);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int trackIndex = (it++)->int32_value();
- return mPlayer->selectTrack(
- srcId, trackIndex, false /* select */, 0xdeadbeef /* not used */);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int32_t type = (it++)->int32_value();
- return mPlayer->getSelectedTrack(srcId, type, response);
- }
-
- default:
- {
- return INVALID_OPERATION;
- }
- }
-}
-
-void NuPlayer2Driver::setAudioSink(const sp<AudioSink> &audioSink) {
- mPlayer->setAudioSink(audioSink);
- mAudioSink = audioSink;
-}
-
-status_t NuPlayer2Driver::setParameter(
- int /* key */, const Parcel & /* request */) {
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2Driver::getParameter(int key __unused, Parcel *reply __unused) {
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2Driver::getMetrics(char **buffer, size_t *length) {
- updateMetrics("api");
- if (mediametrics_getAttributes(mMetricsHandle, buffer, length))
- return OK;
- else
- return FAILED_TRANSACTION;
-}
-
-void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
- ALOGD("notifyResetComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
- mState = STATE_IDLE;
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifySetSurfaceComplete(int64_t /* srcId */) {
- ALOGV("notifySetSurfaceComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- CHECK(mSetSurfaceInProgress);
- mSetSurfaceInProgress = false;
-
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyDuration(int64_t /* srcId */, int64_t durationUs) {
- Mutex::Autolock autoLock(mLock);
- mDurationUs = durationUs;
-}
-
-void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t /* srcId */, int64_t playingUs) {
- Mutex::Autolock autoLock(mLock);
- mPlayingTimeUs += playingUs;
-}
-
-void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t /* srcId */, int64_t rebufferingUs) {
- Mutex::Autolock autoLock(mLock);
- mRebufferingTimeUs += rebufferingUs;
- mRebufferingEvents++;
-}
-
-void NuPlayer2Driver::notifyRebufferingWhenExit(int64_t /* srcId */, bool status) {
- Mutex::Autolock autoLock(mLock);
- mRebufferingAtExit = status;
-}
-
-void NuPlayer2Driver::notifySeekComplete(int64_t srcId) {
- ALOGV("notifySeekComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
- mSeekInProgress = false;
- notifyListener_l(srcId, MEDIA2_SEEK_COMPLETE);
-}
-
-status_t NuPlayer2Driver::dump(
- int fd, const Vector<String16> & /* args */) const {
-
- Vector<sp<AMessage> > trackStats;
- mPlayer->getStats(&trackStats);
-
- AString logString(" NuPlayer2\n");
- char buf[256] = {0};
-
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleepUs);
- }
-
- if (locked) {
- snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
- mState, mAtEOS, mLooping, mAutoLoop);
- mLock.unlock();
- } else {
- snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this);
- }
- logString.append(buf);
-
- for (size_t i = 0; i < trackStats.size(); ++i) {
- const sp<AMessage> &stats = trackStats.itemAt(i);
-
- AString mime;
- if (stats->findString("mime", &mime)) {
- snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str());
- logString.append(buf);
- }
-
- AString name;
- if (stats->findString("component-name", &name)) {
- snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str());
- logString.append(buf);
- }
-
- if (mime.startsWith("video/")) {
- int32_t width, height;
- if (stats->findInt32("width", &width)
- && stats->findInt32("height", &height)) {
- snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height);
- logString.append(buf);
- }
-
- int64_t numFramesTotal = 0;
- int64_t numFramesDropped = 0;
-
- stats->findInt64("frames-total", &numFramesTotal);
- stats->findInt64("frames-dropped-output", &numFramesDropped);
- snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), "
- "percentageDropped(%.2f%%)\n",
- (long long)numFramesTotal,
- (long long)numFramesDropped,
- numFramesTotal == 0
- ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
- logString.append(buf);
- }
- }
-
- ALOGI("%s", logString.c_str());
-
- if (fd >= 0) {
- FILE *out = fdopen(dup(fd), "w");
- fprintf(out, "%s", logString.c_str());
- fclose(out);
- out = NULL;
- }
-
- return OK;
-}
-
-void NuPlayer2Driver::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatNotifyListener: {
- int64_t srcId;
- int32_t msgId;
- int32_t ext1 = 0;
- int32_t ext2 = 0;
- CHECK(msg->findInt64("srcId", &srcId));
- CHECK(msg->findInt32("messageId", &msgId));
- msg->findInt32("ext1", &ext1);
- msg->findInt32("ext2", &ext2);
- sp<PlayerMessageWrapper> in;
- sp<RefBase> obj;
- if (msg->findObject("obj", &obj) && obj != NULL) {
- in = static_cast<PlayerMessageWrapper *>(obj.get());
- }
- sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getPlayerMessage()));
- break;
- }
- default:
- break;
- }
-}
-
-void NuPlayer2Driver::notifyListener(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- Mutex::Autolock autoLock(mLock);
- notifyListener_l(srcId, msg, ext1, ext2, in);
-}
-
-void NuPlayer2Driver::notifyListener_l(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
- this, (long long)srcId, msg, ext1, ext2,
- (in == NULL ? -1 : (int)in->ByteSize()), mAutoLoop, mLooping);
- if (srcId == mSrcId) {
- switch (msg) {
- case MEDIA2_PLAYBACK_COMPLETE:
- {
- if (mState != STATE_RESET_IN_PROGRESS) {
- if (mAutoLoop) {
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
- if (streamType == AUDIO_STREAM_NOTIFICATION) {
- ALOGW("disabling auto-loop for notification");
- mAutoLoop = false;
- }
- }
- if (mLooping || mAutoLoop) {
- mPlayer->rewind();
- if (mAudioSink != NULL) {
- // The renderer has stopped the sink at the end in order to play out
- // the last little bit of audio. In looping mode, we need to restart it.
- mAudioSink->start();
- }
-
- sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
- notify->setInt64("srcId", srcId);
- notify->setInt32("messageId", MEDIA2_INFO);
- notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
- notify->post();
- return;
- }
- if (property_get_bool("persist.debug.sf.stats", false)) {
- Vector<String16> args;
- dump(-1, args);
- }
- mPlayer->pause();
- mState = STATE_PAUSED;
- }
- FALLTHROUGH_INTENDED;
- }
-
- case MEDIA2_ERROR:
- {
- // when we have an error, add it to the analytics for this playback.
- // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
- // [test against msg is due to fall through from previous switch value]
- if (msg == MEDIA2_ERROR) {
- mediametrics_setInt32(mMetricsHandle, kPlayerError, ext1);
- if (ext2 != 0) {
- mediametrics_setInt32(mMetricsHandle, kPlayerErrorCode, ext2);
- }
- mediametrics_setCString(mMetricsHandle, kPlayerErrorState, stateString(mState).c_str());
- }
- mAtEOS = true;
- break;
- }
-
- default:
- break;
- }
- }
-
- sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
- notify->setInt64("srcId", srcId);
- notify->setInt32("messageId", msg);
- notify->setInt32("ext1", ext1);
- notify->setInt32("ext2", ext2);
- notify->setObject("obj", PlayerMessageWrapper::Create((PlayerMessage*)in));
- notify->post();
-}
-
-void NuPlayer2Driver::notifySetDataSourceCompleted(int64_t /* srcId */, status_t err) {
- Mutex::Autolock autoLock(mLock);
-
- CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
-
- mAsyncResult = err;
- mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyPrepareCompleted(int64_t srcId, status_t err) {
- ALOGV("notifyPrepareCompleted %d", err);
-
- Mutex::Autolock autoLock(mLock);
-
- if (srcId != mSrcId) {
- if (err == OK) {
- notifyListener_l(srcId, MEDIA2_PREPARED);
- } else {
- notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
- return;
- }
-
- if (mState != STATE_PREPARING) {
- // We were preparing asynchronously when the client called
- // reset(), we sent a premature "prepared" notification and
- // then initiated the reset. This notification is stale.
- CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
- return;
- }
-
- CHECK_EQ(mState, STATE_PREPARING);
-
- mAsyncResult = err;
-
- if (err == OK) {
- // update state before notifying client, so that if client calls back into NuPlayer2Driver
- // in response, NuPlayer2Driver has the right state
- mState = STATE_PREPARED;
- notifyListener_l(srcId, MEDIA2_PREPARED);
- } else {
- mState = STATE_UNPREPARED;
- notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
-
- sp<MetaData> meta = mPlayer->getFileMeta();
- int32_t loop;
- if (meta != NULL
- && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
- mAutoLoop = true;
- }
-
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyFlagsChanged(int64_t /* srcId */, uint32_t flags) {
- Mutex::Autolock autoLock(mLock);
-
- mPlayerFlags = flags;
-}
-
-// Modular DRM
-status_t NuPlayer2Driver::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
-{
- ALOGV("prepareDrm(%p) state: %d", this, mState);
-
- // leaving the state verification for mediaplayer.cpp
- status_t ret = mPlayer->prepareDrm(srcId, uuid, drmSessionId);
-
- ALOGV("prepareDrm ret: %d", ret);
-
- return ret;
-}
-
-status_t NuPlayer2Driver::releaseDrm(int64_t srcId)
-{
- ALOGV("releaseDrm(%p) state: %d", this, mState);
-
- // leaving the state verification for mediaplayer.cpp
- status_t ret = mPlayer->releaseDrm(srcId);
-
- ALOGV("releaseDrm ret: %d", ret);
-
- return ret;
-}
-
-std::string NuPlayer2Driver::stateString(State state) {
- const char *rval = NULL;
- char rawbuffer[16]; // allows "%d"
-
- switch (state) {
- case STATE_IDLE: rval = "IDLE"; break;
- case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
- case STATE_UNPREPARED: rval = "UNPREPARED"; break;
- case STATE_PREPARING: rval = "PREPARING"; break;
- case STATE_PREPARED: rval = "PREPARED"; break;
- case STATE_RUNNING: rval = "RUNNING"; break;
- case STATE_PAUSED: rval = "PAUSED"; break;
- case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
- default:
- // yes, this buffer is shared and vulnerable to races
- snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
- rval = rawbuffer;
- break;
- }
-
- return rval;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
deleted file mode 100644
index c97e247..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-
-#include <media/MediaMetrics.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-namespace android {
-
-struct ALooper;
-struct MediaClock;
-struct NuPlayer2;
-
-struct NuPlayer2Driver : public MediaPlayer2Interface {
- explicit NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context);
-
- virtual status_t initCheck() override;
-
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t playNextDataSource(int64_t srcId) override;
-
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) override;
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual status_t prepareAsync() override;
- virtual status_t start() override;
- virtual status_t pause() override;
- virtual bool isPlaying() override;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate) override;
- virtual status_t getPlaybackSettings(AudioPlaybackRate *rate) override;
- virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) override;
- virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps) override;
- virtual status_t seekTo(
- int64_t msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
- virtual status_t getCurrentPosition(int64_t *msec) override;
- virtual status_t getDuration(int64_t *msec) override;
- virtual status_t reset() override;
- virtual status_t notifyAt(int64_t mediaTimeUs) override;
- virtual status_t setLooping(int loop) override;
- virtual status_t invoke(const PlayerMessage &request, PlayerMessage *response) override;
- virtual void setAudioSink(const sp<AudioSink> &audioSink) override;
- virtual status_t setParameter(int key, const Parcel &request) override;
- virtual status_t getParameter(int key, Parcel *reply) override;
- virtual status_t getMetrics(char **buf, size_t *length) override;
-
- virtual status_t dump(int fd, const Vector<String16> &args) const override;
-
- virtual void onMessageReceived(const sp<AMessage> &msg) override;
-
- void notifySetDataSourceCompleted(int64_t srcId, status_t err);
- void notifyPrepareCompleted(int64_t srcId, status_t err);
- void notifyResetComplete(int64_t srcId);
- void notifySetSurfaceComplete(int64_t srcId);
- void notifyDuration(int64_t srcId, int64_t durationUs);
- void notifyMorePlayingTimeUs(int64_t srcId, int64_t timeUs);
- void notifyMoreRebufferingTimeUs(int64_t srcId, int64_t timeUs);
- void notifyRebufferingWhenExit(int64_t srcId, bool status);
- void notifySeekComplete(int64_t srcId);
- void notifyListener(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
- const PlayerMessage *in = NULL);
- void notifyFlagsChanged(int64_t srcId, uint32_t flags);
-
- // Modular DRM
- virtual status_t prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
- virtual status_t releaseDrm(int64_t srcId);
-
-protected:
- virtual ~NuPlayer2Driver();
-
-private:
- enum State {
- STATE_IDLE,
- STATE_SET_DATASOURCE_PENDING,
- STATE_UNPREPARED,
- STATE_PREPARING,
- STATE_PREPARED,
- STATE_RUNNING,
- STATE_PAUSED,
- STATE_RESET_IN_PROGRESS,
- };
-
- std::string stateString(State state);
-
- enum {
- kWhatNotifyListener,
- };
-
- mutable Mutex mLock;
- Condition mCondition;
-
- State mState;
-
- status_t mAsyncResult;
-
- // The following are protected through "mLock"
- // >>>
- int64_t mSrcId;
- bool mSetSurfaceInProgress;
- int64_t mDurationUs;
- int64_t mPositionUs;
- bool mSeekInProgress;
- int64_t mPlayingTimeUs;
- int64_t mRebufferingTimeUs;
- int32_t mRebufferingEvents;
- bool mRebufferingAtExit;
- // <<<
-
- sp<ALooper> mLooper;
- sp<ALooper> mNuPlayer2Looper;
- const sp<MediaClock> mMediaClock;
- const sp<NuPlayer2> mPlayer;
- sp<AudioSink> mAudioSink;
- uint32_t mPlayerFlags;
-
- mediametrics_handle_t mMetricsHandle;
- int64_t mPlayerVersion;
- uid_t mClientUid;
-
- bool mAtEOS;
- bool mLooping;
- bool mAutoLoop;
-
- void updateMetrics(const char *where);
- void logMetrics(const char *where);
-
- status_t start_l();
- void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
- const PlayerMessage *in = NULL);
-
- DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2Driver);
-};
-
-} // namespace android
-
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
deleted file mode 100644
index f41a431..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Drm"
-
-#include "NuPlayer2Drm.h"
-
-#include <media/NdkWrapper.h>
-#include <utils/Log.h>
-#include <sstream>
-
-namespace android {
-
-Vector<DrmUUID> NuPlayer2Drm::parsePSSH(const void *pssh, size_t psshsize)
-{
- Vector<DrmUUID> drmSchemes, empty;
- const int DATALEN_SIZE = 4;
-
- // the format of the buffer is 1 or more of:
- // {
- // 16 byte uuid
- // 4 byte data length N
- // N bytes of data
- // }
- // Determine the number of entries in the source data.
- // Since we got the data from stagefright, we trust it is valid and properly formatted.
-
- const uint8_t *data = (const uint8_t*)pssh;
- size_t len = psshsize;
- size_t numentries = 0;
- while (len > 0) {
- if (len < DrmUUID::UUID_SIZE) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- const uint8_t *uuidPtr = data;
-
- // skip uuid
- data += DrmUUID::UUID_SIZE;
- len -= DrmUUID::UUID_SIZE;
-
- // get data length
- if (len < DATALEN_SIZE) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- uint32_t datalen = *((uint32_t*)data);
- data += DATALEN_SIZE;
- len -= DATALEN_SIZE;
-
- if (len < datalen) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- // skip the data
- data += datalen;
- len -= datalen;
-
- DrmUUID _uuid(uuidPtr);
- drmSchemes.add(_uuid);
-
- ALOGV("ParsePSSH[%zu]: %s: %s", numentries,
- _uuid.toHexString().string(),
- DrmUUID::arrayToHex(data, datalen).string()
- );
-
- numentries++;
- }
-
- return drmSchemes;
-}
-
-Vector<DrmUUID> NuPlayer2Drm::getSupportedDrmSchemes(const void *pssh, size_t psshsize)
-{
- Vector<DrmUUID> psshDRMs = parsePSSH(pssh, psshsize);
-
- Vector<DrmUUID> supportedDRMs;
- for (size_t i = 0; i < psshDRMs.size(); i++) {
- DrmUUID uuid = psshDRMs[i];
- if (AMediaDrmWrapper::isCryptoSchemeSupported(uuid.ptr(), NULL)) {
- supportedDRMs.add(uuid);
- }
- }
-
- ALOGV("getSupportedDrmSchemes: psshDRMs: %zu supportedDRMs: %zu",
- psshDRMs.size(), supportedDRMs.size());
-
- return supportedDRMs;
-}
-
-sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(const void *pssh, uint32_t psshsize)
-{
- std::ostringstream buf;
-
- // 1) PSSH bytes
- buf.write(reinterpret_cast<const char *>(&psshsize), sizeof(psshsize));
- buf.write(reinterpret_cast<const char *>(pssh), psshsize);
-
- ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO PSSH: size: %u %s", psshsize,
- DrmUUID::arrayToHex((uint8_t*)pssh, psshsize).string());
-
- // 2) supportedDRMs
- Vector<DrmUUID> supportedDRMs = getSupportedDrmSchemes(pssh, psshsize);
- uint32_t n = supportedDRMs.size();
- buf.write(reinterpret_cast<char *>(&n), sizeof(n));
- for (size_t i = 0; i < n; i++) {
- DrmUUID uuid = supportedDRMs[i];
- buf.write(reinterpret_cast<const char *>(&n), sizeof(n));
- buf.write(reinterpret_cast<const char *>(uuid.ptr()), DrmUUID::UUID_SIZE);
-
- ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO supportedScheme[%zu] %s", i,
- uuid.toHexString().string());
- }
-
- sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(buf.str().c_str(), buf.tellp());
- return drmInfoBuffer;
-}
-
-status_t NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo, PlayerMessage *playerMsg)
-{
- std::ostringstream pssh, drmInfo;
-
- // 0) Generate PSSH bytes
- for (size_t i = 0; i < psshInfo->numentries; i++) {
- PsshEntry *entry = &psshInfo->entries[i];
- uint32_t datalen = entry->datalen;
- pssh.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
- pssh.write(reinterpret_cast<const char *>(&datalen), sizeof(datalen));
- pssh.write(reinterpret_cast<const char *>(entry->data), datalen);
- }
-
- uint32_t psshSize = pssh.tellp();
- std::string psshBase = pssh.str();
- const auto* psshPtr = reinterpret_cast<const uint8_t*>(psshBase.c_str());
- ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO PSSH: size: %u %s", psshSize,
- DrmUUID::arrayToHex(psshPtr, psshSize).string());
-
- // 1) Write PSSH bytes
- playerMsg->add_values()->set_bytes_value(
- reinterpret_cast<const char *>(pssh.str().c_str()), psshSize);
-
- // 2) Write supportedDRMs
- uint32_t numentries = psshInfo->numentries;
- playerMsg->add_values()->set_int32_value(numentries);
- for (size_t i = 0; i < numentries; i++) {
- PsshEntry *entry = &psshInfo->entries[i];
- playerMsg->add_values()->set_bytes_value(
- reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
- ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO supportedScheme[%zu] %s", i,
- DrmUUID::arrayToHex((const uint8_t*)&entry->uuid, sizeof(AMediaUUID)).string());
- }
- return OK;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
deleted file mode 100644
index 968d1be..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DRM_H_
-#define NUPLAYER2_DRM_H_
-
-#include <media/NdkMediaExtractor.h>
-#include <media/stagefright/foundation/ABuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
- struct DrmUUID {
- static const int UUID_SIZE = 16;
-
- DrmUUID() {
- memset(this->uuid, 0, sizeof(uuid));
- }
-
- // to allow defining Vector/KeyedVector of UUID type
- DrmUUID(const DrmUUID &a) {
- memcpy(this->uuid, a.uuid, sizeof(uuid));
- }
-
- // to allow defining Vector/KeyedVector of UUID type
- DrmUUID(const uint8_t uuid_in[UUID_SIZE]) {
- memcpy(this->uuid, uuid_in, sizeof(uuid));
- }
-
- const uint8_t *ptr() const {
- return uuid;
- }
-
- String8 toHexString() const {
- return arrayToHex(uuid, UUID_SIZE);
- }
-
- static String8 toHexString(const uint8_t uuid_in[UUID_SIZE]) {
- return arrayToHex(uuid_in, UUID_SIZE);
- }
-
- static String8 arrayToHex(const uint8_t *array, int bytes) {
- String8 result;
- for (int i = 0; i < bytes; i++) {
- result.appendFormat("%02x", array[i]);
- }
-
- return result;
- }
-
- protected:
- uint8_t uuid[UUID_SIZE];
- };
-
-
- struct NuPlayer2Drm {
-
- // static helpers - internal
-
- protected:
- static Vector<DrmUUID> parsePSSH(const void *pssh, size_t psshsize);
- static Vector<DrmUUID> getSupportedDrmSchemes(const void *pssh, size_t psshsize);
-
- // static helpers - public
-
- public:
- static sp<ABuffer> retrieveDrmInfo(const void *pssh, uint32_t psshsize);
- static status_t retrieveDrmInfo(PsshInfo *, PlayerMessage *);
-
- }; // NuPlayer2Drm
-
-} // android
-
-#endif //NUPLAYER2_DRM_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
deleted file mode 100644
index fd459df..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ /dev/null
@@ -1,2096 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Renderer"
-#include <utils/Log.h>
-
-#include "JWakeLock.h"
-#include "NuPlayer2Renderer.h"
-#include <algorithm>
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaCodecConstants.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/VideoFrameScheduler2.h>
-#include <media/MediaCodecBuffer.h>
-
-#include <inttypes.h>
-
-namespace android {
-
-/*
- * Example of common configuration settings in shell script form
-
- #Turn offload audio off (use PCM for Play Music) -- AudioPolicyManager
- adb shell setprop audio.offload.disable 1
-
- #Allow offload audio with video (requires offloading to be enabled) -- AudioPolicyManager
- adb shell setprop audio.offload.video 1
-
- #Use audio callbacks for PCM data
- adb shell setprop media.stagefright.audio.cbk 1
-
- #Use deep buffer for PCM data with video (it is generally enabled for audio-only)
- adb shell setprop media.stagefright.audio.deep 1
-
- #Set size of buffers for pcm audio sink in msec (example: 1000 msec)
- adb shell setprop media.stagefright.audio.sink 1000
-
- * These configurations take effect for the next track played (not the current track).
- */
-
-static inline bool getUseAudioCallbackSetting() {
- return property_get_bool("media.stagefright.audio.cbk", false /* default_value */);
-}
-
-static inline int32_t getAudioSinkPcmMsSetting() {
- return property_get_int32(
- "media.stagefright.audio.sink", 500 /* default_value */);
-}
-
-// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink
-// is closed to allow the audio DSP to power down.
-static const int64_t kOffloadPauseMaxUs = 10000000LL;
-
-// Maximum allowed delay from AudioSink, 1.5 seconds.
-static const int64_t kMaxAllowedAudioSinkDelayUs = 1500000LL;
-
-static const int64_t kMinimumAudioClockUpdatePeriodUs = 20 /* msec */ * 1000;
-
-// Default video frame display duration when only video exists.
-// Used to set max media time in MediaClock.
-static const int64_t kDefaultVideoFrameIntervalUs = 100000LL;
-
-// static
-const NuPlayer2::Renderer::PcmInfo NuPlayer2::Renderer::AUDIO_PCMINFO_INITIALIZER = {
- AUDIO_CHANNEL_NONE,
- AUDIO_OUTPUT_FLAG_NONE,
- AUDIO_FORMAT_INVALID,
- 0, // mNumChannels
- 0 // mSampleRate
-};
-
-// static
-const int64_t NuPlayer2::Renderer::kMinPositionUpdateDelayUs = 100000LL;
-
-static audio_format_t constexpr audioFormatFromEncoding(int32_t pcmEncoding) {
- switch (pcmEncoding) {
- case kAudioEncodingPcmFloat:
- return AUDIO_FORMAT_PCM_FLOAT;
- case kAudioEncodingPcm16bit:
- return AUDIO_FORMAT_PCM_16_BIT;
- case kAudioEncodingPcm8bit:
- return AUDIO_FORMAT_PCM_8_BIT; // TODO: do we want to support this?
- default:
- ALOGE("%s: Invalid encoding: %d", __func__, pcmEncoding);
- return AUDIO_FORMAT_INVALID;
- }
-}
-
-NuPlayer2::Renderer::Renderer(
- const sp<MediaPlayer2Interface::AudioSink> &sink,
- const sp<MediaClock> &mediaClock,
- const sp<AMessage> ¬ify,
- const sp<JObjectHolder> &context,
- uint32_t flags)
- : mAudioSink(sink),
- mUseVirtualAudioSink(false),
- mNotify(notify),
- mFlags(flags),
- mNumFramesWritten(0),
- mDrainAudioQueuePending(false),
- mDrainVideoQueuePending(false),
- mAudioQueueGeneration(0),
- mVideoQueueGeneration(0),
- mAudioDrainGeneration(0),
- mVideoDrainGeneration(0),
- mAudioEOSGeneration(0),
- mMediaClock(mediaClock),
- mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
- mAudioFirstAnchorTimeMediaUs(-1),
- mAnchorTimeMediaUs(-1),
- mAnchorNumFramesWritten(-1),
- mVideoLateByUs(0LL),
- mNextVideoTimeMediaUs(-1),
- mHasAudio(false),
- mHasVideo(false),
- mNotifyCompleteAudio(false),
- mNotifyCompleteVideo(false),
- mSyncQueues(false),
- mPaused(true),
- mPauseDrainAudioAllowedUs(0),
- mVideoSampleReceived(false),
- mVideoRenderingStarted(false),
- mVideoRenderingStartGeneration(0),
- mAudioRenderingStartGeneration(0),
- mRenderingDataDelivered(false),
- mNextAudioClockUpdateTimeUs(-1),
- mLastAudioMediaTimeUs(-1),
- mAudioOffloadPauseTimeoutGeneration(0),
- mAudioTornDown(false),
- mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
- mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER),
- mTotalBuffersQueued(0),
- mLastAudioBufferDrained(0),
- mUseAudioCallback(false),
- mWakeLock(new JWakeLock(context)) {
- CHECK(mediaClock != NULL);
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
-}
-
-NuPlayer2::Renderer::~Renderer() {
- if (offloadingAudio()) {
- mAudioSink->stop();
- mAudioSink->flush();
- mAudioSink->close();
- }
-
- // Try to avoid racing condition in case callback is still on.
- Mutex::Autolock autoLock(mLock);
- if (mUseAudioCallback) {
- flushQueue(&mAudioQueue);
- flushQueue(&mVideoQueue);
- }
- mWakeLock.clear();
- mVideoScheduler.clear();
- mNotify.clear();
- mAudioSink.clear();
-}
-
-void NuPlayer2::Renderer::queueBuffer(
- bool audio,
- const sp<MediaCodecBuffer> &buffer,
- const sp<AMessage> ¬ifyConsumed) {
- sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this);
- msg->setInt32("queueGeneration", getQueueGeneration(audio));
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->setObject("buffer", buffer);
- msg->setMessage("notifyConsumed", notifyConsumed);
- msg->post();
-}
-
-void NuPlayer2::Renderer::queueEOS(bool audio, status_t finalResult) {
- CHECK_NE(finalResult, (status_t)OK);
-
- sp<AMessage> msg = new AMessage(kWhatQueueEOS, this);
- msg->setInt32("queueGeneration", getQueueGeneration(audio));
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->setInt32("finalResult", finalResult);
- msg->post();
-}
-
-status_t NuPlayer2::Renderer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
- writeToAMessage(msg, rate);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
- if (rate.mSpeed <= 0.f) {
- ALOGW("playback rate cannot be %f", rate.mSpeed);
- return BAD_VALUE;
- }
-
- if (mAudioSink != NULL && mAudioSink->ready()) {
- status_t err = mAudioSink->setPlaybackRate(rate);
- if (err != OK) {
- ALOGW("failed to get playback rate from audio sink, err(%d)", err);
- return err;
- }
- }
- mPlaybackSettings = rate;
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
- return OK;
-}
-
-status_t NuPlayer2::Renderer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, rate);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- if (mAudioSink != NULL && mAudioSink->ready()) {
- status_t err = mAudioSink->getPlaybackRate(rate);
- if (err == OK) {
- if (!isAudioPlaybackRateEqual(*rate, mPlaybackSettings)) {
- ALOGW("correcting mismatch in internal/external playback rate, %f vs %f",
- rate->mSpeed, mPlaybackSettings.mSpeed);
- }
- // get playback settings used by audiosink, as it may be
- // slightly off due to audiosink not taking small changes.
- mPlaybackSettings = *rate;
- }
- return err;
- }
- *rate = mPlaybackSettings;
- return OK;
-}
-
-status_t NuPlayer2::Renderer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
- writeToAMessage(msg, sync, videoFpsHint);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onConfigSync(const AVSyncSettings &sync, float videoFpsHint __unused) {
- if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
- return BAD_VALUE;
- }
- // TODO: support sync sources
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2::Renderer::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
- sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, sync, videoFps);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onGetSyncSettings(
- AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
- *sync = mSyncSettings;
- *videoFps = -1.f;
- return OK;
-}
-
-void NuPlayer2::Renderer::flush(bool audio, bool notifyComplete) {
- {
- Mutex::Autolock autoLock(mLock);
- if (audio) {
- mNotifyCompleteAudio |= notifyComplete;
- clearAudioFirstAnchorTime_l();
- ++mAudioQueueGeneration;
- ++mAudioDrainGeneration;
- } else {
- mNotifyCompleteVideo |= notifyComplete;
- ++mVideoQueueGeneration;
- ++mVideoDrainGeneration;
- mNextVideoTimeMediaUs = -1;
- }
-
- mMediaClock->clearAnchor();
- mVideoLateByUs = 0;
- mSyncQueues = false;
- }
-
- sp<AMessage> msg = new AMessage(kWhatFlush, this);
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->post();
-}
-
-void NuPlayer2::Renderer::signalTimeDiscontinuity() {
-}
-
-void NuPlayer2::Renderer::signalDisableOffloadAudio() {
- (new AMessage(kWhatDisableOffloadAudio, this))->post();
-}
-
-void NuPlayer2::Renderer::signalEnableOffloadAudio() {
- (new AMessage(kWhatEnableOffloadAudio, this))->post();
-}
-
-void NuPlayer2::Renderer::pause() {
- (new AMessage(kWhatPause, this))->post();
-}
-
-void NuPlayer2::Renderer::resume() {
- (new AMessage(kWhatResume, this))->post();
-}
-
-void NuPlayer2::Renderer::setVideoFrameRate(float fps) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, this);
- msg->setFloat("frame-rate", fps);
- msg->post();
-}
-
-// Called on any threads without mLock acquired.
-status_t NuPlayer2::Renderer::getCurrentPosition(int64_t *mediaUs) {
- status_t result = mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
- if (result == OK) {
- return result;
- }
-
- // MediaClock has not started yet. Try to start it if possible.
- {
- Mutex::Autolock autoLock(mLock);
- if (mAudioFirstAnchorTimeMediaUs == -1) {
- return result;
- }
-
- AudioTimestamp ts;
- status_t res = mAudioSink->getTimestamp(ts);
- if (res != OK) {
- return result;
- }
-
- // AudioSink has rendered some frames.
- int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs = mAudioSink->getPlayedOutDurationUs(nowUs)
- + mAudioFirstAnchorTimeMediaUs;
- mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
- }
-
- return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
-}
-
-void NuPlayer2::Renderer::clearAudioFirstAnchorTime_l() {
- mAudioFirstAnchorTimeMediaUs = -1;
- mMediaClock->setStartingTimeMedia(-1);
-}
-
-void NuPlayer2::Renderer::setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs) {
- if (mAudioFirstAnchorTimeMediaUs == -1) {
- mAudioFirstAnchorTimeMediaUs = mediaUs;
- mMediaClock->setStartingTimeMedia(mediaUs);
- }
-}
-
-// Called on renderer looper.
-void NuPlayer2::Renderer::clearAnchorTime() {
- mMediaClock->clearAnchor();
- mAnchorTimeMediaUs = -1;
- mAnchorNumFramesWritten = -1;
-}
-
-void NuPlayer2::Renderer::setVideoLateByUs(int64_t lateUs) {
- Mutex::Autolock autoLock(mLock);
- mVideoLateByUs = lateUs;
-}
-
-int64_t NuPlayer2::Renderer::getVideoLateByUs() {
- Mutex::Autolock autoLock(mLock);
- return mVideoLateByUs;
-}
-
-status_t NuPlayer2::Renderer::openAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool *isOffloaded,
- bool isStreaming) {
- sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, this);
- msg->setMessage("format", format);
- msg->setInt32("offload-only", offloadOnly);
- msg->setInt32("has-video", hasVideo);
- msg->setInt32("flags", flags);
- msg->setInt32("isStreaming", isStreaming);
-
- sp<AMessage> response;
- status_t postStatus = msg->postAndAwaitResponse(&response);
-
- int32_t err;
- if (postStatus != OK || response.get() == nullptr || !response->findInt32("err", &err)) {
- err = INVALID_OPERATION;
- } else if (err == OK && isOffloaded != NULL) {
- int32_t offload;
- CHECK(response->findInt32("offload", &offload));
- *isOffloaded = (offload != 0);
- }
- return err;
-}
-
-void NuPlayer2::Renderer::closeAudioSink() {
- sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, this);
-
- sp<AMessage> response;
- msg->postAndAwaitResponse(&response);
-}
-
-void NuPlayer2::Renderer::changeAudioFormat(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming,
- const sp<AMessage> ¬ify) {
- sp<AMessage> meta = new AMessage;
- meta->setMessage("format", format);
- meta->setInt32("offload-only", offloadOnly);
- meta->setInt32("has-video", hasVideo);
- meta->setInt32("flags", flags);
- meta->setInt32("isStreaming", isStreaming);
-
- sp<AMessage> msg = new AMessage(kWhatChangeAudioFormat, this);
- msg->setInt32("queueGeneration", getQueueGeneration(true /* audio */));
- msg->setMessage("notify", notify);
- msg->setMessage("meta", meta);
- msg->post();
-}
-
-void NuPlayer2::Renderer::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatOpenAudioSink:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- int32_t offloadOnly;
- CHECK(msg->findInt32("offload-only", &offloadOnly));
-
- int32_t hasVideo;
- CHECK(msg->findInt32("has-video", &hasVideo));
-
- uint32_t flags;
- CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
- uint32_t isStreaming;
- CHECK(msg->findInt32("isStreaming", (int32_t *)&isStreaming));
-
- status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->setInt32("offload", offloadingAudio());
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-
- break;
- }
-
- case kWhatCloseAudioSink:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- onCloseAudioSink();
-
- sp<AMessage> response = new AMessage;
- response->postReply(replyID);
- break;
- }
-
- case kWhatStopAudioSink:
- {
- mAudioSink->stop();
- break;
- }
-
- case kWhatChangeAudioFormat:
- {
- int32_t queueGeneration;
- CHECK(msg->findInt32("queueGeneration", &queueGeneration));
-
- sp<AMessage> notify;
- CHECK(msg->findMessage("notify", ¬ify));
-
- if (offloadingAudio()) {
- ALOGW("changeAudioFormat should NOT be called in offload mode");
- notify->setInt32("err", INVALID_OPERATION);
- notify->post();
- break;
- }
-
- sp<AMessage> meta;
- CHECK(msg->findMessage("meta", &meta));
-
- if (queueGeneration != getQueueGeneration(true /* audio */)
- || mAudioQueue.empty()) {
- onChangeAudioFormat(meta, notify);
- break;
- }
-
- QueueEntry entry;
- entry.mNotifyConsumed = notify;
- entry.mMeta = meta;
-
- Mutex::Autolock autoLock(mLock);
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
-
- break;
- }
-
- case kWhatDrainAudioQueue:
- {
- mDrainAudioQueuePending = false;
-
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(true /* audio */)) {
- break;
- }
-
- if (onDrainAudioQueue()) {
- uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
- (status_t)OK);
-
- // Handle AudioTrack race when start is immediately called after flush.
- uint32_t numFramesPendingPlayout =
- (mNumFramesWritten > numFramesPlayed ?
- mNumFramesWritten - numFramesPlayed : 0);
-
- // This is how long the audio sink will have data to
- // play back.
- int64_t delayUs =
- mAudioSink->msecsPerFrame()
- * numFramesPendingPlayout * 1000ll;
- if (mPlaybackSettings.mSpeed > 1.0f) {
- delayUs /= mPlaybackSettings.mSpeed;
- }
-
- // Let's give it more data after about half that time
- // has elapsed.
- delayUs /= 2;
- // check the buffer size to estimate maximum delay permitted.
- const int64_t maxDrainDelayUs = std::max(
- mAudioSink->getBufferDurationInUs(), (int64_t)500000 /* half second */);
- ALOGD_IF(delayUs > maxDrainDelayUs, "postDrainAudioQueue long delay: %lld > %lld",
- (long long)delayUs, (long long)maxDrainDelayUs);
- Mutex::Autolock autoLock(mLock);
- postDrainAudioQueue_l(delayUs);
- }
- break;
- }
-
- case kWhatDrainVideoQueue:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(false /* audio */)) {
- break;
- }
-
- mDrainVideoQueuePending = false;
-
- onDrainVideoQueue();
-
- postDrainVideoQueue();
- break;
- }
-
- case kWhatPostDrainVideoQueue:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(false /* audio */)) {
- break;
- }
-
- mDrainVideoQueuePending = false;
- postDrainVideoQueue();
- break;
- }
-
- case kWhatQueueBuffer:
- {
- onQueueBuffer(msg);
- break;
- }
-
- case kWhatQueueEOS:
- {
- onQueueEOS(msg);
- break;
- }
-
- case kWhatEOS:
- {
- int32_t generation;
- CHECK(msg->findInt32("audioEOSGeneration", &generation));
- if (generation != mAudioEOSGeneration) {
- break;
- }
- status_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
- notifyEOS(true /* audio */, finalResult);
- break;
- }
-
- case kWhatConfigPlayback:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate;
- readFromAMessage(msg, &rate);
- status_t err = onConfigPlayback(rate);
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetPlaybackSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
- status_t err = onGetPlaybackSettings(&rate);
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, rate);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatConfigSync:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AVSyncSettings sync;
- float videoFpsHint;
- readFromAMessage(msg, &sync, &videoFpsHint);
- status_t err = onConfigSync(sync, videoFpsHint);
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSyncSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatGetSyncSettings");
- AVSyncSettings sync;
- float videoFps = -1.f;
- status_t err = onGetSyncSettings(&sync, &videoFps);
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, sync, videoFps);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatFlush:
- {
- onFlush(msg);
- break;
- }
-
- case kWhatDisableOffloadAudio:
- {
- onDisableOffloadAudio();
- break;
- }
-
- case kWhatEnableOffloadAudio:
- {
- onEnableOffloadAudio();
- break;
- }
-
- case kWhatPause:
- {
- onPause();
- break;
- }
-
- case kWhatResume:
- {
- onResume();
- break;
- }
-
- case kWhatSetVideoFrameRate:
- {
- float fps;
- CHECK(msg->findFloat("frame-rate", &fps));
- onSetVideoFrameRate(fps);
- break;
- }
-
- case kWhatAudioTearDown:
- {
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
-
- onAudioTearDown((AudioTearDownReason)reason);
- break;
- }
-
- case kWhatAudioOffloadPauseTimeout:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != mAudioOffloadPauseTimeoutGeneration) {
- break;
- }
- ALOGV("Audio Offload tear down due to pause timeout.");
- onAudioTearDown(kDueToTimeout);
- mWakeLock->release();
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
- if (mDrainAudioQueuePending || mSyncQueues || mUseAudioCallback) {
- return;
- }
-
- if (mAudioQueue.empty()) {
- return;
- }
-
- // FIXME: if paused, wait until AudioTrack stop() is complete before delivering data.
- if (mPaused) {
- const int64_t diffUs = mPauseDrainAudioAllowedUs - ALooper::GetNowUs();
- if (diffUs > delayUs) {
- delayUs = diffUs;
- }
- }
-
- mDrainAudioQueuePending = true;
- sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this);
- msg->setInt32("drainGeneration", mAudioDrainGeneration);
- msg->post(delayUs);
-}
-
-void NuPlayer2::Renderer::prepareForMediaRenderingStart_l() {
- mAudioRenderingStartGeneration = mAudioDrainGeneration;
- mVideoRenderingStartGeneration = mVideoDrainGeneration;
- mRenderingDataDelivered = false;
-}
-
-void NuPlayer2::Renderer::notifyIfMediaRenderingStarted_l() {
- if (mVideoRenderingStartGeneration == mVideoDrainGeneration &&
- mAudioRenderingStartGeneration == mAudioDrainGeneration) {
- mRenderingDataDelivered = true;
- if (mPaused) {
- return;
- }
- mVideoRenderingStartGeneration = -1;
- mAudioRenderingStartGeneration = -1;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatMediaRenderingStart);
- notify->post();
- }
-}
-
-// static
-size_t NuPlayer2::Renderer::AudioSinkCallback(
- MediaPlayer2Interface::AudioSink * /* audioSink */,
- void *buffer,
- size_t size,
- void *cookie,
- MediaPlayer2Interface::AudioSink::cb_event_t event) {
- NuPlayer2::Renderer *me = (NuPlayer2::Renderer *)cookie;
-
- switch (event) {
- case MediaPlayer2Interface::AudioSink::CB_EVENT_FILL_BUFFER:
- {
- return me->fillAudioBuffer(buffer, size);
- break;
- }
-
- case MediaPlayer2Interface::AudioSink::CB_EVENT_STREAM_END:
- {
- ALOGV("AudioSink::CB_EVENT_STREAM_END");
- me->notifyEOSCallback();
- break;
- }
-
- case MediaPlayer2Interface::AudioSink::CB_EVENT_TEAR_DOWN:
- {
- ALOGV("AudioSink::CB_EVENT_TEAR_DOWN");
- me->notifyAudioTearDown(kDueToError);
- break;
- }
- }
-
- return 0;
-}
-
-void NuPlayer2::Renderer::notifyEOSCallback() {
- Mutex::Autolock autoLock(mLock);
-
- if (!mUseAudioCallback) {
- return;
- }
-
- notifyEOS_l(true /* audio */, ERROR_END_OF_STREAM);
-}
-
-size_t NuPlayer2::Renderer::fillAudioBuffer(void *buffer, size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- if (!mUseAudioCallback) {
- return 0;
- }
-
- bool hasEOS = false;
-
- size_t sizeCopied = 0;
- bool firstEntry = true;
- QueueEntry *entry; // will be valid after while loop if hasEOS is set.
- while (sizeCopied < size && !mAudioQueue.empty()) {
- entry = &*mAudioQueue.begin();
-
- if (entry->mBuffer == NULL) { // EOS
- hasEOS = true;
- mAudioQueue.erase(mAudioQueue.begin());
- break;
- }
-
- if (firstEntry && entry->mOffset == 0) {
- firstEntry = false;
- int64_t mediaTimeUs;
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("fillAudioBuffer: rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
- setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
- }
-
- size_t copy = entry->mBuffer->size() - entry->mOffset;
- size_t sizeRemaining = size - sizeCopied;
- if (copy > sizeRemaining) {
- copy = sizeRemaining;
- }
-
- memcpy((char *)buffer + sizeCopied,
- entry->mBuffer->data() + entry->mOffset,
- copy);
-
- entry->mOffset += copy;
- if (entry->mOffset == entry->mBuffer->size()) {
- entry->mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
- entry = NULL;
- }
- sizeCopied += copy;
-
- notifyIfMediaRenderingStarted_l();
- }
-
- if (mAudioFirstAnchorTimeMediaUs >= 0) {
- int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs =
- mAudioFirstAnchorTimeMediaUs + mAudioSink->getPlayedOutDurationUs(nowUs);
- // we don't know how much data we are queueing for offloaded tracks.
- mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
- }
-
- // for non-offloaded audio, we need to compute the frames written because
- // there is no EVENT_STREAM_END notification. The frames written gives
- // an estimate on the pending played out duration.
- if (!offloadingAudio()) {
- mNumFramesWritten += sizeCopied / mAudioSink->frameSize();
- }
-
- if (hasEOS) {
- (new AMessage(kWhatStopAudioSink, this))->post();
- // As there is currently no EVENT_STREAM_END callback notification for
- // non-offloaded audio tracks, we need to post the EOS ourselves.
- if (!offloadingAudio()) {
- int64_t postEOSDelayUs = 0;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
- }
- ALOGV("fillAudioBuffer: notifyEOS_l "
- "mNumFramesWritten:%u finalResult:%d postEOSDelay:%lld",
- mNumFramesWritten, entry->mFinalResult, (long long)postEOSDelayUs);
- notifyEOS_l(true /* audio */, entry->mFinalResult, postEOSDelayUs);
- }
- }
- return sizeCopied;
-}
-
-void NuPlayer2::Renderer::drainAudioQueueUntilLastEOS() {
- List<QueueEntry>::iterator it = mAudioQueue.begin(), itEOS = it;
- bool foundEOS = false;
- while (it != mAudioQueue.end()) {
- int32_t eos;
- QueueEntry *entry = &*it++;
- if ((entry->mBuffer == nullptr && entry->mNotifyConsumed == nullptr)
- || (entry->mNotifyConsumed->findInt32("eos", &eos) && eos != 0)) {
- itEOS = it;
- foundEOS = true;
- }
- }
-
- if (foundEOS) {
- // post all replies before EOS and drop the samples
- for (it = mAudioQueue.begin(); it != itEOS; it++) {
- if (it->mBuffer == nullptr) {
- if (it->mNotifyConsumed == nullptr) {
- // delay doesn't matter as we don't even have an AudioTrack
- notifyEOS(true /* audio */, it->mFinalResult);
- } else {
- // TAG for re-opening audio sink.
- onChangeAudioFormat(it->mMeta, it->mNotifyConsumed);
- }
- } else {
- it->mNotifyConsumed->post();
- }
- }
- mAudioQueue.erase(mAudioQueue.begin(), itEOS);
- }
-}
-
-bool NuPlayer2::Renderer::onDrainAudioQueue() {
- // do not drain audio during teardown as queued buffers may be invalid.
- if (mAudioTornDown) {
- return false;
- }
- // TODO: This call to getPosition checks if AudioTrack has been created
- // in AudioSink before draining audio. If AudioTrack doesn't exist, then
- // CHECKs on getPosition will fail.
- // We still need to figure out why AudioTrack is not created when
- // this function is called. One possible reason could be leftover
- // audio. Another possible place is to check whether decoder
- // has received INFO_FORMAT_CHANGED as the first buffer since
- // AudioSink is opened there, and possible interactions with flush
- // immediately after start. Investigate error message
- // "vorbis_dsp_synthesis returned -135", along with RTSP.
- uint32_t numFramesPlayed;
- if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
- // When getPosition fails, renderer will not reschedule the draining
- // unless new samples are queued.
- // If we have pending EOS (or "eos" marker for discontinuities), we need
- // to post these now as NuPlayer2Decoder might be waiting for it.
- drainAudioQueueUntilLastEOS();
-
- ALOGW("onDrainAudioQueue(): audio sink is not ready");
- return false;
- }
-
-#if 0
- ssize_t numFramesAvailableToWrite =
- mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
-
- if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
- ALOGI("audio sink underrun");
- } else {
- ALOGV("audio queue has %d frames left to play",
- mAudioSink->frameCount() - numFramesAvailableToWrite);
- }
-#endif
-
- uint32_t prevFramesWritten = mNumFramesWritten;
- while (!mAudioQueue.empty()) {
- QueueEntry *entry = &*mAudioQueue.begin();
-
- if (entry->mBuffer == NULL) {
- if (entry->mNotifyConsumed != nullptr) {
- // TAG for re-open audio sink.
- onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
- mAudioQueue.erase(mAudioQueue.begin());
- continue;
- }
-
- // EOS
- if (mPaused) {
- // Do not notify EOS when paused.
- // This is needed to avoid switch to next clip while in pause.
- ALOGV("onDrainAudioQueue(): Do not notify EOS when paused");
- return false;
- }
-
- int64_t postEOSDelayUs = 0;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
- }
- notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
- mLastAudioMediaTimeUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
-
- mAudioQueue.erase(mAudioQueue.begin());
- entry = NULL;
- if (mAudioSink->needsTrailingPadding()) {
- // If we're not in gapless playback (i.e. through setNextPlayer), we
- // need to stop the track here, because that will play out the last
- // little bit at the end of the file. Otherwise short files won't play.
- mAudioSink->stop();
- mNumFramesWritten = 0;
- }
- return false;
- }
-
- mLastAudioBufferDrained = entry->mBufferOrdinal;
-
- // ignore 0-sized buffer which could be EOS marker with no data
- if (entry->mOffset == 0 && entry->mBuffer->size() > 0) {
- int64_t mediaTimeUs;
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("onDrainAudioQueue: rendering audio at media time %.2f secs",
- mediaTimeUs / 1E6);
- onNewAudioMediaTime(mediaTimeUs);
- }
-
- size_t copy = entry->mBuffer->size() - entry->mOffset;
-
- ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset,
- copy, false /* blocking */);
- if (written < 0) {
- // An error in AudioSink write. Perhaps the AudioSink was not properly opened.
- if (written == WOULD_BLOCK) {
- ALOGV("AudioSink write would block when writing %zu bytes", copy);
- } else {
- ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
- // This can only happen when AudioSink was opened with doNotReconnect flag set to
- // true, in which case the NuPlayer2 will handle the reconnect.
- notifyAudioTearDown(kDueToError);
- }
- break;
- }
-
- entry->mOffset += written;
- size_t remainder = entry->mBuffer->size() - entry->mOffset;
- if ((ssize_t)remainder < mAudioSink->frameSize()) {
- if (remainder > 0) {
- ALOGW("Corrupted audio buffer has fractional frames, discarding %zu bytes.",
- remainder);
- entry->mOffset += remainder;
- copy -= remainder;
- }
-
- entry->mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
-
- entry = NULL;
- }
-
- size_t copiedFrames = written / mAudioSink->frameSize();
- mNumFramesWritten += copiedFrames;
-
- {
- Mutex::Autolock autoLock(mLock);
- int64_t maxTimeMedia;
- maxTimeMedia =
- mAnchorTimeMediaUs +
- (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL)
- * 1000LL * mAudioSink->msecsPerFrame());
- mMediaClock->updateMaxTimeMedia(maxTimeMedia);
-
- notifyIfMediaRenderingStarted_l();
- }
-
- if (written != (ssize_t)copy) {
- // A short count was received from AudioSink::write()
- //
- // AudioSink write is called in non-blocking mode.
- // It may return with a short count when:
- //
- // 1) Size to be copied is not a multiple of the frame size. Fractional frames are
- // discarded.
- // 2) The data to be copied exceeds the available buffer in AudioSink.
- // 3) An error occurs and data has been partially copied to the buffer in AudioSink.
- // 4) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
-
- // (Case 1)
- // Must be a multiple of the frame size. If it is not a multiple of a frame size, it
- // needs to fail, as we should not carry over fractional frames between calls.
- CHECK_EQ(copy % mAudioSink->frameSize(), 0u);
-
- // (Case 2, 3, 4)
- // Return early to the caller.
- // Beware of calling immediately again as this may busy-loop if you are not careful.
- ALOGV("AudioSink write short frame count %zd < %zu", written, copy);
- break;
- }
- }
-
- // calculate whether we need to reschedule another write.
- bool reschedule = !mAudioQueue.empty()
- && (!mPaused
- || prevFramesWritten != mNumFramesWritten); // permit pause to fill buffers
- //ALOGD("reschedule:%d empty:%d mPaused:%d prevFramesWritten:%u mNumFramesWritten:%u",
- // reschedule, mAudioQueue.empty(), mPaused, prevFramesWritten, mNumFramesWritten);
- return reschedule;
-}
-
-int64_t NuPlayer2::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
- int32_t sampleRate = offloadingAudio() ?
- mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
- if (sampleRate == 0) {
- ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
- return 0;
- }
- return (int64_t)(numFrames * 1000000LL / sampleRate);
-}
-
-// Calculate duration of pending samples if played at normal rate (i.e., 1.0).
-int64_t NuPlayer2::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
- int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
- if (mUseVirtualAudioSink) {
- int64_t nowUs = ALooper::GetNowUs();
- int64_t mediaUs;
- if (mMediaClock->getMediaTime(nowUs, &mediaUs) != OK) {
- return 0LL;
- } else {
- return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
- }
- }
-
- const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
- int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
- if (pendingUs < 0) {
- // This shouldn't happen unless the timestamp is stale.
- ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
- "writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
- __func__, (long long)pendingUs,
- (long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
- pendingUs = 0;
- }
- return pendingUs;
-}
-
-int64_t NuPlayer2::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
- int64_t realUs;
- if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
- // If failed to get current position, e.g. due to audio clock is
- // not ready, then just play out video immediately without delay.
- return nowUs;
- }
- return realUs;
-}
-
-void NuPlayer2::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {
- Mutex::Autolock autoLock(mLock);
- // TRICKY: vorbis decoder generates multiple frames with the same
- // timestamp, so only update on the first frame with a given timestamp
- if (mediaTimeUs == mAnchorTimeMediaUs) {
- return;
- }
- setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
-
- // mNextAudioClockUpdateTimeUs is -1 if we're waiting for audio sink to start
- if (mNextAudioClockUpdateTimeUs == -1) {
- AudioTimestamp ts;
- if (mAudioSink->getTimestamp(ts) == OK && ts.mPosition > 0) {
- mNextAudioClockUpdateTimeUs = 0; // start our clock updates
- }
- }
- int64_t nowUs = ALooper::GetNowUs();
- if (mNextAudioClockUpdateTimeUs >= 0) {
- if (nowUs >= mNextAudioClockUpdateTimeUs) {
- int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
- mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
- mUseVirtualAudioSink = false;
- mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs;
- }
- } else {
- int64_t unused;
- if ((mMediaClock->getMediaTime(nowUs, &unused) != OK)
- && (getDurationUsIfPlayedAtSampleRate(mNumFramesWritten)
- > kMaxAllowedAudioSinkDelayUs)) {
- // Enough data has been sent to AudioSink, but AudioSink has not rendered
- // any data yet. Something is wrong with AudioSink, e.g., the device is not
- // connected to audio out.
- // Switch to system clock. This essentially creates a virtual AudioSink with
- // initial latenty of getDurationUsIfPlayedAtSampleRate(mNumFramesWritten).
- // This virtual AudioSink renders audio data starting from the very first sample
- // and it's paced by system clock.
- ALOGW("AudioSink stuck. ARE YOU CONNECTED TO AUDIO OUT? Switching to system clock.");
- mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs, nowUs, mediaTimeUs);
- mUseVirtualAudioSink = true;
- }
- }
- mAnchorNumFramesWritten = mNumFramesWritten;
- mAnchorTimeMediaUs = mediaTimeUs;
-}
-
-// Called without mLock acquired.
-void NuPlayer2::Renderer::postDrainVideoQueue() {
- if (mDrainVideoQueuePending
- || getSyncQueues()
- || (mPaused && mVideoSampleReceived)) {
- return;
- }
-
- if (mVideoQueue.empty()) {
- return;
- }
-
- QueueEntry &entry = *mVideoQueue.begin();
-
- sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, this);
- msg->setInt32("drainGeneration", getDrainGeneration(false /* audio */));
-
- if (entry.mBuffer == NULL) {
- // EOS doesn't carry a timestamp.
- msg->post();
- mDrainVideoQueuePending = true;
- return;
- }
-
- int64_t nowUs = ALooper::GetNowUs();
- if (mFlags & FLAG_REAL_TIME) {
- int64_t realTimeUs;
- CHECK(entry.mBuffer->meta()->findInt64("timeUs", &realTimeUs));
-
- realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
-
- int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
-
- int64_t delayUs = realTimeUs - nowUs;
-
- ALOGW_IF(delayUs > 500000, "unusually high delayUs: %lld", (long long)delayUs);
- // post 2 display refreshes before rendering is due
- msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
-
- mDrainVideoQueuePending = true;
- return;
- }
-
- int64_t mediaTimeUs;
- CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
- {
- Mutex::Autolock autoLock(mLock);
- if (mAnchorTimeMediaUs < 0) {
- mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
- mAnchorTimeMediaUs = mediaTimeUs;
- }
- }
- mNextVideoTimeMediaUs = mediaTimeUs;
- if (!mHasAudio) {
- // smooth out videos >= 10fps
- mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
- }
-
- if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
- msg->post();
- } else {
- int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
-
- // post 2 display refreshes before rendering is due
- mMediaClock->addTimer(msg, mediaTimeUs, -twoVsyncsUs);
- }
-
- mDrainVideoQueuePending = true;
-}
-
-void NuPlayer2::Renderer::onDrainVideoQueue() {
- if (mVideoQueue.empty()) {
- return;
- }
-
- QueueEntry *entry = &*mVideoQueue.begin();
-
- if (entry->mBuffer == NULL) {
- // EOS
-
- notifyEOS(false /* audio */, entry->mFinalResult);
-
- mVideoQueue.erase(mVideoQueue.begin());
- entry = NULL;
-
- setVideoLateByUs(0);
- return;
- }
-
- int64_t nowUs = ALooper::GetNowUs();
- int64_t realTimeUs;
- int64_t mediaTimeUs = -1;
- if (mFlags & FLAG_REAL_TIME) {
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
- } else {
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
- realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
- }
- realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
-
- bool tooLate = false;
-
- if (!mPaused) {
- setVideoLateByUs(nowUs - realTimeUs);
- tooLate = (mVideoLateByUs > 40000);
-
- if (tooLate) {
- ALOGV("video late by %lld us (%.2f secs)",
- (long long)mVideoLateByUs, mVideoLateByUs / 1E6);
- } else {
- int64_t mediaUs = 0;
- mMediaClock->getMediaTime(realTimeUs, &mediaUs);
- ALOGV("rendering video at media time %.2f secs",
- (mFlags & FLAG_REAL_TIME ? realTimeUs :
- mediaUs) / 1E6);
-
- if (!(mFlags & FLAG_REAL_TIME)
- && mLastAudioMediaTimeUs != -1
- && mediaTimeUs > mLastAudioMediaTimeUs) {
- // If audio ends before video, video continues to drive media clock.
- // Also smooth out videos >= 10fps.
- mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
- }
- }
- } else {
- setVideoLateByUs(0);
- if (!mVideoSampleReceived && !mHasAudio) {
- // This will ensure that the first frame after a flush won't be used as anchor
- // when renderer is in paused state, because resume can happen any time after seek.
- clearAnchorTime();
- }
- }
-
- // Always render the first video frame while keeping stats on A/V sync.
- if (!mVideoSampleReceived) {
- realTimeUs = nowUs;
- tooLate = false;
- }
-
- entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000LL);
- entry->mNotifyConsumed->setInt32("render", !tooLate);
- entry->mNotifyConsumed->post();
- mVideoQueue.erase(mVideoQueue.begin());
- entry = NULL;
-
- mVideoSampleReceived = true;
-
- if (!mPaused) {
- if (!mVideoRenderingStarted) {
- mVideoRenderingStarted = true;
- notifyVideoRenderingStart();
- }
- Mutex::Autolock autoLock(mLock);
- notifyIfMediaRenderingStarted_l();
- }
-}
-
-void NuPlayer2::Renderer::notifyVideoRenderingStart() {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatVideoRenderingStart);
- notify->post();
-}
-
-void NuPlayer2::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
- Mutex::Autolock autoLock(mLock);
- notifyEOS_l(audio, finalResult, delayUs);
-}
-
-void NuPlayer2::Renderer::notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs) {
- if (audio && delayUs > 0) {
- sp<AMessage> msg = new AMessage(kWhatEOS, this);
- msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
- msg->setInt32("finalResult", finalResult);
- msg->post(delayUs);
- return;
- }
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatEOS);
- notify->setInt32("audio", static_cast<int32_t>(audio));
- notify->setInt32("finalResult", finalResult);
- notify->post(delayUs);
-
- if (audio) {
- // Video might outlive audio. Clear anchor to enable video only case.
- mAnchorTimeMediaUs = -1;
- mHasAudio = false;
- if (mNextVideoTimeMediaUs >= 0) {
- int64_t mediaUs = 0;
- int64_t nowUs = ALooper::GetNowUs();
- status_t result = mMediaClock->getMediaTime(nowUs, &mediaUs);
- if (result == OK) {
- if (mNextVideoTimeMediaUs > mediaUs) {
- mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
- }
- } else {
- mMediaClock->updateAnchor(
- mNextVideoTimeMediaUs, nowUs,
- mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
- }
- }
- }
-}
-
-void NuPlayer2::Renderer::notifyAudioTearDown(AudioTearDownReason reason) {
- sp<AMessage> msg = new AMessage(kWhatAudioTearDown, this);
- msg->setInt32("reason", reason);
- msg->post();
-}
-
-void NuPlayer2::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (dropBufferIfStale(audio, msg)) {
- return;
- }
-
- if (audio) {
- mHasAudio = true;
- } else {
- mHasVideo = true;
- }
-
- if (mHasVideo) {
- if (mVideoScheduler == NULL) {
- mVideoScheduler = new VideoFrameScheduler2();
- mVideoScheduler->init();
- }
- }
-
- sp<RefBase> obj;
- CHECK(msg->findObject("buffer", &obj));
- sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
-
- sp<AMessage> notifyConsumed;
- CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed));
-
- QueueEntry entry;
- entry.mBuffer = buffer;
- entry.mNotifyConsumed = notifyConsumed;
- entry.mOffset = 0;
- entry.mFinalResult = OK;
- entry.mBufferOrdinal = ++mTotalBuffersQueued;
-
- if (audio) {
- Mutex::Autolock autoLock(mLock);
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
- } else {
- mVideoQueue.push_back(entry);
- postDrainVideoQueue();
- }
-
- Mutex::Autolock autoLock(mLock);
- if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
- return;
- }
-
- sp<MediaCodecBuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
- sp<MediaCodecBuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
-
- if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
- // EOS signalled on either queue.
- syncQueuesDone_l();
- return;
- }
-
- int64_t firstAudioTimeUs;
- int64_t firstVideoTimeUs;
- CHECK(firstAudioBuffer->meta()
- ->findInt64("timeUs", &firstAudioTimeUs));
- CHECK(firstVideoBuffer->meta()
- ->findInt64("timeUs", &firstVideoTimeUs));
-
- int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
-
- ALOGV("queueDiff = %.2f secs", diff / 1E6);
-
- if (diff > 100000LL) {
- // Audio data starts More than 0.1 secs before video.
- // Drop some audio.
-
- (*mAudioQueue.begin()).mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
- return;
- }
-
- syncQueuesDone_l();
-}
-
-void NuPlayer2::Renderer::syncQueuesDone_l() {
- if (!mSyncQueues) {
- return;
- }
-
- mSyncQueues = false;
-
- if (!mAudioQueue.empty()) {
- postDrainAudioQueue_l();
- }
-
- if (!mVideoQueue.empty()) {
- mLock.unlock();
- postDrainVideoQueue();
- mLock.lock();
- }
-}
-
-void NuPlayer2::Renderer::onQueueEOS(const sp<AMessage> &msg) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (dropBufferIfStale(audio, msg)) {
- return;
- }
-
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
-
- QueueEntry entry;
- entry.mOffset = 0;
- entry.mFinalResult = finalResult;
-
- if (audio) {
- Mutex::Autolock autoLock(mLock);
- if (mAudioQueue.empty() && mSyncQueues) {
- syncQueuesDone_l();
- }
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
- } else {
- if (mVideoQueue.empty() && getSyncQueues()) {
- Mutex::Autolock autoLock(mLock);
- syncQueuesDone_l();
- }
- mVideoQueue.push_back(entry);
- postDrainVideoQueue();
- }
-}
-
-void NuPlayer2::Renderer::onFlush(const sp<AMessage> &msg) {
- int32_t audio, notifyComplete;
- CHECK(msg->findInt32("audio", &audio));
-
- {
- Mutex::Autolock autoLock(mLock);
- if (audio) {
- notifyComplete = mNotifyCompleteAudio;
- mNotifyCompleteAudio = false;
- mLastAudioMediaTimeUs = -1;
-
- mHasAudio = false;
- if (mNextVideoTimeMediaUs >= 0) {
- int64_t nowUs = ALooper::GetNowUs();
- mMediaClock->updateAnchor(
- mNextVideoTimeMediaUs, nowUs,
- mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
- }
- } else {
- notifyComplete = mNotifyCompleteVideo;
- mNotifyCompleteVideo = false;
- mVideoRenderingStarted = false;
- }
-
- // If we're currently syncing the queues, i.e. dropping audio while
- // aligning the first audio/video buffer times and only one of the
- // two queues has data, we may starve that queue by not requesting
- // more buffers from the decoder. If the other source then encounters
- // a discontinuity that leads to flushing, we'll never find the
- // corresponding discontinuity on the other queue.
- // Therefore we'll stop syncing the queues if at least one of them
- // is flushed.
- syncQueuesDone_l();
- }
- clearAnchorTime();
-
- ALOGV("flushing %s", audio ? "audio" : "video");
- if (audio) {
- {
- Mutex::Autolock autoLock(mLock);
- flushQueue(&mAudioQueue);
-
- ++mAudioDrainGeneration;
- ++mAudioEOSGeneration;
- prepareForMediaRenderingStart_l();
-
- // the frame count will be reset after flush.
- clearAudioFirstAnchorTime_l();
- }
-
- mDrainAudioQueuePending = false;
-
- if (offloadingAudio()) {
- mAudioSink->pause();
- mAudioSink->flush();
- if (!mPaused) {
- mAudioSink->start();
- }
- } else {
- mAudioSink->pause();
- mAudioSink->flush();
- // Call stop() to signal to the AudioSink to completely fill the
- // internal buffer before resuming playback.
- // FIXME: this is ignored after flush().
- mAudioSink->stop();
- if (mPaused) {
- // Race condition: if renderer is paused and audio sink is stopped,
- // we need to make sure that the audio track buffer fully drains
- // before delivering data.
- // FIXME: remove this if we can detect if stop() is complete.
- const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms)
- mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs;
- } else {
- mAudioSink->start();
- }
- mNumFramesWritten = 0;
- }
- mNextAudioClockUpdateTimeUs = -1;
- } else {
- flushQueue(&mVideoQueue);
-
- mDrainVideoQueuePending = false;
-
- if (mVideoScheduler != NULL) {
- mVideoScheduler->restart();
- }
-
- Mutex::Autolock autoLock(mLock);
- ++mVideoDrainGeneration;
- prepareForMediaRenderingStart_l();
- }
-
- mVideoSampleReceived = false;
-
- if (notifyComplete) {
- notifyFlushComplete(audio);
- }
-}
-
-void NuPlayer2::Renderer::flushQueue(List<QueueEntry> *queue) {
- while (!queue->empty()) {
- QueueEntry *entry = &*queue->begin();
-
- if (entry->mBuffer != NULL) {
- entry->mNotifyConsumed->post();
- } else if (entry->mNotifyConsumed != nullptr) {
- // Is it needed to open audio sink now?
- onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
- }
-
- queue->erase(queue->begin());
- entry = NULL;
- }
-}
-
-void NuPlayer2::Renderer::notifyFlushComplete(bool audio) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushComplete);
- notify->setInt32("audio", static_cast<int32_t>(audio));
- notify->post();
-}
-
-bool NuPlayer2::Renderer::dropBufferIfStale(
- bool audio, const sp<AMessage> &msg) {
- int32_t queueGeneration;
- CHECK(msg->findInt32("queueGeneration", &queueGeneration));
-
- if (queueGeneration == getQueueGeneration(audio)) {
- return false;
- }
-
- sp<AMessage> notifyConsumed;
- if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) {
- notifyConsumed->post();
- }
-
- return true;
-}
-
-void NuPlayer2::Renderer::onAudioSinkChanged() {
- if (offloadingAudio()) {
- return;
- }
- CHECK(!mDrainAudioQueuePending);
- mNumFramesWritten = 0;
- mAnchorNumFramesWritten = -1;
- uint32_t written;
- if (mAudioSink->getFramesWritten(&written) == OK) {
- mNumFramesWritten = written;
- }
-}
-
-void NuPlayer2::Renderer::onDisableOffloadAudio() {
- Mutex::Autolock autoLock(mLock);
- mFlags &= ~FLAG_OFFLOAD_AUDIO;
- ++mAudioDrainGeneration;
- if (mAudioRenderingStartGeneration != -1) {
- prepareForMediaRenderingStart_l();
- }
-}
-
-void NuPlayer2::Renderer::onEnableOffloadAudio() {
- Mutex::Autolock autoLock(mLock);
- mFlags |= FLAG_OFFLOAD_AUDIO;
- ++mAudioDrainGeneration;
- if (mAudioRenderingStartGeneration != -1) {
- prepareForMediaRenderingStart_l();
- }
-}
-
-void NuPlayer2::Renderer::onPause() {
- if (mPaused) {
- return;
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- // we do not increment audio drain generation so that we fill audio buffer during pause.
- ++mVideoDrainGeneration;
- prepareForMediaRenderingStart_l();
- mPaused = true;
- mMediaClock->setPlaybackRate(0.0);
- }
-
- mDrainAudioQueuePending = false;
- mDrainVideoQueuePending = false;
-
- // Note: audio data may not have been decoded, and the AudioSink may not be opened.
- mAudioSink->pause();
- startAudioOffloadPauseTimeout();
-
- ALOGV("now paused audio queue has %zu entries, video has %zu entries",
- mAudioQueue.size(), mVideoQueue.size());
-}
-
-void NuPlayer2::Renderer::onResume() {
- if (!mPaused) {
- return;
- }
-
- // Note: audio data may not have been decoded, and the AudioSink may not be opened.
- cancelAudioOffloadPauseTimeout();
- if (mAudioSink->ready()) {
- status_t err = mAudioSink->start();
- if (err != OK) {
- ALOGE("cannot start AudioSink err %d", err);
- notifyAudioTearDown(kDueToError);
- }
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- mPaused = false;
- // rendering started message may have been delayed if we were paused.
- if (mRenderingDataDelivered) {
- notifyIfMediaRenderingStarted_l();
- }
- // configure audiosink as we did not do it when pausing
- if (mAudioSink != NULL && mAudioSink->ready()) {
- mAudioSink->setPlaybackRate(mPlaybackSettings);
- }
-
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
-
- if (!mAudioQueue.empty()) {
- postDrainAudioQueue_l();
- }
- }
-
- if (!mVideoQueue.empty()) {
- postDrainVideoQueue();
- }
-}
-
-void NuPlayer2::Renderer::onSetVideoFrameRate(float fps) {
- if (mVideoScheduler == NULL) {
- mVideoScheduler = new VideoFrameScheduler2();
- }
- mVideoScheduler->init(fps);
-}
-
-int32_t NuPlayer2::Renderer::getQueueGeneration(bool audio) {
- Mutex::Autolock autoLock(mLock);
- return (audio ? mAudioQueueGeneration : mVideoQueueGeneration);
-}
-
-int32_t NuPlayer2::Renderer::getDrainGeneration(bool audio) {
- Mutex::Autolock autoLock(mLock);
- return (audio ? mAudioDrainGeneration : mVideoDrainGeneration);
-}
-
-bool NuPlayer2::Renderer::getSyncQueues() {
- Mutex::Autolock autoLock(mLock);
- return mSyncQueues;
-}
-
-void NuPlayer2::Renderer::onAudioTearDown(AudioTearDownReason reason) {
- if (mAudioTornDown) {
- return;
- }
- mAudioTornDown = true;
-
- int64_t currentPositionUs;
- sp<AMessage> notify = mNotify->dup();
- if (getCurrentPosition(¤tPositionUs) == OK) {
- notify->setInt64("positionUs", currentPositionUs);
- }
-
- mAudioSink->stop();
- mAudioSink->flush();
-
- notify->setInt32("what", kWhatAudioTearDown);
- notify->setInt32("reason", reason);
- notify->post();
-}
-
-void NuPlayer2::Renderer::startAudioOffloadPauseTimeout() {
- if (offloadingAudio()) {
- mWakeLock->acquire();
- sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, this);
- msg->setInt32("drainGeneration", mAudioOffloadPauseTimeoutGeneration);
- msg->post(kOffloadPauseMaxUs);
- }
-}
-
-void NuPlayer2::Renderer::cancelAudioOffloadPauseTimeout() {
- // We may have called startAudioOffloadPauseTimeout() without
- // the AudioSink open and with offloadingAudio enabled.
- //
- // When we cancel, it may be that offloadingAudio is subsequently disabled, so regardless
- // we always release the wakelock and increment the pause timeout generation.
- //
- // Note: The acquired wakelock prevents the device from suspending
- // immediately after offload pause (in case a resume happens shortly thereafter).
- mWakeLock->release(true);
- ++mAudioOffloadPauseTimeoutGeneration;
-}
-
-status_t NuPlayer2::Renderer::onOpenAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming) {
- ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
- offloadOnly, offloadingAudio());
-
- bool audioSinkChanged = false;
-
- int32_t numChannels;
- CHECK(format->findInt32("channel-count", &numChannels));
-
- int32_t channelMask;
- if (!format->findInt32("channel-mask", &channelMask)) {
- // signal to the AudioSink to derive the mask from count.
- channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
- }
-
- int32_t sampleRate;
- CHECK(format->findInt32("sample-rate", &sampleRate));
-
- // read pcm encoding from MediaCodec output format, if available
- int32_t pcmEncoding;
- audio_format_t audioFormat =
- format->findInt32(KEY_PCM_ENCODING, &pcmEncoding) ?
- audioFormatFromEncoding(pcmEncoding) : AUDIO_FORMAT_PCM_16_BIT;
-
- if (offloadingAudio()) {
- AString mime;
- CHECK(format->findString("mime", &mime));
- status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
-
- if (err != OK) {
- ALOGE("Couldn't map mime \"%s\" to a valid "
- "audio_format", mime.c_str());
- onDisableOffloadAudio();
- } else {
- ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
- mime.c_str(), audioFormat);
-
- int avgBitRate = -1;
- format->findInt32("bitrate", &avgBitRate);
-
- int32_t aacProfile = -1;
- if (audioFormat == AUDIO_FORMAT_AAC
- && format->findInt32("aac-profile", &aacProfile)) {
- // Redefine AAC format as per aac profile
- mapAACProfileToAudioFormat(
- audioFormat,
- aacProfile);
- }
-
- audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
- offloadInfo.duration_us = -1;
- format->findInt64(
- "durationUs", &offloadInfo.duration_us);
- offloadInfo.sample_rate = sampleRate;
- offloadInfo.channel_mask = channelMask;
- offloadInfo.format = audioFormat;
- offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
- offloadInfo.bit_rate = avgBitRate;
- offloadInfo.has_video = hasVideo;
- offloadInfo.is_streaming = isStreaming;
-
- if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
- ALOGV("openAudioSink: no change in offload mode");
- // no change from previous configuration, everything ok.
- return OK;
- }
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
-
- ALOGV("openAudioSink: try to open AudioSink in offload mode");
- uint32_t offloadFlags = flags;
- offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- audioSinkChanged = true;
- mAudioSink->close();
-
- err = mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- audioFormat,
- &NuPlayer2::Renderer::AudioSinkCallback,
- this,
- (audio_output_flags_t)offloadFlags,
- &offloadInfo);
-
- if (err == OK) {
- err = mAudioSink->setPlaybackRate(mPlaybackSettings);
- }
-
- if (err == OK) {
- // If the playback is offloaded to h/w, we pass
- // the HAL some metadata information.
- // We don't want to do this for PCM because it
- // will be going through the AudioFlinger mixer
- // before reaching the hardware.
- // TODO
- mCurrentOffloadInfo = offloadInfo;
- if (!mPaused) { // for preview mode, don't start if paused
- err = mAudioSink->start();
- }
- ALOGV_IF(err == OK, "openAudioSink: offload succeeded");
- }
- if (err != OK) {
- // Clean up, fall back to non offload mode.
- mAudioSink->close();
- onDisableOffloadAudio();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- ALOGV("openAudioSink: offload failed");
- if (offloadOnly) {
- notifyAudioTearDown(kForceNonOffload);
- }
- } else {
- mUseAudioCallback = true; // offload mode transfers data through callback
- ++mAudioDrainGeneration; // discard pending kWhatDrainAudioQueue message.
- }
- }
- }
- if (!offloadOnly && !offloadingAudio()) {
- ALOGV("openAudioSink: open AudioSink in NON-offload mode");
- uint32_t pcmFlags = flags;
- pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
-
- const PcmInfo info = {
- (audio_channel_mask_t)channelMask,
- (audio_output_flags_t)pcmFlags,
- audioFormat,
- numChannels,
- sampleRate
- };
- if (memcmp(&mCurrentPcmInfo, &info, sizeof(info)) == 0) {
- ALOGV("openAudioSink: no change in pcm mode");
- // no change from previous configuration, everything ok.
- return OK;
- }
-
- audioSinkChanged = true;
- mAudioSink->close();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- // Note: It is possible to set up the callback, but not use it to send audio data.
- // This requires a fix in AudioSink to explicitly specify the transfer mode.
- mUseAudioCallback = getUseAudioCallbackSetting();
- if (mUseAudioCallback) {
- ++mAudioDrainGeneration; // discard pending kWhatDrainAudioQueue message.
- }
-
- // Compute the desired buffer size.
- // For callback mode, the amount of time before wakeup is about half the buffer size.
- const uint32_t frameCount =
- (unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
-
- // We should always be able to set our playback settings if the sink is closed.
- LOG_ALWAYS_FATAL_IF(mAudioSink->setPlaybackRate(mPlaybackSettings) != OK,
- "onOpenAudioSink: can't set playback rate on closed sink");
- status_t err = mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- audioFormat,
- mUseAudioCallback ? &NuPlayer2::Renderer::AudioSinkCallback : NULL,
- mUseAudioCallback ? this : NULL,
- (audio_output_flags_t)pcmFlags,
- NULL,
- frameCount);
- if (err != OK) {
- ALOGW("openAudioSink: non offloaded open failed status: %d", err);
- mAudioSink->close();
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
- return err;
- }
- mCurrentPcmInfo = info;
- if (!mPaused) { // for preview mode, don't start if paused
- mAudioSink->start();
- }
- }
- if (audioSinkChanged) {
- onAudioSinkChanged();
- }
- mAudioTornDown = false;
- return OK;
-}
-
-void NuPlayer2::Renderer::onCloseAudioSink() {
- mAudioSink->close();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
-}
-
-void NuPlayer2::Renderer::onChangeAudioFormat(
- const sp<AMessage> &meta, const sp<AMessage> ¬ify) {
- sp<AMessage> format;
- CHECK(meta->findMessage("format", &format));
-
- int32_t offloadOnly;
- CHECK(meta->findInt32("offload-only", &offloadOnly));
-
- int32_t hasVideo;
- CHECK(meta->findInt32("has-video", &hasVideo));
-
- uint32_t flags;
- CHECK(meta->findInt32("flags", (int32_t *)&flags));
-
- uint32_t isStreaming;
- CHECK(meta->findInt32("isStreaming", (int32_t *)&isStreaming));
-
- status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
-
- if (err != OK) {
- notify->setInt32("err", err);
- }
- notify->post();
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
deleted file mode 100644
index d065dee..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_RENDERER_H_
-
-#define NUPLAYER2_RENDERER_H_
-
-#include <media/AudioResamplerPublic.h>
-#include <media/AVSyncSettings.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include "NuPlayer2.h"
-
-namespace android {
-
-class JWakeLock;
-struct MediaClock;
-class MediaCodecBuffer;
-struct VideoFrameSchedulerBase;
-
-struct NuPlayer2::Renderer : public AHandler {
- enum Flags {
- FLAG_REAL_TIME = 1,
- FLAG_OFFLOAD_AUDIO = 2,
- };
- Renderer(const sp<MediaPlayer2Interface::AudioSink> &sink,
- const sp<MediaClock> &mediaClock,
- const sp<AMessage> ¬ify,
- const sp<JObjectHolder> &context,
- uint32_t flags = 0);
-
- static size_t AudioSinkCallback(
- MediaPlayer2Interface::AudioSink *audioSink,
- void *data, size_t size, void *me,
- MediaPlayer2Interface::AudioSink::cb_event_t event);
-
- void queueBuffer(
- bool audio,
- const sp<MediaCodecBuffer> &buffer,
- const sp<AMessage> ¬ifyConsumed);
-
- void queueEOS(bool audio, status_t finalResult);
-
- status_t setPlaybackSettings(const AudioPlaybackRate &rate /* sanitized */);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
- status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void flush(bool audio, bool notifyComplete);
-
- void signalTimeDiscontinuity();
-
- void signalDisableOffloadAudio();
- void signalEnableOffloadAudio();
-
- void pause();
- void resume();
-
- void setVideoFrameRate(float fps);
-
- status_t getCurrentPosition(int64_t *mediaUs);
- int64_t getVideoLateByUs();
-
- status_t openAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool *isOffloaded,
- bool isStreaming);
- void closeAudioSink();
-
- // re-open audio sink after all pending audio buffers played.
- void changeAudioFormat(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming,
- const sp<AMessage> ¬ify);
-
- enum {
- kWhatEOS = 'eos ',
- kWhatFlushComplete = 'fluC',
- kWhatPosition = 'posi',
- kWhatVideoRenderingStart = 'vdrd',
- kWhatMediaRenderingStart = 'mdrd',
- kWhatAudioTearDown = 'adTD',
- kWhatAudioOffloadPauseTimeout = 'aOPT',
- };
-
- enum AudioTearDownReason {
- kDueToError = 0, // Could restart with either offload or non-offload.
- kDueToTimeout,
- kForceNonOffload, // Restart only with non-offload.
- };
-
-protected:
- virtual ~Renderer();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
- enum {
- kWhatDrainAudioQueue = 'draA',
- kWhatDrainVideoQueue = 'draV',
- kWhatPostDrainVideoQueue = 'pDVQ',
- kWhatQueueBuffer = 'queB',
- kWhatQueueEOS = 'qEOS',
- kWhatConfigPlayback = 'cfPB',
- kWhatConfigSync = 'cfSy',
- kWhatGetPlaybackSettings = 'gPbS',
- kWhatGetSyncSettings = 'gSyS',
- kWhatFlush = 'flus',
- kWhatPause = 'paus',
- kWhatResume = 'resm',
- kWhatOpenAudioSink = 'opnA',
- kWhatCloseAudioSink = 'clsA',
- kWhatChangeAudioFormat = 'chgA',
- kWhatStopAudioSink = 'stpA',
- kWhatDisableOffloadAudio = 'noOA',
- kWhatEnableOffloadAudio = 'enOA',
- kWhatSetVideoFrameRate = 'sVFR',
- };
-
- // if mBuffer != nullptr, it's a buffer containing real data.
- // else if mNotifyConsumed == nullptr, it's EOS.
- // else it's a tag for re-opening audio sink in different format.
- struct QueueEntry {
- sp<MediaCodecBuffer> mBuffer;
- sp<AMessage> mMeta;
- sp<AMessage> mNotifyConsumed;
- size_t mOffset;
- status_t mFinalResult;
- int32_t mBufferOrdinal;
- };
-
- static const int64_t kMinPositionUpdateDelayUs;
-
- sp<MediaPlayer2Interface::AudioSink> mAudioSink;
- bool mUseVirtualAudioSink;
- sp<AMessage> mNotify;
- Mutex mLock;
- uint32_t mFlags;
- List<QueueEntry> mAudioQueue;
- List<QueueEntry> mVideoQueue;
- uint32_t mNumFramesWritten;
- sp<VideoFrameSchedulerBase> mVideoScheduler;
-
- bool mDrainAudioQueuePending;
- bool mDrainVideoQueuePending;
- int32_t mAudioQueueGeneration;
- int32_t mVideoQueueGeneration;
- int32_t mAudioDrainGeneration;
- int32_t mVideoDrainGeneration;
- int32_t mAudioEOSGeneration;
-
- const sp<MediaClock> mMediaClock;
-
- AudioPlaybackRate mPlaybackSettings;
- AVSyncSettings mSyncSettings;
- float mVideoFpsHint;
-
- int64_t mAudioFirstAnchorTimeMediaUs;
- int64_t mAnchorTimeMediaUs;
- int64_t mAnchorNumFramesWritten;
- int64_t mVideoLateByUs;
- int64_t mNextVideoTimeMediaUs;
- bool mHasAudio;
- bool mHasVideo;
-
- bool mNotifyCompleteAudio;
- bool mNotifyCompleteVideo;
-
- bool mSyncQueues;
-
- // modified on only renderer's thread.
- bool mPaused;
- int64_t mPauseDrainAudioAllowedUs; // time when we can drain/deliver audio in pause mode.
-
- bool mVideoSampleReceived;
- bool mVideoRenderingStarted;
- int32_t mVideoRenderingStartGeneration;
- int32_t mAudioRenderingStartGeneration;
- bool mRenderingDataDelivered;
-
- int64_t mNextAudioClockUpdateTimeUs;
- // the media timestamp of last audio sample right before EOS.
- int64_t mLastAudioMediaTimeUs;
-
- int32_t mAudioOffloadPauseTimeoutGeneration;
- bool mAudioTornDown;
- audio_offload_info_t mCurrentOffloadInfo;
-
- struct PcmInfo {
- audio_channel_mask_t mChannelMask;
- audio_output_flags_t mFlags;
- audio_format_t mFormat;
- int32_t mNumChannels;
- int32_t mSampleRate;
- };
- PcmInfo mCurrentPcmInfo;
- static const PcmInfo AUDIO_PCMINFO_INITIALIZER;
-
- int32_t mTotalBuffersQueued;
- int32_t mLastAudioBufferDrained;
- bool mUseAudioCallback;
-
- sp<JWakeLock> mWakeLock;
-
- status_t getCurrentPositionOnLooper(int64_t *mediaUs);
- status_t getCurrentPositionOnLooper(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
- bool getCurrentPositionIfPaused_l(int64_t *mediaUs);
- status_t getCurrentPositionFromAnchor(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
-
- void notifyEOSCallback();
- size_t fillAudioBuffer(void *buffer, size_t size);
-
- bool onDrainAudioQueue();
- void drainAudioQueueUntilLastEOS();
- int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
- void postDrainAudioQueue_l(int64_t delayUs = 0);
-
- void clearAnchorTime();
- void clearAudioFirstAnchorTime_l();
- void setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs);
- void setVideoLateByUs(int64_t lateUs);
-
- void onNewAudioMediaTime(int64_t mediaTimeUs);
- int64_t getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs);
-
- void onDrainVideoQueue();
- void postDrainVideoQueue();
-
- void prepareForMediaRenderingStart_l();
- void notifyIfMediaRenderingStarted_l();
-
- void onQueueBuffer(const sp<AMessage> &msg);
- void onQueueEOS(const sp<AMessage> &msg);
- void onFlush(const sp<AMessage> &msg);
- void onAudioSinkChanged();
- void onDisableOffloadAudio();
- void onEnableOffloadAudio();
- status_t onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */);
- status_t onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t onConfigSync(const AVSyncSettings &sync, float videoFpsHint);
- status_t onGetSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void onPause();
- void onResume();
- void onSetVideoFrameRate(float fps);
- int32_t getQueueGeneration(bool audio);
- int32_t getDrainGeneration(bool audio);
- bool getSyncQueues();
- void onAudioTearDown(AudioTearDownReason reason);
- status_t onOpenAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming);
- void onCloseAudioSink();
- void onChangeAudioFormat(const sp<AMessage> &meta, const sp<AMessage> ¬ify);
-
- void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
- void notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs = 0);
- void notifyFlushComplete(bool audio);
- void notifyPosition();
- void notifyVideoLateBy(int64_t lateByUs);
- void notifyVideoRenderingStart();
- void notifyAudioTearDown(AudioTearDownReason reason);
-
- void flushQueue(List<QueueEntry> *queue);
- bool dropBufferIfStale(bool audio, const sp<AMessage> &msg);
- void syncQueuesDone_l();
-
- bool offloadingAudio() const { return (mFlags & FLAG_OFFLOAD_AUDIO) != 0; }
-
- void startAudioOffloadPauseTimeout();
- void cancelAudioOffloadPauseTimeout();
-
- int64_t getDurationUsIfPlayedAtSampleRate(uint32_t numFrames);
-
- DISALLOW_EVIL_CONSTRUCTORS(Renderer);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_RENDERER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
deleted file mode 100644
index 9298a99..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_SOURCE_H_
-
-#define NUPLAYER2_SOURCE_H_
-
-#include "NuPlayer2.h"
-
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MetaData.h>
-#include <mediaplayer2/mediaplayer2.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct ABuffer;
-struct AMediaCryptoWrapper;
-class MediaBuffer;
-
-struct NuPlayer2::Source : public AHandler {
- enum Flags {
- FLAG_CAN_PAUSE = 1,
- FLAG_CAN_SEEK_BACKWARD = 2, // the "10 sec back button"
- FLAG_CAN_SEEK_FORWARD = 4, // the "10 sec forward button"
- FLAG_CAN_SEEK = 8, // the "seek bar"
- FLAG_DYNAMIC_DURATION = 16,
- FLAG_SECURE = 32, // Secure codec is required.
- FLAG_PROTECTED = 64, // The screen needs to be protected (screenshot is disabled).
- };
-
- enum {
- kWhatPrepared,
- kWhatFlagsChanged,
- kWhatVideoSizeChanged,
- kWhatBufferingUpdate,
- kWhatPauseOnBufferingStart,
- kWhatResumeOnBufferingEnd,
- kWhatCacheStats,
- kWhatSubtitleData,
- kWhatTimedTextData,
- kWhatTimedMetaData,
- kWhatQueueDecoderShutdown,
- kWhatDrmNoLicense,
- // Modular DRM
- kWhatDrmInfo,
- };
-
- // The provides message is used to notify the player about various
- // events.
- explicit Source(const sp<AMessage> ¬ify)
- : mNotify(notify) {
- }
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) = 0;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
-
- virtual void prepareAsync(int64_t startTimeUs) = 0;
-
- virtual void start() = 0;
- virtual void stop() {}
- virtual void pause() {}
- virtual void resume() {}
-
- // Explicitly disconnect the underling data source
- virtual void disconnect() {}
-
- // Returns OK iff more data was available,
- // an error or ERROR_END_OF_STREAM if not.
- virtual status_t feedMoreTSData() = 0;
-
- // Returns non-NULL format when the specified track exists.
- // When the format has "err" set to -EWOULDBLOCK, source needs more time to get valid meta data.
- // Returns NULL if the specified track doesn't exist or is invalid;
- virtual sp<AMessage> getFormat(bool audio);
-
- virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
- virtual sp<MetaData> getFileFormatMeta() const { return NULL; }
-
- virtual status_t dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) = 0;
-
- virtual status_t getDuration(int64_t * /* durationUs */) {
- return INVALID_OPERATION;
- }
-
- virtual size_t getTrackCount() const {
- return 0;
- }
-
- virtual sp<AMessage> getTrackInfo(size_t /* trackIndex */) const {
- return NULL;
- }
-
- virtual ssize_t getSelectedTrack(media_track_type /* type */) const {
- return INVALID_OPERATION;
- }
-
- virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */, int64_t /* timeUs*/) {
- return INVALID_OPERATION;
- }
-
- virtual status_t seekTo(
- int64_t /* seekTimeUs */,
- MediaPlayer2SeekMode /* mode */ = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) {
- return INVALID_OPERATION;
- }
-
- virtual bool isRealTime() const {
- return false;
- }
-
- virtual bool isStreaming() const {
- return true;
- }
-
- virtual void setOffloadAudio(bool /* offload */) {}
-
- // Modular DRM
- virtual status_t prepareDrm(
- const uint8_t /* uuid */[16], const Vector<uint8_t> & /* drmSessionId */,
- sp<AMediaCryptoWrapper> * /* crypto */) {
- return INVALID_OPERATION;
- }
-
- virtual status_t releaseDrm() {
- return INVALID_OPERATION;
- }
-
-protected:
- virtual ~Source() {}
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- sp<AMessage> dupNotify() const { return mNotify->dup(); }
-
- void notifyFlagsChanged(uint32_t flags);
- void notifyVideoSizeChanged(const sp<AMessage> &format = NULL);
- void notifyPrepared(status_t err = OK);
- // Modular DRM
- void notifyDrmInfo(const sp<ABuffer> &buffer);
-
-private:
- sp<AMessage> mNotify;
-
- DISALLOW_EVIL_CONSTRUCTORS(Source);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_SOURCE_H_
-
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
deleted file mode 100644
index a70269e..0000000
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ /dev/null
@@ -1,903 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "RTSPSource2"
-#include <utils/Log.h>
-
-#include "RTSPSource2.h"
-
-#include "AnotherPacketSource.h"
-#include "MyHandler.h"
-#include "SDPLoader.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-const int64_t kNearEOSTimeoutUs = 2000000LL; // 2 secs
-
-// Default Buffer Underflow/Prepare/StartServer/Overflow Marks
-static const int kUnderflowMarkMs = 1000; // 1 second
-static const int kPrepareMarkMs = 3000; // 3 seconds
-//static const int kStartServerMarkMs = 5000;
-static const int kOverflowMarkMs = 10000; // 10 seconds
-
-NuPlayer2::RTSPSource2::RTSPSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers,
- uid_t uid,
- bool isSDP)
- : Source(notify),
- mHTTPService(httpService),
- mURL(url),
- mUID(uid),
- mFlags(0),
- mIsSDP(isSDP),
- mState(DISCONNECTED),
- mFinalResult(OK),
- mDisconnectReplyID(0),
- mBuffering(false),
- mInPreparationPhase(true),
- mEOSPending(false),
- mSeekGeneration(0),
- mEOSTimeoutAudio(0),
- mEOSTimeoutVideo(0) {
- mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kOverflowMarkMs;
- if (headers) {
- mExtraHeaders = *headers;
-
- ssize_t index =
- mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
-
- if (index >= 0) {
- mFlags |= kFlagIncognito;
-
- mExtraHeaders.removeItemsAt(index);
- }
- }
-}
-
-NuPlayer2::RTSPSource2::~RTSPSource2() {
- if (mLooper != NULL) {
- mLooper->unregisterHandler(id());
- mLooper->stop();
- }
-}
-
-status_t NuPlayer2::RTSPSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- Mutex::Autolock _l(mBufferingSettingsLock);
- *buffering = mBufferingSettings;
- return OK;
-}
-
-status_t NuPlayer2::RTSPSource2::setBufferingSettings(const BufferingSettings& buffering) {
- Mutex::Autolock _l(mBufferingSettingsLock);
- mBufferingSettings = buffering;
- return OK;
-}
-
-// TODO: fetch data starting from |startTimeUs|
-void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
- if (mIsSDP && mHTTPService == NULL) {
- notifyPrepared(BAD_VALUE);
- return;
- }
-
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("rtsp2");
- mLooper->start();
-
- mLooper->registerHandler(this);
- }
-
- CHECK(mHandler == NULL);
- CHECK(mSDPLoader == NULL);
-
- sp<AMessage> notify = new AMessage(kWhatNotify, this);
-
- CHECK_EQ(mState, (int)DISCONNECTED);
- mState = CONNECTING;
-
- if (mIsSDP) {
- mSDPLoader = new SDPLoader(notify,
- (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
- mHTTPService);
-
- mSDPLoader->load(
- mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
- } else {
- mHandler = new MyHandler(mURL.c_str(), notify, true /* uidValid */, mUID);
- mLooper->registerHandler(mHandler);
-
- mHandler->connect();
- }
-
- startBufferingIfNecessary();
-}
-
-void NuPlayer2::RTSPSource2::start() {
-}
-
-void NuPlayer2::RTSPSource2::stop() {
- if (mLooper == NULL) {
- return;
- }
- sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
-
- sp<AMessage> dummy;
- msg->postAndAwaitResponse(&dummy);
-}
-
-status_t NuPlayer2::RTSPSource2::feedMoreTSData() {
- Mutex::Autolock _l(mBufferingLock);
- return mFinalResult;
-}
-
-sp<MetaData> NuPlayer2::RTSPSource2::getFormatMeta(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
-
- if (source == NULL) {
- return NULL;
- }
-
- return source->getFormat();
-}
-
-bool NuPlayer2::RTSPSource2::haveSufficientDataOnAllTracks() {
- // We're going to buffer at least 2 secs worth data on all tracks before
- // starting playback (both at startup and after a seek).
-
- static const int64_t kMinDurationUs = 2000000LL;
-
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs))
- || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) {
- return true;
- }
-
- status_t err;
- int64_t durationUs;
- if (mAudioTrack != NULL
- && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
- < kMinDurationUs
- && err == OK) {
- ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
- durationUs / 1E6);
- return false;
- }
-
- if (mVideoTrack != NULL
- && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
- < kMinDurationUs
- && err == OK) {
- ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
- durationUs / 1E6);
- return false;
- }
-
- return true;
-}
-
-status_t NuPlayer2::RTSPSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- if (!stopBufferingIfNecessary()) {
- return -EWOULDBLOCK;
- }
-
- sp<AnotherPacketSource> source = getSource(audio);
-
- if (source == NULL) {
- return -EWOULDBLOCK;
- }
-
- status_t finalResult;
- if (!source->hasBufferAvailable(&finalResult)) {
- if (finalResult == OK) {
-
- // If other source already signaled EOS, this source should also return EOS
- if (sourceReachedEOS(!audio)) {
- return ERROR_END_OF_STREAM;
- }
-
- // If this source has detected near end, give it some time to retrieve more
- // data before returning EOS
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- if (source->isFinished(mediaDurationUs)) {
- int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
- if (eosTimeout == 0) {
- setEOSTimeout(audio, ALooper::GetNowUs());
- } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
- setEOSTimeout(audio, 0);
- return ERROR_END_OF_STREAM;
- }
- return -EWOULDBLOCK;
- }
-
- if (!sourceNearEOS(!audio)) {
- // We should not enter buffering mode
- // if any of the sources already have detected EOS.
- startBufferingIfNecessary();
- }
-
- return -EWOULDBLOCK;
- }
- return finalResult;
- }
-
- setEOSTimeout(audio, 0);
-
- return source->dequeueAccessUnit(accessUnit);
-}
-
-sp<AnotherPacketSource> NuPlayer2::RTSPSource2::getSource(bool audio) {
- if (mTSParser != NULL) {
- sp<MediaSource> source = mTSParser->getSource(
- audio ? ATSParser::AUDIO : ATSParser::VIDEO);
-
- return static_cast<AnotherPacketSource *>(source.get());
- }
-
- return audio ? mAudioTrack : mVideoTrack;
-}
-
-void NuPlayer2::RTSPSource2::setEOSTimeout(bool audio, int64_t timeout) {
- if (audio) {
- mEOSTimeoutAudio = timeout;
- } else {
- mEOSTimeoutVideo = timeout;
- }
-}
-
-status_t NuPlayer2::RTSPSource2::getDuration(int64_t *durationUs) {
- *durationUs = -1LL;
-
- int64_t audioDurationUs;
- if (mAudioTrack != NULL
- && mAudioTrack->getFormat()->findInt64(
- kKeyDuration, &audioDurationUs)
- && audioDurationUs > *durationUs) {
- *durationUs = audioDurationUs;
- }
-
- int64_t videoDurationUs;
- if (mVideoTrack != NULL
- && mVideoTrack->getFormat()->findInt64(
- kKeyDuration, &videoDurationUs)
- && videoDurationUs > *durationUs) {
- *durationUs = videoDurationUs;
- }
-
- return OK;
-}
-
-status_t NuPlayer2::RTSPSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- sp<AMessage> msg = new AMessage(kWhatPerformSeek, this);
- msg->setInt32("generation", ++mSeekGeneration);
- msg->setInt64("timeUs", seekTimeUs);
- msg->setInt32("mode", mode);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer2::RTSPSource2::performSeek(int64_t seekTimeUs) {
- if (mState != CONNECTED) {
- finishSeek(INVALID_OPERATION);
- return;
- }
-
- mState = SEEKING;
- mHandler->seek(seekTimeUs);
- mEOSPending = false;
-}
-
-void NuPlayer2::RTSPSource2::schedulePollBuffering() {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->post(1000000LL); // 1 second intervals
-}
-
-void NuPlayer2::RTSPSource2::checkBuffering(
- bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) {
- size_t numTracks = mTracks.size();
- size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount;
- preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0;
-
- size_t count = numTracks;
- for (size_t i = 0; i < count; ++i) {
- status_t finalResult;
- TrackInfo *info = &mTracks.editItemAt(i);
- sp<AnotherPacketSource> src = info->mSource;
- if (src == NULL) {
- --numTracks;
- continue;
- }
- int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
-
- int64_t initialMarkUs;
- int64_t maxRebufferingMarkUs;
- {
- Mutex::Autolock _l(mBufferingSettingsLock);
- initialMarkUs = mBufferingSettings.mInitialMarkMs * 1000LL;
- // TODO: maxRebufferingMarkUs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs * 1000ll.
- maxRebufferingMarkUs = mBufferingSettings.mResumePlaybackMarkMs * 1000LL;
- }
- // isFinished when duration is 0 checks for EOS result only
- if (bufferedDurationUs > initialMarkUs
- || src->isFinished(/* duration */ 0)) {
- ++preparedCount;
- }
-
- if (src->isFinished(/* duration */ 0)) {
- ++overflowCount;
- ++finishedCount;
- } else {
- // TODO: redefine kUnderflowMarkMs to a fair value,
- if (bufferedDurationUs < kUnderflowMarkMs * 1000) {
- ++underflowCount;
- }
- if (bufferedDurationUs > maxRebufferingMarkUs) {
- ++overflowCount;
- }
- int64_t startServerMarkUs =
- (kUnderflowMarkMs * 1000LL + maxRebufferingMarkUs) / 2;
- if (bufferedDurationUs < startServerMarkUs) {
- ++startCount;
- }
- }
- }
-
- *prepared = (preparedCount == numTracks);
- *underflow = (underflowCount > 0);
- *overflow = (overflowCount == numTracks);
- *startServer = (startCount > 0);
- *finished = (finishedCount > 0);
-}
-
-void NuPlayer2::RTSPSource2::onPollBuffering() {
- bool prepared, underflow, overflow, startServer, finished;
- checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished);
-
- if (prepared && mInPreparationPhase) {
- mInPreparationPhase = false;
- notifyPrepared();
- }
-
- if (!mInPreparationPhase && underflow) {
- startBufferingIfNecessary();
- }
-
- if (haveSufficientDataOnAllTracks()) {
- stopBufferingIfNecessary();
- }
-
- if (overflow && mHandler != NULL) {
- mHandler->pause();
- }
-
- if (startServer && mHandler != NULL) {
- mHandler->resume();
- }
-
- if (finished && mHandler != NULL) {
- mHandler->cancelAccessUnitTimeoutCheck();
- }
-
- schedulePollBuffering();
-}
-
-void NuPlayer2::RTSPSource2::signalSourceEOS(status_t result) {
- const bool audio = true;
- const bool video = false;
-
- sp<AnotherPacketSource> source = getSource(audio);
- if (source != NULL) {
- source->signalEOS(result);
- }
-
- source = getSource(video);
- if (source != NULL) {
- source->signalEOS(result);
- }
-}
-
-bool NuPlayer2::RTSPSource2::sourceReachedEOS(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
- status_t finalResult;
- return (source != NULL &&
- !source->hasBufferAvailable(&finalResult) &&
- finalResult == ERROR_END_OF_STREAM);
-}
-
-bool NuPlayer2::RTSPSource2::sourceNearEOS(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- return (source != NULL && source->isFinished(mediaDurationUs));
-}
-
-void NuPlayer2::RTSPSource2::onSignalEOS(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mSeekGeneration) {
- return;
- }
-
- if (mEOSPending) {
- signalSourceEOS(ERROR_END_OF_STREAM);
- mEOSPending = false;
- }
-}
-
-void NuPlayer2::RTSPSource2::postSourceEOSIfNecessary() {
- const bool audio = true;
- const bool video = false;
- // If a source has detected near end, give it some time to retrieve more
- // data before signaling EOS
- if (sourceNearEOS(audio) || sourceNearEOS(video)) {
- if (!mEOSPending) {
- sp<AMessage> msg = new AMessage(kWhatSignalEOS, this);
- msg->setInt32("generation", mSeekGeneration);
- msg->post(kNearEOSTimeoutUs);
- mEOSPending = true;
- }
- }
-}
-
-void NuPlayer2::RTSPSource2::onMessageReceived(const sp<AMessage> &msg) {
- if (msg->what() == kWhatDisconnect) {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- mDisconnectReplyID = replyID;
- finishDisconnectIfPossible();
- return;
- } else if (msg->what() == kWhatPerformSeek) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- CHECK(msg->senderAwaitsResponse(&mSeekReplyID));
-
- if (generation != mSeekGeneration) {
- // obsolete.
- finishSeek(OK);
- return;
- }
-
- int64_t seekTimeUs;
- int32_t mode;
- CHECK(msg->findInt64("timeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
-
- // TODO: add "mode" to performSeek.
- performSeek(seekTimeUs/*, (MediaPlayer2SeekMode)mode */);
- return;
- } else if (msg->what() == kWhatPollBuffering) {
- onPollBuffering();
- return;
- } else if (msg->what() == kWhatSignalEOS) {
- onSignalEOS(msg);
- return;
- }
-
- CHECK_EQ(msg->what(), kWhatNotify);
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case MyHandler::kWhatConnected:
- {
- onConnected();
-
- notifyVideoSizeChanged();
-
- uint32_t flags = 0;
-
- if (mHandler->isSeekable()) {
- flags = FLAG_CAN_PAUSE
- | FLAG_CAN_SEEK
- | FLAG_CAN_SEEK_BACKWARD
- | FLAG_CAN_SEEK_FORWARD;
- }
-
- notifyFlagsChanged(flags);
- schedulePollBuffering();
- break;
- }
-
- case MyHandler::kWhatDisconnected:
- {
- onDisconnected(msg);
- break;
- }
-
- case MyHandler::kWhatSeekDone:
- {
- mState = CONNECTED;
- // Unblock seekTo here in case we attempted to seek in a live stream
- finishSeek(OK);
- break;
- }
-
- case MyHandler::kWhatSeekPaused:
- {
- sp<AnotherPacketSource> source = getSource(true /* audio */);
- if (source != NULL) {
- source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
- /* extra */ NULL,
- /* discard */ true);
- }
- source = getSource(false /* video */);
- if (source != NULL) {
- source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
- /* extra */ NULL,
- /* discard */ true);
- };
-
- status_t err = OK;
- msg->findInt32("err", &err);
-
- if (err == OK) {
- int64_t timeUs;
- CHECK(msg->findInt64("time", &timeUs));
- mHandler->continueSeekAfterPause(timeUs);
- } else {
- finishSeek(err);
- }
- break;
- }
-
- case MyHandler::kWhatAccessUnit:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
-
- if (mTSParser == NULL) {
- CHECK_LT(trackIndex, mTracks.size());
- } else {
- CHECK_EQ(trackIndex, 0u);
- }
-
- sp<ABuffer> accessUnit;
- CHECK(msg->findBuffer("accessUnit", &accessUnit));
-
- int32_t damaged;
- if (accessUnit->meta()->findInt32("damaged", &damaged)
- && damaged) {
- ALOGI("dropping damaged access unit.");
- break;
- }
-
- if (mTSParser != NULL) {
- size_t offset = 0;
- status_t err = OK;
- while (offset + 188 <= accessUnit->size()) {
- err = mTSParser->feedTSPacket(
- accessUnit->data() + offset, 188);
- if (err != OK) {
- break;
- }
-
- offset += 188;
- }
-
- if (offset < accessUnit->size()) {
- err = ERROR_MALFORMED;
- }
-
- if (err != OK) {
- signalSourceEOS(err);
- }
-
- postSourceEOSIfNecessary();
- break;
- }
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
-
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- uint32_t rtpTime;
- CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-
- if (!info->mNPTMappingValid) {
- // This is a live stream, we didn't receive any normal
- // playtime mapping. We won't map to npt time.
- source->queueAccessUnit(accessUnit);
- break;
- }
-
- int64_t nptUs =
- ((double)rtpTime - (double)info->mRTPTime)
- / info->mTimeScale
- * 1000000LL
- + info->mNormalPlaytimeUs;
-
- accessUnit->meta()->setInt64("timeUs", nptUs);
-
- source->queueAccessUnit(accessUnit);
- }
- postSourceEOSIfNecessary();
- break;
- }
-
- case MyHandler::kWhatEOS:
- {
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
- CHECK_NE(finalResult, (status_t)OK);
-
- if (mTSParser != NULL) {
- signalSourceEOS(finalResult);
- }
-
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- source->signalEOS(finalResult);
- }
-
- break;
- }
-
- case MyHandler::kWhatSeekDiscontinuity:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- source->queueDiscontinuity(
- ATSParser::DISCONTINUITY_TIME,
- NULL,
- true /* discard */);
- }
-
- break;
- }
-
- case MyHandler::kWhatNormalPlayTimeMapping:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- uint32_t rtpTime;
- CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
-
- int64_t nptUs;
- CHECK(msg->findInt64("nptUs", &nptUs));
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- info->mRTPTime = rtpTime;
- info->mNormalPlaytimeUs = nptUs;
- info->mNPTMappingValid = true;
- break;
- }
-
- case SDPLoader::kWhatSDPLoaded:
- {
- onSDPLoaded(msg);
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-void NuPlayer2::RTSPSource2::onConnected() {
- CHECK(mAudioTrack == NULL);
- CHECK(mVideoTrack == NULL);
-
- size_t numTracks = mHandler->countTracks();
- for (size_t i = 0; i < numTracks; ++i) {
- int32_t timeScale;
- sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
-
- const char *mime;
- CHECK(format->findCString(kKeyMIMEType, &mime));
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
- // Very special case for MPEG2 Transport Streams.
- CHECK_EQ(numTracks, 1u);
-
- mTSParser = new ATSParser;
- return;
- }
-
- bool isAudio = !strncasecmp(mime, "audio/", 6);
- bool isVideo = !strncasecmp(mime, "video/", 6);
-
- TrackInfo info;
- info.mTimeScale = timeScale;
- info.mRTPTime = 0;
- info.mNormalPlaytimeUs = 0LL;
- info.mNPTMappingValid = false;
-
- if ((isAudio && mAudioTrack == NULL)
- || (isVideo && mVideoTrack == NULL)) {
- sp<AnotherPacketSource> source = new AnotherPacketSource(format);
-
- if (isAudio) {
- mAudioTrack = source;
- } else {
- mVideoTrack = source;
- }
-
- info.mSource = source;
- }
-
- mTracks.push(info);
- }
-
- mState = CONNECTED;
-}
-
-void NuPlayer2::RTSPSource2::onSDPLoaded(const sp<AMessage> &msg) {
- status_t err;
- CHECK(msg->findInt32("result", &err));
-
- mSDPLoader.clear();
-
- if (mDisconnectReplyID != 0) {
- err = UNKNOWN_ERROR;
- }
-
- if (err == OK) {
- sp<ASessionDescription> desc;
- sp<RefBase> obj;
- CHECK(msg->findObject("description", &obj));
- desc = static_cast<ASessionDescription *>(obj.get());
-
- AString rtspUri;
- if (!desc->findAttribute(0, "a=control", &rtspUri)) {
- ALOGE("Unable to find url in SDP");
- err = UNKNOWN_ERROR;
- } else {
- sp<AMessage> notify = new AMessage(kWhatNotify, this);
-
- mHandler = new MyHandler(rtspUri.c_str(), notify, true /* uidValid */, mUID);
- mLooper->registerHandler(mHandler);
-
- mHandler->loadSDP(desc);
- }
- }
-
- if (err != OK) {
- if (mState == CONNECTING) {
- // We're still in the preparation phase, signal that it
- // failed.
- notifyPrepared(err);
- }
-
- mState = DISCONNECTED;
- setError(err);
-
- if (mDisconnectReplyID != 0) {
- finishDisconnectIfPossible();
- }
- }
-}
-
-void NuPlayer2::RTSPSource2::onDisconnected(const sp<AMessage> &msg) {
- if (mState == DISCONNECTED) {
- return;
- }
-
- status_t err;
- CHECK(msg->findInt32("result", &err));
- CHECK_NE(err, (status_t)OK);
-
- mLooper->unregisterHandler(mHandler->id());
- mHandler.clear();
-
- if (mState == CONNECTING) {
- // We're still in the preparation phase, signal that it
- // failed.
- notifyPrepared(err);
- }
-
- mState = DISCONNECTED;
- setError(err);
-
- if (mDisconnectReplyID != 0) {
- finishDisconnectIfPossible();
- }
-}
-
-void NuPlayer2::RTSPSource2::finishDisconnectIfPossible() {
- if (mState != DISCONNECTED) {
- if (mHandler != NULL) {
- mHandler->disconnect();
- } else if (mSDPLoader != NULL) {
- mSDPLoader->cancel();
- }
- return;
- }
-
- (new AMessage)->postReply(mDisconnectReplyID);
- mDisconnectReplyID = 0;
-}
-
-void NuPlayer2::RTSPSource2::setError(status_t err) {
- Mutex::Autolock _l(mBufferingLock);
- mFinalResult = err;
-}
-
-void NuPlayer2::RTSPSource2::startBufferingIfNecessary() {
- Mutex::Autolock _l(mBufferingLock);
-
- if (!mBuffering) {
- mBuffering = true;
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
-}
-
-bool NuPlayer2::RTSPSource2::stopBufferingIfNecessary() {
- Mutex::Autolock _l(mBufferingLock);
-
- if (mBuffering) {
- if (!haveSufficientDataOnAllTracks()) {
- return false;
- }
-
- mBuffering = false;
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
-
- return true;
-}
-
-void NuPlayer2::RTSPSource2::finishSeek(status_t err) {
- if (mSeekReplyID == NULL) {
- return;
- }
- sp<AMessage> seekReply = new AMessage;
- seekReply->setInt32("err", err);
- seekReply->postReply(mSeekReplyID);
- mSeekReplyID = NULL;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
deleted file mode 100644
index e5f1716..0000000
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RTSP_SOURCE2_H_
-
-#define RTSP_SOURCE2_H_
-
-#include "NuPlayer2Source.h"
-
-#include "ATSParser.h"
-
-namespace android {
-
-struct ALooper;
-struct AReplyToken;
-struct AnotherPacketSource;
-struct MyHandler;
-struct SDPLoader;
-
-struct NuPlayer2::RTSPSource2 : public NuPlayer2::Source {
- RTSPSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers,
- uid_t uid = 0,
- bool isSDP = false);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
- virtual void start();
- virtual void stop();
-
- virtual status_t feedMoreTSData();
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
-
- virtual status_t getDuration(int64_t *durationUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
- void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
- virtual ~RTSPSource2();
-
- virtual sp<MetaData> getFormatMeta(bool audio);
-
-private:
- enum {
- kWhatNotify = 'noti',
- kWhatDisconnect = 'disc',
- kWhatPerformSeek = 'seek',
- kWhatPollBuffering = 'poll',
- kWhatSignalEOS = 'eos ',
- };
-
- enum State {
- DISCONNECTED,
- CONNECTING,
- CONNECTED,
- SEEKING,
- };
-
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1,
- };
-
- struct TrackInfo {
- sp<AnotherPacketSource> mSource;
-
- int32_t mTimeScale;
- uint32_t mRTPTime;
- int64_t mNormalPlaytimeUs;
- bool mNPTMappingValid;
- };
-
- sp<MediaHTTPService> mHTTPService;
- AString mURL;
- KeyedVector<String8, String8> mExtraHeaders;
- uid_t mUID;
- uint32_t mFlags;
- bool mIsSDP;
- State mState;
- status_t mFinalResult;
- sp<AReplyToken> mDisconnectReplyID;
- Mutex mBufferingLock;
- bool mBuffering;
- bool mInPreparationPhase;
- bool mEOSPending;
-
- Mutex mBufferingSettingsLock;
- BufferingSettings mBufferingSettings;
-
- sp<ALooper> mLooper;
- sp<MyHandler> mHandler;
- sp<SDPLoader> mSDPLoader;
-
- Vector<TrackInfo> mTracks;
- sp<AnotherPacketSource> mAudioTrack;
- sp<AnotherPacketSource> mVideoTrack;
-
- sp<ATSParser> mTSParser;
-
- int32_t mSeekGeneration;
-
- int64_t mEOSTimeoutAudio;
- int64_t mEOSTimeoutVideo;
-
- sp<AReplyToken> mSeekReplyID;
-
- sp<AnotherPacketSource> getSource(bool audio);
-
- void onConnected();
- void onSDPLoaded(const sp<AMessage> &msg);
- void onDisconnected(const sp<AMessage> &msg);
- void finishDisconnectIfPossible();
-
- void performSeek(int64_t seekTimeUs);
- void schedulePollBuffering();
- void checkBuffering(
- bool *prepared,
- bool *underflow,
- bool *overflow,
- bool *startServer,
- bool *finished);
- void onPollBuffering();
-
- bool haveSufficientDataOnAllTracks();
-
- void setEOSTimeout(bool audio, int64_t timeout);
- void setError(status_t err);
- void startBufferingIfNecessary();
- bool stopBufferingIfNecessary();
- void finishSeek(status_t err);
-
- void postSourceEOSIfNecessary();
- void signalSourceEOS(status_t result);
- void onSignalEOS(const sp<AMessage> &msg);
-
- bool sourceNearEOS(bool audio);
- bool sourceReachedEOS(bool audio);
-
- DISALLOW_EVIL_CONSTRUCTORS(RTSPSource2);
-};
-
-} // namespace android
-
-#endif // RTSP_SOURCE2_H_
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 353044c8..bb7f2a5 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -261,62 +261,3 @@
},
}
-cc_library_static {
- name: "libstagefright_player2",
-
- srcs: [
- "ClearFileSource.cpp",
- "DataURISource.cpp",
- "DataSourceBase.cpp",
- "HTTPBase.cpp",
- "HevcUtils.cpp",
- "MediaClock.cpp",
- "MediaSource.cpp",
- "NdkUtils.cpp",
- "Utils.cpp",
- "VideoFrameSchedulerBase.cpp",
- "VideoFrameScheduler2.cpp",
- "http/ClearMediaHTTP.cpp",
- ],
-
- shared_libs: [
- "libgui",
- "liblog",
- "libnetd_client",
- "libutils",
- "libstagefright_foundation",
- "libandroid",
- ],
-
- static_libs: [
- "libmedia_player2_util",
- "libmedia2_jni_core",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Wno-multichar",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- product_variables: {
- debuggable: {
- // enable experiments only in userdebug and eng builds
- cflags: ["-DENABLE_STAGEFRIGHT_EXPERIMENTS"],
- },
- },
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-}
-
diff --git a/media/libstagefright/VideoFrameScheduler2.cpp b/media/libstagefright/VideoFrameScheduler2.cpp
deleted file mode 100644
index 23671f2..0000000
--- a/media/libstagefright/VideoFrameScheduler2.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VideoFrameScheduler2"
-#include <utils/Log.h>
-#define ATRACE_TAG ATRACE_TAG_VIDEO
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
-#include <utils/Trace.h>
-
-#include <algorithm>
-#include <jni.h>
-#include <math.h>
-
-#include <android/choreographer.h>
-#include <android/looper.h>
-#include <media/stagefright/VideoFrameScheduler2.h>
-#include <mediaplayer2/JavaVMHelper.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AUtils.h>
-
-namespace android {
-
-static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr);
-
-/* ======================================================================= */
-/* VsyncTracker */
-/* ======================================================================= */
-
-class VsyncTracker : public RefBase{
-public:
- VsyncTracker();
- ~VsyncTracker() {}
- nsecs_t getVsyncPeriod();
- nsecs_t getVsyncTime(nsecs_t periodOffset);
- void addSample(nsecs_t timestamp);
-
-private:
- static const int kMaxSamples = 32;
- static const int kMinSamplesForUpdate = 6;
- int mNumSamples;
- int mFirstSample;
- nsecs_t mReferenceTime;
- nsecs_t mPhase;
- nsecs_t mPeriod;
- nsecs_t mTimestampSamples[kMaxSamples];
- Mutex mLock;
-
- void updateModelLocked();
-};
-
-VsyncTracker::VsyncTracker()
- : mNumSamples(0),
- mFirstSample(0),
- mReferenceTime(0),
- mPhase(0),
- mPeriod(0) {
- for (int i = 0; i < kMaxSamples; i++) {
- mTimestampSamples[i] = 0;
- }
-}
-
-nsecs_t VsyncTracker::getVsyncPeriod() {
- Mutex::Autolock dataLock(mLock);
- return mPeriod;
-}
-
-nsecs_t VsyncTracker::getVsyncTime(nsecs_t periodOffset) {
- Mutex::Autolock dataLock(mLock);
- const nsecs_t now = systemTime();
- nsecs_t phase = mReferenceTime + mPhase;
-
- // result = (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase
- // prevent overflow
- nsecs_t result = (now - phase) / mPeriod;
- if (result > LONG_LONG_MAX - periodOffset - 1) {
- return LONG_LONG_MAX;
- } else {
- result += periodOffset + 1;
- }
- if (result > LONG_LONG_MAX / mPeriod) {
- return LONG_LONG_MAX;
- } else {
- result *= mPeriod;
- }
- if (result > LONG_LONG_MAX - phase) {
- return LONG_LONG_MAX;
- } else {
- result += phase;
- }
-
- return result;
-}
-
-void VsyncTracker::addSample(nsecs_t timestamp) {
- Mutex::Autolock dataLock(mLock);
- if (mNumSamples == 0) {
- mPhase = 0;
- mReferenceTime = timestamp;
- }
- int idx = (mFirstSample + mNumSamples) % kMaxSamples;
- mTimestampSamples[idx] = timestamp;
- if (mNumSamples < kMaxSamples) {
- mNumSamples++;
- } else {
- mFirstSample = (mFirstSample + 1) % kMaxSamples;
- }
- updateModelLocked();
-}
-
-void VsyncTracker::updateModelLocked() {
- if (mNumSamples < kMinSamplesForUpdate) {
- return;
- }
- nsecs_t durationSum = 0;
- nsecs_t minDuration = LONG_MAX;
- nsecs_t maxDuration = 0;
-
- for (int i = 1; i < mNumSamples; i++) {
- int idx = (mFirstSample + i) % kMaxSamples;
- int prev = (idx + kMaxSamples - 1) % kMaxSamples;
- long duration = mTimestampSamples[idx] - mTimestampSamples[prev];
- durationSum += duration;
- if (minDuration > duration) { minDuration = duration; }
- if (maxDuration < duration) { maxDuration = duration; }
- }
-
- durationSum -= (minDuration + maxDuration);
- mPeriod = durationSum / (mNumSamples - 3);
-
- double sampleAvgX = 0.0;
- double sampleAvgY = 0.0;
- double scale = 2.0 * M_PI / (double) mPeriod;
-
- for (int i = 1; i < mNumSamples; i++) {
- int idx = (mFirstSample + i) % kMaxSamples;
- long sample = mTimestampSamples[idx] - mReferenceTime;
- double samplePhase = (double) (sample % mPeriod) * scale;
- sampleAvgX += cos(samplePhase);
- sampleAvgY += sin(samplePhase);
- }
-
- sampleAvgX /= (double) mNumSamples - 1.0;
- sampleAvgY /= (double) mNumSamples - 1.0;
- mPhase = (long) (atan2(sampleAvgY, sampleAvgX) / scale);
-}
-
-static void frameCallback(int64_t frameTimeNanos, void* data) {
- if (data == NULL) {
- return;
- }
- sp<VsyncTracker> vsyncTracker(static_cast<VsyncTracker*>(data));
- vsyncTracker->addSample(frameTimeNanos);
- AChoreographer_postFrameCallback64(AChoreographer_getInstance(),
- frameCallback, static_cast<void*>(vsyncTracker.get()));
-}
-
-/* ======================================================================= */
-/* JNI */
-/* ======================================================================= */
-
-static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr) {
- static const nsecs_t kOneMillisecInNanosec = 1000000;
- static const nsecs_t kOneSecInNanosec = kOneMillisecInNanosec * 1000;
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jDisplayManagerGlobalCls = env->FindClass(
- "android/hardware/display/DisplayManagerGlobal");
- jclass jDisplayCls = env->FindClass("android/view/Display");
-
- jmethodID jGetInstance = env->GetStaticMethodID(jDisplayManagerGlobalCls,
- "getInstance", "()Landroid/hardware/display/DisplayManagerGlobal;");
- jobject javaDisplayManagerGlobalObj = env->CallStaticObjectMethod(
- jDisplayManagerGlobalCls, jGetInstance);
-
- jfieldID jDEFAULT_DISPLAY = env->GetStaticFieldID(jDisplayCls, "DEFAULT_DISPLAY", "I");
- jint DEFAULT_DISPLAY = env->GetStaticIntField(jDisplayCls, jDEFAULT_DISPLAY);
-
- jmethodID jgetRealDisplay = env->GetMethodID(jDisplayManagerGlobalCls,
- "getRealDisplay", "(I)Landroid/view/Display;");
- jobject javaDisplayObj = env->CallObjectMethod(
- javaDisplayManagerGlobalObj, jgetRealDisplay, DEFAULT_DISPLAY);
-
- jmethodID jGetRefreshRate = env->GetMethodID(jDisplayCls, "getRefreshRate", "()F");
- jfloat javaRefreshRate = env->CallFloatMethod(javaDisplayObj, jGetRefreshRate);
- nsecs_t vsyncPeriod = (nsecs_t) (kOneSecInNanosec / (float) javaRefreshRate);
-
- jmethodID jGetAppVsyncOffsetNanos = env->GetMethodID(
- jDisplayCls, "getAppVsyncOffsetNanos", "()J");
- jlong javaAppVsyncOffset = env->CallLongMethod(javaDisplayObj, jGetAppVsyncOffsetNanos);
- *appVsyncOffsetPtr = (nsecs_t) javaAppVsyncOffset;
-
- jmethodID jGetPresentationDeadlineNanos = env->GetMethodID(
- jDisplayCls, "getPresentationDeadlineNanos", "()J");
- jlong javaPresentationDeadline = env->CallLongMethod(
- javaDisplayObj, jGetPresentationDeadlineNanos);
-
- *sfVsyncOffsetPtr = vsyncPeriod - ((nsecs_t) javaPresentationDeadline - kOneMillisecInNanosec);
-}
-
-/* ======================================================================= */
-/* Choreographer Thread */
-/* ======================================================================= */
-
-struct ChoreographerThread : public Thread {
- ChoreographerThread(bool canCallJava);
- status_t init(void* data);
- virtual status_t readyToRun() override;
- virtual bool threadLoop() override;
-
-protected:
- virtual ~ChoreographerThread() {}
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(ChoreographerThread);
- void* mData;
-};
-
-ChoreographerThread::ChoreographerThread(bool canCallJava) : Thread(canCallJava) {
-}
-
-status_t ChoreographerThread::init(void* data) {
- if (data == NULL) {
- return NO_INIT;
- }
- mData = data;
- return OK;
-}
-
-status_t ChoreographerThread::readyToRun() {
- ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
- if (AChoreographer_getInstance() == NULL) {
- return NO_INIT;
- }
- AChoreographer_postFrameCallback64(AChoreographer_getInstance(), frameCallback, mData);
- return OK;
-}
-
-bool ChoreographerThread::threadLoop() {
- ALooper_pollOnce(-1, nullptr, nullptr, nullptr);
- return true;
-}
-
-/* ======================================================================= */
-/* Frame Scheduler */
-/* ======================================================================= */
-
-VideoFrameScheduler2::VideoFrameScheduler2() : VideoFrameSchedulerBase() {
-
- getVsyncOffset(&mAppVsyncOffset, &mSfVsyncOffset);
-
- Mutex::Autolock threadLock(mLock);
- mChoreographerThread = new ChoreographerThread(true);
-
- mVsyncTracker = new VsyncTracker();
- if (mChoreographerThread->init(static_cast<void*>(mVsyncTracker.get())) != OK) {
- mChoreographerThread.clear();
- }
- if (mChoreographerThread != NULL && mChoreographerThread->run("Choreographer") != OK) {
- mChoreographerThread.clear();
- }
-}
-
-void VideoFrameScheduler2::updateVsync() {
- mVsyncTime = 0;
- mVsyncPeriod = 0;
-
- if (mVsyncTracker != NULL) {
- mVsyncPeriod = mVsyncTracker->getVsyncPeriod();
- mVsyncTime = mVsyncTracker->getVsyncTime(mSfVsyncOffset - mAppVsyncOffset);
- }
- mVsyncRefreshAt = systemTime(SYSTEM_TIME_MONOTONIC) + kVsyncRefreshPeriod;
-}
-
-void VideoFrameScheduler2::release() {
- // Do not change order
- {
- Mutex::Autolock threadLock(mLock);
- mChoreographerThread->requestExitAndWait();
- mChoreographerThread.clear();
- }
-
- mVsyncTracker.clear();
-}
-
-VideoFrameScheduler2::~VideoFrameScheduler2() {
- release();
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp
index 6935655..4f4ceb1 100644
--- a/media/libstagefright/timedtext/Android.bp
+++ b/media/libstagefright/timedtext/Android.bp
@@ -23,32 +23,4 @@
shared_libs: ["libmedia"],
}
-cc_library_static {
- name: "libstagefright_timedtext2",
- srcs: ["TextDescriptions2.cpp"],
-
- static_libs: [
- "libmediaplayer2-protos",
- "libprotobuf-cpp-lite",
- ],
-
- cflags: [
- "-Wno-multichar",
- "-Werror",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- ],
-
- shared_libs: ["libmedia"],
-}
diff --git a/media/libstagefright/timedtext/TextDescriptions2.cpp b/media/libstagefright/timedtext/TextDescriptions2.cpp
deleted file mode 100644
index f48eacc..0000000
--- a/media/libstagefright/timedtext/TextDescriptions2.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "TextDescriptions2.h"
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-TextDescriptions2::TextDescriptions2() {
-}
-
-status_t TextDescriptions2::getPlayerMessageOfDescriptions(
- const uint8_t *data, ssize_t size,
- uint32_t flags, int timeMs, PlayerMessage *playerMsg) {
- if (flags & IN_BAND_TEXT_3GPP) {
- if (flags & GLOBAL_DESCRIPTIONS) {
- return extract3GPPGlobalDescriptions(data, size, playerMsg);
- } else if (flags & LOCAL_DESCRIPTIONS) {
- return extract3GPPLocalDescriptions(data, size, timeMs, playerMsg);
- }
- } else if (flags & OUT_OF_BAND_TEXT_SRT) {
- if (flags & LOCAL_DESCRIPTIONS) {
- return extractSRTLocalDescriptions(data, size, timeMs, playerMsg);
- }
- }
-
- return ERROR_UNSUPPORTED;
-}
-
-// Parse the SRT text sample, and store the timing and text sample in a PlayerMessage.
-// The PlayerMessage will be sent to MediaPlayer2.java through event, and will be
-// parsed in TimedText.java.
-status_t TextDescriptions2::extractSRTLocalDescriptions(
- const uint8_t *data, ssize_t size, int timeMs, PlayerMessage *playerMsg) {
- playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
- playerMsg->add_values()->set_int32_value(KEY_START_TIME);
- playerMsg->add_values()->set_int32_value(timeMs);
-
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
- playerMsg->add_values()->set_bytes_value(data, size);
-
- return OK;
-}
-
-// Extract the local 3GPP display descriptions. 3GPP local descriptions
-// are appended to the text sample if any.
-status_t TextDescriptions2::extract3GPPLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg) {
-
- playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
-
- // write start time to display this text sample
- playerMsg->add_values()->set_int32_value(KEY_START_TIME);
- playerMsg->add_values()->set_int32_value(timeMs);
-
- if (size < 2) {
- return OK;
- }
- ssize_t textLen = (*data) << 8 | (*(data + 1));
-
- if (size < textLen + 2) {
- return OK;
- }
-
- // write text sample length and text sample itself
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
- playerMsg->add_values()->set_bytes_value(data + 2, textLen);
-
- if (size > textLen + 2) {
- data += (textLen + 2);
- size -= (textLen + 2);
- } else {
- return OK;
- }
-
- while (size >= 8) {
- const uint8_t *tmpData = data;
- ssize_t chunkSize = U32_AT(tmpData); // size includes size and type
- uint32_t chunkType = U32_AT(tmpData + 4);
-
- if (chunkSize <= 8 || chunkSize > size) {
- return OK;
- }
-
- size_t remaining = chunkSize - 8;
-
- tmpData += 8;
-
- switch(chunkType) {
- // 'tbox' box to indicate the position of the text with values
- // of top, left, bottom and right
- case FOURCC('t', 'b', 'o', 'x'):
- {
- if (remaining < 8) {
- return OK;
- }
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
-
- tmpData += 8;
- remaining -= 8;
- break;
- }
- default:
- {
- break;
- }
- }
-
- data += chunkSize;
- size -= chunkSize;
- }
-
- return OK;
-}
-
-// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a PlayerMessage
-status_t TextDescriptions2::extract3GPPGlobalDescriptions(
- const uint8_t *data, ssize_t size, PlayerMessage *playerMsg) {
-
- playerMsg->add_values()->set_int32_value(KEY_GLOBAL_SETTING);
-
- while (size >= 8) {
- ssize_t chunkSize = U32_AT(data);
- uint32_t chunkType = U32_AT(data + 4);
- const uint8_t *tmpData = data;
- tmpData += 8;
- size_t remaining = size - 8;
-
- if (size < chunkSize) {
- return OK;
- }
- switch(chunkType) {
- case FOURCC('t', 'x', '3', 'g'):
- {
- if (remaining < 18) {
- return OK;
- }
- // Skip DISPLAY_FLAGS, STRUCT_JUSTIFICATION, and BACKGROUND_COLOR_RGBA
- tmpData += 18;
- remaining -= 18;
-
- if (remaining < 8) {
- return OK;
- }
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
-
- tmpData += 8;
- remaining -= 18;
- // Ignore remaining data.
- break;
- }
- default:
- {
- break;
- }
- }
-
- data += chunkSize;
- size -= chunkSize;
- }
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TextDescriptions2.h b/media/libstagefright/timedtext/TextDescriptions2.h
deleted file mode 100644
index 7c7d2d0..0000000
--- a/media/libstagefright/timedtext/TextDescriptions2.h
+++ /dev/null
@@ -1,88 +0,0 @@
- /*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TEXT_DESCRIPTIONS2_H_
-
-#define TEXT_DESCRIPTIONS2_H_
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ABase.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
-class TextDescriptions2 {
-public:
- enum {
- IN_BAND_TEXT_3GPP = 0x01,
- OUT_OF_BAND_TEXT_SRT = 0x02,
-
- GLOBAL_DESCRIPTIONS = 0x100,
- LOCAL_DESCRIPTIONS = 0x200,
- };
-
- static status_t getPlayerMessageOfDescriptions(
- const uint8_t *data, ssize_t size,
- uint32_t flags, int timeMs, PlayerMessage *playerMsg);
-private:
- TextDescriptions2();
-
- enum {
- // These keys must be in sync with the keys in TimedText.java
- KEY_DISPLAY_FLAGS = 1, // int
- KEY_STYLE_FLAGS = 2, // int
- KEY_BACKGROUND_COLOR_RGBA = 3, // int
- KEY_HIGHLIGHT_COLOR_RGBA = 4, // int
- KEY_SCROLL_DELAY = 5, // int
- KEY_WRAP_TEXT = 6, // int
- KEY_START_TIME = 7, // int
- KEY_STRUCT_BLINKING_TEXT_LIST = 8, // List<CharPos>
- KEY_STRUCT_FONT_LIST = 9, // List<Font>
- KEY_STRUCT_HIGHLIGHT_LIST = 10, // List<CharPos>
- KEY_STRUCT_HYPER_TEXT_LIST = 11, // List<HyperText>
- KEY_STRUCT_KARAOKE_LIST = 12, // List<Karaoke>
- KEY_STRUCT_STYLE_LIST = 13, // List<Style>
- KEY_STRUCT_TEXT_POS = 14, // TextPos
- KEY_STRUCT_JUSTIFICATION = 15, // Justification
- KEY_STRUCT_TEXT = 16, // Text
-
- KEY_GLOBAL_SETTING = 101,
- KEY_LOCAL_SETTING = 102,
- KEY_START_CHAR = 103,
- KEY_END_CHAR = 104,
- KEY_FONT_ID = 105,
- KEY_FONT_SIZE = 106,
- KEY_TEXT_COLOR_RGBA = 107,
- };
-
- static status_t extractSRTLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg);
- static status_t extract3GPPGlobalDescriptions(
- const uint8_t *data, ssize_t size,
- PlayerMessage *playerMsg);
- static status_t extract3GPPLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg);
-
- DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions2);
-};
-
-} // namespace android
-#endif // TEXT_DESCRIPTIONS2_H_
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index a3cabd8..78c8df5 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -90,7 +90,6 @@
"libhidlbase",
"libgui",
"libui",
- "libmedia2_jni_core",
"libmediandk_utils",
],
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 7979c2f..e567613 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -33,8 +33,6 @@
#include <media/NdkMediaDataSource.h>
#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPService.h>
#include "../../libstagefright/include/HTTPBase.h"
#include "../../libstagefright/include/NuCachedSource2.h"
@@ -120,18 +118,11 @@
return size >= 0 ? OK : UNKNOWN_ERROR;
}
-static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj, int version) {
+static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj) {
if (obj == NULL) {
return NULL;
}
- switch (version) {
- case 1:
- return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
- case 2:
- return new JMedia2HTTPService(env, obj);
- default:
- return NULL;
- }
+ return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
}
static sp<MediaHTTPService> createMediaHttpServiceTemplate(
@@ -139,8 +130,7 @@
const char *uri,
const char *clazz,
const char *method,
- const char *signature,
- int version) {
+ const char *signature) {
jobject service = NULL;
if (env == NULL) {
ALOGE("http service must be created from Java thread");
@@ -167,34 +157,22 @@
env->DeleteLocalRef(juri);
env->ExceptionClear();
- sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service, version);
+ sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service);
return httpService;
}
-sp<MediaHTTPService> createMediaHttpService(const char *uri, int version) {
+sp<MediaHTTPService> createMediaHttpService(const char *uri) {
JNIEnv *env;
const char *clazz, *method, *signature;
- switch (version) {
- case 1:
- env = AndroidRuntime::getJNIEnv();
- clazz = "android/media/MediaHTTPService";
- method = "createHttpServiceBinderIfNecessary";
- signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
- break;
- case 2:
- env = JavaVMHelper::getJNIEnv();
- clazz = "android/media/Media2HTTPService";
- method = "createHTTPService";
- signature = "(Ljava/lang/String;)Landroid/media/Media2HTTPService;";
- break;
- default:
- return NULL;
- }
+ env = AndroidRuntime::getJNIEnv();
+ clazz = "android/media/MediaHTTPService";
+ method = "createHttpServiceBinderIfNecessary";
+ signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
- return createMediaHttpServiceTemplate(env, uri, clazz, method, signature, version);
+ return createMediaHttpServiceTemplate(env, uri, clazz, method, signature);
}
@@ -216,7 +194,7 @@
int numheaders,
const char * const *key_values) {
- sp<MediaHTTPService> service = createMediaHttpService(uri, /* version = */ 1);
+ sp<MediaHTTPService> service = createMediaHttpService(uri);
KeyedVector<String8, String8> headers;
for (int i = 0; i < numheaders; ++i) {
String8 key8(key_values[i * 2]);
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index 16ff974..ddcd7da 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -62,7 +62,7 @@
};
-sp<MediaHTTPService> createMediaHttpService(const char *uri, int version);
+sp<MediaHTTPService> createMediaHttpService(const char *uri);
#endif // _NDK_MEDIA_DATASOURCE_PRIV_H
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index c83b255..0da0740 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -89,7 +89,7 @@
ALOGV("setDataSource(%s)", uri);
- sp<MediaHTTPService> httpService = createMediaHttpService(uri, /* version = */ 1);
+ sp<MediaHTTPService> httpService = createMediaHttpService(uri);
if (httpService == NULL) {
ALOGE("can't create http service");
return AMEDIA_ERROR_UNSUPPORTED;