1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/GonkRecorder.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1630 @@ 1.4 +/* 1.5 + * Copyright (C) 2009 The Android Open Source Project 1.6 + * Copyright (C) 2013 Mozilla Foundation 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 + 1.21 +#include "nsDebug.h" 1.22 +#define DOM_CAMERA_LOG_LEVEL 3 1.23 +#include "CameraCommon.h" 1.24 +#include "GonkCameraSource.h" 1.25 +#include "GonkRecorder.h" 1.26 + 1.27 +#define RE_LOGD(fmt, ...) DOM_CAMERA_LOGA("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.28 +#define RE_LOGV(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.29 +#define RE_LOGI(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.30 +#define RE_LOGW(fmt, ...) DOM_CAMERA_LOGW("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.31 +#define RE_LOGE(fmt, ...) DOM_CAMERA_LOGE("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.32 + 1.33 +#include <binder/IPCThreadState.h> 1.34 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.35 +# include <media/openmax/OMX_Audio.h> 1.36 +#endif 1.37 +#include <media/stagefright/foundation/ADebug.h> 1.38 +#include <media/stagefright/AudioSource.h> 1.39 +#include <media/stagefright/AMRWriter.h> 1.40 +#include <media/stagefright/AACWriter.h> 1.41 +#include <media/stagefright/MPEG2TSWriter.h> 1.42 +#include <media/stagefright/MPEG4Writer.h> 1.43 +#include <media/stagefright/MediaDefs.h> 1.44 +#include <media/stagefright/MetaData.h> 1.45 +#include <media/stagefright/OMXClient.h> 1.46 +#include <media/stagefright/OMXCodec.h> 1.47 +#include <media/MediaProfiles.h> 1.48 + 1.49 +#include <utils/Errors.h> 1.50 +#include <sys/types.h> 1.51 +#include <ctype.h> 1.52 +#include <unistd.h> 1.53 + 1.54 +#include <cutils/properties.h> 1.55 +#include <system/audio.h> 1.56 + 1.57 +#define RES_720P (720 * 1280) 1.58 +namespace android { 1.59 + 1.60 +GonkRecorder::GonkRecorder() 1.61 + : mWriter(NULL), 1.62 + mOutputFd(-1), 1.63 + mAudioSource(AUDIO_SOURCE_CNT), 1.64 + mVideoSource(VIDEO_SOURCE_LIST_END), 1.65 + mStarted(false) { 1.66 + 1.67 + RE_LOGV("Constructor"); 1.68 + reset(); 1.69 +} 1.70 + 1.71 +GonkRecorder::~GonkRecorder() { 1.72 + RE_LOGV("Destructor"); 1.73 + stop(); 1.74 +} 1.75 + 1.76 +status_t GonkRecorder::init() { 1.77 + RE_LOGV("init"); 1.78 + return OK; 1.79 +} 1.80 + 1.81 +status_t GonkRecorder::setAudioSource(audio_source_t as) { 1.82 + RE_LOGV("setAudioSource: %d", as); 1.83 + if (as < AUDIO_SOURCE_DEFAULT || 1.84 + as >= AUDIO_SOURCE_CNT) { 1.85 + RE_LOGE("Invalid audio source: %d", as); 1.86 + return BAD_VALUE; 1.87 + } 1.88 + 1.89 + if (as == AUDIO_SOURCE_DEFAULT) { 1.90 + mAudioSource = AUDIO_SOURCE_MIC; 1.91 + } else { 1.92 + mAudioSource = as; 1.93 + } 1.94 + 1.95 + return OK; 1.96 +} 1.97 + 1.98 +status_t GonkRecorder::setVideoSource(video_source vs) { 1.99 + RE_LOGV("setVideoSource: %d", vs); 1.100 + if (vs < VIDEO_SOURCE_DEFAULT || 1.101 + vs >= VIDEO_SOURCE_LIST_END) { 1.102 + RE_LOGE("Invalid video source: %d", vs); 1.103 + return BAD_VALUE; 1.104 + } 1.105 + 1.106 + if (vs == VIDEO_SOURCE_DEFAULT) { 1.107 + mVideoSource = VIDEO_SOURCE_CAMERA; 1.108 + } else { 1.109 + mVideoSource = vs; 1.110 + } 1.111 + 1.112 + return OK; 1.113 +} 1.114 + 1.115 +status_t GonkRecorder::setOutputFormat(output_format of) { 1.116 + RE_LOGV("setOutputFormat: %d", of); 1.117 + if (of < OUTPUT_FORMAT_DEFAULT || 1.118 + of >= OUTPUT_FORMAT_LIST_END) { 1.119 + RE_LOGE("Invalid output format: %d", of); 1.120 + return BAD_VALUE; 1.121 + } 1.122 + 1.123 + if (of == OUTPUT_FORMAT_DEFAULT) { 1.124 + mOutputFormat = OUTPUT_FORMAT_THREE_GPP; 1.125 + } else { 1.126 + mOutputFormat = of; 1.127 + } 1.128 + 1.129 + return OK; 1.130 +} 1.131 + 1.132 +status_t GonkRecorder::setAudioEncoder(audio_encoder ae) { 1.133 + RE_LOGV("setAudioEncoder: %d", ae); 1.134 + if (ae < AUDIO_ENCODER_DEFAULT || 1.135 + ae >= AUDIO_ENCODER_LIST_END) { 1.136 + RE_LOGE("Invalid audio encoder: %d", ae); 1.137 + return BAD_VALUE; 1.138 + } 1.139 + 1.140 + if (ae == AUDIO_ENCODER_DEFAULT) { 1.141 + mAudioEncoder = AUDIO_ENCODER_AMR_NB; 1.142 + } else { 1.143 + mAudioEncoder = ae; 1.144 + } 1.145 + 1.146 + return OK; 1.147 +} 1.148 + 1.149 +status_t GonkRecorder::setVideoEncoder(video_encoder ve) { 1.150 + RE_LOGV("setVideoEncoder: %d", ve); 1.151 + if (ve < VIDEO_ENCODER_DEFAULT || 1.152 + ve >= VIDEO_ENCODER_LIST_END) { 1.153 + RE_LOGE("Invalid video encoder: %d", ve); 1.154 + return BAD_VALUE; 1.155 + } 1.156 + 1.157 + if (ve == VIDEO_ENCODER_DEFAULT) { 1.158 + mVideoEncoder = VIDEO_ENCODER_H263; 1.159 + } else { 1.160 + mVideoEncoder = ve; 1.161 + } 1.162 + 1.163 + return OK; 1.164 +} 1.165 + 1.166 +status_t GonkRecorder::setVideoSize(int width, int height) { 1.167 + RE_LOGV("setVideoSize: %dx%d", width, height); 1.168 + if (width <= 0 || height <= 0) { 1.169 + RE_LOGE("Invalid video size: %dx%d", width, height); 1.170 + return BAD_VALUE; 1.171 + } 1.172 + 1.173 + // Additional check on the dimension will be performed later 1.174 + mVideoWidth = width; 1.175 + mVideoHeight = height; 1.176 + 1.177 + return OK; 1.178 +} 1.179 + 1.180 +status_t GonkRecorder::setVideoFrameRate(int frames_per_second) { 1.181 + RE_LOGV("setVideoFrameRate: %d", frames_per_second); 1.182 + if ((frames_per_second <= 0 && frames_per_second != -1) || 1.183 + frames_per_second > 120) { 1.184 + RE_LOGE("Invalid video frame rate: %d", frames_per_second); 1.185 + return BAD_VALUE; 1.186 + } 1.187 + 1.188 + // Additional check on the frame rate will be performed later 1.189 + mFrameRate = frames_per_second; 1.190 + 1.191 + return OK; 1.192 +} 1.193 + 1.194 +status_t GonkRecorder::setOutputFile(const char *path) { 1.195 + RE_LOGE("setOutputFile(const char*) must not be called"); 1.196 + // We don't actually support this at all, as the media_server process 1.197 + // no longer has permissions to create files. 1.198 + 1.199 + return -EPERM; 1.200 +} 1.201 + 1.202 +status_t GonkRecorder::setOutputFile(int fd, int64_t offset, int64_t length) { 1.203 + RE_LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length); 1.204 + // These don't make any sense, do they? 1.205 + CHECK_EQ(offset, 0ll); 1.206 + CHECK_EQ(length, 0ll); 1.207 + 1.208 + if (fd < 0) { 1.209 + RE_LOGE("Invalid file descriptor: %d", fd); 1.210 + return -EBADF; 1.211 + } 1.212 + 1.213 + if (mOutputFd >= 0) { 1.214 + ::close(mOutputFd); 1.215 + } 1.216 + mOutputFd = dup(fd); 1.217 + 1.218 + return OK; 1.219 +} 1.220 + 1.221 +// Attempt to parse an int64 literal optionally surrounded by whitespace, 1.222 +// returns true on success, false otherwise. 1.223 +static bool safe_strtoi64(const char *s, int64_t *val) { 1.224 + char *end; 1.225 + 1.226 + // It is lame, but according to man page, we have to set errno to 0 1.227 + // before calling strtoll(). 1.228 + errno = 0; 1.229 + *val = strtoll(s, &end, 10); 1.230 + 1.231 + if (end == s || errno == ERANGE) { 1.232 + return false; 1.233 + } 1.234 + 1.235 + // Skip trailing whitespace 1.236 + while (isspace(*end)) { 1.237 + ++end; 1.238 + } 1.239 + 1.240 + // For a successful return, the string must contain nothing but a valid 1.241 + // int64 literal optionally surrounded by whitespace. 1.242 + 1.243 + return *end == '\0'; 1.244 +} 1.245 + 1.246 +// Return true if the value is in [0, 0x007FFFFFFF] 1.247 +static bool safe_strtoi32(const char *s, int32_t *val) { 1.248 + int64_t temp; 1.249 + if (safe_strtoi64(s, &temp)) { 1.250 + if (temp >= 0 && temp <= 0x007FFFFFFF) { 1.251 + *val = static_cast<int32_t>(temp); 1.252 + return true; 1.253 + } 1.254 + } 1.255 + return false; 1.256 +} 1.257 + 1.258 +// Trim both leading and trailing whitespace from the given string. 1.259 +static void TrimString(String8 *s) { 1.260 + size_t num_bytes = s->bytes(); 1.261 + const char *data = s->string(); 1.262 + 1.263 + size_t leading_space = 0; 1.264 + while (leading_space < num_bytes && isspace(data[leading_space])) { 1.265 + ++leading_space; 1.266 + } 1.267 + 1.268 + size_t i = num_bytes; 1.269 + while (i > leading_space && isspace(data[i - 1])) { 1.270 + --i; 1.271 + } 1.272 + 1.273 + s->setTo(String8(&data[leading_space], i - leading_space)); 1.274 +} 1.275 + 1.276 +status_t GonkRecorder::setParamAudioSamplingRate(int32_t sampleRate) { 1.277 + RE_LOGV("setParamAudioSamplingRate: %d", sampleRate); 1.278 + if (sampleRate <= 0) { 1.279 + RE_LOGE("Invalid audio sampling rate: %d", sampleRate); 1.280 + return BAD_VALUE; 1.281 + } 1.282 + 1.283 + // Additional check on the sample rate will be performed later. 1.284 + mSampleRate = sampleRate; 1.285 + return OK; 1.286 +} 1.287 + 1.288 +status_t GonkRecorder::setParamAudioNumberOfChannels(int32_t channels) { 1.289 + RE_LOGV("setParamAudioNumberOfChannels: %d", channels); 1.290 + if (channels <= 0 || channels >= 3) { 1.291 + RE_LOGE("Invalid number of audio channels: %d", channels); 1.292 + return BAD_VALUE; 1.293 + } 1.294 + 1.295 + // Additional check on the number of channels will be performed later. 1.296 + mAudioChannels = channels; 1.297 + return OK; 1.298 +} 1.299 + 1.300 +status_t GonkRecorder::setParamAudioEncodingBitRate(int32_t bitRate) { 1.301 + RE_LOGV("setParamAudioEncodingBitRate: %d", bitRate); 1.302 + if (bitRate <= 0) { 1.303 + RE_LOGE("Invalid audio encoding bit rate: %d", bitRate); 1.304 + return BAD_VALUE; 1.305 + } 1.306 + 1.307 + // The target bit rate may not be exactly the same as the requested. 1.308 + // It depends on many factors, such as rate control, and the bit rate 1.309 + // range that a specific encoder supports. The mismatch between the 1.310 + // the target and requested bit rate will NOT be treated as an error. 1.311 + mAudioBitRate = bitRate; 1.312 + return OK; 1.313 +} 1.314 + 1.315 +status_t GonkRecorder::setParamVideoEncodingBitRate(int32_t bitRate) { 1.316 + RE_LOGV("setParamVideoEncodingBitRate: %d", bitRate); 1.317 + if (bitRate <= 0) { 1.318 + RE_LOGE("Invalid video encoding bit rate: %d", bitRate); 1.319 + return BAD_VALUE; 1.320 + } 1.321 + 1.322 + // The target bit rate may not be exactly the same as the requested. 1.323 + // It depends on many factors, such as rate control, and the bit rate 1.324 + // range that a specific encoder supports. The mismatch between the 1.325 + // the target and requested bit rate will NOT be treated as an error. 1.326 + mVideoBitRate = bitRate; 1.327 + return OK; 1.328 +} 1.329 + 1.330 +// Always rotate clockwise, and only support 0, 90, 180 and 270 for now. 1.331 +status_t GonkRecorder::setParamVideoRotation(int32_t degrees) { 1.332 + RE_LOGV("setParamVideoRotation: %d", degrees); 1.333 + if (degrees < 0 || degrees % 90 != 0) { 1.334 + RE_LOGE("Unsupported video rotation angle: %d", degrees); 1.335 + return BAD_VALUE; 1.336 + } 1.337 + mRotationDegrees = degrees % 360; 1.338 + return OK; 1.339 +} 1.340 + 1.341 +status_t GonkRecorder::setParamMaxFileDurationUs(int64_t timeUs) { 1.342 + RE_LOGV("setParamMaxFileDurationUs: %lld us", timeUs); 1.343 + 1.344 + // This is meant for backward compatibility for MediaRecorder.java 1.345 + if (timeUs <= 0) { 1.346 + RE_LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs); 1.347 + timeUs = 0; // Disable the duration limit for zero or negative values. 1.348 + } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds 1.349 + RE_LOGE("Max file duration is too short: %lld us", timeUs); 1.350 + return BAD_VALUE; 1.351 + } 1.352 + 1.353 + if (timeUs <= 15 * 1000000LL) { 1.354 + RE_LOGW("Target duration (%lld us) too short to be respected", timeUs); 1.355 + } 1.356 + mMaxFileDurationUs = timeUs; 1.357 + return OK; 1.358 +} 1.359 + 1.360 +status_t GonkRecorder::setParamMaxFileSizeBytes(int64_t bytes) { 1.361 + RE_LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes); 1.362 + 1.363 + // This is meant for backward compatibility for MediaRecorder.java 1.364 + if (bytes <= 0) { 1.365 + RE_LOGW("Max file size is not positive: %lld bytes. " 1.366 + "Disabling file size limit.", bytes); 1.367 + bytes = 0; // Disable the file size limit for zero or negative values. 1.368 + } else if (bytes <= 1024) { // XXX: 1 kB 1.369 + RE_LOGE("Max file size is too small: %lld bytes", bytes); 1.370 + return BAD_VALUE; 1.371 + } 1.372 + 1.373 + if (bytes <= 100 * 1024) { 1.374 + RE_LOGW("Target file size (%lld bytes) is too small to be respected", bytes); 1.375 + } 1.376 + 1.377 + if (bytes >= 0xffffffffLL) { 1.378 + RE_LOGW("Target file size (%lld bytes) too large to be respected, clipping to 4GB", bytes); 1.379 + bytes = 0xffffffffLL; 1.380 + } 1.381 + 1.382 + mMaxFileSizeBytes = bytes; 1.383 + return OK; 1.384 +} 1.385 + 1.386 +status_t GonkRecorder::setParamInterleaveDuration(int32_t durationUs) { 1.387 + RE_LOGV("setParamInterleaveDuration: %d", durationUs); 1.388 + if (durationUs <= 500000) { // 500 ms 1.389 + // If interleave duration is too small, it is very inefficient to do 1.390 + // interleaving since the metadata overhead will count for a significant 1.391 + // portion of the saved contents 1.392 + RE_LOGE("Audio/video interleave duration is too small: %d us", durationUs); 1.393 + return BAD_VALUE; 1.394 + } else if (durationUs >= 10000000) { // 10 seconds 1.395 + // If interleaving duration is too large, it can cause the recording 1.396 + // session to use too much memory since we have to save the output 1.397 + // data before we write them out 1.398 + RE_LOGE("Audio/video interleave duration is too large: %d us", durationUs); 1.399 + return BAD_VALUE; 1.400 + } 1.401 + mInterleaveDurationUs = durationUs; 1.402 + return OK; 1.403 +} 1.404 + 1.405 +// If seconds < 0, only the first frame is I frame, and rest are all P frames 1.406 +// If seconds == 0, all frames are encoded as I frames. No P frames 1.407 +// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames 1.408 +status_t GonkRecorder::setParamVideoIFramesInterval(int32_t seconds) { 1.409 + RE_LOGV("setParamVideoIFramesInterval: %d seconds", seconds); 1.410 + mIFramesIntervalSec = seconds; 1.411 + return OK; 1.412 +} 1.413 + 1.414 +status_t GonkRecorder::setParam64BitFileOffset(bool use64Bit) { 1.415 + RE_LOGV("setParam64BitFileOffset: %s", 1.416 + use64Bit? "use 64 bit file offset": "use 32 bit file offset"); 1.417 + mUse64BitFileOffset = use64Bit; 1.418 + return OK; 1.419 +} 1.420 + 1.421 +status_t GonkRecorder::setParamVideoCameraId(int32_t cameraId) { 1.422 + RE_LOGV("setParamVideoCameraId: %d", cameraId); 1.423 + if (cameraId < 0) { 1.424 + return BAD_VALUE; 1.425 + } 1.426 + mCameraId = cameraId; 1.427 + return OK; 1.428 +} 1.429 + 1.430 +status_t GonkRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) { 1.431 + RE_LOGV("setParamTrackTimeStatus: %lld", timeDurationUs); 1.432 + if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms? 1.433 + RE_LOGE("Tracking time duration too short: %lld us", timeDurationUs); 1.434 + return BAD_VALUE; 1.435 + } 1.436 + mTrackEveryTimeDurationUs = timeDurationUs; 1.437 + return OK; 1.438 +} 1.439 + 1.440 +status_t GonkRecorder::setParamVideoEncoderProfile(int32_t profile) { 1.441 + RE_LOGV("setParamVideoEncoderProfile: %d", profile); 1.442 + 1.443 + // Additional check will be done later when we load the encoder. 1.444 + // For now, we are accepting values defined in OpenMAX IL. 1.445 + mVideoEncoderProfile = profile; 1.446 + return OK; 1.447 +} 1.448 + 1.449 +status_t GonkRecorder::setParamVideoEncoderLevel(int32_t level) { 1.450 + RE_LOGV("setParamVideoEncoderLevel: %d", level); 1.451 + 1.452 + // Additional check will be done later when we load the encoder. 1.453 + // For now, we are accepting values defined in OpenMAX IL. 1.454 + mVideoEncoderLevel = level; 1.455 + return OK; 1.456 +} 1.457 + 1.458 +status_t GonkRecorder::setParamMovieTimeScale(int32_t timeScale) { 1.459 + RE_LOGV("setParamMovieTimeScale: %d", timeScale); 1.460 + 1.461 + // The range is set to be the same as the audio's time scale range 1.462 + // since audio's time scale has a wider range. 1.463 + if (timeScale < 600 || timeScale > 96000) { 1.464 + RE_LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale); 1.465 + return BAD_VALUE; 1.466 + } 1.467 + mMovieTimeScale = timeScale; 1.468 + return OK; 1.469 +} 1.470 + 1.471 +status_t GonkRecorder::setParamVideoTimeScale(int32_t timeScale) { 1.472 + RE_LOGV("setParamVideoTimeScale: %d", timeScale); 1.473 + 1.474 + // 60000 is chosen to make sure that each video frame from a 60-fps 1.475 + // video has 1000 ticks. 1.476 + if (timeScale < 600 || timeScale > 60000) { 1.477 + RE_LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale); 1.478 + return BAD_VALUE; 1.479 + } 1.480 + mVideoTimeScale = timeScale; 1.481 + return OK; 1.482 +} 1.483 + 1.484 +status_t GonkRecorder::setParamAudioTimeScale(int32_t timeScale) { 1.485 + RE_LOGV("setParamAudioTimeScale: %d", timeScale); 1.486 + 1.487 + // 96000 Hz is the highest sampling rate support in AAC. 1.488 + if (timeScale < 600 || timeScale > 96000) { 1.489 + RE_LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale); 1.490 + return BAD_VALUE; 1.491 + } 1.492 + mAudioTimeScale = timeScale; 1.493 + return OK; 1.494 +} 1.495 + 1.496 +status_t GonkRecorder::setParamGeoDataLongitude( 1.497 + int64_t longitudex10000) { 1.498 + 1.499 + if (longitudex10000 > 1800000 || longitudex10000 < -1800000) { 1.500 + return BAD_VALUE; 1.501 + } 1.502 + mLongitudex10000 = longitudex10000; 1.503 + return OK; 1.504 +} 1.505 + 1.506 +status_t GonkRecorder::setParamGeoDataLatitude( 1.507 + int64_t latitudex10000) { 1.508 + 1.509 + if (latitudex10000 > 900000 || latitudex10000 < -900000) { 1.510 + return BAD_VALUE; 1.511 + } 1.512 + mLatitudex10000 = latitudex10000; 1.513 + return OK; 1.514 +} 1.515 + 1.516 +status_t GonkRecorder::setParameter( 1.517 + const String8 &key, const String8 &value) { 1.518 + RE_LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string()); 1.519 + if (key == "max-duration") { 1.520 + int64_t max_duration_ms; 1.521 + if (safe_strtoi64(value.string(), &max_duration_ms)) { 1.522 + return setParamMaxFileDurationUs(1000LL * max_duration_ms); 1.523 + } 1.524 + } else if (key == "max-filesize") { 1.525 + int64_t max_filesize_bytes; 1.526 + if (safe_strtoi64(value.string(), &max_filesize_bytes)) { 1.527 + return setParamMaxFileSizeBytes(max_filesize_bytes); 1.528 + } 1.529 + } else if (key == "interleave-duration-us") { 1.530 + int32_t durationUs; 1.531 + if (safe_strtoi32(value.string(), &durationUs)) { 1.532 + return setParamInterleaveDuration(durationUs); 1.533 + } 1.534 + } else if (key == "param-movie-time-scale") { 1.535 + int32_t timeScale; 1.536 + if (safe_strtoi32(value.string(), &timeScale)) { 1.537 + return setParamMovieTimeScale(timeScale); 1.538 + } 1.539 + } else if (key == "param-use-64bit-offset") { 1.540 + int32_t use64BitOffset; 1.541 + if (safe_strtoi32(value.string(), &use64BitOffset)) { 1.542 + return setParam64BitFileOffset(use64BitOffset != 0); 1.543 + } 1.544 + } else if (key == "param-geotag-longitude") { 1.545 + int64_t longitudex10000; 1.546 + if (safe_strtoi64(value.string(), &longitudex10000)) { 1.547 + return setParamGeoDataLongitude(longitudex10000); 1.548 + } 1.549 + } else if (key == "param-geotag-latitude") { 1.550 + int64_t latitudex10000; 1.551 + if (safe_strtoi64(value.string(), &latitudex10000)) { 1.552 + return setParamGeoDataLatitude(latitudex10000); 1.553 + } 1.554 + } else if (key == "param-track-time-status") { 1.555 + int64_t timeDurationUs; 1.556 + if (safe_strtoi64(value.string(), &timeDurationUs)) { 1.557 + return setParamTrackTimeStatus(timeDurationUs); 1.558 + } 1.559 + } else if (key == "audio-param-sampling-rate") { 1.560 + int32_t sampling_rate; 1.561 + if (safe_strtoi32(value.string(), &sampling_rate)) { 1.562 + return setParamAudioSamplingRate(sampling_rate); 1.563 + } 1.564 + } else if (key == "audio-param-number-of-channels") { 1.565 + int32_t number_of_channels; 1.566 + if (safe_strtoi32(value.string(), &number_of_channels)) { 1.567 + return setParamAudioNumberOfChannels(number_of_channels); 1.568 + } 1.569 + } else if (key == "audio-param-encoding-bitrate") { 1.570 + int32_t audio_bitrate; 1.571 + if (safe_strtoi32(value.string(), &audio_bitrate)) { 1.572 + return setParamAudioEncodingBitRate(audio_bitrate); 1.573 + } 1.574 + } else if (key == "audio-param-time-scale") { 1.575 + int32_t timeScale; 1.576 + if (safe_strtoi32(value.string(), &timeScale)) { 1.577 + return setParamAudioTimeScale(timeScale); 1.578 + } 1.579 + } else if (key == "video-param-encoding-bitrate") { 1.580 + int32_t video_bitrate; 1.581 + if (safe_strtoi32(value.string(), &video_bitrate)) { 1.582 + return setParamVideoEncodingBitRate(video_bitrate); 1.583 + } 1.584 + } else if (key == "video-param-rotation-angle-degrees") { 1.585 + int32_t degrees; 1.586 + if (safe_strtoi32(value.string(), °rees)) { 1.587 + return setParamVideoRotation(degrees); 1.588 + } 1.589 + } else if (key == "video-param-i-frames-interval") { 1.590 + int32_t seconds; 1.591 + if (safe_strtoi32(value.string(), &seconds)) { 1.592 + return setParamVideoIFramesInterval(seconds); 1.593 + } 1.594 + } else if (key == "video-param-encoder-profile") { 1.595 + int32_t profile; 1.596 + if (safe_strtoi32(value.string(), &profile)) { 1.597 + return setParamVideoEncoderProfile(profile); 1.598 + } 1.599 + } else if (key == "video-param-encoder-level") { 1.600 + int32_t level; 1.601 + if (safe_strtoi32(value.string(), &level)) { 1.602 + return setParamVideoEncoderLevel(level); 1.603 + } 1.604 + } else if (key == "video-param-camera-id") { 1.605 + int32_t cameraId; 1.606 + if (safe_strtoi32(value.string(), &cameraId)) { 1.607 + return setParamVideoCameraId(cameraId); 1.608 + } 1.609 + } else if (key == "video-param-time-scale") { 1.610 + int32_t timeScale; 1.611 + if (safe_strtoi32(value.string(), &timeScale)) { 1.612 + return setParamVideoTimeScale(timeScale); 1.613 + } 1.614 + } else { 1.615 + RE_LOGE("setParameter: failed to find key %s", key.string()); 1.616 + } 1.617 + return BAD_VALUE; 1.618 +} 1.619 + 1.620 +status_t GonkRecorder::setParameters(const String8 ¶ms) { 1.621 + RE_LOGV("setParameters: %s", params.string()); 1.622 + const char *cparams = params.string(); 1.623 + const char *key_start = cparams; 1.624 + for (;;) { 1.625 + const char *equal_pos = strchr(key_start, '='); 1.626 + if (equal_pos == NULL) { 1.627 + RE_LOGE("Parameters %s miss a value", cparams); 1.628 + return BAD_VALUE; 1.629 + } 1.630 + String8 key(key_start, equal_pos - key_start); 1.631 + TrimString(&key); 1.632 + if (key.length() == 0) { 1.633 + RE_LOGE("Parameters %s contains an empty key", cparams); 1.634 + return BAD_VALUE; 1.635 + } 1.636 + const char *value_start = equal_pos + 1; 1.637 + const char *semicolon_pos = strchr(value_start, ';'); 1.638 + String8 value; 1.639 + if (semicolon_pos == NULL) { 1.640 + value.setTo(value_start); 1.641 + } else { 1.642 + value.setTo(value_start, semicolon_pos - value_start); 1.643 + } 1.644 + if (setParameter(key, value) != OK) { 1.645 + return BAD_VALUE; 1.646 + } 1.647 + if (semicolon_pos == NULL) { 1.648 + break; // Reaches the end 1.649 + } 1.650 + key_start = semicolon_pos + 1; 1.651 + } 1.652 + return OK; 1.653 +} 1.654 + 1.655 +status_t GonkRecorder::setListener(const sp<IMediaRecorderClient> &listener) { 1.656 + mListener = listener; 1.657 + 1.658 + return OK; 1.659 +} 1.660 + 1.661 +status_t GonkRecorder::setClientName(const String16& clientName) { 1.662 + mClientName = clientName; 1.663 + 1.664 + return OK; 1.665 +} 1.666 + 1.667 +status_t GonkRecorder::prepare() { 1.668 + if (mVideoSource != VIDEO_SOURCE_LIST_END && mVideoEncoder != VIDEO_ENCODER_LIST_END && 1.669 + mVideoHeight && mVideoWidth && // Video recording 1.670 + (mVideoHeight * mVideoWidth >= RES_720P)) { 1.671 + // TODO: Above check needs to be updated when mMaxFileDurationUs is set from camera app 1.672 + RE_LOGV("Video is high resolution so setting 64-bit file offsets"); 1.673 + setParam64BitFileOffset(true); 1.674 + } 1.675 + return OK; 1.676 +} 1.677 + 1.678 +status_t GonkRecorder::start() { 1.679 + CHECK_GE(mOutputFd, 0); 1.680 + 1.681 + // Get UID here for permission checking 1.682 + mClientUid = IPCThreadState::self()->getCallingUid(); 1.683 + if (mWriter != NULL) { 1.684 + RE_LOGE("File writer is not avaialble"); 1.685 + return UNKNOWN_ERROR; 1.686 + } 1.687 + 1.688 + status_t status = OK; 1.689 + 1.690 + switch (mOutputFormat) { 1.691 + case OUTPUT_FORMAT_DEFAULT: 1.692 + case OUTPUT_FORMAT_THREE_GPP: 1.693 + case OUTPUT_FORMAT_MPEG_4: 1.694 + status = startMPEG4Recording(); 1.695 + break; 1.696 + 1.697 + case OUTPUT_FORMAT_AMR_NB: 1.698 + case OUTPUT_FORMAT_AMR_WB: 1.699 + status = startAMRRecording(); 1.700 + break; 1.701 + 1.702 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.703 + case OUTPUT_FORMAT_AAC_ADIF: 1.704 + case OUTPUT_FORMAT_AAC_ADTS: 1.705 + status = startAACRecording(); 1.706 + break; 1.707 +#endif 1.708 + 1.709 + case OUTPUT_FORMAT_RTP_AVP: 1.710 + status = startRTPRecording(); 1.711 + break; 1.712 + 1.713 + case OUTPUT_FORMAT_MPEG2TS: 1.714 + status = startMPEG2TSRecording(); 1.715 + break; 1.716 + 1.717 + default: 1.718 + RE_LOGE("Unsupported output file format: %d", mOutputFormat); 1.719 + status = UNKNOWN_ERROR; 1.720 + break; 1.721 + } 1.722 + 1.723 + if ((status == OK) && (!mStarted)) { 1.724 + mStarted = true; 1.725 + } 1.726 + 1.727 + return status; 1.728 +} 1.729 + 1.730 +sp<MediaSource> GonkRecorder::createAudioSource() { 1.731 + sp<AudioSource> audioSource = 1.732 + new AudioSource( 1.733 + mAudioSource, 1.734 + mSampleRate, 1.735 + mAudioChannels); 1.736 + 1.737 + status_t err = audioSource->initCheck(); 1.738 + 1.739 + if (err != OK) { 1.740 + RE_LOGE("audio source is not initialized"); 1.741 + return NULL; 1.742 + } 1.743 + 1.744 + sp<MetaData> encMeta = new MetaData; 1.745 + const char *mime; 1.746 + switch (mAudioEncoder) { 1.747 + case AUDIO_ENCODER_AMR_NB: 1.748 + case AUDIO_ENCODER_DEFAULT: 1.749 + mime = MEDIA_MIMETYPE_AUDIO_AMR_NB; 1.750 + break; 1.751 + case AUDIO_ENCODER_AMR_WB: 1.752 + mime = MEDIA_MIMETYPE_AUDIO_AMR_WB; 1.753 + break; 1.754 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.755 + case AUDIO_ENCODER_AAC: 1.756 + mime = MEDIA_MIMETYPE_AUDIO_AAC; 1.757 + encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC); 1.758 + break; 1.759 + case AUDIO_ENCODER_HE_AAC: 1.760 + mime = MEDIA_MIMETYPE_AUDIO_AAC; 1.761 + encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectHE); 1.762 + break; 1.763 + case AUDIO_ENCODER_AAC_ELD: 1.764 + mime = MEDIA_MIMETYPE_AUDIO_AAC; 1.765 + encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD); 1.766 + break; 1.767 +#endif 1.768 + default: 1.769 + RE_LOGE("Unknown audio encoder: %d", mAudioEncoder); 1.770 + return NULL; 1.771 + } 1.772 + encMeta->setCString(kKeyMIMEType, mime); 1.773 + 1.774 + int32_t maxInputSize; 1.775 + CHECK(audioSource->getFormat()->findInt32( 1.776 + kKeyMaxInputSize, &maxInputSize)); 1.777 + 1.778 + encMeta->setInt32(kKeyMaxInputSize, maxInputSize); 1.779 + encMeta->setInt32(kKeyChannelCount, mAudioChannels); 1.780 + encMeta->setInt32(kKeySampleRate, mSampleRate); 1.781 + encMeta->setInt32(kKeyBitRate, mAudioBitRate); 1.782 + if (mAudioTimeScale > 0) { 1.783 + encMeta->setInt32(kKeyTimeScale, mAudioTimeScale); 1.784 + } 1.785 + 1.786 + // OMXClient::connect() always returns OK and abort's fatally if 1.787 + // it can't connect. 1.788 + OMXClient client; 1.789 + // CHECK_EQ causes an abort if the given condition fails. 1.790 + CHECK_EQ(client.connect(), (status_t)OK); 1.791 + sp<MediaSource> audioEncoder = 1.792 + OMXCodec::Create(client.interface(), encMeta, 1.793 + true /* createEncoder */, audioSource); 1.794 + mAudioSourceNode = audioSource; 1.795 + 1.796 + return audioEncoder; 1.797 +} 1.798 + 1.799 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.800 +status_t GonkRecorder::startAACRecording() { 1.801 + // FIXME: 1.802 + // Add support for OUTPUT_FORMAT_AAC_ADIF 1.803 + CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS); 1.804 + 1.805 + CHECK(mAudioEncoder == AUDIO_ENCODER_AAC || 1.806 + mAudioEncoder == AUDIO_ENCODER_HE_AAC || 1.807 + mAudioEncoder == AUDIO_ENCODER_AAC_ELD); 1.808 + CHECK(mAudioSource != AUDIO_SOURCE_CNT); 1.809 + 1.810 + mWriter = new AACWriter(mOutputFd); 1.811 + status_t status = startRawAudioRecording(); 1.812 + if (status != OK) { 1.813 + mWriter.clear(); 1.814 + mWriter = NULL; 1.815 + } 1.816 + 1.817 + return status; 1.818 +} 1.819 +#endif 1.820 + 1.821 +status_t GonkRecorder::startAMRRecording() { 1.822 + CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB || 1.823 + mOutputFormat == OUTPUT_FORMAT_AMR_WB); 1.824 + 1.825 + if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) { 1.826 + if (mAudioEncoder != AUDIO_ENCODER_DEFAULT && 1.827 + mAudioEncoder != AUDIO_ENCODER_AMR_NB) { 1.828 + RE_LOGE("Invalid encoder %d used for AMRNB recording", 1.829 + mAudioEncoder); 1.830 + return BAD_VALUE; 1.831 + } 1.832 + } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB 1.833 + if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) { 1.834 + RE_LOGE("Invlaid encoder %d used for AMRWB recording", 1.835 + mAudioEncoder); 1.836 + return BAD_VALUE; 1.837 + } 1.838 + } 1.839 + 1.840 + mWriter = new AMRWriter(mOutputFd); 1.841 + status_t status = startRawAudioRecording(); 1.842 + if (status != OK) { 1.843 + mWriter.clear(); 1.844 + mWriter = NULL; 1.845 + } 1.846 + return status; 1.847 +} 1.848 + 1.849 +status_t GonkRecorder::startRawAudioRecording() { 1.850 + if (mAudioSource >= AUDIO_SOURCE_CNT) { 1.851 + RE_LOGE("Invalid audio source: %d", mAudioSource); 1.852 + return BAD_VALUE; 1.853 + } 1.854 + 1.855 + status_t status = BAD_VALUE; 1.856 + if (OK != (status = checkAudioEncoderCapabilities())) { 1.857 + return status; 1.858 + } 1.859 + 1.860 + sp<MediaSource> audioEncoder = createAudioSource(); 1.861 + if (audioEncoder == NULL) { 1.862 + return UNKNOWN_ERROR; 1.863 + } 1.864 + 1.865 + CHECK(mWriter != 0); 1.866 + mWriter->addSource(audioEncoder); 1.867 + 1.868 + if (mMaxFileDurationUs != 0) { 1.869 + mWriter->setMaxFileDuration(mMaxFileDurationUs); 1.870 + } 1.871 + if (mMaxFileSizeBytes != 0) { 1.872 + mWriter->setMaxFileSize(mMaxFileSizeBytes); 1.873 + } 1.874 + mWriter->setListener(mListener); 1.875 + mWriter->start(); 1.876 + 1.877 + return OK; 1.878 +} 1.879 + 1.880 +status_t GonkRecorder::startRTPRecording() { 1.881 + return INVALID_OPERATION; 1.882 +} 1.883 + 1.884 +status_t GonkRecorder::startMPEG2TSRecording() { 1.885 + CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS); 1.886 + 1.887 + sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd); 1.888 + 1.889 + if (mAudioSource != AUDIO_SOURCE_CNT) { 1.890 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.891 + if (mAudioEncoder != AUDIO_ENCODER_AAC && 1.892 + mAudioEncoder != AUDIO_ENCODER_HE_AAC && 1.893 + mAudioEncoder != AUDIO_ENCODER_AAC_ELD) { 1.894 + return ERROR_UNSUPPORTED; 1.895 + } 1.896 +#endif 1.897 + status_t err = setupAudioEncoder(writer); 1.898 + 1.899 + if (err != OK) { 1.900 + return err; 1.901 + } 1.902 + } 1.903 + 1.904 + if (mVideoSource < VIDEO_SOURCE_LIST_END) { 1.905 + if (mVideoEncoder != VIDEO_ENCODER_H264) { 1.906 + return ERROR_UNSUPPORTED; 1.907 + } 1.908 + 1.909 + sp<MediaSource> mediaSource; 1.910 + status_t err = setupMediaSource(&mediaSource); 1.911 + if (err != OK) { 1.912 + return err; 1.913 + } 1.914 + 1.915 + sp<MediaSource> encoder; 1.916 + err = setupVideoEncoder(mediaSource, mVideoBitRate, &encoder); 1.917 + 1.918 + if (err != OK) { 1.919 + return err; 1.920 + } 1.921 + 1.922 + writer->addSource(encoder); 1.923 + } 1.924 + 1.925 + if (mMaxFileDurationUs != 0) { 1.926 + writer->setMaxFileDuration(mMaxFileDurationUs); 1.927 + } 1.928 + 1.929 + if (mMaxFileSizeBytes != 0) { 1.930 + writer->setMaxFileSize(mMaxFileSizeBytes); 1.931 + } 1.932 + 1.933 + mWriter = writer; 1.934 + 1.935 + return mWriter->start(); 1.936 +} 1.937 + 1.938 +void GonkRecorder::clipVideoFrameRate() { 1.939 + RE_LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder); 1.940 + int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName( 1.941 + "enc.vid.fps.min", mVideoEncoder); 1.942 + int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName( 1.943 + "enc.vid.fps.max", mVideoEncoder); 1.944 + if (mFrameRate < minFrameRate && minFrameRate != -1) { 1.945 + RE_LOGW("Intended video encoding frame rate (%d fps) is too small" 1.946 + " and will be set to (%d fps)", mFrameRate, minFrameRate); 1.947 + mFrameRate = minFrameRate; 1.948 + } else if (mFrameRate > maxFrameRate && maxFrameRate != -1) { 1.949 + RE_LOGW("Intended video encoding frame rate (%d fps) is too large" 1.950 + " and will be set to (%d fps)", mFrameRate, maxFrameRate); 1.951 + mFrameRate = maxFrameRate; 1.952 + } 1.953 +} 1.954 + 1.955 +void GonkRecorder::clipVideoBitRate() { 1.956 + RE_LOGV("clipVideoBitRate: encoder %d", mVideoEncoder); 1.957 + int minBitRate = mEncoderProfiles->getVideoEncoderParamByName( 1.958 + "enc.vid.bps.min", mVideoEncoder); 1.959 + int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName( 1.960 + "enc.vid.bps.max", mVideoEncoder); 1.961 + if (mVideoBitRate < minBitRate && minBitRate != -1) { 1.962 + RE_LOGW("Intended video encoding bit rate (%d bps) is too small" 1.963 + " and will be set to (%d bps)", mVideoBitRate, minBitRate); 1.964 + mVideoBitRate = minBitRate; 1.965 + } else if (mVideoBitRate > maxBitRate && maxBitRate != -1) { 1.966 + RE_LOGW("Intended video encoding bit rate (%d bps) is too large" 1.967 + " and will be set to (%d bps)", mVideoBitRate, maxBitRate); 1.968 + mVideoBitRate = maxBitRate; 1.969 + } 1.970 +} 1.971 + 1.972 +void GonkRecorder::clipVideoFrameWidth() { 1.973 + RE_LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder); 1.974 + int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName( 1.975 + "enc.vid.width.min", mVideoEncoder); 1.976 + int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName( 1.977 + "enc.vid.width.max", mVideoEncoder); 1.978 + if (mVideoWidth < minFrameWidth && minFrameWidth != -1) { 1.979 + RE_LOGW("Intended video encoding frame width (%d) is too small" 1.980 + " and will be set to (%d)", mVideoWidth, minFrameWidth); 1.981 + mVideoWidth = minFrameWidth; 1.982 + } else if (mVideoWidth > maxFrameWidth && maxFrameWidth != -1) { 1.983 + RE_LOGW("Intended video encoding frame width (%d) is too large" 1.984 + " and will be set to (%d)", mVideoWidth, maxFrameWidth); 1.985 + mVideoWidth = maxFrameWidth; 1.986 + } 1.987 +} 1.988 + 1.989 +status_t GonkRecorder::checkVideoEncoderCapabilities() { 1.990 + 1.991 + // Dont clip for time lapse capture as encoder will have enough 1.992 + // time to encode because of slow capture rate of time lapse. 1.993 + clipVideoBitRate(); 1.994 + clipVideoFrameRate(); 1.995 + clipVideoFrameWidth(); 1.996 + clipVideoFrameHeight(); 1.997 + setDefaultProfileIfNecessary(); 1.998 + return OK; 1.999 +} 1.1000 + 1.1001 +// Set to use AVC baseline profile if the encoding parameters matches 1.1002 +// CAMCORDER_QUALITY_LOW profile; this is for the sake of MMS service. 1.1003 +void GonkRecorder::setDefaultProfileIfNecessary() { 1.1004 + RE_LOGV("setDefaultProfileIfNecessary"); 1.1005 + 1.1006 + camcorder_quality quality = CAMCORDER_QUALITY_LOW; 1.1007 + 1.1008 + int64_t durationUs = mEncoderProfiles->getCamcorderProfileParamByName( 1.1009 + "duration", mCameraId, quality) * 1000000LL; 1.1010 + 1.1011 + int fileFormat = mEncoderProfiles->getCamcorderProfileParamByName( 1.1012 + "file.format", mCameraId, quality); 1.1013 + 1.1014 + int videoCodec = mEncoderProfiles->getCamcorderProfileParamByName( 1.1015 + "vid.codec", mCameraId, quality); 1.1016 + 1.1017 + int videoBitRate = mEncoderProfiles->getCamcorderProfileParamByName( 1.1018 + "vid.bps", mCameraId, quality); 1.1019 + 1.1020 + int videoFrameRate = mEncoderProfiles->getCamcorderProfileParamByName( 1.1021 + "vid.fps", mCameraId, quality); 1.1022 + 1.1023 + int videoFrameWidth = mEncoderProfiles->getCamcorderProfileParamByName( 1.1024 + "vid.width", mCameraId, quality); 1.1025 + 1.1026 + int videoFrameHeight = mEncoderProfiles->getCamcorderProfileParamByName( 1.1027 + "vid.height", mCameraId, quality); 1.1028 + 1.1029 + int audioCodec = mEncoderProfiles->getCamcorderProfileParamByName( 1.1030 + "aud.codec", mCameraId, quality); 1.1031 + 1.1032 + int audioBitRate = mEncoderProfiles->getCamcorderProfileParamByName( 1.1033 + "aud.bps", mCameraId, quality); 1.1034 + 1.1035 + int audioSampleRate = mEncoderProfiles->getCamcorderProfileParamByName( 1.1036 + "aud.hz", mCameraId, quality); 1.1037 + 1.1038 + int audioChannels = mEncoderProfiles->getCamcorderProfileParamByName( 1.1039 + "aud.ch", mCameraId, quality); 1.1040 + 1.1041 + if (durationUs == mMaxFileDurationUs && 1.1042 + fileFormat == mOutputFormat && 1.1043 + videoCodec == mVideoEncoder && 1.1044 + videoBitRate == mVideoBitRate && 1.1045 + videoFrameRate == mFrameRate && 1.1046 + videoFrameWidth == mVideoWidth && 1.1047 + videoFrameHeight == mVideoHeight && 1.1048 + audioCodec == mAudioEncoder && 1.1049 + audioBitRate == mAudioBitRate && 1.1050 + audioSampleRate == mSampleRate && 1.1051 + audioChannels == mAudioChannels) { 1.1052 + if (videoCodec == VIDEO_ENCODER_H264) { 1.1053 + RE_LOGI("Force to use AVC baseline profile"); 1.1054 + setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline); 1.1055 + } 1.1056 + } 1.1057 +} 1.1058 + 1.1059 +status_t GonkRecorder::checkAudioEncoderCapabilities() { 1.1060 + clipAudioBitRate(); 1.1061 + clipAudioSampleRate(); 1.1062 + clipNumberOfAudioChannels(); 1.1063 + return OK; 1.1064 +} 1.1065 + 1.1066 +void GonkRecorder::clipAudioBitRate() { 1.1067 + RE_LOGV("clipAudioBitRate: encoder %d", mAudioEncoder); 1.1068 + 1.1069 + int minAudioBitRate = 1.1070 + mEncoderProfiles->getAudioEncoderParamByName( 1.1071 + "enc.aud.bps.min", mAudioEncoder); 1.1072 + if (minAudioBitRate != -1 && mAudioBitRate < minAudioBitRate) { 1.1073 + RE_LOGW("Intended audio encoding bit rate (%d) is too small" 1.1074 + " and will be set to (%d)", mAudioBitRate, minAudioBitRate); 1.1075 + mAudioBitRate = minAudioBitRate; 1.1076 + } 1.1077 + 1.1078 + int maxAudioBitRate = 1.1079 + mEncoderProfiles->getAudioEncoderParamByName( 1.1080 + "enc.aud.bps.max", mAudioEncoder); 1.1081 + if (maxAudioBitRate != -1 && mAudioBitRate > maxAudioBitRate) { 1.1082 + RE_LOGW("Intended audio encoding bit rate (%d) is too large" 1.1083 + " and will be set to (%d)", mAudioBitRate, maxAudioBitRate); 1.1084 + mAudioBitRate = maxAudioBitRate; 1.1085 + } 1.1086 +} 1.1087 + 1.1088 +void GonkRecorder::clipAudioSampleRate() { 1.1089 + RE_LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder); 1.1090 + 1.1091 + int minSampleRate = 1.1092 + mEncoderProfiles->getAudioEncoderParamByName( 1.1093 + "enc.aud.hz.min", mAudioEncoder); 1.1094 + if (minSampleRate != -1 && mSampleRate < minSampleRate) { 1.1095 + RE_LOGW("Intended audio sample rate (%d) is too small" 1.1096 + " and will be set to (%d)", mSampleRate, minSampleRate); 1.1097 + mSampleRate = minSampleRate; 1.1098 + } 1.1099 + 1.1100 + int maxSampleRate = 1.1101 + mEncoderProfiles->getAudioEncoderParamByName( 1.1102 + "enc.aud.hz.max", mAudioEncoder); 1.1103 + if (maxSampleRate != -1 && mSampleRate > maxSampleRate) { 1.1104 + RE_LOGW("Intended audio sample rate (%d) is too large" 1.1105 + " and will be set to (%d)", mSampleRate, maxSampleRate); 1.1106 + mSampleRate = maxSampleRate; 1.1107 + } 1.1108 +} 1.1109 + 1.1110 +void GonkRecorder::clipNumberOfAudioChannels() { 1.1111 + RE_LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder); 1.1112 + 1.1113 + int minChannels = 1.1114 + mEncoderProfiles->getAudioEncoderParamByName( 1.1115 + "enc.aud.ch.min", mAudioEncoder); 1.1116 + if (minChannels != -1 && mAudioChannels < minChannels) { 1.1117 + RE_LOGW("Intended number of audio channels (%d) is too small" 1.1118 + " and will be set to (%d)", mAudioChannels, minChannels); 1.1119 + mAudioChannels = minChannels; 1.1120 + } 1.1121 + 1.1122 + int maxChannels = 1.1123 + mEncoderProfiles->getAudioEncoderParamByName( 1.1124 + "enc.aud.ch.max", mAudioEncoder); 1.1125 + if (maxChannels != -1 && mAudioChannels > maxChannels) { 1.1126 + RE_LOGW("Intended number of audio channels (%d) is too large" 1.1127 + " and will be set to (%d)", mAudioChannels, maxChannels); 1.1128 + mAudioChannels = maxChannels; 1.1129 + } 1.1130 +} 1.1131 + 1.1132 +void GonkRecorder::clipVideoFrameHeight() { 1.1133 + RE_LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder); 1.1134 + int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName( 1.1135 + "enc.vid.height.min", mVideoEncoder); 1.1136 + int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName( 1.1137 + "enc.vid.height.max", mVideoEncoder); 1.1138 + if (minFrameHeight != -1 && mVideoHeight < minFrameHeight) { 1.1139 + RE_LOGW("Intended video encoding frame height (%d) is too small" 1.1140 + " and will be set to (%d)", mVideoHeight, minFrameHeight); 1.1141 + mVideoHeight = minFrameHeight; 1.1142 + } else if (maxFrameHeight != -1 && mVideoHeight > maxFrameHeight) { 1.1143 + RE_LOGW("Intended video encoding frame height (%d) is too large" 1.1144 + " and will be set to (%d)", mVideoHeight, maxFrameHeight); 1.1145 + mVideoHeight = maxFrameHeight; 1.1146 + } 1.1147 +} 1.1148 + 1.1149 +// Set up the appropriate MediaSource depending on the chosen option 1.1150 +status_t GonkRecorder::setupMediaSource( 1.1151 + sp<MediaSource> *mediaSource) { 1.1152 + if (mVideoSource == VIDEO_SOURCE_DEFAULT 1.1153 + || mVideoSource == VIDEO_SOURCE_CAMERA) { 1.1154 + sp<GonkCameraSource> cameraSource; 1.1155 + status_t err = setupCameraSource(&cameraSource); 1.1156 + if (err != OK) { 1.1157 + return err; 1.1158 + } 1.1159 + *mediaSource = cameraSource; 1.1160 + } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) { 1.1161 + return BAD_VALUE; 1.1162 + } else { 1.1163 + return INVALID_OPERATION; 1.1164 + } 1.1165 + return OK; 1.1166 +} 1.1167 + 1.1168 +status_t GonkRecorder::setupCameraSource( 1.1169 + sp<GonkCameraSource> *cameraSource) { 1.1170 + status_t err = OK; 1.1171 + if ((err = checkVideoEncoderCapabilities()) != OK) { 1.1172 + return err; 1.1173 + } 1.1174 + Size videoSize; 1.1175 + videoSize.width = mVideoWidth; 1.1176 + videoSize.height = mVideoHeight; 1.1177 + bool useMeta = true; 1.1178 + char value[PROPERTY_VALUE_MAX]; 1.1179 + if (property_get("debug.camcorder.disablemeta", value, NULL) && 1.1180 + atoi(value)) { 1.1181 + useMeta = false; 1.1182 + } 1.1183 + 1.1184 + *cameraSource = GonkCameraSource::Create( 1.1185 + mCameraHw, videoSize, mFrameRate, useMeta); 1.1186 + if (*cameraSource == NULL) { 1.1187 + return UNKNOWN_ERROR; 1.1188 + } 1.1189 + 1.1190 + if ((*cameraSource)->initCheck() != OK) { 1.1191 + (*cameraSource).clear(); 1.1192 + *cameraSource = NULL; 1.1193 + return NO_INIT; 1.1194 + } 1.1195 + 1.1196 + // When frame rate is not set, the actual frame rate will be set to 1.1197 + // the current frame rate being used. 1.1198 + if (mFrameRate == -1) { 1.1199 + int32_t frameRate = 0; 1.1200 + CHECK ((*cameraSource)->getFormat()->findInt32( 1.1201 + kKeyFrameRate, &frameRate)); 1.1202 + RE_LOGI("Frame rate is not explicitly set. Use the current frame " 1.1203 + "rate (%d fps)", frameRate); 1.1204 + mFrameRate = frameRate; 1.1205 + } 1.1206 + 1.1207 + CHECK(mFrameRate != -1); 1.1208 + 1.1209 + mIsMetaDataStoredInVideoBuffers = 1.1210 + (*cameraSource)->isMetaDataStoredInVideoBuffers(); 1.1211 + 1.1212 + return OK; 1.1213 +} 1.1214 + 1.1215 +status_t GonkRecorder::setupVideoEncoder( 1.1216 + sp<MediaSource> cameraSource, 1.1217 + int32_t videoBitRate, 1.1218 + sp<MediaSource> *source) { 1.1219 + source->clear(); 1.1220 + 1.1221 + sp<MetaData> enc_meta = new MetaData; 1.1222 + enc_meta->setInt32(kKeyBitRate, videoBitRate); 1.1223 + enc_meta->setInt32(kKeyFrameRate, mFrameRate); 1.1224 + 1.1225 + switch (mVideoEncoder) { 1.1226 + case VIDEO_ENCODER_H263: 1.1227 + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); 1.1228 + break; 1.1229 + 1.1230 + case VIDEO_ENCODER_MPEG_4_SP: 1.1231 + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); 1.1232 + break; 1.1233 + 1.1234 + case VIDEO_ENCODER_H264: 1.1235 + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 1.1236 + break; 1.1237 + 1.1238 + default: 1.1239 + CHECK(!"Should not be here, unsupported video encoding."); 1.1240 + break; 1.1241 + } 1.1242 + 1.1243 + sp<MetaData> meta = cameraSource->getFormat(); 1.1244 + 1.1245 + int32_t width, height, stride, sliceHeight, colorFormat; 1.1246 + CHECK(meta->findInt32(kKeyWidth, &width)); 1.1247 + CHECK(meta->findInt32(kKeyHeight, &height)); 1.1248 + CHECK(meta->findInt32(kKeyStride, &stride)); 1.1249 + CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight)); 1.1250 + CHECK(meta->findInt32(kKeyColorFormat, &colorFormat)); 1.1251 + 1.1252 + enc_meta->setInt32(kKeyWidth, width); 1.1253 + enc_meta->setInt32(kKeyHeight, height); 1.1254 + enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec); 1.1255 + enc_meta->setInt32(kKeyStride, stride); 1.1256 + enc_meta->setInt32(kKeySliceHeight, sliceHeight); 1.1257 + enc_meta->setInt32(kKeyColorFormat, colorFormat); 1.1258 + if (mVideoTimeScale > 0) { 1.1259 + enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale); 1.1260 + } 1.1261 + if (mVideoEncoderProfile != -1) { 1.1262 + enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile); 1.1263 + } 1.1264 + if (mVideoEncoderLevel != -1) { 1.1265 + enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel); 1.1266 + } 1.1267 + 1.1268 + // OMXClient::connect() always returns OK and abort's fatally if 1.1269 + // it can't connect. 1.1270 + OMXClient client; 1.1271 + // CHECK_EQ causes an abort if the given condition fails. 1.1272 + CHECK_EQ(client.connect(), (status_t)OK); 1.1273 + 1.1274 + uint32_t encoder_flags = 0; 1.1275 + if (mIsMetaDataStoredInVideoBuffers) { 1.1276 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.1277 + encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers; 1.1278 +#else 1.1279 + encoder_flags |= OMXCodec::kHardwareCodecsOnly; 1.1280 + encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers; 1.1281 + encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime; 1.1282 +#endif 1.1283 + } 1.1284 + 1.1285 + sp<MediaSource> encoder = OMXCodec::Create( 1.1286 + client.interface(), enc_meta, 1.1287 + true /* createEncoder */, cameraSource, 1.1288 + NULL, encoder_flags); 1.1289 + if (encoder == NULL) { 1.1290 + RE_LOGW("Failed to create the encoder"); 1.1291 + // When the encoder fails to be created, we need 1.1292 + // release the camera source due to the camera's lock 1.1293 + // and unlock mechanism. 1.1294 + cameraSource->stop(); 1.1295 + return UNKNOWN_ERROR; 1.1296 + } 1.1297 + 1.1298 + *source = encoder; 1.1299 + 1.1300 + return OK; 1.1301 +} 1.1302 + 1.1303 +status_t GonkRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) { 1.1304 + status_t status = BAD_VALUE; 1.1305 + if (OK != (status = checkAudioEncoderCapabilities())) { 1.1306 + return status; 1.1307 + } 1.1308 + 1.1309 + switch(mAudioEncoder) { 1.1310 + case AUDIO_ENCODER_AMR_NB: 1.1311 + case AUDIO_ENCODER_AMR_WB: 1.1312 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.1313 + case AUDIO_ENCODER_AAC: 1.1314 + case AUDIO_ENCODER_HE_AAC: 1.1315 + case AUDIO_ENCODER_AAC_ELD: 1.1316 +#endif 1.1317 + break; 1.1318 + 1.1319 + default: 1.1320 + RE_LOGE("Unsupported audio encoder: %d", mAudioEncoder); 1.1321 + return UNKNOWN_ERROR; 1.1322 + } 1.1323 + 1.1324 + sp<MediaSource> audioEncoder = createAudioSource(); 1.1325 + if (audioEncoder == NULL) { 1.1326 + return UNKNOWN_ERROR; 1.1327 + } 1.1328 + 1.1329 + writer->addSource(audioEncoder); 1.1330 + return OK; 1.1331 +} 1.1332 + 1.1333 +status_t GonkRecorder::setupMPEG4Recording( 1.1334 + int outputFd, 1.1335 + int32_t videoWidth, int32_t videoHeight, 1.1336 + int32_t videoBitRate, 1.1337 + int32_t *totalBitRate, 1.1338 + sp<MediaWriter> *mediaWriter) { 1.1339 + mediaWriter->clear(); 1.1340 + *totalBitRate = 0; 1.1341 + status_t err = OK; 1.1342 + sp<MediaWriter> writer = new MPEG4Writer(outputFd); 1.1343 + 1.1344 + if (mVideoSource < VIDEO_SOURCE_LIST_END) { 1.1345 + 1.1346 + sp<MediaSource> mediaSource; 1.1347 + err = setupMediaSource(&mediaSource); 1.1348 + if (err != OK) { 1.1349 + return err; 1.1350 + } 1.1351 + 1.1352 + sp<MediaSource> encoder; 1.1353 + err = setupVideoEncoder(mediaSource, videoBitRate, &encoder); 1.1354 + if (err != OK) { 1.1355 + return err; 1.1356 + } 1.1357 + 1.1358 + writer->addSource(encoder); 1.1359 + *totalBitRate += videoBitRate; 1.1360 + } 1.1361 + 1.1362 + // Audio source is added at the end if it exists. 1.1363 + // This help make sure that the "recoding" sound is suppressed for 1.1364 + // camcorder applications in the recorded files. 1.1365 + if (mAudioSource != AUDIO_SOURCE_CNT) { 1.1366 + err = setupAudioEncoder(writer); 1.1367 + if (err != OK) return err; 1.1368 + *totalBitRate += mAudioBitRate; 1.1369 + } 1.1370 + 1.1371 + if (mInterleaveDurationUs > 0) { 1.1372 + reinterpret_cast<MPEG4Writer *>(writer.get())-> 1.1373 + setInterleaveDuration(mInterleaveDurationUs); 1.1374 + } 1.1375 + if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) { 1.1376 + reinterpret_cast<MPEG4Writer *>(writer.get())-> 1.1377 + setGeoData(mLatitudex10000, mLongitudex10000); 1.1378 + } 1.1379 + if (mMaxFileDurationUs != 0) { 1.1380 + writer->setMaxFileDuration(mMaxFileDurationUs); 1.1381 + } 1.1382 + if (mMaxFileSizeBytes != 0) { 1.1383 + writer->setMaxFileSize(mMaxFileSizeBytes); 1.1384 + } 1.1385 + 1.1386 + mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId); 1.1387 + if (mStartTimeOffsetMs > 0) { 1.1388 + reinterpret_cast<MPEG4Writer *>(writer.get())-> 1.1389 + setStartTimeOffsetMs(mStartTimeOffsetMs); 1.1390 + } 1.1391 + 1.1392 + writer->setListener(mListener); 1.1393 + *mediaWriter = writer; 1.1394 + return OK; 1.1395 +} 1.1396 + 1.1397 +void GonkRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate, 1.1398 + sp<MetaData> *meta) { 1.1399 + (*meta)->setInt64(kKeyTime, startTimeUs); 1.1400 + (*meta)->setInt32(kKeyFileType, mOutputFormat); 1.1401 + (*meta)->setInt32(kKeyBitRate, totalBitRate); 1.1402 + (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); 1.1403 + if (mMovieTimeScale > 0) { 1.1404 + (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale); 1.1405 + } 1.1406 + if (mTrackEveryTimeDurationUs > 0) { 1.1407 + (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs); 1.1408 + } 1.1409 + 1.1410 + char value[PROPERTY_VALUE_MAX]; 1.1411 + if (property_get("debug.camcorder.rotation", value, 0) > 0 && atoi(value) >= 0) { 1.1412 + mRotationDegrees = atoi(value); 1.1413 + RE_LOGI("Setting rotation to %d", mRotationDegrees ); 1.1414 + } 1.1415 + 1.1416 + if (mRotationDegrees != 0) { 1.1417 + (*meta)->setInt32(kKeyRotation, mRotationDegrees); 1.1418 + } 1.1419 +} 1.1420 + 1.1421 +status_t GonkRecorder::startMPEG4Recording() { 1.1422 + int32_t totalBitRate; 1.1423 + status_t err = setupMPEG4Recording( 1.1424 + mOutputFd, mVideoWidth, mVideoHeight, 1.1425 + mVideoBitRate, &totalBitRate, &mWriter); 1.1426 + if (err != OK) { 1.1427 + return err; 1.1428 + } 1.1429 + 1.1430 + //systemTime() doesn't give correct time because 1.1431 + //HAVE_POSIX_CLOCKS is not defined for utils/Timers.cpp 1.1432 + //so, using clock_gettime directly 1.1433 +#include <time.h> 1.1434 + struct timespec t; 1.1435 + clock_gettime(CLOCK_MONOTONIC, &t); 1.1436 + int64_t startTimeUs = int64_t(t.tv_sec)*1000000000LL + t.tv_nsec; 1.1437 + startTimeUs = startTimeUs / 1000; 1.1438 + sp<MetaData> meta = new MetaData; 1.1439 + setupMPEG4MetaData(startTimeUs, totalBitRate, &meta); 1.1440 + 1.1441 + err = mWriter->start(meta.get()); 1.1442 + if (err != OK) { 1.1443 + return err; 1.1444 + } 1.1445 + 1.1446 + return OK; 1.1447 +} 1.1448 + 1.1449 +status_t GonkRecorder::pause() { 1.1450 + RE_LOGV("pause"); 1.1451 + if (mWriter == NULL) { 1.1452 + return UNKNOWN_ERROR; 1.1453 + } 1.1454 + mWriter->pause(); 1.1455 + 1.1456 + if (mStarted) { 1.1457 + mStarted = false; 1.1458 + } 1.1459 + 1.1460 + 1.1461 + return OK; 1.1462 +} 1.1463 + 1.1464 +status_t GonkRecorder::stop() { 1.1465 + RE_LOGV("stop"); 1.1466 + status_t err = OK; 1.1467 + 1.1468 + if (mWriter != NULL) { 1.1469 + err = mWriter->stop(); 1.1470 + mWriter.clear(); 1.1471 + } 1.1472 + 1.1473 + if (mOutputFd >= 0) { 1.1474 + ::close(mOutputFd); 1.1475 + mOutputFd = -1; 1.1476 + } 1.1477 + 1.1478 + if (mStarted) { 1.1479 + mStarted = false; 1.1480 + } 1.1481 + 1.1482 + 1.1483 + return err; 1.1484 +} 1.1485 + 1.1486 +status_t GonkRecorder::close() { 1.1487 + RE_LOGV("close"); 1.1488 + stop(); 1.1489 + 1.1490 + return OK; 1.1491 +} 1.1492 + 1.1493 +status_t GonkRecorder::reset() { 1.1494 + RE_LOGV("reset"); 1.1495 + stop(); 1.1496 + 1.1497 + // No audio or video source by default 1.1498 + mAudioSource = AUDIO_SOURCE_CNT; 1.1499 + mVideoSource = VIDEO_SOURCE_LIST_END; 1.1500 + 1.1501 + // Default parameters 1.1502 + mOutputFormat = OUTPUT_FORMAT_THREE_GPP; 1.1503 + mAudioEncoder = AUDIO_ENCODER_AMR_NB; 1.1504 + mVideoEncoder = VIDEO_ENCODER_H263; 1.1505 + mVideoWidth = 176; 1.1506 + mVideoHeight = 144; 1.1507 + mFrameRate = -1; 1.1508 + mVideoBitRate = 192000; 1.1509 + mSampleRate = 8000; 1.1510 + mAudioChannels = 1; 1.1511 + mAudioBitRate = 12200; 1.1512 + mInterleaveDurationUs = 0; 1.1513 + mIFramesIntervalSec = 1; 1.1514 + mAudioSourceNode = 0; 1.1515 + mUse64BitFileOffset = false; 1.1516 + mMovieTimeScale = -1; 1.1517 + mAudioTimeScale = -1; 1.1518 + mVideoTimeScale = -1; 1.1519 + mCameraId = 0; 1.1520 + mStartTimeOffsetMs = -1; 1.1521 + mVideoEncoderProfile = -1; 1.1522 + mVideoEncoderLevel = -1; 1.1523 + mMaxFileDurationUs = 0; 1.1524 + mMaxFileSizeBytes = 0; 1.1525 + mTrackEveryTimeDurationUs = 0; 1.1526 + mIsMetaDataStoredInVideoBuffers = false; 1.1527 + mEncoderProfiles = MediaProfiles::getInstance(); 1.1528 + mRotationDegrees = 0; 1.1529 + mLatitudex10000 = -3600000; 1.1530 + mLongitudex10000 = -3600000; 1.1531 + 1.1532 + mOutputFd = -1; 1.1533 + mCameraHw.clear(); 1.1534 + //TODO: May need to register a listener eventually 1.1535 + //if someone is interested in recorder events for now 1.1536 + //default to no listener registered 1.1537 + mListener = NULL; 1.1538 + 1.1539 + return OK; 1.1540 +} 1.1541 + 1.1542 +status_t GonkRecorder::getMaxAmplitude(int *max) { 1.1543 + RE_LOGV("getMaxAmplitude"); 1.1544 + 1.1545 + if (max == NULL) { 1.1546 + RE_LOGE("Null pointer argument"); 1.1547 + return BAD_VALUE; 1.1548 + } 1.1549 + 1.1550 + if (mAudioSourceNode != 0) { 1.1551 + *max = mAudioSourceNode->getMaxAmplitude(); 1.1552 + } else { 1.1553 + *max = 0; 1.1554 + } 1.1555 + 1.1556 + return OK; 1.1557 +} 1.1558 + 1.1559 +status_t GonkRecorder::dump( 1.1560 + int fd, const Vector<String16>& args) const { 1.1561 + RE_LOGV("dump"); 1.1562 + const size_t SIZE = 256; 1.1563 + char buffer[SIZE]; 1.1564 + String8 result; 1.1565 + if (mWriter != 0) { 1.1566 + mWriter->dump(fd, args); 1.1567 + } else { 1.1568 + snprintf(buffer, SIZE, " No file writer\n"); 1.1569 + result.append(buffer); 1.1570 + } 1.1571 + snprintf(buffer, SIZE, " Recorder: %p\n", this); 1.1572 + snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd); 1.1573 + result.append(buffer); 1.1574 + snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat); 1.1575 + result.append(buffer); 1.1576 + snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes); 1.1577 + result.append(buffer); 1.1578 + snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs); 1.1579 + result.append(buffer); 1.1580 + snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32); 1.1581 + result.append(buffer); 1.1582 + snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs); 1.1583 + result.append(buffer); 1.1584 + snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs); 1.1585 + result.append(buffer); 1.1586 + snprintf(buffer, SIZE, " Audio\n"); 1.1587 + result.append(buffer); 1.1588 + snprintf(buffer, SIZE, " Source: %d\n", mAudioSource); 1.1589 + result.append(buffer); 1.1590 + snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder); 1.1591 + result.append(buffer); 1.1592 + snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate); 1.1593 + result.append(buffer); 1.1594 + snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate); 1.1595 + result.append(buffer); 1.1596 + snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels); 1.1597 + result.append(buffer); 1.1598 + snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude()); 1.1599 + result.append(buffer); 1.1600 + snprintf(buffer, SIZE, " Video\n"); 1.1601 + result.append(buffer); 1.1602 + snprintf(buffer, SIZE, " Source: %d\n", mVideoSource); 1.1603 + result.append(buffer); 1.1604 + snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId); 1.1605 + result.append(buffer); 1.1606 + snprintf(buffer, SIZE, " Camera object address: %p\n", mCameraHw.get()); 1.1607 + result.append(buffer); 1.1608 + snprintf(buffer, SIZE, " Start time offset (ms): %d\n", mStartTimeOffsetMs); 1.1609 + result.append(buffer); 1.1610 + snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder); 1.1611 + result.append(buffer); 1.1612 + snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile); 1.1613 + result.append(buffer); 1.1614 + snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel); 1.1615 + result.append(buffer); 1.1616 + snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec); 1.1617 + result.append(buffer); 1.1618 + snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight); 1.1619 + result.append(buffer); 1.1620 + snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate); 1.1621 + result.append(buffer); 1.1622 + snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate); 1.1623 + result.append(buffer); 1.1624 + ::write(fd, result.string(), result.size()); 1.1625 + return OK; 1.1626 +} 1.1627 + 1.1628 +status_t GonkRecorder::setCamera(const sp<GonkCameraHardware>& aCameraHw) { 1.1629 + mCameraHw = aCameraHw; 1.1630 + return OK; 1.1631 +} 1.1632 + 1.1633 +} // namespace android