blob: cf01ff6cd2706fa3a21f02341140d5c87e9c9993 [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
James Dongb00e2462010-04-26 17:48:26 -070023#include <binder/IPCThreadState.h>
Andreas Huber996dddf2010-01-25 15:30:31 -080024#include <media/stagefright/AudioSource.h>
25#include <media/stagefright/AMRWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080026#include <media/stagefright/CameraSource.h>
27#include <media/stagefright/MPEG4Writer.h>
28#include <media/stagefright/MediaDebug.h>
29#include <media/stagefright/MediaDefs.h>
30#include <media/stagefright/MetaData.h>
31#include <media/stagefright/OMXClient.h>
32#include <media/stagefright/OMXCodec.h>
James Dong42a18c02010-06-16 17:27:46 -070033#include <media/MediaProfiles.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080034#include <camera/ICamera.h>
James Dongb00e2462010-04-26 17:48:26 -070035#include <camera/Camera.h>
James Dong2cd841d2010-05-11 11:46:59 -070036#include <camera/CameraParameters.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080037#include <surfaceflinger/ISurface.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080038#include <utils/Errors.h>
James Dongb00e2462010-04-26 17:48:26 -070039#include <sys/types.h>
40#include <unistd.h>
James Dongabed93a2010-04-22 17:27:04 -070041#include <ctype.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080042
Andreas Huber57648e42010-08-04 10:14:30 -070043#include "ARTPWriter.h"
44
Andreas Huberea6a38c2009-11-16 15:43:38 -080045namespace android {
46
James Dongc0ab2a62010-06-29 16:29:19 -070047StagefrightRecorder::StagefrightRecorder()
48 : mWriter(NULL),
49 mOutputFd(-1) {
50
51 LOGV("Constructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080052 reset();
53}
54
55StagefrightRecorder::~StagefrightRecorder() {
James Dongc0ab2a62010-06-29 16:29:19 -070056 LOGV("Destructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080057 stop();
Andreas Huberea6a38c2009-11-16 15:43:38 -080058}
59
60status_t StagefrightRecorder::init() {
James Dongc0ab2a62010-06-29 16:29:19 -070061 LOGV("init");
Andreas Huberea6a38c2009-11-16 15:43:38 -080062 return OK;
63}
64
65status_t StagefrightRecorder::setAudioSource(audio_source as) {
James Dongc0ab2a62010-06-29 16:29:19 -070066 LOGV("setAudioSource: %d", as);
67 if (as < AUDIO_SOURCE_DEFAULT ||
68 as >= AUDIO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -070069 LOGE("Invalid audio source: %d", as);
James Dongc0ab2a62010-06-29 16:29:19 -070070 return BAD_VALUE;
71 }
72
73 if (as == AUDIO_SOURCE_DEFAULT) {
74 mAudioSource = AUDIO_SOURCE_MIC;
75 } else {
76 mAudioSource = as;
77 }
Andreas Huberea6a38c2009-11-16 15:43:38 -080078
79 return OK;
80}
81
82status_t StagefrightRecorder::setVideoSource(video_source vs) {
James Dongc0ab2a62010-06-29 16:29:19 -070083 LOGV("setVideoSource: %d", vs);
84 if (vs < VIDEO_SOURCE_DEFAULT ||
85 vs >= VIDEO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -070086 LOGE("Invalid video source: %d", vs);
James Dongc0ab2a62010-06-29 16:29:19 -070087 return BAD_VALUE;
88 }
89
90 if (vs == VIDEO_SOURCE_DEFAULT) {
91 mVideoSource = VIDEO_SOURCE_CAMERA;
92 } else {
93 mVideoSource = vs;
94 }
Andreas Huberea6a38c2009-11-16 15:43:38 -080095
96 return OK;
97}
98
99status_t StagefrightRecorder::setOutputFormat(output_format of) {
James Dongc0ab2a62010-06-29 16:29:19 -0700100 LOGV("setOutputFormat: %d", of);
101 if (of < OUTPUT_FORMAT_DEFAULT ||
102 of >= OUTPUT_FORMAT_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700103 LOGE("Invalid output format: %d", of);
James Dongc0ab2a62010-06-29 16:29:19 -0700104 return BAD_VALUE;
105 }
106
107 if (of == OUTPUT_FORMAT_DEFAULT) {
108 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
109 } else {
110 mOutputFormat = of;
111 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800112
113 return OK;
114}
115
116status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
James Dongc0ab2a62010-06-29 16:29:19 -0700117 LOGV("setAudioEncoder: %d", ae);
118 if (ae < AUDIO_ENCODER_DEFAULT ||
119 ae >= AUDIO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700120 LOGE("Invalid audio encoder: %d", ae);
James Dongc0ab2a62010-06-29 16:29:19 -0700121 return BAD_VALUE;
122 }
123
124 if (ae == AUDIO_ENCODER_DEFAULT) {
125 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
126 } else {
127 mAudioEncoder = ae;
128 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800129
130 return OK;
131}
132
133status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
James Dongc0ab2a62010-06-29 16:29:19 -0700134 LOGV("setVideoEncoder: %d", ve);
135 if (ve < VIDEO_ENCODER_DEFAULT ||
136 ve >= VIDEO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700137 LOGE("Invalid video encoder: %d", ve);
James Dongc0ab2a62010-06-29 16:29:19 -0700138 return BAD_VALUE;
139 }
140
141 if (ve == VIDEO_ENCODER_DEFAULT) {
142 mVideoEncoder = VIDEO_ENCODER_H263;
143 } else {
144 mVideoEncoder = ve;
145 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800146
147 return OK;
148}
149
150status_t StagefrightRecorder::setVideoSize(int width, int height) {
James Dongc0ab2a62010-06-29 16:29:19 -0700151 LOGV("setVideoSize: %dx%d", width, height);
James Dong2cd841d2010-05-11 11:46:59 -0700152 if (width <= 0 || height <= 0) {
153 LOGE("Invalid video size: %dx%d", width, height);
154 return BAD_VALUE;
155 }
156
157 // Additional check on the dimension will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800158 mVideoWidth = width;
159 mVideoHeight = height;
160
161 return OK;
162}
163
164status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
James Dongc0ab2a62010-06-29 16:29:19 -0700165 LOGV("setVideoFrameRate: %d", frames_per_second);
James Dong2cd841d2010-05-11 11:46:59 -0700166 if (frames_per_second <= 0 || frames_per_second > 30) {
167 LOGE("Invalid video frame rate: %d", frames_per_second);
168 return BAD_VALUE;
169 }
170
171 // Additional check on the frame rate will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800172 mFrameRate = frames_per_second;
173
174 return OK;
175}
176
177status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
James Dong71d714c2010-06-09 15:57:48 -0700178 LOGV("setCamera");
James Dongb00e2462010-04-26 17:48:26 -0700179 if (camera == 0) {
180 LOGE("camera is NULL");
James Dong7b06de62010-06-30 12:41:16 -0700181 return BAD_VALUE;
James Dongb00e2462010-04-26 17:48:26 -0700182 }
183
James Dong71d714c2010-06-09 15:57:48 -0700184 int64_t token = IPCThreadState::self()->clearCallingIdentity();
185 mFlags &= ~FLAGS_HOT_CAMERA;
James Dongb00e2462010-04-26 17:48:26 -0700186 mCamera = Camera::create(camera);
187 if (mCamera == 0) {
188 LOGE("Unable to connect to camera");
James Dong71d714c2010-06-09 15:57:48 -0700189 IPCThreadState::self()->restoreCallingIdentity(token);
James Dong7b06de62010-06-30 12:41:16 -0700190 return -EBUSY;
James Dongb00e2462010-04-26 17:48:26 -0700191 }
192
193 LOGV("Connected to camera");
James Dongb00e2462010-04-26 17:48:26 -0700194 if (mCamera->previewEnabled()) {
195 LOGV("camera is hot");
196 mFlags |= FLAGS_HOT_CAMERA;
197 }
James Dong71d714c2010-06-09 15:57:48 -0700198 IPCThreadState::self()->restoreCallingIdentity(token);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800199
200 return OK;
201}
202
203status_t StagefrightRecorder::setPreviewSurface(const sp<ISurface> &surface) {
James Dongc0ab2a62010-06-29 16:29:19 -0700204 LOGV("setPreviewSurface: %p", surface.get());
Andreas Huberea6a38c2009-11-16 15:43:38 -0800205 mPreviewSurface = surface;
206
207 return OK;
208}
209
210status_t StagefrightRecorder::setOutputFile(const char *path) {
James Dong7b06de62010-06-30 12:41:16 -0700211 LOGE("setOutputFile(const char*) must not be called");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800212 // We don't actually support this at all, as the media_server process
213 // no longer has permissions to create files.
214
James Dong7b06de62010-06-30 12:41:16 -0700215 return -EPERM;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800216}
217
218status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
James Dongc0ab2a62010-06-29 16:29:19 -0700219 LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800220 // These don't make any sense, do they?
221 CHECK_EQ(offset, 0);
222 CHECK_EQ(length, 0);
223
James Dong7b06de62010-06-30 12:41:16 -0700224 if (fd < 0) {
225 LOGE("Invalid file descriptor: %d", fd);
226 return -EBADF;
227 }
228
Andreas Huberea6a38c2009-11-16 15:43:38 -0800229 if (mOutputFd >= 0) {
230 ::close(mOutputFd);
231 }
232 mOutputFd = dup(fd);
233
234 return OK;
235}
236
James Dongabed93a2010-04-22 17:27:04 -0700237// Attempt to parse an int64 literal optionally surrounded by whitespace,
238// returns true on success, false otherwise.
James Dong2cd841d2010-05-11 11:46:59 -0700239static bool safe_strtoi64(const char *s, int64_t *val) {
James Dongabed93a2010-04-22 17:27:04 -0700240 char *end;
James Dong2cd841d2010-05-11 11:46:59 -0700241 *val = strtoll(s, &end, 10);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800242
James Dongabed93a2010-04-22 17:27:04 -0700243 if (end == s || errno == ERANGE) {
244 return false;
245 }
246
247 // Skip trailing whitespace
248 while (isspace(*end)) {
249 ++end;
250 }
251
252 // For a successful return, the string must contain nothing but a valid
253 // int64 literal optionally surrounded by whitespace.
254
255 return *end == '\0';
256}
257
James Dong2cd841d2010-05-11 11:46:59 -0700258// Return true if the value is in [0, 0x007FFFFFFF]
259static bool safe_strtoi32(const char *s, int32_t *val) {
260 int64_t temp;
261 if (safe_strtoi64(s, &temp)) {
262 if (temp >= 0 && temp <= 0x007FFFFFFF) {
263 *val = static_cast<int32_t>(temp);
264 return true;
265 }
266 }
267 return false;
268}
269
James Dongabed93a2010-04-22 17:27:04 -0700270// Trim both leading and trailing whitespace from the given string.
271static void TrimString(String8 *s) {
272 size_t num_bytes = s->bytes();
273 const char *data = s->string();
274
275 size_t leading_space = 0;
276 while (leading_space < num_bytes && isspace(data[leading_space])) {
277 ++leading_space;
278 }
279
280 size_t i = num_bytes;
281 while (i > leading_space && isspace(data[i - 1])) {
282 --i;
283 }
284
285 s->setTo(String8(&data[leading_space], i - leading_space));
286}
287
288status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
289 LOGV("setParamAudioSamplingRate: %d", sampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700290 if (sampleRate <= 0) {
291 LOGE("Invalid audio sampling rate: %d", sampleRate);
292 return BAD_VALUE;
293 }
294
295 // Additional check on the sample rate will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700296 mSampleRate = sampleRate;
297 return OK;
298}
299
300status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
301 LOGV("setParamAudioNumberOfChannels: %d", channels);
James Dong2cd841d2010-05-11 11:46:59 -0700302 if (channels <= 0 || channels >= 3) {
303 LOGE("Invalid number of audio channels: %d", channels);
James Dong7b06de62010-06-30 12:41:16 -0700304 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700305 }
306
307 // Additional check on the number of channels will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700308 mAudioChannels = channels;
309 return OK;
310}
311
312status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
313 LOGV("setParamAudioEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700314 if (bitRate <= 0) {
315 LOGE("Invalid audio encoding bit rate: %d", bitRate);
316 return BAD_VALUE;
317 }
318
319 // The target bit rate may not be exactly the same as the requested.
320 // It depends on many factors, such as rate control, and the bit rate
321 // range that a specific encoder supports. The mismatch between the
322 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700323 mAudioBitRate = bitRate;
324 return OK;
325}
326
327status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
328 LOGV("setParamVideoEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700329 if (bitRate <= 0) {
330 LOGE("Invalid video encoding bit rate: %d", bitRate);
331 return BAD_VALUE;
332 }
333
334 // The target bit rate may not be exactly the same as the requested.
335 // It depends on many factors, such as rate control, and the bit rate
336 // range that a specific encoder supports. The mismatch between the
337 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700338 mVideoBitRate = bitRate;
339 return OK;
340}
341
James Dong7b06de62010-06-30 12:41:16 -0700342status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
343 LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
Nipun Kwatrafb457482010-08-18 15:19:19 -0700344 if (timeUs <= 0) {
345 LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
346 timeUs = 0; // Disable the duration limit for zero or negative values.
347 } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
James Dong7b06de62010-06-30 12:41:16 -0700348 LOGE("Max file duration is too short: %lld us", timeUs);
349 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700350 }
Nipun Kwatrafb457482010-08-18 15:19:19 -0700351
James Dong7b06de62010-06-30 12:41:16 -0700352 mMaxFileDurationUs = timeUs;
353 return OK;
354}
355
356status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
357 LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
358 if (bytes <= 1024) { // XXX: 1 kB
359 LOGE("Max file size is too small: %lld bytes", bytes);
360 return BAD_VALUE;
361 }
362 mMaxFileSizeBytes = bytes;
James Dongabed93a2010-04-22 17:27:04 -0700363 return OK;
364}
365
James Dong3300e962010-04-21 16:14:15 -0700366status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
367 LOGV("setParamInterleaveDuration: %d", durationUs);
James Dong1244eab2010-06-08 11:58:53 -0700368 if (durationUs <= 500000) { // 500 ms
369 // If interleave duration is too small, it is very inefficient to do
370 // interleaving since the metadata overhead will count for a significant
371 // portion of the saved contents
James Dong2cd841d2010-05-11 11:46:59 -0700372 LOGE("Audio/video interleave duration is too small: %d us", durationUs);
373 return BAD_VALUE;
James Dong1244eab2010-06-08 11:58:53 -0700374 } else if (durationUs >= 10000000) { // 10 seconds
375 // If interleaving duration is too large, it can cause the recording
376 // session to use too much memory since we have to save the output
377 // data before we write them out
378 LOGE("Audio/video interleave duration is too large: %d us", durationUs);
379 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700380 }
James Dong3300e962010-04-21 16:14:15 -0700381 mInterleaveDurationUs = durationUs;
382 return OK;
383}
James Dong2cd841d2010-05-11 11:46:59 -0700384
James Dong52d13f02010-07-02 11:39:06 -0700385// If seconds < 0, only the first frame is I frame, and rest are all P frames
386// If seconds == 0, all frames are encoded as I frames. No P frames
387// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames
388status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
389 LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
390 mIFramesIntervalSec = seconds;
James Dong1244eab2010-06-08 11:58:53 -0700391 return OK;
392}
393
James Dong6feaa462010-06-20 08:20:54 -0700394status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
395 LOGV("setParam64BitFileOffset: %s",
396 use64Bit? "use 64 bit file offset": "use 32 bit file offset");
397 mUse64BitFileOffset = use64Bit;
398 return OK;
399}
400
James Dong09936ed2010-06-24 19:04:27 -0700401status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
402 LOGV("setParamVideoCameraId: %d", cameraId);
403 if (cameraId < 0) {
404 return BAD_VALUE;
405 }
406 mCameraId = cameraId;
407 return OK;
408}
409
James Dong09936ed2010-06-24 19:04:27 -0700410status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
411 LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
412 if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
James Dong7b06de62010-06-30 12:41:16 -0700413 LOGE("Tracking time duration too short: %lld us", timeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -0700414 return BAD_VALUE;
415 }
416 mTrackEveryTimeDurationUs = timeDurationUs;
417 return OK;
418}
419
James Dong81c929a2010-07-01 15:02:14 -0700420status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
421 LOGV("setParamVideoEncoderProfile: %d", profile);
422
423 // Additional check will be done later when we load the encoder.
424 // For now, we are accepting values defined in OpenMAX IL.
425 mVideoEncoderProfile = profile;
426 return OK;
427}
428
429status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
430 LOGV("setParamVideoEncoderLevel: %d", level);
431
432 // Additional check will be done later when we load the encoder.
433 // For now, we are accepting values defined in OpenMAX IL.
434 mVideoEncoderLevel = level;
435 return OK;
436}
437
James Dong52d13f02010-07-02 11:39:06 -0700438status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
439 LOGV("setParamMovieTimeScale: %d", timeScale);
440
441 // The range is set to be the same as the audio's time scale range
442 // since audio's time scale has a wider range.
443 if (timeScale < 600 || timeScale > 96000) {
444 LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
445 return BAD_VALUE;
446 }
447 mMovieTimeScale = timeScale;
448 return OK;
449}
450
451status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
452 LOGV("setParamVideoTimeScale: %d", timeScale);
453
454 // 60000 is chosen to make sure that each video frame from a 60-fps
455 // video has 1000 ticks.
456 if (timeScale < 600 || timeScale > 60000) {
457 LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
458 return BAD_VALUE;
459 }
460 mVideoTimeScale = timeScale;
461 return OK;
462}
463
464status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
465 LOGV("setParamAudioTimeScale: %d", timeScale);
466
467 // 96000 Hz is the highest sampling rate support in AAC.
468 if (timeScale < 600 || timeScale > 96000) {
469 LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
470 return BAD_VALUE;
471 }
472 mAudioTimeScale = timeScale;
473 return OK;
474}
475
James Dongabed93a2010-04-22 17:27:04 -0700476status_t StagefrightRecorder::setParameter(
477 const String8 &key, const String8 &value) {
478 LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
479 if (key == "max-duration") {
James Dong2cd841d2010-05-11 11:46:59 -0700480 int64_t max_duration_ms;
James Dongabed93a2010-04-22 17:27:04 -0700481 if (safe_strtoi64(value.string(), &max_duration_ms)) {
James Dong7b06de62010-06-30 12:41:16 -0700482 return setParamMaxFileDurationUs(1000LL * max_duration_ms);
James Dongabed93a2010-04-22 17:27:04 -0700483 }
484 } else if (key == "max-filesize") {
James Dong2cd841d2010-05-11 11:46:59 -0700485 int64_t max_filesize_bytes;
James Dongabed93a2010-04-22 17:27:04 -0700486 if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
James Dong7b06de62010-06-30 12:41:16 -0700487 return setParamMaxFileSizeBytes(max_filesize_bytes);
James Dongabed93a2010-04-22 17:27:04 -0700488 }
James Dong09936ed2010-06-24 19:04:27 -0700489 } else if (key == "interleave-duration-us") {
490 int32_t durationUs;
491 if (safe_strtoi32(value.string(), &durationUs)) {
492 return setParamInterleaveDuration(durationUs);
493 }
James Dong52d13f02010-07-02 11:39:06 -0700494 } else if (key == "param-movie-time-scale") {
495 int32_t timeScale;
496 if (safe_strtoi32(value.string(), &timeScale)) {
497 return setParamMovieTimeScale(timeScale);
498 }
James Dong09936ed2010-06-24 19:04:27 -0700499 } else if (key == "param-use-64bit-offset") {
500 int32_t use64BitOffset;
501 if (safe_strtoi32(value.string(), &use64BitOffset)) {
502 return setParam64BitFileOffset(use64BitOffset != 0);
503 }
James Dong09936ed2010-06-24 19:04:27 -0700504 } else if (key == "param-track-time-status") {
505 int64_t timeDurationUs;
506 if (safe_strtoi64(value.string(), &timeDurationUs)) {
507 return setParamTrackTimeStatus(timeDurationUs);
508 }
James Dongabed93a2010-04-22 17:27:04 -0700509 } else if (key == "audio-param-sampling-rate") {
510 int32_t sampling_rate;
James Dong2cd841d2010-05-11 11:46:59 -0700511 if (safe_strtoi32(value.string(), &sampling_rate)) {
James Dongabed93a2010-04-22 17:27:04 -0700512 return setParamAudioSamplingRate(sampling_rate);
513 }
514 } else if (key == "audio-param-number-of-channels") {
515 int32_t number_of_channels;
James Dong2cd841d2010-05-11 11:46:59 -0700516 if (safe_strtoi32(value.string(), &number_of_channels)) {
James Dongabed93a2010-04-22 17:27:04 -0700517 return setParamAudioNumberOfChannels(number_of_channels);
518 }
519 } else if (key == "audio-param-encoding-bitrate") {
520 int32_t audio_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700521 if (safe_strtoi32(value.string(), &audio_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700522 return setParamAudioEncodingBitRate(audio_bitrate);
523 }
James Dong52d13f02010-07-02 11:39:06 -0700524 } else if (key == "audio-param-time-scale") {
525 int32_t timeScale;
526 if (safe_strtoi32(value.string(), &timeScale)) {
527 return setParamAudioTimeScale(timeScale);
528 }
James Dongabed93a2010-04-22 17:27:04 -0700529 } else if (key == "video-param-encoding-bitrate") {
530 int32_t video_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700531 if (safe_strtoi32(value.string(), &video_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700532 return setParamVideoEncodingBitRate(video_bitrate);
533 }
James Dong09936ed2010-06-24 19:04:27 -0700534 } else if (key == "video-param-i-frames-interval") {
James Dong52d13f02010-07-02 11:39:06 -0700535 int32_t seconds;
536 if (safe_strtoi32(value.string(), &seconds)) {
537 return setParamVideoIFramesInterval(seconds);
James Dong1244eab2010-06-08 11:58:53 -0700538 }
James Dong81c929a2010-07-01 15:02:14 -0700539 } else if (key == "video-param-encoder-profile") {
540 int32_t profile;
541 if (safe_strtoi32(value.string(), &profile)) {
542 return setParamVideoEncoderProfile(profile);
543 }
544 } else if (key == "video-param-encoder-level") {
545 int32_t level;
546 if (safe_strtoi32(value.string(), &level)) {
547 return setParamVideoEncoderLevel(level);
548 }
James Dong09936ed2010-06-24 19:04:27 -0700549 } else if (key == "video-param-camera-id") {
550 int32_t cameraId;
551 if (safe_strtoi32(value.string(), &cameraId)) {
552 return setParamVideoCameraId(cameraId);
James Dong6feaa462010-06-20 08:20:54 -0700553 }
James Dong52d13f02010-07-02 11:39:06 -0700554 } else if (key == "video-param-time-scale") {
555 int32_t timeScale;
556 if (safe_strtoi32(value.string(), &timeScale)) {
557 return setParamVideoTimeScale(timeScale);
558 }
James Dongabed93a2010-04-22 17:27:04 -0700559 } else {
560 LOGE("setParameter: failed to find key %s", key.string());
James Dongabed93a2010-04-22 17:27:04 -0700561 }
James Dong2cd841d2010-05-11 11:46:59 -0700562 return BAD_VALUE;
James Dongabed93a2010-04-22 17:27:04 -0700563}
564
565status_t StagefrightRecorder::setParameters(const String8 &params) {
566 LOGV("setParameters: %s", params.string());
567 const char *cparams = params.string();
568 const char *key_start = cparams;
569 for (;;) {
570 const char *equal_pos = strchr(key_start, '=');
571 if (equal_pos == NULL) {
572 LOGE("Parameters %s miss a value", cparams);
573 return BAD_VALUE;
574 }
575 String8 key(key_start, equal_pos - key_start);
576 TrimString(&key);
577 if (key.length() == 0) {
578 LOGE("Parameters %s contains an empty key", cparams);
579 return BAD_VALUE;
580 }
581 const char *value_start = equal_pos + 1;
582 const char *semicolon_pos = strchr(value_start, ';');
583 String8 value;
584 if (semicolon_pos == NULL) {
585 value.setTo(value_start);
586 } else {
587 value.setTo(value_start, semicolon_pos - value_start);
588 }
589 if (setParameter(key, value) != OK) {
590 return BAD_VALUE;
591 }
592 if (semicolon_pos == NULL) {
593 break; // Reaches the end
594 }
595 key_start = semicolon_pos + 1;
596 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800597 return OK;
598}
599
James Dongfe1bafe2010-06-25 17:06:47 -0700600status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
Andreas Huberea6a38c2009-11-16 15:43:38 -0800601 mListener = listener;
602
603 return OK;
604}
605
606status_t StagefrightRecorder::prepare() {
607 return OK;
608}
609
610status_t StagefrightRecorder::start() {
James Dong7b06de62010-06-30 12:41:16 -0700611 CHECK(mOutputFd >= 0);
612
Andreas Huberea6a38c2009-11-16 15:43:38 -0800613 if (mWriter != NULL) {
James Dong7b06de62010-06-30 12:41:16 -0700614 LOGE("File writer is not avaialble");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800615 return UNKNOWN_ERROR;
616 }
617
Andreas Huber996dddf2010-01-25 15:30:31 -0800618 switch (mOutputFormat) {
619 case OUTPUT_FORMAT_DEFAULT:
620 case OUTPUT_FORMAT_THREE_GPP:
621 case OUTPUT_FORMAT_MPEG_4:
622 return startMPEG4Recording();
623
624 case OUTPUT_FORMAT_AMR_NB:
625 case OUTPUT_FORMAT_AMR_WB:
626 return startAMRRecording();
627
James Dong2cd841d2010-05-11 11:46:59 -0700628 case OUTPUT_FORMAT_AAC_ADIF:
629 case OUTPUT_FORMAT_AAC_ADTS:
630 return startAACRecording();
631
Andreas Huber57648e42010-08-04 10:14:30 -0700632 case OUTPUT_FORMAT_RTP_AVP:
633 return startRTPRecording();
634
Andreas Huber996dddf2010-01-25 15:30:31 -0800635 default:
James Dong7b06de62010-06-30 12:41:16 -0700636 LOGE("Unsupported output file format: %d", mOutputFormat);
Andreas Huber996dddf2010-01-25 15:30:31 -0800637 return UNKNOWN_ERROR;
638 }
639}
640
James Dongabed93a2010-04-22 17:27:04 -0700641sp<MediaSource> StagefrightRecorder::createAudioSource() {
Andreas Huber996dddf2010-01-25 15:30:31 -0800642 sp<AudioSource> audioSource =
643 new AudioSource(
644 mAudioSource,
James Dongabed93a2010-04-22 17:27:04 -0700645 mSampleRate,
James Dongd77d2a92010-06-14 17:45:35 -0700646 mAudioChannels);
Andreas Huber996dddf2010-01-25 15:30:31 -0800647
648 status_t err = audioSource->initCheck();
649
650 if (err != OK) {
James Dongabed93a2010-04-22 17:27:04 -0700651 LOGE("audio source is not initialized");
Andreas Huber996dddf2010-01-25 15:30:31 -0800652 return NULL;
653 }
654
655 sp<MetaData> encMeta = new MetaData;
James Dongabed93a2010-04-22 17:27:04 -0700656 const char *mime;
657 switch (mAudioEncoder) {
658 case AUDIO_ENCODER_AMR_NB:
659 case AUDIO_ENCODER_DEFAULT:
660 mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
661 break;
662 case AUDIO_ENCODER_AMR_WB:
663 mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
664 break;
665 case AUDIO_ENCODER_AAC:
666 mime = MEDIA_MIMETYPE_AUDIO_AAC;
667 break;
668 default:
669 LOGE("Unknown audio encoder: %d", mAudioEncoder);
670 return NULL;
671 }
672 encMeta->setCString(kKeyMIMEType, mime);
Andreas Huber996dddf2010-01-25 15:30:31 -0800673
Andreas Huber259b7c12010-02-10 15:04:31 -0800674 int32_t maxInputSize;
675 CHECK(audioSource->getFormat()->findInt32(
676 kKeyMaxInputSize, &maxInputSize));
677
678 encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
James Dongabed93a2010-04-22 17:27:04 -0700679 encMeta->setInt32(kKeyChannelCount, mAudioChannels);
680 encMeta->setInt32(kKeySampleRate, mSampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700681 encMeta->setInt32(kKeyBitRate, mAudioBitRate);
James Dongeff30e32010-08-13 14:16:26 -0700682 if (mAudioTimeScale > 0) {
683 encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
684 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800685
686 OMXClient client;
687 CHECK_EQ(client.connect(), OK);
688
689 sp<MediaSource> audioEncoder =
690 OMXCodec::Create(client.interface(), encMeta,
691 true /* createEncoder */, audioSource);
James Dong57e7f832010-06-24 19:55:31 -0700692 mAudioSourceNode = audioSource;
Andreas Huber996dddf2010-01-25 15:30:31 -0800693
694 return audioEncoder;
695}
696
James Dong2cd841d2010-05-11 11:46:59 -0700697status_t StagefrightRecorder::startAACRecording() {
698 CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
699 mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
700
701 CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
702 CHECK(mAudioSource != AUDIO_SOURCE_LIST_END);
James Dong2cd841d2010-05-11 11:46:59 -0700703
704 CHECK(0 == "AACWriter is not implemented yet");
705
706 return OK;
707}
708
Andreas Huber996dddf2010-01-25 15:30:31 -0800709status_t StagefrightRecorder::startAMRRecording() {
James Dong2cd841d2010-05-11 11:46:59 -0700710 CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
711 mOutputFormat == OUTPUT_FORMAT_AMR_WB);
712
713 if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
714 if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
715 mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
716 LOGE("Invalid encoder %d used for AMRNB recording",
717 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700718 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700719 }
720 if (mSampleRate != 8000) {
721 LOGE("Invalid sampling rate %d used for AMRNB recording",
722 mSampleRate);
James Dong7b06de62010-06-30 12:41:16 -0700723 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700724 }
725 } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
726 if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
727 LOGE("Invlaid encoder %d used for AMRWB recording",
728 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700729 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700730 }
731 if (mSampleRate != 16000) {
732 LOGE("Invalid sample rate %d used for AMRWB recording",
733 mSampleRate);
James Dong7b06de62010-06-30 12:41:16 -0700734 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700735 }
736 }
737 if (mAudioChannels != 1) {
738 LOGE("Invalid number of audio channels %d used for amr recording",
739 mAudioChannels);
James Dong7b06de62010-06-30 12:41:16 -0700740 return BAD_VALUE;
Andreas Huber996dddf2010-01-25 15:30:31 -0800741 }
742
James Dong2cd841d2010-05-11 11:46:59 -0700743 if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
744 LOGE("Invalid audio source: %d", mAudioSource);
James Dong7b06de62010-06-30 12:41:16 -0700745 return BAD_VALUE;
Andreas Huber996dddf2010-01-25 15:30:31 -0800746 }
747
James Dongabed93a2010-04-22 17:27:04 -0700748 sp<MediaSource> audioEncoder = createAudioSource();
Andreas Huber996dddf2010-01-25 15:30:31 -0800749
750 if (audioEncoder == NULL) {
751 return UNKNOWN_ERROR;
752 }
753
Andreas Huber996dddf2010-01-25 15:30:31 -0800754 mWriter = new AMRWriter(dup(mOutputFd));
755 mWriter->addSource(audioEncoder);
James Dong18244862010-05-11 14:57:02 -0700756
757 if (mMaxFileDurationUs != 0) {
758 mWriter->setMaxFileDuration(mMaxFileDurationUs);
759 }
760 if (mMaxFileSizeBytes != 0) {
761 mWriter->setMaxFileSize(mMaxFileSizeBytes);
762 }
763 mWriter->setListener(mListener);
Andreas Huber996dddf2010-01-25 15:30:31 -0800764 mWriter->start();
765
766 return OK;
767}
768
Andreas Huber57648e42010-08-04 10:14:30 -0700769status_t StagefrightRecorder::startRTPRecording() {
770 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
771
772 if ((mAudioSource != AUDIO_SOURCE_LIST_END
773 && mVideoSource != VIDEO_SOURCE_LIST_END)
774 || (mAudioSource == AUDIO_SOURCE_LIST_END
775 && mVideoSource == VIDEO_SOURCE_LIST_END)) {
776 // Must have exactly one source.
777 return BAD_VALUE;
778 }
779
780 if (mOutputFd < 0) {
781 return BAD_VALUE;
782 }
783
784 sp<MediaSource> source;
785
786 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
787 source = createAudioSource();
788 } else {
789 status_t err = setupVideoEncoder(&source);
790 if (err != OK) {
791 return err;
792 }
793 }
794
795 mWriter = new ARTPWriter(dup(mOutputFd));
796 mWriter->addSource(source);
797 mWriter->setListener(mListener);
798
799 return mWriter->start();
800}
801
James Dong42a18c02010-06-16 17:27:46 -0700802void StagefrightRecorder::clipVideoFrameRate() {
803 LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
804 int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
805 "enc.vid.fps.min", mVideoEncoder);
806 int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
807 "enc.vid.fps.max", mVideoEncoder);
808 if (mFrameRate < minFrameRate) {
809 LOGW("Intended video encoding frame rate (%d fps) is too small"
810 " and will be set to (%d fps)", mFrameRate, minFrameRate);
811 mFrameRate = minFrameRate;
812 } else if (mFrameRate > maxFrameRate) {
813 LOGW("Intended video encoding frame rate (%d fps) is too large"
814 " and will be set to (%d fps)", mFrameRate, maxFrameRate);
815 mFrameRate = maxFrameRate;
816 }
817}
818
819void StagefrightRecorder::clipVideoBitRate() {
820 LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
821 int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
822 "enc.vid.bps.min", mVideoEncoder);
823 int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
824 "enc.vid.bps.max", mVideoEncoder);
825 if (mVideoBitRate < minBitRate) {
826 LOGW("Intended video encoding bit rate (%d bps) is too small"
827 " and will be set to (%d bps)", mVideoBitRate, minBitRate);
828 mVideoBitRate = minBitRate;
829 } else if (mVideoBitRate > maxBitRate) {
830 LOGW("Intended video encoding bit rate (%d bps) is too large"
831 " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
832 mVideoBitRate = maxBitRate;
833 }
834}
835
836void StagefrightRecorder::clipVideoFrameWidth() {
837 LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
838 int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
839 "enc.vid.width.min", mVideoEncoder);
840 int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
841 "enc.vid.width.max", mVideoEncoder);
842 if (mVideoWidth < minFrameWidth) {
843 LOGW("Intended video encoding frame width (%d) is too small"
844 " and will be set to (%d)", mVideoWidth, minFrameWidth);
845 mVideoWidth = minFrameWidth;
846 } else if (mVideoWidth > maxFrameWidth) {
847 LOGW("Intended video encoding frame width (%d) is too large"
848 " and will be set to (%d)", mVideoWidth, maxFrameWidth);
849 mVideoWidth = maxFrameWidth;
850 }
851}
852
James Dong7b06de62010-06-30 12:41:16 -0700853status_t StagefrightRecorder::setupCameraSource() {
854 clipVideoBitRate();
855 clipVideoFrameRate();
856 clipVideoFrameWidth();
857 clipVideoFrameHeight();
858
859 int64_t token = IPCThreadState::self()->clearCallingIdentity();
860 if (mCamera == 0) {
861 mCamera = Camera::connect(mCameraId);
862 if (mCamera == 0) {
863 LOGE("Camera connection could not be established.");
864 return -EBUSY;
865 }
866 mFlags &= ~FLAGS_HOT_CAMERA;
867 mCamera->lock();
868 }
869
870 // Set the actual video recording frame size
871 CameraParameters params(mCamera->getParameters());
872 params.setPreviewSize(mVideoWidth, mVideoHeight);
873 params.setPreviewFrameRate(mFrameRate);
874 String8 s = params.flatten();
James Dongaf3f29e2010-08-03 15:29:20 -0700875 if (OK != mCamera->setParameters(s)) {
876 LOGE("Could not change settings."
877 " Someone else is using camera %d?", mCameraId);
878 return -EBUSY;
879 }
James Dong7b06de62010-06-30 12:41:16 -0700880 CameraParameters newCameraParams(mCamera->getParameters());
881
882 // Check on video frame size
883 int frameWidth = 0, frameHeight = 0;
884 newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
885 if (frameWidth < 0 || frameWidth != mVideoWidth ||
886 frameHeight < 0 || frameHeight != mVideoHeight) {
887 LOGE("Failed to set the video frame size to %dx%d",
888 mVideoWidth, mVideoHeight);
889 IPCThreadState::self()->restoreCallingIdentity(token);
890 return UNKNOWN_ERROR;
891 }
892
893 // Check on video frame rate
894 int frameRate = newCameraParams.getPreviewFrameRate();
895 if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
896 LOGE("Failed to set frame rate to %d fps. The actual "
897 "frame rate is %d", mFrameRate, frameRate);
898 }
899
James Dongaf3f29e2010-08-03 15:29:20 -0700900 // This CHECK is good, since we just passed the lock/unlock
901 // check earlier by calling mCamera->setParameters().
James Dong7b06de62010-06-30 12:41:16 -0700902 CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
903 IPCThreadState::self()->restoreCallingIdentity(token);
904 return OK;
905}
906
James Dong42a18c02010-06-16 17:27:46 -0700907void StagefrightRecorder::clipVideoFrameHeight() {
908 LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
909 int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
910 "enc.vid.height.min", mVideoEncoder);
911 int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
912 "enc.vid.height.max", mVideoEncoder);
913 if (mVideoHeight < minFrameHeight) {
914 LOGW("Intended video encoding frame height (%d) is too small"
915 " and will be set to (%d)", mVideoHeight, minFrameHeight);
916 mVideoHeight = minFrameHeight;
917 } else if (mVideoHeight > maxFrameHeight) {
918 LOGW("Intended video encoding frame height (%d) is too large"
919 " and will be set to (%d)", mVideoHeight, maxFrameHeight);
920 mVideoHeight = maxFrameHeight;
921 }
922}
923
Andreas Huber57648e42010-08-04 10:14:30 -0700924status_t StagefrightRecorder::setupVideoEncoder(sp<MediaSource> *source) {
925 source->clear();
926
James Dong7b06de62010-06-30 12:41:16 -0700927 status_t err = setupCameraSource();
928 if (err != OK) return err;
929
930 sp<CameraSource> cameraSource = CameraSource::CreateFromCamera(mCamera);
931 CHECK(cameraSource != NULL);
932
933 sp<MetaData> enc_meta = new MetaData;
934 enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
935 enc_meta->setInt32(kKeySampleRate, mFrameRate);
936
937 switch (mVideoEncoder) {
938 case VIDEO_ENCODER_H263:
939 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
940 break;
941
942 case VIDEO_ENCODER_MPEG_4_SP:
943 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
944 break;
945
946 case VIDEO_ENCODER_H264:
947 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
948 break;
949
950 default:
951 CHECK(!"Should not be here, unsupported video encoding.");
952 break;
953 }
954
955 sp<MetaData> meta = cameraSource->getFormat();
956
James Dong1cc31e62010-07-02 17:44:44 -0700957 int32_t width, height, stride, sliceHeight, colorFormat;
James Dong7b06de62010-06-30 12:41:16 -0700958 CHECK(meta->findInt32(kKeyWidth, &width));
959 CHECK(meta->findInt32(kKeyHeight, &height));
960 CHECK(meta->findInt32(kKeyStride, &stride));
961 CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
James Dong1cc31e62010-07-02 17:44:44 -0700962 CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
James Dong7b06de62010-06-30 12:41:16 -0700963
964 enc_meta->setInt32(kKeyWidth, width);
965 enc_meta->setInt32(kKeyHeight, height);
James Dong52d13f02010-07-02 11:39:06 -0700966 enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
James Dong7b06de62010-06-30 12:41:16 -0700967 enc_meta->setInt32(kKeyStride, stride);
968 enc_meta->setInt32(kKeySliceHeight, sliceHeight);
James Dong1cc31e62010-07-02 17:44:44 -0700969 enc_meta->setInt32(kKeyColorFormat, colorFormat);
James Dongeff30e32010-08-13 14:16:26 -0700970 if (mVideoTimeScale > 0) {
971 enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
972 }
James Dong81c929a2010-07-01 15:02:14 -0700973 if (mVideoEncoderProfile != -1) {
974 enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
975 }
976 if (mVideoEncoderLevel != -1) {
977 enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
978 }
James Dong7b06de62010-06-30 12:41:16 -0700979
980 OMXClient client;
981 CHECK_EQ(client.connect(), OK);
982
983 sp<MediaSource> encoder = OMXCodec::Create(
984 client.interface(), enc_meta,
985 true /* createEncoder */, cameraSource);
986 if (encoder == NULL) {
987 return UNKNOWN_ERROR;
988 }
989
Andreas Huber57648e42010-08-04 10:14:30 -0700990 *source = encoder;
991
James Dong7b06de62010-06-30 12:41:16 -0700992 return OK;
993}
994
995status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
996 sp<MediaSource> audioEncoder;
997 switch(mAudioEncoder) {
998 case AUDIO_ENCODER_AMR_NB:
999 case AUDIO_ENCODER_AMR_WB:
1000 case AUDIO_ENCODER_AAC:
1001 audioEncoder = createAudioSource();
1002 break;
1003 default:
1004 LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1005 return UNKNOWN_ERROR;
1006 }
1007
1008 if (audioEncoder == NULL) {
1009 return UNKNOWN_ERROR;
1010 }
James Dong52d13f02010-07-02 11:39:06 -07001011
James Dong7b06de62010-06-30 12:41:16 -07001012 writer->addSource(audioEncoder);
1013 return OK;
1014}
1015
Andreas Huber996dddf2010-01-25 15:30:31 -08001016status_t StagefrightRecorder::startMPEG4Recording() {
James Dong6feaa462010-06-20 08:20:54 -07001017 int32_t totalBitRate = 0;
James Dong7b06de62010-06-30 12:41:16 -07001018 status_t err = OK;
1019 sp<MediaWriter> writer = new MPEG4Writer(dup(mOutputFd));
Andreas Huber996dddf2010-01-25 15:30:31 -08001020
James Dongabed93a2010-04-22 17:27:04 -07001021 // Add audio source first if it exists
1022 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -07001023 err = setupAudioEncoder(writer);
1024 if (err != OK) return err;
James Dong6feaa462010-06-20 08:20:54 -07001025 totalBitRate += mAudioBitRate;
James Dongabed93a2010-04-22 17:27:04 -07001026 }
Andreas Huber996dddf2010-01-25 15:30:31 -08001027 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1028 || mVideoSource == VIDEO_SOURCE_CAMERA) {
Andreas Huber57648e42010-08-04 10:14:30 -07001029 sp<MediaSource> encoder;
1030 err = setupVideoEncoder(&encoder);
James Dong7b06de62010-06-30 12:41:16 -07001031 if (err != OK) return err;
Andreas Huber57648e42010-08-04 10:14:30 -07001032 writer->addSource(encoder);
James Dong6feaa462010-06-20 08:20:54 -07001033 totalBitRate += mVideoBitRate;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001034 }
1035
James Dong63299c02010-07-28 10:08:03 -07001036 if (mInterleaveDurationUs > 0) {
1037 reinterpret_cast<MPEG4Writer *>(writer.get())->
1038 setInterleaveDuration(mInterleaveDurationUs);
1039 }
James Dong2cd841d2010-05-11 11:46:59 -07001040
James Dong18244862010-05-11 14:57:02 -07001041 if (mMaxFileDurationUs != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001042 writer->setMaxFileDuration(mMaxFileDurationUs);
James Dong18244862010-05-11 14:57:02 -07001043 }
1044 if (mMaxFileSizeBytes != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001045 writer->setMaxFileSize(mMaxFileSizeBytes);
James Dong18244862010-05-11 14:57:02 -07001046 }
James Dong6feaa462010-06-20 08:20:54 -07001047 sp<MetaData> meta = new MetaData;
James Dong09936ed2010-06-24 19:04:27 -07001048 meta->setInt64(kKeyTime, systemTime() / 1000);
1049 meta->setInt32(kKeyFileType, mOutputFormat);
James Dong6feaa462010-06-20 08:20:54 -07001050 meta->setInt32(kKeyBitRate, totalBitRate);
1051 meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
James Dongeff30e32010-08-13 14:16:26 -07001052 if (mMovieTimeScale > 0) {
1053 meta->setInt32(kKeyTimeScale, mMovieTimeScale);
1054 }
James Dong09936ed2010-06-24 19:04:27 -07001055 if (mTrackEveryTimeDurationUs > 0) {
1056 meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
1057 }
James Dong7b06de62010-06-30 12:41:16 -07001058 writer->setListener(mListener);
1059 mWriter = writer;
1060 return mWriter->start(meta.get());
Andreas Huberea6a38c2009-11-16 15:43:38 -08001061}
1062
James Dong08c74732010-06-10 12:28:15 -07001063status_t StagefrightRecorder::pause() {
James Dongc0ab2a62010-06-29 16:29:19 -07001064 LOGV("pause");
James Dong08c74732010-06-10 12:28:15 -07001065 if (mWriter == NULL) {
1066 return UNKNOWN_ERROR;
1067 }
1068 mWriter->pause();
1069 return OK;
1070}
1071
Andreas Huberea6a38c2009-11-16 15:43:38 -08001072status_t StagefrightRecorder::stop() {
James Dongc0ab2a62010-06-29 16:29:19 -07001073 LOGV("stop");
James Dongd0366622010-08-18 19:10:39 -07001074 status_t err = OK;
James Dongc0ab2a62010-06-29 16:29:19 -07001075 if (mWriter != NULL) {
James Dongd0366622010-08-18 19:10:39 -07001076 err = mWriter->stop();
James Dong7b06de62010-06-30 12:41:16 -07001077 mWriter.clear();
Andreas Huberea6a38c2009-11-16 15:43:38 -08001078 }
1079
James Dongb00e2462010-04-26 17:48:26 -07001080 if (mCamera != 0) {
James Dongc0ab2a62010-06-29 16:29:19 -07001081 LOGV("Disconnect camera");
James Dong71d714c2010-06-09 15:57:48 -07001082 int64_t token = IPCThreadState::self()->clearCallingIdentity();
James Dongb00e2462010-04-26 17:48:26 -07001083 if ((mFlags & FLAGS_HOT_CAMERA) == 0) {
1084 LOGV("Camera was cold when we started, stopping preview");
1085 mCamera->stopPreview();
1086 }
James Dong71d714c2010-06-09 15:57:48 -07001087 mCamera->unlock();
James Dong7b06de62010-06-30 12:41:16 -07001088 mCamera.clear();
James Dong71d714c2010-06-09 15:57:48 -07001089 IPCThreadState::self()->restoreCallingIdentity(token);
James Dongb00e2462010-04-26 17:48:26 -07001090 mFlags = 0;
1091 }
James Dongc0ab2a62010-06-29 16:29:19 -07001092
James Dongc6280bc2010-08-11 17:12:39 -07001093 if (mOutputFd >= 0) {
1094 ::close(mOutputFd);
1095 mOutputFd = -1;
1096 }
1097
James Dongd0366622010-08-18 19:10:39 -07001098 return err;
James Dongc0ab2a62010-06-29 16:29:19 -07001099}
1100
1101status_t StagefrightRecorder::close() {
1102 LOGV("close");
1103 stop();
1104
Andreas Huberea6a38c2009-11-16 15:43:38 -08001105 return OK;
1106}
1107
1108status_t StagefrightRecorder::reset() {
James Dongc0ab2a62010-06-29 16:29:19 -07001109 LOGV("reset");
Andreas Huberea6a38c2009-11-16 15:43:38 -08001110 stop();
1111
James Dongabed93a2010-04-22 17:27:04 -07001112 // No audio or video source by default
Andreas Huberea6a38c2009-11-16 15:43:38 -08001113 mAudioSource = AUDIO_SOURCE_LIST_END;
1114 mVideoSource = VIDEO_SOURCE_LIST_END;
James Dongabed93a2010-04-22 17:27:04 -07001115
1116 // Default parameters
1117 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
1118 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
1119 mVideoEncoder = VIDEO_ENCODER_H263;
1120 mVideoWidth = 176;
1121 mVideoHeight = 144;
1122 mFrameRate = 20;
1123 mVideoBitRate = 192000;
1124 mSampleRate = 8000;
1125 mAudioChannels = 1;
1126 mAudioBitRate = 12200;
James Dongc6161722010-05-20 17:55:52 -07001127 mInterleaveDurationUs = 0;
James Dong52d13f02010-07-02 11:39:06 -07001128 mIFramesIntervalSec = 1;
James Dong57e7f832010-06-24 19:55:31 -07001129 mAudioSourceNode = 0;
James Dong6feaa462010-06-20 08:20:54 -07001130 mUse64BitFileOffset = false;
James Dongeff30e32010-08-13 14:16:26 -07001131 mMovieTimeScale = -1;
1132 mAudioTimeScale = -1;
1133 mVideoTimeScale = -1;
James Dong09936ed2010-06-24 19:04:27 -07001134 mCameraId = 0;
James Dong81c929a2010-07-01 15:02:14 -07001135 mVideoEncoderProfile = -1;
1136 mVideoEncoderLevel = -1;
1137 mMaxFileDurationUs = 0;
1138 mMaxFileSizeBytes = 0;
James Dong09936ed2010-06-24 19:04:27 -07001139 mTrackEveryTimeDurationUs = 0;
James Dong42a18c02010-06-16 17:27:46 -07001140 mEncoderProfiles = MediaProfiles::getInstance();
James Dongabed93a2010-04-22 17:27:04 -07001141
Andreas Huberea6a38c2009-11-16 15:43:38 -08001142 mOutputFd = -1;
James Dongb00e2462010-04-26 17:48:26 -07001143 mFlags = 0;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001144
1145 return OK;
1146}
1147
1148status_t StagefrightRecorder::getMaxAmplitude(int *max) {
James Dongc0ab2a62010-06-29 16:29:19 -07001149 LOGV("getMaxAmplitude");
1150
1151 if (max == NULL) {
1152 LOGE("Null pointer argument");
1153 return BAD_VALUE;
1154 }
1155
James Dong57e7f832010-06-24 19:55:31 -07001156 if (mAudioSourceNode != 0) {
1157 *max = mAudioSourceNode->getMaxAmplitude();
1158 } else {
1159 *max = 0;
1160 }
Andreas Huber996dddf2010-01-25 15:30:31 -08001161
1162 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001163}
1164
James Dong3f51fa72010-08-18 03:32:26 -07001165status_t StagefrightRecorder::dump(
1166 int fd, const Vector<String16>& args) const {
1167 LOGV("dump");
James Dong929642e2010-07-08 11:16:11 -07001168 const size_t SIZE = 256;
1169 char buffer[SIZE];
1170 String8 result;
James Dong3f51fa72010-08-18 03:32:26 -07001171 if (mWriter != 0) {
1172 mWriter->dump(fd, args);
1173 } else {
1174 snprintf(buffer, SIZE, " No file writer\n");
1175 result.append(buffer);
1176 }
1177 snprintf(buffer, SIZE, " Recorder: %p\n", this);
James Dong929642e2010-07-08 11:16:11 -07001178 snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
1179 result.append(buffer);
1180 snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
1181 result.append(buffer);
1182 snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1183 result.append(buffer);
1184 snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
1185 result.append(buffer);
1186 snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1187 result.append(buffer);
1188 snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
1189 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001190 snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1191 result.append(buffer);
1192 snprintf(buffer, SIZE, " Audio\n");
1193 result.append(buffer);
1194 snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
1195 result.append(buffer);
1196 snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
1197 result.append(buffer);
1198 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
1199 result.append(buffer);
1200 snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
1201 result.append(buffer);
1202 snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
1203 result.append(buffer);
1204 snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1205 result.append(buffer);
1206 snprintf(buffer, SIZE, " Video\n");
1207 result.append(buffer);
1208 snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
1209 result.append(buffer);
1210 snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
1211 result.append(buffer);
1212 snprintf(buffer, SIZE, " Camera flags: %d\n", mFlags);
1213 result.append(buffer);
1214 snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
1215 result.append(buffer);
1216 snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
1217 result.append(buffer);
1218 snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
1219 result.append(buffer);
James Dong52d13f02010-07-02 11:39:06 -07001220 snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec);
James Dong929642e2010-07-08 11:16:11 -07001221 result.append(buffer);
1222 snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1223 result.append(buffer);
1224 snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
1225 result.append(buffer);
1226 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
1227 result.append(buffer);
1228 ::write(fd, result.string(), result.size());
1229 return OK;
1230}
Andreas Huberea6a38c2009-11-16 15:43:38 -08001231} // namespace android