diff options
-rw-r--r-- | cmds/screenrecord/screenrecord.cpp | 61 | ||||
-rw-r--r-- | include/media/AudioRecord.h | 13 | ||||
-rw-r--r-- | include/media/AudioTrack.h | 26 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 17 | ||||
-rw-r--r-- | media/libstagefright/SurfaceMediaSource.cpp | 6 | ||||
-rw-r--r-- | media/libstagefright/omx/GraphicBufferSource.cpp | 7 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3IOStreamBase.h | 2 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3InputStream.cpp | 6 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3InputStream.h | 2 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3OutputStream.cpp | 11 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3OutputStream.h | 3 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3Stream.cpp | 18 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3Stream.h | 4 |
13 files changed, 125 insertions, 51 deletions
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp index 3e79ee0..28fc00f 100644 --- a/cmds/screenrecord/screenrecord.cpp +++ b/cmds/screenrecord/screenrecord.cpp @@ -44,8 +44,9 @@ using namespace android; // Command-line parameters. static bool gVerbose = false; // chatty on stdout static bool gRotate = false; // rotate 90 degrees -static uint32_t gVideoWidth = 1280; // 720p -static uint32_t gVideoHeight = 720; +static bool gSizeSpecified = false; // was size explicitly requested? +static uint32_t gVideoWidth = 0; // default width+height +static uint32_t gVideoHeight = 0; static uint32_t gBitRate = 4000000; // 4Mbps // Set by signal handler to stop recording. @@ -107,6 +108,14 @@ static status_t configureSignals() } /* + * Returns "true" if the device is rotated 90 degrees. + */ +static bool isDeviceRotated(int orientation) { + return orientation != DISPLAY_ORIENTATION_0 && + orientation != DISPLAY_ORIENTATION_180; +} + +/* * Configures and starts the MediaCodec encoder. Obtains an input surface * from the codec. */ @@ -114,6 +123,11 @@ static status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec, sp<IGraphicBufferProducer>* pBufferProducer) { status_t err; + if (gVerbose) { + printf("Configuring recorder for %dx%d video at %.2fMbps\n", + gVideoWidth, gVideoHeight, gBitRate / 1000000.0); + } + sp<AMessage> format = new AMessage; format->setInt32("width", gVideoWidth); format->setInt32("height", gVideoHeight); @@ -152,6 +166,7 @@ static status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec, return err; } + ALOGV("Codec prepared"); *pCodec = codec; *pBufferProducer = bufferProducer; return 0; @@ -169,8 +184,7 @@ static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo, // Set the region of the layer stack we're interested in, which in our // case is "all of it". If the app is rotated (so that the width of the // app is based on the height of the display), reverse width/height. - bool deviceRotated = mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 && - mainDpyInfo.orientation != DISPLAY_ORIENTATION_180; + bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation); uint32_t sourceWidth, sourceHeight; if (!deviceRotated) { sourceWidth = mainDpyInfo.w; @@ -295,6 +309,12 @@ static status_t runEncoder(const sp<MediaCodec>& encoder, bufIndex, size, ptsUsec); CHECK(trackIdx != -1); + // If the virtual display isn't providing us with timestamps, + // use the current time. + if (ptsUsec == 0) { + ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000; + } + // The MediaMuxer docs are unclear, but it appears that we // need to pass either the full set of BufferInfo flags, or // (flags & BUFFER_FLAG_SYNCFRAME). @@ -370,11 +390,6 @@ static status_t runEncoder(const sp<MediaCodec>& encoder, static status_t recordScreen(const char* fileName) { status_t err; - if (gVerbose) { - printf("Recording %dx%d video at %.2fMbps\n", - gVideoWidth, gVideoHeight, gBitRate / 1000000.0); - } - // Configure signal handler. err = configureSignals(); if (err != NO_ERROR) return err; @@ -399,11 +414,31 @@ static status_t recordScreen(const char* fileName) { mainDpyInfo.orientation); } + bool rotated = isDeviceRotated(mainDpyInfo.orientation); + if (gVideoWidth == 0) { + gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w; + } + if (gVideoHeight == 0) { + gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h; + } + // Configure and start the encoder. sp<MediaCodec> encoder; sp<IGraphicBufferProducer> bufferProducer; err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer); - if (err != NO_ERROR) return err; + if (err != NO_ERROR && !gSizeSpecified) { + ALOGV("Retrying with 720p"); + if (gVideoWidth != 1280 && gVideoHeight != 720) { + fprintf(stderr, "WARNING: failed at %dx%d, retrying at 720p\n", + gVideoWidth, gVideoHeight); + gVideoWidth = 1280; + gVideoHeight = 720; + err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer); + } + } + if (err != NO_ERROR) { + return err; + } // Configure virtual display. sp<IBinder> dpy; @@ -478,6 +513,8 @@ static void usage() { fprintf(stderr, "Usage: screenrecord [options] <filename>\n" "\n" + "Records the device's display to a .mp4 file.\n" + "\n" "Options:\n" "--size WIDTHxHEIGHT\n" " Set the video size, e.g. \"1280x720\". For best results, use\n" @@ -485,8 +522,7 @@ static void usage() { "--bit-rate RATE\n" " Set the video bit rate, in megabits per second. Default 4Mbps.\n" "--rotate\n" - " Rotate the output 90 degrees. Useful for filling the frame\n" - " when in portrait mode.\n" + " Rotate the output 90 degrees.\n" "--verbose\n" " Display interesting information on stdout.\n" "--help\n" @@ -536,6 +572,7 @@ int main(int argc, char* const argv[]) { gVideoWidth, gVideoHeight); return 2; } + gSizeSpecified = true; break; case 'b': gBitRate = atoi(optarg); diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index 7c240b4..8973c5c 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -35,8 +35,6 @@ class AudioRecord : public RefBase { public: - static const int DEFAULT_SAMPLE_RATE = 8000; - /* Events used by AudioRecord callback function (callback_t). * Keep in sync with frameworks/base/media/java/android/media/AudioRecord.java NATIVE_EVENT_*. */ @@ -62,6 +60,7 @@ public: size_t frameCount; // number of sample frames corresponding to size; // on input it is the number of frames available, // on output is the number of frames actually drained + // (currently ignored, but will make the primary field in future) size_t size; // input/output in bytes == frameCount * frameSize // FIXME this is redundant with respect to frameCount, @@ -366,7 +365,12 @@ public: * Input parameter 'size' is in byte units. * This is implemented on top of obtainBuffer/releaseBuffer. For best * performance use callbacks. Returns actual number of bytes read >= 0, - * or a negative status code. + * or one of the following negative status codes: + * INVALID_OPERATION AudioRecord is configured for streaming mode + * BAD_VALUE size is invalid + * WOULD_BLOCK when obtainBuffer() returns same, or + * AudioRecord was stopped during the read + * or any other error code returned by IAudioRecord::start() or restoreRecord_l(). */ ssize_t read(void* buffer, size_t size); @@ -441,7 +445,7 @@ private: // for client callback handler callback_t mCbf; // callback handler for events, or NULL - void* mUserData; // for client callback handler + void* mUserData; // for notification APIs uint32_t mNotificationFrames; // frames between each notification callback @@ -487,6 +491,7 @@ private: // multi-thread safe. // An exception is that a blocking ClientProxy::obtainBuffer() may be called without a lock, // provided that the caller also holds an extra reference to the proxy and shared memory to keep + // them around in case they are replaced during the obtainBuffer(). sp<AudioRecordClientProxy> mProxy; bool mInOverrun; // whether recorder is currently in overrun state diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 523bd32..ddb5842 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -116,6 +116,7 @@ public: * Returned status (from utils/Errors.h) can be: * - NO_ERROR: successful operation * - NO_INIT: audio server or audio hardware not initialized + * - BAD_VALUE: unsupported configuration */ static status_t getMinFrameCount(size_t* frameCount, @@ -170,9 +171,9 @@ public: */ AudioTrack( audio_stream_type_t streamType, - uint32_t sampleRate = 0, - audio_format_t format = AUDIO_FORMAT_DEFAULT, - audio_channel_mask_t channelMask = 0, + uint32_t sampleRate, + audio_format_t format, + audio_channel_mask_t, int frameCount = 0, audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, callback_t cbf = NULL, @@ -194,10 +195,10 @@ public: */ AudioTrack( audio_stream_type_t streamType, - uint32_t sampleRate = 0, - audio_format_t format = AUDIO_FORMAT_DEFAULT, - audio_channel_mask_t channelMask = 0, - const sp<IMemory>& sharedBuffer = 0, + uint32_t sampleRate, + audio_format_t format, + audio_channel_mask_t channelMask, + const sp<IMemory>& sharedBuffer, audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, callback_t cbf = NULL, void* user = NULL, @@ -227,10 +228,10 @@ public: * * threadCanCallJava: Whether callbacks are made from an attached thread and thus can call JNI. */ - status_t set(audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT, - uint32_t sampleRate = 0, - audio_format_t format = AUDIO_FORMAT_DEFAULT, - audio_channel_mask_t channelMask = 0, + status_t set(audio_stream_type_t streamType, + uint32_t sampleRate, + audio_format_t format, + audio_channel_mask_t channelMask, int frameCount = 0, audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, callback_t cbf = NULL, @@ -682,8 +683,9 @@ protected: STATE_STOPPING, } mState; + // for client callback handler callback_t mCbf; // callback handler for events, or NULL - void* mUserData; // for client callback handler + void* mUserData; // for notification APIs uint32_t mNotificationFramesReq; // requested number of frames between each diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index dfaac4c..bc5ce51 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -60,10 +60,9 @@ status_t AudioRecord::getMinFrameCount( // We double the size of input buffer for ping pong use of record buffer. size <<= 1; - if (audio_is_linear_pcm(format)) { - uint32_t channelCount = popcount(channelMask); - size /= channelCount * audio_bytes_per_sample(format); - } + // Assumes audio_is_linear_pcm(format) + uint32_t channelCount = popcount(channelMask); + size /= channelCount * audio_bytes_per_sample(format); *frameCount = size; return NO_ERROR; @@ -178,7 +177,8 @@ status_t AudioRecord::set( } if (sampleRate == 0) { - sampleRate = DEFAULT_SAMPLE_RATE; + ALOGE("Invalid sample rate %u", sampleRate); + return BAD_VALUE; } mSampleRate = sampleRate; @@ -207,11 +207,8 @@ status_t AudioRecord::set( uint32_t channelCount = popcount(channelMask); mChannelCount = channelCount; - if (audio_is_linear_pcm(format)) { - mFrameSize = channelCount * audio_bytes_per_sample(format); - } else { - mFrameSize = sizeof(uint8_t); - } + // Assumes audio_is_linear_pcm(format), else sizeof(uint8_t) + mFrameSize = channelCount * audio_bytes_per_sample(format); if (sessionId == 0 ) { mSessionId = AudioSystem::newAudioSessionId(); diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index befd4cc..b082c3a 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -65,10 +65,8 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig // reference once the ctor ends, as that would cause the refcount of 'this' // dropping to 0 at the end of the ctor. Since all we need is a wp<...> // that's what we create. - wp<BufferQueue::ConsumerListener> listener; - sp<BufferQueue::ConsumerListener> proxy; - listener = static_cast<BufferQueue::ConsumerListener*>(this); - proxy = new BufferQueue::ProxyConsumerListener(listener); + wp<BufferQueue::ConsumerListener> listener = static_cast<BufferQueue::ConsumerListener*>(this); + sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); status_t err = mBufferQueue->consumerConnect(proxy, false); if (err != NO_ERROR) { diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index d6fd95b..325ffcf 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -69,11 +69,8 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, // reference once the ctor ends, as that would cause the refcount of 'this' // dropping to 0 at the end of the ctor. Since all we need is a wp<...> // that's what we create. - wp<BufferQueue::ConsumerListener> listener; - listener = static_cast<BufferQueue::ConsumerListener*>(this); - - sp<BufferQueue::ConsumerListener> proxy; - proxy = new BufferQueue::ProxyConsumerListener(listener); + wp<BufferQueue::ConsumerListener> listener = static_cast<BufferQueue::ConsumerListener*>(this); + sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); mInitCheck = mBufferQueue->consumerConnect(proxy, false); if (mInitCheck != NO_ERROR) { diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h index 74c4484..9432a59 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h @@ -77,6 +77,8 @@ class Camera3IOStreamBase : virtual size_t getBufferCountLocked(); + virtual status_t getEndpointUsage(uint32_t *usage) = 0; + status_t getBufferPreconditionCheckLocked() const; status_t returnBufferPreconditionCheckLocked() const; diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp index e9a9c2b..1889a11 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp @@ -234,6 +234,12 @@ status_t Camera3InputStream::configureQueueLocked() { return OK; } +status_t Camera3InputStream::getEndpointUsage(uint32_t *usage) { + // Per HAL3 spec, input streams have 0 for their initial usage field. + *usage = 0; + return OK; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h index 8adda88..91d6f16 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.h +++ b/services/camera/libcameraservice/device3/Camera3InputStream.h @@ -79,6 +79,8 @@ class Camera3InputStream : public Camera3IOStreamBase { virtual status_t configureQueueLocked(); + virtual status_t getEndpointUsage(uint32_t *usage); + }; // class Camera3InputStream }; // namespace camera3 diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 0ec2b05..35cb5ba 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -364,6 +364,17 @@ status_t Camera3OutputStream::disconnectLocked() { return OK; } +status_t Camera3OutputStream::getEndpointUsage(uint32_t *usage) { + + status_t res; + int32_t u = 0; + res = mConsumer->query(mConsumer.get(), + NATIVE_WINDOW_CONSUMER_USAGE_BITS, &u); + *usage = u; + + return res; +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h index 774fbdd..6cbb9f4 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h @@ -92,6 +92,9 @@ class Camera3OutputStream : virtual status_t configureQueueLocked(); virtual status_t disconnectLocked(); + + virtual status_t getEndpointUsage(uint32_t *usage); + }; // class Camera3OutputStream } // namespace camera3 diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index ab563df..a6872aa 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -77,7 +77,9 @@ int Camera3Stream::getFormat() const { } camera3_stream* Camera3Stream::startConfiguration() { + ATRACE_CALL(); Mutex::Autolock l(mLock); + status_t res; switch (mState) { case STATE_ERROR: @@ -107,8 +109,15 @@ camera3_stream* Camera3Stream::startConfiguration() { return NULL; } - oldUsage = usage; - oldMaxBuffers = max_buffers; + oldUsage = camera3_stream::usage; + oldMaxBuffers = camera3_stream::max_buffers; + + res = getEndpointUsage(&(camera3_stream::usage)); + if (res != OK) { + ALOGE("%s: Cannot query consumer endpoint usage!", + __FUNCTION__); + return NULL; + } if (mState == STATE_CONSTRUCTED) { mState = STATE_IN_CONFIG; @@ -125,6 +134,7 @@ bool Camera3Stream::isConfiguring() const { } status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) { + ATRACE_CALL(); Mutex::Autolock l(mLock); switch (mState) { case STATE_ERROR: @@ -147,8 +157,8 @@ status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) { // Check if the stream configuration is unchanged, and skip reallocation if // so. As documented in hardware/camera3.h:configure_streams(). if (mState == STATE_IN_RECONFIG && - oldUsage == usage && - oldMaxBuffers == max_buffers) { + oldUsage == camera3_stream::usage && + oldMaxBuffers == camera3_stream::max_buffers) { mState = STATE_CONFIGURED; return OK; } diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index 69d81e4..b64fd86 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -263,6 +263,10 @@ class Camera3Stream : // Get the total number of buffers in the queue virtual size_t getBufferCountLocked() = 0; + // Get the usage flags for the other endpoint, or return + // INVALID_OPERATION if they cannot be obtained. + virtual status_t getEndpointUsage(uint32_t *usage) = 0; + private: uint32_t oldUsage; uint32_t oldMaxBuffers; |