Merge "Remove obsolete drm manager code"
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 190402e..1040415 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -248,7 +248,7 @@
if (c == 0) return NO_INIT;
sp<BufferQueue> bq = new BufferQueue();
- sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount, synchronousMode);
+ sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/);
cc->setName(String8("ProCamera::mCpuConsumer"));
sp<Surface> stc = new Surface(
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
new file mode 100644
index 0000000..b4a5947
--- /dev/null
+++ b/cmds/screenrecord/Android.mk
@@ -0,0 +1,38 @@
+# Copyright 2013 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ screenrecord.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libutils libbinder libstagefright_foundation \
+ libjpeg libgui libcutils liblog
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/media/libstagefright \
+ frameworks/av/media/libstagefright/include \
+ $(TOP)/frameworks/native/include/media/openmax \
+ external/jpeg
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= screenrecord
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
new file mode 100644
index 0000000..3e79ee0
--- /dev/null
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2013 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 "ScreenRecord"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <utils/Errors.h>
+#include <utils/Thread.h>
+
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/ISurfaceComposer.h>
+#include <ui/DisplayInfo.h>
+#include <media/openmax/OMX_IVCommon.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaMuxer.h>
+#include <media/ICrypto.h>
+
+#include <stdio.h>
+#include <signal.h>
+#include <getopt.h>
+
+using namespace android;
+
+// Command-line parameters.
+static bool gVerbose = false; // chatty on stdout
+static bool gRotate = false; // rotate 90 degrees
+static uint32_t gVideoWidth = 1280; // 720p
+static uint32_t gVideoHeight = 720;
+static uint32_t gBitRate = 4000000; // 4Mbps
+
+// Set by signal handler to stop recording.
+static bool gStopRequested;
+
+// Previous signal handler state, restored after first hit.
+static struct sigaction gOrigSigactionINT;
+static struct sigaction gOrigSigactionHUP;
+
+static const uint32_t kMinBitRate = 100000; // 0.1Mbps
+static const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps
+
+/*
+ * Catch keyboard interrupt signals. On receipt, the "stop requested"
+ * flag is raised, and the original handler is restored (so that, if
+ * we get stuck finishing, a second Ctrl-C will kill the process).
+ */
+static void signalCatcher(int signum)
+{
+ gStopRequested = true;
+ switch (signum) {
+ case SIGINT:
+ sigaction(SIGINT, &gOrigSigactionINT, NULL);
+ break;
+ case SIGHUP:
+ sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
+ break;
+ default:
+ abort();
+ break;
+ }
+}
+
+/*
+ * Configures signal handlers. The previous handlers are saved.
+ *
+ * If the command is run from an interactive adb shell, we get SIGINT
+ * when Ctrl-C is hit. If we're run from the host, the local adb process
+ * gets the signal, and we get a SIGHUP when the terminal disconnects.
+ */
+static status_t configureSignals()
+{
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = signalCatcher;
+ if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) {
+ status_t err = -errno;
+ fprintf(stderr, "Unable to configure SIGINT handler: %s\n",
+ strerror(errno));
+ return err;
+ }
+ if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) {
+ status_t err = -errno;
+ fprintf(stderr, "Unable to configure SIGHUP handler: %s\n",
+ strerror(errno));
+ return err;
+ }
+ return NO_ERROR;
+}
+
+/*
+ * Configures and starts the MediaCodec encoder. Obtains an input surface
+ * from the codec.
+ */
+static status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
+ sp<IGraphicBufferProducer>* pBufferProducer) {
+ status_t err;
+
+ sp<AMessage> format = new AMessage;
+ format->setInt32("width", gVideoWidth);
+ format->setInt32("height", gVideoHeight);
+ format->setString("mime", "video/avc");
+ format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
+ format->setInt32("bitrate", gBitRate);
+ format->setFloat("frame-rate", displayFps);
+ format->setInt32("i-frame-interval", 10);
+
+ /// MediaCodec
+ sp<ALooper> looper = new ALooper;
+ looper->setName("screenrecord_looper");
+ looper->start();
+ ALOGV("Creating codec");
+ sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true);
+ err = codec->configure(format, NULL, NULL,
+ MediaCodec::CONFIGURE_FLAG_ENCODE);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err);
+ return err;
+ }
+
+ ALOGV("Creating buffer producer");
+ sp<IGraphicBufferProducer> bufferProducer;
+ err = codec->createInputSurface(&bufferProducer);
+ if (err != NO_ERROR) {
+ fprintf(stderr,
+ "ERROR: unable to create encoder input surface (err=%d)\n", err);
+ return err;
+ }
+
+ ALOGV("Starting codec");
+ err = codec->start();
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err);
+ return err;
+ }
+
+ *pCodec = codec;
+ *pBufferProducer = bufferProducer;
+ return 0;
+}
+
+/*
+ * Configures the virtual display. When this completes, virtual display
+ * frames will start being sent to the encoder's surface.
+ */
+static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
+ const sp<IGraphicBufferProducer>& bufferProducer,
+ sp<IBinder>* pDisplayHandle) {
+ status_t err;
+
+ // Set the region of the layer stack we're interested in, which in our
+ // case is "all of it". If the app is rotated (so that the width of the
+ // app is based on the height of the display), reverse width/height.
+ bool deviceRotated = mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 &&
+ mainDpyInfo.orientation != DISPLAY_ORIENTATION_180;
+ uint32_t sourceWidth, sourceHeight;
+ if (!deviceRotated) {
+ sourceWidth = mainDpyInfo.w;
+ sourceHeight = mainDpyInfo.h;
+ } else {
+ ALOGV("using rotated width/height");
+ sourceHeight = mainDpyInfo.w;
+ sourceWidth = mainDpyInfo.h;
+ }
+ Rect layerStackRect(sourceWidth, sourceHeight);
+
+ // We need to preserve the aspect ratio of the display.
+ float displayAspect = (float) sourceHeight / (float) sourceWidth;
+
+
+ // Set the way we map the output onto the display surface (which will
+ // be e.g. 1280x720 for a 720p video). The rect is interpreted
+ // post-rotation, so if the display is rotated 90 degrees we need to
+ // "pre-rotate" it by flipping width/height, so that the orientation
+ // adjustment changes it back.
+ //
+ // We might want to encode a portrait display as landscape to use more
+ // of the screen real estate. (If players respect a 90-degree rotation
+ // hint, we can essentially get a 720x1280 video instead of 1280x720.)
+ // In that case, we swap the configured video width/height and then
+ // supply a rotation value to the display projection.
+ uint32_t videoWidth, videoHeight;
+ uint32_t outWidth, outHeight;
+ if (!gRotate) {
+ videoWidth = gVideoWidth;
+ videoHeight = gVideoHeight;
+ } else {
+ videoWidth = gVideoHeight;
+ videoHeight = gVideoWidth;
+ }
+ if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
+ // limited by narrow width; reduce height
+ outWidth = videoWidth;
+ outHeight = (uint32_t)(videoWidth * displayAspect);
+ } else {
+ // limited by short height; restrict width
+ outHeight = videoHeight;
+ outWidth = (uint32_t)(videoHeight / displayAspect);
+ }
+ uint32_t offX, offY;
+ offX = (videoWidth - outWidth) / 2;
+ offY = (videoHeight - outHeight) / 2;
+ Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
+
+ if (gVerbose) {
+ if (gRotate) {
+ printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
+ outHeight, outWidth, offY, offX);
+ } else {
+ printf("Content area is %ux%u at offset x=%d y=%d\n",
+ outWidth, outHeight, offX, offY);
+ }
+ }
+
+
+ sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
+ String8("ScreenRecorder"), false /* secure */);
+
+ SurfaceComposerClient::openGlobalTransaction();
+ SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
+ SurfaceComposerClient::setDisplayProjection(dpy,
+ gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
+ layerStackRect, displayRect);
+ SurfaceComposerClient::setDisplayLayerStack(dpy, 0); // default stack
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ *pDisplayHandle = dpy;
+
+ return NO_ERROR;
+}
+
+/*
+ * Runs the MediaCodec encoder, sending the output to the MediaMuxer. The
+ * input frames are coming from the virtual display as fast as SurfaceFlinger
+ * wants to send them.
+ *
+ * The muxer must *not* have been started before calling.
+ */
+static status_t runEncoder(const sp<MediaCodec>& encoder,
+ const sp<MediaMuxer>& muxer) {
+ static int kTimeout = 250000; // be responsive on signal
+ status_t err;
+ ssize_t trackIdx = -1;
+ uint32_t debugNumFrames = 0;
+ time_t debugStartWhen = time(NULL);
+
+ Vector<sp<ABuffer> > buffers;
+ err = encoder->getOutputBuffers(&buffers);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
+ return err;
+ }
+
+ // This is set by the signal handler.
+ gStopRequested = false;
+
+ // Run until we're signaled.
+ while (!gStopRequested) {
+ size_t bufIndex, offset, size;
+ int64_t ptsUsec;
+ uint32_t flags;
+ ALOGV("Calling dequeueOutputBuffer");
+ err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
+ &flags, kTimeout);
+ ALOGV("dequeueOutputBuffer returned %d", err);
+ switch (err) {
+ case NO_ERROR:
+ // got a buffer
+ if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
+ // ignore this -- we passed the CSD into MediaMuxer when
+ // we got the format change notification
+ ALOGV("Got codec config buffer (%u bytes); ignoring", size);
+ size = 0;
+ }
+ if (size != 0) {
+ ALOGV("Got data in buffer %d, size=%d, pts=%lld",
+ bufIndex, size, ptsUsec);
+ CHECK(trackIdx != -1);
+
+ // The MediaMuxer docs are unclear, but it appears that we
+ // need to pass either the full set of BufferInfo flags, or
+ // (flags & BUFFER_FLAG_SYNCFRAME).
+ err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
+ ptsUsec, flags);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed writing data to muxer (err=%d)\n",
+ err);
+ return err;
+ }
+ debugNumFrames++;
+ }
+ err = encoder->releaseOutputBuffer(bufIndex);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Unable to release output buffer (err=%d)\n",
+ err);
+ return err;
+ }
+ if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
+ // Not expecting EOS from SurfaceFlinger. Go with it.
+ ALOGD("Received end-of-stream");
+ gStopRequested = false;
+ }
+ break;
+ case -EAGAIN: // INFO_TRY_AGAIN_LATER
+ // not expected with infinite timeout
+ ALOGV("Got -EAGAIN, looping");
+ break;
+ case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED
+ {
+ // format includes CSD, which we must provide to muxer
+ ALOGV("Encoder format changed");
+ sp<AMessage> newFormat;
+ encoder->getOutputFormat(&newFormat);
+ trackIdx = muxer->addTrack(newFormat);
+ ALOGV("Starting muxer");
+ err = muxer->start();
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
+ return err;
+ }
+ }
+ break;
+ case INFO_OUTPUT_BUFFERS_CHANGED: // INFO_OUTPUT_BUFFERS_CHANGED
+ // not expected for an encoder; handle it anyway
+ ALOGV("Encoder buffers changed");
+ err = encoder->getOutputBuffers(&buffers);
+ if (err != NO_ERROR) {
+ fprintf(stderr,
+ "Unable to get new output buffers (err=%d)\n", err);
+ }
+ break;
+ default:
+ ALOGW("Got weird result %d from dequeueOutputBuffer", err);
+ return err;
+ }
+ }
+
+ ALOGV("Encoder stopping (req=%d)", gStopRequested);
+ if (gVerbose) {
+ printf("Encoder stopping; recorded %u frames in %ld seconds\n",
+ debugNumFrames, time(NULL) - debugStartWhen);
+ }
+ return NO_ERROR;
+}
+
+/*
+ * Main "do work" method.
+ *
+ * Configures codec, muxer, and virtual display, then starts moving bits
+ * around.
+ */
+static status_t recordScreen(const char* fileName) {
+ status_t err;
+
+ if (gVerbose) {
+ printf("Recording %dx%d video at %.2fMbps\n",
+ gVideoWidth, gVideoHeight, gBitRate / 1000000.0);
+ }
+
+ // Configure signal handler.
+ err = configureSignals();
+ if (err != NO_ERROR) return err;
+
+ // Start Binder thread pool. MediaCodec needs to be able to receive
+ // messages from mediaserver.
+ sp<ProcessState> self = ProcessState::self();
+ self->startThreadPool();
+
+ // Get main display parameters.
+ sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain);
+ DisplayInfo mainDpyInfo;
+ err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to get display characteristics\n");
+ return err;
+ }
+ if (gVerbose) {
+ printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
+ mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
+ mainDpyInfo.orientation);
+ }
+
+ // Configure and start the encoder.
+ sp<MediaCodec> encoder;
+ sp<IGraphicBufferProducer> bufferProducer;
+ err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
+ if (err != NO_ERROR) return err;
+
+ // Configure virtual display.
+ sp<IBinder> dpy;
+ err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
+ if (err != NO_ERROR) return err;
+
+ // Configure, but do not start, muxer.
+ sp<MediaMuxer> muxer = new MediaMuxer(fileName,
+ MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ if (gRotate) {
+ muxer->setOrientationHint(90);
+ }
+
+ // Main encoder loop.
+ err = runEncoder(encoder, muxer);
+ if (err != NO_ERROR) return err;
+
+ if (gVerbose) {
+ printf("Stopping encoder and muxer\n");
+ }
+
+ // Shut everything down.
+ //
+ // The virtual display will continue to produce frames until "dpy"
+ // goes out of scope (and something causes the Binder traffic to transmit;
+ // can be forced with IPCThreadState::self()->flushCommands()). This
+ // could cause SurfaceFlinger to get stuck trying to feed us, so we want
+ // to set a NULL Surface to make the virtual display "dormant".
+ bufferProducer = NULL;
+ SurfaceComposerClient::openGlobalTransaction();
+ SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ encoder->stop();
+ muxer->stop();
+ encoder->release();
+
+ return 0;
+}
+
+/*
+ * Parses a string of the form "1280x720".
+ *
+ * Returns true on success.
+ */
+static bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth,
+ uint32_t* pHeight) {
+ long width, height;
+ char* end;
+
+ // Must specify base 10, or "0x0" gets parsed differently.
+ width = strtol(widthHeight, &end, 10);
+ if (end == widthHeight || *end != 'x' || *(end+1) == '\0') {
+ // invalid chars in width, or missing 'x', or missing height
+ return false;
+ }
+ height = strtol(end + 1, &end, 10);
+ if (*end != '\0') {
+ // invalid chars in height
+ return false;
+ }
+
+ *pWidth = width;
+ *pHeight = height;
+ return true;
+}
+
+/*
+ * Dumps usage on stderr.
+ */
+static void usage() {
+ fprintf(stderr,
+ "Usage: screenrecord [options] <filename>\n"
+ "\n"
+ "Options:\n"
+ "--size WIDTHxHEIGHT\n"
+ " Set the video size, e.g. \"1280x720\". For best results, use\n"
+ " a size supported by the AVC encoder.\n"
+ "--bit-rate RATE\n"
+ " Set the video bit rate, in megabits per second. Default 4Mbps.\n"
+ "--rotate\n"
+ " Rotate the output 90 degrees. Useful for filling the frame\n"
+ " when in portrait mode.\n"
+ "--verbose\n"
+ " Display interesting information on stdout.\n"
+ "--help\n"
+ " Show this message.\n"
+ "\n"
+ "Recording continues until Ctrl-C is hit.\n"
+ "\n"
+ );
+}
+
+/*
+ * Parses args and kicks things off.
+ */
+int main(int argc, char* const argv[]) {
+ static const struct option longOptions[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "size", required_argument, NULL, 's' },
+ { "bit-rate", required_argument, NULL, 'b' },
+ { "rotate", no_argument, NULL, 'r' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while (true) {
+ int optionIndex = 0;
+ int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
+ if (ic == -1) {
+ break;
+ }
+
+ switch (ic) {
+ case 'h':
+ usage();
+ return 0;
+ case 'v':
+ gVerbose = true;
+ break;
+ case 's':
+ if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) {
+ fprintf(stderr, "Invalid size '%s', must be width x height\n",
+ optarg);
+ return 2;
+ }
+ if (gVideoWidth == 0 || gVideoHeight == 0) {
+ fprintf(stderr,
+ "Invalid size %ux%u, width and height may not be zero\n",
+ gVideoWidth, gVideoHeight);
+ return 2;
+ }
+ break;
+ case 'b':
+ gBitRate = atoi(optarg);
+ if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) {
+ fprintf(stderr,
+ "Bit rate %dbps outside acceptable range [%d,%d]\n",
+ gBitRate, kMinBitRate, kMaxBitRate);
+ return 2;
+ }
+ break;
+ case 'r':
+ gRotate = true;
+ break;
+ default:
+ if (ic != '?') {
+ fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
+ }
+ return 2;
+ }
+ }
+
+ if (optind != argc - 1) {
+ fprintf(stderr, "Must specify output file (see --help).\n");
+ return 2;
+ }
+
+ status_t err = recordScreen(argv[optind]);
+ ALOGD(err == NO_ERROR ? "success" : "failed");
+ return (int) err;
+}
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index fb1d631..e7b85c0 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -246,6 +246,8 @@
static uint32_t getPrimaryOutputSamplingRate();
static size_t getPrimaryOutputFrameCount();
+ static status_t setLowRamDevice(bool isLowRamDevice);
+
// Check if hw offload is possible for given format, stream type, sample rate,
// bit rate, duration, video and streaming or offload property is enabled
static bool isOffloadSupported(const audio_offload_info_t& info);
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 0aa5870..de45aa8 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -197,6 +197,10 @@
virtual uint32_t getPrimaryOutputSamplingRate() = 0;
virtual size_t getPrimaryOutputFrameCount() = 0;
+ // Intended for AudioService to inform AudioFlinger of device's low RAM attribute,
+ // and should be called at most once. For a definition of what "low RAM" means, see
+ // android.app.ActivityManager.isLowRamDevice().
+ virtual status_t setLowRamDevice(bool isLowRamDevice) = 0;
};
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 6b9b3be..0d59af0 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -772,6 +772,13 @@
return af->getPrimaryOutputFrameCount();
}
+status_t AudioSystem::setLowRamDevice(bool isLowRamDevice)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setLowRamDevice(isLowRamDevice);
+}
+
void AudioSystem::clearAudioConfigCache()
{
Mutex::Autolock _l(gLock);
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 6bb7df6..2e2c0cc 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -73,6 +73,7 @@
LOAD_HW_MODULE,
GET_PRIMARY_OUTPUT_SAMPLING_RATE,
GET_PRIMARY_OUTPUT_FRAME_COUNT,
+ SET_LOW_RAM_DEVICE,
};
class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -698,6 +699,15 @@
return reply.readInt32();
}
+ virtual status_t setLowRamDevice(bool isLowRamDevice)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32((int) isLowRamDevice);
+ remote()->transact(SET_LOW_RAM_DEVICE, data, &reply);
+ return reply.readInt32();
+ }
+
};
IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -1059,6 +1069,12 @@
reply->writeInt32(getPrimaryOutputFrameCount());
return NO_ERROR;
} break;
+ case SET_LOW_RAM_DEVICE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ bool isLowRamDevice = data.readInt32() != 0;
+ reply->writeInt32(setLowRamDevice(isLowRamDevice));
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 9544dbc..90bf324 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -62,6 +62,7 @@
$(TOP)/frameworks/av/include/media/stagefright/timedtext \
$(TOP)/frameworks/native/include/media/hardware \
$(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/native/services/connectivitymanager \
$(TOP)/external/flac/include \
$(TOP)/external/tremolo \
$(TOP)/external/openssl/include \
@@ -69,6 +70,7 @@
LOCAL_SHARED_LIBRARIES := \
libbinder \
libcamera_client \
+ libconnectivitymanager \
libcutils \
libdl \
libdrmframework \
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index d2cc6c2..5fa4b6f 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -30,6 +30,8 @@
#include <cutils/properties.h>
#include <cutils/qtaguid.h>
+#include <ConnectivityManager.h>
+
namespace android {
HTTPBase::HTTPBase()
@@ -164,4 +166,14 @@
}
}
+// static
+void HTTPBase::RegisterSocketUserMark(int sockfd, uid_t uid) {
+ ConnectivityManager::markSocketAsUser(sockfd, uid);
+}
+
+// static
+void HTTPBase::UnRegisterSocketUserMark(int sockfd) {
+ RegisterSocketUserMark(sockfd, geteuid());
+}
+
} // namespace android
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 305e7e0..befd4cc 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -21,7 +21,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <OMX_IVCommon.h>
-#include <MetadataBufferType.h>
+#include <media/hardware/MetadataBufferType.h>
#include <ui/GraphicBuffer.h>
#include <gui/ISurfaceComposer.h>
@@ -54,9 +54,8 @@
ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
}
- mBufferQueue = new BufferQueue(true);
+ mBufferQueue = new BufferQueue();
mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
- mBufferQueue->setSynchronousMode(true);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
GRALLOC_USAGE_HW_TEXTURE);
@@ -71,7 +70,7 @@
listener = static_cast<BufferQueue::ConsumerListener*>(this);
proxy = new BufferQueue::ProxyConsumerListener(listener);
- status_t err = mBufferQueue->consumerConnect(proxy);
+ status_t err = mBufferQueue->consumerConnect(proxy, false);
if (err != NO_ERROR) {
ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)",
strerror(-err), err);
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index d8456fe..5f2b5c8 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -149,7 +149,8 @@
mLevel(OMX_VIDEO_VP8Level_Version0),
mConversionBuffer(NULL),
mInputDataIsMeta(false),
- mGrallocModule(NULL) {
+ mGrallocModule(NULL),
+ mKeyFrameRequested(false) {
initPorts();
}
@@ -519,6 +520,27 @@
}
}
+OMX_ERRORTYPE SoftVPXEncoder::setConfig(
+ OMX_INDEXTYPE index, const OMX_PTR _params) {
+ switch (index) {
+ case OMX_IndexConfigVideoIntraVOPRefresh:
+ {
+ OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
+ (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
+
+ if (params->nPortIndex != kOutputPortIndex) {
+ return OMX_ErrorBadPortIndex;
+ }
+
+ mKeyFrameRequested = params->IntraRefreshVOP;
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::setConfig(index, _params);
+ }
+}
+
OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel(
const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) {
if (profileAndLevel->nPortIndex != kOutputPortIndex) {
@@ -750,12 +772,19 @@
vpx_image_t raw_frame;
vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
kInputBufferAlignment, source);
+
+ vpx_enc_frame_flags_t flags = 0;
+ if (mKeyFrameRequested) {
+ flags |= VPX_EFLAG_FORCE_KF;
+ mKeyFrameRequested = false;
+ }
+
codec_return = vpx_codec_encode(
mCodecContext,
&raw_frame,
inputBufferHeader->nTimeStamp, // in timebase units
mFrameDurationUs, // frame duration in timebase units
- 0, // frame flags
+ flags, // frame flags
VPX_DL_REALTIME); // encoding deadline
if (codec_return != VPX_CODEC_OK) {
ALOGE("vpx encoder failed to encode frame");
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index d570154..4ee5e51 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -78,6 +78,9 @@
virtual OMX_ERRORTYPE internalSetParameter(
OMX_INDEXTYPE index, const OMX_PTR param);
+ virtual OMX_ERRORTYPE setConfig(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
// OMX callback when buffers available
// Note that both an input and output buffer
// is expected to be available to carry out
@@ -163,6 +166,8 @@
bool mInputDataIsMeta;
const hw_module_t *mGrallocModule;
+ bool mKeyFrameRequested;
+
// Initializes input and output OMX ports with sensible
// default values.
void initPorts();
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index c2dc351..d4b7f9f 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -59,6 +59,9 @@
static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
static void UnRegisterSocketUserTag(int sockfd);
+ static void RegisterSocketUserMark(int sockfd, uid_t uid);
+ static void UnRegisterSocketUserMark(int sockfd);
+
protected:
void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 6f3ed0d..d6fd95b 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -18,12 +18,12 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
-#include <GraphicBufferSource.h>
+#include "GraphicBufferSource.h"
#include <OMX_Core.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <MetadataBufferType.h>
+#include <media/hardware/MetadataBufferType.h>
#include <ui/GraphicBuffer.h>
namespace android {
@@ -52,10 +52,9 @@
String8 name("GraphicBufferSource");
- mBufferQueue = new BufferQueue(true);
+ mBufferQueue = new BufferQueue();
mBufferQueue->setConsumerName(name);
mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
- mBufferQueue->setSynchronousMode(true);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
GRALLOC_USAGE_HW_TEXTURE);
@@ -76,7 +75,7 @@
sp<BufferQueue::ConsumerListener> proxy;
proxy = new BufferQueue::ProxyConsumerListener(listener);
- mInitCheck = mBufferQueue->consumerConnect(proxy);
+ mInitCheck = mBufferQueue->consumerConnect(proxy, false);
if (mInitCheck != NO_ERROR) {
ALOGE("Error connecting to BufferQueue: %s (%d)",
strerror(-mInitCheck), mInitCheck);
@@ -131,10 +130,12 @@
void GraphicBufferSource::omxLoaded(){
Mutex::Autolock autoLock(mMutex);
- ALOGV("--> loaded");
- CHECK(mExecuting);
+ if (!mExecuting) {
+ // This can happen if something failed very early.
+ ALOGW("Dropped back down to Loaded without Executing");
+ }
- ALOGV("Dropped down to loaded, avail=%d eos=%d eosSent=%d",
+ ALOGV("--> loaded; avail=%d eos=%d eosSent=%d",
mNumFramesAvailable, mEndOfStream, mEndOfStreamSent);
// Codec is no longer executing. Discard all codec-related state.
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 3068541..906aef3 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -60,6 +60,7 @@
ALOGE("Connection is still open, closing the socket.");
if (mUIDValid) {
HTTPBase::UnRegisterSocketUserTag(mSocket);
+ HTTPBase::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -214,6 +215,7 @@
if (mState != DISCONNECTED) {
if (mUIDValid) {
HTTPBase::UnRegisterSocketUserTag(mSocket);
+ HTTPBase::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -266,6 +268,7 @@
if (mUIDValid) {
HTTPBase::RegisterSocketUserTag(mSocket, mUID,
(uint32_t)*(uint32_t*) "RTSP");
+ HTTPBase::RegisterSocketUserMark(mSocket, mUID);
}
MakeSocketBlocking(mSocket, false);
@@ -295,6 +298,7 @@
if (mUIDValid) {
HTTPBase::UnRegisterSocketUserTag(mSocket);
+ HTTPBase::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -312,6 +316,7 @@
void ARTSPConnection::performDisconnect() {
if (mUIDValid) {
HTTPBase::UnRegisterSocketUserTag(mSocket);
+ HTTPBase::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
@@ -385,6 +390,7 @@
mState = DISCONNECTED;
if (mUIDValid) {
HTTPBase::UnRegisterSocketUserTag(mSocket);
+ HTTPBase::UnRegisterSocketUserMark(mSocket);
}
close(mSocket);
mSocket = -1;
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index e51d9e3..946f602 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -712,7 +712,9 @@
// Clear the tag
if (mUIDValid) {
HTTPBase::UnRegisterSocketUserTag(track->mRTPSocket);
+ HTTPBase::UnRegisterSocketUserMark(track->mRTPSocket);
HTTPBase::UnRegisterSocketUserTag(track->mRTCPSocket);
+ HTTPBase::UnRegisterSocketUserMark(track->mRTCPSocket);
}
close(track->mRTPSocket);
@@ -843,7 +845,9 @@
// Clear the tag
if (mUIDValid) {
HTTPBase::UnRegisterSocketUserTag(info->mRTPSocket);
+ HTTPBase::UnRegisterSocketUserMark(info->mRTPSocket);
HTTPBase::UnRegisterSocketUserTag(info->mRTCPSocket);
+ HTTPBase::UnRegisterSocketUserMark(info->mRTCPSocket);
}
close(info->mRTPSocket);
@@ -1599,6 +1603,8 @@
(uint32_t)*(uint32_t*) "RTP_");
HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
(uint32_t)*(uint32_t*) "RTP_");
+ HTTPBase::RegisterSocketUserMark(info->mRTPSocket, mUID);
+ HTTPBase::RegisterSocketUserMark(info->mRTCPSocket, mUID);
}
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
diff --git a/media/libstagefright/wifi-display/sink/DirectRenderer.cpp b/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
index 15f9c88..cdb2267 100644
--- a/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
+++ b/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
@@ -29,9 +29,8 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
namespace android {
@@ -488,12 +487,38 @@
break;
}
+ case kWhatQueueAccessUnit:
+ onQueueAccessUnit(msg);
+ break;
+
+ case kWhatSetFormat:
+ onSetFormat(msg);
+ break;
+
default:
TRESPASS();
}
}
void DirectRenderer::setFormat(size_t trackIndex, const sp<AMessage> &format) {
+ sp<AMessage> msg = new AMessage(kWhatSetFormat, id());
+ msg->setSize("trackIndex", trackIndex);
+ msg->setMessage("format", format);
+ msg->post();
+}
+
+void DirectRenderer::onSetFormat(const sp<AMessage> &msg) {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+
+ sp<AMessage> format;
+ CHECK(msg->findMessage("format", &format));
+
+ internalSetFormat(trackIndex, format);
+}
+
+void DirectRenderer::internalSetFormat(
+ size_t trackIndex, const sp<AMessage> &format) {
CHECK_LT(trackIndex, 2u);
CHECK(mDecoderContext[trackIndex] == NULL);
@@ -517,18 +542,21 @@
void DirectRenderer::queueAccessUnit(
size_t trackIndex, const sp<ABuffer> &accessUnit) {
+ sp<AMessage> msg = new AMessage(kWhatQueueAccessUnit, id());
+ msg->setSize("trackIndex", trackIndex);
+ msg->setBuffer("accessUnit", accessUnit);
+ msg->post();
+}
+
+void DirectRenderer::onQueueAccessUnit(const sp<AMessage> &msg) {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+
+ sp<ABuffer> accessUnit;
+ CHECK(msg->findBuffer("accessUnit", &accessUnit));
+
CHECK_LT(trackIndex, 2u);
-
- if (mDecoderContext[trackIndex] == NULL) {
- CHECK_EQ(trackIndex, 0u);
-
- sp<AMessage> format = new AMessage;
- format->setString("mime", "video/avc");
- format->setInt32("width", 640);
- format->setInt32("height", 360);
-
- setFormat(trackIndex, format);
- }
+ CHECK(mDecoderContext[trackIndex] != NULL);
mDecoderContext[trackIndex]->queueInputBuffer(accessUnit);
}
diff --git a/media/libstagefright/wifi-display/sink/DirectRenderer.h b/media/libstagefright/wifi-display/sink/DirectRenderer.h
index 1e7dc34..07c2170 100644
--- a/media/libstagefright/wifi-display/sink/DirectRenderer.h
+++ b/media/libstagefright/wifi-display/sink/DirectRenderer.h
@@ -43,6 +43,8 @@
enum {
kWhatDecoderNotify,
kWhatRenderVideo,
+ kWhatQueueAccessUnit,
+ kWhatSetFormat,
};
struct OutputInfo {
@@ -72,6 +74,11 @@
void scheduleVideoRenderIfNecessary();
void onRenderVideo();
+ void onSetFormat(const sp<AMessage> &msg);
+ void onQueueAccessUnit(const sp<AMessage> &msg);
+
+ void internalSetFormat(size_t trackIndex, const sp<AMessage> &format);
+
DISALLOW_EVIL_CONSTRUCTORS(DirectRenderer);
};
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 0214520..6f23854 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -21,6 +21,7 @@
#include "Converter.h"
#include "MediaPuller.h"
+#include "include/avc_utils.h"
#include <cutils/properties.h>
#include <gui/Surface.h>
@@ -33,6 +34,8 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <arpa/inet.h>
+
#include <OMX_Video.h>
namespace android {
@@ -40,12 +43,14 @@
Converter::Converter(
const sp<AMessage> ¬ify,
const sp<ALooper> &codecLooper,
- const sp<AMessage> &outputFormat)
- : mInitCheck(NO_INIT),
- mNotify(notify),
+ const sp<AMessage> &outputFormat,
+ uint32_t flags)
+ : mNotify(notify),
mCodecLooper(codecLooper),
mOutputFormat(outputFormat),
+ mFlags(flags),
mIsVideo(false),
+ mIsH264(false),
mIsPCMAudio(false),
mNeedToManuallyPrependSPSPPS(false),
mDoMoreWorkPending(false)
@@ -55,21 +60,18 @@
#endif
,mPrevVideoBitrate(-1)
,mNumFramesToDrop(0)
+ ,mEncodingSuspended(false)
{
AString mime;
CHECK(mOutputFormat->findString("mime", &mime));
if (!strncasecmp("video/", mime.c_str(), 6)) {
mIsVideo = true;
+
+ mIsH264 = !strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC);
} else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime.c_str())) {
mIsPCMAudio = true;
}
-
- mInitCheck = initEncoder();
-
- if (mInitCheck != OK) {
- releaseEncoder();
- }
}
static void ReleaseMediaBufferReference(const sp<ABuffer> &accessUnit) {
@@ -118,8 +120,19 @@
(new AMessage(kWhatShutdown, id()))->post();
}
-status_t Converter::initCheck() const {
- return mInitCheck;
+status_t Converter::init() {
+ status_t err = initEncoder();
+
+ if (err != OK) {
+ releaseEncoder();
+ }
+
+ return err;
+}
+
+sp<IGraphicBufferProducer> Converter::getGraphicBufferProducer() {
+ CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
+ return mGraphicBufferProducer;
}
size_t Converter::getInputBufferCount() const {
@@ -244,6 +257,16 @@
return err;
}
+ if (mFlags & FLAG_USE_SURFACE_INPUT) {
+ CHECK(mIsVideo);
+
+ err = mEncoder->createInputSurface(&mGraphicBufferProducer);
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
err = mEncoder->start();
if (err != OK) {
@@ -256,7 +279,17 @@
return err;
}
- return mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
+ err = mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (mFlags & FLAG_USE_SURFACE_INPUT) {
+ scheduleDoMoreWork();
+ }
+
+ return OK;
}
void Converter::notifyError(status_t err) {
@@ -312,9 +345,12 @@
sp<ABuffer> accessUnit;
CHECK(msg->findBuffer("accessUnit", &accessUnit));
- if (mIsVideo && mNumFramesToDrop) {
- --mNumFramesToDrop;
- ALOGI("dropping frame.");
+ if (mNumFramesToDrop > 0 || mEncodingSuspended) {
+ if (mNumFramesToDrop > 0) {
+ --mNumFramesToDrop;
+ ALOGI("dropping frame.");
+ }
+
ReleaseMediaBufferReference(accessUnit);
break;
}
@@ -396,7 +432,7 @@
}
if (mIsVideo) {
- ALOGI("requesting IDR frame");
+ ALOGV("requesting IDR frame");
mEncoder->requestIDRFrame();
}
break;
@@ -411,6 +447,10 @@
AString mime;
CHECK(mOutputFormat->findString("mime", &mime));
ALOGI("encoder (%s) shut down.", mime.c_str());
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatShutdownCompleted);
+ notify->post();
break;
}
@@ -431,6 +471,21 @@
break;
}
+ case kWhatSuspendEncoding:
+ {
+ int32_t suspend;
+ CHECK(msg->findInt32("suspend", &suspend));
+
+ mEncodingSuspended = suspend;
+
+ if (mFlags & FLAG_USE_SURFACE_INPUT) {
+ sp<AMessage> params = new AMessage;
+ params->setInt32("drop-input-frames",suspend);
+ mEncoder->setParameters(params);
+ }
+ break;
+ }
+
default:
TRESPASS();
}
@@ -616,22 +671,39 @@
return OK;
}
+sp<ABuffer> Converter::prependCSD(const sp<ABuffer> &accessUnit) const {
+ CHECK(mCSD0 != NULL);
+
+ sp<ABuffer> dup = new ABuffer(accessUnit->size() + mCSD0->size());
+ memcpy(dup->data(), mCSD0->data(), mCSD0->size());
+ memcpy(dup->data() + mCSD0->size(), accessUnit->data(), accessUnit->size());
+
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+ dup->meta()->setInt64("timeUs", timeUs);
+
+ return dup;
+}
+
status_t Converter::doMoreWork() {
status_t err;
- for (;;) {
- size_t bufferIndex;
- err = mEncoder->dequeueInputBuffer(&bufferIndex);
+ if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+ for (;;) {
+ size_t bufferIndex;
+ err = mEncoder->dequeueInputBuffer(&bufferIndex);
- if (err != OK) {
- break;
+ if (err != OK) {
+ break;
+ }
+
+ mAvailEncoderInputIndices.push_back(bufferIndex);
}
- mAvailEncoderInputIndices.push_back(bufferIndex);
+ feedEncoderInputBuffers();
}
- feedEncoderInputBuffers();
-
for (;;) {
size_t bufferIndex;
size_t offset;
@@ -705,9 +777,19 @@
if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
if (!handle) {
+ if (mIsH264) {
+ mCSD0 = buffer;
+ }
mOutputFormat->setBuffer("csd-0", buffer);
}
} else {
+ if (mNeedToManuallyPrependSPSPPS
+ && mIsH264
+ && (mFlags & FLAG_PREPEND_CSD_IF_NECESSARY)
+ && IsIDR(buffer)) {
+ buffer = prependCSD(buffer);
+ }
+
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatAccessUnit);
notify->setBuffer("accessUnit", buffer);
@@ -732,9 +814,18 @@
}
void Converter::dropAFrame() {
+ // Unsupported in surface input mode.
+ CHECK(!(mFlags & FLAG_USE_SURFACE_INPUT));
+
(new AMessage(kWhatDropAFrame, id()))->post();
}
+void Converter::suspendEncoding(bool suspend) {
+ sp<AMessage> msg = new AMessage(kWhatSuspendEncoding, id());
+ msg->setInt32("suspend", suspend);
+ msg->post();
+}
+
int32_t Converter::getVideoBitrate() const {
return mPrevVideoBitrate;
}
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index 76c8b19..5876e07 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -18,13 +18,12 @@
#define CONVERTER_H_
-#include "WifiDisplaySource.h"
-
#include <media/stagefright/foundation/AHandler.h>
namespace android {
struct ABuffer;
+struct IGraphicBufferProducer;
struct MediaCodec;
#define ENABLE_SILENCE_DETECTION 0
@@ -33,11 +32,25 @@
// media access unit of a different format.
// Right now this'll convert raw video into H.264 and raw audio into AAC.
struct Converter : public AHandler {
+ enum {
+ kWhatAccessUnit,
+ kWhatEOS,
+ kWhatError,
+ kWhatShutdownCompleted,
+ };
+
+ enum FlagBits {
+ FLAG_USE_SURFACE_INPUT = 1,
+ FLAG_PREPEND_CSD_IF_NECESSARY = 2,
+ };
Converter(const sp<AMessage> ¬ify,
const sp<ALooper> &codecLooper,
- const sp<AMessage> &outputFormat);
+ const sp<AMessage> &outputFormat,
+ uint32_t flags = 0);
- status_t initCheck() const;
+ status_t init();
+
+ sp<IGraphicBufferProducer> getGraphicBufferProducer();
size_t getInputBufferCount() const;
@@ -50,22 +63,7 @@
void requestIDRFrame();
void dropAFrame();
-
- enum {
- kWhatAccessUnit,
- kWhatEOS,
- kWhatError,
- };
-
- enum {
- kWhatDoMoreWork,
- kWhatRequestIDRFrame,
- kWhatShutdown,
- kWhatMediaPullerNotify,
- kWhatEncoderActivity,
- kWhatDropAFrame,
- kWhatReleaseOutputBuffer,
- };
+ void suspendEncoding(bool suspend);
void shutdownAsync();
@@ -74,22 +72,40 @@
static int32_t GetInt32Property(const char *propName, int32_t defaultValue);
+ enum {
+ // MUST not conflict with private enums below.
+ kWhatMediaPullerNotify = 'pulN',
+ };
+
protected:
virtual ~Converter();
virtual void onMessageReceived(const sp<AMessage> &msg);
private:
- status_t mInitCheck;
+ enum {
+ kWhatDoMoreWork,
+ kWhatRequestIDRFrame,
+ kWhatSuspendEncoding,
+ kWhatShutdown,
+ kWhatEncoderActivity,
+ kWhatDropAFrame,
+ kWhatReleaseOutputBuffer,
+ };
+
sp<AMessage> mNotify;
sp<ALooper> mCodecLooper;
sp<AMessage> mOutputFormat;
+ uint32_t mFlags;
bool mIsVideo;
+ bool mIsH264;
bool mIsPCMAudio;
bool mNeedToManuallyPrependSPSPPS;
sp<MediaCodec> mEncoder;
sp<AMessage> mEncoderActivityNotify;
+ sp<IGraphicBufferProducer> mGraphicBufferProducer;
+
Vector<sp<ABuffer> > mEncoderInputBuffers;
Vector<sp<ABuffer> > mEncoderOutputBuffers;
@@ -97,6 +113,8 @@
List<sp<ABuffer> > mInputBufferQueue;
+ sp<ABuffer> mCSD0;
+
bool mDoMoreWorkPending;
#if ENABLE_SILENCE_DETECTION
@@ -109,6 +127,7 @@
int32_t mPrevVideoBitrate;
int32_t mNumFramesToDrop;
+ bool mEncodingSuspended;
status_t initEncoder();
void releaseEncoder();
@@ -127,6 +146,8 @@
static bool IsSilence(const sp<ABuffer> &accessUnit);
+ sp<ABuffer> prependCSD(const sp<ABuffer> &accessUnit) const;
+
DISALLOW_EVIL_CONSTRUCTORS(Converter);
};
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index a15fbac..0aa4ee5 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -521,7 +521,7 @@
if (mTracks.isEmpty()) {
ALOGI("Reached EOS");
}
- } else {
+ } else if (what != Converter::kWhatShutdownCompleted) {
CHECK_EQ(what, Converter::kWhatError);
status_t err;
@@ -957,14 +957,16 @@
sp<Converter> converter = new Converter(notify, codecLooper, format);
- err = converter->initCheck();
+ looper()->registerHandler(converter);
+
+ err = converter->init();
if (err != OK) {
ALOGE("%s converter returned err %d", isVideo ? "video" : "audio", err);
+
+ looper()->unregisterHandler(converter->id());
return err;
}
- looper()->registerHandler(converter);
-
notify = new AMessage(Converter::kWhatMediaPullerNotify, converter->id());
notify->setSize("trackIndex", trackIndex);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 714854e..54377f1 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -27,9 +27,6 @@
LOCAL_SRC_FILES += StateQueue.cpp
-# uncomment for debugging timing problems related to StateQueue::push()
-LOCAL_CFLAGS += -DSTATE_QUEUE_DUMP
-
LOCAL_C_INCLUDES := \
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils)
@@ -56,24 +53,10 @@
LOCAL_MODULE:= libaudioflinger
-LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp
-
-LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS
-
-# uncomment to display CPU load adjusted for CPU frequency
-# LOCAL_CFLAGS += -DCPU_FREQUENCY_STATISTICS
+LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp AudioWatchdog.cpp
LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
-LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
-
-# uncomment to allow tee sink debugging to be enabled by property
-# LOCAL_CFLAGS += -DTEE_SINK
-
-# uncomment to enable the audio watchdog
-# LOCAL_SRC_FILES += AudioWatchdog.cpp
-# LOCAL_CFLAGS += -DAUDIO_WATCHDOG
-
# Define ANDROID_SMP appropriately. Used to get inline tracing fast-path.
ifeq ($(TARGET_CPU_SMP),true)
LOCAL_CFLAGS += -DANDROID_SMP=1
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 17a69fa..99e077c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#include <dirent.h>
#include <math.h>
#include <signal.h>
@@ -61,6 +62,7 @@
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <media/AudioParameter.h>
+#include <private/android_filesystem_config.h>
// ----------------------------------------------------------------------------
@@ -138,7 +140,9 @@
mMasterMute(false),
mNextUniqueId(1),
mMode(AUDIO_MODE_INVALID),
- mBtNrecIsOff(false)
+ mBtNrecIsOff(false),
+ mIsLowRamDevice(true),
+ mIsDeviceTypeKnown(false)
{
getpid_cached = getpid();
char value[PROPERTY_VALUE_MAX];
@@ -1380,6 +1384,23 @@
// ----------------------------------------------------------------------------
+status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice)
+{
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_SYSTEM) {
+ return PERMISSION_DENIED;
+ }
+ Mutex::Autolock _l(mLock);
+ if (mIsDeviceTypeKnown) {
+ return INVALID_OPERATION;
+ }
+ mIsLowRamDevice = isLowRamDevice;
+ mIsDeviceTypeKnown = true;
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
audio_devices_t *pDevices,
uint32_t *pSamplingRate,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b640b31..f31619b 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -220,6 +220,8 @@
virtual uint32_t getPrimaryOutputSamplingRate();
virtual size_t getPrimaryOutputFrameCount();
+ virtual status_t setLowRamDevice(bool isLowRamDevice);
+
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
@@ -594,12 +596,11 @@
status_t closeOutput_nonvirtual(audio_io_handle_t output);
status_t closeInput_nonvirtual(audio_io_handle_t input);
-// do not use #ifdef here, since AudioFlinger.h is included by more than one module
-//#ifdef TEE_SINK
+#ifdef TEE_SINK
// all record threads serially share a common tee sink, which is re-created on format change
sp<NBAIO_Sink> mRecordTeeSink;
sp<NBAIO_Source> mRecordTeeSource;
-//#endif
+#endif
public:
@@ -624,6 +625,15 @@
static const size_t kTeeSinkTrackFramesDefault = 0x1000;
#endif
+ // This method reads from a variable without mLock, but the variable is updated under mLock. So
+ // we might read a stale value, or a value that's inconsistent with respect to other variables.
+ // In this case, it's safe because the return value isn't used for making an important decision.
+ // The reason we don't want to take mLock is because it could block the caller for a long time.
+ bool isLowRamDevice() const { return mIsLowRamDevice; }
+
+private:
+ bool mIsLowRamDevice;
+ bool mIsDeviceTypeKnown;
};
#undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 7d38f80..df4e029 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "AudioMixer"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index eacecf0..fa1e405 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "AudioPolicyService"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#undef __STRICT_ANSI__
#define __STDINT_LIMITS
#define __STDC_LIMIT_MACROS
@@ -50,7 +51,7 @@
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
-static const nsecs_t kAudioCommandTimeout = 3000000000; // 3 seconds
+static const nsecs_t kAudioCommandTimeout = 3000000000LL; // 3 seconds
namespace {
extern struct audio_policy_service_ops aps_ops;
diff --git a/services/audioflinger/AudioWatchdog.cpp b/services/audioflinger/AudioWatchdog.cpp
index 8f328ee..93d185e 100644
--- a/services/audioflinger/AudioWatchdog.cpp
+++ b/services/audioflinger/AudioWatchdog.cpp
@@ -17,9 +17,12 @@
#define LOG_TAG "AudioWatchdog"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#include <utils/Log.h>
#include "AudioWatchdog.h"
+#ifdef AUDIO_WATCHDOG
+
namespace android {
void AudioWatchdogDump::dump(int fd)
@@ -132,3 +135,5 @@
}
} // namespace android
+
+#endif // AUDIO_WATCHDOG
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
new file mode 100644
index 0000000..bc2038a
--- /dev/null
+++ b/services/audioflinger/Configuration.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+// Put build-time configuration options here rather than Android.mk,
+// so that the instantiate for AudioFlinger service will pick up the same options.
+
+#ifndef ANDROID_AUDIOFLINGER_CONFIGURATION_H
+#define ANDROID_AUDIOFLINGER_CONFIGURATION_H
+
+// uncomment to enable detailed battery usage reporting (not debugged)
+//#define ADD_BATTERY_DATA
+
+// uncomment to enable the audio watchdog
+//#define AUDIO_WATCHDOG
+
+// uncomment to display CPU load adjusted for CPU frequency
+//#define CPU_FREQUENCY_STATISTICS
+
+// uncomment to enable fast mixer to take performance samples for later statistical analysis
+#define FAST_MIXER_STATISTICS
+
+// uncomment to allow fast tracks at non-native sample rate
+//#define FAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
+
+// uncomment for debugging timing problems related to StateQueue::push()
+//#define STATE_QUEUE_DUMP
+
+// uncomment to allow tee sink debugging to be enabled by property
+//#define TEE_SINK
+
+// uncomment to log CPU statistics every n wall clock seconds
+//#define DEBUG_CPU_USAGE 10
+
+#endif // ANDROID_AUDIOFLINGER_CONFIGURATION_H
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 942ea35..1c7a64b 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#include <utils/Log.h>
#include <audio_effects/effect_visualizer.h>
#include <audio_utils/primitives.h>
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 12e4683..5350e2c 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -25,6 +25,7 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include "Configuration.h"
#include <sys/atomics.h>
#include <time.h>
#include <utils/Log.h>
@@ -82,7 +83,7 @@
struct timespec oldLoad = {0, 0}; // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
bool oldLoadValid = false; // whether oldLoad is valid
uint32_t bounds = 0;
- bool full = false; // whether we have collected at least kSamplingN samples
+ bool full = false; // whether we have collected at least mSamplingN samples
#ifdef CPU_FREQUENCY_STATISTICS
ThreadCpuUsage tcu; // for reading the current CPU clock frequency in kHz
#endif
@@ -142,7 +143,9 @@
preIdle = *current;
current = &preIdle;
oldTsValid = false;
+#ifdef FAST_MIXER_STATISTICS
oldLoadValid = false;
+#endif
ignoreNextOverrun = true;
}
previous = current;
@@ -182,8 +185,10 @@
warmupCycles = 0;
sleepNs = -1;
coldGen = current->mColdGen;
+#ifdef FAST_MIXER_STATISTICS
bounds = 0;
full = false;
+#endif
oldTsValid = !clock_gettime(CLOCK_MONOTONIC, &oldTs);
} else {
sleepNs = FAST_HOT_IDLE_NS;
@@ -529,11 +534,11 @@
#ifdef FAST_MIXER_STATISTICS
if (isWarm) {
// advance the FIFO queue bounds
- size_t i = bounds & (FastMixerDumpState::kSamplingN - 1);
+ size_t i = bounds & (dumpState->mSamplingN - 1);
bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF);
if (full) {
bounds += 0x10000;
- } else if (!(bounds & (FastMixerDumpState::kSamplingN - 1))) {
+ } else if (!(bounds & (dumpState->mSamplingN - 1))) {
full = true;
}
// compute the delta value of clock_gettime(CLOCK_MONOTONIC)
@@ -603,26 +608,44 @@
// never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
}
-FastMixerDumpState::FastMixerDumpState() :
+FastMixerDumpState::FastMixerDumpState(
+#ifdef FAST_MIXER_STATISTICS
+ uint32_t samplingN
+#endif
+ ) :
mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0),
mSampleRate(0), mFrameCount(0), /* mMeasuredWarmupTs({0, 0}), */ mWarmupCycles(0),
mTrackMask(0)
#ifdef FAST_MIXER_STATISTICS
- , mBounds(0)
+ , mSamplingN(0), mBounds(0)
#endif
{
mMeasuredWarmupTs.tv_sec = 0;
mMeasuredWarmupTs.tv_nsec = 0;
- // sample arrays aren't accessed atomically with respect to the bounds,
- // so clearing reduces chance for dumpsys to read random uninitialized samples
- memset(&mMonotonicNs, 0, sizeof(mMonotonicNs));
- memset(&mLoadNs, 0, sizeof(mLoadNs));
-#ifdef CPU_FREQUENCY_STATISTICS
- memset(&mCpukHz, 0, sizeof(mCpukHz));
+#ifdef FAST_MIXER_STATISTICS
+ increaseSamplingN(samplingN);
#endif
}
+#ifdef FAST_MIXER_STATISTICS
+void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
+{
+ if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
+ return;
+ }
+ uint32_t additional = samplingN - mSamplingN;
+ // sample arrays aren't accessed atomically with respect to the bounds,
+ // so clearing reduces chance for dumpsys to read random uninitialized samples
+ memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
+ memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
+#ifdef CPU_FREQUENCY_STATISTICS
+ memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
+#endif
+ mSamplingN = samplingN;
+}
+#endif
+
FastMixerDumpState::~FastMixerDumpState()
{
}
@@ -641,7 +664,7 @@
}
}
-void FastMixerDumpState::dump(int fd)
+void FastMixerDumpState::dump(int fd) const
{
if (mCommand == FastMixerState::INITIAL) {
fdprintf(fd, "FastMixer not initialized\n");
@@ -692,9 +715,9 @@
uint32_t newestOpen = bounds & 0xFFFF;
uint32_t oldestClosed = bounds >> 16;
uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
- if (n > kSamplingN) {
+ if (n > mSamplingN) {
ALOGE("too many samples %u", n);
- n = kSamplingN;
+ n = mSamplingN;
}
// statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
// and adjusted CPU load in MHz normalized for CPU clock frequency
@@ -710,7 +733,7 @@
uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
// loop over all the samples
for (uint32_t j = 0; j < n; ++j) {
- size_t i = oldestClosed++ & (kSamplingN - 1);
+ size_t i = oldestClosed++ & (mSamplingN - 1);
uint32_t wallNs = mMonotonicNs[i];
if (tail != NULL) {
tail[j] = wallNs;
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 2ab1d04..6158925 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -85,10 +85,14 @@
// Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks).
// It has a different lifetime than the FastMixer, and so it can't be a member of FastMixer.
struct FastMixerDumpState {
- FastMixerDumpState();
+ FastMixerDumpState(
+#ifdef FAST_MIXER_STATISTICS
+ uint32_t samplingN = kSamplingNforLowRamDevice
+#endif
+ );
/*virtual*/ ~FastMixerDumpState();
- void dump(int fd); // should only be called on a stable copy, not the original
+ void dump(int fd) const; // should only be called on a stable copy, not the original
FastMixerState::Command mCommand; // current command
uint32_t mWriteSequence; // incremented before and after each write()
@@ -106,8 +110,15 @@
#ifdef FAST_MIXER_STATISTICS
// Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency.
- // kSamplingN is the size of the sampling frame, and must be a power of 2 <= 0x8000.
+ // kSamplingN is max size of sampling frame (statistics), and must be a power of 2 <= 0x8000.
+ // The sample arrays are virtually allocated based on this compile-time constant,
+ // but are only initialized and used based on the runtime parameter mSamplingN.
static const uint32_t kSamplingN = 0x8000;
+ // Compile-time constant for a "low RAM device", must be a power of 2 <= kSamplingN.
+ // This value was chosen such that each array uses 1 small page (4 Kbytes).
+ static const uint32_t kSamplingNforLowRamDevice = 0x400;
+ // Corresponding runtime maximum size of sample arrays, must be a power of 2 <= kSamplingN.
+ uint32_t mSamplingN;
// The bounds define the interval of valid samples, and are represented as follows:
// newest open (excluded) endpoint = lower 16 bits of bounds, modulo N
// oldest closed (included) endpoint = upper 16 bits of bounds, modulo N
@@ -119,6 +130,8 @@
#ifdef CPU_FREQUENCY_STATISTICS
uint32_t mCpukHz[kSamplingN]; // absolute CPU clock frequency in kHz, bits 0-3 are CPU#
#endif
+ // Increase sampling window after construction, must be a power of 2 <= kSamplingN
+ void increaseSamplingN(uint32_t samplingN);
#endif
};
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index c45c81b..737de97 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "Configuration.h"
#include "FastMixerState.h"
namespace android {
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
index 3e891a5..c2d3bbd 100644
--- a/services/audioflinger/StateQueue.cpp
+++ b/services/audioflinger/StateQueue.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "StateQueue"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#include <time.h>
#include <cutils/atomic.h>
#include <utils/Log.h>
diff --git a/services/audioflinger/StateQueueInstantiations.cpp b/services/audioflinger/StateQueueInstantiations.cpp
index 077582f..0d5cd0c 100644
--- a/services/audioflinger/StateQueueInstantiations.cpp
+++ b/services/audioflinger/StateQueueInstantiations.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "Configuration.h"
#include "FastMixerState.h"
#include "StateQueue.h"
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d4cd0ea..f27d908 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -20,6 +20,7 @@
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include "Configuration.h"
#include <math.h>
#include <fcntl.h>
#include <sys/stat.h>
@@ -54,14 +55,11 @@
#include "ServiceUtilities.h"
#include "SchedulingPolicyService.h"
-#undef ADD_BATTERY_DATA
-
#ifdef ADD_BATTERY_DATA
#include <media/IMediaPlayerService.h>
#include <media/IMediaDeathNotifier.h>
#endif
-// #define DEBUG_CPU_USAGE 10 // log statistics every n wall clock seconds
#ifdef DEBUG_CPU_USAGE
#include <cpustats/CentralTendencyStatistics.h>
#include <cpustats/ThreadCpuUsage.h>
@@ -2287,6 +2285,8 @@
#endif
}
state->mCommand = FastMixerState::MIX_WRITE;
+ mFastMixerDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
+ FastMixerDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
sq->end();
sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
if (kUseFastMixer == FastMixer_Dynamic) {
@@ -3087,7 +3087,7 @@
write(fd, result.string(), result.size());
// Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- FastMixerDumpState copy = mFastMixerDumpState;
+ const FastMixerDumpState copy(mFastMixerDumpState);
copy.dump(fd);
#ifdef STATE_QUEUE_DUMP
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f0dbee3..c45daae 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#include <math.h>
#include <cutils/compiler.h>
#include <utils/Log.h>
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 77df152..710d0e9 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -445,6 +445,10 @@
return res;
}
+bool Camera2Device::willNotify3A() {
+ return true;
+}
+
void Camera2Device::notificationCallback(int32_t msg_type,
int32_t ext1,
int32_t ext2,
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 3034a1d..372ce9f 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -59,6 +59,7 @@
virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
virtual status_t waitUntilDrained();
virtual status_t setNotifyCallback(NotificationListener *listener);
+ virtual bool willNotify3A();
virtual status_t waitForNextFrame(nsecs_t timeout);
virtual status_t getNextFrame(CameraMetadata *frame);
virtual status_t triggerAutofocus(uint32_t id);
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 73bf30c..9d0f392 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -844,6 +844,10 @@
return OK;
}
+bool Camera3Device::willNotify3A() {
+ return false;
+}
+
status_t Camera3Device::waitForNextFrame(nsecs_t timeout) {
ATRACE_CALL();
status_t res;
@@ -1244,13 +1248,6 @@
}
- AlgState cur3aState;
- AlgState new3aState;
- int32_t aeTriggerId = 0;
- int32_t afTriggerId = 0;
-
- NotificationListener *listener = NULL;
-
// Process the result metadata, if provided
if (result->result != NULL) {
Mutex::Autolock l(mOutputLock);
@@ -1288,59 +1285,6 @@
" metadata for frame %d (%lld vs %lld respectively)",
frameNumber, timestamp, entry.data.i64[0]);
}
-
- // Get 3A states from result metadata
-
- entry = captureResult.find(ANDROID_CONTROL_AE_STATE);
- if (entry.count == 0) {
- CLOGE("No AE state provided by HAL for frame %d!",
- frameNumber);
- } else {
- new3aState.aeState =
- static_cast<camera_metadata_enum_android_control_ae_state>(
- entry.data.u8[0]);
- }
-
- entry = captureResult.find(ANDROID_CONTROL_AF_STATE);
- if (entry.count == 0) {
- CLOGE("No AF state provided by HAL for frame %d!",
- frameNumber);
- } else {
- new3aState.afState =
- static_cast<camera_metadata_enum_android_control_af_state>(
- entry.data.u8[0]);
- }
-
- entry = captureResult.find(ANDROID_CONTROL_AWB_STATE);
- if (entry.count == 0) {
- CLOGE("No AWB state provided by HAL for frame %d!",
- frameNumber);
- } else {
- new3aState.awbState =
- static_cast<camera_metadata_enum_android_control_awb_state>(
- entry.data.u8[0]);
- }
-
- entry = captureResult.find(ANDROID_CONTROL_AF_TRIGGER_ID);
- if (entry.count == 0) {
- CLOGE("No AF trigger ID provided by HAL for frame %d!",
- frameNumber);
- } else {
- afTriggerId = entry.data.i32[0];
- }
-
- entry = captureResult.find(ANDROID_CONTROL_AE_PRECAPTURE_ID);
- if (entry.count == 0) {
- CLOGE("No AE precapture trigger ID provided by HAL"
- " for frame %d!", frameNumber);
- } else {
- aeTriggerId = entry.data.i32[0];
- }
-
- listener = mListener;
- cur3aState = m3AState;
-
- m3AState = new3aState;
} // scope for mOutputLock
// Return completed buffers to their streams with the timestamp
@@ -1357,30 +1301,16 @@
}
}
- // Finally, dispatch any 3A change events to listeners if we got metadata
+ // Finally, signal any waiters for new frames
if (result->result != NULL) {
mResultSignal.signal();
}
- if (result->result != NULL && listener != NULL) {
- if (new3aState.aeState != cur3aState.aeState) {
- ALOGVV("%s: AE state changed from 0x%x to 0x%x",
- __FUNCTION__, cur3aState.aeState, new3aState.aeState);
- listener->notifyAutoExposure(new3aState.aeState, aeTriggerId);
- }
- if (new3aState.afState != cur3aState.afState) {
- ALOGVV("%s: AF state changed from 0x%x to 0x%x",
- __FUNCTION__, cur3aState.afState, new3aState.afState);
- listener->notifyAutoFocus(new3aState.afState, afTriggerId);
- }
- if (new3aState.awbState != cur3aState.awbState) {
- listener->notifyAutoWhitebalance(new3aState.awbState, aeTriggerId);
- }
- }
-
}
+
+
void Camera3Device::notify(const camera3_notify_msg *msg) {
ATRACE_CALL();
NotificationListener *listener;
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h
index faa42b9..2328f89 100644
--- a/services/camera/libcameraservice/Camera3Device.h
+++ b/services/camera/libcameraservice/Camera3Device.h
@@ -107,6 +107,7 @@
virtual status_t waitUntilDrained();
virtual status_t setNotifyCallback(NotificationListener *listener);
+ virtual bool willNotify3A();
virtual status_t waitForNextFrame(nsecs_t timeout);
virtual status_t getNextFrame(CameraMetadata *frame);
@@ -389,18 +390,6 @@
Condition mResultSignal;
NotificationListener *mListener;
- struct AlgState {
- camera_metadata_enum_android_control_ae_state aeState;
- camera_metadata_enum_android_control_af_state afState;
- camera_metadata_enum_android_control_awb_state awbState;
-
- AlgState() :
- aeState(ANDROID_CONTROL_AE_STATE_INACTIVE),
- afState(ANDROID_CONTROL_AF_STATE_INACTIVE),
- awbState(ANDROID_CONTROL_AWB_STATE_INACTIVE) {
- }
- } m3AState;
-
/**** End scope for mOutputLock ****/
/**
diff --git a/services/camera/libcameraservice/CameraDeviceBase.h b/services/camera/libcameraservice/CameraDeviceBase.h
index 8c457d9..aa92bec 100644
--- a/services/camera/libcameraservice/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/CameraDeviceBase.h
@@ -156,6 +156,13 @@
virtual status_t setNotifyCallback(NotificationListener *listener) = 0;
/**
+ * Whether the device supports calling notifyAutofocus, notifyAutoExposure,
+ * and notifyAutoWhitebalance; if this returns false, the client must
+ * synthesize these notifications from received frame metadata.
+ */
+ virtual bool willNotify3A() = 0;
+
+ /**
* Wait for a new frame to be produced, with timeout in nanoseconds.
* Returns TIMED_OUT when no frame produced within the specified duration
*/
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c284a0d..0eb3e32 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -489,6 +489,7 @@
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
client = new ProCamera2Client(this, cameraCb, String16(),
cameraId, facing, callingPid, USE_CALLING_UID, getpid());
break;
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
index efbbe57..d7bafda 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
@@ -111,8 +111,7 @@
// Create CPU buffer queue endpoint, since app hasn't given us one
// Make it async to avoid disconnect deadlocks
sp<BufferQueue> bq = new BufferQueue();
- mCallbackConsumer = new CpuConsumer(bq, kCallbackHeapCount,
- /*synchronized*/ false);
+ mCallbackConsumer = new CpuConsumer(bq, kCallbackHeapCount);
mCallbackConsumer->setFrameAvailableListener(this);
mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
mCallbackWindow = new Surface(
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.cpp b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
index d13d398..114a7a8 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
@@ -33,6 +33,9 @@
ProFrameProcessor(device),
mClient(client),
mLastFrameNumberOfFaces(0) {
+
+ sp<CameraDeviceBase> d = device.promote();
+ mSynthesize3ANotify = !(d->willNotify3A());
}
FrameProcessor::~FrameProcessor() {
@@ -50,6 +53,11 @@
return false;
}
+ if (mSynthesize3ANotify) {
+ // Ignoring missing fields for now
+ process3aState(frame, client);
+ }
+
if (!ProFrameProcessor::processSingleFrame(frame, device)) {
return false;
}
@@ -185,6 +193,99 @@
return OK;
}
+status_t FrameProcessor::process3aState(const CameraMetadata &frame,
+ const sp<Camera2Client> &client) {
+
+ ATRACE_CALL();
+ camera_metadata_ro_entry_t entry;
+ int mId = client->getCameraId();
+
+ entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
+ int32_t frameNumber = entry.data.i32[0];
+
+ // Get 3A states from result metadata
+ bool gotAllStates = true;
+
+ AlgState new3aState;
+
+ entry = frame.find(ANDROID_CONTROL_AE_STATE);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: No AE state provided by HAL for frame %d!",
+ __FUNCTION__, mId, frameNumber);
+ gotAllStates = false;
+ } else {
+ new3aState.aeState =
+ static_cast<camera_metadata_enum_android_control_ae_state>(
+ entry.data.u8[0]);
+ }
+
+ entry = frame.find(ANDROID_CONTROL_AF_STATE);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: No AF state provided by HAL for frame %d!",
+ __FUNCTION__, mId, frameNumber);
+ gotAllStates = false;
+ } else {
+ new3aState.afState =
+ static_cast<camera_metadata_enum_android_control_af_state>(
+ entry.data.u8[0]);
+ }
+
+ entry = frame.find(ANDROID_CONTROL_AWB_STATE);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: No AWB state provided by HAL for frame %d!",
+ __FUNCTION__, mId, frameNumber);
+ gotAllStates = false;
+ } else {
+ new3aState.awbState =
+ static_cast<camera_metadata_enum_android_control_awb_state>(
+ entry.data.u8[0]);
+ }
+
+ int32_t afTriggerId = 0;
+ entry = frame.find(ANDROID_CONTROL_AF_TRIGGER_ID);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: No AF trigger ID provided by HAL for frame %d!",
+ __FUNCTION__, mId, frameNumber);
+ gotAllStates = false;
+ } else {
+ afTriggerId = entry.data.i32[0];
+ }
+
+ int32_t aeTriggerId = 0;
+ entry = frame.find(ANDROID_CONTROL_AE_PRECAPTURE_ID);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: No AE precapture trigger ID provided by HAL"
+ " for frame %d!",
+ __FUNCTION__, mId, frameNumber);
+ gotAllStates = false;
+ } else {
+ aeTriggerId = entry.data.i32[0];
+ }
+
+ if (!gotAllStates) return BAD_VALUE;
+
+ if (new3aState.aeState != m3aState.aeState) {
+ ALOGV("%s: AE state changed from 0x%x to 0x%x",
+ __FUNCTION__, m3aState.aeState, new3aState.aeState);
+ client->notifyAutoExposure(new3aState.aeState, aeTriggerId);
+ }
+ if (new3aState.afState != m3aState.afState) {
+ ALOGV("%s: AF state changed from 0x%x to 0x%x",
+ __FUNCTION__, m3aState.afState, new3aState.afState);
+ client->notifyAutoFocus(new3aState.afState, afTriggerId);
+ }
+ if (new3aState.awbState != m3aState.awbState) {
+ ALOGV("%s: AWB state changed from 0x%x to 0x%x",
+ __FUNCTION__, m3aState.awbState, new3aState.awbState);
+ client->notifyAutoWhitebalance(new3aState.awbState, aeTriggerId);
+ }
+
+ m3aState = new3aState;
+
+ return OK;
+}
+
+
void FrameProcessor::callbackFaceDetection(sp<Camera2Client> client,
const camera_frame_metadata &metadata) {
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.h b/services/camera/libcameraservice/camera2/FrameProcessor.h
index 27ed8f6..f480c55 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.h
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.h
@@ -44,6 +44,9 @@
private:
wp<Camera2Client> mClient;
+
+ bool mSynthesize3ANotify;
+
int mLastFrameNumberOfFaces;
void processNewFrames(const sp<Camera2Client> &client);
@@ -54,6 +57,22 @@
status_t processFaceDetect(const CameraMetadata &frame,
const sp<Camera2Client> &client);
+ // Send 3A state change notifications to client based on frame metadata
+ status_t process3aState(const CameraMetadata &frame,
+ const sp<Camera2Client> &client);
+
+ struct AlgState {
+ camera_metadata_enum_android_control_ae_state aeState;
+ camera_metadata_enum_android_control_af_state afState;
+ camera_metadata_enum_android_control_awb_state awbState;
+
+ AlgState() :
+ aeState(ANDROID_CONTROL_AE_STATE_INACTIVE),
+ afState(ANDROID_CONTROL_AF_STATE_INACTIVE),
+ awbState(ANDROID_CONTROL_AWB_STATE_INACTIVE) {
+ }
+ } m3aState;
+
// Emit FaceDetection event to java if faces changed
void callbackFaceDetection(sp<Camera2Client> client,
const camera_frame_metadata &metadata);
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
index 76fa46c..5981be7 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
@@ -322,8 +322,7 @@
sp<BufferQueue> bq = new BufferQueue();
mRecordingConsumer = new BufferItemConsumer(bq,
GRALLOC_USAGE_HW_VIDEO_ENCODER,
- mRecordingHeapCount + 1,
- true);
+ mRecordingHeapCount + 1);
mRecordingConsumer->setFrameAvailableListener(this);
mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
mRecordingWindow = new Surface(
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
index 3c575f6..0094992 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
@@ -131,8 +131,7 @@
sp<BufferQueue> bq = new BufferQueue();
mZslConsumer = new BufferItemConsumer(bq,
GRALLOC_USAGE_HW_CAMERA_ZSL,
- kZslBufferDepth,
- true);
+ kZslBufferDepth);
mZslConsumer->setFrameAvailableListener(this);
mZslConsumer->setName(String8("Camera2Client::ZslConsumer"));
mZslWindow = new Surface(
diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp
index 6d9acc3..e9a9c2b 100644
--- a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp
@@ -213,8 +213,7 @@
if (mConsumer.get() == 0) {
sp<BufferQueue> bq = new BufferQueue();
mConsumer = new BufferItemConsumer(bq, camera3_stream::usage,
- mTotalBufferCount,
- /*synchronousMode*/true);
+ mTotalBufferCount);
mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
}
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 7625735..8141f4e 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -36,11 +36,10 @@
RingBufferConsumer::RingBufferConsumer(uint32_t consumerUsage,
int bufferCount) :
- ConsumerBase(new BufferQueue(true)),
+ ConsumerBase(new BufferQueue()),
mBufferCount(bufferCount)
{
mBufferQueue->setConsumerUsageBits(consumerUsage);
- mBufferQueue->setSynchronousMode(true);
mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
assert(bufferCount > 0);
diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
index a6a2dc1..e1c7e79 100644
--- a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
@@ -176,7 +176,7 @@
ALOGE("%s: Camera %d: Got error %d after trying to set streaming "
"request", __FUNCTION__, mCameraId, res);
} else {
- mStreamingRequestList.push_back(mRequestIdCounter);
+ mStreamingRequestList.push_back(requestId);
}
} else {
res = mDevice->capture(metadata);