blob: 223e0be21a75940d0955176fa8b6c01b7ae93596 [file] [log] [blame]
Andreas Huberea6a38c2009-11-16 15:43:38 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "StagefrightRecorder"
19#include <utils/Log.h>
20
21#include "StagefrightRecorder.h"
22
Gloria Wang62e05a62011-02-23 11:47:34 -080023#include <binder/IPCThreadState.h>
24#include <binder/IServiceManager.h>
25
26#include <media/IMediaPlayerService.h>
Andreas Huber996dddf2010-01-25 15:30:31 -080027#include <media/stagefright/AudioSource.h>
28#include <media/stagefright/AMRWriter.h>
James Dongf84bfab2011-03-21 14:29:38 -070029#include <media/stagefright/AACWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080030#include <media/stagefright/CameraSource.h>
Nipun Kwatra239f2e52010-08-31 15:35:44 -070031#include <media/stagefright/VideoSourceDownSampler.h>
Nipun Kwatraf9b80182010-07-12 09:17:14 -070032#include <media/stagefright/CameraSourceTimeLapse.h>
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070033#include <media/stagefright/MediaSourceSplitter.h>
Andreas Huber9adf4662010-10-12 14:17:45 -070034#include <media/stagefright/MPEG2TSWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080035#include <media/stagefright/MPEG4Writer.h>
36#include <media/stagefright/MediaDebug.h>
37#include <media/stagefright/MediaDefs.h>
38#include <media/stagefright/MetaData.h>
39#include <media/stagefright/OMXClient.h>
40#include <media/stagefright/OMXCodec.h>
James Dong42a18c02010-06-16 17:27:46 -070041#include <media/MediaProfiles.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080042#include <camera/ICamera.h>
James Dong2cd841d2010-05-11 11:46:59 -070043#include <camera/CameraParameters.h>
Jamie Gennis85cfdd02010-08-10 16:37:53 -070044#include <surfaceflinger/Surface.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080045#include <utils/Errors.h>
James Dongb00e2462010-04-26 17:48:26 -070046#include <sys/types.h>
James Dongabed93a2010-04-22 17:27:04 -070047#include <ctype.h>
Nipun Kwatra453e92f2010-08-04 14:26:45 -070048#include <unistd.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080049
Dima 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()
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070068 : mWriter(NULL), mWriterAux(NULL),
Gloria Wang62e05a62011-02-23 11:47:34 -080069 mOutputFd(-1), mOutputFdAux(-1),
Dima Zavin24fc2fb2011-04-19 22:30:36 -070070 mAudioSource(AUDIO_SOURCE_CNT),
Gloria Wang62e05a62011-02-23 11:47:34 -080071 mVideoSource(VIDEO_SOURCE_LIST_END),
72 mStarted(false) {
James Dongc0ab2a62010-06-29 16:29:19 -070073
74 LOGV("Constructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080075 reset();
76}
77
78StagefrightRecorder::~StagefrightRecorder() {
James Dongc0ab2a62010-06-29 16:29:19 -070079 LOGV("Destructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080080 stop();
Andreas Huberea6a38c2009-11-16 15:43:38 -080081}
82
83status_t StagefrightRecorder::init() {
James Dongc0ab2a62010-06-29 16:29:19 -070084 LOGV("init");
Andreas Huberea6a38c2009-11-16 15:43:38 -080085 return OK;
86}
87
Dima Zavin24fc2fb2011-04-19 22:30:36 -070088status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
James Dongc0ab2a62010-06-29 16:29:19 -070089 LOGV("setAudioSource: %d", as);
90 if (as < AUDIO_SOURCE_DEFAULT ||
Dima Zavin24fc2fb2011-04-19 22:30:36 -070091 as >= AUDIO_SOURCE_CNT) {
James Dong7b06de62010-06-30 12:41:16 -070092 LOGE("Invalid audio source: %d", as);
James Dongc0ab2a62010-06-29 16:29:19 -070093 return BAD_VALUE;
94 }
95
96 if (as == AUDIO_SOURCE_DEFAULT) {
97 mAudioSource = AUDIO_SOURCE_MIC;
98 } else {
99 mAudioSource = as;
100 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800101
102 return OK;
103}
104
105status_t StagefrightRecorder::setVideoSource(video_source vs) {
James Dongc0ab2a62010-06-29 16:29:19 -0700106 LOGV("setVideoSource: %d", vs);
107 if (vs < VIDEO_SOURCE_DEFAULT ||
108 vs >= VIDEO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700109 LOGE("Invalid video source: %d", vs);
James Dongc0ab2a62010-06-29 16:29:19 -0700110 return BAD_VALUE;
111 }
112
113 if (vs == VIDEO_SOURCE_DEFAULT) {
114 mVideoSource = VIDEO_SOURCE_CAMERA;
115 } else {
116 mVideoSource = vs;
117 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800118
119 return OK;
120}
121
122status_t StagefrightRecorder::setOutputFormat(output_format of) {
James Dongc0ab2a62010-06-29 16:29:19 -0700123 LOGV("setOutputFormat: %d", of);
124 if (of < OUTPUT_FORMAT_DEFAULT ||
125 of >= OUTPUT_FORMAT_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700126 LOGE("Invalid output format: %d", of);
James Dongc0ab2a62010-06-29 16:29:19 -0700127 return BAD_VALUE;
128 }
129
130 if (of == OUTPUT_FORMAT_DEFAULT) {
131 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
132 } else {
133 mOutputFormat = of;
134 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800135
136 return OK;
137}
138
139status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
James Dongc0ab2a62010-06-29 16:29:19 -0700140 LOGV("setAudioEncoder: %d", ae);
141 if (ae < AUDIO_ENCODER_DEFAULT ||
142 ae >= AUDIO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700143 LOGE("Invalid audio encoder: %d", ae);
James Dongc0ab2a62010-06-29 16:29:19 -0700144 return BAD_VALUE;
145 }
146
147 if (ae == AUDIO_ENCODER_DEFAULT) {
148 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
149 } else {
150 mAudioEncoder = ae;
151 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800152
153 return OK;
154}
155
156status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
James Dongc0ab2a62010-06-29 16:29:19 -0700157 LOGV("setVideoEncoder: %d", ve);
158 if (ve < VIDEO_ENCODER_DEFAULT ||
159 ve >= VIDEO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700160 LOGE("Invalid video encoder: %d", ve);
James Dongc0ab2a62010-06-29 16:29:19 -0700161 return BAD_VALUE;
162 }
163
164 if (ve == VIDEO_ENCODER_DEFAULT) {
165 mVideoEncoder = VIDEO_ENCODER_H263;
166 } else {
167 mVideoEncoder = ve;
168 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800169
170 return OK;
171}
172
173status_t StagefrightRecorder::setVideoSize(int width, int height) {
James Dongc0ab2a62010-06-29 16:29:19 -0700174 LOGV("setVideoSize: %dx%d", width, height);
James Dong2cd841d2010-05-11 11:46:59 -0700175 if (width <= 0 || height <= 0) {
176 LOGE("Invalid video size: %dx%d", width, height);
177 return BAD_VALUE;
178 }
179
180 // Additional check on the dimension will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800181 mVideoWidth = width;
182 mVideoHeight = height;
183
184 return OK;
185}
186
187status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
James Dongc0ab2a62010-06-29 16:29:19 -0700188 LOGV("setVideoFrameRate: %d", frames_per_second);
James Dongb15f2ea2010-10-24 09:32:39 -0700189 if ((frames_per_second <= 0 && frames_per_second != -1) ||
190 frames_per_second > 120) {
James Dong2cd841d2010-05-11 11:46:59 -0700191 LOGE("Invalid video frame rate: %d", frames_per_second);
192 return BAD_VALUE;
193 }
194
195 // Additional check on the frame rate will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800196 mFrameRate = frames_per_second;
197
198 return OK;
199}
200
Wu-cheng Li42419ce2011-06-01 17:22:24 +0800201status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera,
202 const sp<ICameraRecordingProxy> &proxy) {
James Dong71d714c2010-06-09 15:57:48 -0700203 LOGV("setCamera");
James Dongb00e2462010-04-26 17:48:26 -0700204 if (camera == 0) {
205 LOGE("camera is NULL");
James Dong7b06de62010-06-30 12:41:16 -0700206 return BAD_VALUE;
James Dongb00e2462010-04-26 17:48:26 -0700207 }
Wu-cheng Li42419ce2011-06-01 17:22:24 +0800208 if (proxy == 0) {
209 LOGE("camera proxy is NULL");
210 return BAD_VALUE;
211 }
James Dongb00e2462010-04-26 17:48:26 -0700212
James Dong0c128b62010-10-08 11:59:32 -0700213 mCamera = camera;
Wu-cheng Li42419ce2011-06-01 17:22:24 +0800214 mCameraProxy = proxy;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800215 return OK;
216}
217
Jamie Gennis85cfdd02010-08-10 16:37:53 -0700218status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
James Dongc0ab2a62010-06-29 16:29:19 -0700219 LOGV("setPreviewSurface: %p", surface.get());
Andreas Huberea6a38c2009-11-16 15:43:38 -0800220 mPreviewSurface = surface;
221
222 return OK;
223}
224
225status_t StagefrightRecorder::setOutputFile(const char *path) {
James Dong7b06de62010-06-30 12:41:16 -0700226 LOGE("setOutputFile(const char*) must not be called");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800227 // We don't actually support this at all, as the media_server process
228 // no longer has permissions to create files.
229
James Dong7b06de62010-06-30 12:41:16 -0700230 return -EPERM;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800231}
232
233status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
James Dongc0ab2a62010-06-29 16:29:19 -0700234 LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800235 // These don't make any sense, do they?
236 CHECK_EQ(offset, 0);
237 CHECK_EQ(length, 0);
238
James Dong7b06de62010-06-30 12:41:16 -0700239 if (fd < 0) {
240 LOGE("Invalid file descriptor: %d", fd);
241 return -EBADF;
242 }
243
Andreas Huberea6a38c2009-11-16 15:43:38 -0800244 if (mOutputFd >= 0) {
245 ::close(mOutputFd);
246 }
247 mOutputFd = dup(fd);
248
249 return OK;
250}
251
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700252status_t StagefrightRecorder::setOutputFileAuxiliary(int fd) {
253 LOGV("setOutputFileAuxiliary: %d", fd);
254
255 if (fd < 0) {
256 LOGE("Invalid file descriptor: %d", fd);
257 return -EBADF;
258 }
259
260 mCaptureAuxVideo = true;
261
262 if (mOutputFdAux >= 0) {
263 ::close(mOutputFdAux);
264 }
265 mOutputFdAux = dup(fd);
266
267 return OK;
268}
269
James Dongabed93a2010-04-22 17:27:04 -0700270// Attempt to parse an int64 literal optionally surrounded by whitespace,
271// returns true on success, false otherwise.
James Dong2cd841d2010-05-11 11:46:59 -0700272static bool safe_strtoi64(const char *s, int64_t *val) {
James Dongabed93a2010-04-22 17:27:04 -0700273 char *end;
James Dong75fb2382011-02-08 15:41:58 -0800274
275 // It is lame, but according to man page, we have to set errno to 0
276 // before calling strtoll().
277 errno = 0;
James Dong2cd841d2010-05-11 11:46:59 -0700278 *val = strtoll(s, &end, 10);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800279
James Dongabed93a2010-04-22 17:27:04 -0700280 if (end == s || errno == ERANGE) {
281 return false;
282 }
283
284 // Skip trailing whitespace
285 while (isspace(*end)) {
286 ++end;
287 }
288
289 // For a successful return, the string must contain nothing but a valid
290 // int64 literal optionally surrounded by whitespace.
291
292 return *end == '\0';
293}
294
James Dong2cd841d2010-05-11 11:46:59 -0700295// Return true if the value is in [0, 0x007FFFFFFF]
296static bool safe_strtoi32(const char *s, int32_t *val) {
297 int64_t temp;
298 if (safe_strtoi64(s, &temp)) {
299 if (temp >= 0 && temp <= 0x007FFFFFFF) {
300 *val = static_cast<int32_t>(temp);
301 return true;
302 }
303 }
304 return false;
305}
306
James Dongabed93a2010-04-22 17:27:04 -0700307// Trim both leading and trailing whitespace from the given string.
308static void TrimString(String8 *s) {
309 size_t num_bytes = s->bytes();
310 const char *data = s->string();
311
312 size_t leading_space = 0;
313 while (leading_space < num_bytes && isspace(data[leading_space])) {
314 ++leading_space;
315 }
316
317 size_t i = num_bytes;
318 while (i > leading_space && isspace(data[i - 1])) {
319 --i;
320 }
321
322 s->setTo(String8(&data[leading_space], i - leading_space));
323}
324
325status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
326 LOGV("setParamAudioSamplingRate: %d", sampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700327 if (sampleRate <= 0) {
328 LOGE("Invalid audio sampling rate: %d", sampleRate);
329 return BAD_VALUE;
330 }
331
332 // Additional check on the sample rate will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700333 mSampleRate = sampleRate;
334 return OK;
335}
336
337status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
338 LOGV("setParamAudioNumberOfChannels: %d", channels);
James Dong2cd841d2010-05-11 11:46:59 -0700339 if (channels <= 0 || channels >= 3) {
340 LOGE("Invalid number of audio channels: %d", channels);
James Dong7b06de62010-06-30 12:41:16 -0700341 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700342 }
343
344 // Additional check on the number of channels will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700345 mAudioChannels = channels;
346 return OK;
347}
348
349status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
350 LOGV("setParamAudioEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700351 if (bitRate <= 0) {
352 LOGE("Invalid audio encoding bit rate: %d", bitRate);
353 return BAD_VALUE;
354 }
355
356 // The target bit rate may not be exactly the same as the requested.
357 // It depends on many factors, such as rate control, and the bit rate
358 // range that a specific encoder supports. The mismatch between the
359 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700360 mAudioBitRate = bitRate;
361 return OK;
362}
363
364status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
365 LOGV("setParamVideoEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700366 if (bitRate <= 0) {
367 LOGE("Invalid video encoding bit rate: %d", bitRate);
368 return BAD_VALUE;
369 }
370
371 // The target bit rate may not be exactly the same as the requested.
372 // It depends on many factors, such as rate control, and the bit rate
373 // range that a specific encoder supports. The mismatch between the
374 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700375 mVideoBitRate = bitRate;
376 return OK;
377}
378
James Dongb9d7e012010-11-09 11:15:47 -0800379// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
380status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
381 LOGV("setParamVideoRotation: %d", degrees);
382 if (degrees < 0 || degrees % 90 != 0) {
383 LOGE("Unsupported video rotation angle: %d", degrees);
384 return BAD_VALUE;
385 }
386 mRotationDegrees = degrees % 360;
387 return OK;
388}
389
James Dong7b06de62010-06-30 12:41:16 -0700390status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
391 LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
James Dong26ea64c2010-12-20 11:39:38 -0800392
393 // This is meant for backward compatibility for MediaRecorder.java
Nipun Kwatrafb457482010-08-18 15:19:19 -0700394 if (timeUs <= 0) {
395 LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
396 timeUs = 0; // Disable the duration limit for zero or negative values.
397 } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
James Dong7b06de62010-06-30 12:41:16 -0700398 LOGE("Max file duration is too short: %lld us", timeUs);
399 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700400 }
Nipun Kwatrafb457482010-08-18 15:19:19 -0700401
James Dong5cdcf162010-11-30 18:18:08 -0800402 if (timeUs <= 15 * 1000000LL) {
403 LOGW("Target duration (%lld us) too short to be respected", timeUs);
404 }
James Dong7b06de62010-06-30 12:41:16 -0700405 mMaxFileDurationUs = timeUs;
406 return OK;
407}
408
409status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
410 LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
James Dong26ea64c2010-12-20 11:39:38 -0800411
412 // This is meant for backward compatibility for MediaRecorder.java
413 if (bytes <= 0) {
414 LOGW("Max file size is not positive: %lld bytes. "
415 "Disabling file size limit.", bytes);
416 bytes = 0; // Disable the file size limit for zero or negative values.
417 } else if (bytes <= 1024) { // XXX: 1 kB
James Dong7b06de62010-06-30 12:41:16 -0700418 LOGE("Max file size is too small: %lld bytes", bytes);
419 return BAD_VALUE;
420 }
James Dong5cdcf162010-11-30 18:18:08 -0800421
422 if (bytes <= 100 * 1024) {
423 LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
424 }
425
James Dong7b06de62010-06-30 12:41:16 -0700426 mMaxFileSizeBytes = bytes;
James Dongabed93a2010-04-22 17:27:04 -0700427 return OK;
428}
429
James Dong3300e962010-04-21 16:14:15 -0700430status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
431 LOGV("setParamInterleaveDuration: %d", durationUs);
James Dong1244eab2010-06-08 11:58:53 -0700432 if (durationUs <= 500000) { // 500 ms
433 // If interleave duration is too small, it is very inefficient to do
434 // interleaving since the metadata overhead will count for a significant
435 // portion of the saved contents
James Dong2cd841d2010-05-11 11:46:59 -0700436 LOGE("Audio/video interleave duration is too small: %d us", durationUs);
437 return BAD_VALUE;
James Dong1244eab2010-06-08 11:58:53 -0700438 } else if (durationUs >= 10000000) { // 10 seconds
439 // If interleaving duration is too large, it can cause the recording
440 // session to use too much memory since we have to save the output
441 // data before we write them out
442 LOGE("Audio/video interleave duration is too large: %d us", durationUs);
443 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700444 }
James Dong3300e962010-04-21 16:14:15 -0700445 mInterleaveDurationUs = durationUs;
446 return OK;
447}
James Dong2cd841d2010-05-11 11:46:59 -0700448
James Dong52d13f02010-07-02 11:39:06 -0700449// If seconds < 0, only the first frame is I frame, and rest are all P frames
450// If seconds == 0, all frames are encoded as I frames. No P frames
451// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames
452status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
453 LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
454 mIFramesIntervalSec = seconds;
James Dong1244eab2010-06-08 11:58:53 -0700455 return OK;
456}
457
James Dong6feaa462010-06-20 08:20:54 -0700458status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
459 LOGV("setParam64BitFileOffset: %s",
460 use64Bit? "use 64 bit file offset": "use 32 bit file offset");
461 mUse64BitFileOffset = use64Bit;
462 return OK;
463}
464
James Dong09936ed2010-06-24 19:04:27 -0700465status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
466 LOGV("setParamVideoCameraId: %d", cameraId);
467 if (cameraId < 0) {
468 return BAD_VALUE;
469 }
470 mCameraId = cameraId;
471 return OK;
472}
473
James Dong09936ed2010-06-24 19:04:27 -0700474status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
475 LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
476 if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
James Dong7b06de62010-06-30 12:41:16 -0700477 LOGE("Tracking time duration too short: %lld us", timeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -0700478 return BAD_VALUE;
479 }
480 mTrackEveryTimeDurationUs = timeDurationUs;
481 return OK;
482}
483
James Dong81c929a2010-07-01 15:02:14 -0700484status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
485 LOGV("setParamVideoEncoderProfile: %d", profile);
486
487 // Additional check will be done later when we load the encoder.
488 // For now, we are accepting values defined in OpenMAX IL.
489 mVideoEncoderProfile = profile;
490 return OK;
491}
492
493status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
494 LOGV("setParamVideoEncoderLevel: %d", level);
495
496 // Additional check will be done later when we load the encoder.
497 // For now, we are accepting values defined in OpenMAX IL.
498 mVideoEncoderLevel = level;
499 return OK;
500}
501
James Dong52d13f02010-07-02 11:39:06 -0700502status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
503 LOGV("setParamMovieTimeScale: %d", timeScale);
504
505 // The range is set to be the same as the audio's time scale range
506 // since audio's time scale has a wider range.
507 if (timeScale < 600 || timeScale > 96000) {
508 LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
509 return BAD_VALUE;
510 }
511 mMovieTimeScale = timeScale;
512 return OK;
513}
514
515status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
516 LOGV("setParamVideoTimeScale: %d", timeScale);
517
518 // 60000 is chosen to make sure that each video frame from a 60-fps
519 // video has 1000 ticks.
520 if (timeScale < 600 || timeScale > 60000) {
521 LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
522 return BAD_VALUE;
523 }
524 mVideoTimeScale = timeScale;
525 return OK;
526}
527
528status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
529 LOGV("setParamAudioTimeScale: %d", timeScale);
530
531 // 96000 Hz is the highest sampling rate support in AAC.
532 if (timeScale < 600 || timeScale > 96000) {
533 LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
534 return BAD_VALUE;
535 }
536 mAudioTimeScale = timeScale;
537 return OK;
538}
539
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700540status_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
541 LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
542
543 if(timeLapseEnable == 0) {
544 mCaptureTimeLapse = false;
545 } else if (timeLapseEnable == 1) {
546 mCaptureTimeLapse = true;
547 } else {
548 return BAD_VALUE;
549 }
550 return OK;
551}
552
553status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
554 LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
555
556 // Not allowing time more than a day
557 if (timeUs <= 0 || timeUs > 86400*1E6) {
558 LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
559 return BAD_VALUE;
560 }
561
562 mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
563 return OK;
564}
565
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700566status_t StagefrightRecorder::setParamAuxVideoWidth(int32_t width) {
567 LOGV("setParamAuxVideoWidth : %d", width);
568
569 if (width <= 0) {
570 LOGE("Width (%d) is not positive", width);
571 return BAD_VALUE;
572 }
573
574 mAuxVideoWidth = width;
575 return OK;
576}
577
578status_t StagefrightRecorder::setParamAuxVideoHeight(int32_t height) {
579 LOGV("setParamAuxVideoHeight : %d", height);
580
581 if (height <= 0) {
582 LOGE("Height (%d) is not positive", height);
583 return BAD_VALUE;
584 }
585
586 mAuxVideoHeight = height;
587 return OK;
588}
589
590status_t StagefrightRecorder::setParamAuxVideoEncodingBitRate(int32_t bitRate) {
591 LOGV("StagefrightRecorder::setParamAuxVideoEncodingBitRate: %d", bitRate);
592
593 if (bitRate <= 0) {
594 LOGE("Invalid video encoding bit rate: %d", bitRate);
595 return BAD_VALUE;
596 }
597
598 mAuxVideoBitRate = bitRate;
599 return OK;
600}
601
James Dong987ab482011-05-11 19:09:25 -0700602status_t StagefrightRecorder::setParamGeoDataLongitude(
603 int32_t longitudex10000) {
604
605 if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
606 return BAD_VALUE;
607 }
608 mLongitudex10000 = longitudex10000;
609 return OK;
610}
611
612status_t StagefrightRecorder::setParamGeoDataLatitude(
613 int32_t latitudex10000) {
614
615 if (latitudex10000 > 900000 || latitudex10000 < -900000) {
616 return BAD_VALUE;
617 }
618 mLatitudex10000 = latitudex10000;
619 return OK;
620}
621
James Dongabed93a2010-04-22 17:27:04 -0700622status_t StagefrightRecorder::setParameter(
623 const String8 &key, const String8 &value) {
624 LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
625 if (key == "max-duration") {
James Dong2cd841d2010-05-11 11:46:59 -0700626 int64_t max_duration_ms;
James Dongabed93a2010-04-22 17:27:04 -0700627 if (safe_strtoi64(value.string(), &max_duration_ms)) {
James Dong7b06de62010-06-30 12:41:16 -0700628 return setParamMaxFileDurationUs(1000LL * max_duration_ms);
James Dongabed93a2010-04-22 17:27:04 -0700629 }
630 } else if (key == "max-filesize") {
James Dong2cd841d2010-05-11 11:46:59 -0700631 int64_t max_filesize_bytes;
James Dongabed93a2010-04-22 17:27:04 -0700632 if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
James Dong7b06de62010-06-30 12:41:16 -0700633 return setParamMaxFileSizeBytes(max_filesize_bytes);
James Dongabed93a2010-04-22 17:27:04 -0700634 }
James Dong09936ed2010-06-24 19:04:27 -0700635 } else if (key == "interleave-duration-us") {
636 int32_t durationUs;
637 if (safe_strtoi32(value.string(), &durationUs)) {
638 return setParamInterleaveDuration(durationUs);
639 }
James Dong52d13f02010-07-02 11:39:06 -0700640 } else if (key == "param-movie-time-scale") {
641 int32_t timeScale;
642 if (safe_strtoi32(value.string(), &timeScale)) {
643 return setParamMovieTimeScale(timeScale);
644 }
James Dong09936ed2010-06-24 19:04:27 -0700645 } else if (key == "param-use-64bit-offset") {
646 int32_t use64BitOffset;
647 if (safe_strtoi32(value.string(), &use64BitOffset)) {
648 return setParam64BitFileOffset(use64BitOffset != 0);
649 }
James Dong987ab482011-05-11 19:09:25 -0700650 } else if (key == "param-geotag-longitude") {
651 int32_t longitudex10000;
652 if (safe_strtoi32(value.string(), &longitudex10000)) {
653 return setParamGeoDataLongitude(longitudex10000);
654 }
655 } else if (key == "param-geotag-latitude") {
656 int32_t latitudex10000;
657 if (safe_strtoi32(value.string(), &latitudex10000)) {
658 return setParamGeoDataLatitude(latitudex10000);
659 }
James Dong09936ed2010-06-24 19:04:27 -0700660 } else if (key == "param-track-time-status") {
661 int64_t timeDurationUs;
662 if (safe_strtoi64(value.string(), &timeDurationUs)) {
663 return setParamTrackTimeStatus(timeDurationUs);
664 }
James Dongabed93a2010-04-22 17:27:04 -0700665 } else if (key == "audio-param-sampling-rate") {
666 int32_t sampling_rate;
James Dong2cd841d2010-05-11 11:46:59 -0700667 if (safe_strtoi32(value.string(), &sampling_rate)) {
James Dongabed93a2010-04-22 17:27:04 -0700668 return setParamAudioSamplingRate(sampling_rate);
669 }
670 } else if (key == "audio-param-number-of-channels") {
671 int32_t number_of_channels;
James Dong2cd841d2010-05-11 11:46:59 -0700672 if (safe_strtoi32(value.string(), &number_of_channels)) {
James Dongabed93a2010-04-22 17:27:04 -0700673 return setParamAudioNumberOfChannels(number_of_channels);
674 }
675 } else if (key == "audio-param-encoding-bitrate") {
676 int32_t audio_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700677 if (safe_strtoi32(value.string(), &audio_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700678 return setParamAudioEncodingBitRate(audio_bitrate);
679 }
James Dong52d13f02010-07-02 11:39:06 -0700680 } else if (key == "audio-param-time-scale") {
681 int32_t timeScale;
682 if (safe_strtoi32(value.string(), &timeScale)) {
683 return setParamAudioTimeScale(timeScale);
684 }
James Dongabed93a2010-04-22 17:27:04 -0700685 } else if (key == "video-param-encoding-bitrate") {
686 int32_t video_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700687 if (safe_strtoi32(value.string(), &video_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700688 return setParamVideoEncodingBitRate(video_bitrate);
689 }
James Dongb9d7e012010-11-09 11:15:47 -0800690 } else if (key == "video-param-rotation-angle-degrees") {
691 int32_t degrees;
692 if (safe_strtoi32(value.string(), &degrees)) {
693 return setParamVideoRotation(degrees);
694 }
James Dong09936ed2010-06-24 19:04:27 -0700695 } else if (key == "video-param-i-frames-interval") {
James Dong52d13f02010-07-02 11:39:06 -0700696 int32_t seconds;
697 if (safe_strtoi32(value.string(), &seconds)) {
698 return setParamVideoIFramesInterval(seconds);
James Dong1244eab2010-06-08 11:58:53 -0700699 }
James Dong81c929a2010-07-01 15:02:14 -0700700 } else if (key == "video-param-encoder-profile") {
701 int32_t profile;
702 if (safe_strtoi32(value.string(), &profile)) {
703 return setParamVideoEncoderProfile(profile);
704 }
705 } else if (key == "video-param-encoder-level") {
706 int32_t level;
707 if (safe_strtoi32(value.string(), &level)) {
708 return setParamVideoEncoderLevel(level);
709 }
James Dong09936ed2010-06-24 19:04:27 -0700710 } else if (key == "video-param-camera-id") {
711 int32_t cameraId;
712 if (safe_strtoi32(value.string(), &cameraId)) {
713 return setParamVideoCameraId(cameraId);
James Dong6feaa462010-06-20 08:20:54 -0700714 }
James Dong52d13f02010-07-02 11:39:06 -0700715 } else if (key == "video-param-time-scale") {
716 int32_t timeScale;
717 if (safe_strtoi32(value.string(), &timeScale)) {
718 return setParamVideoTimeScale(timeScale);
719 }
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700720 } else if (key == "time-lapse-enable") {
721 int32_t timeLapseEnable;
722 if (safe_strtoi32(value.string(), &timeLapseEnable)) {
723 return setParamTimeLapseEnable(timeLapseEnable);
724 }
725 } else if (key == "time-between-time-lapse-frame-capture") {
726 int64_t timeBetweenTimeLapseFrameCaptureMs;
727 if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
728 return setParamTimeBetweenTimeLapseFrameCapture(
729 1000LL * timeBetweenTimeLapseFrameCaptureMs);
730 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700731 } else if (key == "video-aux-param-width") {
732 int32_t auxWidth;
733 if (safe_strtoi32(value.string(), &auxWidth)) {
734 return setParamAuxVideoWidth(auxWidth);
735 }
736 } else if (key == "video-aux-param-height") {
737 int32_t auxHeight;
738 if (safe_strtoi32(value.string(), &auxHeight)) {
739 return setParamAuxVideoHeight(auxHeight);
740 }
741 } else if (key == "video-aux-param-encoding-bitrate") {
742 int32_t auxVideoBitRate;
743 if (safe_strtoi32(value.string(), &auxVideoBitRate)) {
744 return setParamAuxVideoEncodingBitRate(auxVideoBitRate);
745 }
James Dongabed93a2010-04-22 17:27:04 -0700746 } else {
747 LOGE("setParameter: failed to find key %s", key.string());
James Dongabed93a2010-04-22 17:27:04 -0700748 }
James Dong2cd841d2010-05-11 11:46:59 -0700749 return BAD_VALUE;
James Dongabed93a2010-04-22 17:27:04 -0700750}
751
752status_t StagefrightRecorder::setParameters(const String8 &params) {
753 LOGV("setParameters: %s", params.string());
754 const char *cparams = params.string();
755 const char *key_start = cparams;
756 for (;;) {
757 const char *equal_pos = strchr(key_start, '=');
758 if (equal_pos == NULL) {
759 LOGE("Parameters %s miss a value", cparams);
760 return BAD_VALUE;
761 }
762 String8 key(key_start, equal_pos - key_start);
763 TrimString(&key);
764 if (key.length() == 0) {
765 LOGE("Parameters %s contains an empty key", cparams);
766 return BAD_VALUE;
767 }
768 const char *value_start = equal_pos + 1;
769 const char *semicolon_pos = strchr(value_start, ';');
770 String8 value;
771 if (semicolon_pos == NULL) {
772 value.setTo(value_start);
773 } else {
774 value.setTo(value_start, semicolon_pos - value_start);
775 }
776 if (setParameter(key, value) != OK) {
777 return BAD_VALUE;
778 }
779 if (semicolon_pos == NULL) {
780 break; // Reaches the end
781 }
782 key_start = semicolon_pos + 1;
783 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800784 return OK;
785}
786
James Dongfe1bafe2010-06-25 17:06:47 -0700787status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
Andreas Huberea6a38c2009-11-16 15:43:38 -0800788 mListener = listener;
789
790 return OK;
791}
792
793status_t StagefrightRecorder::prepare() {
794 return OK;
795}
796
797status_t StagefrightRecorder::start() {
James Dong7b06de62010-06-30 12:41:16 -0700798 CHECK(mOutputFd >= 0);
799
Andreas Huberea6a38c2009-11-16 15:43:38 -0800800 if (mWriter != NULL) {
James Dong7b06de62010-06-30 12:41:16 -0700801 LOGE("File writer is not avaialble");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800802 return UNKNOWN_ERROR;
803 }
804
Gloria Wang62e05a62011-02-23 11:47:34 -0800805 status_t status = OK;
806
Andreas Huber996dddf2010-01-25 15:30:31 -0800807 switch (mOutputFormat) {
808 case OUTPUT_FORMAT_DEFAULT:
809 case OUTPUT_FORMAT_THREE_GPP:
810 case OUTPUT_FORMAT_MPEG_4:
Gloria Wang62e05a62011-02-23 11:47:34 -0800811 status = startMPEG4Recording();
812 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800813
814 case OUTPUT_FORMAT_AMR_NB:
815 case OUTPUT_FORMAT_AMR_WB:
Gloria Wang62e05a62011-02-23 11:47:34 -0800816 status = startAMRRecording();
817 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800818
James Dong2cd841d2010-05-11 11:46:59 -0700819 case OUTPUT_FORMAT_AAC_ADIF:
820 case OUTPUT_FORMAT_AAC_ADTS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800821 status = startAACRecording();
822 break;
James Dong2cd841d2010-05-11 11:46:59 -0700823
Andreas Huber57648e42010-08-04 10:14:30 -0700824 case OUTPUT_FORMAT_RTP_AVP:
Gloria Wang62e05a62011-02-23 11:47:34 -0800825 status = startRTPRecording();
826 break;
Andreas Huber57648e42010-08-04 10:14:30 -0700827
Andreas Huber9adf4662010-10-12 14:17:45 -0700828 case OUTPUT_FORMAT_MPEG2TS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800829 status = startMPEG2TSRecording();
830 break;
Andreas Huber9adf4662010-10-12 14:17:45 -0700831
Andreas Huber996dddf2010-01-25 15:30:31 -0800832 default:
James Dong7b06de62010-06-30 12:41:16 -0700833 LOGE("Unsupported output file format: %d", mOutputFormat);
Gloria Wang62e05a62011-02-23 11:47:34 -0800834 status = UNKNOWN_ERROR;
835 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800836 }
Gloria Wang62e05a62011-02-23 11:47:34 -0800837
838 if ((status == OK) && (!mStarted)) {
839 mStarted = true;
840
841 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700842 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -0800843 params |= IMediaPlayerService::kBatteryDataTrackAudio;
844 }
845 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
846 params |= IMediaPlayerService::kBatteryDataTrackVideo;
847 }
848
849 addBatteryData(params);
850 }
851
852 return status;
Andreas Huber996dddf2010-01-25 15:30:31 -0800853}
854
James Dongabed93a2010-04-22 17:27:04 -0700855sp<MediaSource> StagefrightRecorder::createAudioSource() {
Andreas Huber996dddf2010-01-25 15:30:31 -0800856 sp<AudioSource> audioSource =
857 new AudioSource(
858 mAudioSource,
James Dongabed93a2010-04-22 17:27:04 -0700859 mSampleRate,
James Dongd77d2a92010-06-14 17:45:35 -0700860 mAudioChannels);
Andreas Huber996dddf2010-01-25 15:30:31 -0800861
862 status_t err = audioSource->initCheck();
863
864 if (err != OK) {
James Dongabed93a2010-04-22 17:27:04 -0700865 LOGE("audio source is not initialized");
Andreas Huber996dddf2010-01-25 15:30:31 -0800866 return NULL;
867 }
868
869 sp<MetaData> encMeta = new MetaData;
James Dongabed93a2010-04-22 17:27:04 -0700870 const char *mime;
871 switch (mAudioEncoder) {
872 case AUDIO_ENCODER_AMR_NB:
873 case AUDIO_ENCODER_DEFAULT:
874 mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
875 break;
876 case AUDIO_ENCODER_AMR_WB:
877 mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
878 break;
879 case AUDIO_ENCODER_AAC:
880 mime = MEDIA_MIMETYPE_AUDIO_AAC;
881 break;
882 default:
883 LOGE("Unknown audio encoder: %d", mAudioEncoder);
884 return NULL;
885 }
886 encMeta->setCString(kKeyMIMEType, mime);
Andreas Huber996dddf2010-01-25 15:30:31 -0800887
Andreas Huber259b7c12010-02-10 15:04:31 -0800888 int32_t maxInputSize;
889 CHECK(audioSource->getFormat()->findInt32(
890 kKeyMaxInputSize, &maxInputSize));
891
892 encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
James Dongabed93a2010-04-22 17:27:04 -0700893 encMeta->setInt32(kKeyChannelCount, mAudioChannels);
894 encMeta->setInt32(kKeySampleRate, mSampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700895 encMeta->setInt32(kKeyBitRate, mAudioBitRate);
James Dongeff30e32010-08-13 14:16:26 -0700896 if (mAudioTimeScale > 0) {
897 encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
898 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800899
900 OMXClient client;
901 CHECK_EQ(client.connect(), OK);
902
903 sp<MediaSource> audioEncoder =
904 OMXCodec::Create(client.interface(), encMeta,
905 true /* createEncoder */, audioSource);
James Dong57e7f832010-06-24 19:55:31 -0700906 mAudioSourceNode = audioSource;
Andreas Huber996dddf2010-01-25 15:30:31 -0800907
908 return audioEncoder;
909}
910
James Dong2cd841d2010-05-11 11:46:59 -0700911status_t StagefrightRecorder::startAACRecording() {
James Dongf84bfab2011-03-21 14:29:38 -0700912 // FIXME:
913 // Add support for OUTPUT_FORMAT_AAC_ADIF
914 CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
James Dong2cd841d2010-05-11 11:46:59 -0700915
916 CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700917 CHECK(mAudioSource != AUDIO_SOURCE_CNT);
James Dong2cd841d2010-05-11 11:46:59 -0700918
James Dongf84bfab2011-03-21 14:29:38 -0700919 mWriter = new AACWriter(mOutputFd);
920 status_t status = startRawAudioRecording();
921 if (status != OK) {
922 mWriter.clear();
923 mWriter = NULL;
924 }
James Dong2cd841d2010-05-11 11:46:59 -0700925
James Dongf84bfab2011-03-21 14:29:38 -0700926 return status;
James Dong2cd841d2010-05-11 11:46:59 -0700927}
928
Andreas Huber996dddf2010-01-25 15:30:31 -0800929status_t StagefrightRecorder::startAMRRecording() {
James Dong2cd841d2010-05-11 11:46:59 -0700930 CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
931 mOutputFormat == OUTPUT_FORMAT_AMR_WB);
932
933 if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
934 if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
935 mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
936 LOGE("Invalid encoder %d used for AMRNB recording",
937 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700938 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700939 }
James Dong2cd841d2010-05-11 11:46:59 -0700940 } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
941 if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
942 LOGE("Invlaid encoder %d used for AMRWB recording",
943 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700944 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700945 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800946 }
947
James Dongf84bfab2011-03-21 14:29:38 -0700948 mWriter = new AMRWriter(mOutputFd);
949 status_t status = startRawAudioRecording();
950 if (status != OK) {
951 mWriter.clear();
952 mWriter = NULL;
953 }
954 return status;
955}
956
957status_t StagefrightRecorder::startRawAudioRecording() {
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700958 if (mAudioSource >= AUDIO_SOURCE_CNT) {
James Dong2cd841d2010-05-11 11:46:59 -0700959 LOGE("Invalid audio source: %d", mAudioSource);
James Dong7b06de62010-06-30 12:41:16 -0700960 return BAD_VALUE;
Andreas Huber996dddf2010-01-25 15:30:31 -0800961 }
962
James Dong54815a72011-01-12 20:45:16 -0800963 status_t status = BAD_VALUE;
964 if (OK != (status = checkAudioEncoderCapabilities())) {
965 return status;
966 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800967
James Dong54815a72011-01-12 20:45:16 -0800968 sp<MediaSource> audioEncoder = createAudioSource();
Andreas Huber996dddf2010-01-25 15:30:31 -0800969 if (audioEncoder == NULL) {
970 return UNKNOWN_ERROR;
971 }
972
James Dongf84bfab2011-03-21 14:29:38 -0700973 CHECK(mWriter != 0);
Andreas Huber996dddf2010-01-25 15:30:31 -0800974 mWriter->addSource(audioEncoder);
James Dong18244862010-05-11 14:57:02 -0700975
976 if (mMaxFileDurationUs != 0) {
977 mWriter->setMaxFileDuration(mMaxFileDurationUs);
978 }
979 if (mMaxFileSizeBytes != 0) {
980 mWriter->setMaxFileSize(mMaxFileSizeBytes);
981 }
982 mWriter->setListener(mListener);
Andreas Huber996dddf2010-01-25 15:30:31 -0800983 mWriter->start();
984
985 return OK;
986}
987
Andreas Huber57648e42010-08-04 10:14:30 -0700988status_t StagefrightRecorder::startRTPRecording() {
989 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
990
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700991 if ((mAudioSource != AUDIO_SOURCE_CNT
Andreas Huber57648e42010-08-04 10:14:30 -0700992 && mVideoSource != VIDEO_SOURCE_LIST_END)
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700993 || (mAudioSource == AUDIO_SOURCE_CNT
Andreas Huber57648e42010-08-04 10:14:30 -0700994 && mVideoSource == VIDEO_SOURCE_LIST_END)) {
995 // Must have exactly one source.
996 return BAD_VALUE;
997 }
998
999 if (mOutputFd < 0) {
1000 return BAD_VALUE;
1001 }
1002
1003 sp<MediaSource> source;
1004
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001005 if (mAudioSource != AUDIO_SOURCE_CNT) {
Andreas Huber57648e42010-08-04 10:14:30 -07001006 source = createAudioSource();
1007 } else {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001008
1009 sp<CameraSource> cameraSource;
1010 status_t err = setupCameraSource(&cameraSource);
1011 if (err != OK) {
1012 return err;
1013 }
1014
1015 err = setupVideoEncoder(cameraSource, mVideoBitRate, &source);
Andreas Huber57648e42010-08-04 10:14:30 -07001016 if (err != OK) {
1017 return err;
1018 }
1019 }
1020
James Dong2747e0e2010-11-18 20:59:13 -08001021 mWriter = new ARTPWriter(mOutputFd);
Andreas Huber57648e42010-08-04 10:14:30 -07001022 mWriter->addSource(source);
1023 mWriter->setListener(mListener);
1024
1025 return mWriter->start();
1026}
1027
Andreas Huber9adf4662010-10-12 14:17:45 -07001028status_t StagefrightRecorder::startMPEG2TSRecording() {
1029 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
1030
James Dong2747e0e2010-11-18 20:59:13 -08001031 sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
Andreas Huber9adf4662010-10-12 14:17:45 -07001032
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001033 if (mAudioSource != AUDIO_SOURCE_CNT) {
Andreas Huber9adf4662010-10-12 14:17:45 -07001034 if (mAudioEncoder != AUDIO_ENCODER_AAC) {
1035 return ERROR_UNSUPPORTED;
1036 }
1037
1038 status_t err = setupAudioEncoder(writer);
1039
1040 if (err != OK) {
1041 return err;
1042 }
1043 }
1044
1045 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1046 || mVideoSource == VIDEO_SOURCE_CAMERA) {
1047 if (mVideoEncoder != VIDEO_ENCODER_H264) {
1048 return ERROR_UNSUPPORTED;
1049 }
1050
Kenny Root4a90f932010-10-14 23:58:41 -07001051 sp<CameraSource> cameraSource;
1052 status_t err = setupCameraSource(&cameraSource);
1053 if (err != OK) {
1054 return err;
1055 }
1056
Andreas Huber9adf4662010-10-12 14:17:45 -07001057 sp<MediaSource> encoder;
Kenny Root4a90f932010-10-14 23:58:41 -07001058 err = setupVideoEncoder(cameraSource, mVideoBitRate, &encoder);
Andreas Huber9adf4662010-10-12 14:17:45 -07001059
1060 if (err != OK) {
1061 return err;
1062 }
1063
1064 writer->addSource(encoder);
1065 }
1066
1067 if (mMaxFileDurationUs != 0) {
1068 writer->setMaxFileDuration(mMaxFileDurationUs);
1069 }
1070
1071 if (mMaxFileSizeBytes != 0) {
1072 writer->setMaxFileSize(mMaxFileSizeBytes);
1073 }
1074
1075 mWriter = writer;
1076
1077 return mWriter->start();
1078}
1079
James Dong42a18c02010-06-16 17:27:46 -07001080void StagefrightRecorder::clipVideoFrameRate() {
1081 LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
1082 int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1083 "enc.vid.fps.min", mVideoEncoder);
1084 int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1085 "enc.vid.fps.max", mVideoEncoder);
James Dongb15f2ea2010-10-24 09:32:39 -07001086 if (mFrameRate < minFrameRate && mFrameRate != -1) {
James Dong42a18c02010-06-16 17:27:46 -07001087 LOGW("Intended video encoding frame rate (%d fps) is too small"
1088 " and will be set to (%d fps)", mFrameRate, minFrameRate);
1089 mFrameRate = minFrameRate;
1090 } else if (mFrameRate > maxFrameRate) {
1091 LOGW("Intended video encoding frame rate (%d fps) is too large"
1092 " and will be set to (%d fps)", mFrameRate, maxFrameRate);
1093 mFrameRate = maxFrameRate;
1094 }
1095}
1096
1097void StagefrightRecorder::clipVideoBitRate() {
1098 LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
1099 int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1100 "enc.vid.bps.min", mVideoEncoder);
1101 int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1102 "enc.vid.bps.max", mVideoEncoder);
1103 if (mVideoBitRate < minBitRate) {
1104 LOGW("Intended video encoding bit rate (%d bps) is too small"
1105 " and will be set to (%d bps)", mVideoBitRate, minBitRate);
1106 mVideoBitRate = minBitRate;
1107 } else if (mVideoBitRate > maxBitRate) {
1108 LOGW("Intended video encoding bit rate (%d bps) is too large"
1109 " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
1110 mVideoBitRate = maxBitRate;
1111 }
1112}
1113
1114void StagefrightRecorder::clipVideoFrameWidth() {
1115 LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
1116 int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1117 "enc.vid.width.min", mVideoEncoder);
1118 int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1119 "enc.vid.width.max", mVideoEncoder);
1120 if (mVideoWidth < minFrameWidth) {
1121 LOGW("Intended video encoding frame width (%d) is too small"
1122 " and will be set to (%d)", mVideoWidth, minFrameWidth);
1123 mVideoWidth = minFrameWidth;
1124 } else if (mVideoWidth > maxFrameWidth) {
1125 LOGW("Intended video encoding frame width (%d) is too large"
1126 " and will be set to (%d)", mVideoWidth, maxFrameWidth);
1127 mVideoWidth = maxFrameWidth;
1128 }
1129}
1130
James Dong0c128b62010-10-08 11:59:32 -07001131status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
Nipun Kwatra453e92f2010-08-04 14:26:45 -07001132 if (!mCaptureTimeLapse) {
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001133 // Dont clip for time lapse capture as encoder will have enough
1134 // time to encode because of slow capture rate of time lapse.
1135 clipVideoBitRate();
1136 clipVideoFrameRate();
1137 clipVideoFrameWidth();
1138 clipVideoFrameHeight();
James Dongbe650872011-07-07 16:41:25 -07001139 setDefaultProfileIfNecessary();
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001140 }
James Dong7b06de62010-06-30 12:41:16 -07001141 return OK;
1142}
1143
James Dongbe650872011-07-07 16:41:25 -07001144// Set to use AVC baseline profile if the encoding parameters matches
1145// CAMCORDER_QUALITY_LOW profile; this is for the sake of MMS service.
1146void StagefrightRecorder::setDefaultProfileIfNecessary() {
1147 LOGV("setDefaultProfileIfNecessary");
1148
1149 camcorder_quality quality = CAMCORDER_QUALITY_LOW;
1150
1151 int64_t durationUs = mEncoderProfiles->getCamcorderProfileParamByName(
1152 "duration", mCameraId, quality) * 1000000LL;
1153
1154 int fileFormat = mEncoderProfiles->getCamcorderProfileParamByName(
1155 "file.format", mCameraId, quality);
1156
1157 int videoCodec = mEncoderProfiles->getCamcorderProfileParamByName(
1158 "vid.codec", mCameraId, quality);
1159
1160 int videoBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
1161 "vid.bps", mCameraId, quality);
1162
1163 int videoFrameRate = mEncoderProfiles->getCamcorderProfileParamByName(
1164 "vid.fps", mCameraId, quality);
1165
1166 int videoFrameWidth = mEncoderProfiles->getCamcorderProfileParamByName(
1167 "vid.width", mCameraId, quality);
1168
1169 int videoFrameHeight = mEncoderProfiles->getCamcorderProfileParamByName(
1170 "vid.height", mCameraId, quality);
1171
1172 int audioCodec = mEncoderProfiles->getCamcorderProfileParamByName(
1173 "aud.codec", mCameraId, quality);
1174
1175 int audioBitRate = mEncoderProfiles->getCamcorderProfileParamByName(
1176 "aud.bps", mCameraId, quality);
1177
1178 int audioSampleRate = mEncoderProfiles->getCamcorderProfileParamByName(
1179 "aud.hz", mCameraId, quality);
1180
1181 int audioChannels = mEncoderProfiles->getCamcorderProfileParamByName(
1182 "aud.ch", mCameraId, quality);
1183
1184 if (durationUs == mMaxFileDurationUs &&
1185 fileFormat == mOutputFormat &&
1186 videoCodec == mVideoEncoder &&
1187 videoBitRate == mVideoBitRate &&
1188 videoFrameRate == mFrameRate &&
1189 videoFrameWidth == mVideoWidth &&
1190 videoFrameHeight == mVideoHeight &&
1191 audioCodec == mAudioEncoder &&
1192 audioBitRate == mAudioBitRate &&
1193 audioSampleRate == mSampleRate &&
1194 audioChannels == mAudioChannels) {
1195 if (videoCodec == VIDEO_ENCODER_H264) {
1196 LOGI("Force to use AVC baseline profile");
1197 setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline);
1198 }
1199 }
1200}
1201
James Dong54815a72011-01-12 20:45:16 -08001202status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
1203 clipAudioBitRate();
1204 clipAudioSampleRate();
1205 clipNumberOfAudioChannels();
1206 return OK;
1207}
1208
1209void StagefrightRecorder::clipAudioBitRate() {
1210 LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
1211
1212 int minAudioBitRate =
1213 mEncoderProfiles->getAudioEncoderParamByName(
1214 "enc.aud.bps.min", mAudioEncoder);
1215 if (mAudioBitRate < minAudioBitRate) {
1216 LOGW("Intended audio encoding bit rate (%d) is too small"
1217 " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
1218 mAudioBitRate = minAudioBitRate;
1219 }
1220
1221 int maxAudioBitRate =
1222 mEncoderProfiles->getAudioEncoderParamByName(
1223 "enc.aud.bps.max", mAudioEncoder);
1224 if (mAudioBitRate > maxAudioBitRate) {
1225 LOGW("Intended audio encoding bit rate (%d) is too large"
1226 " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
1227 mAudioBitRate = maxAudioBitRate;
1228 }
1229}
1230
1231void StagefrightRecorder::clipAudioSampleRate() {
1232 LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
1233
1234 int minSampleRate =
1235 mEncoderProfiles->getAudioEncoderParamByName(
1236 "enc.aud.hz.min", mAudioEncoder);
1237 if (mSampleRate < minSampleRate) {
1238 LOGW("Intended audio sample rate (%d) is too small"
1239 " and will be set to (%d)", mSampleRate, minSampleRate);
1240 mSampleRate = minSampleRate;
1241 }
1242
1243 int maxSampleRate =
1244 mEncoderProfiles->getAudioEncoderParamByName(
1245 "enc.aud.hz.max", mAudioEncoder);
1246 if (mSampleRate > maxSampleRate) {
1247 LOGW("Intended audio sample rate (%d) is too large"
1248 " and will be set to (%d)", mSampleRate, maxSampleRate);
1249 mSampleRate = maxSampleRate;
1250 }
1251}
1252
1253void StagefrightRecorder::clipNumberOfAudioChannels() {
1254 LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
1255
1256 int minChannels =
1257 mEncoderProfiles->getAudioEncoderParamByName(
1258 "enc.aud.ch.min", mAudioEncoder);
1259 if (mAudioChannels < minChannels) {
1260 LOGW("Intended number of audio channels (%d) is too small"
1261 " and will be set to (%d)", mAudioChannels, minChannels);
1262 mAudioChannels = minChannels;
1263 }
1264
1265 int maxChannels =
1266 mEncoderProfiles->getAudioEncoderParamByName(
1267 "enc.aud.ch.max", mAudioEncoder);
1268 if (mAudioChannels > maxChannels) {
1269 LOGW("Intended number of audio channels (%d) is too large"
1270 " and will be set to (%d)", mAudioChannels, maxChannels);
1271 mAudioChannels = maxChannels;
1272 }
1273}
1274
James Dong42a18c02010-06-16 17:27:46 -07001275void StagefrightRecorder::clipVideoFrameHeight() {
1276 LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
1277 int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1278 "enc.vid.height.min", mVideoEncoder);
1279 int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1280 "enc.vid.height.max", mVideoEncoder);
1281 if (mVideoHeight < minFrameHeight) {
1282 LOGW("Intended video encoding frame height (%d) is too small"
1283 " and will be set to (%d)", mVideoHeight, minFrameHeight);
1284 mVideoHeight = minFrameHeight;
1285 } else if (mVideoHeight > maxFrameHeight) {
1286 LOGW("Intended video encoding frame height (%d) is too large"
1287 " and will be set to (%d)", mVideoHeight, maxFrameHeight);
1288 mVideoHeight = maxFrameHeight;
1289 }
1290}
1291
James Dong05c2fd52010-11-02 13:20:11 -07001292status_t StagefrightRecorder::setupCameraSource(
1293 sp<CameraSource> *cameraSource) {
James Dongb15f2ea2010-10-24 09:32:39 -07001294 status_t err = OK;
1295 if ((err = checkVideoEncoderCapabilities()) != OK) {
1296 return err;
1297 }
James Dong0c128b62010-10-08 11:59:32 -07001298 Size videoSize;
1299 videoSize.width = mVideoWidth;
1300 videoSize.height = mVideoHeight;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001301 if (mCaptureTimeLapse) {
James Dong0c128b62010-10-08 11:59:32 -07001302 mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
Wu-cheng Li42419ce2011-06-01 17:22:24 +08001303 mCamera, mCameraProxy, mCameraId,
James Dong0c128b62010-10-08 11:59:32 -07001304 videoSize, mFrameRate, mPreviewSurface,
1305 mTimeBetweenTimeLapseFrameCaptureUs);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001306 *cameraSource = mCameraSourceTimeLapse;
1307 } else {
James Dong0c128b62010-10-08 11:59:32 -07001308 *cameraSource = CameraSource::CreateFromCamera(
Wu-cheng Li42419ce2011-06-01 17:22:24 +08001309 mCamera, mCameraProxy, mCameraId, videoSize, mFrameRate,
James Dong05c2fd52010-11-02 13:20:11 -07001310 mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001311 }
Wu-cheng Li42419ce2011-06-01 17:22:24 +08001312 mCamera.clear();
1313 mCameraProxy.clear();
James Dong5df53fe2010-12-05 14:25:34 -08001314 if (*cameraSource == NULL) {
1315 return UNKNOWN_ERROR;
1316 }
1317
1318 if ((*cameraSource)->initCheck() != OK) {
1319 (*cameraSource).clear();
1320 *cameraSource = NULL;
1321 return NO_INIT;
1322 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001323
James Dongb15f2ea2010-10-24 09:32:39 -07001324 // When frame rate is not set, the actual frame rate will be set to
1325 // the current frame rate being used.
1326 if (mFrameRate == -1) {
1327 int32_t frameRate = 0;
1328 CHECK ((*cameraSource)->getFormat()->findInt32(
James Dongaac193c2010-11-10 20:43:53 -08001329 kKeyFrameRate, &frameRate));
James Dongb15f2ea2010-10-24 09:32:39 -07001330 LOGI("Frame rate is not explicitly set. Use the current frame "
1331 "rate (%d fps)", frameRate);
1332 mFrameRate = frameRate;
1333 }
1334
1335 CHECK(mFrameRate != -1);
James Dong05c2fd52010-11-02 13:20:11 -07001336
1337 mIsMetaDataStoredInVideoBuffers =
1338 (*cameraSource)->isMetaDataStoredInVideoBuffers();
1339
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001340 return OK;
1341}
1342
1343status_t StagefrightRecorder::setupVideoEncoder(
1344 sp<MediaSource> cameraSource,
1345 int32_t videoBitRate,
1346 sp<MediaSource> *source) {
1347 source->clear();
James Dong7b06de62010-06-30 12:41:16 -07001348
1349 sp<MetaData> enc_meta = new MetaData;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001350 enc_meta->setInt32(kKeyBitRate, videoBitRate);
James Dongaac193c2010-11-10 20:43:53 -08001351 enc_meta->setInt32(kKeyFrameRate, mFrameRate);
James Dong7b06de62010-06-30 12:41:16 -07001352
1353 switch (mVideoEncoder) {
1354 case VIDEO_ENCODER_H263:
1355 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
1356 break;
1357
1358 case VIDEO_ENCODER_MPEG_4_SP:
1359 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
1360 break;
1361
1362 case VIDEO_ENCODER_H264:
1363 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
1364 break;
1365
1366 default:
1367 CHECK(!"Should not be here, unsupported video encoding.");
1368 break;
1369 }
1370
1371 sp<MetaData> meta = cameraSource->getFormat();
1372
James Dong1cc31e62010-07-02 17:44:44 -07001373 int32_t width, height, stride, sliceHeight, colorFormat;
James Dong7b06de62010-06-30 12:41:16 -07001374 CHECK(meta->findInt32(kKeyWidth, &width));
1375 CHECK(meta->findInt32(kKeyHeight, &height));
1376 CHECK(meta->findInt32(kKeyStride, &stride));
1377 CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
James Dong1cc31e62010-07-02 17:44:44 -07001378 CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
James Dong7b06de62010-06-30 12:41:16 -07001379
1380 enc_meta->setInt32(kKeyWidth, width);
1381 enc_meta->setInt32(kKeyHeight, height);
James Dong52d13f02010-07-02 11:39:06 -07001382 enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
James Dong7b06de62010-06-30 12:41:16 -07001383 enc_meta->setInt32(kKeyStride, stride);
1384 enc_meta->setInt32(kKeySliceHeight, sliceHeight);
James Dong1cc31e62010-07-02 17:44:44 -07001385 enc_meta->setInt32(kKeyColorFormat, colorFormat);
James Dongeff30e32010-08-13 14:16:26 -07001386 if (mVideoTimeScale > 0) {
1387 enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
1388 }
James Dong81c929a2010-07-01 15:02:14 -07001389 if (mVideoEncoderProfile != -1) {
1390 enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
1391 }
1392 if (mVideoEncoderLevel != -1) {
1393 enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
1394 }
James Dong7b06de62010-06-30 12:41:16 -07001395
1396 OMXClient client;
1397 CHECK_EQ(client.connect(), OK);
1398
James Dong6312dd62010-12-02 14:48:23 -08001399 uint32_t encoder_flags = 0;
James Dong5fb60c72011-01-18 21:12:31 -08001400 if (mIsMetaDataStoredInVideoBuffers) {
James Dong6312dd62010-12-02 14:48:23 -08001401 encoder_flags |= OMXCodec::kHardwareCodecsOnly;
James Dong05c2fd52010-11-02 13:20:11 -07001402 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
1403 }
James Dong5f3ab062011-01-25 16:31:28 -08001404
1405 // Do not wait for all the input buffers to become available.
1406 // This give timelapse video recording faster response in
1407 // receiving output from video encoder component.
1408 if (mCaptureTimeLapse) {
1409 encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
1410 }
1411
James Dong7b06de62010-06-30 12:41:16 -07001412 sp<MediaSource> encoder = OMXCodec::Create(
1413 client.interface(), enc_meta,
Nipun Kwatra077cba42010-07-20 11:37:17 -07001414 true /* createEncoder */, cameraSource,
1415 NULL, encoder_flags);
James Dong7b06de62010-06-30 12:41:16 -07001416 if (encoder == NULL) {
James Dong6312dd62010-12-02 14:48:23 -08001417 LOGW("Failed to create the encoder");
1418 // When the encoder fails to be created, we need
1419 // release the camera source due to the camera's lock
1420 // and unlock mechanism.
1421 cameraSource->stop();
James Dong7b06de62010-06-30 12:41:16 -07001422 return UNKNOWN_ERROR;
1423 }
1424
Andreas Huber57648e42010-08-04 10:14:30 -07001425 *source = encoder;
1426
James Dong7b06de62010-06-30 12:41:16 -07001427 return OK;
1428}
1429
1430status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
James Dong54815a72011-01-12 20:45:16 -08001431 status_t status = BAD_VALUE;
1432 if (OK != (status = checkAudioEncoderCapabilities())) {
1433 return status;
1434 }
1435
James Dong7b06de62010-06-30 12:41:16 -07001436 switch(mAudioEncoder) {
1437 case AUDIO_ENCODER_AMR_NB:
1438 case AUDIO_ENCODER_AMR_WB:
1439 case AUDIO_ENCODER_AAC:
James Dong7b06de62010-06-30 12:41:16 -07001440 break;
James Dong54815a72011-01-12 20:45:16 -08001441
James Dong7b06de62010-06-30 12:41:16 -07001442 default:
1443 LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1444 return UNKNOWN_ERROR;
1445 }
1446
James Dong54815a72011-01-12 20:45:16 -08001447 sp<MediaSource> audioEncoder = createAudioSource();
James Dong7b06de62010-06-30 12:41:16 -07001448 if (audioEncoder == NULL) {
1449 return UNKNOWN_ERROR;
1450 }
James Dong52d13f02010-07-02 11:39:06 -07001451
James Dong7b06de62010-06-30 12:41:16 -07001452 writer->addSource(audioEncoder);
1453 return OK;
1454}
1455
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001456status_t StagefrightRecorder::setupMPEG4Recording(
1457 bool useSplitCameraSource,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001458 int outputFd,
1459 int32_t videoWidth, int32_t videoHeight,
1460 int32_t videoBitRate,
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001461 int32_t *totalBitRate,
1462 sp<MediaWriter> *mediaWriter) {
1463 mediaWriter->clear();
1464 *totalBitRate = 0;
James Dong7b06de62010-06-30 12:41:16 -07001465 status_t err = OK;
James Dong2747e0e2010-11-18 20:59:13 -08001466 sp<MediaWriter> writer = new MPEG4Writer(outputFd);
Andreas Huber996dddf2010-01-25 15:30:31 -08001467
1468 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1469 || mVideoSource == VIDEO_SOURCE_CAMERA) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001470
1471 sp<MediaSource> cameraMediaSource;
1472 if (useSplitCameraSource) {
1473 LOGV("Using Split camera source");
1474 cameraMediaSource = mCameraSourceSplitter->createClient();
1475 } else {
1476 sp<CameraSource> cameraSource;
1477 err = setupCameraSource(&cameraSource);
1478 cameraMediaSource = cameraSource;
1479 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001480 if ((videoWidth != mVideoWidth) || (videoHeight != mVideoHeight)) {
1481 // Use downsampling from the original source.
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001482 cameraMediaSource =
1483 new VideoSourceDownSampler(cameraMediaSource, videoWidth, videoHeight);
1484 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001485 if (err != OK) {
1486 return err;
1487 }
1488
Andreas Huber57648e42010-08-04 10:14:30 -07001489 sp<MediaSource> encoder;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001490 err = setupVideoEncoder(cameraMediaSource, videoBitRate, &encoder);
1491 if (err != OK) {
1492 return err;
1493 }
1494
Andreas Huber57648e42010-08-04 10:14:30 -07001495 writer->addSource(encoder);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001496 *totalBitRate += videoBitRate;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001497 }
1498
James Dong44b004b2011-01-19 20:42:19 -08001499 // Audio source is added at the end if it exists.
1500 // This help make sure that the "recoding" sound is suppressed for
1501 // camcorder applications in the recorded files.
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001502 if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
James Dong44b004b2011-01-19 20:42:19 -08001503 err = setupAudioEncoder(writer);
1504 if (err != OK) return err;
1505 *totalBitRate += mAudioBitRate;
1506 }
1507
James Dong63299c02010-07-28 10:08:03 -07001508 if (mInterleaveDurationUs > 0) {
1509 reinterpret_cast<MPEG4Writer *>(writer.get())->
1510 setInterleaveDuration(mInterleaveDurationUs);
1511 }
James Dong987ab482011-05-11 19:09:25 -07001512 if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
1513 reinterpret_cast<MPEG4Writer *>(writer.get())->
1514 setGeoData(mLatitudex10000, mLongitudex10000);
1515 }
James Dong18244862010-05-11 14:57:02 -07001516 if (mMaxFileDurationUs != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001517 writer->setMaxFileDuration(mMaxFileDurationUs);
James Dong18244862010-05-11 14:57:02 -07001518 }
1519 if (mMaxFileSizeBytes != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001520 writer->setMaxFileSize(mMaxFileSizeBytes);
James Dong18244862010-05-11 14:57:02 -07001521 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001522
James Dong13a33162011-05-09 16:56:25 -07001523 mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
1524 if (mStartTimeOffsetMs > 0) {
1525 reinterpret_cast<MPEG4Writer *>(writer.get())->
1526 setStartTimeOffsetMs(mStartTimeOffsetMs);
1527 }
1528
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001529 writer->setListener(mListener);
1530 *mediaWriter = writer;
1531 return OK;
1532}
1533
1534void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
1535 sp<MetaData> *meta) {
1536 (*meta)->setInt64(kKeyTime, startTimeUs);
1537 (*meta)->setInt32(kKeyFileType, mOutputFormat);
1538 (*meta)->setInt32(kKeyBitRate, totalBitRate);
1539 (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
James Dongeff30e32010-08-13 14:16:26 -07001540 if (mMovieTimeScale > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001541 (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
James Dongeff30e32010-08-13 14:16:26 -07001542 }
James Dong09936ed2010-06-24 19:04:27 -07001543 if (mTrackEveryTimeDurationUs > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001544 (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -07001545 }
James Dongb9d7e012010-11-09 11:15:47 -08001546 if (mRotationDegrees != 0) {
1547 (*meta)->setInt32(kKeyRotation, mRotationDegrees);
1548 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001549}
1550
1551status_t StagefrightRecorder::startMPEG4Recording() {
1552 if (mCaptureAuxVideo) {
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001553 if (!mCaptureTimeLapse) {
1554 LOGE("Auxiliary video can be captured only in time lapse mode");
1555 return UNKNOWN_ERROR;
1556 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001557 LOGV("Creating MediaSourceSplitter");
1558 sp<CameraSource> cameraSource;
1559 status_t err = setupCameraSource(&cameraSource);
1560 if (err != OK) {
1561 return err;
1562 }
1563 mCameraSourceSplitter = new MediaSourceSplitter(cameraSource);
1564 } else {
1565 mCameraSourceSplitter = NULL;
1566 }
1567
1568 int32_t totalBitRate;
1569 status_t err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001570 mOutputFd, mVideoWidth, mVideoHeight,
1571 mVideoBitRate, &totalBitRate, &mWriter);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001572 if (err != OK) {
1573 return err;
1574 }
1575
1576 int64_t startTimeUs = systemTime() / 1000;
1577 sp<MetaData> meta = new MetaData;
1578 setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
1579
1580 err = mWriter->start(meta.get());
1581 if (err != OK) {
1582 return err;
1583 }
1584
1585 if (mCaptureAuxVideo) {
1586 CHECK(mOutputFdAux >= 0);
1587 if (mWriterAux != NULL) {
1588 LOGE("Auxiliary File writer is not avaialble");
1589 return UNKNOWN_ERROR;
1590 }
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001591 if ((mAuxVideoWidth > mVideoWidth) || (mAuxVideoHeight > mVideoHeight) ||
1592 ((mAuxVideoWidth == mVideoWidth) && mAuxVideoHeight == mVideoHeight)) {
1593 LOGE("Auxiliary video size (%d x %d) same or larger than the main video size (%d x %d)",
1594 mAuxVideoWidth, mAuxVideoHeight, mVideoWidth, mVideoHeight);
1595 return UNKNOWN_ERROR;
1596 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001597
1598 int32_t totalBitrateAux;
1599 err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001600 mOutputFdAux, mAuxVideoWidth, mAuxVideoHeight,
1601 mAuxVideoBitRate, &totalBitrateAux, &mWriterAux);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001602 if (err != OK) {
1603 return err;
1604 }
1605
1606 sp<MetaData> metaAux = new MetaData;
1607 setupMPEG4MetaData(startTimeUs, totalBitrateAux, &metaAux);
1608
1609 return mWriterAux->start(metaAux.get());
1610 }
1611
1612 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001613}
1614
James Dong08c74732010-06-10 12:28:15 -07001615status_t StagefrightRecorder::pause() {
James Dongc0ab2a62010-06-29 16:29:19 -07001616 LOGV("pause");
James Dong08c74732010-06-10 12:28:15 -07001617 if (mWriter == NULL) {
1618 return UNKNOWN_ERROR;
1619 }
1620 mWriter->pause();
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001621
1622 if (mCaptureAuxVideo) {
1623 if (mWriterAux == NULL) {
1624 return UNKNOWN_ERROR;
1625 }
1626 mWriterAux->pause();
1627 }
1628
Gloria Wang62e05a62011-02-23 11:47:34 -08001629 if (mStarted) {
1630 mStarted = false;
1631
1632 uint32_t params = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001633 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -08001634 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1635 }
1636 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1637 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1638 }
1639
1640 addBatteryData(params);
1641 }
1642
1643
James Dong08c74732010-06-10 12:28:15 -07001644 return OK;
1645}
1646
Andreas Huberea6a38c2009-11-16 15:43:38 -08001647status_t StagefrightRecorder::stop() {
James Dongc0ab2a62010-06-29 16:29:19 -07001648 LOGV("stop");
James Dongd0366622010-08-18 19:10:39 -07001649 status_t err = OK;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001650
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001651 if (mCaptureTimeLapse && mCameraSourceTimeLapse != NULL) {
1652 mCameraSourceTimeLapse->startQuickReadReturns();
1653 mCameraSourceTimeLapse = NULL;
1654 }
1655
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001656 if (mCaptureAuxVideo) {
1657 if (mWriterAux != NULL) {
1658 mWriterAux->stop();
1659 mWriterAux.clear();
1660 }
1661 }
1662
James Dongc0ab2a62010-06-29 16:29:19 -07001663 if (mWriter != NULL) {
James Dongd0366622010-08-18 19:10:39 -07001664 err = mWriter->stop();
James Dong7b06de62010-06-30 12:41:16 -07001665 mWriter.clear();
Andreas Huberea6a38c2009-11-16 15:43:38 -08001666 }
1667
James Dongc6280bc2010-08-11 17:12:39 -07001668 if (mOutputFd >= 0) {
1669 ::close(mOutputFd);
1670 mOutputFd = -1;
1671 }
1672
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001673 if (mCaptureAuxVideo) {
1674 if (mOutputFdAux >= 0) {
1675 ::close(mOutputFdAux);
1676 mOutputFdAux = -1;
1677 }
1678 }
1679
Gloria Wang62e05a62011-02-23 11:47:34 -08001680 if (mStarted) {
1681 mStarted = false;
1682
1683 uint32_t params = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001684 if (mAudioSource != AUDIO_SOURCE_CNT) {
Gloria Wang62e05a62011-02-23 11:47:34 -08001685 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1686 }
1687 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1688 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1689 }
1690
1691 addBatteryData(params);
1692 }
1693
1694
James Dongd0366622010-08-18 19:10:39 -07001695 return err;
James Dongc0ab2a62010-06-29 16:29:19 -07001696}
1697
1698status_t StagefrightRecorder::close() {
1699 LOGV("close");
1700 stop();
1701
Andreas Huberea6a38c2009-11-16 15:43:38 -08001702 return OK;
1703}
1704
1705status_t StagefrightRecorder::reset() {
James Dongc0ab2a62010-06-29 16:29:19 -07001706 LOGV("reset");
Andreas Huberea6a38c2009-11-16 15:43:38 -08001707 stop();
1708
James Dongabed93a2010-04-22 17:27:04 -07001709 // No audio or video source by default
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001710 mAudioSource = AUDIO_SOURCE_CNT;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001711 mVideoSource = VIDEO_SOURCE_LIST_END;
James Dongabed93a2010-04-22 17:27:04 -07001712
1713 // Default parameters
1714 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
1715 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
1716 mVideoEncoder = VIDEO_ENCODER_H263;
1717 mVideoWidth = 176;
1718 mVideoHeight = 144;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001719 mAuxVideoWidth = 176;
1720 mAuxVideoHeight = 144;
James Dongb15f2ea2010-10-24 09:32:39 -07001721 mFrameRate = -1;
James Dongabed93a2010-04-22 17:27:04 -07001722 mVideoBitRate = 192000;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001723 mAuxVideoBitRate = 192000;
James Dongabed93a2010-04-22 17:27:04 -07001724 mSampleRate = 8000;
1725 mAudioChannels = 1;
1726 mAudioBitRate = 12200;
James Dongc6161722010-05-20 17:55:52 -07001727 mInterleaveDurationUs = 0;
James Dong52d13f02010-07-02 11:39:06 -07001728 mIFramesIntervalSec = 1;
James Dong57e7f832010-06-24 19:55:31 -07001729 mAudioSourceNode = 0;
James Dong6feaa462010-06-20 08:20:54 -07001730 mUse64BitFileOffset = false;
James Dongeff30e32010-08-13 14:16:26 -07001731 mMovieTimeScale = -1;
1732 mAudioTimeScale = -1;
1733 mVideoTimeScale = -1;
James Dong09936ed2010-06-24 19:04:27 -07001734 mCameraId = 0;
James Dong13a33162011-05-09 16:56:25 -07001735 mStartTimeOffsetMs = -1;
James Dong81c929a2010-07-01 15:02:14 -07001736 mVideoEncoderProfile = -1;
1737 mVideoEncoderLevel = -1;
1738 mMaxFileDurationUs = 0;
1739 mMaxFileSizeBytes = 0;
James Dong09936ed2010-06-24 19:04:27 -07001740 mTrackEveryTimeDurationUs = 0;
Nipun Kwatrad26920a2010-06-30 18:51:31 -07001741 mCaptureTimeLapse = false;
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001742 mTimeBetweenTimeLapseFrameCaptureUs = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001743 mCaptureAuxVideo = false;
1744 mCameraSourceSplitter = NULL;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001745 mCameraSourceTimeLapse = NULL;
James Dong05c2fd52010-11-02 13:20:11 -07001746 mIsMetaDataStoredInVideoBuffers = false;
James Dong42a18c02010-06-16 17:27:46 -07001747 mEncoderProfiles = MediaProfiles::getInstance();
James Dong5d0b7832010-11-10 12:26:58 -08001748 mRotationDegrees = 0;
James Dong987ab482011-05-11 19:09:25 -07001749 mLatitudex10000 = -3600000;
1750 mLongitudex10000 = -3600000;
James Dongabed93a2010-04-22 17:27:04 -07001751
Andreas Huberea6a38c2009-11-16 15:43:38 -08001752 mOutputFd = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001753 mOutputFdAux = -1;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001754
1755 return OK;
1756}
1757
1758status_t StagefrightRecorder::getMaxAmplitude(int *max) {
James Dongc0ab2a62010-06-29 16:29:19 -07001759 LOGV("getMaxAmplitude");
1760
1761 if (max == NULL) {
1762 LOGE("Null pointer argument");
1763 return BAD_VALUE;
1764 }
1765
James Dong57e7f832010-06-24 19:55:31 -07001766 if (mAudioSourceNode != 0) {
1767 *max = mAudioSourceNode->getMaxAmplitude();
1768 } else {
1769 *max = 0;
1770 }
Andreas Huber996dddf2010-01-25 15:30:31 -08001771
1772 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001773}
1774
James Dong3f51fa72010-08-18 03:32:26 -07001775status_t StagefrightRecorder::dump(
1776 int fd, const Vector<String16>& args) const {
1777 LOGV("dump");
James Dong929642e2010-07-08 11:16:11 -07001778 const size_t SIZE = 256;
1779 char buffer[SIZE];
1780 String8 result;
James Dong3f51fa72010-08-18 03:32:26 -07001781 if (mWriter != 0) {
1782 mWriter->dump(fd, args);
1783 } else {
1784 snprintf(buffer, SIZE, " No file writer\n");
1785 result.append(buffer);
1786 }
1787 snprintf(buffer, SIZE, " Recorder: %p\n", this);
James Dong929642e2010-07-08 11:16:11 -07001788 snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
1789 result.append(buffer);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001790 snprintf(buffer, SIZE, " Output file Auxiliary (fd %d):\n", mOutputFdAux);
1791 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001792 snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
1793 result.append(buffer);
1794 snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1795 result.append(buffer);
1796 snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
1797 result.append(buffer);
1798 snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1799 result.append(buffer);
1800 snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
1801 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001802 snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1803 result.append(buffer);
1804 snprintf(buffer, SIZE, " Audio\n");
1805 result.append(buffer);
1806 snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
1807 result.append(buffer);
1808 snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
1809 result.append(buffer);
1810 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
1811 result.append(buffer);
1812 snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
1813 result.append(buffer);
1814 snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
1815 result.append(buffer);
1816 snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1817 result.append(buffer);
1818 snprintf(buffer, SIZE, " Video\n");
1819 result.append(buffer);
1820 snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
1821 result.append(buffer);
1822 snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
1823 result.append(buffer);
James Dong13a33162011-05-09 16:56:25 -07001824 snprintf(buffer, SIZE, " Start time offset (ms): %d\n", mStartTimeOffsetMs);
1825 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001826 snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
1827 result.append(buffer);
1828 snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
1829 result.append(buffer);
1830 snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
1831 result.append(buffer);
James Dong52d13f02010-07-02 11:39:06 -07001832 snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec);
James Dong929642e2010-07-08 11:16:11 -07001833 result.append(buffer);
1834 snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1835 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001836 snprintf(buffer, SIZE, " Aux Frame size (pixels): %dx%d\n", mAuxVideoWidth, mAuxVideoHeight);
1837 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001838 snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
1839 result.append(buffer);
1840 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
1841 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001842 snprintf(buffer, SIZE, " Aux Bit rate (bps): %d\n", mAuxVideoBitRate);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001843 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001844 ::write(fd, result.string(), result.size());
1845 return OK;
1846}
Andreas Huberea6a38c2009-11-16 15:43:38 -08001847} // namespace android