• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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