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 30 using namespace android; 31 32 // Print usage showing how to use this utility to record videos 33 static 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, " -o filename: output file (default: /sdcard/output.mp4)\n"); 48 exit(1); 49 } 50 51 class DummySource : public MediaSource { 52 53 public: 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 113 protected: 114 virtual ~DummySource() {} 115 116 private: 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 129 enum { 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 136 static 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 152 int 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 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:o: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 'o': 239 { 240 fileName = optarg; 241 break; 242 } 243 244 case 's': 245 { 246 preferSoftwareCodec = true; 247 break; 248 } 249 250 case 'h': 251 default: 252 { 253 usage(argv[0]); 254 break; 255 } 256 } 257 } 258 259 OMXClient client; 260 CHECK_EQ(client.connect(), (status_t)OK); 261 262 status_t err = OK; 263 sp<MediaSource> source = 264 new DummySource(width, height, nFrames, frameRateFps, colorFormat); 265 266 sp<MetaData> enc_meta = new MetaData; 267 switch (codec) { 268 case 1: 269 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); 270 break; 271 case 2: 272 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); 273 break; 274 default: 275 enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 276 break; 277 } 278 enc_meta->setInt32(kKeyWidth, width); 279 enc_meta->setInt32(kKeyHeight, height); 280 enc_meta->setInt32(kKeyFrameRate, frameRateFps); 281 enc_meta->setInt32(kKeyBitRate, bitRateBps); 282 enc_meta->setInt32(kKeyStride, width); 283 enc_meta->setInt32(kKeySliceHeight, height); 284 enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds); 285 enc_meta->setInt32(kKeyColorFormat, colorFormat); 286 if (level != -1) { 287 enc_meta->setInt32(kKeyVideoLevel, level); 288 } 289 if (profile != -1) { 290 enc_meta->setInt32(kKeyVideoProfile, profile); 291 } 292 293 sp<MediaSource> encoder = 294 OMXCodec::Create( 295 client.interface(), enc_meta, true /* createEncoder */, source, 296 0, preferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0); 297 298 sp<MPEG4Writer> writer = new MPEG4Writer(fileName); 299 writer->addSource(encoder); 300 int64_t start = systemTime(); 301 CHECK_EQ((status_t)OK, writer->start()); 302 while (!writer->reachedEOS()) { 303 usleep(100000); 304 } 305 err = writer->stop(); 306 int64_t end = systemTime(); 307 308 fprintf(stderr, "$\n"); 309 client.disconnect(); 310 311 if (err != OK && err != ERROR_END_OF_STREAM) { 312 fprintf(stderr, "record failed: %d\n", err); 313 return 1; 314 } 315 fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000); 316 fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start)); 317 return 0; 318 } 319