blob: 69816681e6790f8b5836a90522a6b3494a26d985 [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 Kwatraf9b80182010-07-12 09:17:14 -070031#include <media/stagefright/CameraSourceTimeLapse.h>
Andreas Huber9adf4662010-10-12 14:17:45 -070032#include <media/stagefright/MPEG2TSWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080033#include <media/stagefright/MPEG4Writer.h>
34#include <media/stagefright/MediaDebug.h>
35#include <media/stagefright/MediaDefs.h>
36#include <media/stagefright/MetaData.h>
37#include <media/stagefright/OMXClient.h>
38#include <media/stagefright/OMXCodec.h>
Pannag Sanketi897e27b2011-07-01 17:39:39 -070039#include <media/stagefright/SurfaceMediaSource.h>
James Dong42a18c02010-06-16 17:27:46 -070040#include <media/MediaProfiles.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080041#include <camera/ICamera.h>
James Dong2cd841d2010-05-11 11:46:59 -070042#include <camera/CameraParameters.h>
Jamie Gennis85cfdd02010-08-10 16:37:53 -070043#include <surfaceflinger/Surface.h>
Pannag Sanketi897e27b2011-07-01 17:39:39 -070044
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 Zavin34bb4192011-05-11 14:15:23 -070050#include <system/audio.h>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070051
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()
James Dong83dd43f2011-06-29 16:56:52 -070068 : mWriter(NULL),
69 mOutputFd(-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),
Pannag Sanketi897e27b2011-07-01 17:39:39 -070072 mStarted(false), mSurfaceMediaSource(NULL) {
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
Pannag Sanketi897e27b2011-07-01 17:39:39 -070088// The client side of mediaserver asks it to creat a SurfaceMediaSource
89// and return a interface reference. The client side will use that
90// while encoding GL Frames
91sp<ISurfaceTexture> StagefrightRecorder::querySurfaceMediaSource() const {
92 LOGV("Get SurfaceMediaSource");
93 return mSurfaceMediaSource;
94}
95
Dima Zavin24fc2fb2011-04-19 22:30:36 -070096status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
James Dongc0ab2a62010-06-29 16:29:19 -070097 LOGV("setAudioSource: %d", as);
98 if (as < AUDIO_SOURCE_DEFAULT ||
Dima Zavin24fc2fb2011-04-19 22:30:36 -070099 as >= AUDIO_SOURCE_CNT) {
James Dong7b06de62010-06-30 12:41:16 -0700100 LOGE("Invalid audio source: %d", as);
James Dongc0ab2a62010-06-29 16:29:19 -0700101 return BAD_VALUE;
102 }
103
104 if (as == AUDIO_SOURCE_DEFAULT) {
105 mAudioSource = AUDIO_SOURCE_MIC;
106 } else {
107 mAudioSource = as;
108 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800109
110 return OK;
111}
112
113status_t StagefrightRecorder::setVideoSource(video_source vs) {
James Dongc0ab2a62010-06-29 16:29:19 -0700114 LOGV("setVideoSource: %d", vs);
115 if (vs < VIDEO_SOURCE_DEFAULT ||
116 vs >= VIDEO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700117 LOGE("Invalid video source: %d", vs);
James Dongc0ab2a62010-06-29 16:29:19 -0700118 return BAD_VALUE;
119 }
120
121 if (vs == VIDEO_SOURCE_DEFAULT) {
122 mVideoSource = VIDEO_SOURCE_CAMERA;
123 } else {
124 mVideoSource = vs;
125 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800126
127 return OK;
128}
129
130status_t StagefrightRecorder::setOutputFormat(output_format of) {
James Dongc0ab2a62010-06-29 16:29:19 -0700131 LOGV("setOutputFormat: %d", of);
132 if (of < OUTPUT_FORMAT_DEFAULT ||
133 of >= OUTPUT_FORMAT_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700134 LOGE("Invalid output format: %d", of);
James Dongc0ab2a62010-06-29 16:29:19 -0700135 return BAD_VALUE;
136 }
137
138 if (of == OUTPUT_FORMAT_DEFAULT) {
139 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
140 } else {
141 mOutputFormat = of;
142 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800143
144 return OK;
145}
146
147status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
James Dongc0ab2a62010-06-29 16:29:19 -0700148 LOGV("setAudioEncoder: %d", ae);
149 if (ae < AUDIO_ENCODER_DEFAULT ||
150 ae >= AUDIO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700151 LOGE("Invalid audio encoder: %d", ae);
James Dongc0ab2a62010-06-29 16:29:19 -0700152 return BAD_VALUE;
153 }
154
155 if (ae == AUDIO_ENCODER_DEFAULT) {
156 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
157 } else {
158 mAudioEncoder = ae;
159 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800160
161 return OK;
162}
163
164status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
James Dongc0ab2a62010-06-29 16:29:19 -0700165 LOGV("setVideoEncoder: %d", ve);
166 if (ve < VIDEO_ENCODER_DEFAULT ||
167 ve >= VIDEO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700168 LOGE("Invalid video encoder: %d", ve);
James Dongc0ab2a62010-06-29 16:29:19 -0700169 return BAD_VALUE;
170 }
171
172 if (ve == VIDEO_ENCODER_DEFAULT) {
173 mVideoEncoder = VIDEO_ENCODER_H263;
174 } else {
175 mVideoEncoder = ve;
176 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800177
178 return OK;
179}
180
181status_t StagefrightRecorder::setVideoSize(int width, int height) {
James Dongc0ab2a62010-06-29 16:29:19 -0700182 LOGV("setVideoSize: %dx%d", width, height);
James Dong2cd841d2010-05-11 11:46:59 -0700183 if (width <= 0 || height <= 0) {
184 LOGE("Invalid video size: %dx%d", width, height);
185 return BAD_VALUE;
186 }
187
188 // Additional check on the dimension will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800189 mVideoWidth = width;
190 mVideoHeight = height;
191
192 return OK;
193}
194
195status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
James Dongc0ab2a62010-06-29 16:29:19 -0700196 LOGV("setVideoFrameRate: %d", frames_per_second);
James Dongb15f2ea2010-10-24 09:32:39 -0700197 if ((frames_per_second <= 0 && frames_per_second != -1) ||
198 frames_per_second > 120) {
James Dong2cd841d2010-05-11 11:46:59 -0700199 LOGE("Invalid video frame rate: %d", frames_per_second);
200 return BAD_VALUE;
201 }
202
203 // Additional check on the frame rate will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800204 mFrameRate = frames_per_second;
205
206 return OK;
207}
208
Wu-cheng Li42419ce2011-06-01 17:22:24 +0800209status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera,
210 const sp<ICameraRecordingProxy> &proxy) {
James Dong71d714c2010-06-09 15:57:48 -0700211 LOGV("setCamera");
James Dongb00e2462010-04-26 17:48:26 -0700212 if (camera == 0) {
213 LOGE("camera is NULL");
James Dong7b06de62010-06-30 12:41:16 -0700214 return BAD_VALUE;
James Dongb00e2462010-04-26 17:48:26 -0700215 }
Wu-cheng Li42419ce2011-06-01 17:22:24 +0800216 if (proxy == 0) {
217 LOGE("camera proxy is NULL");
218 return BAD_VALUE;
219 }
James Dongb00e2462010-04-26 17:48:26 -0700220
James Dong0c128b62010-10-08 11:59:32 -0700221 mCamera = camera;
Wu-cheng Li42419ce2011-06-01 17:22:24 +0800222 mCameraProxy = proxy;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800223 return OK;
224}
225
Jamie Gennis85cfdd02010-08-10 16:37:53 -0700226status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
James Dongc0ab2a62010-06-29 16:29:19 -0700227 LOGV("setPreviewSurface: %p", surface.get());
Andreas Huberea6a38c2009-11-16 15:43:38 -0800228 mPreviewSurface = surface;
229
230 return OK;
231}
232
233status_t StagefrightRecorder::setOutputFile(const char *path) {
James Dong7b06de62010-06-30 12:41:16 -0700234 LOGE("setOutputFile(const char*) must not be called");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800235 // We don't actually support this at all, as the media_server process
236 // no longer has permissions to create files.
237
James Dong7b06de62010-06-30 12:41:16 -0700238 return -EPERM;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800239}
240
241status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
James Dongc0ab2a62010-06-29 16:29:19 -0700242 LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800243 // These don't make any sense, do they?
244 CHECK_EQ(offset, 0);
245 CHECK_EQ(length, 0);
246
James Dong7b06de62010-06-30 12:41:16 -0700247 if (fd < 0) {
248 LOGE("Invalid file descriptor: %d", fd);
249 return -EBADF;
250 }
251
Andreas Huberea6a38c2009-11-16 15:43:38 -0800252 if (mOutputFd >= 0) {
253 ::close(mOutputFd);
254 }
255 mOutputFd = dup(fd);
256
257 return OK;
258}
259
James Dongabed93a2010-04-22 17:27:04 -0700260// Attempt to parse an int64 literal optionally surrounded by whitespace,
261// returns true on success, false otherwise.
James Dong2cd841d2010-05-11 11:46:59 -0700262static bool safe_strtoi64(const char *s, int64_t *val) {
James Dongabed93a2010-04-22 17:27:04 -0700263 char *end;
James Dong75fb2382011-02-08 15:41:58 -0800264
265 // It is lame, but according to man page, we have to set errno to 0
266 // before calling strtoll().
267 errno = 0;
James Dong2cd841d2010-05-11 11:46:59 -0700268 *val = strtoll(s, &end, 10);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800269
James Dongabed93a2010-04-22 17:27:04 -0700270 if (end == s || errno == ERANGE) {
271 return false;
272 }
273
274 // Skip trailing whitespace
275 while (isspace(*end)) {
276 ++end;
277 }
278
279 // For a successful return, the string must contain nothing but a valid
280 // int64 literal optionally surrounded by whitespace.
281
282 return *end == '\0';
283}
284
James Dong2cd841d2010-05-11 11:46:59 -0700285// Return true if the value is in [0, 0x007FFFFFFF]
286static bool safe_strtoi32(const char *s, int32_t *val) {
287 int64_t temp;
288 if (safe_strtoi64(s, &temp)) {
289 if (temp >= 0 && temp <= 0x007FFFFFFF) {
290 *val = static_cast<int32_t>(temp);
291 return true;
292 }
293 }
294 return false;
295}
296
James Dongabed93a2010-04-22 17:27:04 -0700297// Trim both leading and trailing whitespace from the given string.
298static void TrimString(String8 *s) {
299 size_t num_bytes = s->bytes();
300 const char *data = s->string();
301
302 size_t leading_space = 0;
303 while (leading_space < num_bytes && isspace(data[leading_space])) {
304 ++leading_space;
305 }
306
307 size_t i = num_bytes;
308 while (i > leading_space && isspace(data[i - 1])) {
309 --i;
310 }
311
312 s->setTo(String8(&data[leading_space], i - leading_space));
313}
314
315status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
316 LOGV("setParamAudioSamplingRate: %d", sampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700317 if (sampleRate <= 0) {
318 LOGE("Invalid audio sampling rate: %d", sampleRate);
319 return BAD_VALUE;
320 }
321
322 // Additional check on the sample rate will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700323 mSampleRate = sampleRate;
324 return OK;
325}
326
327status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
328 LOGV("setParamAudioNumberOfChannels: %d", channels);
James Dong2cd841d2010-05-11 11:46:59 -0700329 if (channels <= 0 || channels >= 3) {
330 LOGE("Invalid number of audio channels: %d", channels);
James Dong7b06de62010-06-30 12:41:16 -0700331 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700332 }
333
334 // Additional check on the number of channels will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700335 mAudioChannels = channels;
336 return OK;
337}
338
339status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
340 LOGV("setParamAudioEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700341 if (bitRate <= 0) {
342 LOGE("Invalid audio encoding bit rate: %d", bitRate);
343 return BAD_VALUE;
344 }
345
346 // The target bit rate may not be exactly the same as the requested.
347 // It depends on many factors, such as rate control, and the bit rate
348 // range that a specific encoder supports. The mismatch between the
349 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700350 mAudioBitRate = bitRate;
351 return OK;
352}
353
354status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
355 LOGV("setParamVideoEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700356 if (bitRate <= 0) {
357 LOGE("Invalid video encoding bit rate: %d", bitRate);
358 return BAD_VALUE;
359 }
360
361 // The target bit rate may not be exactly the same as the requested.
362 // It depends on many factors, such as rate control, and the bit rate
363 // range that a specific encoder supports. The mismatch between the
364 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700365 mVideoBitRate = bitRate;
366 return OK;
367}
368
James Dongb9d7e012010-11-09 11:15:47 -0800369// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
370status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
371 LOGV("setParamVideoRotation: %d", degrees);
372 if (degrees < 0 || degrees % 90 != 0) {
373 LOGE("Unsupported video rotation angle: %d", degrees);
374 return BAD_VALUE;
375 }
376 mRotationDegrees = degrees % 360;
377 return OK;
378}
379
James Dong7b06de62010-06-30 12:41:16 -0700380status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
381 LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
James Dong26ea64c2010-12-20 11:39:38 -0800382
383 // This is meant for backward compatibility for MediaRecorder.java
Nipun Kwatrafb457482010-08-18 15:19:19 -0700384 if (timeUs <= 0) {
385 LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
386 timeUs = 0; // Disable the duration limit for zero or negative values.
387 } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
James Dong7b06de62010-06-30 12:41:16 -0700388 LOGE("Max file duration is too short: %lld us", timeUs);
389 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700390 }
Nipun Kwatrafb457482010-08-18 15:19:19 -0700391
James Dong5cdcf162010-11-30 18:18:08 -0800392 if (timeUs <= 15 * 1000000LL) {
393 LOGW("Target duration (%lld us) too short to be respected", timeUs);
394 }
James Dong7b06de62010-06-30 12:41:16 -0700395 mMaxFileDurationUs = timeUs;
396 return OK;
397}
398
399status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
400 LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
James Dong26ea64c2010-12-20 11:39:38 -0800401
402 // This is meant for backward compatibility for MediaRecorder.java
403 if (bytes <= 0) {
404 LOGW("Max file size is not positive: %lld bytes. "
405 "Disabling file size limit.", bytes);
406 bytes = 0; // Disable the file size limit for zero or negative values.
407 } else if (bytes <= 1024) { // XXX: 1 kB
James Dong7b06de62010-06-30 12:41:16 -0700408 LOGE("Max file size is too small: %lld bytes", bytes);
409 return BAD_VALUE;
410 }
James Dong5cdcf162010-11-30 18:18:08 -0800411
412 if (bytes <= 100 * 1024) {
413 LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
414 }
415
James Dong7b06de62010-06-30 12:41:16 -0700416 mMaxFileSizeBytes = bytes;
James Dongabed93a2010-04-22 17:27:04 -0700417 return OK;
418}
419
James Dong3300e962010-04-21 16:14:15 -0700420status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
421 LOGV("setParamInterleaveDuration: %d", durationUs);
James Dong1244eab2010-06-08 11:58:53 -0700422 if (durationUs <= 500000) { // 500 ms
423 // If interleave duration is too small, it is very inefficient to do
424 // interleaving since the metadata overhead will count for a significant
425 // portion of the saved contents
James Dong2cd841d2010-05-11 11:46:59 -0700426 LOGE("Audio/video interleave duration is too small: %d us", durationUs);
427 return BAD_VALUE;
James Dong1244eab2010-06-08 11:58:53 -0700428 } else if (durationUs >= 10000000) { // 10 seconds
429 // If interleaving duration is too large, it can cause the recording
430 // session to use too much memory since we have to save the output
431 // data before we write them out
432 LOGE("Audio/video interleave duration is too large: %d us", durationUs);
433 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700434 }
James Dong3300e962010-04-21 16:14:15 -0700435 mInterleaveDurationUs = durationUs;
436 return OK;
437}
James Dong2cd841d2010-05-11 11:46:59 -0700438
James Dong52d13f02010-07-02 11:39:06 -0700439// If seconds < 0, only the first frame is I frame, and rest are all P frames
440// If seconds == 0, all frames are encoded as I frames. No P frames
441// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames
442status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
443 LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
444 mIFramesIntervalSec = seconds;
James Dong1244eab2010-06-08 11:58:53 -0700445 return OK;
446}
447
James Dong6feaa462010-06-20 08:20:54 -0700448status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
449 LOGV("setParam64BitFileOffset: %s",
450 use64Bit? "use 64 bit file offset": "use 32 bit file offset");
451 mUse64BitFileOffset = use64Bit;
452 return OK;
453}
454
James Dong09936ed2010-06-24 19:04:27 -0700455status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
456 LOGV("setParamVideoCameraId: %d", cameraId);
457 if (cameraId < 0) {
458 return BAD_VALUE;
459 }
460 mCameraId = cameraId;
461 return OK;
462}
463
James Dong09936ed2010-06-24 19:04:27 -0700464status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
465 LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
466 if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
James Dong7b06de62010-06-30 12:41:16 -0700467 LOGE("Tracking time duration too short: %lld us", timeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -0700468 return BAD_VALUE;
469 }
470 mTrackEveryTimeDurationUs = timeDurationUs;
471 return OK;
472}
473
James Dong81c929a2010-07-01 15:02:14 -0700474status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
475 LOGV("setParamVideoEncoderProfile: %d", profile);
476
477 // Additional check will be done later when we load the encoder.
478 // For now, we are accepting values defined in OpenMAX IL.
479 mVideoEncoderProfile = profile;
480 return OK;
481}
482
483status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
484 LOGV("setParamVideoEncoderLevel: %d", level);
485
486 // Additional check will be done later when we load the encoder.
487 // For now, we are accepting values defined in OpenMAX IL.
488 mVideoEncoderLevel = level;
489 return OK;
490}
491
James Dong52d13f02010-07-02 11:39:06 -0700492status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
493 LOGV("setParamMovieTimeScale: %d", timeScale);
494
495 // The range is set to be the same as the audio's time scale range
496 // since audio's time scale has a wider range.
497 if (timeScale < 600 || timeScale > 96000) {
498 LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
499 return BAD_VALUE;
500 }
501 mMovieTimeScale = timeScale;
502 return OK;
503}
504
505status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
506 LOGV("setParamVideoTimeScale: %d", timeScale);
507
508 // 60000 is chosen to make sure that each video frame from a 60-fps
509 // video has 1000 ticks.
510 if (timeScale < 600 || timeScale > 60000) {
511 LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
512 return BAD_VALUE;
513 }
514 mVideoTimeScale = timeScale;
515 return OK;
516}
517
518status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
519 LOGV("setParamAudioTimeScale: %d", timeScale);
520
521 // 96000 Hz is the highest sampling rate support in AAC.
522 if (timeScale < 600 || timeScale > 96000) {
523 LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
524 return BAD_VALUE;
525 }
526 mAudioTimeScale = timeScale;
527 return OK;
528}
529
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700530status_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
531 LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
532
533 if(timeLapseEnable == 0) {
534 mCaptureTimeLapse = false;
535 } else if (timeLapseEnable == 1) {
536 mCaptureTimeLapse = true;
537 } else {
538 return BAD_VALUE;
539 }
540 return OK;
541}
542
543status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
544 LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
545
546 // Not allowing time more than a day
547 if (timeUs <= 0 || timeUs > 86400*1E6) {
548 LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
549 return BAD_VALUE;
550 }
551
552 mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
553 return OK;
554}
555
James Dong987ab482011-05-11 19:09:25 -0700556status_t StagefrightRecorder::setParamGeoDataLongitude(
James Dong56f71d72011-10-05 20:02:05 -0700557 int64_t longitudex10000) {
James Dong987ab482011-05-11 19:09:25 -0700558
559 if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
560 return BAD_VALUE;
561 }
562 mLongitudex10000 = longitudex10000;
563 return OK;
564}
565
566status_t StagefrightRecorder::setParamGeoDataLatitude(
James Dong56f71d72011-10-05 20:02:05 -0700567 int64_t latitudex10000) {
James Dong987ab482011-05-11 19:09:25 -0700568
569 if (latitudex10000 > 900000 || latitudex10000 < -900000) {
570 return BAD_VALUE;
571 }
572 mLatitudex10000 = latitudex10000;
573 return OK;
574}
575
James Dongabed93a2010-04-22 17:27:04 -0700576status_t StagefrightRecorder::setParameter(
577 const String8 &key, const String8 &value) {
578 LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
579 if (key == "max-duration") {
James Dong2cd841d2010-05-11 11:46:59 -0700580 int64_t max_duration_ms;
James Dongabed93a2010-04-22 17:27:04 -0700581 if (safe_strtoi64(value.string(), &max_duration_ms)) {
James Dong7b06de62010-06-30 12:41:16 -0700582 return setParamMaxFileDurationUs(1000LL * max_duration_ms);
James Dongabed93a2010-04-22 17:27:04 -0700583 }
584 } else if (key == "max-filesize") {
James Dong2cd841d2010-05-11 11:46:59 -0700585 int64_t max_filesize_bytes;
James Dongabed93a2010-04-22 17:27:04 -0700586 if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
James Dong7b06de62010-06-30 12:41:16 -0700587 return setParamMaxFileSizeBytes(max_filesize_bytes);
James Dongabed93a2010-04-22 17:27:04 -0700588 }
James Dong09936ed2010-06-24 19:04:27 -0700589 } else if (key == "interleave-duration-us") {
590 int32_t durationUs;
591 if (safe_strtoi32(value.string(), &durationUs)) {
592 return setParamInterleaveDuration(durationUs);
593 }
James Dong52d13f02010-07-02 11:39:06 -0700594 } else if (key == "param-movie-time-scale") {
595 int32_t timeScale;
596 if (safe_strtoi32(value.string(), &timeScale)) {
597 return setParamMovieTimeScale(timeScale);
598 }
James Dong09936ed2010-06-24 19:04:27 -0700599 } else if (key == "param-use-64bit-offset") {
600 int32_t use64BitOffset;
601 if (safe_strtoi32(value.string(), &use64BitOffset)) {
602 return setParam64BitFileOffset(use64BitOffset != 0);
603 }
James Dong987ab482011-05-11 19:09:25 -0700604 } else if (key == "param-geotag-longitude") {
James Dong56f71d72011-10-05 20:02:05 -0700605 int64_t longitudex10000;
606 if (safe_strtoi64(value.string(), &longitudex10000)) {
James Dong987ab482011-05-11 19:09:25 -0700607 return setParamGeoDataLongitude(longitudex10000);
608 }
609 } else if (key == "param-geotag-latitude") {
James Dong56f71d72011-10-05 20:02:05 -0700610 int64_t latitudex10000;
611 if (safe_strtoi64(value.string(), &latitudex10000)) {
James Dong987ab482011-05-11 19:09:25 -0700612 return setParamGeoDataLatitude(latitudex10000);
613 }
James Dong09936ed2010-06-24 19:04:27 -0700614 } else if (key == "param-track-time-status") {
615 int64_t timeDurationUs;
616 if (safe_strtoi64(value.string(), &timeDurationUs)) {
617 return setParamTrackTimeStatus(timeDurationUs);
618 }
James Dongabed93a2010-04-22 17:27:04 -0700619 } else if (key == "audio-param-sampling-rate") {
620 int32_t sampling_rate;
James Dong2cd841d2010-05-11 11:46:59 -0700621 if (safe_strtoi32(value.string(), &sampling_rate)) {
James Dongabed93a2010-04-22 17:27:04 -0700622 return setParamAudioSamplingRate(sampling_rate);
623 }
624 } else if (key == "audio-param-number-of-channels") {
625 int32_t number_of_channels;
James Dong2cd841d2010-05-11 11:46:59 -0700626 if (safe_strtoi32(value.string(), &number_of_channels)) {
James Dongabed93a2010-04-22 17:27:04 -0700627 return setParamAudioNumberOfChannels(number_of_channels);
628 }
629 } else if (key == "audio-param-encoding-bitrate") {
630 int32_t audio_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700631 if (safe_strtoi32(value.string(), &audio_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700632 return setParamAudioEncodingBitRate(audio_bitrate);
633 }
James Dong52d13f02010-07-02 11:39:06 -0700634 } else if (key == "audio-param-time-scale") {
635 int32_t timeScale;
636 if (safe_strtoi32(value.string(), &timeScale)) {
637 return setParamAudioTimeScale(timeScale);
638 }
James Dongabed93a2010-04-22 17:27:04 -0700639 } else if (key == "video-param-encoding-bitrate") {
640 int32_t video_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700641 if (safe_strtoi32(value.string(), &video_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700642 return setParamVideoEncodingBitRate(video_bitrate);
643 }
James Dongb9d7e012010-11-09 11:15:47 -0800644 } else if (key == "video-param-rotation-angle-degrees") {
645 int32_t degrees;
646 if (safe_strtoi32(value.string(), &degrees)) {
647 return setParamVideoRotation(degrees);
648 }
James Dong09936ed2010-06-24 19:04:27 -0700649 } else if (key == "video-param-i-frames-interval") {
James Dong52d13f02010-07-02 11:39:06 -0700650 int32_t seconds;
651 if (safe_strtoi32(value.string(), &seconds)) {
652 return setParamVideoIFramesInterval(seconds);
James Dong1244eab2010-06-08 11:58:53 -0700653 }
James Dong81c929a2010-07-01 15:02:14 -0700654 } else if (key == "video-param-encoder-profile") {
655 int32_t profile;
656 if (safe_strtoi32(value.string(), &profile)) {
657 return setParamVideoEncoderProfile(profile);
658 }
659 } else if (key == "video-param-encoder-level") {
660 int32_t level;
661 if (safe_strtoi32(value.string(), &level)) {
662 return setParamVideoEncoderLevel(level);
663 }
James Dong09936ed2010-06-24 19:04:27 -0700664 } else if (key == "video-param-camera-id") {
665 int32_t cameraId;
666 if (safe_strtoi32(value.string(), &cameraId)) {
667 return setParamVideoCameraId(cameraId);
James Dong6feaa462010-06-20 08:20:54 -0700668 }
James Dong52d13f02010-07-02 11:39:06 -0700669 } else if (key == "video-param-time-scale") {
670 int32_t timeScale;
671 if (safe_strtoi32(value.string(), &timeScale)) {
672 return setParamVideoTimeScale(timeScale);
673 }
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700674 } else if (key == "time-lapse-enable") {
675 int32_t timeLapseEnable;
676 if (safe_strtoi32(value.string(), &timeLapseEnable)) {
677 return setParamTimeLapseEnable(timeLapseEnable);
678 }
679 } else if (key == "time-between-time-lapse-frame-capture") {
680 int64_t timeBetweenTimeLapseFrameCaptureMs;
681 if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
682 return setParamTimeBetweenTimeLapseFrameCapture(
683 1000LL * timeBetweenTimeLapseFrameCaptureMs);
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
Gloria Wang62e05a62011-02-23 11:47:34 -0800744 status_t status = OK;
745
Andreas Huber996dddf2010-01-25 15:30:31 -0800746 switch (mOutputFormat) {
747 case OUTPUT_FORMAT_DEFAULT:
748 case OUTPUT_FORMAT_THREE_GPP:
749 case OUTPUT_FORMAT_MPEG_4:
Gloria Wang62e05a62011-02-23 11:47:34 -0800750 status = startMPEG4Recording();
751 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800752
753 case OUTPUT_FORMAT_AMR_NB:
754 case OUTPUT_FORMAT_AMR_WB:
Gloria Wang62e05a62011-02-23 11:47:34 -0800755 status = startAMRRecording();
756 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800757
James Dong2cd841d2010-05-11 11:46:59 -0700758 case OUTPUT_FORMAT_AAC_ADIF:
759 case OUTPUT_FORMAT_AAC_ADTS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800760 status = startAACRecording();
761 break;
James Dong2cd841d2010-05-11 11:46:59 -0700762
Andreas Huber57648e42010-08-04 10:14:30 -0700763 case OUTPUT_FORMAT_RTP_AVP:
Gloria Wang62e05a62011-02-23 11:47:34 -0800764 status = startRTPRecording();
765 break;
Andreas Huber57648e42010-08-04 10:14:30 -0700766
Andreas Huber9adf4662010-10-12 14:17:45 -0700767 case OUTPUT_FORMAT_MPEG2TS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800768 status = startMPEG2TSRecording();
769 break;
Andreas Huber9adf4662010-10-12 14:17:45 -0700770
Andreas Huber996dddf2010-01-25 15:30:31 -0800771 default:
James Dong7b06de62010-06-30 12:41:16 -0700772 LOGE("Unsupported output file format: %d", mOutputFormat);
Gloria Wang62e05a62011-02-23 11:47:34 -0800773 status = UNKNOWN_ERROR;
774 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800775 }
Gloria Wang62e05a62011-02-23 11:47:34 -0800776
777 if ((status == OK) && (!mStarted)) {
778 mStarted = true;
779
780 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700781 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -0800782 params |= IMediaPlayerService::kBatteryDataTrackAudio;
783 }
784 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
785 params |= IMediaPlayerService::kBatteryDataTrackVideo;
786 }
787
788 addBatteryData(params);
789 }
790
791 return status;
Andreas Huber996dddf2010-01-25 15:30:31 -0800792}
793
James Dongabed93a2010-04-22 17:27:04 -0700794sp<MediaSource> StagefrightRecorder::createAudioSource() {
Andreas Huber996dddf2010-01-25 15:30:31 -0800795 sp<AudioSource> audioSource =
796 new AudioSource(
797 mAudioSource,
James Dongabed93a2010-04-22 17:27:04 -0700798 mSampleRate,
James Dongd77d2a92010-06-14 17:45:35 -0700799 mAudioChannels);
Andreas Huber996dddf2010-01-25 15:30:31 -0800800
801 status_t err = audioSource->initCheck();
802
803 if (err != OK) {
James Dongabed93a2010-04-22 17:27:04 -0700804 LOGE("audio source is not initialized");
Andreas Huber996dddf2010-01-25 15:30:31 -0800805 return NULL;
806 }
807
808 sp<MetaData> encMeta = new MetaData;
James Dongabed93a2010-04-22 17:27:04 -0700809 const char *mime;
810 switch (mAudioEncoder) {
811 case AUDIO_ENCODER_AMR_NB:
812 case AUDIO_ENCODER_DEFAULT:
813 mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
814 break;
815 case AUDIO_ENCODER_AMR_WB:
816 mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
817 break;
818 case AUDIO_ENCODER_AAC:
819 mime = MEDIA_MIMETYPE_AUDIO_AAC;
820 break;
821 default:
822 LOGE("Unknown audio encoder: %d", mAudioEncoder);
823 return NULL;
824 }
825 encMeta->setCString(kKeyMIMEType, mime);
Andreas Huber996dddf2010-01-25 15:30:31 -0800826
Andreas Huber259b7c12010-02-10 15:04:31 -0800827 int32_t maxInputSize;
828 CHECK(audioSource->getFormat()->findInt32(
829 kKeyMaxInputSize, &maxInputSize));
830
831 encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
James Dongabed93a2010-04-22 17:27:04 -0700832 encMeta->setInt32(kKeyChannelCount, mAudioChannels);
833 encMeta->setInt32(kKeySampleRate, mSampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700834 encMeta->setInt32(kKeyBitRate, mAudioBitRate);
James Dongeff30e32010-08-13 14:16:26 -0700835 if (mAudioTimeScale > 0) {
836 encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
837 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800838
839 OMXClient client;
840 CHECK_EQ(client.connect(), OK);
841
842 sp<MediaSource> audioEncoder =
843 OMXCodec::Create(client.interface(), encMeta,
844 true /* createEncoder */, audioSource);
James Dong57e7f832010-06-24 19:55:31 -0700845 mAudioSourceNode = audioSource;
Andreas Huber996dddf2010-01-25 15:30:31 -0800846
847 return audioEncoder;
848}
849
James Dong2cd841d2010-05-11 11:46:59 -0700850status_t StagefrightRecorder::startAACRecording() {
James Dongf84bfab2011-03-21 14:29:38 -0700851 // FIXME:
852 // Add support for OUTPUT_FORMAT_AAC_ADIF
853 CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
James Dong2cd841d2010-05-11 11:46:59 -0700854
855 CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700856 CHECK(mAudioSource != AUDIO_SOURCE_CNT);
James Dong2cd841d2010-05-11 11:46:59 -0700857
James Dongf84bfab2011-03-21 14:29:38 -0700858 mWriter = new AACWriter(mOutputFd);
859 status_t status = startRawAudioRecording();
860 if (status != OK) {
861 mWriter.clear();
862 mWriter = NULL;
863 }
James Dong2cd841d2010-05-11 11:46:59 -0700864
James Dongf84bfab2011-03-21 14:29:38 -0700865 return status;
James Dong2cd841d2010-05-11 11:46:59 -0700866}
867
Andreas Huber996dddf2010-01-25 15:30:31 -0800868status_t StagefrightRecorder::startAMRRecording() {
James Dong2cd841d2010-05-11 11:46:59 -0700869 CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
870 mOutputFormat == OUTPUT_FORMAT_AMR_WB);
871
872 if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
873 if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
874 mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
875 LOGE("Invalid encoder %d used for AMRNB recording",
876 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700877 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700878 }
James Dong2cd841d2010-05-11 11:46:59 -0700879 } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
880 if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
881 LOGE("Invlaid encoder %d used for AMRWB recording",
882 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700883 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700884 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800885 }
886
James Dongf84bfab2011-03-21 14:29:38 -0700887 mWriter = new AMRWriter(mOutputFd);
888 status_t status = startRawAudioRecording();
889 if (status != OK) {
890 mWriter.clear();
891 mWriter = NULL;
892 }
893 return status;
894}
895
896status_t StagefrightRecorder::startRawAudioRecording() {
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700897 if (mAudioSource >= AUDIO_SOURCE_CNT) {
James Dong2cd841d2010-05-11 11:46:59 -0700898 LOGE("Invalid audio source: %d", mAudioSource);
James Dong7b06de62010-06-30 12:41:16 -0700899 return BAD_VALUE;
Andreas Huber996dddf2010-01-25 15:30:31 -0800900 }
901
James Dong54815a72011-01-12 20:45:16 -0800902 status_t status = BAD_VALUE;
903 if (OK != (status = checkAudioEncoderCapabilities())) {
904 return status;
905 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800906
James Dong54815a72011-01-12 20:45:16 -0800907 sp<MediaSource> audioEncoder = createAudioSource();
Andreas Huber996dddf2010-01-25 15:30:31 -0800908 if (audioEncoder == NULL) {
909 return UNKNOWN_ERROR;
910 }
911
James Dongf84bfab2011-03-21 14:29:38 -0700912 CHECK(mWriter != 0);
Andreas Huber996dddf2010-01-25 15:30:31 -0800913 mWriter->addSource(audioEncoder);
James Dong18244862010-05-11 14:57:02 -0700914
915 if (mMaxFileDurationUs != 0) {
916 mWriter->setMaxFileDuration(mMaxFileDurationUs);
917 }
918 if (mMaxFileSizeBytes != 0) {
919 mWriter->setMaxFileSize(mMaxFileSizeBytes);
920 }
921 mWriter->setListener(mListener);
Andreas Huber996dddf2010-01-25 15:30:31 -0800922 mWriter->start();
923
924 return OK;
925}
926
Andreas Huber57648e42010-08-04 10:14:30 -0700927status_t StagefrightRecorder::startRTPRecording() {
928 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
929
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700930 if ((mAudioSource != AUDIO_SOURCE_CNT
Andreas Huber57648e42010-08-04 10:14:30 -0700931 && mVideoSource != VIDEO_SOURCE_LIST_END)
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700932 || (mAudioSource == AUDIO_SOURCE_CNT
Andreas Huber57648e42010-08-04 10:14:30 -0700933 && mVideoSource == VIDEO_SOURCE_LIST_END)) {
934 // Must have exactly one source.
935 return BAD_VALUE;
936 }
937
938 if (mOutputFd < 0) {
939 return BAD_VALUE;
940 }
941
942 sp<MediaSource> source;
943
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700944 if (mAudioSource != AUDIO_SOURCE_CNT) {
Andreas Huber57648e42010-08-04 10:14:30 -0700945 source = createAudioSource();
946 } else {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700947
Pannag Sanketi897e27b2011-07-01 17:39:39 -0700948 sp<MediaSource> mediaSource;
949 status_t err = setupMediaSource(&mediaSource);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700950 if (err != OK) {
951 return err;
952 }
953
Pannag Sanketi897e27b2011-07-01 17:39:39 -0700954 err = setupVideoEncoder(mediaSource, mVideoBitRate, &source);
Andreas Huber57648e42010-08-04 10:14:30 -0700955 if (err != OK) {
956 return err;
957 }
958 }
959
James Dong2747e0e2010-11-18 20:59:13 -0800960 mWriter = new ARTPWriter(mOutputFd);
Andreas Huber57648e42010-08-04 10:14:30 -0700961 mWriter->addSource(source);
962 mWriter->setListener(mListener);
963
964 return mWriter->start();
965}
966
Andreas Huber9adf4662010-10-12 14:17:45 -0700967status_t StagefrightRecorder::startMPEG2TSRecording() {
968 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
969
James Dong2747e0e2010-11-18 20:59:13 -0800970 sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
Andreas Huber9adf4662010-10-12 14:17:45 -0700971
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700972 if (mAudioSource != AUDIO_SOURCE_CNT) {
Andreas Huber9adf4662010-10-12 14:17:45 -0700973 if (mAudioEncoder != AUDIO_ENCODER_AAC) {
974 return ERROR_UNSUPPORTED;
975 }
976
977 status_t err = setupAudioEncoder(writer);
978
979 if (err != OK) {
980 return err;
981 }
982 }
983
Pannag Sanketi897e27b2011-07-01 17:39:39 -0700984 if (mVideoSource < VIDEO_SOURCE_LIST_END) {
Andreas Huber9adf4662010-10-12 14:17:45 -0700985 if (mVideoEncoder != VIDEO_ENCODER_H264) {
986 return ERROR_UNSUPPORTED;
987 }
988
Pannag Sanketi897e27b2011-07-01 17:39:39 -0700989 sp<MediaSource> mediaSource;
990 status_t err = setupMediaSource(&mediaSource);
Kenny Root4a90f932010-10-14 23:58:41 -0700991 if (err != OK) {
992 return err;
993 }
994
Andreas Huber9adf4662010-10-12 14:17:45 -0700995 sp<MediaSource> encoder;
Pannag Sanketi897e27b2011-07-01 17:39:39 -0700996 err = setupVideoEncoder(mediaSource, mVideoBitRate, &encoder);
Andreas Huber9adf4662010-10-12 14:17:45 -0700997
998 if (err != OK) {
999 return err;
1000 }
1001
1002 writer->addSource(encoder);
1003 }
1004
1005 if (mMaxFileDurationUs != 0) {
1006 writer->setMaxFileDuration(mMaxFileDurationUs);
1007 }
1008
1009 if (mMaxFileSizeBytes != 0) {
1010 writer->setMaxFileSize(mMaxFileSizeBytes);
1011 }
1012
1013 mWriter = writer;
1014
1015 return mWriter->start();
1016}
1017
James Dong42a18c02010-06-16 17:27:46 -07001018void StagefrightRecorder::clipVideoFrameRate() {
1019 LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
1020 int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1021 "enc.vid.fps.min", mVideoEncoder);
1022 int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1023 "enc.vid.fps.max", mVideoEncoder);
James Dongb15f2ea2010-10-24 09:32:39 -07001024 if (mFrameRate < minFrameRate && mFrameRate != -1) {
James Dong42a18c02010-06-16 17:27:46 -07001025 LOGW("Intended video encoding frame rate (%d fps) is too small"
1026 " and will be set to (%d fps)", mFrameRate, minFrameRate);
1027 mFrameRate = minFrameRate;
1028 } else if (mFrameRate > maxFrameRate) {
1029 LOGW("Intended video encoding frame rate (%d fps) is too large"
1030 " and will be set to (%d fps)", mFrameRate, maxFrameRate);
1031 mFrameRate = maxFrameRate;
1032 }
1033}
1034
1035void StagefrightRecorder::clipVideoBitRate() {
1036 LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
1037 int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1038 "enc.vid.bps.min", mVideoEncoder);
1039 int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1040 "enc.vid.bps.max", mVideoEncoder);
1041 if (mVideoBitRate < minBitRate) {
1042 LOGW("Intended video encoding bit rate (%d bps) is too small"
1043 " and will be set to (%d bps)", mVideoBitRate, minBitRate);
1044 mVideoBitRate = minBitRate;
1045 } else if (mVideoBitRate > maxBitRate) {
1046 LOGW("Intended video encoding bit rate (%d bps) is too large"
1047 " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
1048 mVideoBitRate = maxBitRate;
1049 }
1050}
1051
1052void StagefrightRecorder::clipVideoFrameWidth() {
1053 LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
1054 int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1055 "enc.vid.width.min", mVideoEncoder);
1056 int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1057 "enc.vid.width.max", mVideoEncoder);
1058 if (mVideoWidth < minFrameWidth) {
1059 LOGW("Intended video encoding frame width (%d) is too small"
1060 " and will be set to (%d)", mVideoWidth, minFrameWidth);
1061 mVideoWidth = minFrameWidth;
1062 } else if (mVideoWidth > maxFrameWidth) {
1063 LOGW("Intended video encoding frame width (%d) is too large"
1064 " and will be set to (%d)", mVideoWidth, maxFrameWidth);
1065 mVideoWidth = maxFrameWidth;
1066 }
1067}
1068
James Dong0c128b62010-10-08 11:59:32 -07001069status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
Nipun Kwatra453e92f2010-08-04 14:26:45 -07001070 if (!mCaptureTimeLapse) {
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001071 // Dont clip for time lapse capture as encoder will have enough
1072 // time to encode because of slow capture rate of time lapse.
1073 clipVideoBitRate();
1074 clipVideoFrameRate();
1075 clipVideoFrameWidth();
1076 clipVideoFrameHeight();
James Dongbe650872011-07-07 16:41:25 -07001077 setDefaultProfileIfNecessary();
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001078 }
James Dong7b06de62010-06-30 12:41:16 -07001079 return OK;
1080}
1081
James Dongbe650872011-07-07 16:41:25 -07001082// Set to use AVC baseline profile if the encoding parameters matches
1083// CAMCORDER_QUALITY_LOW profile; this is for the sake of MMS service.
1084void StagefrightRecorder::setDefaultProfileIfNecessary() {
1085 LOGV("setDefaultProfileIfNecessary");
1086
1087 camcorder_quality quality = CAMCORDER_QUALITY_LOW;
1088
1089 int64_t durationUs = mEncoderProfiles->getCamcorderProfileParamByName(
1090 "duration", mCameraId, quality) * 1000000LL;
1091
1092 int fileFormat = mEncoderProfiles->getCamcorderProfileParamByName(
1093 "file.format", mCameraId, quality);
1094
1095 int videoCodec = mEncoderProfiles->getCamcorderProfileParamByName(
1096 "vid.codec", mCameraId, quality);
1097
1098 int videoBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
1099 "vid.bps", mCameraId, quality);
1100
1101 int videoFrameRate = mEncoderProfiles->getCamcorderProfileParamByName(
1102 "vid.fps", mCameraId, quality);
1103
1104 int videoFrameWidth = mEncoderProfiles->getCamcorderProfileParamByName(
1105 "vid.width", mCameraId, quality);
1106
1107 int videoFrameHeight = mEncoderProfiles->getCamcorderProfileParamByName(
1108 "vid.height", mCameraId, quality);
1109
1110 int audioCodec = mEncoderProfiles->getCamcorderProfileParamByName(
1111 "aud.codec", mCameraId, quality);
1112
1113 int audioBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
1114 "aud.bps", mCameraId, quality);
1115
1116 int audioSampleRate = mEncoderProfiles->getCamcorderProfileParamByName(
1117 "aud.hz", mCameraId, quality);
1118
1119 int audioChannels = mEncoderProfiles->getCamcorderProfileParamByName(
1120 "aud.ch", mCameraId, quality);
1121
1122 if (durationUs == mMaxFileDurationUs &&
1123 fileFormat == mOutputFormat &&
1124 videoCodec == mVideoEncoder &&
1125 videoBitRate == mVideoBitRate &&
1126 videoFrameRate == mFrameRate &&
1127 videoFrameWidth == mVideoWidth &&
1128 videoFrameHeight == mVideoHeight &&
1129 audioCodec == mAudioEncoder &&
1130 audioBitRate == mAudioBitRate &&
1131 audioSampleRate == mSampleRate &&
1132 audioChannels == mAudioChannels) {
1133 if (videoCodec == VIDEO_ENCODER_H264) {
1134 LOGI("Force to use AVC baseline profile");
1135 setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline);
1136 }
1137 }
1138}
1139
James Dong54815a72011-01-12 20:45:16 -08001140status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
1141 clipAudioBitRate();
1142 clipAudioSampleRate();
1143 clipNumberOfAudioChannels();
1144 return OK;
1145}
1146
1147void StagefrightRecorder::clipAudioBitRate() {
1148 LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
1149
1150 int minAudioBitRate =
1151 mEncoderProfiles->getAudioEncoderParamByName(
1152 "enc.aud.bps.min", mAudioEncoder);
1153 if (mAudioBitRate < minAudioBitRate) {
1154 LOGW("Intended audio encoding bit rate (%d) is too small"
1155 " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
1156 mAudioBitRate = minAudioBitRate;
1157 }
1158
1159 int maxAudioBitRate =
1160 mEncoderProfiles->getAudioEncoderParamByName(
1161 "enc.aud.bps.max", mAudioEncoder);
1162 if (mAudioBitRate > maxAudioBitRate) {
1163 LOGW("Intended audio encoding bit rate (%d) is too large"
1164 " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
1165 mAudioBitRate = maxAudioBitRate;
1166 }
1167}
1168
1169void StagefrightRecorder::clipAudioSampleRate() {
1170 LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
1171
1172 int minSampleRate =
1173 mEncoderProfiles->getAudioEncoderParamByName(
1174 "enc.aud.hz.min", mAudioEncoder);
1175 if (mSampleRate < minSampleRate) {
1176 LOGW("Intended audio sample rate (%d) is too small"
1177 " and will be set to (%d)", mSampleRate, minSampleRate);
1178 mSampleRate = minSampleRate;
1179 }
1180
1181 int maxSampleRate =
1182 mEncoderProfiles->getAudioEncoderParamByName(
1183 "enc.aud.hz.max", mAudioEncoder);
1184 if (mSampleRate > maxSampleRate) {
1185 LOGW("Intended audio sample rate (%d) is too large"
1186 " and will be set to (%d)", mSampleRate, maxSampleRate);
1187 mSampleRate = maxSampleRate;
1188 }
1189}
1190
1191void StagefrightRecorder::clipNumberOfAudioChannels() {
1192 LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
1193
1194 int minChannels =
1195 mEncoderProfiles->getAudioEncoderParamByName(
1196 "enc.aud.ch.min", mAudioEncoder);
1197 if (mAudioChannels < minChannels) {
1198 LOGW("Intended number of audio channels (%d) is too small"
1199 " and will be set to (%d)", mAudioChannels, minChannels);
1200 mAudioChannels = minChannels;
1201 }
1202
1203 int maxChannels =
1204 mEncoderProfiles->getAudioEncoderParamByName(
1205 "enc.aud.ch.max", mAudioEncoder);
1206 if (mAudioChannels > maxChannels) {
1207 LOGW("Intended number of audio channels (%d) is too large"
1208 " and will be set to (%d)", mAudioChannels, maxChannels);
1209 mAudioChannels = maxChannels;
1210 }
1211}
1212
James Dong42a18c02010-06-16 17:27:46 -07001213void StagefrightRecorder::clipVideoFrameHeight() {
1214 LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
1215 int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1216 "enc.vid.height.min", mVideoEncoder);
1217 int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1218 "enc.vid.height.max", mVideoEncoder);
1219 if (mVideoHeight < minFrameHeight) {
1220 LOGW("Intended video encoding frame height (%d) is too small"
1221 " and will be set to (%d)", mVideoHeight, minFrameHeight);
1222 mVideoHeight = minFrameHeight;
1223 } else if (mVideoHeight > maxFrameHeight) {
1224 LOGW("Intended video encoding frame height (%d) is too large"
1225 " and will be set to (%d)", mVideoHeight, maxFrameHeight);
1226 mVideoHeight = maxFrameHeight;
1227 }
1228}
1229
Pannag Sanketi897e27b2011-07-01 17:39:39 -07001230// Set up the appropriate MediaSource depending on the chosen option
1231status_t StagefrightRecorder::setupMediaSource(
1232 sp<MediaSource> *mediaSource) {
1233 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1234 || mVideoSource == VIDEO_SOURCE_CAMERA) {
1235 sp<CameraSource> cameraSource;
1236 status_t err = setupCameraSource(&cameraSource);
1237 if (err != OK) {
1238 return err;
1239 }
1240 *mediaSource = cameraSource;
1241 } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
1242 // If using GRAlloc buffers, setup surfacemediasource.
1243 // Later a handle to that will be passed
1244 // to the client side when queried
1245 status_t err = setupSurfaceMediaSource();
1246 if (err != OK) {
1247 return err;
1248 }
1249 *mediaSource = mSurfaceMediaSource;
1250 } else {
1251 return INVALID_OPERATION;
1252 }
1253 return OK;
1254}
1255
1256// setupSurfaceMediaSource creates a source with the given
1257// width and height and framerate.
1258// TODO: This could go in a static function inside SurfaceMediaSource
1259// similar to that in CameraSource
1260status_t StagefrightRecorder::setupSurfaceMediaSource() {
1261 status_t err = OK;
1262 mSurfaceMediaSource = new SurfaceMediaSource(mVideoWidth, mVideoHeight);
1263 if (mSurfaceMediaSource == NULL) {
1264 return NO_INIT;
1265 }
1266
1267 if (mFrameRate == -1) {
1268 int32_t frameRate = 0;
1269 CHECK (mSurfaceMediaSource->getFormat()->findInt32(
1270 kKeyFrameRate, &frameRate));
1271 LOGI("Frame rate is not explicitly set. Use the current frame "
1272 "rate (%d fps)", frameRate);
1273 mFrameRate = frameRate;
1274 } else {
1275 err = mSurfaceMediaSource->setFrameRate(mFrameRate);
1276 }
1277 CHECK(mFrameRate != -1);
1278
1279 mIsMetaDataStoredInVideoBuffers =
1280 mSurfaceMediaSource->isMetaDataStoredInVideoBuffers();
1281 return err;
1282}
1283
James Dong05c2fd52010-11-02 13:20:11 -07001284status_t StagefrightRecorder::setupCameraSource(
1285 sp<CameraSource> *cameraSource) {
James Dongb15f2ea2010-10-24 09:32:39 -07001286 status_t err = OK;
1287 if ((err = checkVideoEncoderCapabilities()) != OK) {
1288 return err;
1289 }
James Dong0c128b62010-10-08 11:59:32 -07001290 Size videoSize;
1291 videoSize.width = mVideoWidth;
1292 videoSize.height = mVideoHeight;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001293 if (mCaptureTimeLapse) {
James Dong0c128b62010-10-08 11:59:32 -07001294 mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
Wu-cheng Li42419ce2011-06-01 17:22:24 +08001295 mCamera, mCameraProxy, mCameraId,
James Dong0c128b62010-10-08 11:59:32 -07001296 videoSize, mFrameRate, mPreviewSurface,
1297 mTimeBetweenTimeLapseFrameCaptureUs);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001298 *cameraSource = mCameraSourceTimeLapse;
1299 } else {
James Dong0c128b62010-10-08 11:59:32 -07001300 *cameraSource = CameraSource::CreateFromCamera(
Wu-cheng Li42419ce2011-06-01 17:22:24 +08001301 mCamera, mCameraProxy, mCameraId, videoSize, mFrameRate,
James Dong05c2fd52010-11-02 13:20:11 -07001302 mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001303 }
Wu-cheng Li42419ce2011-06-01 17:22:24 +08001304 mCamera.clear();
1305 mCameraProxy.clear();
James Dong5df53fe2010-12-05 14:25:34 -08001306 if (*cameraSource == NULL) {
1307 return UNKNOWN_ERROR;
1308 }
1309
1310 if ((*cameraSource)->initCheck() != OK) {
1311 (*cameraSource).clear();
1312 *cameraSource = NULL;
1313 return NO_INIT;
1314 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001315
James Dongb15f2ea2010-10-24 09:32:39 -07001316 // When frame rate is not set, the actual frame rate will be set to
1317 // the current frame rate being used.
1318 if (mFrameRate == -1) {
1319 int32_t frameRate = 0;
1320 CHECK ((*cameraSource)->getFormat()->findInt32(
James Dongaac193c2010-11-10 20:43:53 -08001321 kKeyFrameRate, &frameRate));
James Dongb15f2ea2010-10-24 09:32:39 -07001322 LOGI("Frame rate is not explicitly set. Use the current frame "
1323 "rate (%d fps)", frameRate);
1324 mFrameRate = frameRate;
1325 }
1326
1327 CHECK(mFrameRate != -1);
James Dong05c2fd52010-11-02 13:20:11 -07001328
1329 mIsMetaDataStoredInVideoBuffers =
1330 (*cameraSource)->isMetaDataStoredInVideoBuffers();
1331
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001332 return OK;
1333}
1334
1335status_t StagefrightRecorder::setupVideoEncoder(
1336 sp<MediaSource> cameraSource,
1337 int32_t videoBitRate,
1338 sp<MediaSource> *source) {
1339 source->clear();
James Dong7b06de62010-06-30 12:41:16 -07001340
1341 sp<MetaData> enc_meta = new MetaData;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001342 enc_meta->setInt32(kKeyBitRate, videoBitRate);
James Dongaac193c2010-11-10 20:43:53 -08001343 enc_meta->setInt32(kKeyFrameRate, mFrameRate);
James Dong7b06de62010-06-30 12:41:16 -07001344
1345 switch (mVideoEncoder) {
1346 case VIDEO_ENCODER_H263:
1347 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
1348 break;
1349
1350 case VIDEO_ENCODER_MPEG_4_SP:
1351 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
1352 break;
1353
1354 case VIDEO_ENCODER_H264:
1355 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
1356 break;
1357
1358 default:
1359 CHECK(!"Should not be here, unsupported video encoding.");
1360 break;
1361 }
1362
1363 sp<MetaData> meta = cameraSource->getFormat();
1364
James Dong1cc31e62010-07-02 17:44:44 -07001365 int32_t width, height, stride, sliceHeight, colorFormat;
James Dong7b06de62010-06-30 12:41:16 -07001366 CHECK(meta->findInt32(kKeyWidth, &width));
1367 CHECK(meta->findInt32(kKeyHeight, &height));
1368 CHECK(meta->findInt32(kKeyStride, &stride));
1369 CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
James Dong1cc31e62010-07-02 17:44:44 -07001370 CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
James Dong7b06de62010-06-30 12:41:16 -07001371
1372 enc_meta->setInt32(kKeyWidth, width);
1373 enc_meta->setInt32(kKeyHeight, height);
James Dong52d13f02010-07-02 11:39:06 -07001374 enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
James Dong7b06de62010-06-30 12:41:16 -07001375 enc_meta->setInt32(kKeyStride, stride);
1376 enc_meta->setInt32(kKeySliceHeight, sliceHeight);
James Dong1cc31e62010-07-02 17:44:44 -07001377 enc_meta->setInt32(kKeyColorFormat, colorFormat);
James Dongeff30e32010-08-13 14:16:26 -07001378 if (mVideoTimeScale > 0) {
1379 enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
1380 }
James Dong81c929a2010-07-01 15:02:14 -07001381 if (mVideoEncoderProfile != -1) {
1382 enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
1383 }
1384 if (mVideoEncoderLevel != -1) {
1385 enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
1386 }
James Dong7b06de62010-06-30 12:41:16 -07001387
1388 OMXClient client;
1389 CHECK_EQ(client.connect(), OK);
1390
James Dong6312dd62010-12-02 14:48:23 -08001391 uint32_t encoder_flags = 0;
James Dong5fb60c72011-01-18 21:12:31 -08001392 if (mIsMetaDataStoredInVideoBuffers) {
James Dong6312dd62010-12-02 14:48:23 -08001393 encoder_flags |= OMXCodec::kHardwareCodecsOnly;
James Dong05c2fd52010-11-02 13:20:11 -07001394 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
1395 }
James Dong5f3ab062011-01-25 16:31:28 -08001396
1397 // Do not wait for all the input buffers to become available.
1398 // This give timelapse video recording faster response in
1399 // receiving output from video encoder component.
1400 if (mCaptureTimeLapse) {
1401 encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
1402 }
1403
James Dong7b06de62010-06-30 12:41:16 -07001404 sp<MediaSource> encoder = OMXCodec::Create(
1405 client.interface(), enc_meta,
Nipun Kwatra077cba42010-07-20 11:37:17 -07001406 true /* createEncoder */, cameraSource,
1407 NULL, encoder_flags);
James Dong7b06de62010-06-30 12:41:16 -07001408 if (encoder == NULL) {
James Dong6312dd62010-12-02 14:48:23 -08001409 LOGW("Failed to create the encoder");
1410 // When the encoder fails to be created, we need
1411 // release the camera source due to the camera's lock
1412 // and unlock mechanism.
1413 cameraSource->stop();
James Dong7b06de62010-06-30 12:41:16 -07001414 return UNKNOWN_ERROR;
1415 }
1416
Andreas Huber57648e42010-08-04 10:14:30 -07001417 *source = encoder;
1418
James Dong7b06de62010-06-30 12:41:16 -07001419 return OK;
1420}
1421
1422status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
James Dong54815a72011-01-12 20:45:16 -08001423 status_t status = BAD_VALUE;
1424 if (OK != (status = checkAudioEncoderCapabilities())) {
1425 return status;
1426 }
1427
James Dong7b06de62010-06-30 12:41:16 -07001428 switch(mAudioEncoder) {
1429 case AUDIO_ENCODER_AMR_NB:
1430 case AUDIO_ENCODER_AMR_WB:
1431 case AUDIO_ENCODER_AAC:
James Dong7b06de62010-06-30 12:41:16 -07001432 break;
James Dong54815a72011-01-12 20:45:16 -08001433
James Dong7b06de62010-06-30 12:41:16 -07001434 default:
1435 LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1436 return UNKNOWN_ERROR;
1437 }
1438
James Dong54815a72011-01-12 20:45:16 -08001439 sp<MediaSource> audioEncoder = createAudioSource();
James Dong7b06de62010-06-30 12:41:16 -07001440 if (audioEncoder == NULL) {
1441 return UNKNOWN_ERROR;
1442 }
James Dong52d13f02010-07-02 11:39:06 -07001443
James Dong7b06de62010-06-30 12:41:16 -07001444 writer->addSource(audioEncoder);
1445 return OK;
1446}
1447
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001448status_t StagefrightRecorder::setupMPEG4Recording(
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001449 int outputFd,
1450 int32_t videoWidth, int32_t videoHeight,
1451 int32_t videoBitRate,
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001452 int32_t *totalBitRate,
1453 sp<MediaWriter> *mediaWriter) {
1454 mediaWriter->clear();
1455 *totalBitRate = 0;
James Dong7b06de62010-06-30 12:41:16 -07001456 status_t err = OK;
James Dong2747e0e2010-11-18 20:59:13 -08001457 sp<MediaWriter> writer = new MPEG4Writer(outputFd);
Andreas Huber996dddf2010-01-25 15:30:31 -08001458
Pannag Sanketi897e27b2011-07-01 17:39:39 -07001459 if (mVideoSource < VIDEO_SOURCE_LIST_END) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001460
Pannag Sanketi897e27b2011-07-01 17:39:39 -07001461 sp<MediaSource> mediaSource;
James Dong83dd43f2011-06-29 16:56:52 -07001462 err = setupMediaSource(&mediaSource);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001463 if (err != OK) {
1464 return err;
1465 }
1466
Andreas Huber57648e42010-08-04 10:14:30 -07001467 sp<MediaSource> encoder;
Pannag Sanketi897e27b2011-07-01 17:39:39 -07001468 err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001469 if (err != OK) {
1470 return err;
1471 }
1472
Andreas Huber57648e42010-08-04 10:14:30 -07001473 writer->addSource(encoder);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001474 *totalBitRate += videoBitRate;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001475 }
1476
James Dong44b004b2011-01-19 20:42:19 -08001477 // Audio source is added at the end if it exists.
1478 // This help make sure that the "recoding" sound is suppressed for
1479 // camcorder applications in the recorded files.
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001480 if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
James Dong44b004b2011-01-19 20:42:19 -08001481 err = setupAudioEncoder(writer);
1482 if (err != OK) return err;
1483 *totalBitRate += mAudioBitRate;
1484 }
1485
James Dong63299c02010-07-28 10:08:03 -07001486 if (mInterleaveDurationUs > 0) {
1487 reinterpret_cast<MPEG4Writer *>(writer.get())->
1488 setInterleaveDuration(mInterleaveDurationUs);
1489 }
James Dong987ab482011-05-11 19:09:25 -07001490 if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
1491 reinterpret_cast<MPEG4Writer *>(writer.get())->
1492 setGeoData(mLatitudex10000, mLongitudex10000);
1493 }
James Dong18244862010-05-11 14:57:02 -07001494 if (mMaxFileDurationUs != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001495 writer->setMaxFileDuration(mMaxFileDurationUs);
James Dong18244862010-05-11 14:57:02 -07001496 }
1497 if (mMaxFileSizeBytes != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001498 writer->setMaxFileSize(mMaxFileSizeBytes);
James Dong18244862010-05-11 14:57:02 -07001499 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001500
James Dong13a33162011-05-09 16:56:25 -07001501 mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
1502 if (mStartTimeOffsetMs > 0) {
1503 reinterpret_cast<MPEG4Writer *>(writer.get())->
1504 setStartTimeOffsetMs(mStartTimeOffsetMs);
1505 }
1506
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001507 writer->setListener(mListener);
1508 *mediaWriter = writer;
1509 return OK;
1510}
1511
1512void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
1513 sp<MetaData> *meta) {
1514 (*meta)->setInt64(kKeyTime, startTimeUs);
1515 (*meta)->setInt32(kKeyFileType, mOutputFormat);
1516 (*meta)->setInt32(kKeyBitRate, totalBitRate);
1517 (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
James Dongeff30e32010-08-13 14:16:26 -07001518 if (mMovieTimeScale > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001519 (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
James Dongeff30e32010-08-13 14:16:26 -07001520 }
James Dong09936ed2010-06-24 19:04:27 -07001521 if (mTrackEveryTimeDurationUs > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001522 (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -07001523 }
James Dongb9d7e012010-11-09 11:15:47 -08001524 if (mRotationDegrees != 0) {
1525 (*meta)->setInt32(kKeyRotation, mRotationDegrees);
1526 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001527}
1528
1529status_t StagefrightRecorder::startMPEG4Recording() {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001530 int32_t totalBitRate;
James Dong83dd43f2011-06-29 16:56:52 -07001531 status_t err = setupMPEG4Recording(
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001532 mOutputFd, mVideoWidth, mVideoHeight,
1533 mVideoBitRate, &totalBitRate, &mWriter);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001534 if (err != OK) {
1535 return err;
1536 }
1537
1538 int64_t startTimeUs = systemTime() / 1000;
1539 sp<MetaData> meta = new MetaData;
1540 setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
1541
1542 err = mWriter->start(meta.get());
1543 if (err != OK) {
1544 return err;
1545 }
1546
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001547 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001548}
1549
James Dong08c74732010-06-10 12:28:15 -07001550status_t StagefrightRecorder::pause() {
James Dongc0ab2a62010-06-29 16:29:19 -07001551 LOGV("pause");
James Dong08c74732010-06-10 12:28:15 -07001552 if (mWriter == NULL) {
1553 return UNKNOWN_ERROR;
1554 }
1555 mWriter->pause();
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001556
Gloria Wang62e05a62011-02-23 11:47:34 -08001557 if (mStarted) {
1558 mStarted = false;
1559
1560 uint32_t params = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001561 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -08001562 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1563 }
1564 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1565 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1566 }
1567
1568 addBatteryData(params);
1569 }
1570
1571
James Dong08c74732010-06-10 12:28:15 -07001572 return OK;
1573}
1574
Andreas Huberea6a38c2009-11-16 15:43:38 -08001575status_t StagefrightRecorder::stop() {
James Dongc0ab2a62010-06-29 16:29:19 -07001576 LOGV("stop");
James Dongd0366622010-08-18 19:10:39 -07001577 status_t err = OK;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001578
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001579 if (mCaptureTimeLapse && mCameraSourceTimeLapse != NULL) {
1580 mCameraSourceTimeLapse->startQuickReadReturns();
1581 mCameraSourceTimeLapse = NULL;
1582 }
1583
James Dongc0ab2a62010-06-29 16:29:19 -07001584 if (mWriter != NULL) {
James Dongd0366622010-08-18 19:10:39 -07001585 err = mWriter->stop();
James Dong7b06de62010-06-30 12:41:16 -07001586 mWriter.clear();
Andreas Huberea6a38c2009-11-16 15:43:38 -08001587 }
1588
James Dongc6280bc2010-08-11 17:12:39 -07001589 if (mOutputFd >= 0) {
1590 ::close(mOutputFd);
1591 mOutputFd = -1;
1592 }
1593
Gloria Wang62e05a62011-02-23 11:47:34 -08001594 if (mStarted) {
1595 mStarted = false;
1596
1597 uint32_t params = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001598 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -08001599 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1600 }
1601 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1602 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1603 }
1604
1605 addBatteryData(params);
1606 }
1607
1608
James Dongd0366622010-08-18 19:10:39 -07001609 return err;
James Dongc0ab2a62010-06-29 16:29:19 -07001610}
1611
1612status_t StagefrightRecorder::close() {
1613 LOGV("close");
1614 stop();
1615
Andreas Huberea6a38c2009-11-16 15:43:38 -08001616 return OK;
1617}
1618
1619status_t StagefrightRecorder::reset() {
James Dongc0ab2a62010-06-29 16:29:19 -07001620 LOGV("reset");
Andreas Huberea6a38c2009-11-16 15:43:38 -08001621 stop();
1622
James Dongabed93a2010-04-22 17:27:04 -07001623 // No audio or video source by default
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001624 mAudioSource = AUDIO_SOURCE_CNT;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001625 mVideoSource = VIDEO_SOURCE_LIST_END;
James Dongabed93a2010-04-22 17:27:04 -07001626
1627 // Default parameters
1628 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
1629 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
1630 mVideoEncoder = VIDEO_ENCODER_H263;
1631 mVideoWidth = 176;
1632 mVideoHeight = 144;
James Dongb15f2ea2010-10-24 09:32:39 -07001633 mFrameRate = -1;
James Dongabed93a2010-04-22 17:27:04 -07001634 mVideoBitRate = 192000;
1635 mSampleRate = 8000;
1636 mAudioChannels = 1;
1637 mAudioBitRate = 12200;
James Dongc6161722010-05-20 17:55:52 -07001638 mInterleaveDurationUs = 0;
James Dong52d13f02010-07-02 11:39:06 -07001639 mIFramesIntervalSec = 1;
James Dong57e7f832010-06-24 19:55:31 -07001640 mAudioSourceNode = 0;
James Dong6feaa462010-06-20 08:20:54 -07001641 mUse64BitFileOffset = false;
James Dongeff30e32010-08-13 14:16:26 -07001642 mMovieTimeScale = -1;
1643 mAudioTimeScale = -1;
1644 mVideoTimeScale = -1;
James Dong09936ed2010-06-24 19:04:27 -07001645 mCameraId = 0;
James Dong13a33162011-05-09 16:56:25 -07001646 mStartTimeOffsetMs = -1;
James Dong81c929a2010-07-01 15:02:14 -07001647 mVideoEncoderProfile = -1;
1648 mVideoEncoderLevel = -1;
1649 mMaxFileDurationUs = 0;
1650 mMaxFileSizeBytes = 0;
James Dong09936ed2010-06-24 19:04:27 -07001651 mTrackEveryTimeDurationUs = 0;
Nipun Kwatrad26920a2010-06-30 18:51:31 -07001652 mCaptureTimeLapse = false;
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001653 mTimeBetweenTimeLapseFrameCaptureUs = -1;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001654 mCameraSourceTimeLapse = NULL;
James Dong05c2fd52010-11-02 13:20:11 -07001655 mIsMetaDataStoredInVideoBuffers = false;
James Dong42a18c02010-06-16 17:27:46 -07001656 mEncoderProfiles = MediaProfiles::getInstance();
James Dong5d0b7832010-11-10 12:26:58 -08001657 mRotationDegrees = 0;
James Dong987ab482011-05-11 19:09:25 -07001658 mLatitudex10000 = -3600000;
1659 mLongitudex10000 = -3600000;
James Dongabed93a2010-04-22 17:27:04 -07001660
Andreas Huberea6a38c2009-11-16 15:43:38 -08001661 mOutputFd = -1;
1662
1663 return OK;
1664}
1665
1666status_t StagefrightRecorder::getMaxAmplitude(int *max) {
James Dongc0ab2a62010-06-29 16:29:19 -07001667 LOGV("getMaxAmplitude");
1668
1669 if (max == NULL) {
1670 LOGE("Null pointer argument");
1671 return BAD_VALUE;
1672 }
1673
James Dong57e7f832010-06-24 19:55:31 -07001674 if (mAudioSourceNode != 0) {
1675 *max = mAudioSourceNode->getMaxAmplitude();
1676 } else {
1677 *max = 0;
1678 }
Andreas Huber996dddf2010-01-25 15:30:31 -08001679
1680 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001681}
1682
James Dong3f51fa72010-08-18 03:32:26 -07001683status_t StagefrightRecorder::dump(
1684 int fd, const Vector<String16>& args) const {
1685 LOGV("dump");
James Dong929642e2010-07-08 11:16:11 -07001686 const size_t SIZE = 256;
1687 char buffer[SIZE];
1688 String8 result;
James Dong3f51fa72010-08-18 03:32:26 -07001689 if (mWriter != 0) {
1690 mWriter->dump(fd, args);
1691 } else {
1692 snprintf(buffer, SIZE, " No file writer\n");
1693 result.append(buffer);
1694 }
1695 snprintf(buffer, SIZE, " Recorder: %p\n", this);
James Dong929642e2010-07-08 11:16:11 -07001696 snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
1697 result.append(buffer);
1698 snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
1699 result.append(buffer);
1700 snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1701 result.append(buffer);
1702 snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
1703 result.append(buffer);
1704 snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1705 result.append(buffer);
1706 snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
1707 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001708 snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1709 result.append(buffer);
1710 snprintf(buffer, SIZE, " Audio\n");
1711 result.append(buffer);
1712 snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
1713 result.append(buffer);
1714 snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
1715 result.append(buffer);
1716 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
1717 result.append(buffer);
1718 snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
1719 result.append(buffer);
1720 snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
1721 result.append(buffer);
1722 snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1723 result.append(buffer);
1724 snprintf(buffer, SIZE, " Video\n");
1725 result.append(buffer);
1726 snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
1727 result.append(buffer);
1728 snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
1729 result.append(buffer);
James Dong13a33162011-05-09 16:56:25 -07001730 snprintf(buffer, SIZE, " Start time offset (ms): %d\n", mStartTimeOffsetMs);
1731 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001732 snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
1733 result.append(buffer);
1734 snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
1735 result.append(buffer);
1736 snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
1737 result.append(buffer);
James Dong52d13f02010-07-02 11:39:06 -07001738 snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec);
James Dong929642e2010-07-08 11:16:11 -07001739 result.append(buffer);
1740 snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1741 result.append(buffer);
1742 snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
1743 result.append(buffer);
1744 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
1745 result.append(buffer);
1746 ::write(fd, result.string(), result.size());
1747 return OK;
1748}
Andreas Huberea6a38c2009-11-16 15:43:38 -08001749} // namespace android