blob: f134cba9b2879a6aa88211bb5cad914534fe89f4 [file] [log] [blame]
Andreas Huberea6a38c2009-11-16 15:43:38 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "StagefrightRecorder"
19#include <utils/Log.h>
20
21#include "StagefrightRecorder.h"
22
Andreas Huber996dddf2010-01-25 15:30:31 -080023#include <media/stagefright/AudioSource.h>
24#include <media/stagefright/AMRWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080025#include <media/stagefright/CameraSource.h>
Nipun Kwatra239f2e52010-08-31 15:35:44 -070026#include <media/stagefright/VideoSourceDownSampler.h>
Nipun Kwatraf9b80182010-07-12 09:17:14 -070027#include <media/stagefright/CameraSourceTimeLapse.h>
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070028#include <media/stagefright/MediaSourceSplitter.h>
Andreas Huber9adf4662010-10-12 14:17:45 -070029#include <media/stagefright/MPEG2TSWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080030#include <media/stagefright/MPEG4Writer.h>
31#include <media/stagefright/MediaDebug.h>
32#include <media/stagefright/MediaDefs.h>
33#include <media/stagefright/MetaData.h>
34#include <media/stagefright/OMXClient.h>
35#include <media/stagefright/OMXCodec.h>
James Dong42a18c02010-06-16 17:27:46 -070036#include <media/MediaProfiles.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080037#include <camera/ICamera.h>
James Dong2cd841d2010-05-11 11:46:59 -070038#include <camera/CameraParameters.h>
Jamie Gennis85cfdd02010-08-10 16:37:53 -070039#include <surfaceflinger/Surface.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080040#include <utils/Errors.h>
James Dongb00e2462010-04-26 17:48:26 -070041#include <sys/types.h>
James Dongabed93a2010-04-22 17:27:04 -070042#include <ctype.h>
Nipun Kwatra453e92f2010-08-04 14:26:45 -070043#include <unistd.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080044
Andreas Huber57648e42010-08-04 10:14:30 -070045#include "ARTPWriter.h"
46
Andreas Huberea6a38c2009-11-16 15:43:38 -080047namespace android {
48
James Dongc0ab2a62010-06-29 16:29:19 -070049StagefrightRecorder::StagefrightRecorder()
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070050 : mWriter(NULL), mWriterAux(NULL),
51 mOutputFd(-1), mOutputFdAux(-1) {
James Dongc0ab2a62010-06-29 16:29:19 -070052
53 LOGV("Constructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080054 reset();
55}
56
57StagefrightRecorder::~StagefrightRecorder() {
James Dongc0ab2a62010-06-29 16:29:19 -070058 LOGV("Destructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080059 stop();
Andreas Huberea6a38c2009-11-16 15:43:38 -080060}
61
62status_t StagefrightRecorder::init() {
James Dongc0ab2a62010-06-29 16:29:19 -070063 LOGV("init");
Andreas Huberea6a38c2009-11-16 15:43:38 -080064 return OK;
65}
66
67status_t StagefrightRecorder::setAudioSource(audio_source as) {
James Dongc0ab2a62010-06-29 16:29:19 -070068 LOGV("setAudioSource: %d", as);
69 if (as < AUDIO_SOURCE_DEFAULT ||
70 as >= AUDIO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -070071 LOGE("Invalid audio source: %d", as);
James Dongc0ab2a62010-06-29 16:29:19 -070072 return BAD_VALUE;
73 }
74
75 if (as == AUDIO_SOURCE_DEFAULT) {
76 mAudioSource = AUDIO_SOURCE_MIC;
77 } else {
78 mAudioSource = as;
79 }
Andreas Huberea6a38c2009-11-16 15:43:38 -080080
81 return OK;
82}
83
84status_t StagefrightRecorder::setVideoSource(video_source vs) {
James Dongc0ab2a62010-06-29 16:29:19 -070085 LOGV("setVideoSource: %d", vs);
86 if (vs < VIDEO_SOURCE_DEFAULT ||
87 vs >= VIDEO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -070088 LOGE("Invalid video source: %d", vs);
James Dongc0ab2a62010-06-29 16:29:19 -070089 return BAD_VALUE;
90 }
91
92 if (vs == VIDEO_SOURCE_DEFAULT) {
93 mVideoSource = VIDEO_SOURCE_CAMERA;
94 } else {
95 mVideoSource = vs;
96 }
Andreas Huberea6a38c2009-11-16 15:43:38 -080097
98 return OK;
99}
100
101status_t StagefrightRecorder::setOutputFormat(output_format of) {
James Dongc0ab2a62010-06-29 16:29:19 -0700102 LOGV("setOutputFormat: %d", of);
103 if (of < OUTPUT_FORMAT_DEFAULT ||
104 of >= OUTPUT_FORMAT_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700105 LOGE("Invalid output format: %d", of);
James Dongc0ab2a62010-06-29 16:29:19 -0700106 return BAD_VALUE;
107 }
108
109 if (of == OUTPUT_FORMAT_DEFAULT) {
110 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
111 } else {
112 mOutputFormat = of;
113 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800114
115 return OK;
116}
117
118status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
James Dongc0ab2a62010-06-29 16:29:19 -0700119 LOGV("setAudioEncoder: %d", ae);
120 if (ae < AUDIO_ENCODER_DEFAULT ||
121 ae >= AUDIO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700122 LOGE("Invalid audio encoder: %d", ae);
James Dongc0ab2a62010-06-29 16:29:19 -0700123 return BAD_VALUE;
124 }
125
126 if (ae == AUDIO_ENCODER_DEFAULT) {
127 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
128 } else {
129 mAudioEncoder = ae;
130 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800131
132 return OK;
133}
134
135status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
James Dongc0ab2a62010-06-29 16:29:19 -0700136 LOGV("setVideoEncoder: %d", ve);
137 if (ve < VIDEO_ENCODER_DEFAULT ||
138 ve >= VIDEO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700139 LOGE("Invalid video encoder: %d", ve);
James Dongc0ab2a62010-06-29 16:29:19 -0700140 return BAD_VALUE;
141 }
142
143 if (ve == VIDEO_ENCODER_DEFAULT) {
144 mVideoEncoder = VIDEO_ENCODER_H263;
145 } else {
146 mVideoEncoder = ve;
147 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800148
149 return OK;
150}
151
152status_t StagefrightRecorder::setVideoSize(int width, int height) {
James Dongc0ab2a62010-06-29 16:29:19 -0700153 LOGV("setVideoSize: %dx%d", width, height);
James Dong2cd841d2010-05-11 11:46:59 -0700154 if (width <= 0 || height <= 0) {
155 LOGE("Invalid video size: %dx%d", width, height);
156 return BAD_VALUE;
157 }
158
159 // Additional check on the dimension will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800160 mVideoWidth = width;
161 mVideoHeight = height;
162
163 return OK;
164}
165
166status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
James Dongc0ab2a62010-06-29 16:29:19 -0700167 LOGV("setVideoFrameRate: %d", frames_per_second);
James Dongb15f2ea2010-10-24 09:32:39 -0700168 if ((frames_per_second <= 0 && frames_per_second != -1) ||
169 frames_per_second > 120) {
James Dong2cd841d2010-05-11 11:46:59 -0700170 LOGE("Invalid video frame rate: %d", frames_per_second);
171 return BAD_VALUE;
172 }
173
174 // Additional check on the frame rate will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800175 mFrameRate = frames_per_second;
176
177 return OK;
178}
179
180status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
James Dong71d714c2010-06-09 15:57:48 -0700181 LOGV("setCamera");
James Dongb00e2462010-04-26 17:48:26 -0700182 if (camera == 0) {
183 LOGE("camera is NULL");
James Dong7b06de62010-06-30 12:41:16 -0700184 return BAD_VALUE;
James Dongb00e2462010-04-26 17:48:26 -0700185 }
186
James Dong0c128b62010-10-08 11:59:32 -0700187 mCamera = camera;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800188 return OK;
189}
190
Jamie Gennis85cfdd02010-08-10 16:37:53 -0700191status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
James Dongc0ab2a62010-06-29 16:29:19 -0700192 LOGV("setPreviewSurface: %p", surface.get());
Andreas Huberea6a38c2009-11-16 15:43:38 -0800193 mPreviewSurface = surface;
194
195 return OK;
196}
197
198status_t StagefrightRecorder::setOutputFile(const char *path) {
James Dong7b06de62010-06-30 12:41:16 -0700199 LOGE("setOutputFile(const char*) must not be called");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800200 // We don't actually support this at all, as the media_server process
201 // no longer has permissions to create files.
202
James Dong7b06de62010-06-30 12:41:16 -0700203 return -EPERM;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800204}
205
206status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
James Dongc0ab2a62010-06-29 16:29:19 -0700207 LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800208 // These don't make any sense, do they?
209 CHECK_EQ(offset, 0);
210 CHECK_EQ(length, 0);
211
James Dong7b06de62010-06-30 12:41:16 -0700212 if (fd < 0) {
213 LOGE("Invalid file descriptor: %d", fd);
214 return -EBADF;
215 }
216
Andreas Huberea6a38c2009-11-16 15:43:38 -0800217 if (mOutputFd >= 0) {
218 ::close(mOutputFd);
219 }
220 mOutputFd = dup(fd);
221
222 return OK;
223}
224
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700225status_t StagefrightRecorder::setOutputFileAuxiliary(int fd) {
226 LOGV("setOutputFileAuxiliary: %d", fd);
227
228 if (fd < 0) {
229 LOGE("Invalid file descriptor: %d", fd);
230 return -EBADF;
231 }
232
233 mCaptureAuxVideo = true;
234
235 if (mOutputFdAux >= 0) {
236 ::close(mOutputFdAux);
237 }
238 mOutputFdAux = dup(fd);
239
240 return OK;
241}
242
James Dongabed93a2010-04-22 17:27:04 -0700243// Attempt to parse an int64 literal optionally surrounded by whitespace,
244// returns true on success, false otherwise.
James Dong2cd841d2010-05-11 11:46:59 -0700245static bool safe_strtoi64(const char *s, int64_t *val) {
James Dongabed93a2010-04-22 17:27:04 -0700246 char *end;
James Dong2cd841d2010-05-11 11:46:59 -0700247 *val = strtoll(s, &end, 10);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800248
James Dongabed93a2010-04-22 17:27:04 -0700249 if (end == s || errno == ERANGE) {
250 return false;
251 }
252
253 // Skip trailing whitespace
254 while (isspace(*end)) {
255 ++end;
256 }
257
258 // For a successful return, the string must contain nothing but a valid
259 // int64 literal optionally surrounded by whitespace.
260
261 return *end == '\0';
262}
263
James Dong2cd841d2010-05-11 11:46:59 -0700264// Return true if the value is in [0, 0x007FFFFFFF]
265static bool safe_strtoi32(const char *s, int32_t *val) {
266 int64_t temp;
267 if (safe_strtoi64(s, &temp)) {
268 if (temp >= 0 && temp <= 0x007FFFFFFF) {
269 *val = static_cast<int32_t>(temp);
270 return true;
271 }
272 }
273 return false;
274}
275
James Dongabed93a2010-04-22 17:27:04 -0700276// Trim both leading and trailing whitespace from the given string.
277static void TrimString(String8 *s) {
278 size_t num_bytes = s->bytes();
279 const char *data = s->string();
280
281 size_t leading_space = 0;
282 while (leading_space < num_bytes && isspace(data[leading_space])) {
283 ++leading_space;
284 }
285
286 size_t i = num_bytes;
287 while (i > leading_space && isspace(data[i - 1])) {
288 --i;
289 }
290
291 s->setTo(String8(&data[leading_space], i - leading_space));
292}
293
294status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
295 LOGV("setParamAudioSamplingRate: %d", sampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700296 if (sampleRate <= 0) {
297 LOGE("Invalid audio sampling rate: %d", sampleRate);
298 return BAD_VALUE;
299 }
300
301 // Additional check on the sample rate will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700302 mSampleRate = sampleRate;
303 return OK;
304}
305
306status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
307 LOGV("setParamAudioNumberOfChannels: %d", channels);
James Dong2cd841d2010-05-11 11:46:59 -0700308 if (channels <= 0 || channels >= 3) {
309 LOGE("Invalid number of audio channels: %d", channels);
James Dong7b06de62010-06-30 12:41:16 -0700310 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700311 }
312
313 // Additional check on the number of channels will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700314 mAudioChannels = channels;
315 return OK;
316}
317
318status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
319 LOGV("setParamAudioEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700320 if (bitRate <= 0) {
321 LOGE("Invalid audio encoding bit rate: %d", bitRate);
322 return BAD_VALUE;
323 }
324
325 // The target bit rate may not be exactly the same as the requested.
326 // It depends on many factors, such as rate control, and the bit rate
327 // range that a specific encoder supports. The mismatch between the
328 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700329 mAudioBitRate = bitRate;
330 return OK;
331}
332
333status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
334 LOGV("setParamVideoEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700335 if (bitRate <= 0) {
336 LOGE("Invalid video encoding bit rate: %d", bitRate);
337 return BAD_VALUE;
338 }
339
340 // The target bit rate may not be exactly the same as the requested.
341 // It depends on many factors, such as rate control, and the bit rate
342 // range that a specific encoder supports. The mismatch between the
343 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700344 mVideoBitRate = bitRate;
345 return OK;
346}
347
James Dongb9d7e012010-11-09 11:15:47 -0800348// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
349status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
350 LOGV("setParamVideoRotation: %d", degrees);
351 if (degrees < 0 || degrees % 90 != 0) {
352 LOGE("Unsupported video rotation angle: %d", degrees);
353 return BAD_VALUE;
354 }
355 mRotationDegrees = degrees % 360;
356 return OK;
357}
358
James Dong7b06de62010-06-30 12:41:16 -0700359status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
360 LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
James Dong26ea64c2010-12-20 11:39:38 -0800361
362 // This is meant for backward compatibility for MediaRecorder.java
Nipun Kwatrafb457482010-08-18 15:19:19 -0700363 if (timeUs <= 0) {
364 LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
365 timeUs = 0; // Disable the duration limit for zero or negative values.
366 } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
James Dong7b06de62010-06-30 12:41:16 -0700367 LOGE("Max file duration is too short: %lld us", timeUs);
368 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700369 }
Nipun Kwatrafb457482010-08-18 15:19:19 -0700370
James Dong5cdcf162010-11-30 18:18:08 -0800371 if (timeUs <= 15 * 1000000LL) {
372 LOGW("Target duration (%lld us) too short to be respected", timeUs);
373 }
James Dong7b06de62010-06-30 12:41:16 -0700374 mMaxFileDurationUs = timeUs;
375 return OK;
376}
377
378status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
379 LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
James Dong26ea64c2010-12-20 11:39:38 -0800380
381 // This is meant for backward compatibility for MediaRecorder.java
382 if (bytes <= 0) {
383 LOGW("Max file size is not positive: %lld bytes. "
384 "Disabling file size limit.", bytes);
385 bytes = 0; // Disable the file size limit for zero or negative values.
386 } else if (bytes <= 1024) { // XXX: 1 kB
James Dong7b06de62010-06-30 12:41:16 -0700387 LOGE("Max file size is too small: %lld bytes", bytes);
388 return BAD_VALUE;
389 }
James Dong5cdcf162010-11-30 18:18:08 -0800390
391 if (bytes <= 100 * 1024) {
392 LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
393 }
394
James Dong7b06de62010-06-30 12:41:16 -0700395 mMaxFileSizeBytes = bytes;
James Dongabed93a2010-04-22 17:27:04 -0700396 return OK;
397}
398
James Dong3300e962010-04-21 16:14:15 -0700399status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
400 LOGV("setParamInterleaveDuration: %d", durationUs);
James Dong1244eab2010-06-08 11:58:53 -0700401 if (durationUs <= 500000) { // 500 ms
402 // If interleave duration is too small, it is very inefficient to do
403 // interleaving since the metadata overhead will count for a significant
404 // portion of the saved contents
James Dong2cd841d2010-05-11 11:46:59 -0700405 LOGE("Audio/video interleave duration is too small: %d us", durationUs);
406 return BAD_VALUE;
James Dong1244eab2010-06-08 11:58:53 -0700407 } else if (durationUs >= 10000000) { // 10 seconds
408 // If interleaving duration is too large, it can cause the recording
409 // session to use too much memory since we have to save the output
410 // data before we write them out
411 LOGE("Audio/video interleave duration is too large: %d us", durationUs);
412 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700413 }
James Dong3300e962010-04-21 16:14:15 -0700414 mInterleaveDurationUs = durationUs;
415 return OK;
416}
James Dong2cd841d2010-05-11 11:46:59 -0700417
James Dong52d13f02010-07-02 11:39:06 -0700418// If seconds < 0, only the first frame is I frame, and rest are all P frames
419// If seconds == 0, all frames are encoded as I frames. No P frames
420// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames
421status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
422 LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
423 mIFramesIntervalSec = seconds;
James Dong1244eab2010-06-08 11:58:53 -0700424 return OK;
425}
426
James Dong6feaa462010-06-20 08:20:54 -0700427status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
428 LOGV("setParam64BitFileOffset: %s",
429 use64Bit? "use 64 bit file offset": "use 32 bit file offset");
430 mUse64BitFileOffset = use64Bit;
431 return OK;
432}
433
James Dong09936ed2010-06-24 19:04:27 -0700434status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
435 LOGV("setParamVideoCameraId: %d", cameraId);
436 if (cameraId < 0) {
437 return BAD_VALUE;
438 }
439 mCameraId = cameraId;
440 return OK;
441}
442
James Dong09936ed2010-06-24 19:04:27 -0700443status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
444 LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
445 if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
James Dong7b06de62010-06-30 12:41:16 -0700446 LOGE("Tracking time duration too short: %lld us", timeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -0700447 return BAD_VALUE;
448 }
449 mTrackEveryTimeDurationUs = timeDurationUs;
450 return OK;
451}
452
James Dong81c929a2010-07-01 15:02:14 -0700453status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
454 LOGV("setParamVideoEncoderProfile: %d", profile);
455
456 // Additional check will be done later when we load the encoder.
457 // For now, we are accepting values defined in OpenMAX IL.
458 mVideoEncoderProfile = profile;
459 return OK;
460}
461
462status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
463 LOGV("setParamVideoEncoderLevel: %d", level);
464
465 // Additional check will be done later when we load the encoder.
466 // For now, we are accepting values defined in OpenMAX IL.
467 mVideoEncoderLevel = level;
468 return OK;
469}
470
James Dong52d13f02010-07-02 11:39:06 -0700471status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
472 LOGV("setParamMovieTimeScale: %d", timeScale);
473
474 // The range is set to be the same as the audio's time scale range
475 // since audio's time scale has a wider range.
476 if (timeScale < 600 || timeScale > 96000) {
477 LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
478 return BAD_VALUE;
479 }
480 mMovieTimeScale = timeScale;
481 return OK;
482}
483
484status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
485 LOGV("setParamVideoTimeScale: %d", timeScale);
486
487 // 60000 is chosen to make sure that each video frame from a 60-fps
488 // video has 1000 ticks.
489 if (timeScale < 600 || timeScale > 60000) {
490 LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
491 return BAD_VALUE;
492 }
493 mVideoTimeScale = timeScale;
494 return OK;
495}
496
497status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
498 LOGV("setParamAudioTimeScale: %d", timeScale);
499
500 // 96000 Hz is the highest sampling rate support in AAC.
501 if (timeScale < 600 || timeScale > 96000) {
502 LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
503 return BAD_VALUE;
504 }
505 mAudioTimeScale = timeScale;
506 return OK;
507}
508
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700509status_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
510 LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
511
512 if(timeLapseEnable == 0) {
513 mCaptureTimeLapse = false;
514 } else if (timeLapseEnable == 1) {
515 mCaptureTimeLapse = true;
516 } else {
517 return BAD_VALUE;
518 }
519 return OK;
520}
521
522status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
523 LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
524
525 // Not allowing time more than a day
526 if (timeUs <= 0 || timeUs > 86400*1E6) {
527 LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
528 return BAD_VALUE;
529 }
530
531 mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
532 return OK;
533}
534
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700535status_t StagefrightRecorder::setParamAuxVideoWidth(int32_t width) {
536 LOGV("setParamAuxVideoWidth : %d", width);
537
538 if (width <= 0) {
539 LOGE("Width (%d) is not positive", width);
540 return BAD_VALUE;
541 }
542
543 mAuxVideoWidth = width;
544 return OK;
545}
546
547status_t StagefrightRecorder::setParamAuxVideoHeight(int32_t height) {
548 LOGV("setParamAuxVideoHeight : %d", height);
549
550 if (height <= 0) {
551 LOGE("Height (%d) is not positive", height);
552 return BAD_VALUE;
553 }
554
555 mAuxVideoHeight = height;
556 return OK;
557}
558
559status_t StagefrightRecorder::setParamAuxVideoEncodingBitRate(int32_t bitRate) {
560 LOGV("StagefrightRecorder::setParamAuxVideoEncodingBitRate: %d", bitRate);
561
562 if (bitRate <= 0) {
563 LOGE("Invalid video encoding bit rate: %d", bitRate);
564 return BAD_VALUE;
565 }
566
567 mAuxVideoBitRate = bitRate;
568 return OK;
569}
570
James Dongabed93a2010-04-22 17:27:04 -0700571status_t StagefrightRecorder::setParameter(
572 const String8 &key, const String8 &value) {
573 LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
574 if (key == "max-duration") {
James Dong2cd841d2010-05-11 11:46:59 -0700575 int64_t max_duration_ms;
James Dongabed93a2010-04-22 17:27:04 -0700576 if (safe_strtoi64(value.string(), &max_duration_ms)) {
James Dong7b06de62010-06-30 12:41:16 -0700577 return setParamMaxFileDurationUs(1000LL * max_duration_ms);
James Dongabed93a2010-04-22 17:27:04 -0700578 }
579 } else if (key == "max-filesize") {
James Dong2cd841d2010-05-11 11:46:59 -0700580 int64_t max_filesize_bytes;
James Dongabed93a2010-04-22 17:27:04 -0700581 if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
James Dong7b06de62010-06-30 12:41:16 -0700582 return setParamMaxFileSizeBytes(max_filesize_bytes);
James Dongabed93a2010-04-22 17:27:04 -0700583 }
James Dong09936ed2010-06-24 19:04:27 -0700584 } else if (key == "interleave-duration-us") {
585 int32_t durationUs;
586 if (safe_strtoi32(value.string(), &durationUs)) {
587 return setParamInterleaveDuration(durationUs);
588 }
James Dong52d13f02010-07-02 11:39:06 -0700589 } else if (key == "param-movie-time-scale") {
590 int32_t timeScale;
591 if (safe_strtoi32(value.string(), &timeScale)) {
592 return setParamMovieTimeScale(timeScale);
593 }
James Dong09936ed2010-06-24 19:04:27 -0700594 } else if (key == "param-use-64bit-offset") {
595 int32_t use64BitOffset;
596 if (safe_strtoi32(value.string(), &use64BitOffset)) {
597 return setParam64BitFileOffset(use64BitOffset != 0);
598 }
James Dong09936ed2010-06-24 19:04:27 -0700599 } else if (key == "param-track-time-status") {
600 int64_t timeDurationUs;
601 if (safe_strtoi64(value.string(), &timeDurationUs)) {
602 return setParamTrackTimeStatus(timeDurationUs);
603 }
James Dongabed93a2010-04-22 17:27:04 -0700604 } else if (key == "audio-param-sampling-rate") {
605 int32_t sampling_rate;
James Dong2cd841d2010-05-11 11:46:59 -0700606 if (safe_strtoi32(value.string(), &sampling_rate)) {
James Dongabed93a2010-04-22 17:27:04 -0700607 return setParamAudioSamplingRate(sampling_rate);
608 }
609 } else if (key == "audio-param-number-of-channels") {
610 int32_t number_of_channels;
James Dong2cd841d2010-05-11 11:46:59 -0700611 if (safe_strtoi32(value.string(), &number_of_channels)) {
James Dongabed93a2010-04-22 17:27:04 -0700612 return setParamAudioNumberOfChannels(number_of_channels);
613 }
614 } else if (key == "audio-param-encoding-bitrate") {
615 int32_t audio_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700616 if (safe_strtoi32(value.string(), &audio_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700617 return setParamAudioEncodingBitRate(audio_bitrate);
618 }
James Dong52d13f02010-07-02 11:39:06 -0700619 } else if (key == "audio-param-time-scale") {
620 int32_t timeScale;
621 if (safe_strtoi32(value.string(), &timeScale)) {
622 return setParamAudioTimeScale(timeScale);
623 }
James Dongabed93a2010-04-22 17:27:04 -0700624 } else if (key == "video-param-encoding-bitrate") {
625 int32_t video_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700626 if (safe_strtoi32(value.string(), &video_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700627 return setParamVideoEncodingBitRate(video_bitrate);
628 }
James Dongb9d7e012010-11-09 11:15:47 -0800629 } else if (key == "video-param-rotation-angle-degrees") {
630 int32_t degrees;
631 if (safe_strtoi32(value.string(), &degrees)) {
632 return setParamVideoRotation(degrees);
633 }
James Dong09936ed2010-06-24 19:04:27 -0700634 } else if (key == "video-param-i-frames-interval") {
James Dong52d13f02010-07-02 11:39:06 -0700635 int32_t seconds;
636 if (safe_strtoi32(value.string(), &seconds)) {
637 return setParamVideoIFramesInterval(seconds);
James Dong1244eab2010-06-08 11:58:53 -0700638 }
James Dong81c929a2010-07-01 15:02:14 -0700639 } else if (key == "video-param-encoder-profile") {
640 int32_t profile;
641 if (safe_strtoi32(value.string(), &profile)) {
642 return setParamVideoEncoderProfile(profile);
643 }
644 } else if (key == "video-param-encoder-level") {
645 int32_t level;
646 if (safe_strtoi32(value.string(), &level)) {
647 return setParamVideoEncoderLevel(level);
648 }
James Dong09936ed2010-06-24 19:04:27 -0700649 } else if (key == "video-param-camera-id") {
650 int32_t cameraId;
651 if (safe_strtoi32(value.string(), &cameraId)) {
652 return setParamVideoCameraId(cameraId);
James Dong6feaa462010-06-20 08:20:54 -0700653 }
James Dong52d13f02010-07-02 11:39:06 -0700654 } else if (key == "video-param-time-scale") {
655 int32_t timeScale;
656 if (safe_strtoi32(value.string(), &timeScale)) {
657 return setParamVideoTimeScale(timeScale);
658 }
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700659 } else if (key == "time-lapse-enable") {
660 int32_t timeLapseEnable;
661 if (safe_strtoi32(value.string(), &timeLapseEnable)) {
662 return setParamTimeLapseEnable(timeLapseEnable);
663 }
664 } else if (key == "time-between-time-lapse-frame-capture") {
665 int64_t timeBetweenTimeLapseFrameCaptureMs;
666 if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
667 return setParamTimeBetweenTimeLapseFrameCapture(
668 1000LL * timeBetweenTimeLapseFrameCaptureMs);
669 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700670 } else if (key == "video-aux-param-width") {
671 int32_t auxWidth;
672 if (safe_strtoi32(value.string(), &auxWidth)) {
673 return setParamAuxVideoWidth(auxWidth);
674 }
675 } else if (key == "video-aux-param-height") {
676 int32_t auxHeight;
677 if (safe_strtoi32(value.string(), &auxHeight)) {
678 return setParamAuxVideoHeight(auxHeight);
679 }
680 } else if (key == "video-aux-param-encoding-bitrate") {
681 int32_t auxVideoBitRate;
682 if (safe_strtoi32(value.string(), &auxVideoBitRate)) {
683 return setParamAuxVideoEncodingBitRate(auxVideoBitRate);
684 }
James Dongabed93a2010-04-22 17:27:04 -0700685 } else {
686 LOGE("setParameter: failed to find key %s", key.string());
James Dongabed93a2010-04-22 17:27:04 -0700687 }
James Dong2cd841d2010-05-11 11:46:59 -0700688 return BAD_VALUE;
James Dongabed93a2010-04-22 17:27:04 -0700689}
690
691status_t StagefrightRecorder::setParameters(const String8 &params) {
692 LOGV("setParameters: %s", params.string());
693 const char *cparams = params.string();
694 const char *key_start = cparams;
695 for (;;) {
696 const char *equal_pos = strchr(key_start, '=');
697 if (equal_pos == NULL) {
698 LOGE("Parameters %s miss a value", cparams);
699 return BAD_VALUE;
700 }
701 String8 key(key_start, equal_pos - key_start);
702 TrimString(&key);
703 if (key.length() == 0) {
704 LOGE("Parameters %s contains an empty key", cparams);
705 return BAD_VALUE;
706 }
707 const char *value_start = equal_pos + 1;
708 const char *semicolon_pos = strchr(value_start, ';');
709 String8 value;
710 if (semicolon_pos == NULL) {
711 value.setTo(value_start);
712 } else {
713 value.setTo(value_start, semicolon_pos - value_start);
714 }
715 if (setParameter(key, value) != OK) {
716 return BAD_VALUE;
717 }
718 if (semicolon_pos == NULL) {
719 break; // Reaches the end
720 }
721 key_start = semicolon_pos + 1;
722 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800723 return OK;
724}
725
James Dongfe1bafe2010-06-25 17:06:47 -0700726status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
Andreas Huberea6a38c2009-11-16 15:43:38 -0800727 mListener = listener;
728
729 return OK;
730}
731
732status_t StagefrightRecorder::prepare() {
733 return OK;
734}
735
736status_t StagefrightRecorder::start() {
James Dong7b06de62010-06-30 12:41:16 -0700737 CHECK(mOutputFd >= 0);
738
Andreas Huberea6a38c2009-11-16 15:43:38 -0800739 if (mWriter != NULL) {
James Dong7b06de62010-06-30 12:41:16 -0700740 LOGE("File writer is not avaialble");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800741 return UNKNOWN_ERROR;
742 }
743
Andreas Huber996dddf2010-01-25 15:30:31 -0800744 switch (mOutputFormat) {
745 case OUTPUT_FORMAT_DEFAULT:
746 case OUTPUT_FORMAT_THREE_GPP:
747 case OUTPUT_FORMAT_MPEG_4:
748 return startMPEG4Recording();
749
750 case OUTPUT_FORMAT_AMR_NB:
751 case OUTPUT_FORMAT_AMR_WB:
752 return startAMRRecording();
753
James Dong2cd841d2010-05-11 11:46:59 -0700754 case OUTPUT_FORMAT_AAC_ADIF:
755 case OUTPUT_FORMAT_AAC_ADTS:
756 return startAACRecording();
757
Andreas Huber57648e42010-08-04 10:14:30 -0700758 case OUTPUT_FORMAT_RTP_AVP:
759 return startRTPRecording();
760
Andreas Huber9adf4662010-10-12 14:17:45 -0700761 case OUTPUT_FORMAT_MPEG2TS:
762 return startMPEG2TSRecording();
763
Andreas Huber996dddf2010-01-25 15:30:31 -0800764 default:
James Dong7b06de62010-06-30 12:41:16 -0700765 LOGE("Unsupported output file format: %d", mOutputFormat);
Andreas Huber996dddf2010-01-25 15:30:31 -0800766 return UNKNOWN_ERROR;
767 }
768}
769
James Dongabed93a2010-04-22 17:27:04 -0700770sp<MediaSource> StagefrightRecorder::createAudioSource() {
Andreas Huber996dddf2010-01-25 15:30:31 -0800771 sp<AudioSource> audioSource =
772 new AudioSource(
773 mAudioSource,
James Dongabed93a2010-04-22 17:27:04 -0700774 mSampleRate,
James Dongd77d2a92010-06-14 17:45:35 -0700775 mAudioChannels);
Andreas Huber996dddf2010-01-25 15:30:31 -0800776
777 status_t err = audioSource->initCheck();
778
779 if (err != OK) {
James Dongabed93a2010-04-22 17:27:04 -0700780 LOGE("audio source is not initialized");
Andreas Huber996dddf2010-01-25 15:30:31 -0800781 return NULL;
782 }
783
784 sp<MetaData> encMeta = new MetaData;
James Dongabed93a2010-04-22 17:27:04 -0700785 const char *mime;
786 switch (mAudioEncoder) {
787 case AUDIO_ENCODER_AMR_NB:
788 case AUDIO_ENCODER_DEFAULT:
789 mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
790 break;
791 case AUDIO_ENCODER_AMR_WB:
792 mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
793 break;
794 case AUDIO_ENCODER_AAC:
795 mime = MEDIA_MIMETYPE_AUDIO_AAC;
796 break;
797 default:
798 LOGE("Unknown audio encoder: %d", mAudioEncoder);
799 return NULL;
800 }
801 encMeta->setCString(kKeyMIMEType, mime);
Andreas Huber996dddf2010-01-25 15:30:31 -0800802
Andreas Huber259b7c12010-02-10 15:04:31 -0800803 int32_t maxInputSize;
804 CHECK(audioSource->getFormat()->findInt32(
805 kKeyMaxInputSize, &maxInputSize));
806
807 encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
James Dongabed93a2010-04-22 17:27:04 -0700808 encMeta->setInt32(kKeyChannelCount, mAudioChannels);
809 encMeta->setInt32(kKeySampleRate, mSampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700810 encMeta->setInt32(kKeyBitRate, mAudioBitRate);
James Dongeff30e32010-08-13 14:16:26 -0700811 if (mAudioTimeScale > 0) {
812 encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
813 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800814
815 OMXClient client;
816 CHECK_EQ(client.connect(), OK);
817
818 sp<MediaSource> audioEncoder =
819 OMXCodec::Create(client.interface(), encMeta,
820 true /* createEncoder */, audioSource);
James Dong57e7f832010-06-24 19:55:31 -0700821 mAudioSourceNode = audioSource;
Andreas Huber996dddf2010-01-25 15:30:31 -0800822
823 return audioEncoder;
824}
825
James Dong2cd841d2010-05-11 11:46:59 -0700826status_t StagefrightRecorder::startAACRecording() {
827 CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
828 mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
829
830 CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
831 CHECK(mAudioSource != AUDIO_SOURCE_LIST_END);
James Dong2cd841d2010-05-11 11:46:59 -0700832
833 CHECK(0 == "AACWriter is not implemented yet");
834
835 return OK;
836}
837
Andreas Huber996dddf2010-01-25 15:30:31 -0800838status_t StagefrightRecorder::startAMRRecording() {
James Dong2cd841d2010-05-11 11:46:59 -0700839 CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
840 mOutputFormat == OUTPUT_FORMAT_AMR_WB);
841
842 if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
843 if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
844 mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
845 LOGE("Invalid encoder %d used for AMRNB recording",
846 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700847 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700848 }
James Dong2cd841d2010-05-11 11:46:59 -0700849 } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
850 if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
851 LOGE("Invlaid encoder %d used for AMRWB recording",
852 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700853 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700854 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800855 }
856
James Dong2cd841d2010-05-11 11:46:59 -0700857 if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
858 LOGE("Invalid audio source: %d", mAudioSource);
James Dong7b06de62010-06-30 12:41:16 -0700859 return BAD_VALUE;
Andreas Huber996dddf2010-01-25 15:30:31 -0800860 }
861
James Dong54815a72011-01-12 20:45:16 -0800862 status_t status = BAD_VALUE;
863 if (OK != (status = checkAudioEncoderCapabilities())) {
864 return status;
865 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800866
James Dong54815a72011-01-12 20:45:16 -0800867 sp<MediaSource> audioEncoder = createAudioSource();
Andreas Huber996dddf2010-01-25 15:30:31 -0800868 if (audioEncoder == NULL) {
869 return UNKNOWN_ERROR;
870 }
871
James Dong2747e0e2010-11-18 20:59:13 -0800872 mWriter = new AMRWriter(mOutputFd);
Andreas Huber996dddf2010-01-25 15:30:31 -0800873 mWriter->addSource(audioEncoder);
James Dong18244862010-05-11 14:57:02 -0700874
875 if (mMaxFileDurationUs != 0) {
876 mWriter->setMaxFileDuration(mMaxFileDurationUs);
877 }
878 if (mMaxFileSizeBytes != 0) {
879 mWriter->setMaxFileSize(mMaxFileSizeBytes);
880 }
881 mWriter->setListener(mListener);
Andreas Huber996dddf2010-01-25 15:30:31 -0800882 mWriter->start();
883
884 return OK;
885}
886
Andreas Huber57648e42010-08-04 10:14:30 -0700887status_t StagefrightRecorder::startRTPRecording() {
888 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
889
890 if ((mAudioSource != AUDIO_SOURCE_LIST_END
891 && mVideoSource != VIDEO_SOURCE_LIST_END)
892 || (mAudioSource == AUDIO_SOURCE_LIST_END
893 && mVideoSource == VIDEO_SOURCE_LIST_END)) {
894 // Must have exactly one source.
895 return BAD_VALUE;
896 }
897
898 if (mOutputFd < 0) {
899 return BAD_VALUE;
900 }
901
902 sp<MediaSource> source;
903
904 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
905 source = createAudioSource();
906 } else {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700907
908 sp<CameraSource> cameraSource;
909 status_t err = setupCameraSource(&cameraSource);
910 if (err != OK) {
911 return err;
912 }
913
914 err = setupVideoEncoder(cameraSource, mVideoBitRate, &source);
Andreas Huber57648e42010-08-04 10:14:30 -0700915 if (err != OK) {
916 return err;
917 }
918 }
919
James Dong2747e0e2010-11-18 20:59:13 -0800920 mWriter = new ARTPWriter(mOutputFd);
Andreas Huber57648e42010-08-04 10:14:30 -0700921 mWriter->addSource(source);
922 mWriter->setListener(mListener);
923
924 return mWriter->start();
925}
926
Andreas Huber9adf4662010-10-12 14:17:45 -0700927status_t StagefrightRecorder::startMPEG2TSRecording() {
928 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
929
James Dong2747e0e2010-11-18 20:59:13 -0800930 sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
Andreas Huber9adf4662010-10-12 14:17:45 -0700931
932 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
933 if (mAudioEncoder != AUDIO_ENCODER_AAC) {
934 return ERROR_UNSUPPORTED;
935 }
936
937 status_t err = setupAudioEncoder(writer);
938
939 if (err != OK) {
940 return err;
941 }
942 }
943
944 if (mVideoSource == VIDEO_SOURCE_DEFAULT
945 || mVideoSource == VIDEO_SOURCE_CAMERA) {
946 if (mVideoEncoder != VIDEO_ENCODER_H264) {
947 return ERROR_UNSUPPORTED;
948 }
949
Kenny Root4a90f932010-10-14 23:58:41 -0700950 sp<CameraSource> cameraSource;
951 status_t err = setupCameraSource(&cameraSource);
952 if (err != OK) {
953 return err;
954 }
955
Andreas Huber9adf4662010-10-12 14:17:45 -0700956 sp<MediaSource> encoder;
Kenny Root4a90f932010-10-14 23:58:41 -0700957 err = setupVideoEncoder(cameraSource, mVideoBitRate, &encoder);
Andreas Huber9adf4662010-10-12 14:17:45 -0700958
959 if (err != OK) {
960 return err;
961 }
962
963 writer->addSource(encoder);
964 }
965
966 if (mMaxFileDurationUs != 0) {
967 writer->setMaxFileDuration(mMaxFileDurationUs);
968 }
969
970 if (mMaxFileSizeBytes != 0) {
971 writer->setMaxFileSize(mMaxFileSizeBytes);
972 }
973
974 mWriter = writer;
975
976 return mWriter->start();
977}
978
James Dong42a18c02010-06-16 17:27:46 -0700979void StagefrightRecorder::clipVideoFrameRate() {
980 LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
981 int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
982 "enc.vid.fps.min", mVideoEncoder);
983 int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
984 "enc.vid.fps.max", mVideoEncoder);
James Dongb15f2ea2010-10-24 09:32:39 -0700985 if (mFrameRate < minFrameRate && mFrameRate != -1) {
James Dong42a18c02010-06-16 17:27:46 -0700986 LOGW("Intended video encoding frame rate (%d fps) is too small"
987 " and will be set to (%d fps)", mFrameRate, minFrameRate);
988 mFrameRate = minFrameRate;
989 } else if (mFrameRate > maxFrameRate) {
990 LOGW("Intended video encoding frame rate (%d fps) is too large"
991 " and will be set to (%d fps)", mFrameRate, maxFrameRate);
992 mFrameRate = maxFrameRate;
993 }
994}
995
996void StagefrightRecorder::clipVideoBitRate() {
997 LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
998 int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
999 "enc.vid.bps.min", mVideoEncoder);
1000 int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1001 "enc.vid.bps.max", mVideoEncoder);
1002 if (mVideoBitRate < minBitRate) {
1003 LOGW("Intended video encoding bit rate (%d bps) is too small"
1004 " and will be set to (%d bps)", mVideoBitRate, minBitRate);
1005 mVideoBitRate = minBitRate;
1006 } else if (mVideoBitRate > maxBitRate) {
1007 LOGW("Intended video encoding bit rate (%d bps) is too large"
1008 " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
1009 mVideoBitRate = maxBitRate;
1010 }
1011}
1012
1013void StagefrightRecorder::clipVideoFrameWidth() {
1014 LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
1015 int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1016 "enc.vid.width.min", mVideoEncoder);
1017 int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1018 "enc.vid.width.max", mVideoEncoder);
1019 if (mVideoWidth < minFrameWidth) {
1020 LOGW("Intended video encoding frame width (%d) is too small"
1021 " and will be set to (%d)", mVideoWidth, minFrameWidth);
1022 mVideoWidth = minFrameWidth;
1023 } else if (mVideoWidth > maxFrameWidth) {
1024 LOGW("Intended video encoding frame width (%d) is too large"
1025 " and will be set to (%d)", mVideoWidth, maxFrameWidth);
1026 mVideoWidth = maxFrameWidth;
1027 }
1028}
1029
James Dong0c128b62010-10-08 11:59:32 -07001030status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
Nipun Kwatra453e92f2010-08-04 14:26:45 -07001031 if (!mCaptureTimeLapse) {
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001032 // Dont clip for time lapse capture as encoder will have enough
1033 // time to encode because of slow capture rate of time lapse.
1034 clipVideoBitRate();
1035 clipVideoFrameRate();
1036 clipVideoFrameWidth();
1037 clipVideoFrameHeight();
1038 }
James Dong7b06de62010-06-30 12:41:16 -07001039 return OK;
1040}
1041
James Dong54815a72011-01-12 20:45:16 -08001042status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
1043 clipAudioBitRate();
1044 clipAudioSampleRate();
1045 clipNumberOfAudioChannels();
1046 return OK;
1047}
1048
1049void StagefrightRecorder::clipAudioBitRate() {
1050 LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
1051
1052 int minAudioBitRate =
1053 mEncoderProfiles->getAudioEncoderParamByName(
1054 "enc.aud.bps.min", mAudioEncoder);
1055 if (mAudioBitRate < minAudioBitRate) {
1056 LOGW("Intended audio encoding bit rate (%d) is too small"
1057 " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
1058 mAudioBitRate = minAudioBitRate;
1059 }
1060
1061 int maxAudioBitRate =
1062 mEncoderProfiles->getAudioEncoderParamByName(
1063 "enc.aud.bps.max", mAudioEncoder);
1064 if (mAudioBitRate > maxAudioBitRate) {
1065 LOGW("Intended audio encoding bit rate (%d) is too large"
1066 " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
1067 mAudioBitRate = maxAudioBitRate;
1068 }
1069}
1070
1071void StagefrightRecorder::clipAudioSampleRate() {
1072 LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
1073
1074 int minSampleRate =
1075 mEncoderProfiles->getAudioEncoderParamByName(
1076 "enc.aud.hz.min", mAudioEncoder);
1077 if (mSampleRate < minSampleRate) {
1078 LOGW("Intended audio sample rate (%d) is too small"
1079 " and will be set to (%d)", mSampleRate, minSampleRate);
1080 mSampleRate = minSampleRate;
1081 }
1082
1083 int maxSampleRate =
1084 mEncoderProfiles->getAudioEncoderParamByName(
1085 "enc.aud.hz.max", mAudioEncoder);
1086 if (mSampleRate > maxSampleRate) {
1087 LOGW("Intended audio sample rate (%d) is too large"
1088 " and will be set to (%d)", mSampleRate, maxSampleRate);
1089 mSampleRate = maxSampleRate;
1090 }
1091}
1092
1093void StagefrightRecorder::clipNumberOfAudioChannels() {
1094 LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
1095
1096 int minChannels =
1097 mEncoderProfiles->getAudioEncoderParamByName(
1098 "enc.aud.ch.min", mAudioEncoder);
1099 if (mAudioChannels < minChannels) {
1100 LOGW("Intended number of audio channels (%d) is too small"
1101 " and will be set to (%d)", mAudioChannels, minChannels);
1102 mAudioChannels = minChannels;
1103 }
1104
1105 int maxChannels =
1106 mEncoderProfiles->getAudioEncoderParamByName(
1107 "enc.aud.ch.max", mAudioEncoder);
1108 if (mAudioChannels > maxChannels) {
1109 LOGW("Intended number of audio channels (%d) is too large"
1110 " and will be set to (%d)", mAudioChannels, maxChannels);
1111 mAudioChannels = maxChannels;
1112 }
1113}
1114
James Dong42a18c02010-06-16 17:27:46 -07001115void StagefrightRecorder::clipVideoFrameHeight() {
1116 LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
1117 int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1118 "enc.vid.height.min", mVideoEncoder);
1119 int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1120 "enc.vid.height.max", mVideoEncoder);
1121 if (mVideoHeight < minFrameHeight) {
1122 LOGW("Intended video encoding frame height (%d) is too small"
1123 " and will be set to (%d)", mVideoHeight, minFrameHeight);
1124 mVideoHeight = minFrameHeight;
1125 } else if (mVideoHeight > maxFrameHeight) {
1126 LOGW("Intended video encoding frame height (%d) is too large"
1127 " and will be set to (%d)", mVideoHeight, maxFrameHeight);
1128 mVideoHeight = maxFrameHeight;
1129 }
1130}
1131
James Dong05c2fd52010-11-02 13:20:11 -07001132status_t StagefrightRecorder::setupCameraSource(
1133 sp<CameraSource> *cameraSource) {
James Dongb15f2ea2010-10-24 09:32:39 -07001134 status_t err = OK;
1135 if ((err = checkVideoEncoderCapabilities()) != OK) {
1136 return err;
1137 }
James Dong0c128b62010-10-08 11:59:32 -07001138 Size videoSize;
1139 videoSize.width = mVideoWidth;
1140 videoSize.height = mVideoHeight;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001141 if (mCaptureTimeLapse) {
James Dong0c128b62010-10-08 11:59:32 -07001142 mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
1143 mCamera, mCameraId,
1144 videoSize, mFrameRate, mPreviewSurface,
1145 mTimeBetweenTimeLapseFrameCaptureUs);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001146 *cameraSource = mCameraSourceTimeLapse;
1147 } else {
James Dong0c128b62010-10-08 11:59:32 -07001148 *cameraSource = CameraSource::CreateFromCamera(
James Dong05c2fd52010-11-02 13:20:11 -07001149 mCamera, mCameraId, videoSize, mFrameRate,
1150 mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001151 }
James Dong5df53fe2010-12-05 14:25:34 -08001152 if (*cameraSource == NULL) {
1153 return UNKNOWN_ERROR;
1154 }
1155
1156 if ((*cameraSource)->initCheck() != OK) {
1157 (*cameraSource).clear();
1158 *cameraSource = NULL;
1159 return NO_INIT;
1160 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001161
James Dongb15f2ea2010-10-24 09:32:39 -07001162 // When frame rate is not set, the actual frame rate will be set to
1163 // the current frame rate being used.
1164 if (mFrameRate == -1) {
1165 int32_t frameRate = 0;
1166 CHECK ((*cameraSource)->getFormat()->findInt32(
James Dongaac193c2010-11-10 20:43:53 -08001167 kKeyFrameRate, &frameRate));
James Dongb15f2ea2010-10-24 09:32:39 -07001168 LOGI("Frame rate is not explicitly set. Use the current frame "
1169 "rate (%d fps)", frameRate);
1170 mFrameRate = frameRate;
1171 }
1172
1173 CHECK(mFrameRate != -1);
James Dong05c2fd52010-11-02 13:20:11 -07001174
1175 mIsMetaDataStoredInVideoBuffers =
1176 (*cameraSource)->isMetaDataStoredInVideoBuffers();
1177
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001178 return OK;
1179}
1180
1181status_t StagefrightRecorder::setupVideoEncoder(
1182 sp<MediaSource> cameraSource,
1183 int32_t videoBitRate,
1184 sp<MediaSource> *source) {
1185 source->clear();
James Dong7b06de62010-06-30 12:41:16 -07001186
1187 sp<MetaData> enc_meta = new MetaData;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001188 enc_meta->setInt32(kKeyBitRate, videoBitRate);
James Dongaac193c2010-11-10 20:43:53 -08001189 enc_meta->setInt32(kKeyFrameRate, mFrameRate);
James Dong7b06de62010-06-30 12:41:16 -07001190
1191 switch (mVideoEncoder) {
1192 case VIDEO_ENCODER_H263:
1193 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
1194 break;
1195
1196 case VIDEO_ENCODER_MPEG_4_SP:
1197 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
1198 break;
1199
1200 case VIDEO_ENCODER_H264:
1201 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
1202 break;
1203
1204 default:
1205 CHECK(!"Should not be here, unsupported video encoding.");
1206 break;
1207 }
1208
1209 sp<MetaData> meta = cameraSource->getFormat();
1210
James Dong1cc31e62010-07-02 17:44:44 -07001211 int32_t width, height, stride, sliceHeight, colorFormat;
James Dong7b06de62010-06-30 12:41:16 -07001212 CHECK(meta->findInt32(kKeyWidth, &width));
1213 CHECK(meta->findInt32(kKeyHeight, &height));
1214 CHECK(meta->findInt32(kKeyStride, &stride));
1215 CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
James Dong1cc31e62010-07-02 17:44:44 -07001216 CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
James Dong7b06de62010-06-30 12:41:16 -07001217
1218 enc_meta->setInt32(kKeyWidth, width);
1219 enc_meta->setInt32(kKeyHeight, height);
James Dong52d13f02010-07-02 11:39:06 -07001220 enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
James Dong7b06de62010-06-30 12:41:16 -07001221 enc_meta->setInt32(kKeyStride, stride);
1222 enc_meta->setInt32(kKeySliceHeight, sliceHeight);
James Dong1cc31e62010-07-02 17:44:44 -07001223 enc_meta->setInt32(kKeyColorFormat, colorFormat);
James Dongeff30e32010-08-13 14:16:26 -07001224 if (mVideoTimeScale > 0) {
1225 enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
1226 }
James Dong81c929a2010-07-01 15:02:14 -07001227 if (mVideoEncoderProfile != -1) {
1228 enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
1229 }
1230 if (mVideoEncoderLevel != -1) {
1231 enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
1232 }
James Dong7b06de62010-06-30 12:41:16 -07001233
1234 OMXClient client;
1235 CHECK_EQ(client.connect(), OK);
1236
James Dong6312dd62010-12-02 14:48:23 -08001237 uint32_t encoder_flags = 0;
James Dong5fb60c72011-01-18 21:12:31 -08001238 if (mIsMetaDataStoredInVideoBuffers) {
James Dong6312dd62010-12-02 14:48:23 -08001239 encoder_flags |= OMXCodec::kHardwareCodecsOnly;
James Dong05c2fd52010-11-02 13:20:11 -07001240 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
1241 }
James Dong5f3ab062011-01-25 16:31:28 -08001242
1243 // Do not wait for all the input buffers to become available.
1244 // This give timelapse video recording faster response in
1245 // receiving output from video encoder component.
1246 if (mCaptureTimeLapse) {
1247 encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
1248 }
1249
James Dong7b06de62010-06-30 12:41:16 -07001250 sp<MediaSource> encoder = OMXCodec::Create(
1251 client.interface(), enc_meta,
Nipun Kwatra077cba42010-07-20 11:37:17 -07001252 true /* createEncoder */, cameraSource,
1253 NULL, encoder_flags);
James Dong7b06de62010-06-30 12:41:16 -07001254 if (encoder == NULL) {
James Dong6312dd62010-12-02 14:48:23 -08001255 LOGW("Failed to create the encoder");
1256 // When the encoder fails to be created, we need
1257 // release the camera source due to the camera's lock
1258 // and unlock mechanism.
1259 cameraSource->stop();
James Dong7b06de62010-06-30 12:41:16 -07001260 return UNKNOWN_ERROR;
1261 }
1262
Andreas Huber57648e42010-08-04 10:14:30 -07001263 *source = encoder;
1264
James Dong7b06de62010-06-30 12:41:16 -07001265 return OK;
1266}
1267
1268status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
James Dong54815a72011-01-12 20:45:16 -08001269 status_t status = BAD_VALUE;
1270 if (OK != (status = checkAudioEncoderCapabilities())) {
1271 return status;
1272 }
1273
James Dong7b06de62010-06-30 12:41:16 -07001274 switch(mAudioEncoder) {
1275 case AUDIO_ENCODER_AMR_NB:
1276 case AUDIO_ENCODER_AMR_WB:
1277 case AUDIO_ENCODER_AAC:
James Dong7b06de62010-06-30 12:41:16 -07001278 break;
James Dong54815a72011-01-12 20:45:16 -08001279
James Dong7b06de62010-06-30 12:41:16 -07001280 default:
1281 LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1282 return UNKNOWN_ERROR;
1283 }
1284
James Dong54815a72011-01-12 20:45:16 -08001285 sp<MediaSource> audioEncoder = createAudioSource();
James Dong7b06de62010-06-30 12:41:16 -07001286 if (audioEncoder == NULL) {
1287 return UNKNOWN_ERROR;
1288 }
James Dong52d13f02010-07-02 11:39:06 -07001289
James Dong7b06de62010-06-30 12:41:16 -07001290 writer->addSource(audioEncoder);
1291 return OK;
1292}
1293
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001294status_t StagefrightRecorder::setupMPEG4Recording(
1295 bool useSplitCameraSource,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001296 int outputFd,
1297 int32_t videoWidth, int32_t videoHeight,
1298 int32_t videoBitRate,
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001299 int32_t *totalBitRate,
1300 sp<MediaWriter> *mediaWriter) {
1301 mediaWriter->clear();
1302 *totalBitRate = 0;
James Dong7b06de62010-06-30 12:41:16 -07001303 status_t err = OK;
James Dong2747e0e2010-11-18 20:59:13 -08001304 sp<MediaWriter> writer = new MPEG4Writer(outputFd);
Andreas Huber996dddf2010-01-25 15:30:31 -08001305
1306 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1307 || mVideoSource == VIDEO_SOURCE_CAMERA) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001308
1309 sp<MediaSource> cameraMediaSource;
1310 if (useSplitCameraSource) {
1311 LOGV("Using Split camera source");
1312 cameraMediaSource = mCameraSourceSplitter->createClient();
1313 } else {
1314 sp<CameraSource> cameraSource;
1315 err = setupCameraSource(&cameraSource);
1316 cameraMediaSource = cameraSource;
1317 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001318 if ((videoWidth != mVideoWidth) || (videoHeight != mVideoHeight)) {
1319 // Use downsampling from the original source.
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001320 cameraMediaSource =
1321 new VideoSourceDownSampler(cameraMediaSource, videoWidth, videoHeight);
1322 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001323 if (err != OK) {
1324 return err;
1325 }
1326
Andreas Huber57648e42010-08-04 10:14:30 -07001327 sp<MediaSource> encoder;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001328 err = setupVideoEncoder(cameraMediaSource, videoBitRate, &encoder);
1329 if (err != OK) {
1330 return err;
1331 }
1332
Andreas Huber57648e42010-08-04 10:14:30 -07001333 writer->addSource(encoder);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001334 *totalBitRate += videoBitRate;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001335 }
1336
James Dong44b004b2011-01-19 20:42:19 -08001337 // Audio source is added at the end if it exists.
1338 // This help make sure that the "recoding" sound is suppressed for
1339 // camcorder applications in the recorded files.
1340 if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_LIST_END)) {
1341 err = setupAudioEncoder(writer);
1342 if (err != OK) return err;
1343 *totalBitRate += mAudioBitRate;
1344 }
1345
James Dong63299c02010-07-28 10:08:03 -07001346 if (mInterleaveDurationUs > 0) {
1347 reinterpret_cast<MPEG4Writer *>(writer.get())->
1348 setInterleaveDuration(mInterleaveDurationUs);
1349 }
James Dong18244862010-05-11 14:57:02 -07001350 if (mMaxFileDurationUs != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001351 writer->setMaxFileDuration(mMaxFileDurationUs);
James Dong18244862010-05-11 14:57:02 -07001352 }
1353 if (mMaxFileSizeBytes != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001354 writer->setMaxFileSize(mMaxFileSizeBytes);
James Dong18244862010-05-11 14:57:02 -07001355 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001356
1357 writer->setListener(mListener);
1358 *mediaWriter = writer;
1359 return OK;
1360}
1361
1362void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
1363 sp<MetaData> *meta) {
1364 (*meta)->setInt64(kKeyTime, startTimeUs);
1365 (*meta)->setInt32(kKeyFileType, mOutputFormat);
1366 (*meta)->setInt32(kKeyBitRate, totalBitRate);
1367 (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
James Dongeff30e32010-08-13 14:16:26 -07001368 if (mMovieTimeScale > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001369 (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
James Dongeff30e32010-08-13 14:16:26 -07001370 }
James Dong09936ed2010-06-24 19:04:27 -07001371 if (mTrackEveryTimeDurationUs > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001372 (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -07001373 }
James Dongb9d7e012010-11-09 11:15:47 -08001374 if (mRotationDegrees != 0) {
1375 (*meta)->setInt32(kKeyRotation, mRotationDegrees);
1376 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001377}
1378
1379status_t StagefrightRecorder::startMPEG4Recording() {
1380 if (mCaptureAuxVideo) {
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001381 if (!mCaptureTimeLapse) {
1382 LOGE("Auxiliary video can be captured only in time lapse mode");
1383 return UNKNOWN_ERROR;
1384 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001385 LOGV("Creating MediaSourceSplitter");
1386 sp<CameraSource> cameraSource;
1387 status_t err = setupCameraSource(&cameraSource);
1388 if (err != OK) {
1389 return err;
1390 }
1391 mCameraSourceSplitter = new MediaSourceSplitter(cameraSource);
1392 } else {
1393 mCameraSourceSplitter = NULL;
1394 }
1395
1396 int32_t totalBitRate;
1397 status_t err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001398 mOutputFd, mVideoWidth, mVideoHeight,
1399 mVideoBitRate, &totalBitRate, &mWriter);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001400 if (err != OK) {
1401 return err;
1402 }
1403
1404 int64_t startTimeUs = systemTime() / 1000;
1405 sp<MetaData> meta = new MetaData;
1406 setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
1407
1408 err = mWriter->start(meta.get());
1409 if (err != OK) {
1410 return err;
1411 }
1412
1413 if (mCaptureAuxVideo) {
1414 CHECK(mOutputFdAux >= 0);
1415 if (mWriterAux != NULL) {
1416 LOGE("Auxiliary File writer is not avaialble");
1417 return UNKNOWN_ERROR;
1418 }
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001419 if ((mAuxVideoWidth > mVideoWidth) || (mAuxVideoHeight > mVideoHeight) ||
1420 ((mAuxVideoWidth == mVideoWidth) && mAuxVideoHeight == mVideoHeight)) {
1421 LOGE("Auxiliary video size (%d x %d) same or larger than the main video size (%d x %d)",
1422 mAuxVideoWidth, mAuxVideoHeight, mVideoWidth, mVideoHeight);
1423 return UNKNOWN_ERROR;
1424 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001425
1426 int32_t totalBitrateAux;
1427 err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001428 mOutputFdAux, mAuxVideoWidth, mAuxVideoHeight,
1429 mAuxVideoBitRate, &totalBitrateAux, &mWriterAux);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001430 if (err != OK) {
1431 return err;
1432 }
1433
1434 sp<MetaData> metaAux = new MetaData;
1435 setupMPEG4MetaData(startTimeUs, totalBitrateAux, &metaAux);
1436
1437 return mWriterAux->start(metaAux.get());
1438 }
1439
1440 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001441}
1442
James Dong08c74732010-06-10 12:28:15 -07001443status_t StagefrightRecorder::pause() {
James Dongc0ab2a62010-06-29 16:29:19 -07001444 LOGV("pause");
James Dong08c74732010-06-10 12:28:15 -07001445 if (mWriter == NULL) {
1446 return UNKNOWN_ERROR;
1447 }
1448 mWriter->pause();
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001449
1450 if (mCaptureAuxVideo) {
1451 if (mWriterAux == NULL) {
1452 return UNKNOWN_ERROR;
1453 }
1454 mWriterAux->pause();
1455 }
1456
James Dong08c74732010-06-10 12:28:15 -07001457 return OK;
1458}
1459
Andreas Huberea6a38c2009-11-16 15:43:38 -08001460status_t StagefrightRecorder::stop() {
James Dongc0ab2a62010-06-29 16:29:19 -07001461 LOGV("stop");
James Dongd0366622010-08-18 19:10:39 -07001462 status_t err = OK;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001463
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001464 if (mCaptureTimeLapse && mCameraSourceTimeLapse != NULL) {
1465 mCameraSourceTimeLapse->startQuickReadReturns();
1466 mCameraSourceTimeLapse = NULL;
1467 }
1468
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001469 if (mCaptureAuxVideo) {
1470 if (mWriterAux != NULL) {
1471 mWriterAux->stop();
1472 mWriterAux.clear();
1473 }
1474 }
1475
James Dongc0ab2a62010-06-29 16:29:19 -07001476 if (mWriter != NULL) {
James Dongd0366622010-08-18 19:10:39 -07001477 err = mWriter->stop();
James Dong7b06de62010-06-30 12:41:16 -07001478 mWriter.clear();
Andreas Huberea6a38c2009-11-16 15:43:38 -08001479 }
1480
James Dongc6280bc2010-08-11 17:12:39 -07001481 if (mOutputFd >= 0) {
1482 ::close(mOutputFd);
1483 mOutputFd = -1;
1484 }
1485
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001486 if (mCaptureAuxVideo) {
1487 if (mOutputFdAux >= 0) {
1488 ::close(mOutputFdAux);
1489 mOutputFdAux = -1;
1490 }
1491 }
1492
James Dongd0366622010-08-18 19:10:39 -07001493 return err;
James Dongc0ab2a62010-06-29 16:29:19 -07001494}
1495
1496status_t StagefrightRecorder::close() {
1497 LOGV("close");
1498 stop();
1499
Andreas Huberea6a38c2009-11-16 15:43:38 -08001500 return OK;
1501}
1502
1503status_t StagefrightRecorder::reset() {
James Dongc0ab2a62010-06-29 16:29:19 -07001504 LOGV("reset");
Andreas Huberea6a38c2009-11-16 15:43:38 -08001505 stop();
1506
James Dongabed93a2010-04-22 17:27:04 -07001507 // No audio or video source by default
Andreas Huberea6a38c2009-11-16 15:43:38 -08001508 mAudioSource = AUDIO_SOURCE_LIST_END;
1509 mVideoSource = VIDEO_SOURCE_LIST_END;
James Dongabed93a2010-04-22 17:27:04 -07001510
1511 // Default parameters
1512 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
1513 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
1514 mVideoEncoder = VIDEO_ENCODER_H263;
1515 mVideoWidth = 176;
1516 mVideoHeight = 144;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001517 mAuxVideoWidth = 176;
1518 mAuxVideoHeight = 144;
James Dongb15f2ea2010-10-24 09:32:39 -07001519 mFrameRate = -1;
James Dongabed93a2010-04-22 17:27:04 -07001520 mVideoBitRate = 192000;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001521 mAuxVideoBitRate = 192000;
James Dongabed93a2010-04-22 17:27:04 -07001522 mSampleRate = 8000;
1523 mAudioChannels = 1;
1524 mAudioBitRate = 12200;
James Dongc6161722010-05-20 17:55:52 -07001525 mInterleaveDurationUs = 0;
James Dong52d13f02010-07-02 11:39:06 -07001526 mIFramesIntervalSec = 1;
James Dong57e7f832010-06-24 19:55:31 -07001527 mAudioSourceNode = 0;
James Dong6feaa462010-06-20 08:20:54 -07001528 mUse64BitFileOffset = false;
James Dongeff30e32010-08-13 14:16:26 -07001529 mMovieTimeScale = -1;
1530 mAudioTimeScale = -1;
1531 mVideoTimeScale = -1;
James Dong09936ed2010-06-24 19:04:27 -07001532 mCameraId = 0;
James Dong81c929a2010-07-01 15:02:14 -07001533 mVideoEncoderProfile = -1;
1534 mVideoEncoderLevel = -1;
1535 mMaxFileDurationUs = 0;
1536 mMaxFileSizeBytes = 0;
James Dong09936ed2010-06-24 19:04:27 -07001537 mTrackEveryTimeDurationUs = 0;
Nipun Kwatrad26920a2010-06-30 18:51:31 -07001538 mCaptureTimeLapse = false;
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001539 mTimeBetweenTimeLapseFrameCaptureUs = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001540 mCaptureAuxVideo = false;
1541 mCameraSourceSplitter = NULL;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001542 mCameraSourceTimeLapse = NULL;
James Dong05c2fd52010-11-02 13:20:11 -07001543 mIsMetaDataStoredInVideoBuffers = false;
James Dong42a18c02010-06-16 17:27:46 -07001544 mEncoderProfiles = MediaProfiles::getInstance();
James Dong5d0b7832010-11-10 12:26:58 -08001545 mRotationDegrees = 0;
James Dongabed93a2010-04-22 17:27:04 -07001546
Andreas Huberea6a38c2009-11-16 15:43:38 -08001547 mOutputFd = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001548 mOutputFdAux = -1;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001549
1550 return OK;
1551}
1552
1553status_t StagefrightRecorder::getMaxAmplitude(int *max) {
James Dongc0ab2a62010-06-29 16:29:19 -07001554 LOGV("getMaxAmplitude");
1555
1556 if (max == NULL) {
1557 LOGE("Null pointer argument");
1558 return BAD_VALUE;
1559 }
1560
James Dong57e7f832010-06-24 19:55:31 -07001561 if (mAudioSourceNode != 0) {
1562 *max = mAudioSourceNode->getMaxAmplitude();
1563 } else {
1564 *max = 0;
1565 }
Andreas Huber996dddf2010-01-25 15:30:31 -08001566
1567 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001568}
1569
James Dong3f51fa72010-08-18 03:32:26 -07001570status_t StagefrightRecorder::dump(
1571 int fd, const Vector<String16>& args) const {
1572 LOGV("dump");
James Dong929642e2010-07-08 11:16:11 -07001573 const size_t SIZE = 256;
1574 char buffer[SIZE];
1575 String8 result;
James Dong3f51fa72010-08-18 03:32:26 -07001576 if (mWriter != 0) {
1577 mWriter->dump(fd, args);
1578 } else {
1579 snprintf(buffer, SIZE, " No file writer\n");
1580 result.append(buffer);
1581 }
1582 snprintf(buffer, SIZE, " Recorder: %p\n", this);
James Dong929642e2010-07-08 11:16:11 -07001583 snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
1584 result.append(buffer);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001585 snprintf(buffer, SIZE, " Output file Auxiliary (fd %d):\n", mOutputFdAux);
1586 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001587 snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
1588 result.append(buffer);
1589 snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1590 result.append(buffer);
1591 snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
1592 result.append(buffer);
1593 snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1594 result.append(buffer);
1595 snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
1596 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001597 snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1598 result.append(buffer);
1599 snprintf(buffer, SIZE, " Audio\n");
1600 result.append(buffer);
1601 snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
1602 result.append(buffer);
1603 snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
1604 result.append(buffer);
1605 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
1606 result.append(buffer);
1607 snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
1608 result.append(buffer);
1609 snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
1610 result.append(buffer);
1611 snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1612 result.append(buffer);
1613 snprintf(buffer, SIZE, " Video\n");
1614 result.append(buffer);
1615 snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
1616 result.append(buffer);
1617 snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
1618 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001619 snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
1620 result.append(buffer);
1621 snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
1622 result.append(buffer);
1623 snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
1624 result.append(buffer);
James Dong52d13f02010-07-02 11:39:06 -07001625 snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec);
James Dong929642e2010-07-08 11:16:11 -07001626 result.append(buffer);
1627 snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1628 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001629 snprintf(buffer, SIZE, " Aux Frame size (pixels): %dx%d\n", mAuxVideoWidth, mAuxVideoHeight);
1630 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001631 snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
1632 result.append(buffer);
1633 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
1634 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001635 snprintf(buffer, SIZE, " Aux Bit rate (bps): %d\n", mAuxVideoBitRate);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001636 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001637 ::write(fd, result.string(), result.size());
1638 return OK;
1639}
Andreas Huberea6a38c2009-11-16 15:43:38 -08001640} // namespace android