recordvideo.cpp revision d4483f3fd0e024d833082fce3ddbc3a2f3d89b24
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/foundation/ADebug.h>
21#include <media/stagefright/AudioPlayer.h>
22#include <media/stagefright/MediaBufferGroup.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 or other omx YUV420 color format (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, "       -s(oftware) prefer software codec\n");
47    fprintf(stderr, "The output file is /sdcard/output.mp4\n");
48    exit(1);
49}
50
51class DummySource : public MediaSource {
52
53public:
54    DummySource(int width, int height, int nFrames, int fps, int colorFormat)
55        : mWidth(width),
56          mHeight(height),
57          mMaxNumFrames(nFrames),
58          mFrameRate(fps),
59          mColorFormat(colorFormat),
60          mSize((width * height * 3) / 2) {
61
62        mGroup.add_buffer(new MediaBuffer(mSize));
63    }
64
65    virtual sp<MetaData> getFormat() {
66        sp<MetaData> meta = new MetaData;
67        meta->setInt32(kKeyWidth, mWidth);
68        meta->setInt32(kKeyHeight, mHeight);
69        meta->setInt32(kKeyColorFormat, mColorFormat);
70        meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
71
72        return meta;
73    }
74
75    virtual status_t start(MetaData *params) {
76        mNumFramesOutput = 0;
77        return OK;
78    }
79
80    virtual status_t stop() {
81        return OK;
82    }
83
84    virtual status_t read(
85            MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
86
87        if (mNumFramesOutput % 10 == 0) {
88            fprintf(stderr, ".");
89        }
90        if (mNumFramesOutput == mMaxNumFrames) {
91            return ERROR_END_OF_STREAM;
92        }
93
94        status_t err = mGroup.acquire_buffer(buffer);
95        if (err != OK) {
96            return err;
97        }
98
99        // We don't care about the contents. we just test video encoder
100        // Also, by skipping the content generation, we can return from
101        // read() much faster.
102        //char x = (char)((double)rand() / RAND_MAX * 255);
103        //memset((*buffer)->data(), x, mSize);
104        (*buffer)->set_range(0, mSize);
105        (*buffer)->meta_data()->clear();
106        (*buffer)->meta_data()->setInt64(
107                kKeyTime, (mNumFramesOutput * 1000000) / mFrameRate);
108        ++mNumFramesOutput;
109
110        return OK;
111    }
112
113protected:
114    virtual ~DummySource() {}
115
116private:
117    MediaBufferGroup mGroup;
118    int mWidth, mHeight;
119    int mMaxNumFrames;
120    int mFrameRate;
121    int mColorFormat;
122    size_t mSize;
123    int64_t mNumFramesOutput;;
124
125    DummySource(const DummySource &);
126    DummySource &operator=(const DummySource &);
127};
128
129enum {
130    kYUV420SP = 0,
131    kYUV420P  = 1,
132};
133
134// returns -1 if mapping of the given color is unsuccessful
135// returns an omx color enum value otherwise
136static int translateColorToOmxEnumValue(int color) {
137    switch (color) {
138        case kYUV420SP:
139            return OMX_COLOR_FormatYUV420SemiPlanar;
140        case kYUV420P:
141            return OMX_COLOR_FormatYUV420Planar;
142        default:
143            fprintf(stderr, "Custom OMX color format: %d\n", color);
144            if (color == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar ||
145                color == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
146                return color;
147            }
148    }
149    return -1;
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    bool preferSoftwareCodec = false;
167
168    android::ProcessState::self()->startThreadPool();
169    int res;
170    while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:hs")) >= 0) {
171        switch (res) {
172            case 'b':
173            {
174                bitRateBps = atoi(optarg);
175                break;
176            }
177
178            case 'c':
179            {
180                colorFormat = translateColorToOmxEnumValue(atoi(optarg));
181                if (colorFormat == -1) {
182                    usage(argv[0]);
183                }
184                break;
185            }
186
187            case 'f':
188            {
189                frameRateFps = atoi(optarg);
190                break;
191            }
192
193            case 'i':
194            {
195                iFramesIntervalSeconds = atoi(optarg);
196                break;
197            }
198
199            case 'n':
200            {
201                nFrames = atoi(optarg);
202                break;
203            }
204
205            case 'w':
206            {
207                width = atoi(optarg);
208                break;
209            }
210
211            case 't':
212            {
213                height = atoi(optarg);
214                break;
215            }
216
217            case 'l':
218            {
219                level = atoi(optarg);
220                break;
221            }
222
223            case 'p':
224            {
225                profile = atoi(optarg);
226                break;
227            }
228
229            case 'v':
230            {
231                codec = atoi(optarg);
232                if (codec < 0 || codec > 2) {
233                    usage(argv[0]);
234                }
235                break;
236            }
237
238            case 's':
239            {
240                preferSoftwareCodec = true;
241                break;
242            }
243
244            case 'h':
245            default:
246            {
247                usage(argv[0]);
248                break;
249            }
250        }
251    }
252
253    OMXClient client;
254    CHECK_EQ(client.connect(), (status_t)OK);
255
256    status_t err = OK;
257    sp<MediaSource> source =
258        new DummySource(width, height, nFrames, frameRateFps, colorFormat);
259
260    sp<MetaData> enc_meta = new MetaData;
261    switch (codec) {
262        case 1:
263            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
264            break;
265        case 2:
266            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
267            break;
268        default:
269            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
270            break;
271    }
272    enc_meta->setInt32(kKeyWidth, width);
273    enc_meta->setInt32(kKeyHeight, height);
274    enc_meta->setInt32(kKeyFrameRate, frameRateFps);
275    enc_meta->setInt32(kKeyBitRate, bitRateBps);
276    enc_meta->setInt32(kKeyStride, width);
277    enc_meta->setInt32(kKeySliceHeight, height);
278    enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds);
279    enc_meta->setInt32(kKeyColorFormat, colorFormat);
280    if (level != -1) {
281        enc_meta->setInt32(kKeyVideoLevel, level);
282    }
283    if (profile != -1) {
284        enc_meta->setInt32(kKeyVideoProfile, profile);
285    }
286
287    sp<MediaSource> encoder =
288        OMXCodec::Create(
289                client.interface(), enc_meta, true /* createEncoder */, source,
290                0, preferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
291
292    sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
293    writer->addSource(encoder);
294    int64_t start = systemTime();
295    CHECK_EQ((status_t)OK, writer->start());
296    while (!writer->reachedEOS()) {
297    }
298    err = writer->stop();
299    int64_t end = systemTime();
300
301    fprintf(stderr, "$\n");
302    client.disconnect();
303
304    if (err != OK && err != ERROR_END_OF_STREAM) {
305        fprintf(stderr, "record failed: %d\n", err);
306        return 1;
307    }
308    fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000);
309    fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start));
310    return 0;
311}
312