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