Squashed commit of the following:

commit 1efc38dc3c33fef57b759002db3965ed07a28cb0
Author: Andreas Huber <andih@google.com>
Date:   Thu Nov 19 14:36:14 2009 -0800

    Sending the SEEK-COMPLETE notification temporarily broke seeking backwards in time behaviour. This is now fixed.

    Also, get rid of the semi-random delay after posting buffers to surface flinger in favour of delaying the buffer release until the next frame is displayed.

commit 51973062eb5ee63fd64b845d72bac517cc3369cf
Author: Andreas Huber <andih@google.com>
Date:   Wed Nov 18 14:01:43 2009 -0800

    Fix one more unit test, properly send seek-complete notification only after seek actually completed.

commit cb22250b34b1fcfe1bf459723a761fd003950229
Author: Andreas Huber <andih@google.com>
Date:   Wed Nov 18 12:31:36 2009 -0800

    Fix seek-while-paused in AwesomePlayer, revert to using FileSource if MmapSource fails.

commit 25eb9241138ddf7bb27ce90657116c5f8a94d880
Author: Andreas Huber <andih@google.com>
Date:   Wed Nov 18 12:30:40 2009 -0800

    Support seeking and duration in AMRExtractor, assuming all frames are the same size.

commit 44192f2ebb7ea3bbd3ba5910025692dbc6a08faa
Author: Andreas Huber <andih@google.com>
Date:   Wed Nov 18 10:21:44 2009 -0800

    MediaPlayerImpl is dead, long live AwesomePlayer.

