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
main(int argc,char * argv[])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