recordvideo.cpp revision c97a1325466bb0e6cee884ec24a04b65082b853a
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SineSource.h"
18
19#include <binder/ProcessState.h>
20#include <media/stagefright/AudioPlayer.h>
21#include <media/stagefright/MediaBufferGroup.h>
22#include <media/stagefright/MediaDebug.h>
23#include <media/stagefright/MediaDefs.h>
24#include <media/stagefright/MetaData.h>
25#include <media/stagefright/MPEG4Writer.h>
26#include <media/stagefright/OMXClient.h>
27#include <media/stagefright/OMXCodec.h>
28#include <media/MediaPlayerInterface.h>
29
30using namespace android;
31
32// Print usage showing how to use this utility to record videos
33static void usage(const char *me) {
34    fprintf(stderr, "usage: %s\n", me);
35    fprintf(stderr, "       -h(elp)\n");
36    fprintf(stderr, "       -b bit rate in bits per second (default: 300000)\n");
37    fprintf(stderr, "       -c YUV420 color format: [0] semi planar or [1] planar (default: 1)\n");
38    fprintf(stderr, "       -f frame rate in frames per second (default: 30)\n");
39    fprintf(stderr, "       -i I frame interval in seconds (default: 1)\n");
40    fprintf(stderr, "       -n number of frames to be recorded (default: 300)\n");
41    fprintf(stderr, "       -w width in pixels (default: 176)\n");
42    fprintf(stderr, "       -t height in pixels (default: 144)\n");
43    fprintf(stderr, "       -l encoder level. see omx il header (default: encoder specific)\n");
44    fprintf(stderr, "       -p encoder profile. see omx il header (default: encoder specific)\n");
45    fprintf(stderr, "       -v video codec: [0] AVC [1] M4V [2] H263 (default: 0)\n");
46    fprintf(stderr, "The output file is /sdcard/output.mp4\n");
47    exit(1);
48}
49
50class DummySource : public MediaSource {
51
52public:
53    DummySource(int width, int height, int nFrames, int fps, int colorFormat)
54        : mWidth(width),
55          mHeight(height),
56          mMaxNumFrames(nFrames),
57          mFrameRate(fps),
58          mColorFormat(colorFormat),
59          mSize((width * height * 3) / 2) {
60
61        mGroup.add_buffer(new MediaBuffer(mSize));
62
63        // Check the color format to make sure
64        // that the buffer size mSize it set correctly above.
65        CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
66              colorFormat == OMX_COLOR_FormatYUV420Planar);
67    }
68
69    virtual sp<MetaData> getFormat() {
70        sp<MetaData> meta = new MetaData;
71        meta->setInt32(kKeyWidth, mWidth);
72        meta->setInt32(kKeyHeight, mHeight);
73        meta->setInt32(kKeyColorFormat, mColorFormat);
74        meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
75
76        return meta;
77    }
78
79    virtual status_t start(MetaData *params) {
80        mNumFramesOutput = 0;
81        return OK;
82    }
83
84    virtual status_t stop() {
85        return OK;
86    }
87
88    virtual status_t read(
89            MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
90
91        if (mNumFramesOutput % 10 == 0) {
92            fprintf(stderr, ".");
93        }
94        if (mNumFramesOutput == mMaxNumFrames) {
95            return ERROR_END_OF_STREAM;
96        }
97
98        status_t err = mGroup.acquire_buffer(buffer);
99        if (err != OK) {
100            return err;
101        }
102
103        // We don't care about the contents. we just test video encoder
104        // Also, by skipping the content generation, we can return from
105        // read() much faster.
106        //char x = (char)((double)rand() / RAND_MAX * 255);
107        //memset((*buffer)->data(), x, mSize);
108        (*buffer)->set_range(0, mSize);
109        (*buffer)->meta_data()->clear();
110        (*buffer)->meta_data()->setInt64(
111                kKeyTime, (mNumFramesOutput * 1000000) / mFrameRate);
112        ++mNumFramesOutput;
113
114        return OK;
115    }
116
117protected:
118    virtual ~DummySource() {}
119
120private:
121    MediaBufferGroup mGroup;
122    int mWidth, mHeight;
123    int mMaxNumFrames;
124    int mFrameRate;
125    int mColorFormat;
126    size_t mSize;
127    int64_t mNumFramesOutput;;
128
129    DummySource(const DummySource &);
130    DummySource &operator=(const DummySource &);
131};
132
133enum {
134    kYUV420SP = 0,
135    kYUV420P  = 1,
136};
137
138// returns -1 if mapping of the given color is unsuccessful
139// returns an omx color enum value otherwise
140static int translateColorToOmxEnumValue(int color) {
141    switch (color) {
142        case kYUV420SP:
143            return OMX_COLOR_FormatYUV420SemiPlanar;
144        case kYUV420P:
145            return OMX_COLOR_FormatYUV420Planar;
146        default:
147            fprintf(stderr, "Unsupported color: %d\n", color);
148            return -1;
149    }
150}
151
152int main(int argc, char **argv) {
153
154    // Default values for the program if not overwritten
155    int frameRateFps = 30;
156    int width = 176;
157    int height = 144;
158    int bitRateBps = 300000;
159    int iFramesIntervalSeconds = 1;
160    int colorFormat = OMX_COLOR_FormatYUV420Planar;
161    int nFrames = 300;
162    int level = -1;        // Encoder specific default
163    int profile = -1;      // Encoder specific default
164    int codec = 0;
165    const char *fileName = "/sdcard/output.mp4";
166
167    android::ProcessState::self()->startThreadPool();
168    int res;
169    while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:h")) >= 0) {
170        switch (res) {
171            case 'b':
172            {
173                bitRateBps = atoi(optarg);
174                break;
175            }
176
177            case 'c':
178            {
179                colorFormat = translateColorToOmxEnumValue(atoi(optarg));
180                if (colorFormat == -1) {
181                    usage(argv[0]);
182                }
183                break;
184            }
185
186            case 'f':
187            {
188                frameRateFps = atoi(optarg);
189                break;
190            }
191
192            case 'i':
193            {
194                iFramesIntervalSeconds = atoi(optarg);
195                break;
196            }
197
198            case 'n':
199            {
200                nFrames = atoi(optarg);
201                break;
202            }
203
204            case 'w':
205            {
206                width = atoi(optarg);
207                break;
208            }
209
210            case 't':
211            {
212                height = atoi(optarg);
213                break;
214            }
215
216            case 'l':
217            {
218                level = atoi(optarg);
219                break;
220            }
221
222            case 'p':
223            {
224                profile = atoi(optarg);
225                break;
226            }
227
228            case 'v':
229            {
230                codec = atoi(optarg);
231                if (codec < 0 || codec > 2) {
232                    usage(argv[0]);
233                }
234                break;
235            }
236
237            case 'h':
238            default:
239            {
240                usage(argv[0]);
241                break;
242            }
243        }
244    }
245
246    OMXClient client;
247    CHECK_EQ(client.connect(), OK);
248
249    status_t err = OK;
250    sp<MediaSource> source =
251        new DummySource(width, height, nFrames, frameRateFps, colorFormat);
252
253    sp<MetaData> enc_meta = new MetaData;
254    switch (codec) {
255        case 1:
256            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
257            break;
258        case 2:
259            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
260            break;
261        default:
262            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
263            break;
264    }
265    enc_meta->setInt32(kKeyWidth, width);
266    enc_meta->setInt32(kKeyHeight, height);
267    enc_meta->setInt32(kKeySampleRate, frameRateFps);
268    enc_meta->setInt32(kKeyBitRate, bitRateBps);
269    enc_meta->setInt32(kKeyStride, width);
270    enc_meta->setInt32(kKeySliceHeight, height);
271    enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds);
272    enc_meta->setInt32(kKeyColorFormat, colorFormat);
273    if (level != -1) {
274        enc_meta->setInt32(kKeyVideoLevel, level);
275    }
276    if (profile != -1) {
277        enc_meta->setInt32(kKeyVideoProfile, profile);
278    }
279
280    sp<MediaSource> encoder =
281        OMXCodec::Create(
282                client.interface(), enc_meta, true /* createEncoder */, source);
283
284    sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
285    writer->addSource(encoder);
286    int64_t start = systemTime();
287    CHECK_EQ(OK, writer->start());
288    while (!writer->reachedEOS()) {
289    }
290    err = writer->stop();
291    int64_t end = systemTime();
292
293    fprintf(stderr, "$\n");
294    client.disconnect();
295
296    if (err != OK && err != ERROR_END_OF_STREAM) {
297        fprintf(stderr, "record failed: %d\n", err);
298        return 1;
299    }
300    fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000);
301    fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start));
302    return 0;
303}
304