Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
1 /*
2 * Copyright (C) 2009 The Android Open Source Project
3 * Copyright (C) 2013 Mozilla Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
18 #include "nsDebug.h"
19 #define DOM_CAMERA_LOG_LEVEL 3
20 #include "CameraCommon.h"
21 #include "GonkCameraSource.h"
22 #include "GonkRecorder.h"
24 #define RE_LOGD(fmt, ...) DOM_CAMERA_LOGA("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
25 #define RE_LOGV(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
26 #define RE_LOGI(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
27 #define RE_LOGW(fmt, ...) DOM_CAMERA_LOGW("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
28 #define RE_LOGE(fmt, ...) DOM_CAMERA_LOGE("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__)
30 #include <binder/IPCThreadState.h>
31 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
32 # include <media/openmax/OMX_Audio.h>
33 #endif
34 #include <media/stagefright/foundation/ADebug.h>
35 #include <media/stagefright/AudioSource.h>
36 #include <media/stagefright/AMRWriter.h>
37 #include <media/stagefright/AACWriter.h>
38 #include <media/stagefright/MPEG2TSWriter.h>
39 #include <media/stagefright/MPEG4Writer.h>
40 #include <media/stagefright/MediaDefs.h>
41 #include <media/stagefright/MetaData.h>
42 #include <media/stagefright/OMXClient.h>
43 #include <media/stagefright/OMXCodec.h>
44 #include <media/MediaProfiles.h>
46 #include <utils/Errors.h>
47 #include <sys/types.h>
48 #include <ctype.h>
49 #include <unistd.h>
51 #include <cutils/properties.h>
52 #include <system/audio.h>
54 #define RES_720P (720 * 1280)
55 namespace android {
57 GonkRecorder::GonkRecorder()
58 : mWriter(NULL),
59 mOutputFd(-1),
60 mAudioSource(AUDIO_SOURCE_CNT),
61 mVideoSource(VIDEO_SOURCE_LIST_END),
62 mStarted(false) {
64 RE_LOGV("Constructor");
65 reset();
66 }
68 GonkRecorder::~GonkRecorder() {
69 RE_LOGV("Destructor");
70 stop();
71 }
73 status_t GonkRecorder::init() {
74 RE_LOGV("init");
75 return OK;
76 }
78 status_t GonkRecorder::setAudioSource(audio_source_t as) {
79 RE_LOGV("setAudioSource: %d", as);
80 if (as < AUDIO_SOURCE_DEFAULT ||
81 as >= AUDIO_SOURCE_CNT) {
82 RE_LOGE("Invalid audio source: %d", as);
83 return BAD_VALUE;
84 }
86 if (as == AUDIO_SOURCE_DEFAULT) {
87 mAudioSource = AUDIO_SOURCE_MIC;
88 } else {
89 mAudioSource = as;
90 }
92 return OK;
93 }
95 status_t GonkRecorder::setVideoSource(video_source vs) {
96 RE_LOGV("setVideoSource: %d", vs);
97 if (vs < VIDEO_SOURCE_DEFAULT ||
98 vs >= VIDEO_SOURCE_LIST_END) {
99 RE_LOGE("Invalid video source: %d", vs);
100 return BAD_VALUE;
101 }
103 if (vs == VIDEO_SOURCE_DEFAULT) {
104 mVideoSource = VIDEO_SOURCE_CAMERA;
105 } else {
106 mVideoSource = vs;
107 }
109 return OK;
110 }
112 status_t GonkRecorder::setOutputFormat(output_format of) {
113 RE_LOGV("setOutputFormat: %d", of);
114 if (of < OUTPUT_FORMAT_DEFAULT ||
115 of >= OUTPUT_FORMAT_LIST_END) {
116 RE_LOGE("Invalid output format: %d", of);
117 return BAD_VALUE;
118 }
120 if (of == OUTPUT_FORMAT_DEFAULT) {
121 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
122 } else {
123 mOutputFormat = of;
124 }
126 return OK;
127 }
129 status_t GonkRecorder::setAudioEncoder(audio_encoder ae) {
130 RE_LOGV("setAudioEncoder: %d", ae);
131 if (ae < AUDIO_ENCODER_DEFAULT ||
132 ae >= AUDIO_ENCODER_LIST_END) {
133 RE_LOGE("Invalid audio encoder: %d", ae);
134 return BAD_VALUE;
135 }
137 if (ae == AUDIO_ENCODER_DEFAULT) {
138 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
139 } else {
140 mAudioEncoder = ae;
141 }
143 return OK;
144 }
146 status_t GonkRecorder::setVideoEncoder(video_encoder ve) {
147 RE_LOGV("setVideoEncoder: %d", ve);
148 if (ve < VIDEO_ENCODER_DEFAULT ||
149 ve >= VIDEO_ENCODER_LIST_END) {
150 RE_LOGE("Invalid video encoder: %d", ve);
151 return BAD_VALUE;
152 }
154 if (ve == VIDEO_ENCODER_DEFAULT) {
155 mVideoEncoder = VIDEO_ENCODER_H263;
156 } else {
157 mVideoEncoder = ve;
158 }
160 return OK;
161 }
163 status_t GonkRecorder::setVideoSize(int width, int height) {
164 RE_LOGV("setVideoSize: %dx%d", width, height);
165 if (width <= 0 || height <= 0) {
166 RE_LOGE("Invalid video size: %dx%d", width, height);
167 return BAD_VALUE;
168 }
170 // Additional check on the dimension will be performed later
171 mVideoWidth = width;
172 mVideoHeight = height;
174 return OK;
175 }
177 status_t GonkRecorder::setVideoFrameRate(int frames_per_second) {
178 RE_LOGV("setVideoFrameRate: %d", frames_per_second);
179 if ((frames_per_second <= 0 && frames_per_second != -1) ||
180 frames_per_second > 120) {
181 RE_LOGE("Invalid video frame rate: %d", frames_per_second);
182 return BAD_VALUE;
183 }
185 // Additional check on the frame rate will be performed later
186 mFrameRate = frames_per_second;
188 return OK;
189 }
191 status_t GonkRecorder::setOutputFile(const char *path) {
192 RE_LOGE("setOutputFile(const char*) must not be called");
193 // We don't actually support this at all, as the media_server process
194 // no longer has permissions to create files.
196 return -EPERM;
197 }
199 status_t GonkRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
200 RE_LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
201 // These don't make any sense, do they?
202 CHECK_EQ(offset, 0ll);
203 CHECK_EQ(length, 0ll);
205 if (fd < 0) {
206 RE_LOGE("Invalid file descriptor: %d", fd);
207 return -EBADF;
208 }
210 if (mOutputFd >= 0) {
211 ::close(mOutputFd);
212 }
213 mOutputFd = dup(fd);
215 return OK;
216 }
218 // Attempt to parse an int64 literal optionally surrounded by whitespace,
219 // returns true on success, false otherwise.
220 static bool safe_strtoi64(const char *s, int64_t *val) {
221 char *end;
223 // It is lame, but according to man page, we have to set errno to 0
224 // before calling strtoll().
225 errno = 0;
226 *val = strtoll(s, &end, 10);
228 if (end == s || errno == ERANGE) {
229 return false;
230 }
232 // Skip trailing whitespace
233 while (isspace(*end)) {
234 ++end;
235 }
237 // For a successful return, the string must contain nothing but a valid
238 // int64 literal optionally surrounded by whitespace.
240 return *end == '\0';
241 }
243 // Return true if the value is in [0, 0x007FFFFFFF]
244 static bool safe_strtoi32(const char *s, int32_t *val) {
245 int64_t temp;
246 if (safe_strtoi64(s, &temp)) {
247 if (temp >= 0 && temp <= 0x007FFFFFFF) {
248 *val = static_cast<int32_t>(temp);
249 return true;
250 }
251 }
252 return false;
253 }
255 // Trim both leading and trailing whitespace from the given string.
256 static void TrimString(String8 *s) {
257 size_t num_bytes = s->bytes();
258 const char *data = s->string();
260 size_t leading_space = 0;
261 while (leading_space < num_bytes && isspace(data[leading_space])) {
262 ++leading_space;
263 }
265 size_t i = num_bytes;
266 while (i > leading_space && isspace(data[i - 1])) {
267 --i;
268 }
270 s->setTo(String8(&data[leading_space], i - leading_space));
271 }
273 status_t GonkRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
274 RE_LOGV("setParamAudioSamplingRate: %d", sampleRate);
275 if (sampleRate <= 0) {
276 RE_LOGE("Invalid audio sampling rate: %d", sampleRate);
277 return BAD_VALUE;
278 }
280 // Additional check on the sample rate will be performed later.
281 mSampleRate = sampleRate;
282 return OK;
283 }
285 status_t GonkRecorder::setParamAudioNumberOfChannels(int32_t channels) {
286 RE_LOGV("setParamAudioNumberOfChannels: %d", channels);
287 if (channels <= 0 || channels >= 3) {
288 RE_LOGE("Invalid number of audio channels: %d", channels);
289 return BAD_VALUE;
290 }
292 // Additional check on the number of channels will be performed later.
293 mAudioChannels = channels;
294 return OK;
295 }
297 status_t GonkRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
298 RE_LOGV("setParamAudioEncodingBitRate: %d", bitRate);
299 if (bitRate <= 0) {
300 RE_LOGE("Invalid audio encoding bit rate: %d", bitRate);
301 return BAD_VALUE;
302 }
304 // The target bit rate may not be exactly the same as the requested.
305 // It depends on many factors, such as rate control, and the bit rate
306 // range that a specific encoder supports. The mismatch between the
307 // the target and requested bit rate will NOT be treated as an error.
308 mAudioBitRate = bitRate;
309 return OK;
310 }
312 status_t GonkRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
313 RE_LOGV("setParamVideoEncodingBitRate: %d", bitRate);
314 if (bitRate <= 0) {
315 RE_LOGE("Invalid video encoding bit rate: %d", bitRate);
316 return BAD_VALUE;
317 }
319 // The target bit rate may not be exactly the same as the requested.
320 // It depends on many factors, such as rate control, and the bit rate
321 // range that a specific encoder supports. The mismatch between the
322 // the target and requested bit rate will NOT be treated as an error.
323 mVideoBitRate = bitRate;
324 return OK;
325 }
327 // Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
328 status_t GonkRecorder::setParamVideoRotation(int32_t degrees) {
329 RE_LOGV("setParamVideoRotation: %d", degrees);
330 if (degrees < 0 || degrees % 90 != 0) {
331 RE_LOGE("Unsupported video rotation angle: %d", degrees);
332 return BAD_VALUE;
333 }
334 mRotationDegrees = degrees % 360;
335 return OK;
336 }
338 status_t GonkRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
339 RE_LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
341 // This is meant for backward compatibility for MediaRecorder.java
342 if (timeUs <= 0) {
343 RE_LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
344 timeUs = 0; // Disable the duration limit for zero or negative values.
345 } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
346 RE_LOGE("Max file duration is too short: %lld us", timeUs);
347 return BAD_VALUE;
348 }
350 if (timeUs <= 15 * 1000000LL) {
351 RE_LOGW("Target duration (%lld us) too short to be respected", timeUs);
352 }
353 mMaxFileDurationUs = timeUs;
354 return OK;
355 }
357 status_t GonkRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
358 RE_LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
360 // This is meant for backward compatibility for MediaRecorder.java
361 if (bytes <= 0) {
362 RE_LOGW("Max file size is not positive: %lld bytes. "
363 "Disabling file size limit.", bytes);
364 bytes = 0; // Disable the file size limit for zero or negative values.
365 } else if (bytes <= 1024) { // XXX: 1 kB
366 RE_LOGE("Max file size is too small: %lld bytes", bytes);
367 return BAD_VALUE;
368 }
370 if (bytes <= 100 * 1024) {
371 RE_LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
372 }
374 if (bytes >= 0xffffffffLL) {
375 RE_LOGW("Target file size (%lld bytes) too large to be respected, clipping to 4GB", bytes);
376 bytes = 0xffffffffLL;
377 }
379 mMaxFileSizeBytes = bytes;
380 return OK;
381 }
383 status_t GonkRecorder::setParamInterleaveDuration(int32_t durationUs) {
384 RE_LOGV("setParamInterleaveDuration: %d", durationUs);
385 if (durationUs <= 500000) { // 500 ms
386 // If interleave duration is too small, it is very inefficient to do
387 // interleaving since the metadata overhead will count for a significant
388 // portion of the saved contents
389 RE_LOGE("Audio/video interleave duration is too small: %d us", durationUs);
390 return BAD_VALUE;
391 } else if (durationUs >= 10000000) { // 10 seconds
392 // If interleaving duration is too large, it can cause the recording
393 // session to use too much memory since we have to save the output
394 // data before we write them out
395 RE_LOGE("Audio/video interleave duration is too large: %d us", durationUs);
396 return BAD_VALUE;
397 }
398 mInterleaveDurationUs = durationUs;
399 return OK;
400 }
402 // If seconds < 0, only the first frame is I frame, and rest are all P frames
403 // If seconds == 0, all frames are encoded as I frames. No P frames
404 // If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames
405 status_t GonkRecorder::setParamVideoIFramesInterval(int32_t seconds) {
406 RE_LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
407 mIFramesIntervalSec = seconds;
408 return OK;
409 }
411 status_t GonkRecorder::setParam64BitFileOffset(bool use64Bit) {
412 RE_LOGV("setParam64BitFileOffset: %s",
413 use64Bit? "use 64 bit file offset": "use 32 bit file offset");
414 mUse64BitFileOffset = use64Bit;
415 return OK;
416 }
418 status_t GonkRecorder::setParamVideoCameraId(int32_t cameraId) {
419 RE_LOGV("setParamVideoCameraId: %d", cameraId);
420 if (cameraId < 0) {
421 return BAD_VALUE;
422 }
423 mCameraId = cameraId;
424 return OK;
425 }
427 status_t GonkRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
428 RE_LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
429 if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
430 RE_LOGE("Tracking time duration too short: %lld us", timeDurationUs);
431 return BAD_VALUE;
432 }
433 mTrackEveryTimeDurationUs = timeDurationUs;
434 return OK;
435 }
437 status_t GonkRecorder::setParamVideoEncoderProfile(int32_t profile) {
438 RE_LOGV("setParamVideoEncoderProfile: %d", profile);
440 // Additional check will be done later when we load the encoder.
441 // For now, we are accepting values defined in OpenMAX IL.
442 mVideoEncoderProfile = profile;
443 return OK;
444 }
446 status_t GonkRecorder::setParamVideoEncoderLevel(int32_t level) {
447 RE_LOGV("setParamVideoEncoderLevel: %d", level);
449 // Additional check will be done later when we load the encoder.
450 // For now, we are accepting values defined in OpenMAX IL.
451 mVideoEncoderLevel = level;
452 return OK;
453 }
455 status_t GonkRecorder::setParamMovieTimeScale(int32_t timeScale) {
456 RE_LOGV("setParamMovieTimeScale: %d", timeScale);
458 // The range is set to be the same as the audio's time scale range
459 // since audio's time scale has a wider range.
460 if (timeScale < 600 || timeScale > 96000) {
461 RE_LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
462 return BAD_VALUE;
463 }
464 mMovieTimeScale = timeScale;
465 return OK;
466 }
468 status_t GonkRecorder::setParamVideoTimeScale(int32_t timeScale) {
469 RE_LOGV("setParamVideoTimeScale: %d", timeScale);
471 // 60000 is chosen to make sure that each video frame from a 60-fps
472 // video has 1000 ticks.
473 if (timeScale < 600 || timeScale > 60000) {
474 RE_LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
475 return BAD_VALUE;
476 }
477 mVideoTimeScale = timeScale;
478 return OK;
479 }
481 status_t GonkRecorder::setParamAudioTimeScale(int32_t timeScale) {
482 RE_LOGV("setParamAudioTimeScale: %d", timeScale);
484 // 96000 Hz is the highest sampling rate support in AAC.
485 if (timeScale < 600 || timeScale > 96000) {
486 RE_LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
487 return BAD_VALUE;
488 }
489 mAudioTimeScale = timeScale;
490 return OK;
491 }
493 status_t GonkRecorder::setParamGeoDataLongitude(
494 int64_t longitudex10000) {
496 if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
497 return BAD_VALUE;
498 }
499 mLongitudex10000 = longitudex10000;
500 return OK;
501 }
503 status_t GonkRecorder::setParamGeoDataLatitude(
504 int64_t latitudex10000) {
506 if (latitudex10000 > 900000 || latitudex10000 < -900000) {
507 return BAD_VALUE;
508 }
509 mLatitudex10000 = latitudex10000;
510 return OK;
511 }
513 status_t GonkRecorder::setParameter(
514 const String8 &key, const String8 &value) {
515 RE_LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
516 if (key == "max-duration") {
517 int64_t max_duration_ms;
518 if (safe_strtoi64(value.string(), &max_duration_ms)) {
519 return setParamMaxFileDurationUs(1000LL * max_duration_ms);
520 }
521 } else if (key == "max-filesize") {
522 int64_t max_filesize_bytes;
523 if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
524 return setParamMaxFileSizeBytes(max_filesize_bytes);
525 }
526 } else if (key == "interleave-duration-us") {
527 int32_t durationUs;
528 if (safe_strtoi32(value.string(), &durationUs)) {
529 return setParamInterleaveDuration(durationUs);
530 }
531 } else if (key == "param-movie-time-scale") {
532 int32_t timeScale;
533 if (safe_strtoi32(value.string(), &timeScale)) {
534 return setParamMovieTimeScale(timeScale);
535 }
536 } else if (key == "param-use-64bit-offset") {
537 int32_t use64BitOffset;
538 if (safe_strtoi32(value.string(), &use64BitOffset)) {
539 return setParam64BitFileOffset(use64BitOffset != 0);
540 }
541 } else if (key == "param-geotag-longitude") {
542 int64_t longitudex10000;
543 if (safe_strtoi64(value.string(), &longitudex10000)) {
544 return setParamGeoDataLongitude(longitudex10000);
545 }
546 } else if (key == "param-geotag-latitude") {
547 int64_t latitudex10000;
548 if (safe_strtoi64(value.string(), &latitudex10000)) {
549 return setParamGeoDataLatitude(latitudex10000);
550 }
551 } else if (key == "param-track-time-status") {
552 int64_t timeDurationUs;
553 if (safe_strtoi64(value.string(), &timeDurationUs)) {
554 return setParamTrackTimeStatus(timeDurationUs);
555 }
556 } else if (key == "audio-param-sampling-rate") {
557 int32_t sampling_rate;
558 if (safe_strtoi32(value.string(), &sampling_rate)) {
559 return setParamAudioSamplingRate(sampling_rate);
560 }
561 } else if (key == "audio-param-number-of-channels") {
562 int32_t number_of_channels;
563 if (safe_strtoi32(value.string(), &number_of_channels)) {
564 return setParamAudioNumberOfChannels(number_of_channels);
565 }
566 } else if (key == "audio-param-encoding-bitrate") {
567 int32_t audio_bitrate;
568 if (safe_strtoi32(value.string(), &audio_bitrate)) {
569 return setParamAudioEncodingBitRate(audio_bitrate);
570 }
571 } else if (key == "audio-param-time-scale") {
572 int32_t timeScale;
573 if (safe_strtoi32(value.string(), &timeScale)) {
574 return setParamAudioTimeScale(timeScale);
575 }
576 } else if (key == "video-param-encoding-bitrate") {
577 int32_t video_bitrate;
578 if (safe_strtoi32(value.string(), &video_bitrate)) {
579 return setParamVideoEncodingBitRate(video_bitrate);
580 }
581 } else if (key == "video-param-rotation-angle-degrees") {
582 int32_t degrees;
583 if (safe_strtoi32(value.string(), °rees)) {
584 return setParamVideoRotation(degrees);
585 }
586 } else if (key == "video-param-i-frames-interval") {
587 int32_t seconds;
588 if (safe_strtoi32(value.string(), &seconds)) {
589 return setParamVideoIFramesInterval(seconds);
590 }
591 } else if (key == "video-param-encoder-profile") {
592 int32_t profile;
593 if (safe_strtoi32(value.string(), &profile)) {
594 return setParamVideoEncoderProfile(profile);
595 }
596 } else if (key == "video-param-encoder-level") {
597 int32_t level;
598 if (safe_strtoi32(value.string(), &level)) {
599 return setParamVideoEncoderLevel(level);
600 }
601 } else if (key == "video-param-camera-id") {
602 int32_t cameraId;
603 if (safe_strtoi32(value.string(), &cameraId)) {
604 return setParamVideoCameraId(cameraId);
605 }
606 } else if (key == "video-param-time-scale") {
607 int32_t timeScale;
608 if (safe_strtoi32(value.string(), &timeScale)) {
609 return setParamVideoTimeScale(timeScale);
610 }
611 } else {
612 RE_LOGE("setParameter: failed to find key %s", key.string());
613 }
614 return BAD_VALUE;
615 }
617 status_t GonkRecorder::setParameters(const String8 ¶ms) {
618 RE_LOGV("setParameters: %s", params.string());
619 const char *cparams = params.string();
620 const char *key_start = cparams;
621 for (;;) {
622 const char *equal_pos = strchr(key_start, '=');
623 if (equal_pos == NULL) {
624 RE_LOGE("Parameters %s miss a value", cparams);
625 return BAD_VALUE;
626 }
627 String8 key(key_start, equal_pos - key_start);
628 TrimString(&key);
629 if (key.length() == 0) {
630 RE_LOGE("Parameters %s contains an empty key", cparams);
631 return BAD_VALUE;
632 }
633 const char *value_start = equal_pos + 1;
634 const char *semicolon_pos = strchr(value_start, ';');
635 String8 value;
636 if (semicolon_pos == NULL) {
637 value.setTo(value_start);
638 } else {
639 value.setTo(value_start, semicolon_pos - value_start);
640 }
641 if (setParameter(key, value) != OK) {
642 return BAD_VALUE;
643 }
644 if (semicolon_pos == NULL) {
645 break; // Reaches the end
646 }
647 key_start = semicolon_pos + 1;
648 }
649 return OK;
650 }
652 status_t GonkRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
653 mListener = listener;
655 return OK;
656 }
658 status_t GonkRecorder::setClientName(const String16& clientName) {
659 mClientName = clientName;
661 return OK;
662 }
664 status_t GonkRecorder::prepare() {
665 if (mVideoSource != VIDEO_SOURCE_LIST_END && mVideoEncoder != VIDEO_ENCODER_LIST_END &&
666 mVideoHeight && mVideoWidth && // Video recording
667 (mVideoHeight * mVideoWidth >= RES_720P)) {
668 // TODO: Above check needs to be updated when mMaxFileDurationUs is set from camera app
669 RE_LOGV("Video is high resolution so setting 64-bit file offsets");
670 setParam64BitFileOffset(true);
671 }
672 return OK;
673 }
675 status_t GonkRecorder::start() {
676 CHECK_GE(mOutputFd, 0);
678 // Get UID here for permission checking
679 mClientUid = IPCThreadState::self()->getCallingUid();
680 if (mWriter != NULL) {
681 RE_LOGE("File writer is not avaialble");
682 return UNKNOWN_ERROR;
683 }
685 status_t status = OK;
687 switch (mOutputFormat) {
688 case OUTPUT_FORMAT_DEFAULT:
689 case OUTPUT_FORMAT_THREE_GPP:
690 case OUTPUT_FORMAT_MPEG_4:
691 status = startMPEG4Recording();
692 break;
694 case OUTPUT_FORMAT_AMR_NB:
695 case OUTPUT_FORMAT_AMR_WB:
696 status = startAMRRecording();
697 break;
699 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
700 case OUTPUT_FORMAT_AAC_ADIF:
701 case OUTPUT_FORMAT_AAC_ADTS:
702 status = startAACRecording();
703 break;
704 #endif
706 case OUTPUT_FORMAT_RTP_AVP:
707 status = startRTPRecording();
708 break;
710 case OUTPUT_FORMAT_MPEG2TS:
711 status = startMPEG2TSRecording();
712 break;
714 default:
715 RE_LOGE("Unsupported output file format: %d", mOutputFormat);
716 status = UNKNOWN_ERROR;
717 break;
718 }
720 if ((status == OK) && (!mStarted)) {
721 mStarted = true;
722 }
724 return status;
725 }
727 sp<MediaSource> GonkRecorder::createAudioSource() {
728 sp<AudioSource> audioSource =
729 new AudioSource(
730 mAudioSource,
731 mSampleRate,
732 mAudioChannels);
734 status_t err = audioSource->initCheck();
736 if (err != OK) {
737 RE_LOGE("audio source is not initialized");
738 return NULL;
739 }
741 sp<MetaData> encMeta = new MetaData;
742 const char *mime;
743 switch (mAudioEncoder) {
744 case AUDIO_ENCODER_AMR_NB:
745 case AUDIO_ENCODER_DEFAULT:
746 mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
747 break;
748 case AUDIO_ENCODER_AMR_WB:
749 mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
750 break;
751 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
752 case AUDIO_ENCODER_AAC:
753 mime = MEDIA_MIMETYPE_AUDIO_AAC;
754 encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC);
755 break;
756 case AUDIO_ENCODER_HE_AAC:
757 mime = MEDIA_MIMETYPE_AUDIO_AAC;
758 encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectHE);
759 break;
760 case AUDIO_ENCODER_AAC_ELD:
761 mime = MEDIA_MIMETYPE_AUDIO_AAC;
762 encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
763 break;
764 #endif
765 default:
766 RE_LOGE("Unknown audio encoder: %d", mAudioEncoder);
767 return NULL;
768 }
769 encMeta->setCString(kKeyMIMEType, mime);
771 int32_t maxInputSize;
772 CHECK(audioSource->getFormat()->findInt32(
773 kKeyMaxInputSize, &maxInputSize));
775 encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
776 encMeta->setInt32(kKeyChannelCount, mAudioChannels);
777 encMeta->setInt32(kKeySampleRate, mSampleRate);
778 encMeta->setInt32(kKeyBitRate, mAudioBitRate);
779 if (mAudioTimeScale > 0) {
780 encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
781 }
783 // OMXClient::connect() always returns OK and abort's fatally if
784 // it can't connect.
785 OMXClient client;
786 // CHECK_EQ causes an abort if the given condition fails.
787 CHECK_EQ(client.connect(), (status_t)OK);
788 sp<MediaSource> audioEncoder =
789 OMXCodec::Create(client.interface(), encMeta,
790 true /* createEncoder */, audioSource);
791 mAudioSourceNode = audioSource;
793 return audioEncoder;
794 }
796 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
797 status_t GonkRecorder::startAACRecording() {
798 // FIXME:
799 // Add support for OUTPUT_FORMAT_AAC_ADIF
800 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
802 CHECK(mAudioEncoder == AUDIO_ENCODER_AAC ||
803 mAudioEncoder == AUDIO_ENCODER_HE_AAC ||
804 mAudioEncoder == AUDIO_ENCODER_AAC_ELD);
805 CHECK(mAudioSource != AUDIO_SOURCE_CNT);
807 mWriter = new AACWriter(mOutputFd);
808 status_t status = startRawAudioRecording();
809 if (status != OK) {
810 mWriter.clear();
811 mWriter = NULL;
812 }
814 return status;
815 }
816 #endif
818 status_t GonkRecorder::startAMRRecording() {
819 CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
820 mOutputFormat == OUTPUT_FORMAT_AMR_WB);
822 if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
823 if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
824 mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
825 RE_LOGE("Invalid encoder %d used for AMRNB recording",
826 mAudioEncoder);
827 return BAD_VALUE;
828 }
829 } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
830 if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
831 RE_LOGE("Invlaid encoder %d used for AMRWB recording",
832 mAudioEncoder);
833 return BAD_VALUE;
834 }
835 }
837 mWriter = new AMRWriter(mOutputFd);
838 status_t status = startRawAudioRecording();
839 if (status != OK) {
840 mWriter.clear();
841 mWriter = NULL;
842 }
843 return status;
844 }
846 status_t GonkRecorder::startRawAudioRecording() {
847 if (mAudioSource >= AUDIO_SOURCE_CNT) {
848 RE_LOGE("Invalid audio source: %d", mAudioSource);
849 return BAD_VALUE;
850 }
852 status_t status = BAD_VALUE;
853 if (OK != (status = checkAudioEncoderCapabilities())) {
854 return status;
855 }
857 sp<MediaSource> audioEncoder = createAudioSource();
858 if (audioEncoder == NULL) {
859 return UNKNOWN_ERROR;
860 }
862 CHECK(mWriter != 0);
863 mWriter->addSource(audioEncoder);
865 if (mMaxFileDurationUs != 0) {
866 mWriter->setMaxFileDuration(mMaxFileDurationUs);
867 }
868 if (mMaxFileSizeBytes != 0) {
869 mWriter->setMaxFileSize(mMaxFileSizeBytes);
870 }
871 mWriter->setListener(mListener);
872 mWriter->start();
874 return OK;
875 }
877 status_t GonkRecorder::startRTPRecording() {
878 return INVALID_OPERATION;
879 }
881 status_t GonkRecorder::startMPEG2TSRecording() {
882 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
884 sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
886 if (mAudioSource != AUDIO_SOURCE_CNT) {
887 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
888 if (mAudioEncoder != AUDIO_ENCODER_AAC &&
889 mAudioEncoder != AUDIO_ENCODER_HE_AAC &&
890 mAudioEncoder != AUDIO_ENCODER_AAC_ELD) {
891 return ERROR_UNSUPPORTED;
892 }
893 #endif
894 status_t err = setupAudioEncoder(writer);
896 if (err != OK) {
897 return err;
898 }
899 }
901 if (mVideoSource < VIDEO_SOURCE_LIST_END) {
902 if (mVideoEncoder != VIDEO_ENCODER_H264) {
903 return ERROR_UNSUPPORTED;
904 }
906 sp<MediaSource> mediaSource;
907 status_t err = setupMediaSource(&mediaSource);
908 if (err != OK) {
909 return err;
910 }
912 sp<MediaSource> encoder;
913 err = setupVideoEncoder(mediaSource, mVideoBitRate, &encoder);
915 if (err != OK) {
916 return err;
917 }
919 writer->addSource(encoder);
920 }
922 if (mMaxFileDurationUs != 0) {
923 writer->setMaxFileDuration(mMaxFileDurationUs);
924 }
926 if (mMaxFileSizeBytes != 0) {
927 writer->setMaxFileSize(mMaxFileSizeBytes);
928 }
930 mWriter = writer;
932 return mWriter->start();
933 }
935 void GonkRecorder::clipVideoFrameRate() {
936 RE_LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
937 int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
938 "enc.vid.fps.min", mVideoEncoder);
939 int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
940 "enc.vid.fps.max", mVideoEncoder);
941 if (mFrameRate < minFrameRate && minFrameRate != -1) {
942 RE_LOGW("Intended video encoding frame rate (%d fps) is too small"
943 " and will be set to (%d fps)", mFrameRate, minFrameRate);
944 mFrameRate = minFrameRate;
945 } else if (mFrameRate > maxFrameRate && maxFrameRate != -1) {
946 RE_LOGW("Intended video encoding frame rate (%d fps) is too large"
947 " and will be set to (%d fps)", mFrameRate, maxFrameRate);
948 mFrameRate = maxFrameRate;
949 }
950 }
952 void GonkRecorder::clipVideoBitRate() {
953 RE_LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
954 int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
955 "enc.vid.bps.min", mVideoEncoder);
956 int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
957 "enc.vid.bps.max", mVideoEncoder);
958 if (mVideoBitRate < minBitRate && minBitRate != -1) {
959 RE_LOGW("Intended video encoding bit rate (%d bps) is too small"
960 " and will be set to (%d bps)", mVideoBitRate, minBitRate);
961 mVideoBitRate = minBitRate;
962 } else if (mVideoBitRate > maxBitRate && maxBitRate != -1) {
963 RE_LOGW("Intended video encoding bit rate (%d bps) is too large"
964 " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
965 mVideoBitRate = maxBitRate;
966 }
967 }
969 void GonkRecorder::clipVideoFrameWidth() {
970 RE_LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
971 int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
972 "enc.vid.width.min", mVideoEncoder);
973 int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
974 "enc.vid.width.max", mVideoEncoder);
975 if (mVideoWidth < minFrameWidth && minFrameWidth != -1) {
976 RE_LOGW("Intended video encoding frame width (%d) is too small"
977 " and will be set to (%d)", mVideoWidth, minFrameWidth);
978 mVideoWidth = minFrameWidth;
979 } else if (mVideoWidth > maxFrameWidth && maxFrameWidth != -1) {
980 RE_LOGW("Intended video encoding frame width (%d) is too large"
981 " and will be set to (%d)", mVideoWidth, maxFrameWidth);
982 mVideoWidth = maxFrameWidth;
983 }
984 }
986 status_t GonkRecorder::checkVideoEncoderCapabilities() {
988 // Dont clip for time lapse capture as encoder will have enough
989 // time to encode because of slow capture rate of time lapse.
990 clipVideoBitRate();
991 clipVideoFrameRate();
992 clipVideoFrameWidth();
993 clipVideoFrameHeight();
994 setDefaultProfileIfNecessary();
995 return OK;
996 }
998 // Set to use AVC baseline profile if the encoding parameters matches
999 // CAMCORDER_QUALITY_LOW profile; this is for the sake of MMS service.
1000 void GonkRecorder::setDefaultProfileIfNecessary() {
1001 RE_LOGV("setDefaultProfileIfNecessary");
1003 camcorder_quality quality = CAMCORDER_QUALITY_LOW;
1005 int64_t durationUs = mEncoderProfiles->getCamcorderProfileParamByName(
1006 "duration", mCameraId, quality) * 1000000LL;
1008 int fileFormat = mEncoderProfiles->getCamcorderProfileParamByName(
1009 "file.format", mCameraId, quality);
1011 int videoCodec = mEncoderProfiles->getCamcorderProfileParamByName(
1012 "vid.codec", mCameraId, quality);
1014 int videoBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
1015 "vid.bps", mCameraId, quality);
1017 int videoFrameRate = mEncoderProfiles->getCamcorderProfileParamByName(
1018 "vid.fps", mCameraId, quality);
1020 int videoFrameWidth = mEncoderProfiles->getCamcorderProfileParamByName(
1021 "vid.width", mCameraId, quality);
1023 int videoFrameHeight = mEncoderProfiles->getCamcorderProfileParamByName(
1024 "vid.height", mCameraId, quality);
1026 int audioCodec = mEncoderProfiles->getCamcorderProfileParamByName(
1027 "aud.codec", mCameraId, quality);
1029 int audioBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
1030 "aud.bps", mCameraId, quality);
1032 int audioSampleRate = mEncoderProfiles->getCamcorderProfileParamByName(
1033 "aud.hz", mCameraId, quality);
1035 int audioChannels = mEncoderProfiles->getCamcorderProfileParamByName(
1036 "aud.ch", mCameraId, quality);
1038 if (durationUs == mMaxFileDurationUs &&
1039 fileFormat == mOutputFormat &&
1040 videoCodec == mVideoEncoder &&
1041 videoBitRate == mVideoBitRate &&
1042 videoFrameRate == mFrameRate &&
1043 videoFrameWidth == mVideoWidth &&
1044 videoFrameHeight == mVideoHeight &&
1045 audioCodec == mAudioEncoder &&
1046 audioBitRate == mAudioBitRate &&
1047 audioSampleRate == mSampleRate &&
1048 audioChannels == mAudioChannels) {
1049 if (videoCodec == VIDEO_ENCODER_H264) {
1050 RE_LOGI("Force to use AVC baseline profile");
1051 setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline);
1052 }
1053 }
1054 }
1056 status_t GonkRecorder::checkAudioEncoderCapabilities() {
1057 clipAudioBitRate();
1058 clipAudioSampleRate();
1059 clipNumberOfAudioChannels();
1060 return OK;
1061 }
1063 void GonkRecorder::clipAudioBitRate() {
1064 RE_LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
1066 int minAudioBitRate =
1067 mEncoderProfiles->getAudioEncoderParamByName(
1068 "enc.aud.bps.min", mAudioEncoder);
1069 if (minAudioBitRate != -1 && mAudioBitRate < minAudioBitRate) {
1070 RE_LOGW("Intended audio encoding bit rate (%d) is too small"
1071 " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
1072 mAudioBitRate = minAudioBitRate;
1073 }
1075 int maxAudioBitRate =
1076 mEncoderProfiles->getAudioEncoderParamByName(
1077 "enc.aud.bps.max", mAudioEncoder);
1078 if (maxAudioBitRate != -1 && mAudioBitRate > maxAudioBitRate) {
1079 RE_LOGW("Intended audio encoding bit rate (%d) is too large"
1080 " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
1081 mAudioBitRate = maxAudioBitRate;
1082 }
1083 }
1085 void GonkRecorder::clipAudioSampleRate() {
1086 RE_LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
1088 int minSampleRate =
1089 mEncoderProfiles->getAudioEncoderParamByName(
1090 "enc.aud.hz.min", mAudioEncoder);
1091 if (minSampleRate != -1 && mSampleRate < minSampleRate) {
1092 RE_LOGW("Intended audio sample rate (%d) is too small"
1093 " and will be set to (%d)", mSampleRate, minSampleRate);
1094 mSampleRate = minSampleRate;
1095 }
1097 int maxSampleRate =
1098 mEncoderProfiles->getAudioEncoderParamByName(
1099 "enc.aud.hz.max", mAudioEncoder);
1100 if (maxSampleRate != -1 && mSampleRate > maxSampleRate) {
1101 RE_LOGW("Intended audio sample rate (%d) is too large"
1102 " and will be set to (%d)", mSampleRate, maxSampleRate);
1103 mSampleRate = maxSampleRate;
1104 }
1105 }
1107 void GonkRecorder::clipNumberOfAudioChannels() {
1108 RE_LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
1110 int minChannels =
1111 mEncoderProfiles->getAudioEncoderParamByName(
1112 "enc.aud.ch.min", mAudioEncoder);
1113 if (minChannels != -1 && mAudioChannels < minChannels) {
1114 RE_LOGW("Intended number of audio channels (%d) is too small"
1115 " and will be set to (%d)", mAudioChannels, minChannels);
1116 mAudioChannels = minChannels;
1117 }
1119 int maxChannels =
1120 mEncoderProfiles->getAudioEncoderParamByName(
1121 "enc.aud.ch.max", mAudioEncoder);
1122 if (maxChannels != -1 && mAudioChannels > maxChannels) {
1123 RE_LOGW("Intended number of audio channels (%d) is too large"
1124 " and will be set to (%d)", mAudioChannels, maxChannels);
1125 mAudioChannels = maxChannels;
1126 }
1127 }
1129 void GonkRecorder::clipVideoFrameHeight() {
1130 RE_LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
1131 int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1132 "enc.vid.height.min", mVideoEncoder);
1133 int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1134 "enc.vid.height.max", mVideoEncoder);
1135 if (minFrameHeight != -1 && mVideoHeight < minFrameHeight) {
1136 RE_LOGW("Intended video encoding frame height (%d) is too small"
1137 " and will be set to (%d)", mVideoHeight, minFrameHeight);
1138 mVideoHeight = minFrameHeight;
1139 } else if (maxFrameHeight != -1 && mVideoHeight > maxFrameHeight) {
1140 RE_LOGW("Intended video encoding frame height (%d) is too large"
1141 " and will be set to (%d)", mVideoHeight, maxFrameHeight);
1142 mVideoHeight = maxFrameHeight;
1143 }
1144 }
1146 // Set up the appropriate MediaSource depending on the chosen option
1147 status_t GonkRecorder::setupMediaSource(
1148 sp<MediaSource> *mediaSource) {
1149 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1150 || mVideoSource == VIDEO_SOURCE_CAMERA) {
1151 sp<GonkCameraSource> cameraSource;
1152 status_t err = setupCameraSource(&cameraSource);
1153 if (err != OK) {
1154 return err;
1155 }
1156 *mediaSource = cameraSource;
1157 } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
1158 return BAD_VALUE;
1159 } else {
1160 return INVALID_OPERATION;
1161 }
1162 return OK;
1163 }
1165 status_t GonkRecorder::setupCameraSource(
1166 sp<GonkCameraSource> *cameraSource) {
1167 status_t err = OK;
1168 if ((err = checkVideoEncoderCapabilities()) != OK) {
1169 return err;
1170 }
1171 Size videoSize;
1172 videoSize.width = mVideoWidth;
1173 videoSize.height = mVideoHeight;
1174 bool useMeta = true;
1175 char value[PROPERTY_VALUE_MAX];
1176 if (property_get("debug.camcorder.disablemeta", value, NULL) &&
1177 atoi(value)) {
1178 useMeta = false;
1179 }
1181 *cameraSource = GonkCameraSource::Create(
1182 mCameraHw, videoSize, mFrameRate, useMeta);
1183 if (*cameraSource == NULL) {
1184 return UNKNOWN_ERROR;
1185 }
1187 if ((*cameraSource)->initCheck() != OK) {
1188 (*cameraSource).clear();
1189 *cameraSource = NULL;
1190 return NO_INIT;
1191 }
1193 // When frame rate is not set, the actual frame rate will be set to
1194 // the current frame rate being used.
1195 if (mFrameRate == -1) {
1196 int32_t frameRate = 0;
1197 CHECK ((*cameraSource)->getFormat()->findInt32(
1198 kKeyFrameRate, &frameRate));
1199 RE_LOGI("Frame rate is not explicitly set. Use the current frame "
1200 "rate (%d fps)", frameRate);
1201 mFrameRate = frameRate;
1202 }
1204 CHECK(mFrameRate != -1);
1206 mIsMetaDataStoredInVideoBuffers =
1207 (*cameraSource)->isMetaDataStoredInVideoBuffers();
1209 return OK;
1210 }
1212 status_t GonkRecorder::setupVideoEncoder(
1213 sp<MediaSource> cameraSource,
1214 int32_t videoBitRate,
1215 sp<MediaSource> *source) {
1216 source->clear();
1218 sp<MetaData> enc_meta = new MetaData;
1219 enc_meta->setInt32(kKeyBitRate, videoBitRate);
1220 enc_meta->setInt32(kKeyFrameRate, mFrameRate);
1222 switch (mVideoEncoder) {
1223 case VIDEO_ENCODER_H263:
1224 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
1225 break;
1227 case VIDEO_ENCODER_MPEG_4_SP:
1228 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
1229 break;
1231 case VIDEO_ENCODER_H264:
1232 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
1233 break;
1235 default:
1236 CHECK(!"Should not be here, unsupported video encoding.");
1237 break;
1238 }
1240 sp<MetaData> meta = cameraSource->getFormat();
1242 int32_t width, height, stride, sliceHeight, colorFormat;
1243 CHECK(meta->findInt32(kKeyWidth, &width));
1244 CHECK(meta->findInt32(kKeyHeight, &height));
1245 CHECK(meta->findInt32(kKeyStride, &stride));
1246 CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
1247 CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
1249 enc_meta->setInt32(kKeyWidth, width);
1250 enc_meta->setInt32(kKeyHeight, height);
1251 enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
1252 enc_meta->setInt32(kKeyStride, stride);
1253 enc_meta->setInt32(kKeySliceHeight, sliceHeight);
1254 enc_meta->setInt32(kKeyColorFormat, colorFormat);
1255 if (mVideoTimeScale > 0) {
1256 enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
1257 }
1258 if (mVideoEncoderProfile != -1) {
1259 enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
1260 }
1261 if (mVideoEncoderLevel != -1) {
1262 enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
1263 }
1265 // OMXClient::connect() always returns OK and abort's fatally if
1266 // it can't connect.
1267 OMXClient client;
1268 // CHECK_EQ causes an abort if the given condition fails.
1269 CHECK_EQ(client.connect(), (status_t)OK);
1271 uint32_t encoder_flags = 0;
1272 if (mIsMetaDataStoredInVideoBuffers) {
1273 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
1274 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
1275 #else
1276 encoder_flags |= OMXCodec::kHardwareCodecsOnly;
1277 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
1278 encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
1279 #endif
1280 }
1282 sp<MediaSource> encoder = OMXCodec::Create(
1283 client.interface(), enc_meta,
1284 true /* createEncoder */, cameraSource,
1285 NULL, encoder_flags);
1286 if (encoder == NULL) {
1287 RE_LOGW("Failed to create the encoder");
1288 // When the encoder fails to be created, we need
1289 // release the camera source due to the camera's lock
1290 // and unlock mechanism.
1291 cameraSource->stop();
1292 return UNKNOWN_ERROR;
1293 }
1295 *source = encoder;
1297 return OK;
1298 }
1300 status_t GonkRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
1301 status_t status = BAD_VALUE;
1302 if (OK != (status = checkAudioEncoderCapabilities())) {
1303 return status;
1304 }
1306 switch(mAudioEncoder) {
1307 case AUDIO_ENCODER_AMR_NB:
1308 case AUDIO_ENCODER_AMR_WB:
1309 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
1310 case AUDIO_ENCODER_AAC:
1311 case AUDIO_ENCODER_HE_AAC:
1312 case AUDIO_ENCODER_AAC_ELD:
1313 #endif
1314 break;
1316 default:
1317 RE_LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1318 return UNKNOWN_ERROR;
1319 }
1321 sp<MediaSource> audioEncoder = createAudioSource();
1322 if (audioEncoder == NULL) {
1323 return UNKNOWN_ERROR;
1324 }
1326 writer->addSource(audioEncoder);
1327 return OK;
1328 }
1330 status_t GonkRecorder::setupMPEG4Recording(
1331 int outputFd,
1332 int32_t videoWidth, int32_t videoHeight,
1333 int32_t videoBitRate,
1334 int32_t *totalBitRate,
1335 sp<MediaWriter> *mediaWriter) {
1336 mediaWriter->clear();
1337 *totalBitRate = 0;
1338 status_t err = OK;
1339 sp<MediaWriter> writer = new MPEG4Writer(outputFd);
1341 if (mVideoSource < VIDEO_SOURCE_LIST_END) {
1343 sp<MediaSource> mediaSource;
1344 err = setupMediaSource(&mediaSource);
1345 if (err != OK) {
1346 return err;
1347 }
1349 sp<MediaSource> encoder;
1350 err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);
1351 if (err != OK) {
1352 return err;
1353 }
1355 writer->addSource(encoder);
1356 *totalBitRate += videoBitRate;
1357 }
1359 // Audio source is added at the end if it exists.
1360 // This help make sure that the "recoding" sound is suppressed for
1361 // camcorder applications in the recorded files.
1362 if (mAudioSource != AUDIO_SOURCE_CNT) {
1363 err = setupAudioEncoder(writer);
1364 if (err != OK) return err;
1365 *totalBitRate += mAudioBitRate;
1366 }
1368 if (mInterleaveDurationUs > 0) {
1369 reinterpret_cast<MPEG4Writer *>(writer.get())->
1370 setInterleaveDuration(mInterleaveDurationUs);
1371 }
1372 if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
1373 reinterpret_cast<MPEG4Writer *>(writer.get())->
1374 setGeoData(mLatitudex10000, mLongitudex10000);
1375 }
1376 if (mMaxFileDurationUs != 0) {
1377 writer->setMaxFileDuration(mMaxFileDurationUs);
1378 }
1379 if (mMaxFileSizeBytes != 0) {
1380 writer->setMaxFileSize(mMaxFileSizeBytes);
1381 }
1383 mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
1384 if (mStartTimeOffsetMs > 0) {
1385 reinterpret_cast<MPEG4Writer *>(writer.get())->
1386 setStartTimeOffsetMs(mStartTimeOffsetMs);
1387 }
1389 writer->setListener(mListener);
1390 *mediaWriter = writer;
1391 return OK;
1392 }
1394 void GonkRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
1395 sp<MetaData> *meta) {
1396 (*meta)->setInt64(kKeyTime, startTimeUs);
1397 (*meta)->setInt32(kKeyFileType, mOutputFormat);
1398 (*meta)->setInt32(kKeyBitRate, totalBitRate);
1399 (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
1400 if (mMovieTimeScale > 0) {
1401 (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
1402 }
1403 if (mTrackEveryTimeDurationUs > 0) {
1404 (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
1405 }
1407 char value[PROPERTY_VALUE_MAX];
1408 if (property_get("debug.camcorder.rotation", value, 0) > 0 && atoi(value) >= 0) {
1409 mRotationDegrees = atoi(value);
1410 RE_LOGI("Setting rotation to %d", mRotationDegrees );
1411 }
1413 if (mRotationDegrees != 0) {
1414 (*meta)->setInt32(kKeyRotation, mRotationDegrees);
1415 }
1416 }
1418 status_t GonkRecorder::startMPEG4Recording() {
1419 int32_t totalBitRate;
1420 status_t err = setupMPEG4Recording(
1421 mOutputFd, mVideoWidth, mVideoHeight,
1422 mVideoBitRate, &totalBitRate, &mWriter);
1423 if (err != OK) {
1424 return err;
1425 }
1427 //systemTime() doesn't give correct time because
1428 //HAVE_POSIX_CLOCKS is not defined for utils/Timers.cpp
1429 //so, using clock_gettime directly
1430 #include <time.h>
1431 struct timespec t;
1432 clock_gettime(CLOCK_MONOTONIC, &t);
1433 int64_t startTimeUs = int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
1434 startTimeUs = startTimeUs / 1000;
1435 sp<MetaData> meta = new MetaData;
1436 setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
1438 err = mWriter->start(meta.get());
1439 if (err != OK) {
1440 return err;
1441 }
1443 return OK;
1444 }
1446 status_t GonkRecorder::pause() {
1447 RE_LOGV("pause");
1448 if (mWriter == NULL) {
1449 return UNKNOWN_ERROR;
1450 }
1451 mWriter->pause();
1453 if (mStarted) {
1454 mStarted = false;
1455 }
1458 return OK;
1459 }
1461 status_t GonkRecorder::stop() {
1462 RE_LOGV("stop");
1463 status_t err = OK;
1465 if (mWriter != NULL) {
1466 err = mWriter->stop();
1467 mWriter.clear();
1468 }
1470 if (mOutputFd >= 0) {
1471 ::close(mOutputFd);
1472 mOutputFd = -1;
1473 }
1475 if (mStarted) {
1476 mStarted = false;
1477 }
1480 return err;
1481 }
1483 status_t GonkRecorder::close() {
1484 RE_LOGV("close");
1485 stop();
1487 return OK;
1488 }
1490 status_t GonkRecorder::reset() {
1491 RE_LOGV("reset");
1492 stop();
1494 // No audio or video source by default
1495 mAudioSource = AUDIO_SOURCE_CNT;
1496 mVideoSource = VIDEO_SOURCE_LIST_END;
1498 // Default parameters
1499 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
1500 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
1501 mVideoEncoder = VIDEO_ENCODER_H263;
1502 mVideoWidth = 176;
1503 mVideoHeight = 144;
1504 mFrameRate = -1;
1505 mVideoBitRate = 192000;
1506 mSampleRate = 8000;
1507 mAudioChannels = 1;
1508 mAudioBitRate = 12200;
1509 mInterleaveDurationUs = 0;
1510 mIFramesIntervalSec = 1;
1511 mAudioSourceNode = 0;
1512 mUse64BitFileOffset = false;
1513 mMovieTimeScale = -1;
1514 mAudioTimeScale = -1;
1515 mVideoTimeScale = -1;
1516 mCameraId = 0;
1517 mStartTimeOffsetMs = -1;
1518 mVideoEncoderProfile = -1;
1519 mVideoEncoderLevel = -1;
1520 mMaxFileDurationUs = 0;
1521 mMaxFileSizeBytes = 0;
1522 mTrackEveryTimeDurationUs = 0;
1523 mIsMetaDataStoredInVideoBuffers = false;
1524 mEncoderProfiles = MediaProfiles::getInstance();
1525 mRotationDegrees = 0;
1526 mLatitudex10000 = -3600000;
1527 mLongitudex10000 = -3600000;
1529 mOutputFd = -1;
1530 mCameraHw.clear();
1531 //TODO: May need to register a listener eventually
1532 //if someone is interested in recorder events for now
1533 //default to no listener registered
1534 mListener = NULL;
1536 return OK;
1537 }
1539 status_t GonkRecorder::getMaxAmplitude(int *max) {
1540 RE_LOGV("getMaxAmplitude");
1542 if (max == NULL) {
1543 RE_LOGE("Null pointer argument");
1544 return BAD_VALUE;
1545 }
1547 if (mAudioSourceNode != 0) {
1548 *max = mAudioSourceNode->getMaxAmplitude();
1549 } else {
1550 *max = 0;
1551 }
1553 return OK;
1554 }
1556 status_t GonkRecorder::dump(
1557 int fd, const Vector<String16>& args) const {
1558 RE_LOGV("dump");
1559 const size_t SIZE = 256;
1560 char buffer[SIZE];
1561 String8 result;
1562 if (mWriter != 0) {
1563 mWriter->dump(fd, args);
1564 } else {
1565 snprintf(buffer, SIZE, " No file writer\n");
1566 result.append(buffer);
1567 }
1568 snprintf(buffer, SIZE, " Recorder: %p\n", this);
1569 snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
1570 result.append(buffer);
1571 snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
1572 result.append(buffer);
1573 snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1574 result.append(buffer);
1575 snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
1576 result.append(buffer);
1577 snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1578 result.append(buffer);
1579 snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
1580 result.append(buffer);
1581 snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1582 result.append(buffer);
1583 snprintf(buffer, SIZE, " Audio\n");
1584 result.append(buffer);
1585 snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
1586 result.append(buffer);
1587 snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
1588 result.append(buffer);
1589 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
1590 result.append(buffer);
1591 snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
1592 result.append(buffer);
1593 snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
1594 result.append(buffer);
1595 snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1596 result.append(buffer);
1597 snprintf(buffer, SIZE, " Video\n");
1598 result.append(buffer);
1599 snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
1600 result.append(buffer);
1601 snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
1602 result.append(buffer);
1603 snprintf(buffer, SIZE, " Camera object address: %p\n", mCameraHw.get());
1604 result.append(buffer);
1605 snprintf(buffer, SIZE, " Start time offset (ms): %d\n", mStartTimeOffsetMs);
1606 result.append(buffer);
1607 snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
1608 result.append(buffer);
1609 snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
1610 result.append(buffer);
1611 snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
1612 result.append(buffer);
1613 snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec);
1614 result.append(buffer);
1615 snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1616 result.append(buffer);
1617 snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
1618 result.append(buffer);
1619 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
1620 result.append(buffer);
1621 ::write(fd, result.string(), result.size());
1622 return OK;
1623 }
1625 status_t GonkRecorder::setCamera(const sp<GonkCameraHardware>& aCameraHw) {
1626 mCameraHw = aCameraHw;
1627 return OK;
1628 }
1630 } // namespace android