commit c5b52d3c0674f5dc94db506afbce52401cceddac
Author: Andreas Huber <andih@google.com>
Date:   Wed Nov 18 09:42:23 2009 -0800

    New implementation of the stagefright mediaplayer.
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
new file mode 100644
index 0000000..ed46cea
--- /dev/null
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2009 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 "AwesomePlayer"
+#include <utils/Log.h>
+
+#include "include/AwesomePlayer.h"
+
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXCodec.h>
+
+namespace android {
+
+struct AwesomeEvent : public TimedEventQueue::Event {
+    AwesomeEvent(AwesomePlayer *player, int32_t code)
+        : mPlayer(player),
+          mCode(code) {
+    }
+
+protected:
+    virtual ~AwesomeEvent() {}
+
+    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+        mPlayer->onEvent(mCode);
+    }
+
+private:
+    AwesomePlayer *mPlayer;
+    int32_t mCode;
+
+    AwesomeEvent(const AwesomeEvent &);
+    AwesomeEvent &operator=(const AwesomeEvent &);
+};
+
+AwesomePlayer::AwesomePlayer()
+    : mTimeSource(NULL),
+      mAudioPlayer(NULL),
+      mLastVideoBuffer(NULL),
+      mVideoBuffer(NULL) {
+    CHECK_EQ(mClient.connect(), OK);
+
+    DataSource::RegisterDefaultSniffers();
+
+    mVideoEvent = new AwesomeEvent(this, 0);
+    mVideoEventPending = false;
+    mStreamDoneEvent = new AwesomeEvent(this, 1);
+    mStreamDoneEventPending = false;
+
+    mQueue.start();
+
+    reset();
+}
+
+AwesomePlayer::~AwesomePlayer() {
+    mQueue.stop();
+
+    reset();
+
+    mClient.disconnect();
+}
+
+void AwesomePlayer::cancelPlayerEvents() {
+    mQueue.cancelEvent(mVideoEvent->eventID());
+    mVideoEventPending = false;
+    mQueue.cancelEvent(mStreamDoneEvent->eventID());
+    mStreamDoneEventPending = false;
+}
+
+void AwesomePlayer::setListener(const sp<MediaPlayerBase> &listener) {
+    Mutex::Autolock autoLock(mLock);
+    mListener = listener;
+}
+
+status_t AwesomePlayer::setDataSource(const char *uri) {
+    Mutex::Autolock autoLock(mLock);
+
+    reset_l();
+
+    sp<MediaExtractor> extractor = MediaExtractor::CreateFromURI(uri);
+
+    if (extractor == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    return setDataSource_l(extractor);
+}
+
+status_t AwesomePlayer::setDataSource(
+        int fd, int64_t offset, int64_t length) {
+    Mutex::Autolock autoLock(mLock);
+
+    reset_l();
+
+    sp<DataSource> source = new FileSource(fd, offset, length);
+
+    status_t err = source->initCheck();
+
+    if (err != OK) {
+        return err;
+    }
+
+    sp<MediaExtractor> extractor = MediaExtractor::Create(source);
+
+    if (extractor == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    return setDataSource_l(extractor);
+}
+
+status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
+    reset_l();
+
+    bool haveAudio = false;
+    bool haveVideo = false;
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+        if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
+            if (setVideoSource(extractor->getTrack(i)) == OK) {
+                haveVideo = true;
+            }
+        } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
+            if (setAudioSource(extractor->getTrack(i)) == OK) {
+                haveAudio = true;
+            }
+        }
+
+        if (haveAudio && haveVideo) {
+            break;
+        }
+    }
+
+    return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
+}
+
+void AwesomePlayer::reset() {
+    Mutex::Autolock autoLock(mLock);
+    reset_l();
+}
+
+void AwesomePlayer::reset_l() {
+    cancelPlayerEvents();
+
+    if (mLastVideoBuffer) {
+        mLastVideoBuffer->release();
+        mLastVideoBuffer = NULL;
+    }
+
+    if (mVideoBuffer) {
+        mVideoBuffer->release();
+        mVideoBuffer = NULL;
+    }
+
+    if (mVideoSource != NULL) {
+        mVideoSource->stop();
+        mVideoSource.clear();
+    }
+
+    mAudioSource.clear();
+
+    if (mTimeSource != mAudioPlayer) {
+        delete mTimeSource;
+    }
+    mTimeSource = NULL;
+
+    delete mAudioPlayer;
+    mAudioPlayer = NULL;
+
+    mVideoRenderer.clear();
+
+    mDurationUs = -1;
+    mFlags = 0;
+    mVideoWidth = mVideoHeight = -1;
+    mTimeSourceDeltaUs = 0;
+    mVideoTimeUs = 0;
+
+    mSeeking = false;
+    mSeekTimeUs = 0;
+}
+
+// static
+void AwesomePlayer::AudioNotify(void *_me, int what) {
+    AwesomePlayer *me = (AwesomePlayer *)_me;
+
+    Mutex::Autolock autoLock(me->mLock);
+
+    switch (what) {
+        case AudioPlayer::REACHED_EOS:
+            me->postStreamDoneEvent_l();
+            break;
+
+        case AudioPlayer::SEEK_COMPLETE:
+        {
+            if (me->mListener != NULL) {
+                me->mListener->sendEvent(MEDIA_SEEK_COMPLETE);
+            }
+
+            break;
+        }
+
+        default:
+            CHECK(!"should not be here.");
+            break;
+    }
+}
+
+void AwesomePlayer::onStreamDone() {
+    // Posted whenever any stream finishes playing.
+
+    Mutex::Autolock autoLock(mLock);
+    mStreamDoneEventPending = false;
+
+    if (mFlags & LOOPING) {
+        seekTo_l(0);
+
+        if (mVideoRenderer != NULL) {
+            postVideoEvent_l();
+        }
+    } else {
+        if (mListener != NULL) {
+            mListener->sendEvent(MEDIA_PLAYBACK_COMPLETE);
+        }
+
+        pause_l();
+    }
+}
+
+status_t AwesomePlayer::play() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFlags & PLAYING) {
+        return OK;
+    }
+
+    mFlags |= PLAYING;
+    mFlags |= FIRST_FRAME;
+
+    if (mAudioSource != NULL) {
+        if (mAudioPlayer == NULL) {
+            if (mAudioSink != NULL) {
+                mAudioPlayer = new AudioPlayer(mAudioSink);
+
+                mAudioPlayer->setListenerCallback(
+                        &AwesomePlayer::AudioNotify, this);
+
+                mAudioPlayer->setSource(mAudioSource);
+                mAudioPlayer->start();
+
+                delete mTimeSource;
+                mTimeSource = mAudioPlayer;
+
+                // If there was a seek request while we were paused
+                // and we're just starting up again, honor the request now.
+                seekAudioIfNecessary_l();
+            }
+        } else {
+            mAudioPlayer->resume();
+        }
+    }
+
+    if (mTimeSource == NULL && mAudioPlayer == NULL) {
+        mTimeSource = new SystemTimeSource;
+    }
+
+    if (mVideoSource != NULL) {
+        if (mVideoRenderer == NULL) {
+            initRenderer_l();
+        }
+
+        if (mVideoRenderer != NULL) {
+            // Kick off video playback
+            postVideoEvent_l();
+        }
+    }
+
+    return OK;
+}
+
+void AwesomePlayer::initRenderer_l() {
+    if (mISurface != NULL) {
+        sp<MetaData> meta = mVideoSource->getFormat();
+
+        int32_t format;
+        const char *component;
+        int32_t decodedWidth, decodedHeight;
+        CHECK(meta->findInt32(kKeyColorFormat, &format));
+        CHECK(meta->findCString(kKeyDecoderComponent, &component));
+        CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
+        CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
+
+        mVideoRenderer =
+            mClient.interface()->createRenderer(
+                    mISurface, component,
+                    (OMX_COLOR_FORMATTYPE)format,
+                    decodedWidth, decodedHeight,
+                    mVideoWidth, mVideoHeight);
+    }
+}
+
+status_t AwesomePlayer::pause() {
+    Mutex::Autolock autoLock(mLock);
+    return pause_l();
+}
+
+status_t AwesomePlayer::pause_l() {
+    if (!(mFlags & PLAYING)) {
+        return OK;
+    }
+
+    cancelPlayerEvents();
+
+    if (mAudioPlayer != NULL) {
+        mAudioPlayer->pause();
+    }
+
+    mFlags &= ~PLAYING;
+
+    return OK;
+}
+
+bool AwesomePlayer::isPlaying() const {
+    Mutex::Autolock autoLock(mLock);
+
+    return mFlags & PLAYING;
+}
+
+void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
+    Mutex::Autolock autoLock(mLock);
+
+    mISurface = isurface;
+}
+
+void AwesomePlayer::setAudioSink(
+        const sp<MediaPlayerBase::AudioSink> &audioSink) {
+    Mutex::Autolock autoLock(mLock);
+
+    mAudioSink = audioSink;
+}
+
+status_t AwesomePlayer::setLooping(bool shouldLoop) {
+    Mutex::Autolock autoLock(mLock);
+
+    mFlags = mFlags & ~LOOPING;
+
+    if (shouldLoop) {
+        mFlags |= LOOPING;
+    }
+
+    return OK;
+}
+
+status_t AwesomePlayer::getDuration(int64_t *durationUs) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mDurationUs < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    *durationUs = mDurationUs;
+
+    return OK;
+}
+
+status_t AwesomePlayer::getPosition(int64_t *positionUs) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mVideoRenderer != NULL) {
+        *positionUs = mVideoTimeUs;
+    } else if (mAudioPlayer != NULL) {
+        *positionUs = mAudioPlayer->getMediaTimeUs();
+    } else {
+        *positionUs = 0;
+    }
+
+    return OK;
+}
+
+status_t AwesomePlayer::seekTo(int64_t timeUs) {
+    Mutex::Autolock autoLock(mLock);
+    return seekTo_l(timeUs);
+}
+
+status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
+    mSeeking = true;
+    mSeekTimeUs = timeUs;
+
+    seekAudioIfNecessary_l();
+
+    return OK;
+}
+
+void AwesomePlayer::seekAudioIfNecessary_l() {
+    if (mSeeking && mVideoRenderer == NULL && mAudioPlayer != NULL) {
+        mAudioPlayer->seekTo(mSeekTimeUs);
+
+        mSeeking = false;
+    }
+}
+
+status_t AwesomePlayer::getVideoDimensions(
+        int32_t *width, int32_t *height) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mVideoWidth < 0 || mVideoHeight < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    *width = mVideoWidth;
+    *height = mVideoHeight;
+
+    return OK;
+}
+
+status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) {
+    if (source == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    mAudioSource = OMXCodec::Create(
+            mClient.interface(), source->getFormat(),
+            false, // createEncoder
+            source);
+
+    if (mAudioSource != NULL) {
+        int64_t durationUs;
+        if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+            if (mDurationUs < 0 || durationUs > mDurationUs) {
+                mDurationUs = durationUs;
+            }
+        }
+    }
+
+    return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
+}
+
+status_t AwesomePlayer::setVideoSource(const sp<MediaSource> &source) {
+    if (source == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    mVideoSource = OMXCodec::Create(
+            mClient.interface(), source->getFormat(),
+            false, // createEncoder
+            source);
+
+    if (mVideoSource != NULL) {
+        int64_t durationUs;
+        if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+            if (mDurationUs < 0 || durationUs > mDurationUs) {
+                mDurationUs = durationUs;
+            }
+        }
+
+        CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
+        CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
+
+        mVideoSource->start();
+    }
+
+    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
+}
+
+void AwesomePlayer::onEvent(int32_t code) {
+    if (code == 1) {
+        onStreamDone();
+        return;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+    mVideoEventPending = false;
+
+    if (mSeeking) {
+        if (mLastVideoBuffer) {
+            mLastVideoBuffer->release();
+            mLastVideoBuffer = NULL;
+        }
+
+        if (mVideoBuffer) {
+            mVideoBuffer->release();
+            mVideoBuffer = NULL;
+        }
+    }
+
+    if (!mVideoBuffer) {
+        MediaSource::ReadOptions options;
+        if (mSeeking) {
+            LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
+
+            options.setSeekTo(mSeekTimeUs);
+        }
+        for (;;) {
+            status_t err = mVideoSource->read(&mVideoBuffer, &options);
+
+            if (err != OK) {
+                CHECK_EQ(mVideoBuffer, NULL);
+
+                if (err == INFO_FORMAT_CHANGED) {
+                    LOGV("VideoSource signalled format change.");
+
+                    initRenderer_l();
+                    continue;
+                }
+
+                postStreamDoneEvent_l();
+                return;
+            }
+
+            break;
+        }
+    }
+
+    int64_t timeUs;
+    CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+
+    mVideoTimeUs = timeUs;
+
+    if (mSeeking) {
+        if (mAudioPlayer != NULL) {
+            LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
+
+            mAudioPlayer->seekTo(timeUs);
+        } else {
+            // If we're playing video only, report seek complete now,
+            // otherwise audio player will notify us later.
+            if (mListener != NULL) {
+                mListener->sendEvent(MEDIA_SEEK_COMPLETE);
+            }
+        }
+
+        mFlags |= FIRST_FRAME;
+        mSeeking = false;
+    }
+
+    if (mFlags & FIRST_FRAME) {
+        mFlags &= ~FIRST_FRAME;
+
+        mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs;
+    }
+
+    int64_t realTimeUs, mediaTimeUs;
+    if (mAudioPlayer != NULL
+        && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
+        mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
+    }
+
+    int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs;
+
+    int64_t latenessUs = nowUs - timeUs;
+
+    if (latenessUs > 20000) {
+        // We're more than 20ms late.
+        LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
+
+        mVideoBuffer->release();
+        mVideoBuffer = NULL;
+
+        postVideoEvent_l();
+        return;
+    }
+
+    if (latenessUs < -10000) {
+        // We're more than 10ms early.
+
+        postVideoEvent_l(10000);
+        return;
+    }
+
+    void *id;
+    if (mVideoBuffer->meta_data()->findPointer(kKeyBufferID, &id)) {
+        mVideoRenderer->render((IOMX::buffer_id)id);
+    }
+
+    if (mLastVideoBuffer) {
+        mLastVideoBuffer->release();
+        mLastVideoBuffer = NULL;
+    }
+    mLastVideoBuffer = mVideoBuffer;
+    mVideoBuffer = NULL;
+
+    postVideoEvent_l();
+}
+
+void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
+    if (mVideoEventPending) {
+        return;
+    }
+
+    mVideoEventPending = true;
+    mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void AwesomePlayer::postStreamDoneEvent_l() {
+    if (mStreamDoneEventPending) {
+        return;
+    }
+    mStreamDoneEventPending = true;
+    mQueue.postEvent(mStreamDoneEvent);
+}
+
+}  // namespace android
+