dom/camera/GonkRecorder.cpp

changeset 0
6474c204b198
     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(), &degrees)) {
   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 &params) {
   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

mercurial