Merge "Fix integer overflow when handling MPEG4 tx3g atom" into mnc-dev
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index 0d04760..36fa3b5 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -143,7 +143,7 @@
ssize_t newTrackIndex = muxer->addTrack(format);
if (newTrackIndex < 0) {
- fprintf(stderr, "%s track (%d) unsupported by muxer\n",
+ fprintf(stderr, "%s track (%zu) unsupported by muxer\n",
isAudio ? "audio" : "video",
i);
} else {
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index cdb923d..0a54df9 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -236,9 +236,6 @@
status_t freeBuffer(OMX_U32 portIndex, size_t i);
status_t handleSetSurface(const sp<Surface> &surface);
- status_t setNativeWindowSizeFormatAndUsage(
- ANativeWindow *nativeWindow /* nonnull */,
- int width, int height, int format, int rotation, int usage);
status_t setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */);
status_t configureOutputBuffersFromNativeWindow(
@@ -332,8 +329,6 @@
status_t initNativeWindow();
- status_t pushBlankBuffersToNativeWindow();
-
// Returns true iff all buffers on the given port have status
// OWNED_BY_US or OWNED_BY_NATIVE_WINDOW.
bool allYourBuffersAreBelongToUs(OMX_U32 portIndex);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index f5d523d..56d2523 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -224,6 +224,7 @@
kFlagGatherCodecSpecificData = 512,
kFlagIsAsync = 1024,
kFlagIsComponentAllocated = 2048,
+ kFlagPushBlankBuffersOnShutdown = 4096,
};
struct BufferInfo {
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index 9d1d675..ce34338 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -54,7 +54,7 @@
static sp<IMediaCodecList> getLocalInstance();
// only to be used in getLocalInstance
- void updateDetailsForMultipleCodecs(const KeyedVector<AString, CodecSettings>& updates);
+ void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
private:
class BinderDeathObserver : public IBinder::DeathRecipient {
@@ -97,7 +97,6 @@
status_t initCheck() const;
void parseXMLFile(const char *path);
- void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
static void StartElementHandlerWrapper(
void *me, const char *name, const char **attrs);
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 84b1b1a..7fabcb3 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -298,7 +298,6 @@
status_t queueBufferToNativeWindow(BufferInfo *info);
status_t cancelBufferToNativeWindow(BufferInfo *info);
BufferInfo* dequeueBufferFromNativeWindow();
- status_t pushBlankBuffersToNativeWindow();
status_t freeBuffersOnPort(
OMX_U32 portIndex, bool onlyThoseWeOwn = false);
@@ -347,7 +346,6 @@
status_t configureCodec(const sp<MetaData> &meta);
- status_t applyRotation();
status_t waitForBufferFilled_l();
int64_t getDecodingTimeUs();
diff --git a/include/media/stagefright/SurfaceUtils.h b/include/media/stagefright/SurfaceUtils.h
new file mode 100644
index 0000000..c1a9c0a
--- /dev/null
+++ b/include/media/stagefright/SurfaceUtils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 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 SURFACE_UTILS_H_
+
+#define SURFACE_UTILS_H_
+
+#include <utils/Errors.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+status_t setNativeWindowSizeFormatAndUsage(
+ ANativeWindow *nativeWindow /* nonnull */,
+ int width, int height, int format, int rotation, int usage);
+status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */);
+
+} // namespace android
+
+#endif // SURFACE_UTILS_H_
diff --git a/media/libmedia/IMediaHTTPService.cpp b/media/libmedia/IMediaHTTPService.cpp
index f30d0f3..0c16a2b 100644
--- a/media/libmedia/IMediaHTTPService.cpp
+++ b/media/libmedia/IMediaHTTPService.cpp
@@ -44,6 +44,7 @@
status_t err = reply.readInt32();
if (err != OK) {
+ ALOGE("Unable to make HTTP connection (err = %d)", err);
return NULL;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index a118dec..1fb4365 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -189,7 +189,8 @@
mVideoFpsHint(-1.f),
mStarted(false),
mPaused(false),
- mPausedByClient(false) {
+ mPausedByClient(false),
+ mPausedForBuffering(false) {
clearFlushComplete();
}
@@ -683,7 +684,10 @@
{
ALOGV("kWhatStart");
if (mStarted) {
- onResume();
+ // do not resume yet if the source is still buffering
+ if (!mPausedForBuffering) {
+ onResume();
+ }
} else {
onStart();
}
@@ -2007,9 +2011,10 @@
case Source::kWhatPauseOnBufferingStart:
{
// ignore if not playing
- if (mStarted && !mPausedByClient) {
+ if (mStarted) {
ALOGI("buffer low, pausing...");
+ mPausedForBuffering = true;
onPause();
}
// fall-thru
@@ -2024,10 +2029,15 @@
case Source::kWhatResumeOnBufferingEnd:
{
// ignore if not playing
- if (mStarted && !mPausedByClient) {
+ if (mStarted) {
ALOGI("buffer ready, resuming...");
- onResume();
+ mPausedForBuffering = false;
+
+ // do not resume yet if client didn't unpause
+ if (!mPausedByClient) {
+ onResume();
+ }
}
// fall-thru
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 6b7d71e..df9debc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -203,6 +203,9 @@
// still become true, when we pause internally due to buffering.
bool mPausedByClient;
+ // Pause state as requested by source (internally) due to buffering
+ bool mPausedForBuffering;
+
inline const sp<DecoderBase> &getDecoder(bool audio) {
return audio ? mAudioDecoder : mVideoDecoder;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 22395cc..5475a4a 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -42,6 +42,7 @@
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/SurfaceUtils.h>
#include <media/hardware/HardwareAPI.h>
#include <OMX_AudioExt.h>
@@ -650,6 +651,11 @@
(void)surface->getIGraphicBufferProducer()->allowAllocation(false);
}
+ // push blank buffers to previous window if requested
+ if (mFlags & kFlagPushBlankBuffersToNativeWindowOnShutdown) {
+ pushBlankBuffersToNativeWindow(mNativeWindow.get());
+ }
+
mNativeWindow = nativeWindow;
return OK;
}
@@ -748,82 +754,6 @@
return OK;
}
-status_t ACodec::setNativeWindowSizeFormatAndUsage(
- ANativeWindow *nativeWindow /* nonnull */,
- int width, int height, int format, int rotation, int usage) {
- status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height);
- if (err != 0) {
- ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_buffers_format(nativeWindow, format);
- if (err != 0) {
- ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- int transform = 0;
- if ((rotation % 90) == 0) {
- switch ((rotation / 90) & 3) {
- case 1: transform = HAL_TRANSFORM_ROT_90; break;
- case 2: transform = HAL_TRANSFORM_ROT_180; break;
- case 3: transform = HAL_TRANSFORM_ROT_270; break;
- default: transform = 0; break;
- }
- }
-
- err = native_window_set_buffers_transform(nativeWindow, transform);
- if (err != 0) {
- ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- // Make sure to check whether either Stagefright or the video decoder
- // requested protected buffers.
- if (usage & GRALLOC_USAGE_PROTECTED) {
- // Verify that the ANativeWindow sends images directly to
- // SurfaceFlinger.
- int queuesToNativeWindow = 0;
- err = nativeWindow->query(
- nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow);
- if (err != 0) {
- ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err);
- return err;
- }
- if (queuesToNativeWindow != 1) {
- ALOGE("native window could not be authenticated");
- return PERMISSION_DENIED;
- }
- }
-
- int consumerUsage = 0;
- err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
- if (err != 0) {
- ALOGW("failed to get consumer usage bits. ignoring");
- err = 0;
- }
-
- int finalUsage = usage | consumerUsage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP;
- ALOGV("gralloc usage: %#x(ACodec) + %#x(Consumer) = %#x", usage, consumerUsage, finalUsage);
- err = native_window_set_usage(nativeWindow, finalUsage);
- if (err != 0) {
- ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_scaling_mode(
- nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- if (err != 0) {
- ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x",
- nativeWindow, width, height, format, rotation, finalUsage);
- return OK;
-}
-
status_t ACodec::setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
@@ -849,6 +779,8 @@
usage |= GRALLOC_USAGE_PROTECTED;
}
+ usage |= GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP;
+
ALOGV("gralloc usage: %#x(OMX) => %#x(ACodec)", omxUsage, usage);
return setNativeWindowSizeFormatAndUsage(
nativeWindow,
@@ -4123,137 +4055,6 @@
notify->post();
}
-status_t ACodec::pushBlankBuffersToNativeWindow() {
- status_t err = NO_ERROR;
- ANativeWindowBuffer* anb = NULL;
- int numBufs = 0;
- int minUndequeuedBufs = 0;
-
- // We need to reconnect to the ANativeWindow as a CPU client to ensure that
- // no frames get dropped by SurfaceFlinger assuming that these are video
- // frames.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = setNativeWindowSizeFormatAndUsage(
- mNativeWindow.get(), 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set format failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- static_cast<Surface*>(mNativeWindow.get())
- ->getIGraphicBufferProducer()->allowAllocation(true);
-
- err = mNativeWindow->query(mNativeWindow.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
- "failed: %s (%d)", strerror(-err), -err);
- goto error;
- }
-
- numBufs = minUndequeuedBufs + 1;
- err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- // We push numBufs + 1 buffers to ensure that we've drawn into the same
- // buffer twice. This should guarantee that the buffer has been displayed
- // on the screen and then been replaced, so an previous video frames are
- // guaranteed NOT to be currently displayed.
- for (int i = 0; i < numBufs + 1; i++) {
- err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-
- // Fill the buffer with the a 1x1 checkerboard pattern ;)
- uint32_t* img = NULL;
- err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: lock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- *img = 0;
-
- err = buf->unlock();
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: unlock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = mNativeWindow->queueBuffer(mNativeWindow.get(),
- buf->getNativeBuffer(), -1);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- anb = NULL;
- }
-
-error:
-
- if (err != NO_ERROR) {
- // Clean up after an error.
- if (anb != NULL) {
- mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
- }
-
- native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
-
- return err;
- } else {
- // Clean up after success.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- return NO_ERROR;
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
ACodec::PortDescription::PortDescription() {
@@ -6148,7 +5949,7 @@
// them has made it to the display. This allows the OMX
// component teardown to zero out any protected buffers
// without the risk of scanning out one of those buffers.
- mCodec->pushBlankBuffersToNativeWindow();
+ pushBlankBuffersToNativeWindow(mCodec->mNativeWindow.get());
}
mCodec->changeState(mCodec->mIdleToLoadedState);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 45581f3..fa17b2e 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -57,6 +57,7 @@
StagefrightMediaScanner.cpp \
StagefrightMetadataRetriever.cpp \
SurfaceMediaSource.cpp \
+ SurfaceUtils.cpp \
ThrottledSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 320157f..9bb0179 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2026,6 +2026,10 @@
return ERROR_IO;
}
const int kSkipBytesOfDataBox = 16;
+ if (chunk_data_size <= kSkipBytesOfDataBox) {
+ return ERROR_MALFORMED;
+ }
+
mFileMetaData->setData(
kKeyAlbumArt, MetaData::TYPE_NONE,
buffer->data() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
@@ -2609,11 +2613,11 @@
}
status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int depth) {
- if (size < 4) {
+ if (size < 4 || size == SIZE_MAX) {
return ERROR_MALFORMED;
}
- uint8_t *buffer = new (std::nothrow) uint8_t[size];
+ uint8_t *buffer = new (std::nothrow) uint8_t[size + 1];
if (buffer == NULL) {
return ERROR_MALFORMED;
}
@@ -2682,6 +2686,10 @@
int len16 = 0; // Number of UTF-16 characters
// smallest possible valid UTF-16 string w BOM: 0xfe 0xff 0x00 0x00
+ if (size < 6) {
+ return ERROR_MALFORMED;
+ }
+
if (size - 6 >= 4) {
len16 = ((size - 6) / 2) - 1; // don't include 0x0000 terminator
framedata = (char16_t *)(buffer + 6);
@@ -2705,6 +2713,7 @@
}
if (isUTF8) {
+ buffer[size] = 0;
mFileMetaData->setCString(metadataKey, (const char *)buffer + 6);
} else {
// Convert from UTF-16 string to UTF-8 string.
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ed4f682..44f6542 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -46,6 +46,7 @@
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/SurfaceUtils.h>
#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <utils/Singleton.h>
@@ -1659,6 +1660,11 @@
sp<AMessage> format;
CHECK(msg->findMessage("format", &format));
+ int32_t push;
+ if (msg->findInt32("push-blank-buffers-on-shutdown", &push) && push != 0) {
+ mFlags |= kFlagPushBlankBuffersOnShutdown;
+ }
+
if (obj != NULL) {
format->setObject("native-window", obj);
status_t err = handleSetSurface(static_cast<Surface *>(obj.get()));
@@ -1725,6 +1731,10 @@
} else {
if (err == OK) {
if (mFlags & kFlagUsesSoftwareRenderer) {
+ if (mSoftRenderer != NULL
+ && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
+ pushBlankBuffersToNativeWindow(mSurface.get());
+ }
mSoftRenderer = new SoftwareRenderer(surface);
// TODO: check if this was successful
} else {
@@ -1848,6 +1858,10 @@
msg->what() == kWhatStop /* keepComponentAllocated */);
returnBuffersToCodec();
+
+ if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
+ pushBlankBuffersToNativeWindow(mSurface.get());
+ }
break;
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index f12a913..e212fb8 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -44,8 +44,6 @@
static MediaCodecList *gCodecList = NULL;
-static const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
-
static bool parseBoolean(const char *s) {
if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) {
return true;
@@ -61,7 +59,6 @@
// static
sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
bool profilingNeeded = false;
- KeyedVector<AString, CodecSettings> updates;
Vector<sp<MediaCodecInfo>> infos;
{
@@ -89,13 +86,13 @@
}
if (profilingNeeded) {
- profileCodecs(infos, &updates);
+ profileCodecs(infos);
}
{
Mutex::Autolock autoLock(sInitMutex);
- if (updates.size() > 0) {
- gCodecList->updateDetailsForMultipleCodecs(updates);
+ if (profilingNeeded) {
+ gCodecList->parseTopLevelXMLFile(kProfilingResults, true /* ignore_errors */);
}
return sCodecList;
@@ -145,19 +142,6 @@
parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
}
-void MediaCodecList::updateDetailsForMultipleCodecs(
- const KeyedVector<AString, CodecSettings>& updates) {
- if (updates.size() == 0) {
- return;
- }
-
- exportResultsToXML(kProfilingResults, updates);
-
- for (size_t i = 0; i < updates.size(); ++i) {
- applyCodecSettings(updates.keyAt(i), updates.valueAt(i), &mCodecInfos);
- }
-}
-
void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_errors) {
// get href_base
char *href_base_end = strrchr(codecs_xml, '/');
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 265b1ea..535db09 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -30,6 +30,8 @@
namespace android {
+const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
+
// a limit to avoid allocating unreasonable number of codec instances in the measurement.
// this should be in sync with the MAX_SUPPORTED_INSTANCES defined in MediaCodecInfo.java.
static const int kMaxInstances = 32;
@@ -171,20 +173,6 @@
return codecs.size();
}
-static void printLongString(const char *buf, size_t size) {
- AString print;
- const char *start = buf;
- size_t len;
- size_t totalLen = size;
- while (totalLen > 0) {
- len = (totalLen > 500) ? 500 : totalLen;
- print.setTo(start, len);
- ALOGV("%s", print.c_str());
- totalLen -= len;
- start += len;
- }
-}
-
bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2) {
ssize_t pos = s.find(delimiter.c_str());
if (pos < 0) {
@@ -207,9 +195,18 @@
return true;
}
+void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos) {
+ CodecSettings global_results; // TODO: add global results.
+ KeyedVector<AString, CodecSettings> encoder_results;
+ KeyedVector<AString, CodecSettings> decoder_results;
+ profileCodecs(infos, &encoder_results, &decoder_results);
+ exportResultsToXML(kProfilingResults, global_results, encoder_results, decoder_results);
+}
+
void profileCodecs(
const Vector<sp<MediaCodecInfo>> &infos,
- KeyedVector<AString, CodecSettings> *results,
+ KeyedVector<AString, CodecSettings> *encoder_results,
+ KeyedVector<AString, CodecSettings> *decoder_results,
bool forceToMeasure) {
KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
for (size_t i = 0; i < infos.size(); ++i) {
@@ -240,157 +237,86 @@
AString key = name;
key.append(" ");
key.append(mimes[i]);
- key.append(" ");
- key.append(info->isEncoder() ? "encoder" : "decoder");
- results->add(key, settings);
+
+ if (info->isEncoder()) {
+ encoder_results->add(key, settings);
+ } else {
+ decoder_results->add(key, settings);
+ }
}
}
}
}
-void applyCodecSettings(
- const AString& codecInfo,
- const CodecSettings &settings,
- Vector<sp<MediaCodecInfo>> *infos) {
- AString name;
- AString mime;
- AString type;
- if (!splitString(codecInfo, " ", &name, &mime, &type)) {
- return;
- }
-
- for (size_t i = 0; i < infos->size(); ++i) {
- const sp<MediaCodecInfo> &info = infos->itemAt(i);
- if (name != info->getCodecName()) {
- continue;
- }
-
- Vector<AString> mimes;
- info->getSupportedMimes(&mimes);
- for (size_t j = 0; j < mimes.size(); ++j) {
- if (mimes[j] != mime) {
- continue;
- }
- const sp<MediaCodecInfo::Capabilities> &caps = info->getCapabilitiesFor(mime.c_str());
- for (size_t k = 0; k < settings.size(); ++k) {
- caps->getDetails()->setString(
- settings.keyAt(k).c_str(), settings.valueAt(k).c_str());
- }
- }
- }
-}
-
-void exportResultsToXML(const char *fileName, const KeyedVector<AString, CodecSettings>& results) {
-#if LOG_NDEBUG == 0
- ALOGE("measurement results");
+static AString globalResultsToXml(const CodecSettings& results) {
+ AString ret;
for (size_t i = 0; i < results.size(); ++i) {
- ALOGE("key %s", results.keyAt(i).c_str());
- const CodecSettings &settings = results.valueAt(i);
- for (size_t j = 0; j < settings.size(); ++j) {
- ALOGE("name %s value %s", settings.keyAt(j).c_str(), settings.valueAt(j).c_str());
- }
+ AString setting = AStringPrintf(
+ " <Setting name=\"%s\" value=\"%s\" />\n",
+ results.keyAt(i).c_str(),
+ results.valueAt(i).c_str());
+ ret.append(setting);
}
-#endif
+ return ret;
+}
- AString overrides;
- FILE *f = fopen(fileName, "rb");
- if (f != NULL) {
- fseek(f, 0, SEEK_END);
- long size = ftell(f);
- rewind(f);
-
- char *buf = (char *)malloc(size);
- if (fread(buf, size, 1, f) == 1) {
- overrides.setTo(buf, size);
- if (!LOG_NDEBUG) {
- ALOGV("Existing overrides:");
- printLongString(buf, size);
- }
- } else {
- ALOGE("Failed to read %s", fileName);
- }
- fclose(f);
- free(buf);
- }
-
+static AString codecResultsToXml(const KeyedVector<AString, CodecSettings>& results) {
+ AString ret;
for (size_t i = 0; i < results.size(); ++i) {
AString name;
AString mime;
- AString type;
- if (!splitString(results.keyAt(i), " ", &name, &mime, &type)) {
+ if (!splitString(results.keyAt(i), " ", &name, &mime)) {
continue;
}
- name = AStringPrintf("\"%s\"", name.c_str());
- mime = AStringPrintf("\"%s\"", mime.c_str());
- ALOGV("name(%s) mime(%s) type(%s)", name.c_str(), mime.c_str(), type.c_str());
- ssize_t posCodec = overrides.find(name.c_str());
- size_t posInsert = 0;
- if (posCodec < 0) {
- AString encodersDecoders = (type == "encoder") ? "<Encoders>" : "<Decoders>";
- AString encodersDecodersEnd = (type == "encoder") ? "</Encoders>" : "</Decoders>";
- ssize_t posEncodersDecoders = overrides.find(encodersDecoders.c_str());
- if (posEncodersDecoders < 0) {
- AString mediaCodecs = "<MediaCodecs>";
- ssize_t posMediaCodec = overrides.find(mediaCodecs.c_str());
- if (posMediaCodec < 0) {
- posMediaCodec = overrides.size();
- overrides.insert("\n<MediaCodecs>\n</MediaCodecs>\n", posMediaCodec);
- posMediaCodec = overrides.find(mediaCodecs.c_str(), posMediaCodec);
- }
- posEncodersDecoders = posMediaCodec + mediaCodecs.size();
- AString codecs = AStringPrintf(
- "\n %s\n %s", encodersDecoders.c_str(), encodersDecodersEnd.c_str());
- overrides.insert(codecs.c_str(), posEncodersDecoders);
- posEncodersDecoders = overrides.find(encodersDecoders.c_str(), posEncodersDecoders);
- }
- posCodec = posEncodersDecoders + encodersDecoders.size();
- AString codec = AStringPrintf(
- "\n <MediaCodec name=%s type=%s update=\"true\" >\n </MediaCodec>",
- name.c_str(),
- mime.c_str());
- overrides.insert(codec.c_str(), posCodec);
- posCodec = overrides.find(name.c_str());
- }
-
- // insert to existing entry
- ssize_t posMime = overrides.find(mime.c_str(), posCodec);
- ssize_t posEnd = overrides.find(">", posCodec);
- if (posEnd < 0) {
- ALOGE("Format error in overrides file.");
- return;
- }
- if (posMime < 0 || posMime > posEnd) {
- // new mime for an existing component
- AString codecEnd = "</MediaCodec>";
- posInsert = overrides.find(codecEnd.c_str(), posCodec) + codecEnd.size();
- AString codec = AStringPrintf(
- "\n <MediaCodec name=%s type=%s update=\"true\" >\n </MediaCodec>",
- name.c_str(),
- mime.c_str());
- overrides.insert(codec.c_str(), posInsert);
- posInsert = overrides.find(">", posInsert) + 1;
- } else {
- posInsert = posEnd + 1;
- }
-
+ AString codec =
+ AStringPrintf(" <MediaCodec name=\"%s\" type=\"%s\" update=\"true\" >\n",
+ name.c_str(),
+ mime.c_str());
+ ret.append(codec);
CodecSettings settings = results.valueAt(i);
for (size_t i = 0; i < settings.size(); ++i) {
// WARNING: we assume all the settings are "Limit". Currently we have only one type
// of setting in this case, which is "max-supported-instances".
- AString strInsert = AStringPrintf(
- "\n <Limit name=\"%s\" value=\"%s\" />",
+ AString setting = AStringPrintf(
+ " <Limit name=\"%s\" value=\"%s\" />\n",
settings.keyAt(i).c_str(),
settings.valueAt(i).c_str());
- overrides.insert(strInsert, posInsert);
+ ret.append(setting);
}
+ ret.append(" </MediaCodec>\n");
+ }
+ return ret;
+}
+
+void exportResultsToXML(
+ const char *fileName,
+ const CodecSettings& global_results,
+ const KeyedVector<AString, CodecSettings>& encoder_results,
+ const KeyedVector<AString, CodecSettings>& decoder_results) {
+ if (global_results.size() == 0 && encoder_results.size() == 0 && decoder_results.size() == 0) {
+ return;
}
- if (!LOG_NDEBUG) {
- ALOGV("New overrides:");
- printLongString(overrides.c_str(), overrides.size());
+ AString overrides;
+ overrides.append("<MediaCodecs>\n");
+ if (global_results.size() > 0) {
+ overrides.append(" <Settings>\n");
+ overrides.append(globalResultsToXml(global_results));
+ overrides.append(" </Settings>\n");
}
+ if (encoder_results.size() > 0) {
+ overrides.append(" <Encoders>\n");
+ overrides.append(codecResultsToXml(encoder_results));
+ overrides.append(" </Encoders>\n");
+ }
+ if (decoder_results.size() > 0) {
+ overrides.append(" <Decoders>\n");
+ overrides.append(codecResultsToXml(decoder_results));
+ overrides.append(" </Decoders>\n");
+ }
+ overrides.append("</MediaCodecs>\n");
- f = fopen(fileName, "wb");
+ FILE *f = fopen(fileName, "wb");
if (f == NULL) {
ALOGE("Failed to open %s for writing.", fileName);
return;
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/MediaCodecListOverrides.h
index c6cc2ea..c4758fa 100644
--- a/media/libstagefright/MediaCodecListOverrides.h
+++ b/media/libstagefright/MediaCodecListOverrides.h
@@ -26,24 +26,27 @@
namespace android {
+extern const char *kProfilingResults;
+
struct MediaCodecInfo;
bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2);
-bool splitString(
- const AString &s, const AString &delimiter, AString *s1, AString *s2, AString *s3);
+// profile codecs and save the result to xml file named kProfilingResults.
+void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos);
+// profile codecs and save the result to encoder_results and decoder_results.
void profileCodecs(
const Vector<sp<MediaCodecInfo>> &infos,
- KeyedVector<AString, CodecSettings> *results,
- bool forceToMeasure = false); // forceToMeasure is mainly for testing
+ KeyedVector<AString, CodecSettings> *encoder_results,
+ KeyedVector<AString, CodecSettings> *decoder_results,
+ bool forceToMeasure = false);
-void applyCodecSettings(
- const AString& codecInfo,
- const CodecSettings &settings,
- Vector<sp<MediaCodecInfo>> *infos);
-
-void exportResultsToXML(const char *fileName, const KeyedVector<AString, CodecSettings>& results);
+void exportResultsToXML(
+ const char *fileName,
+ const CodecSettings& global_results,
+ const KeyedVector<AString, CodecSettings>& encoder_results,
+ const KeyedVector<AString, CodecSettings>& decoder_results);
} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 8d4bab8..aa6a7c0 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -43,6 +43,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SurfaceUtils.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/SkipCutBuffer.h>
#include <utils/Vector.h>
@@ -1783,35 +1784,6 @@
return OK;
}
-status_t OMXCodec::applyRotation() {
- sp<MetaData> meta = mSource->getFormat();
-
- int32_t rotationDegrees;
- if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- uint32_t transform;
- switch (rotationDegrees) {
- case 0: transform = 0; break;
- case 90: transform = HAL_TRANSFORM_ROT_90; break;
- case 180: transform = HAL_TRANSFORM_ROT_180; break;
- case 270: transform = HAL_TRANSFORM_ROT_270; break;
- default: transform = 0; break;
- }
-
- status_t err = OK;
-
- if (transform) {
- err = native_window_set_buffers_transform(
- mNativeWindow.get(), transform);
- ALOGE("native_window_set_buffers_transform failed: %s (%d)",
- strerror(-err), -err);
- }
-
- return err;
-}
-
status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
// Get the number of buffers needed.
OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -1825,30 +1797,11 @@
return err;
}
- err = native_window_set_buffers_dimensions(
- mNativeWindow.get(),
- def.format.video.nFrameWidth,
- def.format.video.nFrameHeight);
+ sp<MetaData> meta = mSource->getFormat();
- if (err != 0) {
- ALOGE("native_window_set_buffers_dimensions failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_buffers_format(
- mNativeWindow.get(),
- def.format.video.eColorFormat);
-
- if (err != 0) {
- ALOGE("native_window_set_buffers_format failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = applyRotation();
- if (err != OK) {
- return err;
+ int32_t rotationDegrees;
+ if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
+ rotationDegrees = 0;
}
// Set up the native window.
@@ -1859,34 +1812,19 @@
// XXX: Currently this error is logged, but not fatal.
usage = 0;
}
+
if (mFlags & kEnableGrallocUsageProtected) {
usage |= GRALLOC_USAGE_PROTECTED;
}
- // Make sure to check whether either Stagefright or the video decoder
- // requested protected buffers.
- if (usage & GRALLOC_USAGE_PROTECTED) {
- // Verify that the ANativeWindow sends images directly to
- // SurfaceFlinger.
- int queuesToNativeWindow = 0;
- err = mNativeWindow->query(
- mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
- &queuesToNativeWindow);
- if (err != 0) {
- ALOGE("error authenticating native window: %d", err);
- return err;
- }
- if (queuesToNativeWindow != 1) {
- ALOGE("native window could not be authenticated");
- return PERMISSION_DENIED;
- }
- }
-
- ALOGV("native_window_set_usage usage=0x%x", usage);
- err = native_window_set_usage(
- mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
+ err = setNativeWindowSizeFormatAndUsage(
+ mNativeWindow.get(),
+ def.format.video.nFrameWidth,
+ def.format.video.nFrameHeight,
+ def.format.video.eColorFormat,
+ rotationDegrees,
+ usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
if (err != 0) {
- ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
return err;
}
@@ -2053,156 +1991,6 @@
return bufInfo;
}
-status_t OMXCodec::pushBlankBuffersToNativeWindow() {
- status_t err = NO_ERROR;
- ANativeWindowBuffer* anb = NULL;
- int numBufs = 0;
- int minUndequeuedBufs = 0;
-
- // We need to reconnect to the ANativeWindow as a CPU client to ensure that
- // no frames get dropped by SurfaceFlinger assuming that these are video
- // frames.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_buffers_dimensions(mNativeWindow.get(), 1, 1);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffers_dimensions failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = native_window_set_buffers_format(mNativeWindow.get(), HAL_PIXEL_FORMAT_RGBX_8888);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffers_format failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = native_window_set_usage(mNativeWindow.get(),
- GRALLOC_USAGE_SW_WRITE_OFTEN);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_usage failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = native_window_set_scaling_mode(mNativeWindow.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- if (err != OK) {
- ALOGE("error pushing blank frames: set_scaling_mode failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = mNativeWindow->query(mNativeWindow.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
- "failed: %s (%d)", strerror(-err), -err);
- goto error;
- }
-
- numBufs = minUndequeuedBufs + 1;
- err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- // We push numBufs + 1 buffers to ensure that we've drawn into the same
- // buffer twice. This should guarantee that the buffer has been displayed
- // on the screen and then been replaced, so an previous video frames are
- // guaranteed NOT to be currently displayed.
- for (int i = 0; i < numBufs + 1; i++) {
- err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-
- // Fill the buffer with the a 1x1 checkerboard pattern ;)
- uint32_t* img = NULL;
- err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: lock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- *img = 0;
-
- err = buf->unlock();
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: unlock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = mNativeWindow->queueBuffer(mNativeWindow.get(),
- buf->getNativeBuffer(), -1);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- anb = NULL;
- }
-
-error:
-
- if (err != NO_ERROR) {
- // Clean up after an error.
- if (anb != NULL) {
- mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
- }
-
- native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
-
- return err;
- } else {
- // Clean up after success.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- return NO_ERROR;
- }
-}
-
int64_t OMXCodec::getDecodingTimeUs() {
CHECK(mIsEncoder && mIsVideo);
@@ -2784,7 +2572,7 @@
// them has made it to the display. This allows the OMX
// component teardown to zero out any protected buffers
// without the risk of scanning out one of those buffers.
- pushBlankBuffersToNativeWindow();
+ pushBlankBuffersToNativeWindow(mNativeWindow.get());
}
setState(IDLE_TO_LOADED);
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
new file mode 100644
index 0000000..6b62e43
--- /dev/null
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2015 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 "SurfaceUtils"
+#include <utils/Log.h>
+
+#include <media/stagefright/SurfaceUtils.h>
+
+#include <gui/Surface.h>
+
+namespace android {
+
+status_t setNativeWindowSizeFormatAndUsage(
+ ANativeWindow *nativeWindow /* nonnull */,
+ int width, int height, int format, int rotation, int usage) {
+ status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_set_buffers_format(nativeWindow, format);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ int transform = 0;
+ if ((rotation % 90) == 0) {
+ switch ((rotation / 90) & 3) {
+ case 1: transform = HAL_TRANSFORM_ROT_90; break;
+ case 2: transform = HAL_TRANSFORM_ROT_180; break;
+ case 3: transform = HAL_TRANSFORM_ROT_270; break;
+ default: transform = 0; break;
+ }
+ }
+
+ err = native_window_set_buffers_transform(nativeWindow, transform);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ // Make sure to check whether either Stagefright or the video decoder
+ // requested protected buffers.
+ if (usage & GRALLOC_USAGE_PROTECTED) {
+ // Verify that the ANativeWindow sends images directly to
+ // SurfaceFlinger.
+ int queuesToNativeWindow = 0;
+ err = nativeWindow->query(
+ nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow);
+ if (err != NO_ERROR) {
+ ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ if (queuesToNativeWindow != 1) {
+ ALOGE("native window could not be authenticated");
+ return PERMISSION_DENIED;
+ }
+ }
+
+ int consumerUsage = 0;
+ err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
+ if (err != NO_ERROR) {
+ ALOGW("failed to get consumer usage bits. ignoring");
+ err = NO_ERROR;
+ }
+
+ int finalUsage = usage | consumerUsage;
+ ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage);
+ err = native_window_set_usage(nativeWindow, finalUsage);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_set_scaling_mode(
+ nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x",
+ nativeWindow, width, height, format, rotation, finalUsage);
+ return NO_ERROR;
+}
+
+status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) {
+ status_t err = NO_ERROR;
+ ANativeWindowBuffer* anb = NULL;
+ int numBufs = 0;
+ int minUndequeuedBufs = 0;
+
+ // We need to reconnect to the ANativeWindow as a CPU client to ensure that
+ // no frames get dropped by SurfaceFlinger assuming that these are video
+ // frames.
+ err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
+ (void)native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ return err;
+ }
+
+ err = setNativeWindowSizeFormatAndUsage(
+ nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ if (err != NO_ERROR) {
+ goto error;
+ }
+
+ static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true);
+
+ err = nativeWindow->query(nativeWindow,
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
+ "failed: %s (%d)", strerror(-err), -err);
+ goto error;
+ }
+
+ numBufs = minUndequeuedBufs + 1;
+ err = native_window_set_buffer_count(nativeWindow, numBufs);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err);
+ goto error;
+ }
+
+ // We push numBufs + 1 buffers to ensure that we've drawn into the same
+ // buffer twice. This should guarantee that the buffer has been displayed
+ // on the screen and then been replaced, so an previous video frames are
+ // guaranteed NOT to be currently displayed.
+ for (int i = 0; i < numBufs + 1; i++) {
+ err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ break;
+ }
+
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+
+ // Fill the buffer with the a 1x1 checkerboard pattern ;)
+ uint32_t *img = NULL;
+ err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
+ break;
+ }
+
+ *img = 0;
+
+ err = buf->unlock();
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err);
+ break;
+ }
+
+ err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err);
+ break;
+ }
+
+ anb = NULL;
+ }
+
+error:
+
+ if (anb != NULL) {
+ nativeWindow->cancelBuffer(nativeWindow, anb, -1);
+ anb = NULL;
+ }
+
+ // Clean up after success or error.
+ status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU);
+ if (err2 != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2);
+ if (err == NO_ERROR) {
+ err = err2;
+ }
+ }
+
+ err2 = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ if (err2 != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
+ if (err == NO_ERROR) {
+ err = err2;
+ }
+ }
+
+ return err;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index bb89567..2d9b3d4 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -30,12 +30,11 @@
namespace android {
MediaHTTP::MediaHTTP(const sp<IMediaHTTPConnection> &conn)
- : mInitCheck(NO_INIT),
+ : mInitCheck((conn != NULL) ? OK : NO_INIT),
mHTTPConnection(conn),
mCachedSizeValid(false),
mCachedSize(0ll),
mDrmManagerClient(NULL) {
- mInitCheck = OK;
}
MediaHTTP::~MediaHTTP() {
@@ -171,6 +170,10 @@
}
String8 MediaHTTP::getUri() {
+ if (mInitCheck != OK) {
+ return String8::empty();
+ }
+
String8 uri;
if (OK == mHTTPConnection->getUri(&uri)) {
return uri;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index d8c38e7..64a8532 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -1503,11 +1503,10 @@
ALOGV("discarding fetcher-%d", fetcher->getFetcherID());
fetcher->stopAsync();
} else {
- float threshold = -1.0f; // always finish fetching by default
+ float threshold = 0.0f; // default to pause after current block (47Kbytes)
bool disconnect = false;
if (timeUs >= 0ll) {
// seeking, no need to finish fetching
- threshold = 0.0f;
disconnect = true;
} else if (delayRemoval) {
// adapting, abort if remaining of current segment is over threshold
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 53087b6..5a0deec 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -1424,11 +1424,17 @@
int64_t minDiffUs, maxDiffUs;
if (mSeekMode == LiveSession::kSeekModeNextSample) {
+ // if the previous fetcher paused in the middle of a segment, we
+ // want to start at a segment that overlaps the last sample
minDiffUs = -mPlaylist->getTargetDuration();
maxDiffUs = 0ll;
} else {
+ // if the previous fetcher paused at the end of a segment, ideally
+ // we want to start at the segment that's roughly aligned with its
+ // next segment, but if the two variants are not well aligned we
+ // adjust the diff to within (-T/2, T/2)
minDiffUs = -mPlaylist->getTargetDuration() / 2;
- maxDiffUs = mPlaylist->getTargetDuration();
+ maxDiffUs = mPlaylist->getTargetDuration() / 2;
}
int32_t oldSeqNumber = mSeqNumber;
@@ -1611,6 +1617,9 @@
ALOGE("MPEG2 Transport streams do not contain subtitles.");
return ERROR_MALFORMED;
}
+ if (stream == LiveSession::STREAMTYPE_METADATA) {
+ continue;
+ }
ATSParser::SourceType type =LiveSession::getSourceTypeForStream(stream);
sp<AnotherPacketSource> source =
static_cast<AnotherPacketSource *>(
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 00f071b..ba17e90 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1673,21 +1673,11 @@
}
size_t n = strlen(baseURL);
- if (baseURL[n - 1] == '/') {
- out->setTo(baseURL);
- out->append(url);
- } else {
- const char *slashPos = strrchr(baseURL, '/');
-
- if (slashPos > &baseURL[6]) {
- out->setTo(baseURL, slashPos - baseURL);
- } else {
- out->setTo(baseURL);
- }
-
+ out->setTo(baseURL);
+ if (baseURL[n - 1] != '/') {
out->append("/");
- out->append(url);
}
+ out->append(url);
return true;
}
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index 170cde3..146a244 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -31,29 +31,8 @@
static const char kTestOverridesStr[] =
"<MediaCodecs>\n"
" <Settings>\n"
-" <Setting name=\"max-max-supported-instances\" value=\"8\" update=\"true\" />\n"
-" </Settings>\n"
-" <Encoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"bitrate\" range=\"1-20000000\" />\n"
-" <Feature name=\"can-swap-width-height\" />\n"
-" </MediaCodec>\n"
-" </Encoders>\n"
-" <Decoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"size\" min=\"64x64\" max=\"1920x1088\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"different_mime\" update=\"true\" >\n"
-" </MediaCodec>\n"
-" </Decoders>\n"
-"</MediaCodecs>\n";
-
-static const char kTestOverridesStrNew1[] =
-"<MediaCodecs>\n"
-" <Settings>\n"
-" <Setting name=\"max-max-supported-instances\" value=\"8\" update=\"true\" />\n"
+" <Setting name=\"supports-multiple-secure-codecs\" value=\"false\" />\n"
+" <Setting name=\"supports-secure-with-non-secure-codec\" value=\"true\" />\n"
" </Settings>\n"
" <Encoders>\n"
" <MediaCodec name=\"OMX.qcom.video.encoder.avc\" type=\"video/avc\" update=\"true\" >\n"
@@ -61,57 +40,21 @@
" </MediaCodec>\n"
" <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"bitrate\" range=\"1-20000000\" />\n"
-" <Feature name=\"can-swap-width-height\" />\n"
" </MediaCodec>\n"
" </Encoders>\n"
" <Decoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
+" <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
+" <Limit name=\"max-supported-instances\" value=\"1\" />\n"
" </MediaCodec>\n"
" <MediaCodec name=\"OMX.qcom.video.decoder.h263\" type=\"video/3gpp\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"1\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"size\" min=\"64x64\" max=\"1920x1088\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"different_mime\" update=\"true\" >\n"
-" </MediaCodec>\n"
" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"video/mpeg2\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
" </MediaCodec>\n"
-" </Decoders>\n"
-"</MediaCodecs>\n";
-
-static const char kTestOverridesStrNew2[] =
-"\n"
-"<MediaCodecs>\n"
-" <Encoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.encoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" </MediaCodec>\n"
-" </Encoders>\n"
-" <Decoders>\n"
" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"video/mpeg2\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.h263\" type=\"video/3gpp\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"1\" />\n"
-" </MediaCodec>\n"
" </Decoders>\n"
"</MediaCodecs>\n";
@@ -119,53 +62,6 @@
public:
MediaCodecListOverridesTest() {}
- void verifyOverrides(const KeyedVector<AString, CodecSettings> &overrides) {
- EXPECT_EQ(3u, overrides.size());
-
- EXPECT_TRUE(overrides.keyAt(0) == "OMX.qcom.video.decoder.avc video/avc decoder");
- const CodecSettings &settings0 = overrides.valueAt(0);
- EXPECT_EQ(1u, settings0.size());
- EXPECT_TRUE(settings0.keyAt(0) == "max-supported-instances");
- EXPECT_TRUE(settings0.valueAt(0) == "4");
-
- EXPECT_TRUE(overrides.keyAt(1) == "OMX.qcom.video.encoder.avc video/avc encoder");
- const CodecSettings &settings1 = overrides.valueAt(1);
- EXPECT_EQ(1u, settings1.size());
- EXPECT_TRUE(settings1.keyAt(0) == "max-supported-instances");
- EXPECT_TRUE(settings1.valueAt(0) == "3");
-
- EXPECT_TRUE(overrides.keyAt(2) == "global");
- const CodecSettings &settings2 = overrides.valueAt(2);
- EXPECT_EQ(3u, settings2.size());
- EXPECT_TRUE(settings2.keyAt(0) == "max-max-supported-instances");
- EXPECT_TRUE(settings2.valueAt(0) == "8");
- EXPECT_TRUE(settings2.keyAt(1) == "supports-multiple-secure-codecs");
- EXPECT_TRUE(settings2.valueAt(1) == "false");
- EXPECT_TRUE(settings2.keyAt(2) == "supports-secure-with-non-secure-codec");
- EXPECT_TRUE(settings2.valueAt(2) == "true");
- }
-
- void verifySetting(const sp<AMessage> &details, const char *name, const char *value) {
- AString value1;
- EXPECT_TRUE(details->findString(name, &value1));
- EXPECT_TRUE(value1 == value);
- }
-
- void createTestInfos(Vector<sp<MediaCodecInfo>> *infos) {
- const char *name = "OMX.qcom.video.decoder.avc";
- const bool encoder = false;
- const char *mime = "video/avc";
- sp<MediaCodecInfo> info = new MediaCodecInfo(name, encoder, mime);
- infos->push_back(info);
- const sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mime);
- const sp<AMessage> details = caps->getDetails();
- details->setString("cap1", "value1");
- details->setString("max-max-supported-instances", "16");
-
- info = new MediaCodecInfo("anothercodec", true, "anothermime");
- infos->push_back(info);
- }
-
void addMaxInstancesSetting(
const AString &key,
const AString &value,
@@ -175,16 +71,34 @@
results->add(key, settings);
}
- void exportTestResultsToXML(const char *fileName) {
- KeyedVector<AString, CodecSettings> r;
- addMaxInstancesSetting("OMX.qcom.video.decoder.avc.secure video/avc decoder", "1", &r);
- addMaxInstancesSetting("OMX.qcom.video.decoder.h263 video/3gpp decoder", "4", &r);
- addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg2 video/mpeg2 decoder", "3", &r);
- addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg4 video/mp4v-es decoder", "3", &r);
- addMaxInstancesSetting("OMX.qcom.video.encoder.avc video/avc encoder", "4", &r);
- addMaxInstancesSetting("OMX.qcom.video.encoder.mpeg4 video/mp4v-es encoder", "4", &r);
+ void verifyProfileResults(const KeyedVector<AString, CodecSettings> &results) {
+ EXPECT_LT(0u, results.size());
+ for (size_t i = 0; i < results.size(); ++i) {
+ AString key = results.keyAt(i);
+ CodecSettings settings = results.valueAt(i);
+ EXPECT_EQ(1u, settings.size());
+ EXPECT_TRUE(settings.keyAt(0) == "max-supported-instances");
+ AString valueS = settings.valueAt(0);
+ int32_t value = strtol(valueS.c_str(), NULL, 10);
+ EXPECT_LT(0, value);
+ ALOGV("profileCodecs results %s %s", key.c_str(), valueS.c_str());
+ }
+ }
- exportResultsToXML(fileName, r);
+ void exportTestResultsToXML(const char *fileName) {
+ CodecSettings gR;
+ gR.add("supports-multiple-secure-codecs", "false");
+ gR.add("supports-secure-with-non-secure-codec", "true");
+ KeyedVector<AString, CodecSettings> eR;
+ addMaxInstancesSetting("OMX.qcom.video.encoder.avc video/avc", "4", &eR);
+ addMaxInstancesSetting("OMX.qcom.video.encoder.mpeg4 video/mp4v-es", "4", &eR);
+ KeyedVector<AString, CodecSettings> dR;
+ addMaxInstancesSetting("OMX.qcom.video.decoder.avc.secure video/avc", "1", &dR);
+ addMaxInstancesSetting("OMX.qcom.video.decoder.h263 video/3gpp", "4", &dR);
+ addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg2 video/mpeg2", "3", &dR);
+ addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg4 video/mp4v-es", "3", &dR);
+
+ exportResultsToXML(fileName, gR, eR, dR);
}
};
@@ -198,18 +112,6 @@
EXPECT_TRUE(splitString(s, delimiter, &s1, &s2));
EXPECT_TRUE(s1 == "abc");
EXPECT_TRUE(s2 == "123");
-
- s = "abc123xyz";
- delimiter = ",";
- AString s3;
- EXPECT_FALSE(splitString(s, delimiter, &s1, &s2, &s3));
- s = "abc,123xyz";
- EXPECT_FALSE(splitString(s, delimiter, &s1, &s2, &s3));
- s = "abc,123,xyz";
- EXPECT_TRUE(splitString(s, delimiter, &s1, &s2, &s3));
- EXPECT_TRUE(s1 == "abc");
- EXPECT_TRUE(s2 == "123" );
- EXPECT_TRUE(s3 == "xyz");
}
// TODO: the codec component never returns OMX_EventCmdComplete in unit test.
@@ -219,76 +121,14 @@
for (size_t i = 0; i < list->countCodecs(); ++i) {
infos.push_back(list->getCodecInfo(i));
}
- KeyedVector<AString, CodecSettings> results;
- profileCodecs(infos, &results, true /* forceToMeasure */);
- EXPECT_LT(0u, results.size());
- for (size_t i = 0; i < results.size(); ++i) {
- AString key = results.keyAt(i);
- CodecSettings settings = results.valueAt(i);
- EXPECT_EQ(1u, settings.size());
- EXPECT_TRUE(settings.keyAt(0) == "max-supported-instances");
- AString valueS = settings.valueAt(0);
- int32_t value = strtol(valueS.c_str(), NULL, 10);
- EXPECT_LT(0, value);
- ALOGV("profileCodecs results %s %s", key.c_str(), valueS.c_str());
- }
+ KeyedVector<AString, CodecSettings> encoder_results;
+ KeyedVector<AString, CodecSettings> decoder_results;
+ profileCodecs(infos, &encoder_results, &decoder_results, true /* forceToMeasure */);
+ verifyProfileResults(encoder_results);
+ verifyProfileResults(decoder_results);
}
-TEST_F(MediaCodecListOverridesTest, applyCodecSettings) {
- AString codecInfo = "OMX.qcom.video.decoder.avc video/avc decoder";
- Vector<sp<MediaCodecInfo>> infos;
- createTestInfos(&infos);
- CodecSettings settings;
- settings.add("max-supported-instances", "3");
- settings.add("max-max-supported-instances", "8");
- applyCodecSettings(codecInfo, settings, &infos);
-
- EXPECT_EQ(2u, infos.size());
- EXPECT_TRUE(AString(infos[0]->getCodecName()) == "OMX.qcom.video.decoder.avc");
- const sp<AMessage> details = infos[0]->getCapabilitiesFor("video/avc")->getDetails();
- verifySetting(details, "max-supported-instances", "3");
- verifySetting(details, "max-max-supported-instances", "8");
-
- EXPECT_TRUE(AString(infos[1]->getCodecName()) == "anothercodec");
- EXPECT_EQ(0u, infos[1]->getCapabilitiesFor("anothermime")->getDetails()->countEntries());
-}
-
-TEST_F(MediaCodecListOverridesTest, exportResultsToExistingFile) {
- const char *fileName = "/sdcard/mediacodec_list_overrides_test.xml";
- remove(fileName);
-
- FILE *f = fopen(fileName, "wb");
- if (f == NULL) {
- ALOGW("Failed to open %s for writing.", fileName);
- return;
- }
- EXPECT_EQ(
- strlen(kTestOverridesStr),
- fwrite(kTestOverridesStr, 1, strlen(kTestOverridesStr), f));
- fclose(f);
-
- exportTestResultsToXML(fileName);
-
- // verify
- AString overrides;
- f = fopen(fileName, "rb");
- ASSERT_TRUE(f != NULL);
- fseek(f, 0, SEEK_END);
- long size = ftell(f);
- rewind(f);
-
- char *buf = (char *)malloc(size);
- EXPECT_EQ((size_t)1, fread(buf, size, 1, f));
- overrides.setTo(buf, size);
- fclose(f);
- free(buf);
-
- EXPECT_TRUE(overrides == kTestOverridesStrNew1);
-
- remove(fileName);
-}
-
-TEST_F(MediaCodecListOverridesTest, exportResultsToEmptyFile) {
+TEST_F(MediaCodecListOverridesTest, exportTestResultsToXML) {
const char *fileName = "/sdcard/mediacodec_list_overrides_test.xml";
remove(fileName);
@@ -308,7 +148,7 @@
fclose(f);
free(buf);
- EXPECT_TRUE(overrides == kTestOverridesStrNew2);
+ EXPECT_TRUE(overrides == kTestOverridesStr);
remove(fileName);
}
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 7040af4..193fd64 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -66,9 +66,9 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif
-// Set kUseNewMixer to true to use the new mixer engine always. Otherwise the
-// original code will be used for stereo sinks, the new mixer for multichannel.
-static const bool kUseNewMixer = true;
+// Set kUseNewMixer to true to use the new mixer engine. Otherwise the
+// original code will be used. This is false for now.
+static const bool kUseNewMixer = false;
// Set kUseFloat to true to allow floating input into the mixer engine.
// If kUseNewMixer is false, this is ignored or may be overridden internally
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index bf1692d..9c4f9cd 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -128,7 +128,6 @@
List<const CameraMetadata> metadataRequestList;
int32_t requestId = mRequestIdCounter;
uint32_t loopCounter = 0;
- bool isReprocess = false;
for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end(); ++it) {
sp<CaptureRequest> request = *it;
@@ -136,18 +135,15 @@
ALOGE("%s: Camera %d: Sent null request.",
__FUNCTION__, mCameraId);
return BAD_VALUE;
- } else if (it == requests.begin()) {
- isReprocess = request->mIsReprocess;
- if (isReprocess && !mInputStream.configured) {
- ALOGE("%s: Camera %d: no input stream is configured.");
+ } else if (request->mIsReprocess) {
+ if (!mInputStream.configured) {
+ ALOGE("%s: Camera %d: no input stream is configured.", __FUNCTION__, mCameraId);
return BAD_VALUE;
- } else if (isReprocess && streaming) {
- ALOGE("%s: Camera %d: streaming reprocess requests not supported.");
+ } else if (streaming) {
+ ALOGE("%s: Camera %d: streaming reprocess requests not supported.", __FUNCTION__,
+ mCameraId);
return BAD_VALUE;
}
- } else if (isReprocess != request->mIsReprocess) {
- ALOGE("%s: Camera %d: Sent regular and reprocess requests.");
- return BAD_VALUE;
}
CameraMetadata metadata(request->mMetadata);
@@ -196,7 +192,7 @@
metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
outputStreamIds.size());
- if (isReprocess) {
+ if (request->mIsReprocess) {
metadata.update(ANDROID_REQUEST_INPUT_STREAMS, &mInputStream.id, 1);
}
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 84c5754..2504bfd 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -187,6 +187,8 @@
assert(mBuffersInFlight.size() == 0);
+ mConsumer->abandon();
+
/**
* no-op since we can't disconnect the producer from the consumer-side
*/
diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk
index 84218cf..b72230f 100644
--- a/services/mediaresourcemanager/Android.mk
+++ b/services/mediaresourcemanager/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ResourceManagerService.cpp
+LOCAL_SRC_FILES := ResourceManagerService.cpp ServiceLog.cpp
LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
@@ -13,6 +13,9 @@
LOCAL_C_INCLUDES += \
$(TOPDIR)frameworks/av/include
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 17aac4e..e3f70ff 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -29,6 +29,7 @@
#include <unistd.h>
#include "ResourceManagerService.h"
+#include "ServiceLog.h"
namespace android {
@@ -88,7 +89,7 @@
return infos.editItemAt(infos.size() - 1);
}
-status_t ResourceManagerService::dump(int fd, const Vector<String16>& args) {
+status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
Mutex::Autolock lock(mLock);
String8 result;
@@ -103,16 +104,14 @@
snprintf(buffer, SIZE, " SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
result.append(buffer);
- snprintf(buffer, SIZE, " Processes:\n");
- result.append(buffer);
+ result.append(" Processes:\n");
for (size_t i = 0; i < mMap.size(); ++i) {
snprintf(buffer, SIZE, " Pid: %d\n", mMap.keyAt(i));
result.append(buffer);
const ResourceInfos &infos = mMap.valueAt(i);
for (size_t j = 0; j < infos.size(); ++j) {
- snprintf(buffer, SIZE, " Client:\n");
- result.append(buffer);
+ result.append(" Client:\n");
snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
result.append(buffer);
@@ -120,14 +119,15 @@
result.append(buffer);
Vector<MediaResource> resources = infos[j].resources;
- snprintf(buffer, SIZE, " Resources:\n");
- result.append(buffer);
+ result.append(" Resources:\n");
for (size_t k = 0; k < resources.size(); ++k) {
snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
result.append(buffer);
}
}
}
+ result.append(" Logs:\n");
+ result.append(mServiceLog->toString());
write(fd, result.string(), result.size());
return OK;
@@ -135,18 +135,21 @@
ResourceManagerService::ResourceManagerService()
: mProcessInfo(new ProcessInfo()),
+ mServiceLog(new ServiceLog()),
mSupportsMultipleSecureCodecs(true),
mSupportsSecureWithNonSecureCodec(true) {}
ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
: mProcessInfo(processInfo),
+ mServiceLog(new ServiceLog()),
mSupportsMultipleSecureCodecs(true),
mSupportsSecureWithNonSecureCodec(true) {}
ResourceManagerService::~ResourceManagerService() {}
void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
- ALOGV("config(%s)", getString(policies).string());
+ String8 log = String8::format("config(%s)", getString(policies).string());
+ mServiceLog->add(log);
Mutex::Autolock lock(mLock);
for (size_t i = 0; i < policies.size(); ++i) {
@@ -165,8 +168,9 @@
int64_t clientId,
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources) {
- ALOGV("addResource(pid %d, clientId %lld, resources %s)",
+ String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
+ mServiceLog->add(log);
Mutex::Autolock lock(mLock);
ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
@@ -176,7 +180,8 @@
}
void ResourceManagerService::removeResource(int64_t clientId) {
- ALOGV("removeResource(%lld)", (long long) clientId);
+ String8 log = String8::format("removeResource(%lld)", (long long) clientId);
+ mServiceLog->add(log);
Mutex::Autolock lock(mLock);
bool found = false;
@@ -201,8 +206,9 @@
bool ResourceManagerService::reclaimResource(
int callingPid, const Vector<MediaResource> &resources) {
- ALOGV("reclaimResource(callingPid %d, resources %s)",
+ String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
callingPid, getString(resources).string());
+ mServiceLog->add(log);
Vector<sp<IResourceManagerClient>> clients;
{
@@ -265,7 +271,8 @@
sp<IResourceManagerClient> failedClient;
for (size_t i = 0; i < clients.size(); ++i) {
- ALOGV("reclaimResource from client %p", clients[i].get());
+ log = String8::format("reclaimResource from client %p", clients[i].get());
+ mServiceLog->add(log);
if (!clients[i]->reclaimResource()) {
failedClient = clients[i];
break;
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 0c3d694..0d9d878 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -30,6 +30,7 @@
namespace android {
+class ServiceLog;
struct ProcessInfoInterface;
struct ResourceInfo {
@@ -96,6 +97,7 @@
mutable Mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
+ sp<ServiceLog> mServiceLog;
PidResourceInfosMap mMap;
bool mSupportsMultipleSecureCodecs;
bool mSupportsSecureWithNonSecureCodec;
diff --git a/services/mediaresourcemanager/ServiceLog.cpp b/services/mediaresourcemanager/ServiceLog.cpp
new file mode 100644
index 0000000..be7b308
--- /dev/null
+++ b/services/mediaresourcemanager/ServiceLog.cpp
@@ -0,0 +1,54 @@
+/*
+**
+** Copyright 2015, 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 "ServiceLog"
+#include <utils/Log.h>
+
+#include <time.h>
+
+#include "ServiceLog.h"
+
+static const size_t kDefaultMaxNum = 100;
+
+namespace android {
+
+ServiceLog::ServiceLog() : mMaxNum(kDefaultMaxNum) {}
+ServiceLog::ServiceLog(size_t maxNum) : mMaxNum(maxNum) {}
+
+void ServiceLog::add(const String8 &log) {
+ Mutex::Autolock lock(mLock);
+ time_t now = time(0);
+ char buf[64];
+ strftime(buf, sizeof(buf), "%m-%d %T", localtime(&now));
+ String8 formattedLog = String8::format("%s %s", buf, log.string());
+ if (mLogs.add(formattedLog) == mMaxNum) {
+ mLogs.removeAt(0);
+ }
+}
+
+String8 ServiceLog::toString() const {
+ Mutex::Autolock lock(mLock);
+ String8 result;
+ for (size_t i = 0; i < mLogs.size(); ++i) {
+ result.append(mLogs[i]);
+ result.append("\n");
+ }
+ return result;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ServiceLog.h b/services/mediaresourcemanager/ServiceLog.h
new file mode 100644
index 0000000..14814ff
--- /dev/null
+++ b/services/mediaresourcemanager/ServiceLog.h
@@ -0,0 +1,46 @@
+/*
+**
+** Copyright 2015, 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_SERVICELOG_H
+#define ANDROID_SERVICELOG_H
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ServiceLog : public RefBase {
+public:
+ ServiceLog();
+ ServiceLog(size_t maxNum);
+
+ void add(const String8 &log);
+ String8 toString() const;
+
+private:
+ int mMaxNum;
+ mutable Mutex mLock;
+ Vector<String8> mLogs;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SERVICELOG_H
diff --git a/services/mediaresourcemanager/test/Android.mk b/services/mediaresourcemanager/test/Android.mk
index 228b62a..3b4ef0d 100644
--- a/services/mediaresourcemanager/test/Android.mk
+++ b/services/mediaresourcemanager/test/Android.mk
@@ -20,6 +20,35 @@
frameworks/av/include \
frameworks/av/services/mediaresourcemanager \
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := ServiceLog_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ ServiceLog_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libmedia \
+ libresourcemanagerservice \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/include \
+ frameworks/av/services/mediaresourcemanager \
+
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
LOCAL_32_BIT_ONLY := true
include $(BUILD_NATIVE_TEST)
diff --git a/services/mediaresourcemanager/test/ServiceLog_test.cpp b/services/mediaresourcemanager/test/ServiceLog_test.cpp
new file mode 100644
index 0000000..6ddcb87
--- /dev/null
+++ b/services/mediaresourcemanager/test/ServiceLog_test.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 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 "ServiceLog_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include "ServiceLog.h"
+
+namespace android {
+
+class ServiceLogTest : public ::testing::Test {
+public:
+ ServiceLogTest() : mServiceLog(new ServiceLog(3)) {
+ }
+
+protected:
+ sp<ServiceLog> mServiceLog;
+};
+
+TEST_F(ServiceLogTest, addThenToString) {
+ mServiceLog->add(String8("log1"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+ ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+ mServiceLog->add(String8("log2"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+ ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+ mServiceLog->add(String8("log3"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+ ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+ mServiceLog->add(String8("log4"));
+ EXPECT_FALSE(mServiceLog->toString().contains("log1"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log4"));
+ ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+ mServiceLog->add(String8("log5"));
+ EXPECT_FALSE(mServiceLog->toString().contains("log1"));
+ EXPECT_FALSE(mServiceLog->toString().contains("log2"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log4"));
+ EXPECT_TRUE(mServiceLog->toString().contains("log5"));
+ ALOGV("toString:\n%s", mServiceLog->toString().string());
+}
+
+} // namespace android