blob: c1687c4f95f9ab9596efa12b3224dde4da3d21b7 [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
Gloria Wang62e05a62011-02-23 11:47:34 -080023#include <binder/IPCThreadState.h>
24#include <binder/IServiceManager.h>
25
26#include <media/IMediaPlayerService.h>
Andreas Huber996dddf2010-01-25 15:30:31 -080027#include <media/stagefright/AudioSource.h>
28#include <media/stagefright/AMRWriter.h>
James Dongf84bfab2011-03-21 14:29:38 -070029#include <media/stagefright/AACWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080030#include <media/stagefright/CameraSource.h>
Nipun Kwatra239f2e52010-08-31 15:35:44 -070031#include <media/stagefright/VideoSourceDownSampler.h>
Nipun Kwatraf9b80182010-07-12 09:17:14 -070032#include <media/stagefright/CameraSourceTimeLapse.h>
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070033#include <media/stagefright/MediaSourceSplitter.h>
Andreas Huber9adf4662010-10-12 14:17:45 -070034#include <media/stagefright/MPEG2TSWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080035#include <media/stagefright/MPEG4Writer.h>
36#include <media/stagefright/MediaDebug.h>
37#include <media/stagefright/MediaDefs.h>
38#include <media/stagefright/MetaData.h>
39#include <media/stagefright/OMXClient.h>
40#include <media/stagefright/OMXCodec.h>
James Dong42a18c02010-06-16 17:27:46 -070041#include <media/MediaProfiles.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080042#include <camera/ICamera.h>
James Dong2cd841d2010-05-11 11:46:59 -070043#include <camera/CameraParameters.h>
Jamie Gennis85cfdd02010-08-10 16:37:53 -070044#include <surfaceflinger/Surface.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080045#include <utils/Errors.h>
James Dongb00e2462010-04-26 17:48:26 -070046#include <sys/types.h>
James Dongabed93a2010-04-22 17:27:04 -070047#include <ctype.h>
Nipun Kwatra453e92f2010-08-04 14:26:45 -070048#include <unistd.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080049
Dima Zavin24fc2fb2011-04-19 22:30:36 -070050#include <hardware/audio.h>
51
Andreas Huber57648e42010-08-04 10:14:30 -070052#include "ARTPWriter.h"
53
Andreas Huberea6a38c2009-11-16 15:43:38 -080054namespace android {
55
Gloria Wang62e05a62011-02-23 11:47:34 -080056// To collect the encoder usage for the battery app
57static void addBatteryData(uint32_t params) {
58 sp<IBinder> binder =
59 defaultServiceManager()->getService(String16("media.player"));
60 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
61 CHECK(service.get() != NULL);
62
63 service->addBatteryData(params);
64}
65
66
James Dongc0ab2a62010-06-29 16:29:19 -070067StagefrightRecorder::StagefrightRecorder()
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070068 : mWriter(NULL), mWriterAux(NULL),
Gloria Wang62e05a62011-02-23 11:47:34 -080069 mOutputFd(-1), mOutputFdAux(-1),
Dima Zavin24fc2fb2011-04-19 22:30:36 -070070 mAudioSource(AUDIO_SOURCE_CNT),
Gloria Wang62e05a62011-02-23 11:47:34 -080071 mVideoSource(VIDEO_SOURCE_LIST_END),
72 mStarted(false) {
James Dongc0ab2a62010-06-29 16:29:19 -070073
74 LOGV("Constructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080075 reset();
76}
77
78StagefrightRecorder::~StagefrightRecorder() {
James Dongc0ab2a62010-06-29 16:29:19 -070079 LOGV("Destructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080080 stop();
Andreas Huberea6a38c2009-11-16 15:43:38 -080081}
82
83status_t StagefrightRecorder::init() {
James Dongc0ab2a62010-06-29 16:29:19 -070084 LOGV("init");
Andreas Huberea6a38c2009-11-16 15:43:38 -080085 return OK;
86}
87
Dima Zavin24fc2fb2011-04-19 22:30:36 -070088status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
James Dongc0ab2a62010-06-29 16:29:19 -070089 LOGV("setAudioSource: %d", as);
90 if (as < AUDIO_SOURCE_DEFAULT ||
Dima Zavin24fc2fb2011-04-19 22:30:36 -070091 as >= AUDIO_SOURCE_CNT) {
James Dong7b06de62010-06-30 12:41:16 -070092 LOGE("Invalid audio source: %d", as);
James Dongc0ab2a62010-06-29 16:29:19 -070093 return BAD_VALUE;
94 }
95
96 if (as == AUDIO_SOURCE_DEFAULT) {
97 mAudioSource = AUDIO_SOURCE_MIC;
98 } else {
99 mAudioSource = as;
100 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800101
102 return OK;
103}
104
105status_t StagefrightRecorder::setVideoSource(video_source vs) {
James Dongc0ab2a62010-06-29 16:29:19 -0700106 LOGV("setVideoSource: %d", vs);
107 if (vs < VIDEO_SOURCE_DEFAULT ||
108 vs >= VIDEO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700109 LOGE("Invalid video source: %d", vs);
James Dongc0ab2a62010-06-29 16:29:19 -0700110 return BAD_VALUE;
111 }
112
113 if (vs == VIDEO_SOURCE_DEFAULT) {
114 mVideoSource = VIDEO_SOURCE_CAMERA;
115 } else {
116 mVideoSource = vs;
117 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800118
119 return OK;
120}
121
122status_t StagefrightRecorder::setOutputFormat(output_format of) {
James Dongc0ab2a62010-06-29 16:29:19 -0700123 LOGV("setOutputFormat: %d", of);
124 if (of < OUTPUT_FORMAT_DEFAULT ||
125 of >= OUTPUT_FORMAT_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700126 LOGE("Invalid output format: %d", of);
James Dongc0ab2a62010-06-29 16:29:19 -0700127 return BAD_VALUE;
128 }
129
130 if (of == OUTPUT_FORMAT_DEFAULT) {
131 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
132 } else {
133 mOutputFormat = of;
134 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800135
136 return OK;
137}
138
139status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
James Dongc0ab2a62010-06-29 16:29:19 -0700140 LOGV("setAudioEncoder: %d", ae);
141 if (ae < AUDIO_ENCODER_DEFAULT ||
142 ae >= AUDIO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700143 LOGE("Invalid audio encoder: %d", ae);
James Dongc0ab2a62010-06-29 16:29:19 -0700144 return BAD_VALUE;
145 }
146
147 if (ae == AUDIO_ENCODER_DEFAULT) {
148 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
149 } else {
150 mAudioEncoder = ae;
151 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800152
153 return OK;
154}
155
156status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
James Dongc0ab2a62010-06-29 16:29:19 -0700157 LOGV("setVideoEncoder: %d", ve);
158 if (ve < VIDEO_ENCODER_DEFAULT ||
159 ve >= VIDEO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700160 LOGE("Invalid video encoder: %d", ve);
James Dongc0ab2a62010-06-29 16:29:19 -0700161 return BAD_VALUE;
162 }
163
164 if (ve == VIDEO_ENCODER_DEFAULT) {
165 mVideoEncoder = VIDEO_ENCODER_H263;
166 } else {
167 mVideoEncoder = ve;
168 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800169
170 return OK;
171}
172
173status_t StagefrightRecorder::setVideoSize(int width, int height) {
James Dongc0ab2a62010-06-29 16:29:19 -0700174 LOGV("setVideoSize: %dx%d", width, height);
James Dong2cd841d2010-05-11 11:46:59 -0700175 if (width <= 0 || height <= 0) {
176 LOGE("Invalid video size: %dx%d", width, height);
177 return BAD_VALUE;
178 }
179
180 // Additional check on the dimension will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800181 mVideoWidth = width;
182 mVideoHeight = height;
183
184 return OK;
185}
186
187status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
James Dongc0ab2a62010-06-29 16:29:19 -0700188 LOGV("setVideoFrameRate: %d", frames_per_second);
James Dongb15f2ea2010-10-24 09:32:39 -0700189 if ((frames_per_second <= 0 && frames_per_second != -1) ||
190 frames_per_second > 120) {
James Dong2cd841d2010-05-11 11:46:59 -0700191 LOGE("Invalid video frame rate: %d", frames_per_second);
192 return BAD_VALUE;
193 }
194
195 // Additional check on the frame rate will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800196 mFrameRate = frames_per_second;
197
198 return OK;
199}
200
201status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
James Dong71d714c2010-06-09 15:57:48 -0700202 LOGV("setCamera");
James Dongb00e2462010-04-26 17:48:26 -0700203 if (camera == 0) {
204 LOGE("camera is NULL");
James Dong7b06de62010-06-30 12:41:16 -0700205 return BAD_VALUE;
James Dongb00e2462010-04-26 17:48:26 -0700206 }
207
James Dong0c128b62010-10-08 11:59:32 -0700208 mCamera = camera;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800209 return OK;
210}
211
Jamie Gennis85cfdd02010-08-10 16:37:53 -0700212status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
James Dongc0ab2a62010-06-29 16:29:19 -0700213 LOGV("setPreviewSurface: %p", surface.get());
Andreas Huberea6a38c2009-11-16 15:43:38 -0800214 mPreviewSurface = surface;
215
216 return OK;
217}
218
219status_t StagefrightRecorder::setOutputFile(const char *path) {
James Dong7b06de62010-06-30 12:41:16 -0700220 LOGE("setOutputFile(const char*) must not be called");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800221 // We don't actually support this at all, as the media_server process
222 // no longer has permissions to create files.
223
James Dong7b06de62010-06-30 12:41:16 -0700224 return -EPERM;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800225}
226
227status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
James Dongc0ab2a62010-06-29 16:29:19 -0700228 LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800229 // These don't make any sense, do they?
230 CHECK_EQ(offset, 0);
231 CHECK_EQ(length, 0);
232
James Dong7b06de62010-06-30 12:41:16 -0700233 if (fd < 0) {
234 LOGE("Invalid file descriptor: %d", fd);
235 return -EBADF;
236 }
237
Andreas Huberea6a38c2009-11-16 15:43:38 -0800238 if (mOutputFd >= 0) {
239 ::close(mOutputFd);
240 }
241 mOutputFd = dup(fd);
242
243 return OK;
244}
245
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700246status_t StagefrightRecorder::setOutputFileAuxiliary(int fd) {
247 LOGV("setOutputFileAuxiliary: %d", fd);
248
249 if (fd < 0) {
250 LOGE("Invalid file descriptor: %d", fd);
251 return -EBADF;
252 }
253
254 mCaptureAuxVideo = true;
255
256 if (mOutputFdAux >= 0) {
257 ::close(mOutputFdAux);
258 }
259 mOutputFdAux = dup(fd);
260
261 return OK;
262}
263
James Dongabed93a2010-04-22 17:27:04 -0700264// Attempt to parse an int64 literal optionally surrounded by whitespace,
265// returns true on success, false otherwise.
James Dong2cd841d2010-05-11 11:46:59 -0700266static bool safe_strtoi64(const char *s, int64_t *val) {
James Dongabed93a2010-04-22 17:27:04 -0700267 char *end;
James Dong75fb2382011-02-08 15:41:58 -0800268
269 // It is lame, but according to man page, we have to set errno to 0
270 // before calling strtoll().
271 errno = 0;
James Dong2cd841d2010-05-11 11:46:59 -0700272 *val = strtoll(s, &end, 10);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800273
James Dongabed93a2010-04-22 17:27:04 -0700274 if (end == s || errno == ERANGE) {
275 return false;
276 }
277
278 // Skip trailing whitespace
279 while (isspace(*end)) {
280 ++end;
281 }
282
283 // For a successful return, the string must contain nothing but a valid
284 // int64 literal optionally surrounded by whitespace.
285
286 return *end == '\0';
287}
288
James Dong2cd841d2010-05-11 11:46:59 -0700289// Return true if the value is in [0, 0x007FFFFFFF]
290static bool safe_strtoi32(const char *s, int32_t *val) {
291 int64_t temp;
292 if (safe_strtoi64(s, &temp)) {
293 if (temp >= 0 && temp <= 0x007FFFFFFF) {
294 *val = static_cast<int32_t>(temp);
295 return true;
296 }
297 }
298 return false;
299}
300
James Dongabed93a2010-04-22 17:27:04 -0700301// Trim both leading and trailing whitespace from the given string.
302static void TrimString(String8 *s) {
303 size_t num_bytes = s->bytes();
304 const char *data = s->string();
305
306 size_t leading_space = 0;
307 while (leading_space < num_bytes && isspace(data[leading_space])) {
308 ++leading_space;
309 }
310
311 size_t i = num_bytes;
312 while (i > leading_space && isspace(data[i - 1])) {
313 --i;
314 }
315
316 s->setTo(String8(&data[leading_space], i - leading_space));
317}
318
319status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
320 LOGV("setParamAudioSamplingRate: %d", sampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700321 if (sampleRate <= 0) {
322 LOGE("Invalid audio sampling rate: %d", sampleRate);
323 return BAD_VALUE;
324 }
325
326 // Additional check on the sample rate will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700327 mSampleRate = sampleRate;
328 return OK;
329}
330
331status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
332 LOGV("setParamAudioNumberOfChannels: %d", channels);
James Dong2cd841d2010-05-11 11:46:59 -0700333 if (channels <= 0 || channels >= 3) {
334 LOGE("Invalid number of audio channels: %d", channels);
James Dong7b06de62010-06-30 12:41:16 -0700335 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700336 }
337
338 // Additional check on the number of channels will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700339 mAudioChannels = channels;
340 return OK;
341}
342
343status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
344 LOGV("setParamAudioEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700345 if (bitRate <= 0) {
346 LOGE("Invalid audio encoding bit rate: %d", bitRate);
347 return BAD_VALUE;
348 }
349
350 // The target bit rate may not be exactly the same as the requested.
351 // It depends on many factors, such as rate control, and the bit rate
352 // range that a specific encoder supports. The mismatch between the
353 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700354 mAudioBitRate = bitRate;
355 return OK;
356}
357
358status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
359 LOGV("setParamVideoEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700360 if (bitRate <= 0) {
361 LOGE("Invalid video encoding bit rate: %d", bitRate);
362 return BAD_VALUE;
363 }
364
365 // The target bit rate may not be exactly the same as the requested.
366 // It depends on many factors, such as rate control, and the bit rate
367 // range that a specific encoder supports. The mismatch between the
368 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700369 mVideoBitRate = bitRate;
370 return OK;
371}
372
James Dongb9d7e012010-11-09 11:15:47 -0800373// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
374status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
375 LOGV("setParamVideoRotation: %d", degrees);
376 if (degrees < 0 || degrees % 90 != 0) {
377 LOGE("Unsupported video rotation angle: %d", degrees);
378 return BAD_VALUE;
379 }
380 mRotationDegrees = degrees % 360;
381 return OK;
382}
383
James Dong7b06de62010-06-30 12:41:16 -0700384status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
385 LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
James Dong26ea64c2010-12-20 11:39:38 -0800386
387 // This is meant for backward compatibility for MediaRecorder.java
Nipun Kwatrafb457482010-08-18 15:19:19 -0700388 if (timeUs <= 0) {
389 LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
390 timeUs = 0; // Disable the duration limit for zero or negative values.
391 } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
James Dong7b06de62010-06-30 12:41:16 -0700392 LOGE("Max file duration is too short: %lld us", timeUs);
393 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700394 }
Nipun Kwatrafb457482010-08-18 15:19:19 -0700395
James Dong5cdcf162010-11-30 18:18:08 -0800396 if (timeUs <= 15 * 1000000LL) {
397 LOGW("Target duration (%lld us) too short to be respected", timeUs);
398 }
James Dong7b06de62010-06-30 12:41:16 -0700399 mMaxFileDurationUs = timeUs;
400 return OK;
401}
402
403status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
404 LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
James Dong26ea64c2010-12-20 11:39:38 -0800405
406 // This is meant for backward compatibility for MediaRecorder.java
407 if (bytes <= 0) {
408 LOGW("Max file size is not positive: %lld bytes. "
409 "Disabling file size limit.", bytes);
410 bytes = 0; // Disable the file size limit for zero or negative values.
411 } else if (bytes <= 1024) { // XXX: 1 kB
James Dong7b06de62010-06-30 12:41:16 -0700412 LOGE("Max file size is too small: %lld bytes", bytes);
413 return BAD_VALUE;
414 }
James Dong5cdcf162010-11-30 18:18:08 -0800415
416 if (bytes <= 100 * 1024) {
417 LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
418 }
419
James Dong7b06de62010-06-30 12:41:16 -0700420 mMaxFileSizeBytes = bytes;
James Dongabed93a2010-04-22 17:27:04 -0700421 return OK;
422}
423
James Dong3300e962010-04-21 16:14:15 -0700424status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
425 LOGV("setParamInterleaveDuration: %d", durationUs);
James Dong1244eab2010-06-08 11:58:53 -0700426 if (durationUs <= 500000) { // 500 ms
427 // If interleave duration is too small, it is very inefficient to do
428 // interleaving since the metadata overhead will count for a significant
429 // portion of the saved contents
James Dong2cd841d2010-05-11 11:46:59 -0700430 LOGE("Audio/video interleave duration is too small: %d us", durationUs);
431 return BAD_VALUE;
James Dong1244eab2010-06-08 11:58:53 -0700432 } else if (durationUs >= 10000000) { // 10 seconds
433 // If interleaving duration is too large, it can cause the recording
434 // session to use too much memory since we have to save the output
435 // data before we write them out
436 LOGE("Audio/video interleave duration is too large: %d us", durationUs);
437 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700438 }
James Dong3300e962010-04-21 16:14:15 -0700439 mInterleaveDurationUs = durationUs;
440 return OK;
441}
James Dong2cd841d2010-05-11 11:46:59 -0700442
James Dong52d13f02010-07-02 11:39:06 -0700443// If seconds < 0, only the first frame is I frame, and rest are all P frames
444// If seconds == 0, all frames are encoded as I frames. No P frames
445// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames
446status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
447 LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
448 mIFramesIntervalSec = seconds;
James Dong1244eab2010-06-08 11:58:53 -0700449 return OK;
450}
451
James Dong6feaa462010-06-20 08:20:54 -0700452status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
453 LOGV("setParam64BitFileOffset: %s",
454 use64Bit? "use 64 bit file offset": "use 32 bit file offset");
455 mUse64BitFileOffset = use64Bit;
456 return OK;
457}
458
James Dong09936ed2010-06-24 19:04:27 -0700459status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
460 LOGV("setParamVideoCameraId: %d", cameraId);
461 if (cameraId < 0) {
462 return BAD_VALUE;
463 }
464 mCameraId = cameraId;
465 return OK;
466}
467
James Dong09936ed2010-06-24 19:04:27 -0700468status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
469 LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
470 if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
James Dong7b06de62010-06-30 12:41:16 -0700471 LOGE("Tracking time duration too short: %lld us", timeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -0700472 return BAD_VALUE;
473 }
474 mTrackEveryTimeDurationUs = timeDurationUs;
475 return OK;
476}
477
James Dong81c929a2010-07-01 15:02:14 -0700478status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
479 LOGV("setParamVideoEncoderProfile: %d", profile);
480
481 // Additional check will be done later when we load the encoder.
482 // For now, we are accepting values defined in OpenMAX IL.
483 mVideoEncoderProfile = profile;
484 return OK;
485}
486
487status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
488 LOGV("setParamVideoEncoderLevel: %d", level);
489
490 // Additional check will be done later when we load the encoder.
491 // For now, we are accepting values defined in OpenMAX IL.
492 mVideoEncoderLevel = level;
493 return OK;
494}
495
James Dong52d13f02010-07-02 11:39:06 -0700496status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
497 LOGV("setParamMovieTimeScale: %d", timeScale);
498
499 // The range is set to be the same as the audio's time scale range
500 // since audio's time scale has a wider range.
501 if (timeScale < 600 || timeScale > 96000) {
502 LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
503 return BAD_VALUE;
504 }
505 mMovieTimeScale = timeScale;
506 return OK;
507}
508
509status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
510 LOGV("setParamVideoTimeScale: %d", timeScale);
511
512 // 60000 is chosen to make sure that each video frame from a 60-fps
513 // video has 1000 ticks.
514 if (timeScale < 600 || timeScale > 60000) {
515 LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
516 return BAD_VALUE;
517 }
518 mVideoTimeScale = timeScale;
519 return OK;
520}
521
522status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
523 LOGV("setParamAudioTimeScale: %d", timeScale);
524
525 // 96000 Hz is the highest sampling rate support in AAC.
526 if (timeScale < 600 || timeScale > 96000) {
527 LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
528 return BAD_VALUE;
529 }
530 mAudioTimeScale = timeScale;
531 return OK;
532}
533
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700534status_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
535 LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
536
537 if(timeLapseEnable == 0) {
538 mCaptureTimeLapse = false;
539 } else if (timeLapseEnable == 1) {
540 mCaptureTimeLapse = true;
541 } else {
542 return BAD_VALUE;
543 }
544 return OK;
545}
546
547status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
548 LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
549
550 // Not allowing time more than a day
551 if (timeUs <= 0 || timeUs > 86400*1E6) {
552 LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
553 return BAD_VALUE;
554 }
555
556 mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
557 return OK;
558}
559
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700560status_t StagefrightRecorder::setParamAuxVideoWidth(int32_t width) {
561 LOGV("setParamAuxVideoWidth : %d", width);
562
563 if (width <= 0) {
564 LOGE("Width (%d) is not positive", width);
565 return BAD_VALUE;
566 }
567
568 mAuxVideoWidth = width;
569 return OK;
570}
571
572status_t StagefrightRecorder::setParamAuxVideoHeight(int32_t height) {
573 LOGV("setParamAuxVideoHeight : %d", height);
574
575 if (height <= 0) {
576 LOGE("Height (%d) is not positive", height);
577 return BAD_VALUE;
578 }
579
580 mAuxVideoHeight = height;
581 return OK;
582}
583
584status_t StagefrightRecorder::setParamAuxVideoEncodingBitRate(int32_t bitRate) {
585 LOGV("StagefrightRecorder::setParamAuxVideoEncodingBitRate: %d", bitRate);
586
587 if (bitRate <= 0) {
588 LOGE("Invalid video encoding bit rate: %d", bitRate);
589 return BAD_VALUE;
590 }
591
592 mAuxVideoBitRate = bitRate;
593 return OK;
594}
595
James Dongabed93a2010-04-22 17:27:04 -0700596status_t StagefrightRecorder::setParameter(
597 const String8 &key, const String8 &value) {
598 LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
599 if (key == "max-duration") {
James Dong2cd841d2010-05-11 11:46:59 -0700600 int64_t max_duration_ms;
James Dongabed93a2010-04-22 17:27:04 -0700601 if (safe_strtoi64(value.string(), &max_duration_ms)) {
James Dong7b06de62010-06-30 12:41:16 -0700602 return setParamMaxFileDurationUs(1000LL * max_duration_ms);
James Dongabed93a2010-04-22 17:27:04 -0700603 }
604 } else if (key == "max-filesize") {
James Dong2cd841d2010-05-11 11:46:59 -0700605 int64_t max_filesize_bytes;
James Dongabed93a2010-04-22 17:27:04 -0700606 if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
James Dong7b06de62010-06-30 12:41:16 -0700607 return setParamMaxFileSizeBytes(max_filesize_bytes);
James Dongabed93a2010-04-22 17:27:04 -0700608 }
James Dong09936ed2010-06-24 19:04:27 -0700609 } else if (key == "interleave-duration-us") {
610 int32_t durationUs;
611 if (safe_strtoi32(value.string(), &durationUs)) {
612 return setParamInterleaveDuration(durationUs);
613 }
James Dong52d13f02010-07-02 11:39:06 -0700614 } else if (key == "param-movie-time-scale") {
615 int32_t timeScale;
616 if (safe_strtoi32(value.string(), &timeScale)) {
617 return setParamMovieTimeScale(timeScale);
618 }
James Dong09936ed2010-06-24 19:04:27 -0700619 } else if (key == "param-use-64bit-offset") {
620 int32_t use64BitOffset;
621 if (safe_strtoi32(value.string(), &use64BitOffset)) {
622 return setParam64BitFileOffset(use64BitOffset != 0);
623 }
James Dong09936ed2010-06-24 19:04:27 -0700624 } else if (key == "param-track-time-status") {
625 int64_t timeDurationUs;
626 if (safe_strtoi64(value.string(), &timeDurationUs)) {
627 return setParamTrackTimeStatus(timeDurationUs);
628 }
James Dongabed93a2010-04-22 17:27:04 -0700629 } else if (key == "audio-param-sampling-rate") {
630 int32_t sampling_rate;
James Dong2cd841d2010-05-11 11:46:59 -0700631 if (safe_strtoi32(value.string(), &sampling_rate)) {
James Dongabed93a2010-04-22 17:27:04 -0700632 return setParamAudioSamplingRate(sampling_rate);
633 }
634 } else if (key == "audio-param-number-of-channels") {
635 int32_t number_of_channels;
James Dong2cd841d2010-05-11 11:46:59 -0700636 if (safe_strtoi32(value.string(), &number_of_channels)) {
James Dongabed93a2010-04-22 17:27:04 -0700637 return setParamAudioNumberOfChannels(number_of_channels);
638 }
639 } else if (key == "audio-param-encoding-bitrate") {
640 int32_t audio_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700641 if (safe_strtoi32(value.string(), &audio_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700642 return setParamAudioEncodingBitRate(audio_bitrate);
643 }
James Dong52d13f02010-07-02 11:39:06 -0700644 } else if (key == "audio-param-time-scale") {
645 int32_t timeScale;
646 if (safe_strtoi32(value.string(), &timeScale)) {
647 return setParamAudioTimeScale(timeScale);
648 }
James Dongabed93a2010-04-22 17:27:04 -0700649 } else if (key == "video-param-encoding-bitrate") {
650 int32_t video_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700651 if (safe_strtoi32(value.string(), &video_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700652 return setParamVideoEncodingBitRate(video_bitrate);
653 }
James Dongb9d7e012010-11-09 11:15:47 -0800654 } else if (key == "video-param-rotation-angle-degrees") {
655 int32_t degrees;
656 if (safe_strtoi32(value.string(), &degrees)) {
657 return setParamVideoRotation(degrees);
658 }
James Dong09936ed2010-06-24 19:04:27 -0700659 } else if (key == "video-param-i-frames-interval") {
James Dong52d13f02010-07-02 11:39:06 -0700660 int32_t seconds;
661 if (safe_strtoi32(value.string(), &seconds)) {
662 return setParamVideoIFramesInterval(seconds);
James Dong1244eab2010-06-08 11:58:53 -0700663 }
James Dong81c929a2010-07-01 15:02:14 -0700664 } else if (key == "video-param-encoder-profile") {
665 int32_t profile;
666 if (safe_strtoi32(value.string(), &profile)) {
667 return setParamVideoEncoderProfile(profile);
668 }
669 } else if (key == "video-param-encoder-level") {
670 int32_t level;
671 if (safe_strtoi32(value.string(), &level)) {
672 return setParamVideoEncoderLevel(level);
673 }
James Dong09936ed2010-06-24 19:04:27 -0700674 } else if (key == "video-param-camera-id") {
675 int32_t cameraId;
676 if (safe_strtoi32(value.string(), &cameraId)) {
677 return setParamVideoCameraId(cameraId);
James Dong6feaa462010-06-20 08:20:54 -0700678 }
James Dong52d13f02010-07-02 11:39:06 -0700679 } else if (key == "video-param-time-scale") {
680 int32_t timeScale;
681 if (safe_strtoi32(value.string(), &timeScale)) {
682 return setParamVideoTimeScale(timeScale);
683 }
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700684 } else if (key == "time-lapse-enable") {
685 int32_t timeLapseEnable;
686 if (safe_strtoi32(value.string(), &timeLapseEnable)) {
687 return setParamTimeLapseEnable(timeLapseEnable);
688 }
689 } else if (key == "time-between-time-lapse-frame-capture") {
690 int64_t timeBetweenTimeLapseFrameCaptureMs;
691 if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
692 return setParamTimeBetweenTimeLapseFrameCapture(
693 1000LL * timeBetweenTimeLapseFrameCaptureMs);
694 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700695 } else if (key == "video-aux-param-width") {
696 int32_t auxWidth;
697 if (safe_strtoi32(value.string(), &auxWidth)) {
698 return setParamAuxVideoWidth(auxWidth);
699 }
700 } else if (key == "video-aux-param-height") {
701 int32_t auxHeight;
702 if (safe_strtoi32(value.string(), &auxHeight)) {
703 return setParamAuxVideoHeight(auxHeight);
704 }
705 } else if (key == "video-aux-param-encoding-bitrate") {
706 int32_t auxVideoBitRate;
707 if (safe_strtoi32(value.string(), &auxVideoBitRate)) {
708 return setParamAuxVideoEncodingBitRate(auxVideoBitRate);
709 }
James Dongabed93a2010-04-22 17:27:04 -0700710 } else {
711 LOGE("setParameter: failed to find key %s", key.string());
James Dongabed93a2010-04-22 17:27:04 -0700712 }
James Dong2cd841d2010-05-11 11:46:59 -0700713 return BAD_VALUE;
James Dongabed93a2010-04-22 17:27:04 -0700714}
715
716status_t StagefrightRecorder::setParameters(const String8 &params) {
717 LOGV("setParameters: %s", params.string());
718 const char *cparams = params.string();
719 const char *key_start = cparams;
720 for (;;) {
721 const char *equal_pos = strchr(key_start, '=');
722 if (equal_pos == NULL) {
723 LOGE("Parameters %s miss a value", cparams);
724 return BAD_VALUE;
725 }
726 String8 key(key_start, equal_pos - key_start);
727 TrimString(&key);
728 if (key.length() == 0) {
729 LOGE("Parameters %s contains an empty key", cparams);
730 return BAD_VALUE;
731 }
732 const char *value_start = equal_pos + 1;
733 const char *semicolon_pos = strchr(value_start, ';');
734 String8 value;
735 if (semicolon_pos == NULL) {
736 value.setTo(value_start);
737 } else {
738 value.setTo(value_start, semicolon_pos - value_start);
739 }
740 if (setParameter(key, value) != OK) {
741 return BAD_VALUE;
742 }
743 if (semicolon_pos == NULL) {
744 break; // Reaches the end
745 }
746 key_start = semicolon_pos + 1;
747 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800748 return OK;
749}
750
James Dongfe1bafe2010-06-25 17:06:47 -0700751status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
Andreas Huberea6a38c2009-11-16 15:43:38 -0800752 mListener = listener;
753
754 return OK;
755}
756
757status_t StagefrightRecorder::prepare() {
758 return OK;
759}
760
761status_t StagefrightRecorder::start() {
James Dong7b06de62010-06-30 12:41:16 -0700762 CHECK(mOutputFd >= 0);
763
Andreas Huberea6a38c2009-11-16 15:43:38 -0800764 if (mWriter != NULL) {
James Dong7b06de62010-06-30 12:41:16 -0700765 LOGE("File writer is not avaialble");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800766 return UNKNOWN_ERROR;
767 }
768
Gloria Wang62e05a62011-02-23 11:47:34 -0800769 status_t status = OK;
770
Andreas Huber996dddf2010-01-25 15:30:31 -0800771 switch (mOutputFormat) {
772 case OUTPUT_FORMAT_DEFAULT:
773 case OUTPUT_FORMAT_THREE_GPP:
774 case OUTPUT_FORMAT_MPEG_4:
Gloria Wang62e05a62011-02-23 11:47:34 -0800775 status = startMPEG4Recording();
776 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800777
778 case OUTPUT_FORMAT_AMR_NB:
779 case OUTPUT_FORMAT_AMR_WB:
Gloria Wang62e05a62011-02-23 11:47:34 -0800780 status = startAMRRecording();
781 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800782
James Dong2cd841d2010-05-11 11:46:59 -0700783 case OUTPUT_FORMAT_AAC_ADIF:
784 case OUTPUT_FORMAT_AAC_ADTS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800785 status = startAACRecording();
786 break;
James Dong2cd841d2010-05-11 11:46:59 -0700787
Andreas Huber57648e42010-08-04 10:14:30 -0700788 case OUTPUT_FORMAT_RTP_AVP:
Gloria Wang62e05a62011-02-23 11:47:34 -0800789 status = startRTPRecording();
790 break;
Andreas Huber57648e42010-08-04 10:14:30 -0700791
Andreas Huber9adf4662010-10-12 14:17:45 -0700792 case OUTPUT_FORMAT_MPEG2TS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800793 status = startMPEG2TSRecording();
794 break;
Andreas Huber9adf4662010-10-12 14:17:45 -0700795
Andreas Huber996dddf2010-01-25 15:30:31 -0800796 default:
James Dong7b06de62010-06-30 12:41:16 -0700797 LOGE("Unsupported output file format: %d", mOutputFormat);
Gloria Wang62e05a62011-02-23 11:47:34 -0800798 status = UNKNOWN_ERROR;
799 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800800 }
Gloria Wang62e05a62011-02-23 11:47:34 -0800801
802 if ((status == OK) && (!mStarted)) {
803 mStarted = true;
804
805 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700806 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -0800807 params |= IMediaPlayerService::kBatteryDataTrackAudio;
808 }
809 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
810 params |= IMediaPlayerService::kBatteryDataTrackVideo;
811 }
812
813 addBatteryData(params);
814 }
815
816 return status;
Andreas Huber996dddf2010-01-25 15:30:31 -0800817}
818
James Dongabed93a2010-04-22 17:27:04 -0700819sp<MediaSource> StagefrightRecorder::createAudioSource() {
Andreas Huber996dddf2010-01-25 15:30:31 -0800820 sp<AudioSource> audioSource =
821 new AudioSource(
822 mAudioSource,
James Dongabed93a2010-04-22 17:27:04 -0700823 mSampleRate,
James Dongd77d2a92010-06-14 17:45:35 -0700824 mAudioChannels);
Andreas Huber996dddf2010-01-25 15:30:31 -0800825
826 status_t err = audioSource->initCheck();
827
828 if (err != OK) {
James Dongabed93a2010-04-22 17:27:04 -0700829 LOGE("audio source is not initialized");
Andreas Huber996dddf2010-01-25 15:30:31 -0800830 return NULL;
831 }
832
833 sp<MetaData> encMeta = new MetaData;
James Dongabed93a2010-04-22 17:27:04 -0700834 const char *mime;
835 switch (mAudioEncoder) {
836 case AUDIO_ENCODER_AMR_NB:
837 case AUDIO_ENCODER_DEFAULT:
838 mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
839 break;
840 case AUDIO_ENCODER_AMR_WB:
841 mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
842 break;
843 case AUDIO_ENCODER_AAC:
844 mime = MEDIA_MIMETYPE_AUDIO_AAC;
845 break;
846 default:
847 LOGE("Unknown audio encoder: %d", mAudioEncoder);
848 return NULL;
849 }
850 encMeta->setCString(kKeyMIMEType, mime);
Andreas Huber996dddf2010-01-25 15:30:31 -0800851
Andreas Huber259b7c12010-02-10 15:04:31 -0800852 int32_t maxInputSize;
853 CHECK(audioSource->getFormat()->findInt32(
854 kKeyMaxInputSize, &maxInputSize));
855
856 encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
James Dongabed93a2010-04-22 17:27:04 -0700857 encMeta->setInt32(kKeyChannelCount, mAudioChannels);
858 encMeta->setInt32(kKeySampleRate, mSampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700859 encMeta->setInt32(kKeyBitRate, mAudioBitRate);
James Dongeff30e32010-08-13 14:16:26 -0700860 if (mAudioTimeScale > 0) {
861 encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
862 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800863
864 OMXClient client;
865 CHECK_EQ(client.connect(), OK);
866
867 sp<MediaSource> audioEncoder =
868 OMXCodec::Create(client.interface(), encMeta,
869 true /* createEncoder */, audioSource);
James Dong57e7f832010-06-24 19:55:31 -0700870 mAudioSourceNode = audioSource;
Andreas Huber996dddf2010-01-25 15:30:31 -0800871
872 return audioEncoder;
873}
874
James Dong2cd841d2010-05-11 11:46:59 -0700875status_t StagefrightRecorder::startAACRecording() {
James Dongf84bfab2011-03-21 14:29:38 -0700876 // FIXME:
877 // Add support for OUTPUT_FORMAT_AAC_ADIF
878 CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
James Dong2cd841d2010-05-11 11:46:59 -0700879
880 CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700881 CHECK(mAudioSource != AUDIO_SOURCE_CNT);
James Dong2cd841d2010-05-11 11:46:59 -0700882
James Dongf84bfab2011-03-21 14:29:38 -0700883 mWriter = new AACWriter(mOutputFd);
884 status_t status = startRawAudioRecording();
885 if (status != OK) {
886 mWriter.clear();
887 mWriter = NULL;
888 }
James Dong2cd841d2010-05-11 11:46:59 -0700889
James Dongf84bfab2011-03-21 14:29:38 -0700890 return status;
James Dong2cd841d2010-05-11 11:46:59 -0700891}
892
Andreas Huber996dddf2010-01-25 15:30:31 -0800893status_t StagefrightRecorder::startAMRRecording() {
James Dong2cd841d2010-05-11 11:46:59 -0700894 CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
895 mOutputFormat == OUTPUT_FORMAT_AMR_WB);
896
897 if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
898 if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
899 mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
900 LOGE("Invalid encoder %d used for AMRNB recording",
901 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700902 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700903 }
James Dong2cd841d2010-05-11 11:46:59 -0700904 } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
905 if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
906 LOGE("Invlaid encoder %d used for AMRWB recording",
907 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700908 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700909 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800910 }
911
James Dongf84bfab2011-03-21 14:29:38 -0700912 mWriter = new AMRWriter(mOutputFd);
913 status_t status = startRawAudioRecording();
914 if (status != OK) {
915 mWriter.clear();
916 mWriter = NULL;
917 }
918 return status;
919}
920
921status_t StagefrightRecorder::startRawAudioRecording() {
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700922 if (mAudioSource >= AUDIO_SOURCE_CNT) {
James Dong2cd841d2010-05-11 11:46:59 -0700923 LOGE("Invalid audio source: %d", mAudioSource);
James Dong7b06de62010-06-30 12:41:16 -0700924 return BAD_VALUE;
Andreas Huber996dddf2010-01-25 15:30:31 -0800925 }
926
James Dong54815a72011-01-12 20:45:16 -0800927 status_t status = BAD_VALUE;
928 if (OK != (status = checkAudioEncoderCapabilities())) {
929 return status;
930 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800931
James Dong54815a72011-01-12 20:45:16 -0800932 sp<MediaSource> audioEncoder = createAudioSource();
Andreas Huber996dddf2010-01-25 15:30:31 -0800933 if (audioEncoder == NULL) {
934 return UNKNOWN_ERROR;
935 }
936
James Dongf84bfab2011-03-21 14:29:38 -0700937 CHECK(mWriter != 0);
Andreas Huber996dddf2010-01-25 15:30:31 -0800938 mWriter->addSource(audioEncoder);
James Dong18244862010-05-11 14:57:02 -0700939
940 if (mMaxFileDurationUs != 0) {
941 mWriter->setMaxFileDuration(mMaxFileDurationUs);
942 }
943 if (mMaxFileSizeBytes != 0) {
944 mWriter->setMaxFileSize(mMaxFileSizeBytes);
945 }
946 mWriter->setListener(mListener);
Andreas Huber996dddf2010-01-25 15:30:31 -0800947 mWriter->start();
948
949 return OK;
950}
951
Andreas Huber57648e42010-08-04 10:14:30 -0700952status_t StagefrightRecorder::startRTPRecording() {
953 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
954
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700955 if ((mAudioSource != AUDIO_SOURCE_CNT
Andreas Huber57648e42010-08-04 10:14:30 -0700956 && mVideoSource != VIDEO_SOURCE_LIST_END)
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700957 || (mAudioSource == AUDIO_SOURCE_CNT
Andreas Huber57648e42010-08-04 10:14:30 -0700958 && mVideoSource == VIDEO_SOURCE_LIST_END)) {
959 // Must have exactly one source.
960 return BAD_VALUE;
961 }
962
963 if (mOutputFd < 0) {
964 return BAD_VALUE;
965 }
966
967 sp<MediaSource> source;
968
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700969 if (mAudioSource != AUDIO_SOURCE_CNT) {
Andreas Huber57648e42010-08-04 10:14:30 -0700970 source = createAudioSource();
971 } else {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700972
973 sp<CameraSource> cameraSource;
974 status_t err = setupCameraSource(&cameraSource);
975 if (err != OK) {
976 return err;
977 }
978
979 err = setupVideoEncoder(cameraSource, mVideoBitRate, &source);
Andreas Huber57648e42010-08-04 10:14:30 -0700980 if (err != OK) {
981 return err;
982 }
983 }
984
James Dong2747e0e2010-11-18 20:59:13 -0800985 mWriter = new ARTPWriter(mOutputFd);
Andreas Huber57648e42010-08-04 10:14:30 -0700986 mWriter->addSource(source);
987 mWriter->setListener(mListener);
988
989 return mWriter->start();
990}
991
Andreas Huber9adf4662010-10-12 14:17:45 -0700992status_t StagefrightRecorder::startMPEG2TSRecording() {
993 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
994
James Dong2747e0e2010-11-18 20:59:13 -0800995 sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
Andreas Huber9adf4662010-10-12 14:17:45 -0700996
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700997 if (mAudioSource != AUDIO_SOURCE_CNT) {
Andreas Huber9adf4662010-10-12 14:17:45 -0700998 if (mAudioEncoder != AUDIO_ENCODER_AAC) {
999 return ERROR_UNSUPPORTED;
1000 }
1001
1002 status_t err = setupAudioEncoder(writer);
1003
1004 if (err != OK) {
1005 return err;
1006 }
1007 }
1008
1009 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1010 || mVideoSource == VIDEO_SOURCE_CAMERA) {
1011 if (mVideoEncoder != VIDEO_ENCODER_H264) {
1012 return ERROR_UNSUPPORTED;
1013 }
1014
Kenny Root4a90f932010-10-14 23:58:41 -07001015 sp<CameraSource> cameraSource;
1016 status_t err = setupCameraSource(&cameraSource);
1017 if (err != OK) {
1018 return err;
1019 }
1020
Andreas Huber9adf4662010-10-12 14:17:45 -07001021 sp<MediaSource> encoder;
Kenny Root4a90f932010-10-14 23:58:41 -07001022 err = setupVideoEncoder(cameraSource, mVideoBitRate, &encoder);
Andreas Huber9adf4662010-10-12 14:17:45 -07001023
1024 if (err != OK) {
1025 return err;
1026 }
1027
1028 writer->addSource(encoder);
1029 }
1030
1031 if (mMaxFileDurationUs != 0) {
1032 writer->setMaxFileDuration(mMaxFileDurationUs);
1033 }
1034
1035 if (mMaxFileSizeBytes != 0) {
1036 writer->setMaxFileSize(mMaxFileSizeBytes);
1037 }
1038
1039 mWriter = writer;
1040
1041 return mWriter->start();
1042}
1043
James Dong42a18c02010-06-16 17:27:46 -07001044void StagefrightRecorder::clipVideoFrameRate() {
1045 LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
1046 int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1047 "enc.vid.fps.min", mVideoEncoder);
1048 int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1049 "enc.vid.fps.max", mVideoEncoder);
James Dongb15f2ea2010-10-24 09:32:39 -07001050 if (mFrameRate < minFrameRate && mFrameRate != -1) {
James Dong42a18c02010-06-16 17:27:46 -07001051 LOGW("Intended video encoding frame rate (%d fps) is too small"
1052 " and will be set to (%d fps)", mFrameRate, minFrameRate);
1053 mFrameRate = minFrameRate;
1054 } else if (mFrameRate > maxFrameRate) {
1055 LOGW("Intended video encoding frame rate (%d fps) is too large"
1056 " and will be set to (%d fps)", mFrameRate, maxFrameRate);
1057 mFrameRate = maxFrameRate;
1058 }
1059}
1060
1061void StagefrightRecorder::clipVideoBitRate() {
1062 LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
1063 int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1064 "enc.vid.bps.min", mVideoEncoder);
1065 int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1066 "enc.vid.bps.max", mVideoEncoder);
1067 if (mVideoBitRate < minBitRate) {
1068 LOGW("Intended video encoding bit rate (%d bps) is too small"
1069 " and will be set to (%d bps)", mVideoBitRate, minBitRate);
1070 mVideoBitRate = minBitRate;
1071 } else if (mVideoBitRate > maxBitRate) {
1072 LOGW("Intended video encoding bit rate (%d bps) is too large"
1073 " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
1074 mVideoBitRate = maxBitRate;
1075 }
1076}
1077
1078void StagefrightRecorder::clipVideoFrameWidth() {
1079 LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
1080 int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1081 "enc.vid.width.min", mVideoEncoder);
1082 int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1083 "enc.vid.width.max", mVideoEncoder);
1084 if (mVideoWidth < minFrameWidth) {
1085 LOGW("Intended video encoding frame width (%d) is too small"
1086 " and will be set to (%d)", mVideoWidth, minFrameWidth);
1087 mVideoWidth = minFrameWidth;
1088 } else if (mVideoWidth > maxFrameWidth) {
1089 LOGW("Intended video encoding frame width (%d) is too large"
1090 " and will be set to (%d)", mVideoWidth, maxFrameWidth);
1091 mVideoWidth = maxFrameWidth;
1092 }
1093}
1094
James Dong0c128b62010-10-08 11:59:32 -07001095status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
Nipun Kwatra453e92f2010-08-04 14:26:45 -07001096 if (!mCaptureTimeLapse) {
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001097 // Dont clip for time lapse capture as encoder will have enough
1098 // time to encode because of slow capture rate of time lapse.
1099 clipVideoBitRate();
1100 clipVideoFrameRate();
1101 clipVideoFrameWidth();
1102 clipVideoFrameHeight();
1103 }
James Dong7b06de62010-06-30 12:41:16 -07001104 return OK;
1105}
1106
James Dong54815a72011-01-12 20:45:16 -08001107status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
1108 clipAudioBitRate();
1109 clipAudioSampleRate();
1110 clipNumberOfAudioChannels();
1111 return OK;
1112}
1113
1114void StagefrightRecorder::clipAudioBitRate() {
1115 LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
1116
1117 int minAudioBitRate =
1118 mEncoderProfiles->getAudioEncoderParamByName(
1119 "enc.aud.bps.min", mAudioEncoder);
1120 if (mAudioBitRate < minAudioBitRate) {
1121 LOGW("Intended audio encoding bit rate (%d) is too small"
1122 " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
1123 mAudioBitRate = minAudioBitRate;
1124 }
1125
1126 int maxAudioBitRate =
1127 mEncoderProfiles->getAudioEncoderParamByName(
1128 "enc.aud.bps.max", mAudioEncoder);
1129 if (mAudioBitRate > maxAudioBitRate) {
1130 LOGW("Intended audio encoding bit rate (%d) is too large"
1131 " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
1132 mAudioBitRate = maxAudioBitRate;
1133 }
1134}
1135
1136void StagefrightRecorder::clipAudioSampleRate() {
1137 LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
1138
1139 int minSampleRate =
1140 mEncoderProfiles->getAudioEncoderParamByName(
1141 "enc.aud.hz.min", mAudioEncoder);
1142 if (mSampleRate < minSampleRate) {
1143 LOGW("Intended audio sample rate (%d) is too small"
1144 " and will be set to (%d)", mSampleRate, minSampleRate);
1145 mSampleRate = minSampleRate;
1146 }
1147
1148 int maxSampleRate =
1149 mEncoderProfiles->getAudioEncoderParamByName(
1150 "enc.aud.hz.max", mAudioEncoder);
1151 if (mSampleRate > maxSampleRate) {
1152 LOGW("Intended audio sample rate (%d) is too large"
1153 " and will be set to (%d)", mSampleRate, maxSampleRate);
1154 mSampleRate = maxSampleRate;
1155 }
1156}
1157
1158void StagefrightRecorder::clipNumberOfAudioChannels() {
1159 LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
1160
1161 int minChannels =
1162 mEncoderProfiles->getAudioEncoderParamByName(
1163 "enc.aud.ch.min", mAudioEncoder);
1164 if (mAudioChannels < minChannels) {
1165 LOGW("Intended number of audio channels (%d) is too small"
1166 " and will be set to (%d)", mAudioChannels, minChannels);
1167 mAudioChannels = minChannels;
1168 }
1169
1170 int maxChannels =
1171 mEncoderProfiles->getAudioEncoderParamByName(
1172 "enc.aud.ch.max", mAudioEncoder);
1173 if (mAudioChannels > maxChannels) {
1174 LOGW("Intended number of audio channels (%d) is too large"
1175 " and will be set to (%d)", mAudioChannels, maxChannels);
1176 mAudioChannels = maxChannels;
1177 }
1178}
1179
James Dong42a18c02010-06-16 17:27:46 -07001180void StagefrightRecorder::clipVideoFrameHeight() {
1181 LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
1182 int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1183 "enc.vid.height.min", mVideoEncoder);
1184 int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1185 "enc.vid.height.max", mVideoEncoder);
1186 if (mVideoHeight < minFrameHeight) {
1187 LOGW("Intended video encoding frame height (%d) is too small"
1188 " and will be set to (%d)", mVideoHeight, minFrameHeight);
1189 mVideoHeight = minFrameHeight;
1190 } else if (mVideoHeight > maxFrameHeight) {
1191 LOGW("Intended video encoding frame height (%d) is too large"
1192 " and will be set to (%d)", mVideoHeight, maxFrameHeight);
1193 mVideoHeight = maxFrameHeight;
1194 }
1195}
1196
James Dong05c2fd52010-11-02 13:20:11 -07001197status_t StagefrightRecorder::setupCameraSource(
1198 sp<CameraSource> *cameraSource) {
James Dongb15f2ea2010-10-24 09:32:39 -07001199 status_t err = OK;
1200 if ((err = checkVideoEncoderCapabilities()) != OK) {
1201 return err;
1202 }
James Dong0c128b62010-10-08 11:59:32 -07001203 Size videoSize;
1204 videoSize.width = mVideoWidth;
1205 videoSize.height = mVideoHeight;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001206 if (mCaptureTimeLapse) {
James Dong0c128b62010-10-08 11:59:32 -07001207 mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
1208 mCamera, mCameraId,
1209 videoSize, mFrameRate, mPreviewSurface,
1210 mTimeBetweenTimeLapseFrameCaptureUs);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001211 *cameraSource = mCameraSourceTimeLapse;
1212 } else {
James Dong0c128b62010-10-08 11:59:32 -07001213 *cameraSource = CameraSource::CreateFromCamera(
James Dong05c2fd52010-11-02 13:20:11 -07001214 mCamera, mCameraId, videoSize, mFrameRate,
1215 mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001216 }
James Dong5df53fe2010-12-05 14:25:34 -08001217 if (*cameraSource == NULL) {
1218 return UNKNOWN_ERROR;
1219 }
1220
1221 if ((*cameraSource)->initCheck() != OK) {
1222 (*cameraSource).clear();
1223 *cameraSource = NULL;
1224 return NO_INIT;
1225 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001226
James Dongb15f2ea2010-10-24 09:32:39 -07001227 // When frame rate is not set, the actual frame rate will be set to
1228 // the current frame rate being used.
1229 if (mFrameRate == -1) {
1230 int32_t frameRate = 0;
1231 CHECK ((*cameraSource)->getFormat()->findInt32(
James Dongaac193c2010-11-10 20:43:53 -08001232 kKeyFrameRate, &frameRate));
James Dongb15f2ea2010-10-24 09:32:39 -07001233 LOGI("Frame rate is not explicitly set. Use the current frame "
1234 "rate (%d fps)", frameRate);
1235 mFrameRate = frameRate;
1236 }
1237
1238 CHECK(mFrameRate != -1);
James Dong05c2fd52010-11-02 13:20:11 -07001239
1240 mIsMetaDataStoredInVideoBuffers =
1241 (*cameraSource)->isMetaDataStoredInVideoBuffers();
1242
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001243 return OK;
1244}
1245
1246status_t StagefrightRecorder::setupVideoEncoder(
1247 sp<MediaSource> cameraSource,
1248 int32_t videoBitRate,
1249 sp<MediaSource> *source) {
1250 source->clear();
James Dong7b06de62010-06-30 12:41:16 -07001251
1252 sp<MetaData> enc_meta = new MetaData;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001253 enc_meta->setInt32(kKeyBitRate, videoBitRate);
James Dongaac193c2010-11-10 20:43:53 -08001254 enc_meta->setInt32(kKeyFrameRate, mFrameRate);
James Dong7b06de62010-06-30 12:41:16 -07001255
1256 switch (mVideoEncoder) {
1257 case VIDEO_ENCODER_H263:
1258 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
1259 break;
1260
1261 case VIDEO_ENCODER_MPEG_4_SP:
1262 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
1263 break;
1264
1265 case VIDEO_ENCODER_H264:
1266 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
1267 break;
1268
1269 default:
1270 CHECK(!"Should not be here, unsupported video encoding.");
1271 break;
1272 }
1273
1274 sp<MetaData> meta = cameraSource->getFormat();
1275
James Dong1cc31e62010-07-02 17:44:44 -07001276 int32_t width, height, stride, sliceHeight, colorFormat;
James Dong7b06de62010-06-30 12:41:16 -07001277 CHECK(meta->findInt32(kKeyWidth, &width));
1278 CHECK(meta->findInt32(kKeyHeight, &height));
1279 CHECK(meta->findInt32(kKeyStride, &stride));
1280 CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
James Dong1cc31e62010-07-02 17:44:44 -07001281 CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
James Dong7b06de62010-06-30 12:41:16 -07001282
1283 enc_meta->setInt32(kKeyWidth, width);
1284 enc_meta->setInt32(kKeyHeight, height);
James Dong52d13f02010-07-02 11:39:06 -07001285 enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
James Dong7b06de62010-06-30 12:41:16 -07001286 enc_meta->setInt32(kKeyStride, stride);
1287 enc_meta->setInt32(kKeySliceHeight, sliceHeight);
James Dong1cc31e62010-07-02 17:44:44 -07001288 enc_meta->setInt32(kKeyColorFormat, colorFormat);
James Dongeff30e32010-08-13 14:16:26 -07001289 if (mVideoTimeScale > 0) {
1290 enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
1291 }
James Dong81c929a2010-07-01 15:02:14 -07001292 if (mVideoEncoderProfile != -1) {
1293 enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
1294 }
1295 if (mVideoEncoderLevel != -1) {
1296 enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
1297 }
James Dong7b06de62010-06-30 12:41:16 -07001298
1299 OMXClient client;
1300 CHECK_EQ(client.connect(), OK);
1301
James Dong6312dd62010-12-02 14:48:23 -08001302 uint32_t encoder_flags = 0;
James Dong5fb60c72011-01-18 21:12:31 -08001303 if (mIsMetaDataStoredInVideoBuffers) {
James Dong6312dd62010-12-02 14:48:23 -08001304 encoder_flags |= OMXCodec::kHardwareCodecsOnly;
James Dong05c2fd52010-11-02 13:20:11 -07001305 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
1306 }
James Dong5f3ab062011-01-25 16:31:28 -08001307
1308 // Do not wait for all the input buffers to become available.
1309 // This give timelapse video recording faster response in
1310 // receiving output from video encoder component.
1311 if (mCaptureTimeLapse) {
1312 encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
1313 }
1314
James Dong7b06de62010-06-30 12:41:16 -07001315 sp<MediaSource> encoder = OMXCodec::Create(
1316 client.interface(), enc_meta,
Nipun Kwatra077cba42010-07-20 11:37:17 -07001317 true /* createEncoder */, cameraSource,
1318 NULL, encoder_flags);
James Dong7b06de62010-06-30 12:41:16 -07001319 if (encoder == NULL) {
James Dong6312dd62010-12-02 14:48:23 -08001320 LOGW("Failed to create the encoder");
1321 // When the encoder fails to be created, we need
1322 // release the camera source due to the camera's lock
1323 // and unlock mechanism.
1324 cameraSource->stop();
James Dong7b06de62010-06-30 12:41:16 -07001325 return UNKNOWN_ERROR;
1326 }
1327
Andreas Huber57648e42010-08-04 10:14:30 -07001328 *source = encoder;
1329
James Dong7b06de62010-06-30 12:41:16 -07001330 return OK;
1331}
1332
1333status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
James Dong54815a72011-01-12 20:45:16 -08001334 status_t status = BAD_VALUE;
1335 if (OK != (status = checkAudioEncoderCapabilities())) {
1336 return status;
1337 }
1338
James Dong7b06de62010-06-30 12:41:16 -07001339 switch(mAudioEncoder) {
1340 case AUDIO_ENCODER_AMR_NB:
1341 case AUDIO_ENCODER_AMR_WB:
1342 case AUDIO_ENCODER_AAC:
James Dong7b06de62010-06-30 12:41:16 -07001343 break;
James Dong54815a72011-01-12 20:45:16 -08001344
James Dong7b06de62010-06-30 12:41:16 -07001345 default:
1346 LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1347 return UNKNOWN_ERROR;
1348 }
1349
James Dong54815a72011-01-12 20:45:16 -08001350 sp<MediaSource> audioEncoder = createAudioSource();
James Dong7b06de62010-06-30 12:41:16 -07001351 if (audioEncoder == NULL) {
1352 return UNKNOWN_ERROR;
1353 }
James Dong52d13f02010-07-02 11:39:06 -07001354
James Dong7b06de62010-06-30 12:41:16 -07001355 writer->addSource(audioEncoder);
1356 return OK;
1357}
1358
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001359status_t StagefrightRecorder::setupMPEG4Recording(
1360 bool useSplitCameraSource,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001361 int outputFd,
1362 int32_t videoWidth, int32_t videoHeight,
1363 int32_t videoBitRate,
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001364 int32_t *totalBitRate,
1365 sp<MediaWriter> *mediaWriter) {
1366 mediaWriter->clear();
1367 *totalBitRate = 0;
James Dong7b06de62010-06-30 12:41:16 -07001368 status_t err = OK;
James Dong2747e0e2010-11-18 20:59:13 -08001369 sp<MediaWriter> writer = new MPEG4Writer(outputFd);
Andreas Huber996dddf2010-01-25 15:30:31 -08001370
1371 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1372 || mVideoSource == VIDEO_SOURCE_CAMERA) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001373
1374 sp<MediaSource> cameraMediaSource;
1375 if (useSplitCameraSource) {
1376 LOGV("Using Split camera source");
1377 cameraMediaSource = mCameraSourceSplitter->createClient();
1378 } else {
1379 sp<CameraSource> cameraSource;
1380 err = setupCameraSource(&cameraSource);
1381 cameraMediaSource = cameraSource;
1382 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001383 if ((videoWidth != mVideoWidth) || (videoHeight != mVideoHeight)) {
1384 // Use downsampling from the original source.
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001385 cameraMediaSource =
1386 new VideoSourceDownSampler(cameraMediaSource, videoWidth, videoHeight);
1387 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001388 if (err != OK) {
1389 return err;
1390 }
1391
Andreas Huber57648e42010-08-04 10:14:30 -07001392 sp<MediaSource> encoder;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001393 err = setupVideoEncoder(cameraMediaSource, videoBitRate, &encoder);
1394 if (err != OK) {
1395 return err;
1396 }
1397
Andreas Huber57648e42010-08-04 10:14:30 -07001398 writer->addSource(encoder);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001399 *totalBitRate += videoBitRate;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001400 }
1401
James Dong44b004b2011-01-19 20:42:19 -08001402 // Audio source is added at the end if it exists.
1403 // This help make sure that the "recoding" sound is suppressed for
1404 // camcorder applications in the recorded files.
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001405 if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
James Dong44b004b2011-01-19 20:42:19 -08001406 err = setupAudioEncoder(writer);
1407 if (err != OK) return err;
1408 *totalBitRate += mAudioBitRate;
1409 }
1410
James Dong63299c02010-07-28 10:08:03 -07001411 if (mInterleaveDurationUs > 0) {
1412 reinterpret_cast<MPEG4Writer *>(writer.get())->
1413 setInterleaveDuration(mInterleaveDurationUs);
1414 }
James Dong18244862010-05-11 14:57:02 -07001415 if (mMaxFileDurationUs != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001416 writer->setMaxFileDuration(mMaxFileDurationUs);
James Dong18244862010-05-11 14:57:02 -07001417 }
1418 if (mMaxFileSizeBytes != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001419 writer->setMaxFileSize(mMaxFileSizeBytes);
James Dong18244862010-05-11 14:57:02 -07001420 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001421
1422 writer->setListener(mListener);
1423 *mediaWriter = writer;
1424 return OK;
1425}
1426
1427void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
1428 sp<MetaData> *meta) {
1429 (*meta)->setInt64(kKeyTime, startTimeUs);
1430 (*meta)->setInt32(kKeyFileType, mOutputFormat);
1431 (*meta)->setInt32(kKeyBitRate, totalBitRate);
1432 (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
James Dongeff30e32010-08-13 14:16:26 -07001433 if (mMovieTimeScale > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001434 (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
James Dongeff30e32010-08-13 14:16:26 -07001435 }
James Dong09936ed2010-06-24 19:04:27 -07001436 if (mTrackEveryTimeDurationUs > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001437 (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -07001438 }
James Dongb9d7e012010-11-09 11:15:47 -08001439 if (mRotationDegrees != 0) {
1440 (*meta)->setInt32(kKeyRotation, mRotationDegrees);
1441 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001442}
1443
1444status_t StagefrightRecorder::startMPEG4Recording() {
1445 if (mCaptureAuxVideo) {
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001446 if (!mCaptureTimeLapse) {
1447 LOGE("Auxiliary video can be captured only in time lapse mode");
1448 return UNKNOWN_ERROR;
1449 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001450 LOGV("Creating MediaSourceSplitter");
1451 sp<CameraSource> cameraSource;
1452 status_t err = setupCameraSource(&cameraSource);
1453 if (err != OK) {
1454 return err;
1455 }
1456 mCameraSourceSplitter = new MediaSourceSplitter(cameraSource);
1457 } else {
1458 mCameraSourceSplitter = NULL;
1459 }
1460
1461 int32_t totalBitRate;
1462 status_t err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001463 mOutputFd, mVideoWidth, mVideoHeight,
1464 mVideoBitRate, &totalBitRate, &mWriter);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001465 if (err != OK) {
1466 return err;
1467 }
1468
1469 int64_t startTimeUs = systemTime() / 1000;
1470 sp<MetaData> meta = new MetaData;
1471 setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
1472
1473 err = mWriter->start(meta.get());
1474 if (err != OK) {
1475 return err;
1476 }
1477
1478 if (mCaptureAuxVideo) {
1479 CHECK(mOutputFdAux >= 0);
1480 if (mWriterAux != NULL) {
1481 LOGE("Auxiliary File writer is not avaialble");
1482 return UNKNOWN_ERROR;
1483 }
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001484 if ((mAuxVideoWidth > mVideoWidth) || (mAuxVideoHeight > mVideoHeight) ||
1485 ((mAuxVideoWidth == mVideoWidth) && mAuxVideoHeight == mVideoHeight)) {
1486 LOGE("Auxiliary video size (%d x %d) same or larger than the main video size (%d x %d)",
1487 mAuxVideoWidth, mAuxVideoHeight, mVideoWidth, mVideoHeight);
1488 return UNKNOWN_ERROR;
1489 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001490
1491 int32_t totalBitrateAux;
1492 err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001493 mOutputFdAux, mAuxVideoWidth, mAuxVideoHeight,
1494 mAuxVideoBitRate, &totalBitrateAux, &mWriterAux);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001495 if (err != OK) {
1496 return err;
1497 }
1498
1499 sp<MetaData> metaAux = new MetaData;
1500 setupMPEG4MetaData(startTimeUs, totalBitrateAux, &metaAux);
1501
1502 return mWriterAux->start(metaAux.get());
1503 }
1504
1505 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001506}
1507
James Dong08c74732010-06-10 12:28:15 -07001508status_t StagefrightRecorder::pause() {
James Dongc0ab2a62010-06-29 16:29:19 -07001509 LOGV("pause");
James Dong08c74732010-06-10 12:28:15 -07001510 if (mWriter == NULL) {
1511 return UNKNOWN_ERROR;
1512 }
1513 mWriter->pause();
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001514
1515 if (mCaptureAuxVideo) {
1516 if (mWriterAux == NULL) {
1517 return UNKNOWN_ERROR;
1518 }
1519 mWriterAux->pause();
1520 }
1521
Gloria Wang62e05a62011-02-23 11:47:34 -08001522 if (mStarted) {
1523 mStarted = false;
1524
1525 uint32_t params = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001526 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -08001527 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1528 }
1529 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1530 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1531 }
1532
1533 addBatteryData(params);
1534 }
1535
1536
James Dong08c74732010-06-10 12:28:15 -07001537 return OK;
1538}
1539
Andreas Huberea6a38c2009-11-16 15:43:38 -08001540status_t StagefrightRecorder::stop() {
James Dongc0ab2a62010-06-29 16:29:19 -07001541 LOGV("stop");
James Dongd0366622010-08-18 19:10:39 -07001542 status_t err = OK;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001543
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001544 if (mCaptureTimeLapse && mCameraSourceTimeLapse != NULL) {
1545 mCameraSourceTimeLapse->startQuickReadReturns();
1546 mCameraSourceTimeLapse = NULL;
1547 }
1548
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001549 if (mCaptureAuxVideo) {
1550 if (mWriterAux != NULL) {
1551 mWriterAux->stop();
1552 mWriterAux.clear();
1553 }
1554 }
1555
James Dongc0ab2a62010-06-29 16:29:19 -07001556 if (mWriter != NULL) {
James Dongd0366622010-08-18 19:10:39 -07001557 err = mWriter->stop();
James Dong7b06de62010-06-30 12:41:16 -07001558 mWriter.clear();
Andreas Huberea6a38c2009-11-16 15:43:38 -08001559 }
1560
James Dongc6280bc2010-08-11 17:12:39 -07001561 if (mOutputFd >= 0) {
1562 ::close(mOutputFd);
1563 mOutputFd = -1;
1564 }
1565
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001566 if (mCaptureAuxVideo) {
1567 if (mOutputFdAux >= 0) {
1568 ::close(mOutputFdAux);
1569 mOutputFdAux = -1;
1570 }
1571 }
1572
Gloria Wang62e05a62011-02-23 11:47:34 -08001573 if (mStarted) {
1574 mStarted = false;
1575
1576 uint32_t params = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001577 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -08001578 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1579 }
1580 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1581 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1582 }
1583
1584 addBatteryData(params);
1585 }
1586
1587
James Dongd0366622010-08-18 19:10:39 -07001588 return err;
James Dongc0ab2a62010-06-29 16:29:19 -07001589}
1590
1591status_t StagefrightRecorder::close() {
1592 LOGV("close");
1593 stop();
1594
Andreas Huberea6a38c2009-11-16 15:43:38 -08001595 return OK;
1596}
1597
1598status_t StagefrightRecorder::reset() {
James Dongc0ab2a62010-06-29 16:29:19 -07001599 LOGV("reset");
Andreas Huberea6a38c2009-11-16 15:43:38 -08001600 stop();
1601
James Dongabed93a2010-04-22 17:27:04 -07001602 // No audio or video source by default
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001603 mAudioSource = AUDIO_SOURCE_CNT;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001604 mVideoSource = VIDEO_SOURCE_LIST_END;
James Dongabed93a2010-04-22 17:27:04 -07001605
1606 // Default parameters
1607 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
1608 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
1609 mVideoEncoder = VIDEO_ENCODER_H263;
1610 mVideoWidth = 176;
1611 mVideoHeight = 144;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001612 mAuxVideoWidth = 176;
1613 mAuxVideoHeight = 144;
James Dongb15f2ea2010-10-24 09:32:39 -07001614 mFrameRate = -1;
James Dongabed93a2010-04-22 17:27:04 -07001615 mVideoBitRate = 192000;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001616 mAuxVideoBitRate = 192000;
James Dongabed93a2010-04-22 17:27:04 -07001617 mSampleRate = 8000;
1618 mAudioChannels = 1;
1619 mAudioBitRate = 12200;
James Dongc6161722010-05-20 17:55:52 -07001620 mInterleaveDurationUs = 0;
James Dong52d13f02010-07-02 11:39:06 -07001621 mIFramesIntervalSec = 1;
James Dong57e7f832010-06-24 19:55:31 -07001622 mAudioSourceNode = 0;
James Dong6feaa462010-06-20 08:20:54 -07001623 mUse64BitFileOffset = false;
James Dongeff30e32010-08-13 14:16:26 -07001624 mMovieTimeScale = -1;
1625 mAudioTimeScale = -1;
1626 mVideoTimeScale = -1;
James Dong09936ed2010-06-24 19:04:27 -07001627 mCameraId = 0;
James Dong81c929a2010-07-01 15:02:14 -07001628 mVideoEncoderProfile = -1;
1629 mVideoEncoderLevel = -1;
1630 mMaxFileDurationUs = 0;
1631 mMaxFileSizeBytes = 0;
James Dong09936ed2010-06-24 19:04:27 -07001632 mTrackEveryTimeDurationUs = 0;
Nipun Kwatrad26920a2010-06-30 18:51:31 -07001633 mCaptureTimeLapse = false;
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001634 mTimeBetweenTimeLapseFrameCaptureUs = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001635 mCaptureAuxVideo = false;
1636 mCameraSourceSplitter = NULL;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001637 mCameraSourceTimeLapse = NULL;
James Dong05c2fd52010-11-02 13:20:11 -07001638 mIsMetaDataStoredInVideoBuffers = false;
James Dong42a18c02010-06-16 17:27:46 -07001639 mEncoderProfiles = MediaProfiles::getInstance();
James Dong5d0b7832010-11-10 12:26:58 -08001640 mRotationDegrees = 0;
James Dongabed93a2010-04-22 17:27:04 -07001641
Andreas Huberea6a38c2009-11-16 15:43:38 -08001642 mOutputFd = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001643 mOutputFdAux = -1;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001644
1645 return OK;
1646}
1647
1648status_t StagefrightRecorder::getMaxAmplitude(int *max) {
James Dongc0ab2a62010-06-29 16:29:19 -07001649 LOGV("getMaxAmplitude");
1650
1651 if (max == NULL) {
1652 LOGE("Null pointer argument");
1653 return BAD_VALUE;
1654 }
1655
James Dong57e7f832010-06-24 19:55:31 -07001656 if (mAudioSourceNode != 0) {
1657 *max = mAudioSourceNode->getMaxAmplitude();
1658 } else {
1659 *max = 0;
1660 }
Andreas Huber996dddf2010-01-25 15:30:31 -08001661
1662 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001663}
1664
James Dong3f51fa72010-08-18 03:32:26 -07001665status_t StagefrightRecorder::dump(
1666 int fd, const Vector<String16>& args) const {
1667 LOGV("dump");
James Dong929642e2010-07-08 11:16:11 -07001668 const size_t SIZE = 256;
1669 char buffer[SIZE];
1670 String8 result;
James Dong3f51fa72010-08-18 03:32:26 -07001671 if (mWriter != 0) {
1672 mWriter->dump(fd, args);
1673 } else {
1674 snprintf(buffer, SIZE, " No file writer\n");
1675 result.append(buffer);
1676 }
1677 snprintf(buffer, SIZE, " Recorder: %p\n", this);
James Dong929642e2010-07-08 11:16:11 -07001678 snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
1679 result.append(buffer);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001680 snprintf(buffer, SIZE, " Output file Auxiliary (fd %d):\n", mOutputFdAux);
1681 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001682 snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
1683 result.append(buffer);
1684 snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1685 result.append(buffer);
1686 snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
1687 result.append(buffer);
1688 snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1689 result.append(buffer);
1690 snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
1691 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001692 snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1693 result.append(buffer);
1694 snprintf(buffer, SIZE, " Audio\n");
1695 result.append(buffer);
1696 snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
1697 result.append(buffer);
1698 snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
1699 result.append(buffer);
1700 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
1701 result.append(buffer);
1702 snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
1703 result.append(buffer);
1704 snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
1705 result.append(buffer);
1706 snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1707 result.append(buffer);
1708 snprintf(buffer, SIZE, " Video\n");
1709 result.append(buffer);
1710 snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
1711 result.append(buffer);
1712 snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
1713 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001714 snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
1715 result.append(buffer);
1716 snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
1717 result.append(buffer);
1718 snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
1719 result.append(buffer);
James Dong52d13f02010-07-02 11:39:06 -07001720 snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec);
James Dong929642e2010-07-08 11:16:11 -07001721 result.append(buffer);
1722 snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1723 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001724 snprintf(buffer, SIZE, " Aux Frame size (pixels): %dx%d\n", mAuxVideoWidth, mAuxVideoHeight);
1725 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001726 snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
1727 result.append(buffer);
1728 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
1729 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001730 snprintf(buffer, SIZE, " Aux Bit rate (bps): %d\n", mAuxVideoBitRate);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001731 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001732 ::write(fd, result.string(), result.size());
1733 return OK;
1734}
Andreas Huberea6a38c2009-11-16 15:43:38 -08001735} // namespace android