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