blob: e3dfabb02493f9171462b2ede6dc5d04b3b5e5c0 [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>
Andreas Huberea6a38c2009-11-16 15:43:38 -080029#include <media/stagefright/CameraSource.h>
Nipun Kwatra239f2e52010-08-31 15:35:44 -070030#include <media/stagefright/VideoSourceDownSampler.h>
Nipun Kwatraf9b80182010-07-12 09:17:14 -070031#include <media/stagefright/CameraSourceTimeLapse.h>
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070032#include <media/stagefright/MediaSourceSplitter.h>
Andreas Huber9adf4662010-10-12 14:17:45 -070033#include <media/stagefright/MPEG2TSWriter.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080034#include <media/stagefright/MPEG4Writer.h>
35#include <media/stagefright/MediaDebug.h>
36#include <media/stagefright/MediaDefs.h>
37#include <media/stagefright/MetaData.h>
38#include <media/stagefright/OMXClient.h>
39#include <media/stagefright/OMXCodec.h>
James Dong42a18c02010-06-16 17:27:46 -070040#include <media/MediaProfiles.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080041#include <camera/ICamera.h>
James Dong2cd841d2010-05-11 11:46:59 -070042#include <camera/CameraParameters.h>
Jamie Gennis85cfdd02010-08-10 16:37:53 -070043#include <surfaceflinger/Surface.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080044#include <utils/Errors.h>
James Dongb00e2462010-04-26 17:48:26 -070045#include <sys/types.h>
James Dongabed93a2010-04-22 17:27:04 -070046#include <ctype.h>
Nipun Kwatra453e92f2010-08-04 14:26:45 -070047#include <unistd.h>
Andreas Huberea6a38c2009-11-16 15:43:38 -080048
Andreas Huber57648e42010-08-04 10:14:30 -070049#include "ARTPWriter.h"
50
Andreas Huberea6a38c2009-11-16 15:43:38 -080051namespace android {
52
Gloria Wang62e05a62011-02-23 11:47:34 -080053// To collect the encoder usage for the battery app
54static void addBatteryData(uint32_t params) {
55 sp<IBinder> binder =
56 defaultServiceManager()->getService(String16("media.player"));
57 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
58 CHECK(service.get() != NULL);
59
60 service->addBatteryData(params);
61}
62
63
James Dongc0ab2a62010-06-29 16:29:19 -070064StagefrightRecorder::StagefrightRecorder()
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -070065 : mWriter(NULL), mWriterAux(NULL),
Gloria Wang62e05a62011-02-23 11:47:34 -080066 mOutputFd(-1), mOutputFdAux(-1),
67 mAudioSource(AUDIO_SOURCE_LIST_END),
68 mVideoSource(VIDEO_SOURCE_LIST_END),
69 mStarted(false) {
James Dongc0ab2a62010-06-29 16:29:19 -070070
71 LOGV("Constructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080072 reset();
73}
74
75StagefrightRecorder::~StagefrightRecorder() {
James Dongc0ab2a62010-06-29 16:29:19 -070076 LOGV("Destructor");
Andreas Huberea6a38c2009-11-16 15:43:38 -080077 stop();
Andreas Huberea6a38c2009-11-16 15:43:38 -080078}
79
80status_t StagefrightRecorder::init() {
James Dongc0ab2a62010-06-29 16:29:19 -070081 LOGV("init");
Andreas Huberea6a38c2009-11-16 15:43:38 -080082 return OK;
83}
84
85status_t StagefrightRecorder::setAudioSource(audio_source as) {
James Dongc0ab2a62010-06-29 16:29:19 -070086 LOGV("setAudioSource: %d", as);
87 if (as < AUDIO_SOURCE_DEFAULT ||
88 as >= AUDIO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -070089 LOGE("Invalid audio source: %d", as);
James Dongc0ab2a62010-06-29 16:29:19 -070090 return BAD_VALUE;
91 }
92
93 if (as == AUDIO_SOURCE_DEFAULT) {
94 mAudioSource = AUDIO_SOURCE_MIC;
95 } else {
96 mAudioSource = as;
97 }
Andreas Huberea6a38c2009-11-16 15:43:38 -080098
99 return OK;
100}
101
102status_t StagefrightRecorder::setVideoSource(video_source vs) {
James Dongc0ab2a62010-06-29 16:29:19 -0700103 LOGV("setVideoSource: %d", vs);
104 if (vs < VIDEO_SOURCE_DEFAULT ||
105 vs >= VIDEO_SOURCE_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700106 LOGE("Invalid video source: %d", vs);
James Dongc0ab2a62010-06-29 16:29:19 -0700107 return BAD_VALUE;
108 }
109
110 if (vs == VIDEO_SOURCE_DEFAULT) {
111 mVideoSource = VIDEO_SOURCE_CAMERA;
112 } else {
113 mVideoSource = vs;
114 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800115
116 return OK;
117}
118
119status_t StagefrightRecorder::setOutputFormat(output_format of) {
James Dongc0ab2a62010-06-29 16:29:19 -0700120 LOGV("setOutputFormat: %d", of);
121 if (of < OUTPUT_FORMAT_DEFAULT ||
122 of >= OUTPUT_FORMAT_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700123 LOGE("Invalid output format: %d", of);
James Dongc0ab2a62010-06-29 16:29:19 -0700124 return BAD_VALUE;
125 }
126
127 if (of == OUTPUT_FORMAT_DEFAULT) {
128 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
129 } else {
130 mOutputFormat = of;
131 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800132
133 return OK;
134}
135
136status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
James Dongc0ab2a62010-06-29 16:29:19 -0700137 LOGV("setAudioEncoder: %d", ae);
138 if (ae < AUDIO_ENCODER_DEFAULT ||
139 ae >= AUDIO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700140 LOGE("Invalid audio encoder: %d", ae);
James Dongc0ab2a62010-06-29 16:29:19 -0700141 return BAD_VALUE;
142 }
143
144 if (ae == AUDIO_ENCODER_DEFAULT) {
145 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
146 } else {
147 mAudioEncoder = ae;
148 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800149
150 return OK;
151}
152
153status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
James Dongc0ab2a62010-06-29 16:29:19 -0700154 LOGV("setVideoEncoder: %d", ve);
155 if (ve < VIDEO_ENCODER_DEFAULT ||
156 ve >= VIDEO_ENCODER_LIST_END) {
James Dong7b06de62010-06-30 12:41:16 -0700157 LOGE("Invalid video encoder: %d", ve);
James Dongc0ab2a62010-06-29 16:29:19 -0700158 return BAD_VALUE;
159 }
160
161 if (ve == VIDEO_ENCODER_DEFAULT) {
162 mVideoEncoder = VIDEO_ENCODER_H263;
163 } else {
164 mVideoEncoder = ve;
165 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800166
167 return OK;
168}
169
170status_t StagefrightRecorder::setVideoSize(int width, int height) {
James Dongc0ab2a62010-06-29 16:29:19 -0700171 LOGV("setVideoSize: %dx%d", width, height);
James Dong2cd841d2010-05-11 11:46:59 -0700172 if (width <= 0 || height <= 0) {
173 LOGE("Invalid video size: %dx%d", width, height);
174 return BAD_VALUE;
175 }
176
177 // Additional check on the dimension will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800178 mVideoWidth = width;
179 mVideoHeight = height;
180
181 return OK;
182}
183
184status_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
James Dongc0ab2a62010-06-29 16:29:19 -0700185 LOGV("setVideoFrameRate: %d", frames_per_second);
James Dongb15f2ea2010-10-24 09:32:39 -0700186 if ((frames_per_second <= 0 && frames_per_second != -1) ||
187 frames_per_second > 120) {
James Dong2cd841d2010-05-11 11:46:59 -0700188 LOGE("Invalid video frame rate: %d", frames_per_second);
189 return BAD_VALUE;
190 }
191
192 // Additional check on the frame rate will be performed later
Andreas Huberea6a38c2009-11-16 15:43:38 -0800193 mFrameRate = frames_per_second;
194
195 return OK;
196}
197
198status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
James Dong71d714c2010-06-09 15:57:48 -0700199 LOGV("setCamera");
James Dongb00e2462010-04-26 17:48:26 -0700200 if (camera == 0) {
201 LOGE("camera is NULL");
James Dong7b06de62010-06-30 12:41:16 -0700202 return BAD_VALUE;
James Dongb00e2462010-04-26 17:48:26 -0700203 }
204
James Dong0c128b62010-10-08 11:59:32 -0700205 mCamera = camera;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800206 return OK;
207}
208
Jamie Gennis85cfdd02010-08-10 16:37:53 -0700209status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
James Dongc0ab2a62010-06-29 16:29:19 -0700210 LOGV("setPreviewSurface: %p", surface.get());
Andreas Huberea6a38c2009-11-16 15:43:38 -0800211 mPreviewSurface = surface;
212
213 return OK;
214}
215
216status_t StagefrightRecorder::setOutputFile(const char *path) {
James Dong7b06de62010-06-30 12:41:16 -0700217 LOGE("setOutputFile(const char*) must not be called");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800218 // We don't actually support this at all, as the media_server process
219 // no longer has permissions to create files.
220
James Dong7b06de62010-06-30 12:41:16 -0700221 return -EPERM;
Andreas Huberea6a38c2009-11-16 15:43:38 -0800222}
223
224status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
James Dongc0ab2a62010-06-29 16:29:19 -0700225 LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800226 // These don't make any sense, do they?
227 CHECK_EQ(offset, 0);
228 CHECK_EQ(length, 0);
229
James Dong7b06de62010-06-30 12:41:16 -0700230 if (fd < 0) {
231 LOGE("Invalid file descriptor: %d", fd);
232 return -EBADF;
233 }
234
Andreas Huberea6a38c2009-11-16 15:43:38 -0800235 if (mOutputFd >= 0) {
236 ::close(mOutputFd);
237 }
238 mOutputFd = dup(fd);
239
240 return OK;
241}
242
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700243status_t StagefrightRecorder::setOutputFileAuxiliary(int fd) {
244 LOGV("setOutputFileAuxiliary: %d", fd);
245
246 if (fd < 0) {
247 LOGE("Invalid file descriptor: %d", fd);
248 return -EBADF;
249 }
250
251 mCaptureAuxVideo = true;
252
253 if (mOutputFdAux >= 0) {
254 ::close(mOutputFdAux);
255 }
256 mOutputFdAux = dup(fd);
257
258 return OK;
259}
260
James Dongabed93a2010-04-22 17:27:04 -0700261// Attempt to parse an int64 literal optionally surrounded by whitespace,
262// returns true on success, false otherwise.
James Dong2cd841d2010-05-11 11:46:59 -0700263static bool safe_strtoi64(const char *s, int64_t *val) {
James Dongabed93a2010-04-22 17:27:04 -0700264 char *end;
James Dong75fb2382011-02-08 15:41:58 -0800265
266 // It is lame, but according to man page, we have to set errno to 0
267 // before calling strtoll().
268 errno = 0;
James Dong2cd841d2010-05-11 11:46:59 -0700269 *val = strtoll(s, &end, 10);
Andreas Huberea6a38c2009-11-16 15:43:38 -0800270
James Dongabed93a2010-04-22 17:27:04 -0700271 if (end == s || errno == ERANGE) {
272 return false;
273 }
274
275 // Skip trailing whitespace
276 while (isspace(*end)) {
277 ++end;
278 }
279
280 // For a successful return, the string must contain nothing but a valid
281 // int64 literal optionally surrounded by whitespace.
282
283 return *end == '\0';
284}
285
James Dong2cd841d2010-05-11 11:46:59 -0700286// Return true if the value is in [0, 0x007FFFFFFF]
287static bool safe_strtoi32(const char *s, int32_t *val) {
288 int64_t temp;
289 if (safe_strtoi64(s, &temp)) {
290 if (temp >= 0 && temp <= 0x007FFFFFFF) {
291 *val = static_cast<int32_t>(temp);
292 return true;
293 }
294 }
295 return false;
296}
297
James Dongabed93a2010-04-22 17:27:04 -0700298// Trim both leading and trailing whitespace from the given string.
299static void TrimString(String8 *s) {
300 size_t num_bytes = s->bytes();
301 const char *data = s->string();
302
303 size_t leading_space = 0;
304 while (leading_space < num_bytes && isspace(data[leading_space])) {
305 ++leading_space;
306 }
307
308 size_t i = num_bytes;
309 while (i > leading_space && isspace(data[i - 1])) {
310 --i;
311 }
312
313 s->setTo(String8(&data[leading_space], i - leading_space));
314}
315
316status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
317 LOGV("setParamAudioSamplingRate: %d", sampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700318 if (sampleRate <= 0) {
319 LOGE("Invalid audio sampling rate: %d", sampleRate);
320 return BAD_VALUE;
321 }
322
323 // Additional check on the sample rate will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700324 mSampleRate = sampleRate;
325 return OK;
326}
327
328status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
329 LOGV("setParamAudioNumberOfChannels: %d", channels);
James Dong2cd841d2010-05-11 11:46:59 -0700330 if (channels <= 0 || channels >= 3) {
331 LOGE("Invalid number of audio channels: %d", channels);
James Dong7b06de62010-06-30 12:41:16 -0700332 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700333 }
334
335 // Additional check on the number of channels will be performed later.
James Dongabed93a2010-04-22 17:27:04 -0700336 mAudioChannels = channels;
337 return OK;
338}
339
340status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
341 LOGV("setParamAudioEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700342 if (bitRate <= 0) {
343 LOGE("Invalid audio encoding bit rate: %d", bitRate);
344 return BAD_VALUE;
345 }
346
347 // The target bit rate may not be exactly the same as the requested.
348 // It depends on many factors, such as rate control, and the bit rate
349 // range that a specific encoder supports. The mismatch between the
350 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700351 mAudioBitRate = bitRate;
352 return OK;
353}
354
355status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
356 LOGV("setParamVideoEncodingBitRate: %d", bitRate);
James Dong2cd841d2010-05-11 11:46:59 -0700357 if (bitRate <= 0) {
358 LOGE("Invalid video encoding bit rate: %d", bitRate);
359 return BAD_VALUE;
360 }
361
362 // The target bit rate may not be exactly the same as the requested.
363 // It depends on many factors, such as rate control, and the bit rate
364 // range that a specific encoder supports. The mismatch between the
365 // the target and requested bit rate will NOT be treated as an error.
James Dongabed93a2010-04-22 17:27:04 -0700366 mVideoBitRate = bitRate;
367 return OK;
368}
369
James Dongb9d7e012010-11-09 11:15:47 -0800370// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
371status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
372 LOGV("setParamVideoRotation: %d", degrees);
373 if (degrees < 0 || degrees % 90 != 0) {
374 LOGE("Unsupported video rotation angle: %d", degrees);
375 return BAD_VALUE;
376 }
377 mRotationDegrees = degrees % 360;
378 return OK;
379}
380
James Dong7b06de62010-06-30 12:41:16 -0700381status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
382 LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
James Dong26ea64c2010-12-20 11:39:38 -0800383
384 // This is meant for backward compatibility for MediaRecorder.java
Nipun Kwatrafb457482010-08-18 15:19:19 -0700385 if (timeUs <= 0) {
386 LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
387 timeUs = 0; // Disable the duration limit for zero or negative values.
388 } else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
James Dong7b06de62010-06-30 12:41:16 -0700389 LOGE("Max file duration is too short: %lld us", timeUs);
390 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700391 }
Nipun Kwatrafb457482010-08-18 15:19:19 -0700392
James Dong5cdcf162010-11-30 18:18:08 -0800393 if (timeUs <= 15 * 1000000LL) {
394 LOGW("Target duration (%lld us) too short to be respected", timeUs);
395 }
James Dong7b06de62010-06-30 12:41:16 -0700396 mMaxFileDurationUs = timeUs;
397 return OK;
398}
399
400status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
401 LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
James Dong26ea64c2010-12-20 11:39:38 -0800402
403 // This is meant for backward compatibility for MediaRecorder.java
404 if (bytes <= 0) {
405 LOGW("Max file size is not positive: %lld bytes. "
406 "Disabling file size limit.", bytes);
407 bytes = 0; // Disable the file size limit for zero or negative values.
408 } else if (bytes <= 1024) { // XXX: 1 kB
James Dong7b06de62010-06-30 12:41:16 -0700409 LOGE("Max file size is too small: %lld bytes", bytes);
410 return BAD_VALUE;
411 }
James Dong5cdcf162010-11-30 18:18:08 -0800412
413 if (bytes <= 100 * 1024) {
414 LOGW("Target file size (%lld bytes) is too small to be respected", bytes);
415 }
416
James Dong7b06de62010-06-30 12:41:16 -0700417 mMaxFileSizeBytes = bytes;
James Dongabed93a2010-04-22 17:27:04 -0700418 return OK;
419}
420
James Dong3300e962010-04-21 16:14:15 -0700421status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
422 LOGV("setParamInterleaveDuration: %d", durationUs);
James Dong1244eab2010-06-08 11:58:53 -0700423 if (durationUs <= 500000) { // 500 ms
424 // If interleave duration is too small, it is very inefficient to do
425 // interleaving since the metadata overhead will count for a significant
426 // portion of the saved contents
James Dong2cd841d2010-05-11 11:46:59 -0700427 LOGE("Audio/video interleave duration is too small: %d us", durationUs);
428 return BAD_VALUE;
James Dong1244eab2010-06-08 11:58:53 -0700429 } else if (durationUs >= 10000000) { // 10 seconds
430 // If interleaving duration is too large, it can cause the recording
431 // session to use too much memory since we have to save the output
432 // data before we write them out
433 LOGE("Audio/video interleave duration is too large: %d us", durationUs);
434 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700435 }
James Dong3300e962010-04-21 16:14:15 -0700436 mInterleaveDurationUs = durationUs;
437 return OK;
438}
James Dong2cd841d2010-05-11 11:46:59 -0700439
James Dong52d13f02010-07-02 11:39:06 -0700440// If seconds < 0, only the first frame is I frame, and rest are all P frames
441// If seconds == 0, all frames are encoded as I frames. No P frames
442// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames
443status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
444 LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
445 mIFramesIntervalSec = seconds;
James Dong1244eab2010-06-08 11:58:53 -0700446 return OK;
447}
448
James Dong6feaa462010-06-20 08:20:54 -0700449status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
450 LOGV("setParam64BitFileOffset: %s",
451 use64Bit? "use 64 bit file offset": "use 32 bit file offset");
452 mUse64BitFileOffset = use64Bit;
453 return OK;
454}
455
James Dong09936ed2010-06-24 19:04:27 -0700456status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
457 LOGV("setParamVideoCameraId: %d", cameraId);
458 if (cameraId < 0) {
459 return BAD_VALUE;
460 }
461 mCameraId = cameraId;
462 return OK;
463}
464
James Dong09936ed2010-06-24 19:04:27 -0700465status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
466 LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
467 if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
James Dong7b06de62010-06-30 12:41:16 -0700468 LOGE("Tracking time duration too short: %lld us", timeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -0700469 return BAD_VALUE;
470 }
471 mTrackEveryTimeDurationUs = timeDurationUs;
472 return OK;
473}
474
James Dong81c929a2010-07-01 15:02:14 -0700475status_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
476 LOGV("setParamVideoEncoderProfile: %d", profile);
477
478 // Additional check will be done later when we load the encoder.
479 // For now, we are accepting values defined in OpenMAX IL.
480 mVideoEncoderProfile = profile;
481 return OK;
482}
483
484status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
485 LOGV("setParamVideoEncoderLevel: %d", level);
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 mVideoEncoderLevel = level;
490 return OK;
491}
492
James Dong52d13f02010-07-02 11:39:06 -0700493status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
494 LOGV("setParamMovieTimeScale: %d", timeScale);
495
496 // The range is set to be the same as the audio's time scale range
497 // since audio's time scale has a wider range.
498 if (timeScale < 600 || timeScale > 96000) {
499 LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
500 return BAD_VALUE;
501 }
502 mMovieTimeScale = timeScale;
503 return OK;
504}
505
506status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
507 LOGV("setParamVideoTimeScale: %d", timeScale);
508
509 // 60000 is chosen to make sure that each video frame from a 60-fps
510 // video has 1000 ticks.
511 if (timeScale < 600 || timeScale > 60000) {
512 LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
513 return BAD_VALUE;
514 }
515 mVideoTimeScale = timeScale;
516 return OK;
517}
518
519status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
520 LOGV("setParamAudioTimeScale: %d", timeScale);
521
522 // 96000 Hz is the highest sampling rate support in AAC.
523 if (timeScale < 600 || timeScale > 96000) {
524 LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
525 return BAD_VALUE;
526 }
527 mAudioTimeScale = timeScale;
528 return OK;
529}
530
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700531status_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
532 LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
533
534 if(timeLapseEnable == 0) {
535 mCaptureTimeLapse = false;
536 } else if (timeLapseEnable == 1) {
537 mCaptureTimeLapse = true;
538 } else {
539 return BAD_VALUE;
540 }
541 return OK;
542}
543
544status_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
545 LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
546
547 // Not allowing time more than a day
548 if (timeUs <= 0 || timeUs > 86400*1E6) {
549 LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
550 return BAD_VALUE;
551 }
552
553 mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
554 return OK;
555}
556
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700557status_t StagefrightRecorder::setParamAuxVideoWidth(int32_t width) {
558 LOGV("setParamAuxVideoWidth : %d", width);
559
560 if (width <= 0) {
561 LOGE("Width (%d) is not positive", width);
562 return BAD_VALUE;
563 }
564
565 mAuxVideoWidth = width;
566 return OK;
567}
568
569status_t StagefrightRecorder::setParamAuxVideoHeight(int32_t height) {
570 LOGV("setParamAuxVideoHeight : %d", height);
571
572 if (height <= 0) {
573 LOGE("Height (%d) is not positive", height);
574 return BAD_VALUE;
575 }
576
577 mAuxVideoHeight = height;
578 return OK;
579}
580
581status_t StagefrightRecorder::setParamAuxVideoEncodingBitRate(int32_t bitRate) {
582 LOGV("StagefrightRecorder::setParamAuxVideoEncodingBitRate: %d", bitRate);
583
584 if (bitRate <= 0) {
585 LOGE("Invalid video encoding bit rate: %d", bitRate);
586 return BAD_VALUE;
587 }
588
589 mAuxVideoBitRate = bitRate;
590 return OK;
591}
592
James Dongabed93a2010-04-22 17:27:04 -0700593status_t StagefrightRecorder::setParameter(
594 const String8 &key, const String8 &value) {
595 LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
596 if (key == "max-duration") {
James Dong2cd841d2010-05-11 11:46:59 -0700597 int64_t max_duration_ms;
James Dongabed93a2010-04-22 17:27:04 -0700598 if (safe_strtoi64(value.string(), &max_duration_ms)) {
James Dong7b06de62010-06-30 12:41:16 -0700599 return setParamMaxFileDurationUs(1000LL * max_duration_ms);
James Dongabed93a2010-04-22 17:27:04 -0700600 }
601 } else if (key == "max-filesize") {
James Dong2cd841d2010-05-11 11:46:59 -0700602 int64_t max_filesize_bytes;
James Dongabed93a2010-04-22 17:27:04 -0700603 if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
James Dong7b06de62010-06-30 12:41:16 -0700604 return setParamMaxFileSizeBytes(max_filesize_bytes);
James Dongabed93a2010-04-22 17:27:04 -0700605 }
James Dong09936ed2010-06-24 19:04:27 -0700606 } else if (key == "interleave-duration-us") {
607 int32_t durationUs;
608 if (safe_strtoi32(value.string(), &durationUs)) {
609 return setParamInterleaveDuration(durationUs);
610 }
James Dong52d13f02010-07-02 11:39:06 -0700611 } else if (key == "param-movie-time-scale") {
612 int32_t timeScale;
613 if (safe_strtoi32(value.string(), &timeScale)) {
614 return setParamMovieTimeScale(timeScale);
615 }
James Dong09936ed2010-06-24 19:04:27 -0700616 } else if (key == "param-use-64bit-offset") {
617 int32_t use64BitOffset;
618 if (safe_strtoi32(value.string(), &use64BitOffset)) {
619 return setParam64BitFileOffset(use64BitOffset != 0);
620 }
James Dong09936ed2010-06-24 19:04:27 -0700621 } else if (key == "param-track-time-status") {
622 int64_t timeDurationUs;
623 if (safe_strtoi64(value.string(), &timeDurationUs)) {
624 return setParamTrackTimeStatus(timeDurationUs);
625 }
James Dongabed93a2010-04-22 17:27:04 -0700626 } else if (key == "audio-param-sampling-rate") {
627 int32_t sampling_rate;
James Dong2cd841d2010-05-11 11:46:59 -0700628 if (safe_strtoi32(value.string(), &sampling_rate)) {
James Dongabed93a2010-04-22 17:27:04 -0700629 return setParamAudioSamplingRate(sampling_rate);
630 }
631 } else if (key == "audio-param-number-of-channels") {
632 int32_t number_of_channels;
James Dong2cd841d2010-05-11 11:46:59 -0700633 if (safe_strtoi32(value.string(), &number_of_channels)) {
James Dongabed93a2010-04-22 17:27:04 -0700634 return setParamAudioNumberOfChannels(number_of_channels);
635 }
636 } else if (key == "audio-param-encoding-bitrate") {
637 int32_t audio_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700638 if (safe_strtoi32(value.string(), &audio_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700639 return setParamAudioEncodingBitRate(audio_bitrate);
640 }
James Dong52d13f02010-07-02 11:39:06 -0700641 } else if (key == "audio-param-time-scale") {
642 int32_t timeScale;
643 if (safe_strtoi32(value.string(), &timeScale)) {
644 return setParamAudioTimeScale(timeScale);
645 }
James Dongabed93a2010-04-22 17:27:04 -0700646 } else if (key == "video-param-encoding-bitrate") {
647 int32_t video_bitrate;
James Dong2cd841d2010-05-11 11:46:59 -0700648 if (safe_strtoi32(value.string(), &video_bitrate)) {
James Dongabed93a2010-04-22 17:27:04 -0700649 return setParamVideoEncodingBitRate(video_bitrate);
650 }
James Dongb9d7e012010-11-09 11:15:47 -0800651 } else if (key == "video-param-rotation-angle-degrees") {
652 int32_t degrees;
653 if (safe_strtoi32(value.string(), &degrees)) {
654 return setParamVideoRotation(degrees);
655 }
James Dong09936ed2010-06-24 19:04:27 -0700656 } else if (key == "video-param-i-frames-interval") {
James Dong52d13f02010-07-02 11:39:06 -0700657 int32_t seconds;
658 if (safe_strtoi32(value.string(), &seconds)) {
659 return setParamVideoIFramesInterval(seconds);
James Dong1244eab2010-06-08 11:58:53 -0700660 }
James Dong81c929a2010-07-01 15:02:14 -0700661 } else if (key == "video-param-encoder-profile") {
662 int32_t profile;
663 if (safe_strtoi32(value.string(), &profile)) {
664 return setParamVideoEncoderProfile(profile);
665 }
666 } else if (key == "video-param-encoder-level") {
667 int32_t level;
668 if (safe_strtoi32(value.string(), &level)) {
669 return setParamVideoEncoderLevel(level);
670 }
James Dong09936ed2010-06-24 19:04:27 -0700671 } else if (key == "video-param-camera-id") {
672 int32_t cameraId;
673 if (safe_strtoi32(value.string(), &cameraId)) {
674 return setParamVideoCameraId(cameraId);
James Dong6feaa462010-06-20 08:20:54 -0700675 }
James Dong52d13f02010-07-02 11:39:06 -0700676 } else if (key == "video-param-time-scale") {
677 int32_t timeScale;
678 if (safe_strtoi32(value.string(), &timeScale)) {
679 return setParamVideoTimeScale(timeScale);
680 }
Nipun Kwatrad01371b2010-07-20 21:33:31 -0700681 } else if (key == "time-lapse-enable") {
682 int32_t timeLapseEnable;
683 if (safe_strtoi32(value.string(), &timeLapseEnable)) {
684 return setParamTimeLapseEnable(timeLapseEnable);
685 }
686 } else if (key == "time-between-time-lapse-frame-capture") {
687 int64_t timeBetweenTimeLapseFrameCaptureMs;
688 if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
689 return setParamTimeBetweenTimeLapseFrameCapture(
690 1000LL * timeBetweenTimeLapseFrameCaptureMs);
691 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -0700692 } else if (key == "video-aux-param-width") {
693 int32_t auxWidth;
694 if (safe_strtoi32(value.string(), &auxWidth)) {
695 return setParamAuxVideoWidth(auxWidth);
696 }
697 } else if (key == "video-aux-param-height") {
698 int32_t auxHeight;
699 if (safe_strtoi32(value.string(), &auxHeight)) {
700 return setParamAuxVideoHeight(auxHeight);
701 }
702 } else if (key == "video-aux-param-encoding-bitrate") {
703 int32_t auxVideoBitRate;
704 if (safe_strtoi32(value.string(), &auxVideoBitRate)) {
705 return setParamAuxVideoEncodingBitRate(auxVideoBitRate);
706 }
James Dongabed93a2010-04-22 17:27:04 -0700707 } else {
708 LOGE("setParameter: failed to find key %s", key.string());
James Dongabed93a2010-04-22 17:27:04 -0700709 }
James Dong2cd841d2010-05-11 11:46:59 -0700710 return BAD_VALUE;
James Dongabed93a2010-04-22 17:27:04 -0700711}
712
713status_t StagefrightRecorder::setParameters(const String8 &params) {
714 LOGV("setParameters: %s", params.string());
715 const char *cparams = params.string();
716 const char *key_start = cparams;
717 for (;;) {
718 const char *equal_pos = strchr(key_start, '=');
719 if (equal_pos == NULL) {
720 LOGE("Parameters %s miss a value", cparams);
721 return BAD_VALUE;
722 }
723 String8 key(key_start, equal_pos - key_start);
724 TrimString(&key);
725 if (key.length() == 0) {
726 LOGE("Parameters %s contains an empty key", cparams);
727 return BAD_VALUE;
728 }
729 const char *value_start = equal_pos + 1;
730 const char *semicolon_pos = strchr(value_start, ';');
731 String8 value;
732 if (semicolon_pos == NULL) {
733 value.setTo(value_start);
734 } else {
735 value.setTo(value_start, semicolon_pos - value_start);
736 }
737 if (setParameter(key, value) != OK) {
738 return BAD_VALUE;
739 }
740 if (semicolon_pos == NULL) {
741 break; // Reaches the end
742 }
743 key_start = semicolon_pos + 1;
744 }
Andreas Huberea6a38c2009-11-16 15:43:38 -0800745 return OK;
746}
747
James Dongfe1bafe2010-06-25 17:06:47 -0700748status_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
Andreas Huberea6a38c2009-11-16 15:43:38 -0800749 mListener = listener;
750
751 return OK;
752}
753
754status_t StagefrightRecorder::prepare() {
755 return OK;
756}
757
758status_t StagefrightRecorder::start() {
James Dong7b06de62010-06-30 12:41:16 -0700759 CHECK(mOutputFd >= 0);
760
Andreas Huberea6a38c2009-11-16 15:43:38 -0800761 if (mWriter != NULL) {
James Dong7b06de62010-06-30 12:41:16 -0700762 LOGE("File writer is not avaialble");
Andreas Huberea6a38c2009-11-16 15:43:38 -0800763 return UNKNOWN_ERROR;
764 }
765
Gloria Wang62e05a62011-02-23 11:47:34 -0800766 status_t status = OK;
767
Andreas Huber996dddf2010-01-25 15:30:31 -0800768 switch (mOutputFormat) {
769 case OUTPUT_FORMAT_DEFAULT:
770 case OUTPUT_FORMAT_THREE_GPP:
771 case OUTPUT_FORMAT_MPEG_4:
Gloria Wang62e05a62011-02-23 11:47:34 -0800772 status = startMPEG4Recording();
773 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800774
775 case OUTPUT_FORMAT_AMR_NB:
776 case OUTPUT_FORMAT_AMR_WB:
Gloria Wang62e05a62011-02-23 11:47:34 -0800777 status = startAMRRecording();
778 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800779
James Dong2cd841d2010-05-11 11:46:59 -0700780 case OUTPUT_FORMAT_AAC_ADIF:
781 case OUTPUT_FORMAT_AAC_ADTS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800782 status = startAACRecording();
783 break;
James Dong2cd841d2010-05-11 11:46:59 -0700784
Andreas Huber57648e42010-08-04 10:14:30 -0700785 case OUTPUT_FORMAT_RTP_AVP:
Gloria Wang62e05a62011-02-23 11:47:34 -0800786 status = startRTPRecording();
787 break;
Andreas Huber57648e42010-08-04 10:14:30 -0700788
Andreas Huber9adf4662010-10-12 14:17:45 -0700789 case OUTPUT_FORMAT_MPEG2TS:
Gloria Wang62e05a62011-02-23 11:47:34 -0800790 status = startMPEG2TSRecording();
791 break;
Andreas Huber9adf4662010-10-12 14:17:45 -0700792
Andreas Huber996dddf2010-01-25 15:30:31 -0800793 default:
James Dong7b06de62010-06-30 12:41:16 -0700794 LOGE("Unsupported output file format: %d", mOutputFormat);
Gloria Wang62e05a62011-02-23 11:47:34 -0800795 status = UNKNOWN_ERROR;
796 break;
Andreas Huber996dddf2010-01-25 15:30:31 -0800797 }
Gloria Wang62e05a62011-02-23 11:47:34 -0800798
799 if ((status == OK) && (!mStarted)) {
800 mStarted = true;
801
802 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
803 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
804 params |= IMediaPlayerService::kBatteryDataTrackAudio;
805 }
806 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
807 params |= IMediaPlayerService::kBatteryDataTrackVideo;
808 }
809
810 addBatteryData(params);
811 }
812
813 return status;
Andreas Huber996dddf2010-01-25 15:30:31 -0800814}
815
James Dongabed93a2010-04-22 17:27:04 -0700816sp<MediaSource> StagefrightRecorder::createAudioSource() {
Andreas Huber996dddf2010-01-25 15:30:31 -0800817 sp<AudioSource> audioSource =
818 new AudioSource(
819 mAudioSource,
James Dongabed93a2010-04-22 17:27:04 -0700820 mSampleRate,
James Dongd77d2a92010-06-14 17:45:35 -0700821 mAudioChannels);
Andreas Huber996dddf2010-01-25 15:30:31 -0800822
823 status_t err = audioSource->initCheck();
824
825 if (err != OK) {
James Dongabed93a2010-04-22 17:27:04 -0700826 LOGE("audio source is not initialized");
Andreas Huber996dddf2010-01-25 15:30:31 -0800827 return NULL;
828 }
829
830 sp<MetaData> encMeta = new MetaData;
James Dongabed93a2010-04-22 17:27:04 -0700831 const char *mime;
832 switch (mAudioEncoder) {
833 case AUDIO_ENCODER_AMR_NB:
834 case AUDIO_ENCODER_DEFAULT:
835 mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
836 break;
837 case AUDIO_ENCODER_AMR_WB:
838 mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
839 break;
840 case AUDIO_ENCODER_AAC:
841 mime = MEDIA_MIMETYPE_AUDIO_AAC;
842 break;
843 default:
844 LOGE("Unknown audio encoder: %d", mAudioEncoder);
845 return NULL;
846 }
847 encMeta->setCString(kKeyMIMEType, mime);
Andreas Huber996dddf2010-01-25 15:30:31 -0800848
Andreas Huber259b7c12010-02-10 15:04:31 -0800849 int32_t maxInputSize;
850 CHECK(audioSource->getFormat()->findInt32(
851 kKeyMaxInputSize, &maxInputSize));
852
853 encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
James Dongabed93a2010-04-22 17:27:04 -0700854 encMeta->setInt32(kKeyChannelCount, mAudioChannels);
855 encMeta->setInt32(kKeySampleRate, mSampleRate);
James Dong2cd841d2010-05-11 11:46:59 -0700856 encMeta->setInt32(kKeyBitRate, mAudioBitRate);
James Dongeff30e32010-08-13 14:16:26 -0700857 if (mAudioTimeScale > 0) {
858 encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
859 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800860
861 OMXClient client;
862 CHECK_EQ(client.connect(), OK);
863
864 sp<MediaSource> audioEncoder =
865 OMXCodec::Create(client.interface(), encMeta,
866 true /* createEncoder */, audioSource);
James Dong57e7f832010-06-24 19:55:31 -0700867 mAudioSourceNode = audioSource;
Andreas Huber996dddf2010-01-25 15:30:31 -0800868
869 return audioEncoder;
870}
871
James Dong2cd841d2010-05-11 11:46:59 -0700872status_t StagefrightRecorder::startAACRecording() {
873 CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
874 mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
875
876 CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
877 CHECK(mAudioSource != AUDIO_SOURCE_LIST_END);
James Dong2cd841d2010-05-11 11:46:59 -0700878
879 CHECK(0 == "AACWriter is not implemented yet");
880
881 return OK;
882}
883
Andreas Huber996dddf2010-01-25 15:30:31 -0800884status_t StagefrightRecorder::startAMRRecording() {
James Dong2cd841d2010-05-11 11:46:59 -0700885 CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
886 mOutputFormat == OUTPUT_FORMAT_AMR_WB);
887
888 if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
889 if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
890 mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
891 LOGE("Invalid encoder %d used for AMRNB recording",
892 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700893 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700894 }
James Dong2cd841d2010-05-11 11:46:59 -0700895 } else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
896 if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
897 LOGE("Invlaid encoder %d used for AMRWB recording",
898 mAudioEncoder);
James Dong7b06de62010-06-30 12:41:16 -0700899 return BAD_VALUE;
James Dong2cd841d2010-05-11 11:46:59 -0700900 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800901 }
902
James Dong2cd841d2010-05-11 11:46:59 -0700903 if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
904 LOGE("Invalid audio source: %d", mAudioSource);
James Dong7b06de62010-06-30 12:41:16 -0700905 return BAD_VALUE;
Andreas Huber996dddf2010-01-25 15:30:31 -0800906 }
907
James Dong54815a72011-01-12 20:45:16 -0800908 status_t status = BAD_VALUE;
909 if (OK != (status = checkAudioEncoderCapabilities())) {
910 return status;
911 }
Andreas Huber996dddf2010-01-25 15:30:31 -0800912
James Dong54815a72011-01-12 20:45:16 -0800913 sp<MediaSource> audioEncoder = createAudioSource();
Andreas Huber996dddf2010-01-25 15:30:31 -0800914 if (audioEncoder == NULL) {
915 return UNKNOWN_ERROR;
916 }
917
James Dong2747e0e2010-11-18 20:59:13 -0800918 mWriter = new AMRWriter(mOutputFd);
Andreas Huber996dddf2010-01-25 15:30:31 -0800919 mWriter->addSource(audioEncoder);
James Dong18244862010-05-11 14:57:02 -0700920
921 if (mMaxFileDurationUs != 0) {
922 mWriter->setMaxFileDuration(mMaxFileDurationUs);
923 }
924 if (mMaxFileSizeBytes != 0) {
925 mWriter->setMaxFileSize(mMaxFileSizeBytes);
926 }
927 mWriter->setListener(mListener);
Andreas Huber996dddf2010-01-25 15:30:31 -0800928 mWriter->start();
929
930 return OK;
931}
932
Andreas Huber57648e42010-08-04 10:14:30 -0700933status_t StagefrightRecorder::startRTPRecording() {
934 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
935
936 if ((mAudioSource != AUDIO_SOURCE_LIST_END
937 && mVideoSource != VIDEO_SOURCE_LIST_END)
938 || (mAudioSource == AUDIO_SOURCE_LIST_END
939 && mVideoSource == VIDEO_SOURCE_LIST_END)) {
940 // Must have exactly one source.
941 return BAD_VALUE;
942 }
943
944 if (mOutputFd < 0) {
945 return BAD_VALUE;
946 }
947
948 sp<MediaSource> source;
949
950 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
951 source = createAudioSource();
952 } else {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -0700953
954 sp<CameraSource> cameraSource;
955 status_t err = setupCameraSource(&cameraSource);
956 if (err != OK) {
957 return err;
958 }
959
960 err = setupVideoEncoder(cameraSource, mVideoBitRate, &source);
Andreas Huber57648e42010-08-04 10:14:30 -0700961 if (err != OK) {
962 return err;
963 }
964 }
965
James Dong2747e0e2010-11-18 20:59:13 -0800966 mWriter = new ARTPWriter(mOutputFd);
Andreas Huber57648e42010-08-04 10:14:30 -0700967 mWriter->addSource(source);
968 mWriter->setListener(mListener);
969
970 return mWriter->start();
971}
972
Andreas Huber9adf4662010-10-12 14:17:45 -0700973status_t StagefrightRecorder::startMPEG2TSRecording() {
974 CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
975
James Dong2747e0e2010-11-18 20:59:13 -0800976 sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
Andreas Huber9adf4662010-10-12 14:17:45 -0700977
978 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
979 if (mAudioEncoder != AUDIO_ENCODER_AAC) {
980 return ERROR_UNSUPPORTED;
981 }
982
983 status_t err = setupAudioEncoder(writer);
984
985 if (err != OK) {
986 return err;
987 }
988 }
989
990 if (mVideoSource == VIDEO_SOURCE_DEFAULT
991 || mVideoSource == VIDEO_SOURCE_CAMERA) {
992 if (mVideoEncoder != VIDEO_ENCODER_H264) {
993 return ERROR_UNSUPPORTED;
994 }
995
Kenny Root4a90f932010-10-14 23:58:41 -0700996 sp<CameraSource> cameraSource;
997 status_t err = setupCameraSource(&cameraSource);
998 if (err != OK) {
999 return err;
1000 }
1001
Andreas Huber9adf4662010-10-12 14:17:45 -07001002 sp<MediaSource> encoder;
Kenny Root4a90f932010-10-14 23:58:41 -07001003 err = setupVideoEncoder(cameraSource, mVideoBitRate, &encoder);
Andreas Huber9adf4662010-10-12 14:17:45 -07001004
1005 if (err != OK) {
1006 return err;
1007 }
1008
1009 writer->addSource(encoder);
1010 }
1011
1012 if (mMaxFileDurationUs != 0) {
1013 writer->setMaxFileDuration(mMaxFileDurationUs);
1014 }
1015
1016 if (mMaxFileSizeBytes != 0) {
1017 writer->setMaxFileSize(mMaxFileSizeBytes);
1018 }
1019
1020 mWriter = writer;
1021
1022 return mWriter->start();
1023}
1024
James Dong42a18c02010-06-16 17:27:46 -07001025void StagefrightRecorder::clipVideoFrameRate() {
1026 LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
1027 int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1028 "enc.vid.fps.min", mVideoEncoder);
1029 int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
1030 "enc.vid.fps.max", mVideoEncoder);
James Dongb15f2ea2010-10-24 09:32:39 -07001031 if (mFrameRate < minFrameRate && mFrameRate != -1) {
James Dong42a18c02010-06-16 17:27:46 -07001032 LOGW("Intended video encoding frame rate (%d fps) is too small"
1033 " and will be set to (%d fps)", mFrameRate, minFrameRate);
1034 mFrameRate = minFrameRate;
1035 } else if (mFrameRate > maxFrameRate) {
1036 LOGW("Intended video encoding frame rate (%d fps) is too large"
1037 " and will be set to (%d fps)", mFrameRate, maxFrameRate);
1038 mFrameRate = maxFrameRate;
1039 }
1040}
1041
1042void StagefrightRecorder::clipVideoBitRate() {
1043 LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
1044 int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1045 "enc.vid.bps.min", mVideoEncoder);
1046 int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
1047 "enc.vid.bps.max", mVideoEncoder);
1048 if (mVideoBitRate < minBitRate) {
1049 LOGW("Intended video encoding bit rate (%d bps) is too small"
1050 " and will be set to (%d bps)", mVideoBitRate, minBitRate);
1051 mVideoBitRate = minBitRate;
1052 } else if (mVideoBitRate > maxBitRate) {
1053 LOGW("Intended video encoding bit rate (%d bps) is too large"
1054 " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
1055 mVideoBitRate = maxBitRate;
1056 }
1057}
1058
1059void StagefrightRecorder::clipVideoFrameWidth() {
1060 LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
1061 int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1062 "enc.vid.width.min", mVideoEncoder);
1063 int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
1064 "enc.vid.width.max", mVideoEncoder);
1065 if (mVideoWidth < minFrameWidth) {
1066 LOGW("Intended video encoding frame width (%d) is too small"
1067 " and will be set to (%d)", mVideoWidth, minFrameWidth);
1068 mVideoWidth = minFrameWidth;
1069 } else if (mVideoWidth > maxFrameWidth) {
1070 LOGW("Intended video encoding frame width (%d) is too large"
1071 " and will be set to (%d)", mVideoWidth, maxFrameWidth);
1072 mVideoWidth = maxFrameWidth;
1073 }
1074}
1075
James Dong0c128b62010-10-08 11:59:32 -07001076status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
Nipun Kwatra453e92f2010-08-04 14:26:45 -07001077 if (!mCaptureTimeLapse) {
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001078 // Dont clip for time lapse capture as encoder will have enough
1079 // time to encode because of slow capture rate of time lapse.
1080 clipVideoBitRate();
1081 clipVideoFrameRate();
1082 clipVideoFrameWidth();
1083 clipVideoFrameHeight();
1084 }
James Dong7b06de62010-06-30 12:41:16 -07001085 return OK;
1086}
1087
James Dong54815a72011-01-12 20:45:16 -08001088status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
1089 clipAudioBitRate();
1090 clipAudioSampleRate();
1091 clipNumberOfAudioChannels();
1092 return OK;
1093}
1094
1095void StagefrightRecorder::clipAudioBitRate() {
1096 LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
1097
1098 int minAudioBitRate =
1099 mEncoderProfiles->getAudioEncoderParamByName(
1100 "enc.aud.bps.min", mAudioEncoder);
1101 if (mAudioBitRate < minAudioBitRate) {
1102 LOGW("Intended audio encoding bit rate (%d) is too small"
1103 " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
1104 mAudioBitRate = minAudioBitRate;
1105 }
1106
1107 int maxAudioBitRate =
1108 mEncoderProfiles->getAudioEncoderParamByName(
1109 "enc.aud.bps.max", mAudioEncoder);
1110 if (mAudioBitRate > maxAudioBitRate) {
1111 LOGW("Intended audio encoding bit rate (%d) is too large"
1112 " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
1113 mAudioBitRate = maxAudioBitRate;
1114 }
1115}
1116
1117void StagefrightRecorder::clipAudioSampleRate() {
1118 LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
1119
1120 int minSampleRate =
1121 mEncoderProfiles->getAudioEncoderParamByName(
1122 "enc.aud.hz.min", mAudioEncoder);
1123 if (mSampleRate < minSampleRate) {
1124 LOGW("Intended audio sample rate (%d) is too small"
1125 " and will be set to (%d)", mSampleRate, minSampleRate);
1126 mSampleRate = minSampleRate;
1127 }
1128
1129 int maxSampleRate =
1130 mEncoderProfiles->getAudioEncoderParamByName(
1131 "enc.aud.hz.max", mAudioEncoder);
1132 if (mSampleRate > maxSampleRate) {
1133 LOGW("Intended audio sample rate (%d) is too large"
1134 " and will be set to (%d)", mSampleRate, maxSampleRate);
1135 mSampleRate = maxSampleRate;
1136 }
1137}
1138
1139void StagefrightRecorder::clipNumberOfAudioChannels() {
1140 LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
1141
1142 int minChannels =
1143 mEncoderProfiles->getAudioEncoderParamByName(
1144 "enc.aud.ch.min", mAudioEncoder);
1145 if (mAudioChannels < minChannels) {
1146 LOGW("Intended number of audio channels (%d) is too small"
1147 " and will be set to (%d)", mAudioChannels, minChannels);
1148 mAudioChannels = minChannels;
1149 }
1150
1151 int maxChannels =
1152 mEncoderProfiles->getAudioEncoderParamByName(
1153 "enc.aud.ch.max", mAudioEncoder);
1154 if (mAudioChannels > maxChannels) {
1155 LOGW("Intended number of audio channels (%d) is too large"
1156 " and will be set to (%d)", mAudioChannels, maxChannels);
1157 mAudioChannels = maxChannels;
1158 }
1159}
1160
James Dong42a18c02010-06-16 17:27:46 -07001161void StagefrightRecorder::clipVideoFrameHeight() {
1162 LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
1163 int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1164 "enc.vid.height.min", mVideoEncoder);
1165 int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
1166 "enc.vid.height.max", mVideoEncoder);
1167 if (mVideoHeight < minFrameHeight) {
1168 LOGW("Intended video encoding frame height (%d) is too small"
1169 " and will be set to (%d)", mVideoHeight, minFrameHeight);
1170 mVideoHeight = minFrameHeight;
1171 } else if (mVideoHeight > maxFrameHeight) {
1172 LOGW("Intended video encoding frame height (%d) is too large"
1173 " and will be set to (%d)", mVideoHeight, maxFrameHeight);
1174 mVideoHeight = maxFrameHeight;
1175 }
1176}
1177
James Dong05c2fd52010-11-02 13:20:11 -07001178status_t StagefrightRecorder::setupCameraSource(
1179 sp<CameraSource> *cameraSource) {
James Dongb15f2ea2010-10-24 09:32:39 -07001180 status_t err = OK;
1181 if ((err = checkVideoEncoderCapabilities()) != OK) {
1182 return err;
1183 }
James Dong0c128b62010-10-08 11:59:32 -07001184 Size videoSize;
1185 videoSize.width = mVideoWidth;
1186 videoSize.height = mVideoHeight;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001187 if (mCaptureTimeLapse) {
James Dong0c128b62010-10-08 11:59:32 -07001188 mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
1189 mCamera, mCameraId,
1190 videoSize, mFrameRate, mPreviewSurface,
1191 mTimeBetweenTimeLapseFrameCaptureUs);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001192 *cameraSource = mCameraSourceTimeLapse;
1193 } else {
James Dong0c128b62010-10-08 11:59:32 -07001194 *cameraSource = CameraSource::CreateFromCamera(
James Dong05c2fd52010-11-02 13:20:11 -07001195 mCamera, mCameraId, videoSize, mFrameRate,
1196 mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001197 }
James Dong5df53fe2010-12-05 14:25:34 -08001198 if (*cameraSource == NULL) {
1199 return UNKNOWN_ERROR;
1200 }
1201
1202 if ((*cameraSource)->initCheck() != OK) {
1203 (*cameraSource).clear();
1204 *cameraSource = NULL;
1205 return NO_INIT;
1206 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001207
James Dongb15f2ea2010-10-24 09:32:39 -07001208 // When frame rate is not set, the actual frame rate will be set to
1209 // the current frame rate being used.
1210 if (mFrameRate == -1) {
1211 int32_t frameRate = 0;
1212 CHECK ((*cameraSource)->getFormat()->findInt32(
James Dongaac193c2010-11-10 20:43:53 -08001213 kKeyFrameRate, &frameRate));
James Dongb15f2ea2010-10-24 09:32:39 -07001214 LOGI("Frame rate is not explicitly set. Use the current frame "
1215 "rate (%d fps)", frameRate);
1216 mFrameRate = frameRate;
1217 }
1218
1219 CHECK(mFrameRate != -1);
James Dong05c2fd52010-11-02 13:20:11 -07001220
1221 mIsMetaDataStoredInVideoBuffers =
1222 (*cameraSource)->isMetaDataStoredInVideoBuffers();
1223
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001224 return OK;
1225}
1226
1227status_t StagefrightRecorder::setupVideoEncoder(
1228 sp<MediaSource> cameraSource,
1229 int32_t videoBitRate,
1230 sp<MediaSource> *source) {
1231 source->clear();
James Dong7b06de62010-06-30 12:41:16 -07001232
1233 sp<MetaData> enc_meta = new MetaData;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001234 enc_meta->setInt32(kKeyBitRate, videoBitRate);
James Dongaac193c2010-11-10 20:43:53 -08001235 enc_meta->setInt32(kKeyFrameRate, mFrameRate);
James Dong7b06de62010-06-30 12:41:16 -07001236
1237 switch (mVideoEncoder) {
1238 case VIDEO_ENCODER_H263:
1239 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
1240 break;
1241
1242 case VIDEO_ENCODER_MPEG_4_SP:
1243 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
1244 break;
1245
1246 case VIDEO_ENCODER_H264:
1247 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
1248 break;
1249
1250 default:
1251 CHECK(!"Should not be here, unsupported video encoding.");
1252 break;
1253 }
1254
1255 sp<MetaData> meta = cameraSource->getFormat();
1256
James Dong1cc31e62010-07-02 17:44:44 -07001257 int32_t width, height, stride, sliceHeight, colorFormat;
James Dong7b06de62010-06-30 12:41:16 -07001258 CHECK(meta->findInt32(kKeyWidth, &width));
1259 CHECK(meta->findInt32(kKeyHeight, &height));
1260 CHECK(meta->findInt32(kKeyStride, &stride));
1261 CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
James Dong1cc31e62010-07-02 17:44:44 -07001262 CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
James Dong7b06de62010-06-30 12:41:16 -07001263
1264 enc_meta->setInt32(kKeyWidth, width);
1265 enc_meta->setInt32(kKeyHeight, height);
James Dong52d13f02010-07-02 11:39:06 -07001266 enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
James Dong7b06de62010-06-30 12:41:16 -07001267 enc_meta->setInt32(kKeyStride, stride);
1268 enc_meta->setInt32(kKeySliceHeight, sliceHeight);
James Dong1cc31e62010-07-02 17:44:44 -07001269 enc_meta->setInt32(kKeyColorFormat, colorFormat);
James Dongeff30e32010-08-13 14:16:26 -07001270 if (mVideoTimeScale > 0) {
1271 enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
1272 }
James Dong81c929a2010-07-01 15:02:14 -07001273 if (mVideoEncoderProfile != -1) {
1274 enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
1275 }
1276 if (mVideoEncoderLevel != -1) {
1277 enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
1278 }
James Dong7b06de62010-06-30 12:41:16 -07001279
1280 OMXClient client;
1281 CHECK_EQ(client.connect(), OK);
1282
James Dong6312dd62010-12-02 14:48:23 -08001283 uint32_t encoder_flags = 0;
James Dong5fb60c72011-01-18 21:12:31 -08001284 if (mIsMetaDataStoredInVideoBuffers) {
James Dong6312dd62010-12-02 14:48:23 -08001285 encoder_flags |= OMXCodec::kHardwareCodecsOnly;
James Dong05c2fd52010-11-02 13:20:11 -07001286 encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
1287 }
James Dong5f3ab062011-01-25 16:31:28 -08001288
1289 // Do not wait for all the input buffers to become available.
1290 // This give timelapse video recording faster response in
1291 // receiving output from video encoder component.
1292 if (mCaptureTimeLapse) {
1293 encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
1294 }
1295
James Dong7b06de62010-06-30 12:41:16 -07001296 sp<MediaSource> encoder = OMXCodec::Create(
1297 client.interface(), enc_meta,
Nipun Kwatra077cba42010-07-20 11:37:17 -07001298 true /* createEncoder */, cameraSource,
1299 NULL, encoder_flags);
James Dong7b06de62010-06-30 12:41:16 -07001300 if (encoder == NULL) {
James Dong6312dd62010-12-02 14:48:23 -08001301 LOGW("Failed to create the encoder");
1302 // When the encoder fails to be created, we need
1303 // release the camera source due to the camera's lock
1304 // and unlock mechanism.
1305 cameraSource->stop();
James Dong7b06de62010-06-30 12:41:16 -07001306 return UNKNOWN_ERROR;
1307 }
1308
Andreas Huber57648e42010-08-04 10:14:30 -07001309 *source = encoder;
1310
James Dong7b06de62010-06-30 12:41:16 -07001311 return OK;
1312}
1313
1314status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
James Dong54815a72011-01-12 20:45:16 -08001315 status_t status = BAD_VALUE;
1316 if (OK != (status = checkAudioEncoderCapabilities())) {
1317 return status;
1318 }
1319
James Dong7b06de62010-06-30 12:41:16 -07001320 switch(mAudioEncoder) {
1321 case AUDIO_ENCODER_AMR_NB:
1322 case AUDIO_ENCODER_AMR_WB:
1323 case AUDIO_ENCODER_AAC:
James Dong7b06de62010-06-30 12:41:16 -07001324 break;
James Dong54815a72011-01-12 20:45:16 -08001325
James Dong7b06de62010-06-30 12:41:16 -07001326 default:
1327 LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1328 return UNKNOWN_ERROR;
1329 }
1330
James Dong54815a72011-01-12 20:45:16 -08001331 sp<MediaSource> audioEncoder = createAudioSource();
James Dong7b06de62010-06-30 12:41:16 -07001332 if (audioEncoder == NULL) {
1333 return UNKNOWN_ERROR;
1334 }
James Dong52d13f02010-07-02 11:39:06 -07001335
James Dong7b06de62010-06-30 12:41:16 -07001336 writer->addSource(audioEncoder);
1337 return OK;
1338}
1339
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001340status_t StagefrightRecorder::setupMPEG4Recording(
1341 bool useSplitCameraSource,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001342 int outputFd,
1343 int32_t videoWidth, int32_t videoHeight,
1344 int32_t videoBitRate,
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001345 int32_t *totalBitRate,
1346 sp<MediaWriter> *mediaWriter) {
1347 mediaWriter->clear();
1348 *totalBitRate = 0;
James Dong7b06de62010-06-30 12:41:16 -07001349 status_t err = OK;
James Dong2747e0e2010-11-18 20:59:13 -08001350 sp<MediaWriter> writer = new MPEG4Writer(outputFd);
Andreas Huber996dddf2010-01-25 15:30:31 -08001351
1352 if (mVideoSource == VIDEO_SOURCE_DEFAULT
1353 || mVideoSource == VIDEO_SOURCE_CAMERA) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001354
1355 sp<MediaSource> cameraMediaSource;
1356 if (useSplitCameraSource) {
1357 LOGV("Using Split camera source");
1358 cameraMediaSource = mCameraSourceSplitter->createClient();
1359 } else {
1360 sp<CameraSource> cameraSource;
1361 err = setupCameraSource(&cameraSource);
1362 cameraMediaSource = cameraSource;
1363 }
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001364 if ((videoWidth != mVideoWidth) || (videoHeight != mVideoHeight)) {
1365 // Use downsampling from the original source.
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001366 cameraMediaSource =
1367 new VideoSourceDownSampler(cameraMediaSource, videoWidth, videoHeight);
1368 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001369 if (err != OK) {
1370 return err;
1371 }
1372
Andreas Huber57648e42010-08-04 10:14:30 -07001373 sp<MediaSource> encoder;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001374 err = setupVideoEncoder(cameraMediaSource, videoBitRate, &encoder);
1375 if (err != OK) {
1376 return err;
1377 }
1378
Andreas Huber57648e42010-08-04 10:14:30 -07001379 writer->addSource(encoder);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001380 *totalBitRate += videoBitRate;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001381 }
1382
James Dong44b004b2011-01-19 20:42:19 -08001383 // Audio source is added at the end if it exists.
1384 // This help make sure that the "recoding" sound is suppressed for
1385 // camcorder applications in the recorded files.
1386 if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_LIST_END)) {
1387 err = setupAudioEncoder(writer);
1388 if (err != OK) return err;
1389 *totalBitRate += mAudioBitRate;
1390 }
1391
James Dong63299c02010-07-28 10:08:03 -07001392 if (mInterleaveDurationUs > 0) {
1393 reinterpret_cast<MPEG4Writer *>(writer.get())->
1394 setInterleaveDuration(mInterleaveDurationUs);
1395 }
James Dong18244862010-05-11 14:57:02 -07001396 if (mMaxFileDurationUs != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001397 writer->setMaxFileDuration(mMaxFileDurationUs);
James Dong18244862010-05-11 14:57:02 -07001398 }
1399 if (mMaxFileSizeBytes != 0) {
James Dong7b06de62010-06-30 12:41:16 -07001400 writer->setMaxFileSize(mMaxFileSizeBytes);
James Dong18244862010-05-11 14:57:02 -07001401 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001402
1403 writer->setListener(mListener);
1404 *mediaWriter = writer;
1405 return OK;
1406}
1407
1408void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
1409 sp<MetaData> *meta) {
1410 (*meta)->setInt64(kKeyTime, startTimeUs);
1411 (*meta)->setInt32(kKeyFileType, mOutputFormat);
1412 (*meta)->setInt32(kKeyBitRate, totalBitRate);
1413 (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
James Dongeff30e32010-08-13 14:16:26 -07001414 if (mMovieTimeScale > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001415 (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
James Dongeff30e32010-08-13 14:16:26 -07001416 }
James Dong09936ed2010-06-24 19:04:27 -07001417 if (mTrackEveryTimeDurationUs > 0) {
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001418 (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
James Dong09936ed2010-06-24 19:04:27 -07001419 }
James Dongb9d7e012010-11-09 11:15:47 -08001420 if (mRotationDegrees != 0) {
1421 (*meta)->setInt32(kKeyRotation, mRotationDegrees);
1422 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001423}
1424
1425status_t StagefrightRecorder::startMPEG4Recording() {
1426 if (mCaptureAuxVideo) {
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001427 if (!mCaptureTimeLapse) {
1428 LOGE("Auxiliary video can be captured only in time lapse mode");
1429 return UNKNOWN_ERROR;
1430 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001431 LOGV("Creating MediaSourceSplitter");
1432 sp<CameraSource> cameraSource;
1433 status_t err = setupCameraSource(&cameraSource);
1434 if (err != OK) {
1435 return err;
1436 }
1437 mCameraSourceSplitter = new MediaSourceSplitter(cameraSource);
1438 } else {
1439 mCameraSourceSplitter = NULL;
1440 }
1441
1442 int32_t totalBitRate;
1443 status_t err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001444 mOutputFd, mVideoWidth, mVideoHeight,
1445 mVideoBitRate, &totalBitRate, &mWriter);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001446 if (err != OK) {
1447 return err;
1448 }
1449
1450 int64_t startTimeUs = systemTime() / 1000;
1451 sp<MetaData> meta = new MetaData;
1452 setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
1453
1454 err = mWriter->start(meta.get());
1455 if (err != OK) {
1456 return err;
1457 }
1458
1459 if (mCaptureAuxVideo) {
1460 CHECK(mOutputFdAux >= 0);
1461 if (mWriterAux != NULL) {
1462 LOGE("Auxiliary File writer is not avaialble");
1463 return UNKNOWN_ERROR;
1464 }
Nipun Kwatrafb5a2d72010-09-13 18:52:55 -07001465 if ((mAuxVideoWidth > mVideoWidth) || (mAuxVideoHeight > mVideoHeight) ||
1466 ((mAuxVideoWidth == mVideoWidth) && mAuxVideoHeight == mVideoHeight)) {
1467 LOGE("Auxiliary video size (%d x %d) same or larger than the main video size (%d x %d)",
1468 mAuxVideoWidth, mAuxVideoHeight, mVideoWidth, mVideoHeight);
1469 return UNKNOWN_ERROR;
1470 }
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001471
1472 int32_t totalBitrateAux;
1473 err = setupMPEG4Recording(mCaptureAuxVideo,
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001474 mOutputFdAux, mAuxVideoWidth, mAuxVideoHeight,
1475 mAuxVideoBitRate, &totalBitrateAux, &mWriterAux);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001476 if (err != OK) {
1477 return err;
1478 }
1479
1480 sp<MetaData> metaAux = new MetaData;
1481 setupMPEG4MetaData(startTimeUs, totalBitrateAux, &metaAux);
1482
1483 return mWriterAux->start(metaAux.get());
1484 }
1485
1486 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001487}
1488
James Dong08c74732010-06-10 12:28:15 -07001489status_t StagefrightRecorder::pause() {
James Dongc0ab2a62010-06-29 16:29:19 -07001490 LOGV("pause");
James Dong08c74732010-06-10 12:28:15 -07001491 if (mWriter == NULL) {
1492 return UNKNOWN_ERROR;
1493 }
1494 mWriter->pause();
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001495
1496 if (mCaptureAuxVideo) {
1497 if (mWriterAux == NULL) {
1498 return UNKNOWN_ERROR;
1499 }
1500 mWriterAux->pause();
1501 }
1502
Gloria Wang62e05a62011-02-23 11:47:34 -08001503 if (mStarted) {
1504 mStarted = false;
1505
1506 uint32_t params = 0;
1507 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
1508 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1509 }
1510 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1511 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1512 }
1513
1514 addBatteryData(params);
1515 }
1516
1517
James Dong08c74732010-06-10 12:28:15 -07001518 return OK;
1519}
1520
Andreas Huberea6a38c2009-11-16 15:43:38 -08001521status_t StagefrightRecorder::stop() {
James Dongc0ab2a62010-06-29 16:29:19 -07001522 LOGV("stop");
James Dongd0366622010-08-18 19:10:39 -07001523 status_t err = OK;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001524
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001525 if (mCaptureTimeLapse && mCameraSourceTimeLapse != NULL) {
1526 mCameraSourceTimeLapse->startQuickReadReturns();
1527 mCameraSourceTimeLapse = NULL;
1528 }
1529
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001530 if (mCaptureAuxVideo) {
1531 if (mWriterAux != NULL) {
1532 mWriterAux->stop();
1533 mWriterAux.clear();
1534 }
1535 }
1536
James Dongc0ab2a62010-06-29 16:29:19 -07001537 if (mWriter != NULL) {
James Dongd0366622010-08-18 19:10:39 -07001538 err = mWriter->stop();
James Dong7b06de62010-06-30 12:41:16 -07001539 mWriter.clear();
Andreas Huberea6a38c2009-11-16 15:43:38 -08001540 }
1541
James Dongc6280bc2010-08-11 17:12:39 -07001542 if (mOutputFd >= 0) {
1543 ::close(mOutputFd);
1544 mOutputFd = -1;
1545 }
1546
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001547 if (mCaptureAuxVideo) {
1548 if (mOutputFdAux >= 0) {
1549 ::close(mOutputFdAux);
1550 mOutputFdAux = -1;
1551 }
1552 }
1553
Gloria Wang62e05a62011-02-23 11:47:34 -08001554 if (mStarted) {
1555 mStarted = false;
1556
1557 uint32_t params = 0;
1558 if (mAudioSource != AUDIO_SOURCE_LIST_END) {
1559 params |= IMediaPlayerService::kBatteryDataTrackAudio;
1560 }
1561 if (mVideoSource != VIDEO_SOURCE_LIST_END) {
1562 params |= IMediaPlayerService::kBatteryDataTrackVideo;
1563 }
1564
1565 addBatteryData(params);
1566 }
1567
1568
James Dongd0366622010-08-18 19:10:39 -07001569 return err;
James Dongc0ab2a62010-06-29 16:29:19 -07001570}
1571
1572status_t StagefrightRecorder::close() {
1573 LOGV("close");
1574 stop();
1575
Andreas Huberea6a38c2009-11-16 15:43:38 -08001576 return OK;
1577}
1578
1579status_t StagefrightRecorder::reset() {
James Dongc0ab2a62010-06-29 16:29:19 -07001580 LOGV("reset");
Andreas Huberea6a38c2009-11-16 15:43:38 -08001581 stop();
1582
James Dongabed93a2010-04-22 17:27:04 -07001583 // No audio or video source by default
Andreas Huberea6a38c2009-11-16 15:43:38 -08001584 mAudioSource = AUDIO_SOURCE_LIST_END;
1585 mVideoSource = VIDEO_SOURCE_LIST_END;
James Dongabed93a2010-04-22 17:27:04 -07001586
1587 // Default parameters
1588 mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
1589 mAudioEncoder = AUDIO_ENCODER_AMR_NB;
1590 mVideoEncoder = VIDEO_ENCODER_H263;
1591 mVideoWidth = 176;
1592 mVideoHeight = 144;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001593 mAuxVideoWidth = 176;
1594 mAuxVideoHeight = 144;
James Dongb15f2ea2010-10-24 09:32:39 -07001595 mFrameRate = -1;
James Dongabed93a2010-04-22 17:27:04 -07001596 mVideoBitRate = 192000;
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001597 mAuxVideoBitRate = 192000;
James Dongabed93a2010-04-22 17:27:04 -07001598 mSampleRate = 8000;
1599 mAudioChannels = 1;
1600 mAudioBitRate = 12200;
James Dongc6161722010-05-20 17:55:52 -07001601 mInterleaveDurationUs = 0;
James Dong52d13f02010-07-02 11:39:06 -07001602 mIFramesIntervalSec = 1;
James Dong57e7f832010-06-24 19:55:31 -07001603 mAudioSourceNode = 0;
James Dong6feaa462010-06-20 08:20:54 -07001604 mUse64BitFileOffset = false;
James Dongeff30e32010-08-13 14:16:26 -07001605 mMovieTimeScale = -1;
1606 mAudioTimeScale = -1;
1607 mVideoTimeScale = -1;
James Dong09936ed2010-06-24 19:04:27 -07001608 mCameraId = 0;
James Dong81c929a2010-07-01 15:02:14 -07001609 mVideoEncoderProfile = -1;
1610 mVideoEncoderLevel = -1;
1611 mMaxFileDurationUs = 0;
1612 mMaxFileSizeBytes = 0;
James Dong09936ed2010-06-24 19:04:27 -07001613 mTrackEveryTimeDurationUs = 0;
Nipun Kwatrad26920a2010-06-30 18:51:31 -07001614 mCaptureTimeLapse = false;
Nipun Kwatrad01371b2010-07-20 21:33:31 -07001615 mTimeBetweenTimeLapseFrameCaptureUs = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001616 mCaptureAuxVideo = false;
1617 mCameraSourceSplitter = NULL;
Nipun Kwatra7553cf72010-09-15 15:08:49 -07001618 mCameraSourceTimeLapse = NULL;
James Dong05c2fd52010-11-02 13:20:11 -07001619 mIsMetaDataStoredInVideoBuffers = false;
James Dong42a18c02010-06-16 17:27:46 -07001620 mEncoderProfiles = MediaProfiles::getInstance();
James Dong5d0b7832010-11-10 12:26:58 -08001621 mRotationDegrees = 0;
James Dongabed93a2010-04-22 17:27:04 -07001622
Andreas Huberea6a38c2009-11-16 15:43:38 -08001623 mOutputFd = -1;
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001624 mOutputFdAux = -1;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001625
1626 return OK;
1627}
1628
1629status_t StagefrightRecorder::getMaxAmplitude(int *max) {
James Dongc0ab2a62010-06-29 16:29:19 -07001630 LOGV("getMaxAmplitude");
1631
1632 if (max == NULL) {
1633 LOGE("Null pointer argument");
1634 return BAD_VALUE;
1635 }
1636
James Dong57e7f832010-06-24 19:55:31 -07001637 if (mAudioSourceNode != 0) {
1638 *max = mAudioSourceNode->getMaxAmplitude();
1639 } else {
1640 *max = 0;
1641 }
Andreas Huber996dddf2010-01-25 15:30:31 -08001642
1643 return OK;
Andreas Huberea6a38c2009-11-16 15:43:38 -08001644}
1645
James Dong3f51fa72010-08-18 03:32:26 -07001646status_t StagefrightRecorder::dump(
1647 int fd, const Vector<String16>& args) const {
1648 LOGV("dump");
James Dong929642e2010-07-08 11:16:11 -07001649 const size_t SIZE = 256;
1650 char buffer[SIZE];
1651 String8 result;
James Dong3f51fa72010-08-18 03:32:26 -07001652 if (mWriter != 0) {
1653 mWriter->dump(fd, args);
1654 } else {
1655 snprintf(buffer, SIZE, " No file writer\n");
1656 result.append(buffer);
1657 }
1658 snprintf(buffer, SIZE, " Recorder: %p\n", this);
James Dong929642e2010-07-08 11:16:11 -07001659 snprintf(buffer, SIZE, " Output file (fd %d):\n", mOutputFd);
1660 result.append(buffer);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001661 snprintf(buffer, SIZE, " Output file Auxiliary (fd %d):\n", mOutputFdAux);
1662 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001663 snprintf(buffer, SIZE, " File format: %d\n", mOutputFormat);
1664 result.append(buffer);
1665 snprintf(buffer, SIZE, " Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1666 result.append(buffer);
1667 snprintf(buffer, SIZE, " Max file duration (us): %lld\n", mMaxFileDurationUs);
1668 result.append(buffer);
1669 snprintf(buffer, SIZE, " File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1670 result.append(buffer);
1671 snprintf(buffer, SIZE, " Interleave duration (us): %d\n", mInterleaveDurationUs);
1672 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001673 snprintf(buffer, SIZE, " Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1674 result.append(buffer);
1675 snprintf(buffer, SIZE, " Audio\n");
1676 result.append(buffer);
1677 snprintf(buffer, SIZE, " Source: %d\n", mAudioSource);
1678 result.append(buffer);
1679 snprintf(buffer, SIZE, " Encoder: %d\n", mAudioEncoder);
1680 result.append(buffer);
1681 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mAudioBitRate);
1682 result.append(buffer);
1683 snprintf(buffer, SIZE, " Sampling rate (hz): %d\n", mSampleRate);
1684 result.append(buffer);
1685 snprintf(buffer, SIZE, " Number of channels: %d\n", mAudioChannels);
1686 result.append(buffer);
1687 snprintf(buffer, SIZE, " Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1688 result.append(buffer);
1689 snprintf(buffer, SIZE, " Video\n");
1690 result.append(buffer);
1691 snprintf(buffer, SIZE, " Source: %d\n", mVideoSource);
1692 result.append(buffer);
1693 snprintf(buffer, SIZE, " Camera Id: %d\n", mCameraId);
1694 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001695 snprintf(buffer, SIZE, " Encoder: %d\n", mVideoEncoder);
1696 result.append(buffer);
1697 snprintf(buffer, SIZE, " Encoder profile: %d\n", mVideoEncoderProfile);
1698 result.append(buffer);
1699 snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel);
1700 result.append(buffer);
James Dong52d13f02010-07-02 11:39:06 -07001701 snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec);
James Dong929642e2010-07-08 11:16:11 -07001702 result.append(buffer);
1703 snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1704 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001705 snprintf(buffer, SIZE, " Aux Frame size (pixels): %dx%d\n", mAuxVideoWidth, mAuxVideoHeight);
1706 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001707 snprintf(buffer, SIZE, " Frame rate (fps): %d\n", mFrameRate);
1708 result.append(buffer);
1709 snprintf(buffer, SIZE, " Bit rate (bps): %d\n", mVideoBitRate);
1710 result.append(buffer);
Nipun Kwatra239f2e52010-08-31 15:35:44 -07001711 snprintf(buffer, SIZE, " Aux Bit rate (bps): %d\n", mAuxVideoBitRate);
Nipun Kwatrad7e7a3f2010-08-26 17:05:18 -07001712 result.append(buffer);
James Dong929642e2010-07-08 11:16:11 -07001713 ::write(fd, result.string(), result.size());
1714 return OK;
1715}
Andreas Huberea6a38c2009-11-16 15:43:38 -08001716} // namespace android