summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/img_utils/include/img_utils/DngUtils.h37
-rw-r--r--media/img_utils/src/DngUtils.cpp97
-rw-r--r--media/libmedia/IMediaHTTPConnection.cpp2
-rw-r--r--media/libmediaplayerservice/MediaPlayerFactory.cpp6
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp3
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.h1
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp16
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h2
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp42
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h9
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp1
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h7
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp6
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp74
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp34
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h1
-rw-r--r--media/libstagefright/ACodec.cpp25
-rw-r--r--media/libstagefright/CallbackDataSource.cpp23
-rwxr-xr-x[-rw-r--r--]media/libstagefright/MPEG4Extractor.cpp14
-rw-r--r--media/libstagefright/MediaCodec.cpp14
-rw-r--r--media/libstagefright/MediaCodecList.cpp5
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp305
-rwxr-xr-xmedia/libstagefright/codecs/avcdec/SoftAVCDec.cpp2
-rw-r--r--media/libstagefright/codecs/on2/dec/SoftVPX.cpp2
-rw-r--r--media/libstagefright/codecs/opus/dec/SoftOpus.cpp14
-rw-r--r--media/libstagefright/foundation/AHierarchicalStateMachine.cpp3
-rw-r--r--media/libstagefright/foundation/ALooperRoster.cpp3
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp7
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp4
-rw-r--r--media/mediaserver/Android.mk4
-rw-r--r--media/mediaserver/IcuUtils.h25
-rw-r--r--media/mediaserver/icuutils.cpp42
-rw-r--r--media/mediaserver/main_mediaserver.cpp2
-rw-r--r--services/audioflinger/Threads.cpp62
-rw-r--r--services/audioflinger/Threads.h7
-rw-r--r--services/audioflinger/Tracks.cpp4
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.cpp5
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.h5
39 files changed, 612 insertions, 307 deletions
diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h
index 4389b02..3dcedc5 100644
--- a/media/img_utils/include/img_utils/DngUtils.h
+++ b/media/img_utils/include/img_utils/DngUtils.h
@@ -31,6 +31,7 @@ namespace android {
namespace img_utils {
#define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
/**
* Utility class for building values for the OpcodeList tags specified
@@ -107,13 +108,49 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> {
uint32_t mapPlanes,
const float* mapGains);
+ /**
+ * Add WarpRectilinear opcode for the given metadata parameters.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ virtual status_t addWarpRectilinearForMetadata(const float* kCoeffs,
+ uint32_t activeArrayWidth,
+ uint32_t activeArrayHeight,
+ float opticalCenterX,
+ float opticalCenterY);
+
+ /**
+ * Add a WarpRectilinear opcode.
+ *
+ * numPlanes - Number of planes included in this opcode.
+ * opticalCenterX, opticalCenterY - Normalized x,y coordinates of the sensor optical
+ * center relative to the top,left pixel of the produced images (e.g. [0.5, 0.5]
+ * gives a sensor optical center in the image center.
+ * kCoeffs - A list of coefficients for the polynomial equation representing the distortion
+ * correction. For each plane, 6 coefficients must be included:
+ * {k_r0, k_r1, k_r2, k_r3, k_t0, k_t1}. See the DNG 1.4 specification for an
+ * outline of the polynomial used here.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ virtual status_t addWarpRectilinear(uint32_t numPlanes,
+ double opticalCenterX,
+ double opticalCenterY,
+ const double* kCoeffs);
+
// TODO: Add other Opcode methods
protected:
static const uint32_t FLAG_OPTIONAL = 0x1u;
static const uint32_t FLAG_OPTIONAL_FOR_PREVIEW = 0x2u;
+ // Opcode IDs
enum {
+ WARP_RECTILINEAR_ID = 1,
GAIN_MAP_ID = 9,
+ };
+
+ // LSM mosaic indices
+ enum {
LSM_R_IND = 0,
LSM_GE_IND = 1,
LSM_GO_IND = 2,
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index d3b4a35..b213403 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -16,6 +16,10 @@
#include <img_utils/DngUtils.h>
+#include <inttypes.h>
+
+#include <math.h>
+
namespace android {
namespace img_utils {
@@ -229,7 +233,7 @@ status_t OpcodeListBuilder::addGainMap(uint32_t top,
err = mEndianOut.write(version, 0, NELEMS(version));
if (err != OK) return err;
- // Do not include optional flag for preview, as this can have a large effect on the output.
+ // Allow this opcode to be skipped if not supported
uint32_t flags = FLAG_OPTIONAL;
err = mEndianOut.write(&flags, 0, 1);
@@ -278,5 +282,96 @@ status_t OpcodeListBuilder::addGainMap(uint32_t top,
return OK;
}
+status_t OpcodeListBuilder::addWarpRectilinearForMetadata(const float* kCoeffs,
+ uint32_t activeArrayWidth,
+ uint32_t activeArrayHeight,
+ float opticalCenterX,
+ float opticalCenterY) {
+ if (activeArrayWidth <= 1 || activeArrayHeight <= 1) {
+ ALOGE("%s: Cannot add opcode for active array with dimensions w=%" PRIu32 ", h=%" PRIu32,
+ __FUNCTION__, activeArrayWidth, activeArrayHeight);
+ return BAD_VALUE;
+ }
+
+ double normalizedOCX = opticalCenterX / static_cast<double>(activeArrayWidth - 1);
+ double normalizedOCY = opticalCenterY / static_cast<double>(activeArrayHeight - 1);
+
+ normalizedOCX = CLAMP(normalizedOCX, 0, 1);
+ normalizedOCY = CLAMP(normalizedOCY, 0, 1);
+
+ // Conversion factors from Camera2 K factors to DNG spec. K factors:
+ //
+ // Note: these are necessary because our unit system assumes a
+ // normalized max radius of sqrt(2), whereas the DNG spec's
+ // WarpRectilinear opcode assumes a normalized max radius of 1.
+ // Thus, each K coefficient must include the domain scaling
+ // factor (the DNG domain is scaled by sqrt(2) to emulate the
+ // domain used by the Camera2 specification).
+
+ const double c_0 = sqrt(2);
+ const double c_1 = 2 * sqrt(2);
+ const double c_2 = 4 * sqrt(2);
+ const double c_3 = 8 * sqrt(2);
+ const double c_4 = 2;
+ const double c_5 = 2;
+
+ const double coeffs[] = { c_0 * kCoeffs[0],
+ c_1 * kCoeffs[1],
+ c_2 * kCoeffs[2],
+ c_3 * kCoeffs[3],
+ c_4 * kCoeffs[4],
+ c_5 * kCoeffs[5] };
+
+
+ return addWarpRectilinear(/*numPlanes*/1,
+ /*opticalCenterX*/normalizedOCX,
+ /*opticalCenterY*/normalizedOCY,
+ coeffs);
+}
+
+status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes,
+ double opticalCenterX,
+ double opticalCenterY,
+ const double* kCoeffs) {
+
+ uint32_t opcodeId = WARP_RECTILINEAR_ID;
+
+ status_t err = mEndianOut.write(&opcodeId, 0, 1);
+ if (err != OK) return err;
+
+ uint8_t version[] = {1, 3, 0, 0};
+ err = mEndianOut.write(version, 0, NELEMS(version));
+ if (err != OK) return err;
+
+ // Allow this opcode to be skipped if not supported
+ uint32_t flags = FLAG_OPTIONAL;
+
+ err = mEndianOut.write(&flags, 0, 1);
+ if (err != OK) return err;
+
+ const uint32_t NUMBER_CENTER_ARGS = 2;
+ const uint32_t NUMBER_COEFFS = numPlanes * 6;
+ uint32_t totalSize = (NUMBER_CENTER_ARGS + NUMBER_COEFFS) * sizeof(double) + sizeof(uint32_t);
+
+ err = mEndianOut.write(&totalSize, 0, 1);
+ if (err != OK) return err;
+
+ err = mEndianOut.write(&numPlanes, 0, 1);
+ if (err != OK) return err;
+
+ err = mEndianOut.write(kCoeffs, 0, NUMBER_COEFFS);
+ if (err != OK) return err;
+
+ err = mEndianOut.write(&opticalCenterX, 0, 1);
+ if (err != OK) return err;
+
+ err = mEndianOut.write(&opticalCenterY, 0, 1);
+ if (err != OK) return err;
+
+ mCount++;
+
+ return OK;
+}
+
} /*namespace img_utils*/
} /*namespace android*/
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
index 09137ef..7e89d7f 100644
--- a/media/libmedia/IMediaHTTPConnection.cpp
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -70,7 +70,7 @@ struct BpMediaHTTPConnection : public BpInterface<IMediaHTTPConnection> {
int32_t exceptionCode = reply.readExceptionCode();
if (exceptionCode) {
- return UNKNOWN_ERROR;
+ return false;
}
sp<IBinder> binder = reply.readStrongBinder();
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index ca33aed..e8d495b 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -70,12 +70,6 @@ static player_type getDefaultPlayerType() {
return STAGEFRIGHT_PLAYER;
}
- // TODO: remove this EXPERIMENTAL developer settings property
- if (property_get("persist.sys.media.use-awesome", value, NULL)
- && !strcasecmp("true", value)) {
- return STAGEFRIGHT_PLAYER;
- }
-
return NU_PLAYER;
}
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 9a37302..a5a1fa5 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -191,10 +191,13 @@ status_t MetadataRetrieverClient::setDataSource(
return ret;
}
+Mutex MetadataRetrieverClient::sLock;
+
sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
{
ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
Mutex::Autolock lock(mLock);
+ Mutex::Autolock glock(sLock);
mThumbnail.clear();
if (mRetriever == NULL) {
ALOGE("retriever is not initialized");
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index e71a29e..fe7547c 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -63,6 +63,7 @@ private:
virtual ~MetadataRetrieverClient();
mutable Mutex mLock;
+ static Mutex sLock;
sp<MediaMetadataRetrieverBase> mRetriever;
pid_t mPid;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 8760cbb..ef96a28 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1729,13 +1729,15 @@ status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) {
return renderer->getCurrentPosition(mediaUs);
}
-void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) {
- sp<DecoderBase> decoder = getDecoder(false /* audio */);
- if (decoder != NULL) {
- decoder->getStats(numFramesTotal, numFramesDropped);
- } else {
- *numFramesTotal = 0;
- *numFramesDropped = 0;
+void NuPlayer::getStats(Vector<sp<AMessage> > *mTrackStats) {
+ CHECK(mTrackStats != NULL);
+
+ mTrackStats->clear();
+ if (mVideoDecoder != NULL) {
+ mTrackStats->push_back(mVideoDecoder->getStats());
+ }
+ if (mAudioDecoder != NULL) {
+ mTrackStats->push_back(mAudioDecoder->getStats());
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index d7aa830..298ea6d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -77,7 +77,7 @@ struct NuPlayer : public AHandler {
status_t getSelectedTrack(int32_t type, Parcel* reply) const;
status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
status_t getCurrentPosition(int64_t *mediaUs);
- void getStats(int64_t *mNumFramesTotal, int64_t *mNumFramesDropped);
+ void getStats(Vector<sp<AMessage> > *mTrackStats);
sp<MetaData> getFileMeta();
float getFrameRate();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index c649c62..99a2a84 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -58,7 +58,10 @@ NuPlayer::Decoder::Decoder(
mCCDecoder(ccDecoder),
mSkipRenderingUntilMediaTimeUs(-1ll),
mNumFramesTotal(0ll),
- mNumFramesDropped(0ll),
+ mNumInputFramesDropped(0ll),
+ mNumOutputFramesDropped(0ll),
+ mVideoWidth(0),
+ mVideoHeight(0),
mIsAudio(true),
mIsVideoAVC(false),
mIsSecure(false),
@@ -77,11 +80,11 @@ NuPlayer::Decoder::~Decoder() {
releaseAndResetMediaBuffers();
}
-void NuPlayer::Decoder::getStats(
- int64_t *numFramesTotal,
- int64_t *numFramesDropped) const {
- *numFramesTotal = mNumFramesTotal;
- *numFramesDropped = mNumFramesDropped;
+sp<AMessage> NuPlayer::Decoder::getStats() const {
+ mStats->setInt64("frames-total", mNumFramesTotal);
+ mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
+ mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
+ return mStats;
}
void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
@@ -237,6 +240,18 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
+ mStats->setString("mime", mime.c_str());
+ mStats->setString("component-name", mComponentName.c_str());
+
+ if (!mIsAudio) {
+ int32_t width, height;
+ if (mOutputFormat->findInt32("width", &width)
+ && mOutputFormat->findInt32("height", &height)) {
+ mStats->setInt32("width", width);
+ mStats->setInt32("height", height);
+ }
+ }
+
sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
mCodec->setCallback(reply);
@@ -520,6 +535,8 @@ bool NuPlayer::Decoder::handleAnOutputBuffer(
mSkipRenderingUntilMediaTimeUs = -1;
}
+ mNumFramesTotal += !mIsAudio;
+
// wait until 1st frame comes out to signal resume complete
notifyResumeCompleteIfNecessary();
@@ -536,6 +553,12 @@ bool NuPlayer::Decoder::handleAnOutputBuffer(
void NuPlayer::Decoder::handleOutputFormatChange(const sp<AMessage> &format) {
if (!mIsAudio) {
+ int32_t width, height;
+ if (format->findInt32("width", &width)
+ && format->findInt32("height", &height)) {
+ mStats->setInt32("width", width);
+ mStats->setInt32("height", height);
+ }
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatVideoSizeChanged);
notify->setMessage("format", format);
@@ -654,10 +677,6 @@ status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
return ERROR_END_OF_STREAM;
}
- if (!mIsAudio) {
- ++mNumFramesTotal;
- }
-
dropAccessUnit = false;
if (!mIsAudio
&& !mIsSecure
@@ -665,7 +684,7 @@ status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
&& mIsVideoAVC
&& !IsAVCReferenceFrame(accessUnit)) {
dropAccessUnit = true;
- ++mNumFramesDropped;
+ ++mNumInputFramesDropped;
}
} while (dropAccessUnit);
@@ -833,6 +852,7 @@ void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
CHECK(msg->findInt64("timestampNs", &timestampNs));
err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);
} else {
+ mNumOutputFramesDropped += !mIsAudio;
err = mCodec->releaseOutputBuffer(bufferIx);
}
if (err != OK) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 070d51a..ceccb7a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -30,9 +30,7 @@ struct NuPlayer::Decoder : public DecoderBase {
const sp<Surface> &surface = NULL,
const sp<CCDecoder> &ccDecoder = NULL);
- virtual void getStats(
- int64_t *mNumFramesTotal,
- int64_t *mNumFramesDropped) const;
+ virtual sp<AMessage> getStats() const;
protected:
virtual ~Decoder();
@@ -77,7 +75,10 @@ private:
int64_t mSkipRenderingUntilMediaTimeUs;
int64_t mNumFramesTotal;
- int64_t mNumFramesDropped;
+ int64_t mNumInputFramesDropped;
+ int64_t mNumOutputFramesDropped;
+ int32_t mVideoWidth;
+ int32_t mVideoHeight;
bool mIsAudio;
bool mIsVideoAVC;
bool mIsSecure;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 9d509bf..7e76842 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -31,6 +31,7 @@ namespace android {
NuPlayer::DecoderBase::DecoderBase(const sp<AMessage> &notify)
: mNotify(notify),
mBufferGeneration(0),
+ mStats(new AMessage),
mRequestInputBuffersPending(false) {
// Every decoder has its own looper because MediaCodec operations
// are blocking, but NuPlayer needs asynchronous operations.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index b52e7f7..8f030f0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -42,9 +42,9 @@ struct NuPlayer::DecoderBase : public AHandler {
void signalResume(bool notifyComplete);
void initiateShutdown();
- virtual void getStats(
- int64_t *mNumFramesTotal,
- int64_t *mNumFramesDropped) const = 0;
+ virtual sp<AMessage> getStats() const {
+ return mStats;
+ }
enum {
kWhatInputDiscontinuity = 'inDi',
@@ -76,6 +76,7 @@ protected:
sp<AMessage> mNotify;
int32_t mBufferGeneration;
+ sp<AMessage> mStats;
private:
enum {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index d7b070e..30146c4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -59,12 +59,6 @@ NuPlayer::DecoderPassThrough::DecoderPassThrough(
NuPlayer::DecoderPassThrough::~DecoderPassThrough() {
}
-void NuPlayer::DecoderPassThrough::getStats(
- int64_t *numFramesTotal, int64_t *numFramesDropped) const {
- *numFramesTotal = 0;
- *numFramesDropped = 0;
-}
-
void NuPlayer::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
ALOGV("[%s] onConfigure", mComponentName.c_str());
mCachedBytes = 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index 2f6df2c..db33e87 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -29,10 +29,6 @@ struct NuPlayer::DecoderPassThrough : public DecoderBase {
const sp<Source> &source,
const sp<Renderer> &renderer);
- virtual void getStats(
- int64_t *mNumFramesTotal,
- int64_t *mNumFramesDropped) const;
-
protected:
virtual ~DecoderPassThrough();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 84ae25e..3882dcd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "NuPlayerDriver"
#include <inttypes.h>
#include <utils/Log.h>
+#include <cutils/properties.h>
#include "NuPlayerDriver.h"
@@ -241,7 +242,7 @@ status_t NuPlayerDriver::prepareAsync() {
}
status_t NuPlayerDriver::start() {
- ALOGD("start(%p)", this);
+ ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
Mutex::Autolock autoLock(mLock);
switch (mState) {
@@ -484,6 +485,13 @@ status_t NuPlayerDriver::reset() {
notifyListener_l(MEDIA_STOPPED);
}
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.debug.sf.stats", value, NULL) &&
+ (!strcmp("1", value) || !strcasecmp("true", value))) {
+ Vector<String16> args;
+ dump(-1, args);
+ }
+
mState = STATE_RESET_IN_PROGRESS;
mPlayer->resetAsync();
@@ -652,22 +660,59 @@ void NuPlayerDriver::notifySeekComplete_l() {
status_t NuPlayerDriver::dump(
int fd, const Vector<String16> & /* args */) const {
- int64_t numFramesTotal;
- int64_t numFramesDropped;
- mPlayer->getStats(&numFramesTotal, &numFramesDropped);
- FILE *out = fdopen(dup(fd), "w");
+ Vector<sp<AMessage> > trackStats;
+ mPlayer->getStats(&trackStats);
+
+ AString logString(" NuPlayer\n");
+ char buf[256] = {0};
+
+ for (size_t i = 0; i < trackStats.size(); ++i) {
+ const sp<AMessage> &stats = trackStats.itemAt(i);
+
+ AString mime;
+ if (stats->findString("mime", &mime)) {
+ snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str());
+ logString.append(buf);
+ }
+
+ AString name;
+ if (stats->findString("component-name", &name)) {
+ snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str());
+ logString.append(buf);
+ }
- fprintf(out, " NuPlayer\n");
- fprintf(out, " numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), "
- "percentageDropped(%.2f)\n",
- numFramesTotal,
- numFramesDropped,
- numFramesTotal == 0
- ? 0.0 : (double)numFramesDropped / numFramesTotal);
+ if (mime.startsWith("video/")) {
+ int32_t width, height;
+ if (stats->findInt32("width", &width)
+ && stats->findInt32("height", &height)) {
+ snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height);
+ logString.append(buf);
+ }
- fclose(out);
- out = NULL;
+ int64_t numFramesTotal = 0;
+ int64_t numFramesDropped = 0;
+
+ stats->findInt64("frames-total", &numFramesTotal);
+ stats->findInt64("frames-dropped-output", &numFramesDropped);
+ snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), "
+ "percentageDropped(%.2f%%)\n",
+ (long long)numFramesTotal,
+ (long long)numFramesDropped,
+ numFramesTotal == 0
+ ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
+ logString.append(buf);
+ }
+ }
+
+ ALOGI("%s", logString.c_str());
+
+ if (fd >= 0) {
+ FILE *out = fdopen(dup(fd), "w");
+ fprintf(out, "%s", logString.c_str());
+ fclose(out);
+ out = NULL;
+ }
return OK;
}
@@ -680,6 +725,7 @@ void NuPlayerDriver::notifyListener(
void NuPlayerDriver::notifyListener_l(
int msg, int ext1, int ext2, const Parcel *in) {
+ ALOGD("notifyListener_l(%p), (%d, %d, %d)", this, msg, ext1, ext2);
switch (msg) {
case MEDIA_PLAYBACK_COMPLETE:
{
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index fb2e767..7e55aac 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -771,6 +771,33 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
return sizeCopied;
}
+void NuPlayer::Renderer::drainAudioQueueUntilLastEOS() {
+ List<QueueEntry>::iterator it = mAudioQueue.begin(), itEOS = it;
+ bool foundEOS = false;
+ while (it != mAudioQueue.end()) {
+ int32_t eos;
+ QueueEntry *entry = &*it++;
+ if (entry->mBuffer == NULL
+ || (entry->mNotifyConsumed->findInt32("eos", &eos) && eos != 0)) {
+ itEOS = it;
+ foundEOS = true;
+ }
+ }
+
+ if (foundEOS) {
+ // post all replies before EOS and drop the samples
+ for (it = mAudioQueue.begin(); it != itEOS; it++) {
+ if (it->mBuffer == NULL) {
+ // delay doesn't matter as we don't even have an AudioTrack
+ notifyEOS(true /* audio */, it->mFinalResult);
+ } else {
+ it->mNotifyConsumed->post();
+ }
+ }
+ mAudioQueue.erase(mAudioQueue.begin(), itEOS);
+ }
+}
+
bool NuPlayer::Renderer::onDrainAudioQueue() {
// TODO: This call to getPosition checks if AudioTrack has been created
// in AudioSink before draining audio. If AudioTrack doesn't exist, then
@@ -784,6 +811,13 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
// "vorbis_dsp_synthesis returned -135", along with RTSP.
uint32_t numFramesPlayed;
if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
+ // When getPosition fails, renderer will not reschedule the draining
+ // unless new samples are queued.
+ // If we have pending EOS (or "eos" marker for discontinuities), we need
+ // to post these now as NuPlayerDecoder might be waiting for it.
+ drainAudioQueueUntilLastEOS();
+
+ ALOGW("onDrainAudioQueue(): audio sink is not ready");
return false;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index c2fea40..3e65649 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -208,6 +208,7 @@ private:
size_t fillAudioBuffer(void *buffer, size_t size);
bool onDrainAudioQueue();
+ void drainAudioQueueUntilLastEOS();
int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
void postDrainAudioQueue_l(int64_t delayUs = 0);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a57d4cf..527e9cd 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -110,6 +110,8 @@ static void InitOMXParams(T *params) {
struct MessageList : public RefBase {
MessageList() {
}
+ virtual ~MessageList() {
+ }
std::list<sp<AMessage> > &getList() { return mList; }
private:
std::list<sp<AMessage> > mList;
@@ -126,15 +128,19 @@ struct CodecObserver : public BnOMXObserver {
// from IOMXObserver
virtual void onMessages(const std::list<omx_message> &messages) {
- sp<AMessage> notify;
+ if (messages.empty()) {
+ return;
+ }
+
+ sp<AMessage> notify = mNotify->dup();
bool first = true;
sp<MessageList> msgList = new MessageList();
for (std::list<omx_message>::const_iterator it = messages.cbegin();
it != messages.cend(); ++it) {
const omx_message &omx_msg = *it;
if (first) {
- notify = mNotify->dup();
notify->setInt32("node", omx_msg.node);
+ first = false;
}
sp<AMessage> msg = new AMessage;
@@ -1390,7 +1396,8 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
status_t err = OK;
- for (size_t i = mBuffers[portIndex].size(); i-- > 0;) {
+ for (size_t i = mBuffers[portIndex].size(); i > 0;) {
+ i--;
status_t err2 = freeBuffer(portIndex, i);
if (err == OK) {
err = err2;
@@ -1404,7 +1411,8 @@ status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
status_t ACodec::freeOutputBuffersNotOwnedByComponent() {
status_t err = OK;
- for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
+ for (size_t i = mBuffers[kPortIndexOutput].size(); i > 0;) {
+ i--;
BufferInfo *info =
&mBuffers[kPortIndexOutput].editItemAt(i);
@@ -5196,16 +5204,11 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
int64_t timestampNs = 0;
if (!msg->findInt64("timestampNs", &timestampNs)) {
- // TODO: it seems like we should use the timestamp
- // in the (media)buffer as it potentially came from
- // an input surface, but we did not propagate it prior to
- // API 20. Perhaps check for target SDK version.
-#if 0
+ // use media timestamp if client did not request a specific render timestamp
if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
- ALOGV("using buffer PTS of %" PRId64, timestampNs);
+ ALOGV("using buffer PTS of %lld", (long long)timestampNs);
timestampNs *= 1000;
}
-#endif
}
status_t err;
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 41f0175..e17fdf8 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -109,9 +109,26 @@ ssize_t TinyCacheSource::readAt(off64_t offset, void* data, size_t size) {
}
// Check if the cache satisfies the read.
- if (offset >= mCachedOffset && offset + size <= mCachedOffset + mCachedSize) {
- memcpy(data, &mCache[offset - mCachedOffset], size);
- return size;
+ if (mCachedOffset <= offset
+ && offset < (off64_t) (mCachedOffset + mCachedSize)) {
+ if (offset + size <= mCachedOffset + mCachedSize) {
+ memcpy(data, &mCache[offset - mCachedOffset], size);
+ return size;
+ } else {
+ // If the cache hits only partially, flush the cache and read the
+ // remainder.
+
+ // This value is guaranteed to be greater than 0 because of the
+ // enclosing if statement.
+ const ssize_t remaining = mCachedOffset + mCachedSize - offset;
+ memcpy(data, &mCache[offset - mCachedOffset], remaining);
+ const ssize_t readMore = readAt(offset + remaining,
+ (uint8_t*)data + remaining, size - remaining);
+ if (readMore < 0) {
+ return readMore;
+ }
+ return remaining + readMore;
+ }
}
// Fill the cache and copy to the caller.
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 62612c7..8bf47b1 100644..100755
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1665,7 +1665,18 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return err;
}
}
-
+ if (mPath.size() >= 2
+ && mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'v')) {
+ // Check if the video is MPEG2
+ ESDS esds(&buffer[4], chunk_data_size - 4);
+
+ uint8_t objectTypeIndication;
+ if (esds.getObjectTypeIndication(&objectTypeIndication) == OK) {
+ if (objectTypeIndication >= 0x60 && objectTypeIndication <= 0x65) {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+ }
+ }
+ }
break;
}
@@ -2847,6 +2858,7 @@ status_t MPEG4Extractor::verifyTrack(Track *track) {
return ERROR_MALFORMED;
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
if (!track->meta->findData(kKeyESDS, &type, &data, &size)
|| type != kTypeESDS) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7ee84a8..e5b7202 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2452,18 +2452,12 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
int64_t renderTimeNs = 0;
- if (msg->findInt64("timestampNs", &renderTimeNs)) {
- info->mNotify->setInt64("timestampNs", renderTimeNs);
- } else {
- // TODO: it seems like we should use the timestamp
- // in the (media)buffer as it potentially came from
- // an input surface, but we did not propagate it prior to
- // API 20. Perhaps check for target SDK version.
-#if 0
- ALOGV("using buffer PTS of %" PRId64, timestampNs);
+ if (!msg->findInt64("timestampNs", &renderTimeNs)) {
+ // use media timestamp if client did not request a specific render timestamp
+ ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs);
renderTimeNs = mediaTimeUs * 1000;
-#endif
}
+ info->mNotify->setInt64("timestampNs", renderTimeNs);
if (mSoftRenderer != NULL) {
std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index d48ede9..a47bfc7 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -79,6 +79,8 @@ sp<IMediaCodecList> MediaCodecList::sCodecList;
// static
void *MediaCodecList::profilerThreadWrapper(void * /*arg*/) {
ALOGV("Enter profilerThreadWrapper.");
+ remove(kProfilingResults); // remove previous result so that it won't be loaded to
+ // the new MediaCodecList
MediaCodecList *codecList = new MediaCodecList();
if (codecList->initCheck() != OK) {
ALOGW("Failed to create a new MediaCodecList, skipping codec profiling.");
@@ -218,7 +220,8 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_er
}
}
- for (size_t i = mCodecInfos.size(); i-- > 0;) {
+ for (size_t i = mCodecInfos.size(); i > 0;) {
+ i--;
const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get();
if (info.mCaps.size() == 0) {
// No types supported by this component???
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e9566f2..7c554db 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,22 +20,35 @@
#include <inttypes.h>
#include <utils/Log.h>
+#include <gui/Surface.h>
#include "include/StagefrightMetadataRetriever.h"
+#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/Utils.h>
+
#include <CharacterEncodingDetector.h>
namespace android {
+static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
+static const size_t kRetryCount = 20; // must be >0
+
StagefrightMetadataRetriever::StagefrightMetadataRetriever()
: mParsedMetaData(false),
mAlbumArt(NULL) {
@@ -123,73 +136,52 @@ status_t StagefrightMetadataRetriever::setDataSource(
return OK;
}
-static bool isYUV420PlanarSupported(
- OMXClient *client,
- const sp<MetaData> &trackMeta) {
-
- const char *mime;
- CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
-
- Vector<CodecCapabilities> caps;
- if (QueryCodecs(client->interface(), mime,
- true, /* queryDecoders */
- true, /* hwCodecOnly */
- &caps) == OK) {
-
- for (size_t j = 0; j < caps.size(); ++j) {
- CodecCapabilities cap = caps[j];
- for (size_t i = 0; i < cap.mColorFormats.size(); ++i) {
- if (cap.mColorFormats[i] == OMX_COLOR_FormatYUV420Planar) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-static VideoFrame *extractVideoFrameWithCodecFlags(
- OMXClient *client,
+static VideoFrame *extractVideoFrame(
+ const char *componentName,
const sp<MetaData> &trackMeta,
const sp<MediaSource> &source,
- uint32_t flags,
int64_t frameTimeUs,
int seekMode) {
sp<MetaData> format = source->getFormat();
- // XXX:
- // Once all vendors support OMX_COLOR_FormatYUV420Planar, we can
- // remove this check and always set the decoder output color format
- if (isYUV420PlanarSupported(client, trackMeta)) {
- format->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
- }
+ sp<AMessage> videoFormat;
+ convertMetaDataToMessage(trackMeta, &videoFormat);
- sp<MediaSource> decoder =
- OMXCodec::Create(
- client->interface(), format, false, source,
- NULL, flags | OMXCodec::kClientNeedsFramebuffer);
+ // TODO: Use Flexible color instead
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
- if (decoder.get() == NULL) {
- ALOGV("unable to instantiate video decoder.");
+ status_t err;
+ sp<ALooper> looper = new ALooper;
+ looper->start();
+ sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
+ looper, componentName, &err);
+ if (decoder.get() == NULL || err != OK) {
+ ALOGW("Failed to instantiate decoder [%s]", componentName);
return NULL;
}
- status_t err = decoder->start();
+ err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
if (err != OK) {
- ALOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
+ ALOGW("configure returned error %d (%s)", err, asString(err));
+ decoder->release();
return NULL;
}
- // Read one output buffer, ignore format change notifications
- // and spurious empty buffers.
+ err = decoder->start();
+ if (err != OK) {
+ ALOGW("start returned error %d (%s)", err, asString(err));
+ decoder->release();
+ return NULL;
+ }
MediaSource::ReadOptions options;
if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
ALOGE("Unknown seek mode: %d", seekMode);
+ decoder->release();
return NULL;
}
@@ -208,64 +200,155 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
options.setSeekTo(frameTimeUs, mode);
}
- MediaBuffer *buffer = NULL;
- do {
- if (buffer != NULL) {
- buffer->release();
- buffer = NULL;
- }
- err = decoder->read(&buffer, &options);
- options.clearSeekTo();
- } while (err == INFO_FORMAT_CHANGED
- || (buffer != NULL && buffer->range_length() == 0));
-
+ err = source->start();
if (err != OK) {
- CHECK(buffer == NULL);
+ ALOGW("source failed to start: %d (%s)", err, asString(err));
+ decoder->release();
+ return NULL;
+ }
- ALOGV("decoding frame failed.");
- decoder->stop();
+ Vector<sp<ABuffer> > inputBuffers;
+ err = decoder->getInputBuffers(&inputBuffers);
+ if (err != OK) {
+ ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
+ decoder->release();
+ return NULL;
+ }
+ Vector<sp<ABuffer> > outputBuffers;
+ err = decoder->getOutputBuffers(&outputBuffers);
+ if (err != OK) {
+ ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
+ decoder->release();
return NULL;
}
- ALOGV("successfully decoded video frame.");
+ sp<AMessage> outputFormat = NULL;
+ bool haveMoreInputs = true;
+ size_t index, offset, size;
+ int64_t timeUs;
+ size_t retriesLeft = kRetryCount;
+ bool done = false;
- int32_t unreadable;
- if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
- && unreadable != 0) {
- ALOGV("video frame is unreadable, decoder does not give us access "
- "to the video data.");
+ do {
+ size_t inputIndex = -1;
+ int64_t ptsUs = 0ll;
+ uint32_t flags = 0;
+ sp<ABuffer> codecBuffer = NULL;
+
+ while (haveMoreInputs) {
+ err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
+ if (err != OK) {
+ ALOGW("Timed out waiting for input");
+ if (retriesLeft) {
+ err = OK;
+ }
+ break;
+ }
+ codecBuffer = inputBuffers[inputIndex];
- buffer->release();
- buffer = NULL;
+ MediaBuffer *mediaBuffer = NULL;
- decoder->stop();
+ err = source->read(&mediaBuffer, &options);
+ options.clearSeekTo();
+ if (err != OK) {
+ ALOGW("Input Error or EOS");
+ haveMoreInputs = false;
+ break;
+ }
+
+ if (mediaBuffer->range_length() > codecBuffer->capacity()) {
+ ALOGE("buffer size (%zu) too large for codec input size (%zu)",
+ mediaBuffer->range_length(), codecBuffer->capacity());
+ err = BAD_VALUE;
+ } else {
+ codecBuffer->setRange(0, mediaBuffer->range_length());
+
+ CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
+ memcpy(codecBuffer->data(),
+ (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
+ mediaBuffer->range_length());
+ }
+
+ mediaBuffer->release();
+ break;
+ }
+
+ if (err == OK && inputIndex < inputBuffers.size()) {
+ ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
+ codecBuffer->size(), ptsUs, flags);
+ err = decoder->queueInputBuffer(
+ inputIndex,
+ codecBuffer->offset(),
+ codecBuffer->size(),
+ ptsUs,
+ flags);
+
+ // we don't expect an output from codec config buffer
+ if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+ continue;
+ }
+ }
+
+ while (err == OK) {
+ // wait for a decoded buffer
+ err = decoder->dequeueOutputBuffer(
+ &index,
+ &offset,
+ &size,
+ &timeUs,
+ &flags,
+ kBufferTimeOutUs);
+
+ if (err == INFO_FORMAT_CHANGED) {
+ ALOGV("Received format change");
+ err = decoder->getOutputFormat(&outputFormat);
+ } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+ ALOGV("Output buffers changed");
+ err = decoder->getOutputBuffers(&outputBuffers);
+ } else {
+ if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
+ ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
+ err = OK;
+ } else if (err == OK) {
+ ALOGV("Received an output buffer");
+ done = true;
+ } else {
+ ALOGW("Received error %d (%s) instead of output", err, asString(err));
+ done = true;
+ }
+ break;
+ }
+ }
+ } while (err == OK && !done);
+ if (err != OK || size <= 0 || outputFormat == NULL) {
+ ALOGE("Failed to decode thumbnail frame");
+ source->stop();
+ decoder->stop();
+ decoder->release();
return NULL;
}
- int64_t timeUs;
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+ ALOGV("successfully decoded video frame.");
+ sp<ABuffer> videoFrameBuffer = outputBuffers.itemAt(index);
+
if (thumbNailTime >= 0) {
if (timeUs != thumbNailTime) {
- const char *mime;
- CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+ AString mime;
+ CHECK(outputFormat->findString("mime", &mime));
- ALOGV("thumbNailTime = %" PRId64 " us, timeUs = %" PRId64 " us, mime = %s",
- thumbNailTime, timeUs, mime);
+ ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
+ (long long)thumbNailTime, (long long)timeUs, mime.c_str());
}
}
- sp<MetaData> meta = decoder->getFormat();
-
int32_t width, height;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
+ CHECK(outputFormat->findInt32("width", &width));
+ CHECK(outputFormat->findInt32("height", &height));
int32_t crop_left, crop_top, crop_right, crop_bottom;
- if (!meta->findRect(
- kKeyCropRect,
- &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+ if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
crop_left = crop_top = 0;
crop_right = width - 1;
crop_bottom = height - 1;
@@ -285,23 +368,21 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
frame->mData = new uint8_t[frame->mSize];
frame->mRotationAngle = rotationAngle;
- int32_t displayWidth, displayHeight;
- if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
- frame->mDisplayWidth = displayWidth;
- }
- if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
- frame->mDisplayHeight = displayHeight;
+ int32_t sarWidth, sarHeight;
+ if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
+ && trackMeta->findInt32(kKeySARHeight, &sarHeight)
+ && sarHeight != 0) {
+ frame->mDisplayWidth = (frame->mDisplayWidth * sarWidth) / sarHeight;
}
int32_t srcFormat;
- CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
+ CHECK(outputFormat->findInt32("color-format", &srcFormat));
- ColorConverter converter(
- (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
+ ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
if (converter.isValid()) {
err = converter.convert(
- (const uint8_t *)buffer->data() + buffer->range_offset(),
+ (const uint8_t *)videoFrameBuffer->data(),
width, height,
crop_left, crop_top, crop_right, crop_bottom,
frame->mData,
@@ -309,17 +390,16 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
frame->mHeight,
0, 0, frame->mWidth - 1, frame->mHeight - 1);
} else {
- ALOGE("Unable to instantiate color conversion from format 0x%08x to "
- "RGB565",
- srcFormat);
+ ALOGE("Unable to convert from format 0x%08x to RGB565", srcFormat);
err = ERROR_UNSUPPORTED;
}
- buffer->release();
- buffer = NULL;
-
+ videoFrameBuffer.clear();
+ source->stop();
+ decoder->releaseOutputBuffer(index);
decoder->stop();
+ decoder->release();
if (err != OK) {
ALOGE("Colorconverter failed to convert frame.");
@@ -390,20 +470,29 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
}
- VideoFrame *frame =
- extractVideoFrameWithCodecFlags(
- &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
- timeUs, option);
-
- if (frame == NULL) {
- ALOGV("Software decoder failed to extract thumbnail, "
- "trying hardware decoder.");
+ const char *mime;
+ CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
- frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
- timeUs, option);
+ Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
+ OMXCodec::findMatchingCodecs(
+ mime,
+ false, /* encoder */
+ NULL, /* matchComponentName */
+ OMXCodec::kPreferSoftwareCodecs,
+ &matchingCodecs);
+
+ for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+ const char *componentName = matchingCodecs[i].mName.string();
+ VideoFrame *frame =
+ extractVideoFrame(componentName, trackMeta, source, timeUs, option);
+
+ if (frame != NULL) {
+ return frame;
+ }
+ ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName);
}
- return frame;
+ return NULL;
}
MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index 8ac337a..f3af777 100755
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -787,7 +787,7 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
}
if (s_dec_op.u4_output_present) {
- outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+ outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
mTimeStampsValid[s_dec_op.u4_ts] = false;
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index a35909e..e161fb8 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -146,8 +146,8 @@ bool SoftVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *por
}
outHeader->nOffset = 0;
- outHeader->nFilledLen = (width * height * 3) / 2;
outHeader->nFlags = 0;
+ outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
uint8_t *dst = outHeader->pBuffer;
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index 7ff9ee7..cb10bce 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -34,6 +34,12 @@ namespace android {
static const int kRate = 48000;
+// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
+// mappings for up to 8 channels. This information is part of the Vorbis I
+// Specification:
+// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
+static const int kMaxChannels = 8;
+
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
@@ -101,7 +107,7 @@ void SoftOpus::initPorts() {
def.eDir = OMX_DirOutput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
+ def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t) * kMaxChannels;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
@@ -225,12 +231,6 @@ static uint16_t ReadLE16(const uint8_t *data, size_t data_size,
return val;
}
-// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
-// mappings for up to 8 channels. This information is part of the Vorbis I
-// Specification:
-// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
-static const int kMaxChannels = 8;
-
// Maximum packet size used in Xiph's opusdec.
static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
diff --git a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
index 5f7c70d..b837f66 100644
--- a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
+++ b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
@@ -109,7 +109,8 @@ void AHierarchicalStateMachine::changeState(const sp<AState> &state) {
A.editItemAt(i)->stateExited();
}
- for (size_t i = B.size(); i-- > 0;) {
+ for (size_t i = B.size(); i > 0;) {
+ i--;
B.editItemAt(i)->stateEntered();
}
}
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 473ce1b..9ed53e7 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -79,7 +79,8 @@ void ALooperRoster::unregisterStaleHandlers() {
{
Mutex::Autolock autoLock(mLock);
- for (size_t i = mHandlers.size(); i-- > 0;) {
+ for (size_t i = mHandlers.size(); i > 0;) {
+ i--;
const HandlerInfo &info = mHandlers.valueAt(i);
sp<ALooper> looper = info.mLooper.promote();
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index db429f6..e3c3e80 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -694,7 +694,8 @@ status_t ATSParser::Stream::parse(
status_t err = flush(event);
if (err != OK) {
- return err;
+ ALOGW("Error (%08x) happened while flushing; we simply discard "
+ "the PES packet and continue.", err);
}
}
@@ -996,10 +997,6 @@ status_t ATSParser::Stream::parsePES(ABitReader *br, SyncEvent *event) {
return ERROR_MALFORMED;
}
- if (br->numBitsLeft() < dataLength * 8) {
- return ERROR_MALFORMED;
- }
-
onPayloadData(
PTS_DTS_flags, PTS, DTS, br->data(), dataLength, event);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 692667f..6ee1a77 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -1423,7 +1423,9 @@ void OMXNodeInstance::onMessages(std::list<omx_message> &messages) {
}
}
- mObserver->onMessages(messages);
+ if (!messages.empty()) {
+ mObserver->onMessages(messages);
+ }
}
void OMXNodeInstance::onObserverDied(OMXMaster *master) {
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 78dfbb1..b6de0d9 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -11,8 +11,7 @@ endif
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- main_mediaserver.cpp \
- icuutils.cpp
+ main_mediaserver.cpp
LOCAL_SHARED_LIBRARIES := \
libaudioflinger \
@@ -33,6 +32,7 @@ LOCAL_SHARED_LIBRARIES := \
libradioservice
LOCAL_STATIC_LIBRARIES := \
+ libicuandroid_utils \
libregistermsext
LOCAL_C_INCLUDES := \
diff --git a/media/mediaserver/IcuUtils.h b/media/mediaserver/IcuUtils.h
deleted file mode 100644
index 52fab6d..0000000
--- a/media/mediaserver/IcuUtils.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 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 ICU_UTILS_H
-#define ICU_UTILS_H
-
-// Initializes ICU or dies trying. This must be called when the process
-// is single threaded.
-void initializeIcuOrDie();
-
-#endif // ICU_UTILS_H
-
diff --git a/media/mediaserver/icuutils.cpp b/media/mediaserver/icuutils.cpp
deleted file mode 100644
index 4015849..0000000
--- a/media/mediaserver/icuutils.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#include "IcuUtils.h"
-
-#include "unicode/putil.h"
-#include "unicode/uclean.h"
-#include "unicode/utypes.h"
-#include "utils/Log.h"
-
-#include <stdlib.h>
-
-void initializeIcuOrDie() {
- const char* systemPathPrefix = getenv("ANDROID_ROOT");
- LOG_ALWAYS_FATAL_IF(systemPathPrefix == NULL, "ANDROID_ROOT environment variable not set");
-
- char buf[256];
- const int num_written = snprintf(buf, sizeof(buf), "%s/usr/icu/", systemPathPrefix);
- LOG_ALWAYS_FATAL_IF((num_written < 0 || static_cast<size_t>(num_written) >= sizeof(buf)),
- "Unable to construct ICU path.");
-
- u_setDataDirectory(buf);
- UErrorCode status = U_ZERO_ERROR;
-
- // u_setDataDirectory doesn't try doing anything with the directory we gave
- // it, so we'll have to call u_init to make sure it was successful.
- u_init(&status);
- LOG_ALWAYS_FATAL_IF(!U_SUCCESS(status), "Failed to initialize ICU %s", u_errorName(status));
-}
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 27a40b2..4a485ed 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -125,7 +125,7 @@ int main(int argc __unused, char** argv)
prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
setpgid(0, 0); // but if I die first, don't kill my parent
}
- initializeIcuOrDie();
+ InitializeIcuOrDie();
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ad445a5..489f2d4 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4459,6 +4459,17 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr
}
}
+void AudioFlinger::DirectOutputThread::onAddNewTrack_l()
+{
+ sp<Track> previousTrack = mPreviousTrack.promote();
+ sp<Track> latestTrack = mLatestActiveTrack.promote();
+
+ if (previousTrack != 0 && latestTrack != 0 &&
+ (previousTrack->sessionId() != latestTrack->sessionId())) {
+ mFlushPending = true;
+ }
+ PlaybackThread::onAddNewTrack_l();
+}
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prepareTracks_l(
Vector< sp<Track> > *tracksToRemove
@@ -4468,7 +4479,6 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
mixer_state mixerStatus = MIXER_IDLE;
bool doHwPause = false;
bool doHwResume = false;
- bool flushPending = false;
// find out which tracks need to be processed
for (size_t i = 0; i < count; i++) {
@@ -4478,6 +4488,12 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
continue;
}
+ if (t->isInvalid()) {
+ ALOGW("An invalidated track shouldn't be in active list");
+ tracksToRemove->add(t);
+ continue;
+ }
+
Track* const track = t.get();
audio_track_cblk_t* cblk = track->cblk();
// Only consider last track started for volume and mixer state control.
@@ -4497,7 +4513,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
} else if (track->isFlushPending()) {
track->flushAck();
if (last) {
- flushPending = true;
+ mFlushPending = true;
}
} else if (track->isResumePending()) {
track->resumeAck();
@@ -4538,6 +4554,21 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
// compute volume for this track
processVolume_l(track, last);
if (last) {
+ sp<Track> previousTrack = mPreviousTrack.promote();
+ if (previousTrack != 0) {
+ if (track != previousTrack.get()) {
+ // Flush any data still being written from last track
+ mBytesRemaining = 0;
+ // flush data already sent if changing audio session as audio
+ // comes from a different source. Also invalidate previous track to force a
+ // seek when resuming.
+ if (previousTrack->sessionId() != track->sessionId()) {
+ previousTrack->invalidate();
+ }
+ }
+ }
+ mPreviousTrack = track;
+
// reset retry count
track->mRetryCount = kMaxTrackRetriesDirect;
mActiveTrack = t;
@@ -4604,11 +4635,11 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
}
// if an active track did not command a flush, check for pending flush on stopped tracks
- if (!flushPending) {
+ if (!mFlushPending) {
for (size_t i = 0; i < mTracks.size(); i++) {
if (mTracks[i]->isFlushPending()) {
mTracks[i]->flushAck();
- flushPending = true;
+ mFlushPending = true;
}
}
}
@@ -4618,10 +4649,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
// before flush and then resume HW. This can happen in case of pause/flush/resume
// if resume is received before pause is executed.
if (mHwSupportsPause && !mStandby &&
- (doHwPause || (flushPending && !mHwPaused && (count != 0)))) {
+ (doHwPause || (mFlushPending && !mHwPaused && (count != 0)))) {
mOutput->stream->pause(mOutput->stream);
}
- if (flushPending) {
+ if (mFlushPending) {
flushHw_l();
}
if (mHwSupportsPause && !mStandby && doHwResume) {
@@ -4680,14 +4711,13 @@ void AudioFlinger::DirectOutputThread::threadLoop_exit()
{
{
Mutex::Autolock _l(mLock);
- bool flushPending = false;
for (size_t i = 0; i < mTracks.size(); i++) {
if (mTracks[i]->isFlushPending()) {
mTracks[i]->flushAck();
- flushPending = true;
+ mFlushPending = true;
}
}
- if (flushPending) {
+ if (mFlushPending) {
flushHw_l();
}
}
@@ -4825,6 +4855,7 @@ void AudioFlinger::DirectOutputThread::flushHw_l()
{
mOutput->flush();
mHwPaused = false;
+ mFlushPending = false;
}
// ----------------------------------------------------------------------------
@@ -5146,7 +5177,6 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
}
if (mFlushPending) {
flushHw_l();
- mFlushPending = false;
}
if (!mStandby && doHwResume) {
mOutput->stream->resume(mOutput->stream);
@@ -5194,18 +5224,6 @@ void AudioFlinger::OffloadThread::flushHw_l()
}
}
-void AudioFlinger::OffloadThread::onAddNewTrack_l()
-{
- sp<Track> previousTrack = mPreviousTrack.promote();
- sp<Track> latestTrack = mLatestActiveTrack.promote();
-
- if (previousTrack != 0 && latestTrack != 0 &&
- (previousTrack->sessionId() != latestTrack->sessionId())) {
- mFlushPending = true;
- }
- PlaybackThread::onAddNewTrack_l();
-}
-
// ----------------------------------------------------------------------------
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 7b4fb14..4ebe615 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -941,6 +941,8 @@ protected:
virtual void threadLoop_exit();
virtual bool shouldStandby_l();
+ virtual void onAddNewTrack_l();
+
// volumes last sent to audio HAL with stream->set_volume()
float mLeftVolFloat;
float mRightVolFloat;
@@ -952,6 +954,9 @@ protected:
// prepareTracks_l() tells threadLoop_mix() the name of the single active track
sp<Track> mActiveTrack;
+
+ wp<Track> mPreviousTrack; // used to detect track switch
+
public:
virtual bool hasFastMixer() const { return false; }
};
@@ -971,12 +976,10 @@ protected:
virtual bool waitingAsyncCallback();
virtual bool waitingAsyncCallback_l();
- virtual void onAddNewTrack_l();
private:
size_t mPausedWriteLength; // length in bytes of write interrupted by pause
size_t mPausedBytesRemaining; // bytes still waiting in mixbuffer after resume
- wp<Track> mPreviousTrack; // used to detect track switch
};
class AsyncCallbackThread : public Thread {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 1b03060..f7da209 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1951,7 +1951,9 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
type),
mOverflow(false),
- mFramesToDrop(0)
+ mFramesToDrop(0),
+ mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
+ mRecordBufferConverter(NULL)
{
if (mCblk == NULL) {
return;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bded309..deebc23 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -789,6 +789,11 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice(
// only allow deep buffering for music stream type
if (stream != AUDIO_STREAM_MUSIC) {
flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ } else if (/* stream == AUDIO_STREAM_MUSIC && */
+ flags == AUDIO_OUTPUT_FLAG_NONE &&
+ property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+ // use DEEP_BUFFER as default output for music stream type
+ flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
}
if (stream == AUDIO_STREAM_TTS) {
flags = AUDIO_OUTPUT_FLAG_TTS;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 3bda70c..0f485ca 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -27,8 +27,7 @@
namespace android {
-struct CameraDeviceClientBase :
- public CameraService::BasicClient, public BnCameraDeviceUser
+struct CameraDeviceClientBase : public CameraService::BasicClient, public BnCameraDeviceUser
{
typedef ICameraDeviceCallbacks TCamCallbacks;
@@ -167,7 +166,7 @@ private:
// Find the closest dimensions for a given format in available stream configurations with
// a width <= ROUNDING_WIDTH_CAP
- static const int32_t ROUNDING_WIDTH_CAP = 1080;
+ static const int32_t ROUNDING_WIDTH_CAP = 1920;
static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format,
android_dataspace dataSpace, const CameraMetadata& info,
/*out*/int32_t* outWidth, /*out*/int32_t* outHeight);