StagefrightRecorder.cpp revision 4b79168835965cf0fc41ebe2a367e22b4cb20d08
130ab66297501757d745b9ae10da61adcd891f497Andreas Huber/*
230ab66297501757d745b9ae10da61adcd891f497Andreas Huber * Copyright (C) 2009 The Android Open Source Project
330ab66297501757d745b9ae10da61adcd891f497Andreas Huber *
430ab66297501757d745b9ae10da61adcd891f497Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
530ab66297501757d745b9ae10da61adcd891f497Andreas Huber * you may not use this file except in compliance with the License.
630ab66297501757d745b9ae10da61adcd891f497Andreas Huber * You may obtain a copy of the License at
730ab66297501757d745b9ae10da61adcd891f497Andreas Huber *
830ab66297501757d745b9ae10da61adcd891f497Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
930ab66297501757d745b9ae10da61adcd891f497Andreas Huber *
1030ab66297501757d745b9ae10da61adcd891f497Andreas Huber * Unless required by applicable law or agreed to in writing, software
1130ab66297501757d745b9ae10da61adcd891f497Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1230ab66297501757d745b9ae10da61adcd891f497Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1330ab66297501757d745b9ae10da61adcd891f497Andreas Huber * See the License for the specific language governing permissions and
1430ab66297501757d745b9ae10da61adcd891f497Andreas Huber * limitations under the License.
1530ab66297501757d745b9ae10da61adcd891f497Andreas Huber */
1630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1730ab66297501757d745b9ae10da61adcd891f497Andreas Huber//#define LOG_NDEBUG 0
1830ab66297501757d745b9ae10da61adcd891f497Andreas Huber#define LOG_TAG "StagefrightRecorder"
1930ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <utils/Log.h>
2030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
2130ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include "StagefrightRecorder.h"
2230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
23c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong#include <binder/IPCThreadState.h>
242dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber#include <media/stagefright/AudioSource.h>
252dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber#include <media/stagefright/AMRWriter.h>
2630ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <media/stagefright/CameraSource.h>
2765e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra#include <media/stagefright/CameraSourceTimeLapse.h>
2830ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <media/stagefright/MPEG4Writer.h>
2930ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <media/stagefright/MediaDebug.h>
3030ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <media/stagefright/MediaDefs.h>
3130ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <media/stagefright/MetaData.h>
3230ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <media/stagefright/OMXClient.h>
3330ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <media/stagefright/OMXCodec.h>
3499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong#include <media/MediaProfiles.h>
353cf613507f1e2f7bd932d921a6e222e426fd3be4Mathias Agopian#include <camera/ICamera.h>
36c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong#include <camera/Camera.h>
37ef9d0cd72e476a4b7556833fb09505a51b626797James Dong#include <camera/CameraParameters.h>
384b79168835965cf0fc41ebe2a367e22b4cb20d08Jamie Gennis#include <surfaceflinger/Surface.h>
3930ab66297501757d745b9ae10da61adcd891f497Andreas Huber#include <utils/Errors.h>
40c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong#include <sys/types.h>
41050b28a593350047845a45a14cc5026221ac1620James Dong#include <ctype.h>
42ca2fa61ef03cac008ea86e6fe16b2e5f9f1a2be3Nipun Kwatra#include <unistd.h>
4330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
4439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber#include "ARTPWriter.h"
4539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
4630ab66297501757d745b9ae10da61adcd891f497Andreas Hubernamespace android {
4730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
48d329e21495eda9dbc531fdd0c26c77f1593ac3f4James DongStagefrightRecorder::StagefrightRecorder()
49d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    : mWriter(NULL),
50d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong      mOutputFd(-1) {
51d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
52d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("Constructor");
5330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    reset();
5430ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
5530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
5630ab66297501757d745b9ae10da61adcd891f497Andreas HuberStagefrightRecorder::~StagefrightRecorder() {
57d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("Destructor");
5830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    stop();
5930ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
6030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
6130ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::init() {
62d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("init");
6330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
6430ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
6530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
6630ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setAudioSource(audio_source as) {
67d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setAudioSource: %d", as);
68d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (as < AUDIO_SOURCE_DEFAULT ||
69d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        as >= AUDIO_SOURCE_LIST_END) {
70934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Invalid audio source: %d", as);
71d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        return BAD_VALUE;
72d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
73d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
74d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (as == AUDIO_SOURCE_DEFAULT) {
75d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mAudioSource = AUDIO_SOURCE_MIC;
76d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    } else {
77d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mAudioSource = as;
78d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
7930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
8030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
8130ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
8230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
8330ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setVideoSource(video_source vs) {
84d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setVideoSource: %d", vs);
85d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (vs < VIDEO_SOURCE_DEFAULT ||
86d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        vs >= VIDEO_SOURCE_LIST_END) {
87934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Invalid video source: %d", vs);
88d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        return BAD_VALUE;
89d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
90d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
91d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (vs == VIDEO_SOURCE_DEFAULT) {
92d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mVideoSource = VIDEO_SOURCE_CAMERA;
93d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    } else {
94d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mVideoSource = vs;
95d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
9630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
9730ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
9830ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
9930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
10030ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setOutputFormat(output_format of) {
101d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setOutputFormat: %d", of);
102d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (of < OUTPUT_FORMAT_DEFAULT ||
103d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        of >= OUTPUT_FORMAT_LIST_END) {
104934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Invalid output format: %d", of);
105d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        return BAD_VALUE;
106d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
107d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
108d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (of == OUTPUT_FORMAT_DEFAULT) {
109d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
110d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    } else {
111d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mOutputFormat = of;
112d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
11330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
11430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
11530ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
11630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
11730ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
118d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setAudioEncoder: %d", ae);
119d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (ae < AUDIO_ENCODER_DEFAULT ||
120d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        ae >= AUDIO_ENCODER_LIST_END) {
121934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Invalid audio encoder: %d", ae);
122d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        return BAD_VALUE;
123d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
124d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
125d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (ae == AUDIO_ENCODER_DEFAULT) {
126d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mAudioEncoder = AUDIO_ENCODER_AMR_NB;
127d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    } else {
128d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mAudioEncoder = ae;
129d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
13030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
13130ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
13230ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
13330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
13430ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setVideoEncoder(video_encoder ve) {
135d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setVideoEncoder: %d", ve);
136d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (ve < VIDEO_ENCODER_DEFAULT ||
137d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        ve >= VIDEO_ENCODER_LIST_END) {
138934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Invalid video encoder: %d", ve);
139d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        return BAD_VALUE;
140d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
141d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
142d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (ve == VIDEO_ENCODER_DEFAULT) {
143d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mVideoEncoder = VIDEO_ENCODER_H263;
144d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    } else {
145d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        mVideoEncoder = ve;
146d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
14730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
14830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
14930ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
15030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
15130ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setVideoSize(int width, int height) {
152d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setVideoSize: %dx%d", width, height);
153ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (width <= 0 || height <= 0) {
154ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid video size: %dx%d", width, height);
155ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        return BAD_VALUE;
156ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
157ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
158ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // Additional check on the dimension will be performed later
15930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mVideoWidth = width;
16030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mVideoHeight = height;
16130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
16230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
16330ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
16430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
16530ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setVideoFrameRate(int frames_per_second) {
166d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setVideoFrameRate: %d", frames_per_second);
167ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (frames_per_second <= 0 || frames_per_second > 30) {
168ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid video frame rate: %d", frames_per_second);
169ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        return BAD_VALUE;
170ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
171ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
172ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // Additional check on the frame rate will be performed later
17330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mFrameRate = frames_per_second;
17430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
17530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
17630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
17730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
17830ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
1799d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong    LOGV("setCamera");
180c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    if (camera == 0) {
181c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        LOGE("camera is NULL");
182934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return BAD_VALUE;
183c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    }
184c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong
1859d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong    int64_t token = IPCThreadState::self()->clearCallingIdentity();
1869d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong    mFlags &= ~FLAGS_HOT_CAMERA;
187c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    mCamera = Camera::create(camera);
188c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    if (mCamera == 0) {
189c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        LOGE("Unable to connect to camera");
1909d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong        IPCThreadState::self()->restoreCallingIdentity(token);
191934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return -EBUSY;
192c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    }
193c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong
194c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    LOGV("Connected to camera");
195c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    if (mCamera->previewEnabled()) {
196c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        LOGV("camera is hot");
197c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        mFlags |= FLAGS_HOT_CAMERA;
198c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    }
1999d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong    IPCThreadState::self()->restoreCallingIdentity(token);
20030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
20130ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
20230ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
20330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
2044b79168835965cf0fc41ebe2a367e22b4cb20d08Jamie Gennisstatus_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
205d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setPreviewSurface: %p", surface.get());
20630ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mPreviewSurface = surface;
20730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
20830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
20930ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
21030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
21130ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setOutputFile(const char *path) {
212934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    LOGE("setOutputFile(const char*) must not be called");
21330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    // We don't actually support this at all, as the media_server process
21430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    // no longer has permissions to create files.
21530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
216934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    return -EPERM;
21730ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
21830ab66297501757d745b9ae10da61adcd891f497Andreas Huber
21930ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
220d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
22130ab66297501757d745b9ae10da61adcd891f497Andreas Huber    // These don't make any sense, do they?
22230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    CHECK_EQ(offset, 0);
22330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    CHECK_EQ(length, 0);
22430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
225934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (fd < 0) {
226934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Invalid file descriptor: %d", fd);
227934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return -EBADF;
228934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
229934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
23030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    if (mOutputFd >= 0) {
23130ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ::close(mOutputFd);
23230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    }
23330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mOutputFd = dup(fd);
23430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
23530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
23630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
23730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
238050b28a593350047845a45a14cc5026221ac1620James Dong// Attempt to parse an int64 literal optionally surrounded by whitespace,
239050b28a593350047845a45a14cc5026221ac1620James Dong// returns true on success, false otherwise.
240ef9d0cd72e476a4b7556833fb09505a51b626797James Dongstatic bool safe_strtoi64(const char *s, int64_t *val) {
241050b28a593350047845a45a14cc5026221ac1620James Dong    char *end;
242ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    *val = strtoll(s, &end, 10);
243050b28a593350047845a45a14cc5026221ac1620James Dong
244050b28a593350047845a45a14cc5026221ac1620James Dong    if (end == s || errno == ERANGE) {
245050b28a593350047845a45a14cc5026221ac1620James Dong        return false;
246050b28a593350047845a45a14cc5026221ac1620James Dong    }
247050b28a593350047845a45a14cc5026221ac1620James Dong
248050b28a593350047845a45a14cc5026221ac1620James Dong    // Skip trailing whitespace
249050b28a593350047845a45a14cc5026221ac1620James Dong    while (isspace(*end)) {
250050b28a593350047845a45a14cc5026221ac1620James Dong        ++end;
251050b28a593350047845a45a14cc5026221ac1620James Dong    }
252050b28a593350047845a45a14cc5026221ac1620James Dong
253050b28a593350047845a45a14cc5026221ac1620James Dong    // For a successful return, the string must contain nothing but a valid
254050b28a593350047845a45a14cc5026221ac1620James Dong    // int64 literal optionally surrounded by whitespace.
255050b28a593350047845a45a14cc5026221ac1620James Dong
256050b28a593350047845a45a14cc5026221ac1620James Dong    return *end == '\0';
257050b28a593350047845a45a14cc5026221ac1620James Dong}
258050b28a593350047845a45a14cc5026221ac1620James Dong
259ef9d0cd72e476a4b7556833fb09505a51b626797James Dong// Return true if the value is in [0, 0x007FFFFFFF]
260ef9d0cd72e476a4b7556833fb09505a51b626797James Dongstatic bool safe_strtoi32(const char *s, int32_t *val) {
261ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    int64_t temp;
262ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (safe_strtoi64(s, &temp)) {
263ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (temp >= 0 && temp <= 0x007FFFFFFF) {
264ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            *val = static_cast<int32_t>(temp);
265ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            return true;
266ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        }
267ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
268ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    return false;
269ef9d0cd72e476a4b7556833fb09505a51b626797James Dong}
270ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
271050b28a593350047845a45a14cc5026221ac1620James Dong// Trim both leading and trailing whitespace from the given string.
272050b28a593350047845a45a14cc5026221ac1620James Dongstatic void TrimString(String8 *s) {
273050b28a593350047845a45a14cc5026221ac1620James Dong    size_t num_bytes = s->bytes();
274050b28a593350047845a45a14cc5026221ac1620James Dong    const char *data = s->string();
275050b28a593350047845a45a14cc5026221ac1620James Dong
276050b28a593350047845a45a14cc5026221ac1620James Dong    size_t leading_space = 0;
277050b28a593350047845a45a14cc5026221ac1620James Dong    while (leading_space < num_bytes && isspace(data[leading_space])) {
278050b28a593350047845a45a14cc5026221ac1620James Dong        ++leading_space;
279050b28a593350047845a45a14cc5026221ac1620James Dong    }
280050b28a593350047845a45a14cc5026221ac1620James Dong
281050b28a593350047845a45a14cc5026221ac1620James Dong    size_t i = num_bytes;
282050b28a593350047845a45a14cc5026221ac1620James Dong    while (i > leading_space && isspace(data[i - 1])) {
283050b28a593350047845a45a14cc5026221ac1620James Dong        --i;
284050b28a593350047845a45a14cc5026221ac1620James Dong    }
285050b28a593350047845a45a14cc5026221ac1620James Dong
286050b28a593350047845a45a14cc5026221ac1620James Dong    s->setTo(String8(&data[leading_space], i - leading_space));
287050b28a593350047845a45a14cc5026221ac1620James Dong}
288050b28a593350047845a45a14cc5026221ac1620James Dong
289050b28a593350047845a45a14cc5026221ac1620James Dongstatus_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
290050b28a593350047845a45a14cc5026221ac1620James Dong    LOGV("setParamAudioSamplingRate: %d", sampleRate);
291ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (sampleRate <= 0) {
292ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid audio sampling rate: %d", sampleRate);
293ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        return BAD_VALUE;
294ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
295ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
296ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // Additional check on the sample rate will be performed later.
297050b28a593350047845a45a14cc5026221ac1620James Dong    mSampleRate = sampleRate;
298050b28a593350047845a45a14cc5026221ac1620James Dong    return OK;
299050b28a593350047845a45a14cc5026221ac1620James Dong}
300050b28a593350047845a45a14cc5026221ac1620James Dong
301050b28a593350047845a45a14cc5026221ac1620James Dongstatus_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
302050b28a593350047845a45a14cc5026221ac1620James Dong    LOGV("setParamAudioNumberOfChannels: %d", channels);
303ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (channels <= 0 || channels >= 3) {
304ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid number of audio channels: %d", channels);
305934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return BAD_VALUE;
306ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
307ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
308ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // Additional check on the number of channels will be performed later.
309050b28a593350047845a45a14cc5026221ac1620James Dong    mAudioChannels = channels;
310050b28a593350047845a45a14cc5026221ac1620James Dong    return OK;
311050b28a593350047845a45a14cc5026221ac1620James Dong}
312050b28a593350047845a45a14cc5026221ac1620James Dong
313050b28a593350047845a45a14cc5026221ac1620James Dongstatus_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
314050b28a593350047845a45a14cc5026221ac1620James Dong    LOGV("setParamAudioEncodingBitRate: %d", bitRate);
315ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (bitRate <= 0) {
316ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid audio encoding bit rate: %d", bitRate);
317ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        return BAD_VALUE;
318ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
319ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
320ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // The target bit rate may not be exactly the same as the requested.
321ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // It depends on many factors, such as rate control, and the bit rate
322ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // range that a specific encoder supports. The mismatch between the
323ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // the target and requested bit rate will NOT be treated as an error.
324050b28a593350047845a45a14cc5026221ac1620James Dong    mAudioBitRate = bitRate;
325050b28a593350047845a45a14cc5026221ac1620James Dong    return OK;
326050b28a593350047845a45a14cc5026221ac1620James Dong}
327050b28a593350047845a45a14cc5026221ac1620James Dong
328050b28a593350047845a45a14cc5026221ac1620James Dongstatus_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
329050b28a593350047845a45a14cc5026221ac1620James Dong    LOGV("setParamVideoEncodingBitRate: %d", bitRate);
330ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (bitRate <= 0) {
331ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid video encoding bit rate: %d", bitRate);
332ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        return BAD_VALUE;
333ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
334ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
335ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // The target bit rate may not be exactly the same as the requested.
336ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // It depends on many factors, such as rate control, and the bit rate
337ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // range that a specific encoder supports. The mismatch between the
338ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    // the target and requested bit rate will NOT be treated as an error.
339050b28a593350047845a45a14cc5026221ac1620James Dong    mVideoBitRate = bitRate;
340050b28a593350047845a45a14cc5026221ac1620James Dong    return OK;
341050b28a593350047845a45a14cc5026221ac1620James Dong}
342050b28a593350047845a45a14cc5026221ac1620James Dong
343934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dongstatus_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
344934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
345e4fc55de48241c5fb4c4b9d652fd2d4cd0b71138James Dong    if (timeUs <= 100000LL) {  // XXX: 100 milli-seconds
346934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Max file duration is too short: %lld us", timeUs);
347934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return BAD_VALUE;
348ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
349934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    mMaxFileDurationUs = timeUs;
350934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    return OK;
351934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong}
352934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
353934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dongstatus_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
354934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    LOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
355934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (bytes <= 1024) {  // XXX: 1 kB
356934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Max file size is too small: %lld bytes", bytes);
357934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return BAD_VALUE;
358934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
359934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    mMaxFileSizeBytes = bytes;
360050b28a593350047845a45a14cc5026221ac1620James Dong    return OK;
361050b28a593350047845a45a14cc5026221ac1620James Dong}
362050b28a593350047845a45a14cc5026221ac1620James Dong
36313aec890216948b0c364f8f92792129d0335f506James Dongstatus_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
36413aec890216948b0c364f8f92792129d0335f506James Dong    LOGV("setParamInterleaveDuration: %d", durationUs);
365ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong    if (durationUs <= 500000) {           //  500 ms
366ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        // If interleave duration is too small, it is very inefficient to do
367ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        // interleaving since the metadata overhead will count for a significant
368ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        // portion of the saved contents
369ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Audio/video interleave duration is too small: %d us", durationUs);
370ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        return BAD_VALUE;
371ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong    } else if (durationUs >= 10000000) {  // 10 seconds
372ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        // If interleaving duration is too large, it can cause the recording
373ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        // session to use too much memory since we have to save the output
374ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        // data before we write them out
375ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        LOGE("Audio/video interleave duration is too large: %d us", durationUs);
376ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        return BAD_VALUE;
377ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
37813aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
37913aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
38013aec890216948b0c364f8f92792129d0335f506James Dong}
381ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
3828f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong// If seconds <  0, only the first frame is I frame, and rest are all P frames
3838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong// If seconds == 0, all frames are encoded as I frames. No P frames
3848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong// If seconds >  0, it is the time spacing (seconds) between 2 neighboring I frames
3858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dongstatus_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) {
3868f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("setParamVideoIFramesInterval: %d seconds", seconds);
3878f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    mIFramesIntervalSec = seconds;
388ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong    return OK;
389ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong}
390ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong
3912dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
3922dec2b5be2056c6d9428897dc672185872d30d17James Dong    LOGV("setParam64BitFileOffset: %s",
3932dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64Bit? "use 64 bit file offset": "use 32 bit file offset");
3942dec2b5be2056c6d9428897dc672185872d30d17James Dong    mUse64BitFileOffset = use64Bit;
3952dec2b5be2056c6d9428897dc672185872d30d17James Dong    return OK;
3962dec2b5be2056c6d9428897dc672185872d30d17James Dong}
3972dec2b5be2056c6d9428897dc672185872d30d17James Dong
39893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
39993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    LOGV("setParamVideoCameraId: %d", cameraId);
40093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    if (cameraId < 0) {
40193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        return BAD_VALUE;
40293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
40393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mCameraId = cameraId;
40493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    return OK;
40593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
40693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
40793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
40893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    LOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
40993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    if (timeDurationUs < 20000) {  // Infeasible if shorter than 20 ms?
410934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Tracking time duration too short: %lld us", timeDurationUs);
41193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        return BAD_VALUE;
41293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
41393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = timeDurationUs;
41493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    return OK;
41593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
41693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
417145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dongstatus_t StagefrightRecorder::setParamVideoEncoderProfile(int32_t profile) {
418145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    LOGV("setParamVideoEncoderProfile: %d", profile);
419145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong
420145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    // Additional check will be done later when we load the encoder.
421145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    // For now, we are accepting values defined in OpenMAX IL.
422145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    mVideoEncoderProfile = profile;
423145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    return OK;
424145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong}
425145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong
426145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dongstatus_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) {
427145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    LOGV("setParamVideoEncoderLevel: %d", level);
428145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong
429145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    // Additional check will be done later when we load the encoder.
430145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    // For now, we are accepting values defined in OpenMAX IL.
431145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    mVideoEncoderLevel = level;
432145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    return OK;
433145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong}
434145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong
4358f5f2fcee5c12d08df71d17017410c50951fc2e3James Dongstatus_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) {
4368f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("setParamMovieTimeScale: %d", timeScale);
4378f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4388f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    // The range is set to be the same as the audio's time scale range
4398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    // since audio's time scale has a wider range.
4408f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (timeScale < 600 || timeScale > 96000) {
4418f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale);
4428f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        return BAD_VALUE;
4438f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
4448f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    mMovieTimeScale = timeScale;
4458f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    return OK;
4468f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong}
4478f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4488f5f2fcee5c12d08df71d17017410c50951fc2e3James Dongstatus_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) {
4498f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("setParamVideoTimeScale: %d", timeScale);
4508f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4518f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    // 60000 is chosen to make sure that each video frame from a 60-fps
4528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    // video has 1000 ticks.
4538f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (timeScale < 600 || timeScale > 60000) {
4548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale);
4558f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        return BAD_VALUE;
4568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
4578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    mVideoTimeScale = timeScale;
4588f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    return OK;
4598f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong}
4608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dongstatus_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) {
4628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("setParamAudioTimeScale: %d", timeScale);
4638f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4648f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    // 96000 Hz is the highest sampling rate support in AAC.
4658f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (timeScale < 600 || timeScale > 96000) {
4668f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale);
4678f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        return BAD_VALUE;
4688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
4698f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    mAudioTimeScale = timeScale;
4708f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    return OK;
4718f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong}
4728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
473e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatrastatus_t StagefrightRecorder::setParamTimeLapseEnable(int32_t timeLapseEnable) {
474e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    LOGV("setParamTimeLapseEnable: %d", timeLapseEnable);
475e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra
476e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    if(timeLapseEnable == 0) {
477e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        mCaptureTimeLapse = false;
478e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    } else if (timeLapseEnable == 1) {
479e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        mCaptureTimeLapse = true;
480e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    } else {
481e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        return BAD_VALUE;
482e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    }
483e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    return OK;
484e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra}
485e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra
486f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatrastatus_t StagefrightRecorder::setParamUseStillCameraForTimeLapse(int32_t useStillCamera) {
487f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    LOGV("setParamUseStillCameraForTimeLapse: %d", useStillCamera);
488f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra
489f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    if(useStillCamera == 0) {
490f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra        mUseStillCameraForTimeLapse= false;
491f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    } else if (useStillCamera == 1) {
492f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra        mUseStillCameraForTimeLapse= true;
493f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    } else {
494f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra        return BAD_VALUE;
495f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    }
496f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    return OK;
497f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra}
498f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra
499e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatrastatus_t StagefrightRecorder::setParamTimeBetweenTimeLapseFrameCapture(int64_t timeUs) {
500e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    LOGV("setParamTimeBetweenTimeLapseFrameCapture: %lld us", timeUs);
501e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra
502e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    // Not allowing time more than a day
503e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    if (timeUs <= 0 || timeUs > 86400*1E6) {
504e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        LOGE("Time between time lapse frame capture (%lld) is out of range [0, 1 Day]", timeUs);
505e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        return BAD_VALUE;
506e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    }
507e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra
508e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    mTimeBetweenTimeLapseFrameCaptureUs = timeUs;
509e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    return OK;
510e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra}
511e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra
512050b28a593350047845a45a14cc5026221ac1620James Dongstatus_t StagefrightRecorder::setParameter(
513050b28a593350047845a45a14cc5026221ac1620James Dong        const String8 &key, const String8 &value) {
514050b28a593350047845a45a14cc5026221ac1620James Dong    LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
515050b28a593350047845a45a14cc5026221ac1620James Dong    if (key == "max-duration") {
516ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        int64_t max_duration_ms;
517050b28a593350047845a45a14cc5026221ac1620James Dong        if (safe_strtoi64(value.string(), &max_duration_ms)) {
518934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return setParamMaxFileDurationUs(1000LL * max_duration_ms);
519050b28a593350047845a45a14cc5026221ac1620James Dong        }
520050b28a593350047845a45a14cc5026221ac1620James Dong    } else if (key == "max-filesize") {
521ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        int64_t max_filesize_bytes;
522050b28a593350047845a45a14cc5026221ac1620James Dong        if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
523934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return setParamMaxFileSizeBytes(max_filesize_bytes);
524050b28a593350047845a45a14cc5026221ac1620James Dong        }
52593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    } else if (key == "interleave-duration-us") {
52693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int32_t durationUs;
52793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (safe_strtoi32(value.string(), &durationUs)) {
52893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return setParamInterleaveDuration(durationUs);
52993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
5308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    } else if (key == "param-movie-time-scale") {
5318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int32_t timeScale;
5328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (safe_strtoi32(value.string(), &timeScale)) {
5338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            return setParamMovieTimeScale(timeScale);
5348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        }
53593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    } else if (key == "param-use-64bit-offset") {
53693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int32_t use64BitOffset;
53793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (safe_strtoi32(value.string(), &use64BitOffset)) {
53893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return setParam64BitFileOffset(use64BitOffset != 0);
53993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
54093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    } else if (key == "param-track-time-status") {
54193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeDurationUs;
54293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (safe_strtoi64(value.string(), &timeDurationUs)) {
54393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return setParamTrackTimeStatus(timeDurationUs);
54493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
545050b28a593350047845a45a14cc5026221ac1620James Dong    } else if (key == "audio-param-sampling-rate") {
546050b28a593350047845a45a14cc5026221ac1620James Dong        int32_t sampling_rate;
547ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (safe_strtoi32(value.string(), &sampling_rate)) {
548050b28a593350047845a45a14cc5026221ac1620James Dong            return setParamAudioSamplingRate(sampling_rate);
549050b28a593350047845a45a14cc5026221ac1620James Dong        }
550050b28a593350047845a45a14cc5026221ac1620James Dong    } else if (key == "audio-param-number-of-channels") {
551050b28a593350047845a45a14cc5026221ac1620James Dong        int32_t number_of_channels;
552ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (safe_strtoi32(value.string(), &number_of_channels)) {
553050b28a593350047845a45a14cc5026221ac1620James Dong            return setParamAudioNumberOfChannels(number_of_channels);
554050b28a593350047845a45a14cc5026221ac1620James Dong        }
555050b28a593350047845a45a14cc5026221ac1620James Dong    } else if (key == "audio-param-encoding-bitrate") {
556050b28a593350047845a45a14cc5026221ac1620James Dong        int32_t audio_bitrate;
557ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (safe_strtoi32(value.string(), &audio_bitrate)) {
558050b28a593350047845a45a14cc5026221ac1620James Dong            return setParamAudioEncodingBitRate(audio_bitrate);
559050b28a593350047845a45a14cc5026221ac1620James Dong        }
5608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    } else if (key == "audio-param-time-scale") {
5618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int32_t timeScale;
5628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (safe_strtoi32(value.string(), &timeScale)) {
5638f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            return setParamAudioTimeScale(timeScale);
5648f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        }
565050b28a593350047845a45a14cc5026221ac1620James Dong    } else if (key == "video-param-encoding-bitrate") {
566050b28a593350047845a45a14cc5026221ac1620James Dong        int32_t video_bitrate;
567ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (safe_strtoi32(value.string(), &video_bitrate)) {
568050b28a593350047845a45a14cc5026221ac1620James Dong            return setParamVideoEncodingBitRate(video_bitrate);
569050b28a593350047845a45a14cc5026221ac1620James Dong        }
57093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    } else if (key == "video-param-i-frames-interval") {
5718f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int32_t seconds;
5728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (safe_strtoi32(value.string(), &seconds)) {
5738f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            return setParamVideoIFramesInterval(seconds);
574ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong        }
575145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    } else if (key == "video-param-encoder-profile") {
576145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        int32_t profile;
577145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        if (safe_strtoi32(value.string(), &profile)) {
578145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong            return setParamVideoEncoderProfile(profile);
579145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        }
580145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    } else if (key == "video-param-encoder-level") {
581145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        int32_t level;
582145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        if (safe_strtoi32(value.string(), &level)) {
583145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong            return setParamVideoEncoderLevel(level);
584145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        }
58593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    } else if (key == "video-param-camera-id") {
58693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int32_t cameraId;
58793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (safe_strtoi32(value.string(), &cameraId)) {
58893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return setParamVideoCameraId(cameraId);
5892dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
5908f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    } else if (key == "video-param-time-scale") {
5918f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int32_t timeScale;
5928f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (safe_strtoi32(value.string(), &timeScale)) {
5938f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            return setParamVideoTimeScale(timeScale);
5948f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        }
595e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    } else if (key == "time-lapse-enable") {
596e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        int32_t timeLapseEnable;
597e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        if (safe_strtoi32(value.string(), &timeLapseEnable)) {
598e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra            return setParamTimeLapseEnable(timeLapseEnable);
599e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        }
600f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    } else if (key == "use-still-camera-for-time-lapse") {
601f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra        int32_t useStillCamera;
602f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra        if (safe_strtoi32(value.string(), &useStillCamera)) {
603f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra            return setParamUseStillCameraForTimeLapse(useStillCamera);
604f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra        }
605e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    } else if (key == "time-between-time-lapse-frame-capture") {
606e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        int64_t timeBetweenTimeLapseFrameCaptureMs;
607e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
608e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra            return setParamTimeBetweenTimeLapseFrameCapture(
609e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra                    1000LL * timeBetweenTimeLapseFrameCaptureMs);
610e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        }
611050b28a593350047845a45a14cc5026221ac1620James Dong    } else {
612050b28a593350047845a45a14cc5026221ac1620James Dong        LOGE("setParameter: failed to find key %s", key.string());
613050b28a593350047845a45a14cc5026221ac1620James Dong    }
614ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    return BAD_VALUE;
615050b28a593350047845a45a14cc5026221ac1620James Dong}
61630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
617050b28a593350047845a45a14cc5026221ac1620James Dongstatus_t StagefrightRecorder::setParameters(const String8 &params) {
618050b28a593350047845a45a14cc5026221ac1620James Dong    LOGV("setParameters: %s", params.string());
619050b28a593350047845a45a14cc5026221ac1620James Dong    const char *cparams = params.string();
620050b28a593350047845a45a14cc5026221ac1620James Dong    const char *key_start = cparams;
621050b28a593350047845a45a14cc5026221ac1620James Dong    for (;;) {
622050b28a593350047845a45a14cc5026221ac1620James Dong        const char *equal_pos = strchr(key_start, '=');
623050b28a593350047845a45a14cc5026221ac1620James Dong        if (equal_pos == NULL) {
624050b28a593350047845a45a14cc5026221ac1620James Dong            LOGE("Parameters %s miss a value", cparams);
625050b28a593350047845a45a14cc5026221ac1620James Dong            return BAD_VALUE;
626050b28a593350047845a45a14cc5026221ac1620James Dong        }
627050b28a593350047845a45a14cc5026221ac1620James Dong        String8 key(key_start, equal_pos - key_start);
628050b28a593350047845a45a14cc5026221ac1620James Dong        TrimString(&key);
629050b28a593350047845a45a14cc5026221ac1620James Dong        if (key.length() == 0) {
630050b28a593350047845a45a14cc5026221ac1620James Dong            LOGE("Parameters %s contains an empty key", cparams);
631050b28a593350047845a45a14cc5026221ac1620James Dong            return BAD_VALUE;
632050b28a593350047845a45a14cc5026221ac1620James Dong        }
633050b28a593350047845a45a14cc5026221ac1620James Dong        const char *value_start = equal_pos + 1;
634050b28a593350047845a45a14cc5026221ac1620James Dong        const char *semicolon_pos = strchr(value_start, ';');
635050b28a593350047845a45a14cc5026221ac1620James Dong        String8 value;
636050b28a593350047845a45a14cc5026221ac1620James Dong        if (semicolon_pos == NULL) {
637050b28a593350047845a45a14cc5026221ac1620James Dong            value.setTo(value_start);
638050b28a593350047845a45a14cc5026221ac1620James Dong        } else {
639050b28a593350047845a45a14cc5026221ac1620James Dong            value.setTo(value_start, semicolon_pos - value_start);
640050b28a593350047845a45a14cc5026221ac1620James Dong        }
641050b28a593350047845a45a14cc5026221ac1620James Dong        if (setParameter(key, value) != OK) {
642050b28a593350047845a45a14cc5026221ac1620James Dong            return BAD_VALUE;
643050b28a593350047845a45a14cc5026221ac1620James Dong        }
644050b28a593350047845a45a14cc5026221ac1620James Dong        if (semicolon_pos == NULL) {
645050b28a593350047845a45a14cc5026221ac1620James Dong            break;  // Reaches the end
646050b28a593350047845a45a14cc5026221ac1620James Dong        }
647050b28a593350047845a45a14cc5026221ac1620James Dong        key_start = semicolon_pos + 1;
648050b28a593350047845a45a14cc5026221ac1620James Dong    }
64930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
65030ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
65130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
65237047fceba836f341d0108beed0991b0f8dfc543James Dongstatus_t StagefrightRecorder::setListener(const sp<IMediaRecorderClient> &listener) {
65330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mListener = listener;
65430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
65530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
65630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
65730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
65830ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::prepare() {
65930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
66030ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
66130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
66230ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::start() {
663934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK(mOutputFd >= 0);
664934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
66530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    if (mWriter != NULL) {
666934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("File writer is not avaialble");
66730ab66297501757d745b9ae10da61adcd891f497Andreas Huber        return UNKNOWN_ERROR;
66830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    }
66930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
6702dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    switch (mOutputFormat) {
6712dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        case OUTPUT_FORMAT_DEFAULT:
6722dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        case OUTPUT_FORMAT_THREE_GPP:
6732dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        case OUTPUT_FORMAT_MPEG_4:
6742dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber            return startMPEG4Recording();
6752dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
6762dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        case OUTPUT_FORMAT_AMR_NB:
6772dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        case OUTPUT_FORMAT_AMR_WB:
6782dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber            return startAMRRecording();
6792dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
680ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        case OUTPUT_FORMAT_AAC_ADIF:
681ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        case OUTPUT_FORMAT_AAC_ADTS:
682ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            return startAACRecording();
683ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
68439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        case OUTPUT_FORMAT_RTP_AVP:
68539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return startRTPRecording();
68639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
6872dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        default:
688934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            LOGE("Unsupported output file format: %d", mOutputFormat);
6892dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber            return UNKNOWN_ERROR;
6902dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    }
6912dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber}
6922dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
693050b28a593350047845a45a14cc5026221ac1620James Dongsp<MediaSource> StagefrightRecorder::createAudioSource() {
6942dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    sp<AudioSource> audioSource =
6952dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        new AudioSource(
6962dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber                mAudioSource,
697050b28a593350047845a45a14cc5026221ac1620James Dong                mSampleRate,
698be6ec71af2d12e2a55f2f0b1b77d3fa5d593a1c7James Dong                mAudioChannels);
6992dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
7002dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    status_t err = audioSource->initCheck();
7012dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
7022dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    if (err != OK) {
703050b28a593350047845a45a14cc5026221ac1620James Dong        LOGE("audio source is not initialized");
7042dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        return NULL;
7052dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    }
7062dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
7072dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    sp<MetaData> encMeta = new MetaData;
708050b28a593350047845a45a14cc5026221ac1620James Dong    const char *mime;
709050b28a593350047845a45a14cc5026221ac1620James Dong    switch (mAudioEncoder) {
710050b28a593350047845a45a14cc5026221ac1620James Dong        case AUDIO_ENCODER_AMR_NB:
711050b28a593350047845a45a14cc5026221ac1620James Dong        case AUDIO_ENCODER_DEFAULT:
712050b28a593350047845a45a14cc5026221ac1620James Dong            mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
713050b28a593350047845a45a14cc5026221ac1620James Dong            break;
714050b28a593350047845a45a14cc5026221ac1620James Dong        case AUDIO_ENCODER_AMR_WB:
715050b28a593350047845a45a14cc5026221ac1620James Dong            mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
716050b28a593350047845a45a14cc5026221ac1620James Dong            break;
717050b28a593350047845a45a14cc5026221ac1620James Dong        case AUDIO_ENCODER_AAC:
718050b28a593350047845a45a14cc5026221ac1620James Dong            mime = MEDIA_MIMETYPE_AUDIO_AAC;
719050b28a593350047845a45a14cc5026221ac1620James Dong            break;
720050b28a593350047845a45a14cc5026221ac1620James Dong        default:
721050b28a593350047845a45a14cc5026221ac1620James Dong            LOGE("Unknown audio encoder: %d", mAudioEncoder);
722050b28a593350047845a45a14cc5026221ac1620James Dong            return NULL;
723050b28a593350047845a45a14cc5026221ac1620James Dong    }
724050b28a593350047845a45a14cc5026221ac1620James Dong    encMeta->setCString(kKeyMIMEType, mime);
7252dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
726b45c62c8e9b05c2703bdae18cc298ae55550db8aAndreas Huber    int32_t maxInputSize;
727b45c62c8e9b05c2703bdae18cc298ae55550db8aAndreas Huber    CHECK(audioSource->getFormat()->findInt32(
728b45c62c8e9b05c2703bdae18cc298ae55550db8aAndreas Huber                kKeyMaxInputSize, &maxInputSize));
729b45c62c8e9b05c2703bdae18cc298ae55550db8aAndreas Huber
730b45c62c8e9b05c2703bdae18cc298ae55550db8aAndreas Huber    encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
731050b28a593350047845a45a14cc5026221ac1620James Dong    encMeta->setInt32(kKeyChannelCount, mAudioChannels);
732050b28a593350047845a45a14cc5026221ac1620James Dong    encMeta->setInt32(kKeySampleRate, mSampleRate);
733ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    encMeta->setInt32(kKeyBitRate, mAudioBitRate);
734c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mAudioTimeScale > 0) {
735c059860c73678a202bfa33062723e8f82fb779d9James Dong        encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
736c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
7372dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
7382dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    OMXClient client;
7392dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    CHECK_EQ(client.connect(), OK);
7402dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
7412dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    sp<MediaSource> audioEncoder =
7422dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        OMXCodec::Create(client.interface(), encMeta,
7432dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber                         true /* createEncoder */, audioSource);
744d3d4e5069e1af0437c4f5a7b4ba344bda5b937afJames Dong    mAudioSourceNode = audioSource;
7452dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
7462dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return audioEncoder;
7472dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber}
7482dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
749ef9d0cd72e476a4b7556833fb09505a51b626797James Dongstatus_t StagefrightRecorder::startAACRecording() {
750ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
751ef9d0cd72e476a4b7556833fb09505a51b626797James Dong          mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
752ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
753ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
754ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    CHECK(mAudioSource != AUDIO_SOURCE_LIST_END);
755ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
756ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    CHECK(0 == "AACWriter is not implemented yet");
757ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
758ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    return OK;
759ef9d0cd72e476a4b7556833fb09505a51b626797James Dong}
760ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
7612dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t StagefrightRecorder::startAMRRecording() {
762ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
763ef9d0cd72e476a4b7556833fb09505a51b626797James Dong          mOutputFormat == OUTPUT_FORMAT_AMR_WB);
764ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
765ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (mOutputFormat == OUTPUT_FORMAT_AMR_NB) {
766ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (mAudioEncoder != AUDIO_ENCODER_DEFAULT &&
767ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
768ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            LOGE("Invalid encoder %d used for AMRNB recording",
769ef9d0cd72e476a4b7556833fb09505a51b626797James Dong                    mAudioEncoder);
770934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return BAD_VALUE;
771ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        }
772ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (mSampleRate != 8000) {
773ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            LOGE("Invalid sampling rate %d used for AMRNB recording",
774ef9d0cd72e476a4b7556833fb09505a51b626797James Dong                    mSampleRate);
775934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return BAD_VALUE;
776ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        }
777ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    } else {  // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
778ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
779ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            LOGE("Invlaid encoder %d used for AMRWB recording",
780ef9d0cd72e476a4b7556833fb09505a51b626797James Dong                    mAudioEncoder);
781934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return BAD_VALUE;
782ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        }
783ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        if (mSampleRate != 16000) {
784ef9d0cd72e476a4b7556833fb09505a51b626797James Dong            LOGE("Invalid sample rate %d used for AMRWB recording",
785ef9d0cd72e476a4b7556833fb09505a51b626797James Dong                    mSampleRate);
786934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return BAD_VALUE;
787ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        }
788ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    }
789ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (mAudioChannels != 1) {
790ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid number of audio channels %d used for amr recording",
791ef9d0cd72e476a4b7556833fb09505a51b626797James Dong                mAudioChannels);
792934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return BAD_VALUE;
7932dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    }
7942dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
795ef9d0cd72e476a4b7556833fb09505a51b626797James Dong    if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
796ef9d0cd72e476a4b7556833fb09505a51b626797James Dong        LOGE("Invalid audio source: %d", mAudioSource);
797934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return BAD_VALUE;
7982dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    }
7992dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
800050b28a593350047845a45a14cc5026221ac1620James Dong    sp<MediaSource> audioEncoder = createAudioSource();
8012dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
8022dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    if (audioEncoder == NULL) {
8032dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber        return UNKNOWN_ERROR;
8042dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    }
8052dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
8062dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    mWriter = new AMRWriter(dup(mOutputFd));
8072dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    mWriter->addSource(audioEncoder);
808d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
809d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationUs != 0) {
810d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        mWriter->setMaxFileDuration(mMaxFileDurationUs);
811d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
812d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeBytes != 0) {
813d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        mWriter->setMaxFileSize(mMaxFileSizeBytes);
814d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
815d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    mWriter->setListener(mListener);
8162dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    mWriter->start();
8172dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
8182dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
8192dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber}
8202dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
82139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberstatus_t StagefrightRecorder::startRTPRecording() {
82239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
82339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
82439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if ((mAudioSource != AUDIO_SOURCE_LIST_END
82539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                && mVideoSource != VIDEO_SOURCE_LIST_END)
82639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            || (mAudioSource == AUDIO_SOURCE_LIST_END
82739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber                && mVideoSource == VIDEO_SOURCE_LIST_END)) {
82839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        // Must have exactly one source.
82939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return BAD_VALUE;
83039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
83139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
83239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (mOutputFd < 0) {
83339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        return BAD_VALUE;
83439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
83539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
83639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    sp<MediaSource> source;
83739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
83839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    if (mAudioSource != AUDIO_SOURCE_LIST_END) {
83939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        source = createAudioSource();
84039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    } else {
84139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        status_t err = setupVideoEncoder(&source);
84239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        if (err != OK) {
84339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber            return err;
84439ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        }
84539ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    }
84639ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
84739ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mWriter = new ARTPWriter(dup(mOutputFd));
84839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mWriter->addSource(source);
84939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    mWriter->setListener(mListener);
85039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
85139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    return mWriter->start();
85239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber}
85339ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
85499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dongvoid StagefrightRecorder::clipVideoFrameRate() {
85599c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
85699c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
85799c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.fps.min", mVideoEncoder);
85899c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName(
85999c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.fps.max", mVideoEncoder);
86099c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    if (mFrameRate < minFrameRate) {
86199c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding frame rate (%d fps) is too small"
86299c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d fps)", mFrameRate, minFrameRate);
86399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mFrameRate = minFrameRate;
86499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    } else if (mFrameRate > maxFrameRate) {
86599c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding frame rate (%d fps) is too large"
86699c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d fps)", mFrameRate, maxFrameRate);
86799c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mFrameRate = maxFrameRate;
86899c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    }
86999c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong}
87099c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong
87199c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dongvoid StagefrightRecorder::clipVideoBitRate() {
87299c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    LOGV("clipVideoBitRate: encoder %d", mVideoEncoder);
87399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int minBitRate = mEncoderProfiles->getVideoEncoderParamByName(
87499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.bps.min", mVideoEncoder);
87599c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int maxBitRate = mEncoderProfiles->getVideoEncoderParamByName(
87699c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.bps.max", mVideoEncoder);
87799c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    if (mVideoBitRate < minBitRate) {
87899c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding bit rate (%d bps) is too small"
87999c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d bps)", mVideoBitRate, minBitRate);
88099c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mVideoBitRate = minBitRate;
88199c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    } else if (mVideoBitRate > maxBitRate) {
88299c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding bit rate (%d bps) is too large"
88399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d bps)", mVideoBitRate, maxBitRate);
88499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mVideoBitRate = maxBitRate;
88599c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    }
88699c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong}
88799c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong
88899c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dongvoid StagefrightRecorder::clipVideoFrameWidth() {
88999c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    LOGV("clipVideoFrameWidth: encoder %d", mVideoEncoder);
89099c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int minFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
89199c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.width.min", mVideoEncoder);
89299c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int maxFrameWidth = mEncoderProfiles->getVideoEncoderParamByName(
89399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.width.max", mVideoEncoder);
89499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    if (mVideoWidth < minFrameWidth) {
89599c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding frame width (%d) is too small"
89699c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d)", mVideoWidth, minFrameWidth);
89799c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mVideoWidth = minFrameWidth;
89899c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    } else if (mVideoWidth > maxFrameWidth) {
89999c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding frame width (%d) is too large"
90099c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d)", mVideoWidth, maxFrameWidth);
90199c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mVideoWidth = maxFrameWidth;
90299c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    }
90399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong}
90499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong
905934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dongstatus_t StagefrightRecorder::setupCameraSource() {
906ca2fa61ef03cac008ea86e6fe16b2e5f9f1a2be3Nipun Kwatra    if (!mCaptureTimeLapse) {
907e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        // Dont clip for time lapse capture as encoder will have enough
908e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        // time to encode because of slow capture rate of time lapse.
909e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        clipVideoBitRate();
910e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        clipVideoFrameRate();
911e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        clipVideoFrameWidth();
912e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        clipVideoFrameHeight();
913e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    }
914934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
915934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    int64_t token = IPCThreadState::self()->clearCallingIdentity();
916934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (mCamera == 0) {
917934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        mCamera = Camera::connect(mCameraId);
918934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        if (mCamera == 0) {
919934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            LOGE("Camera connection could not be established.");
920934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return -EBUSY;
921934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        }
922934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        mFlags &= ~FLAGS_HOT_CAMERA;
923934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        mCamera->lock();
924934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
925934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
926934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    // Set the actual video recording frame size
927934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CameraParameters params(mCamera->getParameters());
928e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra
929ca2fa61ef03cac008ea86e6fe16b2e5f9f1a2be3Nipun Kwatra    // dont change the preview size when using still camera for time lapse
930ca2fa61ef03cac008ea86e6fe16b2e5f9f1a2be3Nipun Kwatra    // as mVideoWidth, mVideoHeight may correspond to HD resolution not
931ca2fa61ef03cac008ea86e6fe16b2e5f9f1a2be3Nipun Kwatra    // supported by the video camera.
932ca2fa61ef03cac008ea86e6fe16b2e5f9f1a2be3Nipun Kwatra    if (!(mCaptureTimeLapse && mUseStillCameraForTimeLapse)) {
933e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        params.setPreviewSize(mVideoWidth, mVideoHeight);
934e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    }
935e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra
936934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    params.setPreviewFrameRate(mFrameRate);
937934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    String8 s = params.flatten();
93848f6ce0e17297c575dcbb25671a7bee80ba13061James Dong    if (OK != mCamera->setParameters(s)) {
93948f6ce0e17297c575dcbb25671a7bee80ba13061James Dong        LOGE("Could not change settings."
94048f6ce0e17297c575dcbb25671a7bee80ba13061James Dong             " Someone else is using camera %d?", mCameraId);
94148f6ce0e17297c575dcbb25671a7bee80ba13061James Dong        return -EBUSY;
94248f6ce0e17297c575dcbb25671a7bee80ba13061James Dong    }
943934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CameraParameters newCameraParams(mCamera->getParameters());
944934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
945934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    // Check on video frame size
946934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    int frameWidth = 0, frameHeight = 0;
947934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    newCameraParams.getPreviewSize(&frameWidth, &frameHeight);
948ca2fa61ef03cac008ea86e6fe16b2e5f9f1a2be3Nipun Kwatra    if (!(mCaptureTimeLapse && mUseStillCameraForTimeLapse) &&
949e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        (frameWidth  < 0 || frameWidth  != mVideoWidth ||
950e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra        frameHeight < 0 || frameHeight != mVideoHeight)) {
951934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Failed to set the video frame size to %dx%d",
952934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong                mVideoWidth, mVideoHeight);
953934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        IPCThreadState::self()->restoreCallingIdentity(token);
954934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return UNKNOWN_ERROR;
955934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
956934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
957934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    // Check on video frame rate
958934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    int frameRate = newCameraParams.getPreviewFrameRate();
959934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (frameRate < 0 || (frameRate - mFrameRate) != 0) {
960934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        LOGE("Failed to set frame rate to %d fps. The actual "
961934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong             "frame rate is %d", mFrameRate, frameRate);
962934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
963934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
96448f6ce0e17297c575dcbb25671a7bee80ba13061James Dong    // This CHECK is good, since we just passed the lock/unlock
96548f6ce0e17297c575dcbb25671a7bee80ba13061James Dong    // check earlier by calling mCamera->setParameters().
966934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK_EQ(OK, mCamera->setPreviewDisplay(mPreviewSurface));
967934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    IPCThreadState::self()->restoreCallingIdentity(token);
968934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    return OK;
969934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong}
970934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong
97199c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dongvoid StagefrightRecorder::clipVideoFrameHeight() {
97299c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
97399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
97499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.height.min", mVideoEncoder);
97599c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    int maxFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
97699c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong                        "enc.vid.height.max", mVideoEncoder);
97799c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    if (mVideoHeight < minFrameHeight) {
97899c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding frame height (%d) is too small"
97999c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d)", mVideoHeight, minFrameHeight);
98099c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mVideoHeight = minFrameHeight;
98199c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    } else if (mVideoHeight > maxFrameHeight) {
98299c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        LOGW("Intended video encoding frame height (%d) is too large"
98399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong             " and will be set to (%d)", mVideoHeight, maxFrameHeight);
98499c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong        mVideoHeight = maxFrameHeight;
98599c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    }
98699c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong}
98799c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong
98839ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huberstatus_t StagefrightRecorder::setupVideoEncoder(sp<MediaSource> *source) {
98939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    source->clear();
99039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
991934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    status_t err = setupCameraSource();
992934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (err != OK) return err;
9932dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
99465e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra    sp<CameraSource> cameraSource = (mCaptureTimeLapse) ?
995f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra        CameraSourceTimeLapse::CreateFromCamera(mCamera, mUseStillCameraForTimeLapse,
996e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra                mTimeBetweenTimeLapseFrameCaptureUs, mVideoWidth, mVideoHeight, mFrameRate):
99765e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra        CameraSource::CreateFromCamera(mCamera);
998934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK(cameraSource != NULL);
999050b28a593350047845a45a14cc5026221ac1620James Dong
1000934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    sp<MetaData> enc_meta = new MetaData;
1001934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    enc_meta->setInt32(kKeyBitRate, mVideoBitRate);
1002934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    enc_meta->setInt32(kKeySampleRate, mFrameRate);
1003ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
1004934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    switch (mVideoEncoder) {
1005934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        case VIDEO_ENCODER_H263:
1006934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
1007934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            break;
100865ae665befd929efd1a7d1c9addac41c699f04b2James Dong
1009934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        case VIDEO_ENCODER_MPEG_4_SP:
1010934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
1011934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            break;
101230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1013934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        case VIDEO_ENCODER_H264:
1014934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
1015934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            break;
101630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1017934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        default:
1018934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            CHECK(!"Should not be here, unsupported video encoding.");
1019934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            break;
1020934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
1021ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
1022934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    sp<MetaData> meta = cameraSource->getFormat();
102330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
102429a84457aed4c45bc900998b5e11c03023264208James Dong    int32_t width, height, stride, sliceHeight, colorFormat;
1025934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK(meta->findInt32(kKeyWidth, &width));
1026934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK(meta->findInt32(kKeyHeight, &height));
1027934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK(meta->findInt32(kKeyStride, &stride));
1028934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
102929a84457aed4c45bc900998b5e11c03023264208James Dong    CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
103030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1031934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    enc_meta->setInt32(kKeyWidth, width);
1032934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    enc_meta->setInt32(kKeyHeight, height);
10338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
1034934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    enc_meta->setInt32(kKeyStride, stride);
1035934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    enc_meta->setInt32(kKeySliceHeight, sliceHeight);
103629a84457aed4c45bc900998b5e11c03023264208James Dong    enc_meta->setInt32(kKeyColorFormat, colorFormat);
1037c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mVideoTimeScale > 0) {
1038c059860c73678a202bfa33062723e8f82fb779d9James Dong        enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
1039c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1040145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    if (mVideoEncoderProfile != -1) {
1041145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
1042145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    }
1043145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    if (mVideoEncoderLevel != -1) {
1044145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong        enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
1045145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    }
104630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1047934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    OMXClient client;
1048934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    CHECK_EQ(client.connect(), OK);
104930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1050e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    // Use software codec for time lapse
10517a42770f47225483a885b168d05e81b6a81189c0Nipun Kwatra    uint32_t encoder_flags = (mCaptureTimeLapse) ? OMXCodec::kPreferSoftwareCodecs : 0;
1052934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    sp<MediaSource> encoder = OMXCodec::Create(
1053934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            client.interface(), enc_meta,
10547a42770f47225483a885b168d05e81b6a81189c0Nipun Kwatra            true /* createEncoder */, cameraSource,
10557a42770f47225483a885b168d05e81b6a81189c0Nipun Kwatra            NULL, encoder_flags);
1056934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (encoder == NULL) {
1057934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return UNKNOWN_ERROR;
1058934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
105930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
106039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber    *source = encoder;
106139ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber
1062934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    return OK;
1063934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong}
106430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1065934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dongstatus_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
1066934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    sp<MediaSource> audioEncoder;
1067934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    switch(mAudioEncoder) {
1068934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        case AUDIO_ENCODER_AMR_NB:
1069934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        case AUDIO_ENCODER_AMR_WB:
1070934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        case AUDIO_ENCODER_AAC:
1071934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            audioEncoder = createAudioSource();
1072934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            break;
1073934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        default:
1074934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            LOGE("Unsupported audio encoder: %d", mAudioEncoder);
1075934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            return UNKNOWN_ERROR;
1076934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
107730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1078934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (audioEncoder == NULL) {
1079934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        return UNKNOWN_ERROR;
1080934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
10818f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
1082934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    writer->addSource(audioEncoder);
1083934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    return OK;
1084934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong}
108530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1086934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dongstatus_t StagefrightRecorder::startMPEG4Recording() {
1087934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    int32_t totalBitRate = 0;
1088934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    status_t err = OK;
1089934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    sp<MediaWriter> writer = new MPEG4Writer(dup(mOutputFd));
109030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1091934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    // Add audio source first if it exists
1092fc20aab463f527ab3b0664986f0381a86b375884Nipun Kwatra    if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_LIST_END)) {
1093934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        err = setupAudioEncoder(writer);
1094934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        if (err != OK) return err;
1095934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        totalBitRate += mAudioBitRate;
1096934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    }
1097934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    if (mVideoSource == VIDEO_SOURCE_DEFAULT
1098934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong            || mVideoSource == VIDEO_SOURCE_CAMERA) {
109939ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        sp<MediaSource> encoder;
110039ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        err = setupVideoEncoder(&encoder);
1101934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        if (err != OK) return err;
110239ddf8e0f18766f7ba1e3246b774aa6ebd93eea8Andreas Huber        writer->addSource(encoder);
11032dec2b5be2056c6d9428897dc672185872d30d17James Dong        totalBitRate += mVideoBitRate;
110430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    }
110530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1106f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong    if (mInterleaveDurationUs > 0) {
1107f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong        reinterpret_cast<MPEG4Writer *>(writer.get())->
1108f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong            setInterleaveDuration(mInterleaveDurationUs);
1109f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong    }
1110ef9d0cd72e476a4b7556833fb09505a51b626797James Dong
1111d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationUs != 0) {
1112934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        writer->setMaxFileDuration(mMaxFileDurationUs);
1113d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1114d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeBytes != 0) {
1115934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        writer->setMaxFileSize(mMaxFileSizeBytes);
1116d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
11172dec2b5be2056c6d9428897dc672185872d30d17James Dong    sp<MetaData> meta = new MetaData;
111893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    meta->setInt64(kKeyTime, systemTime() / 1000);
111993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    meta->setInt32(kKeyFileType, mOutputFormat);
11202dec2b5be2056c6d9428897dc672185872d30d17James Dong    meta->setInt32(kKeyBitRate, totalBitRate);
11212dec2b5be2056c6d9428897dc672185872d30d17James Dong    meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
1122c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMovieTimeScale > 0) {
1123c059860c73678a202bfa33062723e8f82fb779d9James Dong        meta->setInt32(kKeyTimeScale, mMovieTimeScale);
1124c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
112593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    if (mTrackEveryTimeDurationUs > 0) {
112693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
112793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
1128934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    writer->setListener(mListener);
1129934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    mWriter = writer;
1130934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong    return mWriter->start(meta.get());
113130ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
113230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1133a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dongstatus_t StagefrightRecorder::pause() {
1134d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("pause");
1135a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mWriter == NULL) {
1136a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return UNKNOWN_ERROR;
1137a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
1138a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mWriter->pause();
1139a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
1140a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1141a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
114230ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::stop() {
1143d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("stop");
114437187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
1145d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (mWriter != NULL) {
114637187916a486504acaf83bea30147eb5fbf46ae5James Dong        err = mWriter->stop();
1147934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        mWriter.clear();
114830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    }
114930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1150c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    if (mCamera != 0) {
1151d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        LOGV("Disconnect camera");
11529d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong        int64_t token = IPCThreadState::self()->clearCallingIdentity();
1153c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        if ((mFlags & FLAGS_HOT_CAMERA) == 0) {
1154c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong            LOGV("Camera was cold when we started, stopping preview");
1155c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong            mCamera->stopPreview();
1156c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        }
11579d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong        mCamera->unlock();
1158934da11c4cc598d3dd3b53726c362bcdcc0fd37fJames Dong        mCamera.clear();
11599d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong        IPCThreadState::self()->restoreCallingIdentity(token);
1160c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        mFlags = 0;
1161c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    }
1162d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
116325d83125cee222993673d3ba261ae1186bcad8c2James Dong    if (mOutputFd >= 0) {
116425d83125cee222993673d3ba261ae1186bcad8c2James Dong        ::close(mOutputFd);
116525d83125cee222993673d3ba261ae1186bcad8c2James Dong        mOutputFd = -1;
116625d83125cee222993673d3ba261ae1186bcad8c2James Dong    }
116725d83125cee222993673d3ba261ae1186bcad8c2James Dong
116837187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
1169d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong}
1170d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
1171d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dongstatus_t StagefrightRecorder::close() {
1172d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("close");
1173d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    stop();
1174d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
117530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
117630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
117730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
117830ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::reset() {
1179d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("reset");
118030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    stop();
118130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1182050b28a593350047845a45a14cc5026221ac1620James Dong    // No audio or video source by default
118330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mAudioSource = AUDIO_SOURCE_LIST_END;
118430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mVideoSource = VIDEO_SOURCE_LIST_END;
1185050b28a593350047845a45a14cc5026221ac1620James Dong
1186050b28a593350047845a45a14cc5026221ac1620James Dong    // Default parameters
1187050b28a593350047845a45a14cc5026221ac1620James Dong    mOutputFormat  = OUTPUT_FORMAT_THREE_GPP;
1188050b28a593350047845a45a14cc5026221ac1620James Dong    mAudioEncoder  = AUDIO_ENCODER_AMR_NB;
1189050b28a593350047845a45a14cc5026221ac1620James Dong    mVideoEncoder  = VIDEO_ENCODER_H263;
1190050b28a593350047845a45a14cc5026221ac1620James Dong    mVideoWidth    = 176;
1191050b28a593350047845a45a14cc5026221ac1620James Dong    mVideoHeight   = 144;
1192050b28a593350047845a45a14cc5026221ac1620James Dong    mFrameRate     = 20;
1193050b28a593350047845a45a14cc5026221ac1620James Dong    mVideoBitRate  = 192000;
1194050b28a593350047845a45a14cc5026221ac1620James Dong    mSampleRate    = 8000;
1195050b28a593350047845a45a14cc5026221ac1620James Dong    mAudioChannels = 1;
1196050b28a593350047845a45a14cc5026221ac1620James Dong    mAudioBitRate  = 12200;
1197e136c3bb38e88315bf8797a464ebf2c788296b22James Dong    mInterleaveDurationUs = 0;
11988f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    mIFramesIntervalSec = 1;
1199d3d4e5069e1af0437c4f5a7b4ba344bda5b937afJames Dong    mAudioSourceNode = 0;
12002dec2b5be2056c6d9428897dc672185872d30d17James Dong    mUse64BitFileOffset = false;
1201c059860c73678a202bfa33062723e8f82fb779d9James Dong    mMovieTimeScale  = -1;
1202c059860c73678a202bfa33062723e8f82fb779d9James Dong    mAudioTimeScale  = -1;
1203c059860c73678a202bfa33062723e8f82fb779d9James Dong    mVideoTimeScale  = -1;
120493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mCameraId        = 0;
1205145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    mVideoEncoderProfile = -1;
1206145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    mVideoEncoderLevel   = -1;
1207145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    mMaxFileDurationUs = 0;
1208145bfe5eb3e08c9689c28f6bf3287a979438b04bJames Dong    mMaxFileSizeBytes = 0;
120993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
1210fc20aab463f527ab3b0664986f0381a86b375884Nipun Kwatra    mCaptureTimeLapse = false;
1211f95ce6452d87316b8f5df6692537bd039377f349Nipun Kwatra    mUseStillCameraForTimeLapse = true;
1212e4e0a6994d39c4a7cba09c5fff442b2dca1df8f8Nipun Kwatra    mTimeBetweenTimeLapseFrameCaptureUs = -1;
121399c2a076b4a46762a22bbb4dfbd51d107e0532d9James Dong    mEncoderProfiles = MediaProfiles::getInstance();
1214050b28a593350047845a45a14cc5026221ac1620James Dong
121530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mOutputFd = -1;
1216c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    mFlags = 0;
121730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
121830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return OK;
121930ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
122030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
122130ab66297501757d745b9ae10da61adcd891f497Andreas Huberstatus_t StagefrightRecorder::getMaxAmplitude(int *max) {
1222d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    LOGV("getMaxAmplitude");
1223d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
1224d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    if (max == NULL) {
1225d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        LOGE("Null pointer argument");
1226d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong        return BAD_VALUE;
1227d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong    }
1228d329e21495eda9dbc531fdd0c26c77f1593ac3f4James Dong
1229d3d4e5069e1af0437c4f5a7b4ba344bda5b937afJames Dong    if (mAudioSourceNode != 0) {
1230d3d4e5069e1af0437c4f5a7b4ba344bda5b937afJames Dong        *max = mAudioSourceNode->getMaxAmplitude();
1231d3d4e5069e1af0437c4f5a7b4ba344bda5b937afJames Dong    } else {
1232d3d4e5069e1af0437c4f5a7b4ba344bda5b937afJames Dong        *max = 0;
1233d3d4e5069e1af0437c4f5a7b4ba344bda5b937afJames Dong    }
12342dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
12352dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
123630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
123730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1238b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dongstatus_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const {
1239b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    const size_t SIZE = 256;
1240b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    char buffer[SIZE];
1241b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    String8 result;
1242b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "   Recorder: %p", this);
1243b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "   Output file (fd %d):\n", mOutputFd);
1244b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1245b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     File format: %d\n", mOutputFormat);
1246b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1247b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Max file size (bytes): %lld\n", mMaxFileSizeBytes);
1248b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1249b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Max file duration (us): %lld\n", mMaxFileDurationUs);
1250b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1251b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
1252b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1253b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Interleave duration (us): %d\n", mInterleaveDurationUs);
1254b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1255b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
1256b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1257b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "   Audio\n");
1258b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1259b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Source: %d\n", mAudioSource);
1260b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1261b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Encoder: %d\n", mAudioEncoder);
1262b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1263b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mAudioBitRate);
1264b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1265b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Sampling rate (hz): %d\n", mSampleRate);
1266b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1267b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Number of channels: %d\n", mAudioChannels);
1268b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1269b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
1270b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1271b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "   Video\n");
1272b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1273b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Source: %d\n", mVideoSource);
1274b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1275b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Camera Id: %d\n", mCameraId);
1276b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1277b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Camera flags: %d\n", mFlags);
1278b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1279b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Encoder: %d\n", mVideoEncoder);
1280b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1281b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Encoder profile: %d\n", mVideoEncoderProfile);
1282b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1283b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Encoder level: %d\n", mVideoEncoderLevel);
1284b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
12858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    snprintf(buffer, SIZE, "     I frames interval (s): %d\n", mIFramesIntervalSec);
1286b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1287b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
1288b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1289b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Frame rate (fps): %d\n", mFrameRate);
1290b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1291b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mVideoBitRate);
1292b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    result.append(buffer);
1293b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    ::write(fd, result.string(), result.size());
1294b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong    return OK;
1295b914122eb9cb54bbeae4ec03bfebb194aecdccbdJames Dong}
129630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}  // namespace android
1297