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 <inttypes.h> 20 #include <binder/ProcessState.h> 21 #include <media/stagefright/foundation/ADebug.h> 22 #include <media/stagefright/AudioPlayer.h> 23 #include <media/stagefright/MediaBufferGroup.h> 24 #include <media/stagefright/MediaDefs.h> 25 #include <media/stagefright/MetaData.h> 26 #include <media/stagefright/MPEG4Writer.h> 27 #include <media/stagefright/OMXClient.h> 28 #include <media/stagefright/OMXCodec.h> 29 #include <media/MediaPlayerInterface.h> 30 31 using namespace android; 32 33 // Print usage showing how to use this utility to record videos 34 static void usage(const char *me) { 35 fprintf(stderr, "usage: %s\n", me); 36 fprintf(stderr, " -h(elp)\n"); 37 fprintf(stderr, " -b bit rate in bits per second (default: 300000)\n"); 38 fprintf(stderr, " -c YUV420 color format: [0] semi planar or [1] planar or other omx YUV420 color format (default: 1)\n"); 39 fprintf(stderr, " -f frame rate in frames per second (default: 30)\n"); 40 fprintf(stderr, " -i I frame interval in seconds (default: 1)\n"); 41 fprintf(stderr, " -n number of frames to be recorded (default: 300)\n"); 42 fprintf(stderr, " -w width in pixels (default: 176)\n"); 43 fprintf(stderr, " -t height in pixels (default: 144)\n"); 44 fprintf(stderr, " -l encoder level. see omx il header (default: encoder specific)\n"); 45 fprintf(stderr, " -p encoder profile. see omx il header (default: encoder specific)\n"); 46 fprintf(stderr, " -v video codec: [0] AVC [1] M4V [2] H263 (default: 0)\n"); 47 fprintf(stderr, " -s(oftware) prefer software codec\n"); 48 fprintf(stderr, " -o filename: output file (default: /sdcard/output.mp4)\n"); 49 exit(1); 50 } 51 52 class DummySource : public MediaSource { 53 54 public: 55 DummySource(int width, int height, int nFrames, int fps, int colorFormat) 56 : mWidth(width), 57 mHeight(height), 58 mMaxNumFrames(nFrames), 59 mFrameRate(fps), 60 mColorFormat(colorFormat), 61 mSize((width * height * 3) / 2) { 62 63 mGroup.add_buffer(new MediaBuffer(mSize)); 64 } 65 66 virtual sp<MetaData> getFormat() { 67 sp<MetaData> meta = new MetaData; 68 meta->setInt32(kKeyWidth, mWidth); 69 meta->setInt32(kKeyHeight, mHeight); 70 meta->setInt32(kKeyColorFormat, mColorFormat); 71 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); 72 73 return meta; 74 } 75 76 virtual status_t start(MetaData *params __unused) { 77 mNumFramesOutput = 0; 78 return OK; 79 } 80 81 virtual status_t stop() { 82 return OK; 83 } 84 85 virtual status_t read( 86 MediaBuffer **buffer, const MediaSource::ReadOptions *options __unused) { 87 88 if (mNumFramesOutput % 10 == 0) { 89 fprintf(stderr, "."); 90 } 91 if (mNumFramesOutput == mMaxNumFrames) { 92 return ERROR_END_OF_STREAM; 93 } 94 95 status_t err = mGroup.acquire_buffer(buffer); 96 if (err != OK) { 97 return err; 98 } 99 100 // We don't care about the contents. we just test video encoder 101 // Also, by skipping the content generation, we can return from 102 // read() much faster. 103 #if 0 104 // iterate through solid planes of color. 105 static unsigned char x = 0x60; 106 memset((*buffer)->data(), x, mSize); 107 x = x >= 0xa0 ? 0x60 : x + 1; 108 #endif 109 (*buffer)->set_range(0, mSize); 110 (*buffer)->meta_data()->clear(); 111 (*buffer)->meta_data()->setInt64( 112 kKeyTime, (mNumFramesOutput * 1000000) / mFrameRate); 113 ++mNumFramesOutput; 114 115 return OK; 116 } 117 118 protected: 119 virtual ~DummySource() {} 120 121 private: 122 MediaBufferGroup mGroup; 123 int mWidth, mHeight; 124 int mMaxNumFrames; 125 int mFrameRate; 126 int mColorFormat; 127 size_t mSize; 128 int64_t mNumFramesOutput;; 129 130 DummySource(const DummySource &); 131 DummySource &operator=(const DummySource &); 132 }; 133 134 enum { 135 kYUV420SP = 0, 136 kYUV420P = 1, 137 }; 138 139 // returns -1 if mapping of the given color is unsuccessful 140 // returns an omx color enum value otherwise 141 static int translateColorToOmxEnumValue(int color) { 142 switch (color) { 143 case kYUV420SP: 144 return OMX_COLOR_FormatYUV420SemiPlanar; 145 case kYUV420P: 146 return OMX_COLOR_FormatYUV420Planar; 147 default: 148 fprintf(stderr, "Custom OMX color format: %d\n", color); 149 if (color == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar || 150 color == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) { 151 return color; 152 } 153 } 154 return -1; 155 } 156 157 int main(int argc, char **argv) { 158 159 // Default values for the program if not overwritten 160 int frameRateFps = 30; 161 int width = 176; 162 int height = 144; 163 int bitRateBps = 300000; 164 int iFramesIntervalSeconds = 1; 165 int colorFormat = OMX_COLOR_FormatYUV420Planar; 166 int nFrames = 300; 167 int level = -1; // Encoder specific default 168 int profile = -1; // Encoder specific default 169 int codec = 0; 170 const char *fileName = "/sdcard/output.mp4"; 171 bool preferSoftwareCodec = false; 172 173 android::ProcessState::self()->startThreadPool(); 174 int res; 175 while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:o:hs")) >= 0) { 176 switch (res) { 177 case 'b': 178 { 179 bitRateBps = atoi(optarg); 180 break; 181 } 182 183 case 'c': 184 { 185 colorFormat = translateColorToOmxEnumValue(atoi(optarg)); 186 if (colorFormat == -1) { 187 usage(argv[0]); 188 } 189 break; 190 } 191 192 case 'f': 193 { 194 frameRateFps = atoi(optarg); 195 break; 196 } 197 198 case 'i': 199 { 200 iFramesIntervalSeconds = atoi(optarg); 201 break; 202 } 203 204 case 'n': 205 { 206 nFrames = atoi(optarg); 207 break; 208 } 209 210 case 'w': 211 { 212 width = atoi(optarg); 213 break; 214 } 215 216 case 't': 217 { 218 height = atoi(optarg); 219 break; 220 } 221 222 case 'l': 223 { 224 level = atoi(optarg); 225 break; 226 } 227 228 case 'p': 229 { 230 profile = atoi(optarg); 231 break; 232 } 233 234 case 'v': 235 { 236 codec = atoi(optarg); 237 if (codec < 0 || codec > 2) { 238 usage(argv[0]); 239 } 240 break; 241 } 242 243 case 'o': 244 { 245 fileName = optarg; 246 break; 247 } 248 249 case 's': 250 { 251 preferSoftwareCodec = true; 252 break; 253 } 254 255 case 'h': 256 default: 257 { 258 usage(argv[0]); 259 break; 260 } 261 } 262 } 263 264 OMXClient client; 265 CHECK_EQ(client.connect(), (status_t)OK); 266 267 status_t err = OK; 268 sp<MediaSource> source = 269 new DummySource(width, height, nFrames, frameRateFps, colorFormat); 270 271 sp<MetaData> enc_meta = new MetaData; 272 switch (codec) { 273 case 1: 274 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); 275 break; 276 case 2: 277 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); 278 break; 279 default: 280 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 281 break; 282 } 283 enc_meta->setInt32(kKeyWidth, width); 284 enc_meta->setInt32(kKeyHeight, height); 285 enc_meta->setInt32(kKeyFrameRate, frameRateFps); 286 enc_meta->setInt32(kKeyBitRate, bitRateBps); 287 enc_meta->setInt32(kKeyStride, width); 288 enc_meta->setInt32(kKeySliceHeight, height); 289 enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds); 290 enc_meta->setInt32(kKeyColorFormat, colorFormat); 291 if (level != -1) { 292 enc_meta->setInt32(kKeyVideoLevel, level); 293 } 294 if (profile != -1) { 295 enc_meta->setInt32(kKeyVideoProfile, profile); 296 } 297 298 sp<MediaSource> encoder = 299 OMXCodec::Create( 300 client.interface(), enc_meta, true /* createEncoder */, source, 301 0, preferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0); 302 303 sp<MPEG4Writer> writer = new MPEG4Writer(fileName); 304 writer->addSource(encoder); 305 int64_t start = systemTime(); 306 CHECK_EQ((status_t)OK, writer->start()); 307 while (!writer->reachedEOS()) { 308 usleep(100000); 309 } 310 err = writer->stop(); 311 int64_t end = systemTime(); 312 313 fprintf(stderr, "$\n"); 314 client.disconnect(); 315 316 if (err != OK && err != ERROR_END_OF_STREAM) { 317 fprintf(stderr, "record failed: %d\n", err); 318 return 1; 319 } 320 fprintf(stderr, "encoding %d frames in %" PRId64 " us\n", nFrames, (end-start)/1000); 321 fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start)); 322 return 0; 323 } 324