Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  * * Redistributions in binary form must reproduce the above copyright
     11  * notice, this list of conditions and the following disclaimer in
     12  * the documentation and/or other materials provided with the
     13  * distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <stdio.h>
     30 #include <stdint.h>
     31 #include <assert.h>
     32 #include <stdlib.h>
     33 
     34 #include "mp4enc_api.h"
     35 
     36 // Constants.
     37 enum {
     38     kMaxWidth         = 720,
     39     kMaxHeight        = 480,
     40     kMaxFrameRate     = 30,
     41     kMaxBitrate       = 2048, // in kbps.
     42     kOutputBufferSize = 250 * 1024,
     43     kIDRFrameRefreshIntervalInSec = 1, // in seconds.
     44 };
     45 
     46 int main(int argc, char *argv[]) {
     47 
     48     if (argc < 8) {
     49         fprintf(stderr, "Usage %s <input yuv> <output file> <mode> <width> "
     50                         "<height> <frame rate> <bitrate in kbps>\n", argv[0]);
     51         fprintf(stderr, "mode : h263 or mpeg4\n");
     52         fprintf(stderr, "Max width %d\n", kMaxWidth);
     53         fprintf(stderr, "Max height %d\n", kMaxHeight);
     54         fprintf(stderr, "Max framerate %d\n", kMaxFrameRate);
     55         fprintf(stderr, "Max bitrate %d kbps\n", kMaxBitrate);
     56         return EXIT_FAILURE;
     57     }
     58 
     59     // Read mode.
     60     bool isH263mode;
     61     if (strcmp(argv[3], "mpeg4") == 0) {
     62         isH263mode = false;
     63     } else if (strcmp(argv[3], "h263") == 0) {
     64         isH263mode = true;
     65     } else {
     66         fprintf(stderr, "Unsupported mode %s\n", argv[3]);
     67         return EXIT_FAILURE;
     68     }
     69 
     70     // Read height and width.
     71     int32_t width;
     72     int32_t height;
     73     width = atoi(argv[4]);
     74     height = atoi(argv[5]);
     75     if (width > kMaxWidth || height > kMaxHeight || width <= 0 || height <= 0) {
     76         fprintf(stderr, "Unsupported dimensions %dx%d\n", width, height);
     77         return EXIT_FAILURE;
     78     }
     79 
     80     if (width % 16 != 0 || height % 16 != 0) {
     81         fprintf(stderr, "Video frame size %dx%d must be a multiple of 16\n",
     82             width, height);
     83         return EXIT_FAILURE;
     84     }
     85 
     86     // Read frame rate.
     87     int32_t frameRate;
     88     frameRate = atoi(argv[6]);
     89     if (frameRate > kMaxFrameRate || frameRate <= 0) {
     90         fprintf(stderr, "Unsupported frame rate %d\n", frameRate);
     91         return EXIT_FAILURE;
     92     }
     93 
     94     // Read bitrate.
     95     int32_t bitrate;
     96     bitrate = atoi(argv[7]);
     97     if (bitrate > kMaxBitrate || bitrate <= 0) {
     98         fprintf(stderr, "Unsupported bitrate %d\n", bitrate);
     99         return EXIT_FAILURE;
    100     }
    101 
    102     // Allocate input buffer.
    103     uint8_t *inputBuf = (uint8_t *)malloc((width * height * 3) / 2);
    104     assert(inputBuf != NULL);
    105 
    106     // Allocate output buffer.
    107     uint8_t *outputBuf = (uint8_t *)malloc(kOutputBufferSize);
    108     assert(outputBuf != NULL);
    109 
    110     // Open the input file.
    111     FILE *fpInput = fopen(argv[1], "rb");
    112     if (fpInput == NULL) {
    113         fprintf(stderr, "Could not open %s\n", argv[1]);
    114         free(inputBuf);
    115         free(outputBuf);
    116         return EXIT_FAILURE;
    117     }
    118 
    119     // Open the output file.
    120     FILE *fpOutput = fopen(argv[2], "wb");
    121     if (fpOutput == NULL) {
    122         fprintf(stderr, "Could not open %s\n", argv[2]);
    123         free(inputBuf);
    124         free(outputBuf);
    125         fclose(fpInput);
    126         return EXIT_FAILURE;
    127     }
    128 
    129     // Initialize the encoder parameters.
    130     tagvideoEncOptions encParams;
    131     memset(&encParams, 0, sizeof(tagvideoEncOptions));
    132     if (!PVGetDefaultEncOption(&encParams, 0)) {
    133         fprintf(stderr, "Failed to get default encoding parameters\n");
    134         free(inputBuf);
    135         free(outputBuf);
    136         fclose(fpInput);
    137         fclose(fpOutput);
    138         return EXIT_FAILURE;
    139     }
    140 
    141     if (isH263mode == false) {
    142         encParams.encMode = COMBINE_MODE_WITH_ERR_RES;
    143     } else {
    144         encParams.encMode = H263_MODE;
    145     }
    146     encParams.encWidth[0] = width;
    147     encParams.encHeight[0] = height;
    148     encParams.encFrameRate[0] = frameRate;
    149     encParams.rcType = VBR_1;
    150     encParams.vbvDelay = 5.0f;
    151     encParams.profile_level = CORE_PROFILE_LEVEL2;
    152     encParams.packetSize = 32;
    153     encParams.rvlcEnable = PV_OFF;
    154     encParams.numLayers = 1;
    155     encParams.timeIncRes = 1000;
    156     encParams.tickPerSrc = encParams.timeIncRes / frameRate;
    157 
    158     encParams.bitRate[0] = bitrate * 1024;
    159     encParams.iQuant[0] = 15;
    160     encParams.pQuant[0] = 12;
    161     encParams.quantType[0] = 0;
    162     encParams.noFrameSkipped = PV_OFF;
    163 
    164     int32_t  IDRFrameRefreshIntervalInSec = kIDRFrameRefreshIntervalInSec;
    165     if (IDRFrameRefreshIntervalInSec == 0) {
    166         encParams.intraPeriod = 1;  // All I frames.
    167     } else {
    168         encParams.intraPeriod = (IDRFrameRefreshIntervalInSec * frameRate);
    169     }
    170 
    171     encParams.numIntraMB = 0;
    172     encParams.sceneDetect = PV_ON;
    173     encParams.searchRange = 16;
    174     encParams.mv8x8Enable = PV_OFF;
    175     encParams.gobHeaderInterval = 0;
    176     encParams.useACPred = PV_ON;
    177     encParams.intraDCVlcTh = 0;
    178 
    179     // Initialize the handle.
    180     tagvideoEncControls handle;
    181     memset(&handle, 0, sizeof(tagvideoEncControls));
    182 
    183     // Initialize the encoder.
    184     if (!PVInitVideoEncoder(&handle, &encParams)) {
    185         fprintf(stderr, "Failed to initialize the encoder\n");
    186         fclose(fpInput);
    187         fclose(fpOutput);
    188         free(inputBuf);
    189         free(outputBuf);
    190         return EXIT_FAILURE;
    191     }
    192 
    193     // Generate the header.
    194     int32_t headerLength = kOutputBufferSize;
    195     if (!PVGetVolHeader(&handle, outputBuf, &headerLength, 0)) {
    196         fprintf(stderr, "Failed to get VOL header\n");
    197         fclose(fpInput);
    198         fclose(fpOutput);
    199         free(inputBuf);
    200         free(outputBuf);
    201         return EXIT_FAILURE;
    202     }
    203     fwrite(outputBuf, 1, headerLength, fpOutput);
    204 
    205     // Core loop.
    206     int32_t retVal = EXIT_SUCCESS;
    207     int32_t frameSize = (width * height * 3) / 2;
    208     int32_t numFramesEncoded = 0;
    209 
    210     while (1) {
    211         // Read the input frame.
    212         int32_t bytesRead;
    213         bytesRead = fread(inputBuf, 1, frameSize, fpInput);
    214         if (bytesRead != frameSize) {
    215             break; // End of file.
    216         }
    217 
    218         // Encode the input frame.
    219         VideoEncFrameIO vin, vout;
    220         memset(&vin, 0, sizeof(vin));
    221         memset(&vout, 0, sizeof(vout));
    222         vin.height = height; // height is multiple of 16.
    223         vin.pitch = width; // width is multiple of 16.
    224         vin.timestamp = (numFramesEncoded * 1000) / frameRate;  // in ms.
    225         vin.yChan = inputBuf;
    226         vin.uChan = vin.yChan + vin.height * vin.pitch;
    227         vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2);
    228 
    229         uint32_t modTimeMs = 0;
    230         int32_t nLayer = 0;
    231         MP4HintTrack hintTrack;
    232         int32_t dataLength = kOutputBufferSize;
    233         if (!PVEncodeVideoFrame(&handle, &vin, &vout,
    234                 &modTimeMs, outputBuf, &dataLength, &nLayer) ||
    235             !PVGetHintTrack(&handle, &hintTrack)) {
    236             fprintf(stderr, "Failed to encode frame or get hink track at "
    237                     " frame %d\n", numFramesEncoded);
    238             retVal = EXIT_FAILURE;
    239             break;
    240         }
    241         PVGetOverrunBuffer(&handle);
    242         numFramesEncoded++;
    243 
    244         // Write the output.
    245         fwrite(outputBuf, 1, dataLength, fpOutput);
    246     }
    247 
    248     // Close input and output file.
    249     fclose(fpInput);
    250     fclose(fpOutput);
    251 
    252     // Free allocated memory.
    253     free(inputBuf);
    254     free(outputBuf);
    255 
    256     // Close encoder instance.
    257     PVCleanUpVideoEncoder(&handle);
    258     return retVal;
    259 }
    260