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