diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/CamcorderProfile.java | 2 | ||||
-rw-r--r-- | media/java/android/media/MediaRecorder.java | 2 | ||||
-rw-r--r-- | media/libmedia/mediaplayer.cpp | 98 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 59 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 5 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 2 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 17 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerDriver.h | 2 | ||||
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 18 | ||||
-rwxr-xr-x | media/libstagefright/OMXCodec.cpp | 160 | ||||
-rw-r--r-- | media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp | 6 | ||||
-rw-r--r-- | media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp | 6 |
12 files changed, 263 insertions, 114 deletions
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java index 51a45cd..7d60c55 100644 --- a/media/java/android/media/CamcorderProfile.java +++ b/media/java/android/media/CamcorderProfile.java @@ -82,7 +82,6 @@ public class CamcorderProfile /** * Quality level corresponding to the QVGA (320x240) resolution. - * {@hide} */ public static final int QUALITY_QVGA = 7; @@ -127,7 +126,6 @@ public class CamcorderProfile /** * Time lapse quality level corresponding to the QVGA (320 x 240) resolution. - * {@hide} */ public static final int QUALITY_TIME_LAPSE_QVGA = 1007; diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 8f5d0e5..2a11d19 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -299,7 +299,7 @@ public class MediaRecorder setVideoEncodingBitRate(profile.videoBitRate); setVideoEncoder(profile.videoCodec); if (profile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW && - profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_1080P) { + profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_QVGA) { // Enable time lapse. Also don't set audio for time lapse. setParameter(String.format("time-lapse-enable=1")); } else { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 37a82e9..f72300b 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -86,8 +86,6 @@ void MediaPlayer::disconnect() if (p != 0) { p->disconnect(); } - - disconnectNativeWindow(); } // always call with lock held @@ -221,63 +219,12 @@ status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *m return mPlayer->getMetadata(update_only, apply_filter, metadata); } -void MediaPlayer::disconnectNativeWindow() { - if (mConnectedWindow != NULL) { - status_t err = native_window_api_disconnect(mConnectedWindow.get(), - NATIVE_WINDOW_API_MEDIA); - - if (err != OK) { - LOGW("native_window_api_disconnect returned an error: %s (%d)", - strerror(-err), err); - } - } - mConnectedWindow.clear(); -} - status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface) { LOGV("setVideoSurface"); Mutex::Autolock _l(mLock); if (mPlayer == 0) return NO_INIT; - - sp<IBinder> binder(surface == NULL ? NULL : surface->asBinder()); - if (mConnectedWindowBinder == binder) { - return OK; - } - - if (surface != NULL) { - status_t err = native_window_api_connect(surface.get(), - NATIVE_WINDOW_API_MEDIA); - - if (err != OK) { - LOGE("setVideoSurface failed: %d", err); - // Note that we must do the reset before disconnecting from the ANW. - // Otherwise queue/dequeue calls could be made on the disconnected - // ANW, which may result in errors. - reset_l(); - - disconnectNativeWindow(); - - return err; - } - } - - // Note that we must set the player's new surface before disconnecting the - // old one. Otherwise queue/dequeue calls could be made on the disconnected - // ANW, which may result in errors. - status_t err = mPlayer->setVideoSurface(surface); - - disconnectNativeWindow(); - - mConnectedWindow = surface; - - if (err == OK) { - mConnectedWindowBinder = binder; - } else { - disconnectNativeWindow(); - } - - return err; + return mPlayer->setVideoSurface(surface); } status_t MediaPlayer::setVideoSurfaceTexture( @@ -286,48 +233,7 @@ status_t MediaPlayer::setVideoSurfaceTexture( LOGV("setVideoSurfaceTexture"); Mutex::Autolock _l(mLock); if (mPlayer == 0) return NO_INIT; - - sp<IBinder> binder(surfaceTexture == NULL ? NULL : - surfaceTexture->asBinder()); - if (mConnectedWindowBinder == binder) { - return OK; - } - - sp<ANativeWindow> anw; - if (surfaceTexture != NULL) { - anw = new SurfaceTextureClient(surfaceTexture); - status_t err = native_window_api_connect(anw.get(), - NATIVE_WINDOW_API_MEDIA); - - if (err != OK) { - LOGE("setVideoSurfaceTexture failed: %d", err); - // Note that we must do the reset before disconnecting from the ANW. - // Otherwise queue/dequeue calls could be made on the disconnected - // ANW, which may result in errors. - reset_l(); - - disconnectNativeWindow(); - - return err; - } - } - - // Note that we must set the player's new SurfaceTexture before - // disconnecting the old one. Otherwise queue/dequeue calls could be made - // on the disconnected ANW, which may result in errors. - status_t err = mPlayer->setVideoSurfaceTexture(surfaceTexture); - - disconnectNativeWindow(); - - mConnectedWindow = anw; - - if (err == OK) { - mConnectedWindowBinder = binder; - } else { - disconnectNativeWindow(); - } - - return err; + return mPlayer->setVideoSurfaceTexture(surfaceTexture); } // must call with lock held diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 2ea2af9..b655358 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -40,6 +40,7 @@ #include <binder/IServiceManager.h> #include <binder/MemoryHeapBase.h> #include <binder/MemoryBase.h> +#include <gui/SurfaceTextureClient.h> #include <utils/Errors.h> // for status_t #include <utils/String8.h> #include <utils/SystemClock.h> @@ -528,6 +529,8 @@ void MediaPlayerService::Client::disconnect() p->reset(); } + disconnectNativeWindow(); + IPCThreadState::self()->flushCommands(); } @@ -793,13 +796,67 @@ status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface) return p->setVideoSurface(surface); } +void MediaPlayerService::Client::disconnectNativeWindow() { + if (mConnectedWindow != NULL) { + status_t err = native_window_api_disconnect(mConnectedWindow.get(), + NATIVE_WINDOW_API_MEDIA); + + if (err != OK) { + LOGW("native_window_api_disconnect returned an error: %s (%d)", + strerror(-err), err); + } + } + mConnectedWindow.clear(); +} + status_t MediaPlayerService::Client::setVideoSurfaceTexture( const sp<ISurfaceTexture>& surfaceTexture) { LOGV("[%d] setVideoSurfaceTexture(%p)", mConnId, surfaceTexture.get()); sp<MediaPlayerBase> p = getPlayer(); if (p == 0) return UNKNOWN_ERROR; - return p->setVideoSurfaceTexture(surfaceTexture); + + sp<IBinder> binder(surfaceTexture == NULL ? NULL : + surfaceTexture->asBinder()); + if (mConnectedWindowBinder == binder) { + return OK; + } + + sp<ANativeWindow> anw; + if (surfaceTexture != NULL) { + anw = new SurfaceTextureClient(surfaceTexture); + status_t err = native_window_api_connect(anw.get(), + NATIVE_WINDOW_API_MEDIA); + + if (err != OK) { + LOGE("setVideoSurfaceTexture failed: %d", err); + // Note that we must do the reset before disconnecting from the ANW. + // Otherwise queue/dequeue calls could be made on the disconnected + // ANW, which may result in errors. + reset(); + + disconnectNativeWindow(); + + return err; + } + } + + // Note that we must set the player's new SurfaceTexture before + // disconnecting the old one. Otherwise queue/dequeue calls could be made + // on the disconnected ANW, which may result in errors. + status_t err = p->setVideoSurfaceTexture(surfaceTexture); + + disconnectNativeWindow(); + + mConnectedWindow = anw; + + if (err == OK) { + mConnectedWindowBinder = binder; + } else { + disconnectNativeWindow(); + } + + return err; } status_t MediaPlayerService::Client::invoke(const Parcel& request, diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 53e625a..62214ba 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -318,6 +318,9 @@ private: // @param type Of the metadata to be recorded. void addNewMetadataUpdate(media::Metadata::Type type); + // Disconnect from the currently connected ANativeWindow. + void disconnectNativeWindow(); + mutable Mutex mLock; sp<MediaPlayerBase> mPlayer; sp<MediaPlayerService> mService; @@ -329,6 +332,8 @@ private: int32_t mConnId; int mAudioSessionId; uid_t mUID; + sp<ANativeWindow> mConnectedWindow; + sp<IBinder> mConnectedWindowBinder; // Metadata filters. media::Metadata::Filter mMetadataAllow; // protected by mLock diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 4c710b4..7cdb76c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -796,7 +796,7 @@ void NuPlayer::notifyListener(int msg, int ext1, int ext2) { return; } - driver->sendEvent(msg, ext1, ext2); + driver->notifyListener(msg, ext1, ext2); } void NuPlayer::flushDecoder(bool audio, bool needShutdown) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index b1e917d..452ba99 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -35,6 +35,7 @@ NuPlayerDriver::NuPlayerDriver() mNumFramesDropped(0), mLooper(new ALooper), mState(UNINITIALIZED), + mAtEOS(false), mStartupSeekTimeUs(-1) { mLooper->setName("NuPlayerDriver Looper"); @@ -106,7 +107,7 @@ status_t NuPlayerDriver::prepare() { } status_t NuPlayerDriver::prepareAsync() { - sendEvent(MEDIA_PREPARED); + notifyListener(MEDIA_PREPARED); return OK; } @@ -117,6 +118,7 @@ status_t NuPlayerDriver::start() { return INVALID_OPERATION; case STOPPED: { + mAtEOS = false; mPlayer->start(); if (mStartupSeekTimeUs >= 0) { @@ -173,7 +175,7 @@ status_t NuPlayerDriver::pause() { } bool NuPlayerDriver::isPlaying() { - return mState == PLAYING; + return mState == PLAYING && !mAtEOS; } status_t NuPlayerDriver::seekTo(int msec) { @@ -190,6 +192,7 @@ status_t NuPlayerDriver::seekTo(int msec) { case PLAYING: case PAUSED: { + mAtEOS = false; mPlayer->seekToAsync(seekTimeUs); break; } @@ -291,7 +294,7 @@ void NuPlayerDriver::notifyPosition(int64_t positionUs) { } void NuPlayerDriver::notifySeekComplete() { - sendEvent(MEDIA_SEEK_COMPLETE); + notifyListener(MEDIA_SEEK_COMPLETE); } void NuPlayerDriver::notifyFrameStats( @@ -320,4 +323,12 @@ status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const { return OK; } +void NuPlayerDriver::notifyListener(int msg, int ext1, int ext2) { + if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) { + mAtEOS = true; + } + + sendEvent(msg, ext1, ext2); +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 181c37d..aaa3de0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -67,6 +67,7 @@ struct NuPlayerDriver : public MediaPlayerInterface { void notifyPosition(int64_t positionUs); void notifySeekComplete(); void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped); + void notifyListener(int msg, int ext1 = 0, int ext2 = 0); protected: virtual ~NuPlayerDriver(); @@ -95,6 +96,7 @@ private: }; State mState; + bool mAtEOS; int64_t mStartupSeekTimeUs; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 1c7e58d..f37e75b 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -385,10 +385,12 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { for (size_t i = 0; i < extractor->countTracks(); ++i) { sp<MetaData> meta = extractor->getTrackMetaData(i); - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); + const char *_mime; + CHECK(meta->findCString(kKeyMIMEType, &_mime)); - if (!haveVideo && !strncasecmp(mime, "video/", 6)) { + String8 mime = String8(_mime); + + if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) { setVideoSource(extractor->getTrack(i)); haveVideo = true; @@ -409,9 +411,9 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { mStats.mTracks.push(); TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); - stat->mMIME = mime; + stat->mMIME = mime.string(); } - } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { + } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) { setAudioSource(extractor->getTrack(i)); haveAudio = true; @@ -421,10 +423,10 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { mStats.mTracks.push(); TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); - stat->mMIME = mime; + stat->mMIME = mime.string(); } - if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { + if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) { // Only do this for vorbis audio, none of the other audio // formats even support this ringtone specific hack and // retrieving the metadata on some extractors may turn out @@ -436,7 +438,7 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { modifyFlags(AUTO_LOOPING, SET); } } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { + } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { addTextSource(extractor->getTrack(i)); } } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 7e55790..dfd3f4a 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -2010,6 +2010,157 @@ OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() { 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) { + LOGE("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) { + LOGE("error pushing blank frames: api_connect failed: %s (%d)", + strerror(-err), -err); + return err; + } + + err = native_window_set_scaling_mode(mNativeWindow.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + if (err != NO_ERROR) { + LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + err = native_window_set_buffers_geometry(mNativeWindow.get(), 1, 1, + HAL_PIXEL_FORMAT_RGBX_8888); + if (err != NO_ERROR) { + LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + err = native_window_set_usage(mNativeWindow.get(), + GRALLOC_USAGE_SW_WRITE_OFTEN); + if (err != NO_ERROR) { + LOGE("error pushing blank frames: set_usage failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + err = mNativeWindow->query(mNativeWindow.get(), + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); + if (err != NO_ERROR) { + LOGE("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) { + LOGE("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 = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb); + if (err != NO_ERROR) { + LOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + err = mNativeWindow->lockBuffer(mNativeWindow.get(), + buf->getNativeBuffer()); + if (err != NO_ERROR) { + LOGE("error pushing blank frames: lockBuffer failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + // 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) { + LOGE("error pushing blank frames: lock failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + *img = 0; + + err = buf->unlock(); + if (err != NO_ERROR) { + LOGE("error pushing blank frames: unlock failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + err = mNativeWindow->queueBuffer(mNativeWindow.get(), + buf->getNativeBuffer()); + if (err != NO_ERROR) { + LOGE("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); + } + + 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) { + LOGE("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) { + LOGE("error pushing blank frames: api_connect failed: %s (%d)", + strerror(-err), -err); + return err; + } + + return NO_ERROR; + } +} + int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) { CHECK(mIsEncoder); @@ -2598,6 +2749,15 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) { mPortStatus[kPortIndexInput] = ENABLED; mPortStatus[kPortIndexOutput] = ENABLED; + if ((mFlags & kEnableGrallocUsageProtected) && + mNativeWindow != NULL) { + // We push enough 1x1 blank buffers to ensure that one of + // 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(); + } + setState(IDLE_TO_LOADED); } break; diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp index 94a79ab..d361ef4 100644 --- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp +++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp @@ -82,7 +82,11 @@ status_t AMRNBEncoder::start(MetaData *params) { &mEncState, &mSidState, false /* dtx_enable */), 0); - mSource->start(params); + status_t err = mSource->start(params); + if (err != OK) { + LOGE("AudioSource is not available"); + return err; + } mAnchorTimeUs = 0; mNumFramesOutput = 0; diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp index 002f055..5eacc16 100644 --- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp +++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp @@ -137,8 +137,12 @@ status_t AMRWBEncoder::start(MetaData *params) { CHECK_EQ(OK, initCheck()); mNumFramesOutput = 0; - mSource->start(params); + status_t err = mSource->start(params); + if (err != OK) { + LOGE("AudioSource is not available"); + return err; + } mStarted = true; return OK; |