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