Home | History | Annotate | Download | only in stagefright
      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, "The output file is /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     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         usleep(100000);
    298     }
    299     err = writer->stop();
    300     int64_t end = systemTime();
    301 
    302     fprintf(stderr, "$\n");
    303     client.disconnect();
    304 
    305     if (err != OK && err != ERROR_END_OF_STREAM) {
    306         fprintf(stderr, "record failed: %d\n", err);
    307         return 1;
    308     }
    309     fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000);
    310     fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start));
    311     return 0;
    312 }
    313