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 <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