1 /*
2 * Copyright (c) 2009-2011 Intel Corporation.  All rights reserved.
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 <string.h>
18 #include <stdlib.h>
19 
20 #include "VideoEncoderLog.h"
21 #include "VideoEncoderMP4.h"
22 #include <va/va_tpi.h>
23 
VideoEncoderMP4()24 VideoEncoderMP4::VideoEncoderMP4()
25     :mProfileLevelIndication(3)
26     ,mFixedVOPTimeIncrement(0) {
27     mComParams.profile = (VAProfile)PROFILE_MPEG4SIMPLE;
28     mAutoReferenceSurfaceNum = 2;
29 }
30 
getHeaderPos(uint8_t * inBuffer,uint32_t bufSize,uint32_t * headerSize)31 Encode_Status VideoEncoderMP4::getHeaderPos(
32         uint8_t *inBuffer, uint32_t bufSize, uint32_t *headerSize) {
33 
34     uint32_t bytesLeft = bufSize;
35 
36     *headerSize = 0;
37     CHECK_NULL_RETURN_IFFAIL(inBuffer);
38 
39     if (bufSize < 4) {
40         //bufSize shoule not < 4
41         LOG_E("Buffer size too small\n");
42         return ENCODE_FAIL;
43     }
44 
45     while (bytesLeft > 4  &&
46             (memcmp("\x00\x00\x01\xB6", &inBuffer[bufSize - bytesLeft], 4) &&
47              memcmp("\x00\x00\x01\xB3", &inBuffer[bufSize - bytesLeft], 4))) {
48         --bytesLeft;
49     }
50 
51     if (bytesLeft <= 4) {
52         LOG_E("NO header found\n");
53         *headerSize = 0; //
54     } else {
55         *headerSize = bufSize - bytesLeft;
56     }
57 
58     return ENCODE_SUCCESS;
59 }
60 
outputConfigData(VideoEncOutputBuffer * outBuffer)61 Encode_Status VideoEncoderMP4::outputConfigData(
62         VideoEncOutputBuffer *outBuffer) {
63 
64     Encode_Status ret = ENCODE_SUCCESS;
65     uint32_t headerSize = 0;
66 
67     ret = getHeaderPos((uint8_t *)mCurSegment->buf + mOffsetInSeg,
68             mCurSegment->size - mOffsetInSeg, &headerSize);
69     CHECK_ENCODE_STATUS_RETURN("getHeaderPos");
70     if (headerSize == 0) {
71         outBuffer->dataSize = 0;
72         mCurSegment = NULL;
73         return ENCODE_NO_REQUEST_DATA;
74     }
75 
76     if (headerSize <= outBuffer->bufferSize) {
77         memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg, headerSize);
78         mTotalSizeCopied += headerSize;
79         mOffsetInSeg += headerSize;
80         outBuffer->dataSize = headerSize;
81         outBuffer->remainingSize = 0;
82         outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
83         outBuffer->flag |= ENCODE_BUFFERFLAG_CODECCONFIG;
84         outBuffer->flag |= ENCODE_BUFFERFLAG_SYNCFRAME;
85     } else {
86         // we need a big enough buffer, otherwise we won't output anything
87         outBuffer->dataSize = 0;
88         outBuffer->remainingSize = headerSize;
89         outBuffer->flag |= ENCODE_BUFFERFLAG_DATAINVALID;
90         LOG_E("Buffer size too small\n");
91         return ENCODE_BUFFER_TOO_SMALL;
92     }
93 
94     return ret;
95 }
96 
getExtFormatOutput(VideoEncOutputBuffer * outBuffer)97 Encode_Status VideoEncoderMP4::getExtFormatOutput(VideoEncOutputBuffer *outBuffer) {
98 
99     Encode_Status ret = ENCODE_SUCCESS;
100 
101     LOG_V("Begin\n");
102     CHECK_NULL_RETURN_IFFAIL(outBuffer);
103 
104     switch (outBuffer->format) {
105         case OUTPUT_CODEC_DATA: {
106             // Output the codec config data
107             ret = outputConfigData(outBuffer);
108             CHECK_ENCODE_STATUS_CLEANUP("outputCodecData");
109             break;
110         }
111         default:
112             LOG_E("Invalid buffer mode for MPEG-4:2\n");
113             ret = ENCODE_FAIL;
114             break;
115     }
116 
117     LOG_I("out size is = %d\n", outBuffer->dataSize);
118 
119 
120 CLEAN_UP:
121 
122     LOG_V("End\n");
123     return ret;
124 }
125 
renderSequenceParams(EncodeTask *)126 Encode_Status VideoEncoderMP4::renderSequenceParams(EncodeTask *) {
127 
128     VAStatus vaStatus = VA_STATUS_SUCCESS;
129     VAEncSequenceParameterBufferMPEG4 mp4SequenceParams = VAEncSequenceParameterBufferMPEG4();
130 
131     uint32_t frameRateNum = mComParams.frameRate.frameRateNum;
132     uint32_t frameRateDenom = mComParams.frameRate.frameRateDenom;
133 
134     LOG_V( "Begin\n\n");
135     // set up the sequence params for HW
136     mp4SequenceParams.profile_and_level_indication = mProfileLevelIndication;
137     mp4SequenceParams.video_object_layer_width= mComParams.resolution.width;
138     mp4SequenceParams.video_object_layer_height= mComParams.resolution.height;
139     mp4SequenceParams.vop_time_increment_resolution =
140             (unsigned int) (frameRateNum + frameRateDenom /2) / frameRateDenom;
141     mp4SequenceParams.fixed_vop_time_increment= mFixedVOPTimeIncrement;
142     mp4SequenceParams.bits_per_second= mComParams.rcParams.bitRate;
143     mp4SequenceParams.frame_rate =
144             (unsigned int) (frameRateNum + frameRateDenom /2) / frameRateDenom;
145     mp4SequenceParams.initial_qp = mComParams.rcParams.initQP;
146     mp4SequenceParams.min_qp = mComParams.rcParams.minQP;
147     mp4SequenceParams.intra_period = mComParams.intraPeriod;
148     //mpeg4_seq_param.fixed_vop_rate = 30;
149 
150     LOG_V("===mpeg4 sequence params===\n");
151     LOG_I("profile_and_level_indication = %d\n", (uint32_t)mp4SequenceParams.profile_and_level_indication);
152     LOG_I("intra_period = %d\n", mp4SequenceParams.intra_period);
153     LOG_I("video_object_layer_width = %d\n", mp4SequenceParams.video_object_layer_width);
154     LOG_I("video_object_layer_height = %d\n", mp4SequenceParams.video_object_layer_height);
155     LOG_I("vop_time_increment_resolution = %d\n", mp4SequenceParams.vop_time_increment_resolution);
156     LOG_I("fixed_vop_rate = %d\n", mp4SequenceParams.fixed_vop_rate);
157     LOG_I("fixed_vop_time_increment = %d\n", mp4SequenceParams.fixed_vop_time_increment);
158     LOG_I("bitrate = %d\n", mp4SequenceParams.bits_per_second);
159     LOG_I("frame_rate = %d\n", mp4SequenceParams.frame_rate);
160     LOG_I("initial_qp = %d\n", mp4SequenceParams.initial_qp);
161     LOG_I("min_qp = %d\n", mp4SequenceParams.min_qp);
162     LOG_I("intra_period = %d\n\n", mp4SequenceParams.intra_period);
163 
164     vaStatus = vaCreateBuffer(
165             mVADisplay, mVAContext,
166             VAEncSequenceParameterBufferType,
167             sizeof(mp4SequenceParams),
168             1, &mp4SequenceParams,
169             &mSeqParamBuf);
170     CHECK_VA_STATUS_RETURN("vaCreateBuffer");
171 
172     vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSeqParamBuf, 1);
173     CHECK_VA_STATUS_RETURN("vaRenderPicture");
174 
175     LOG_V( "end\n");
176     return ENCODE_SUCCESS;
177 }
178 
renderPictureParams(EncodeTask * task)179 Encode_Status VideoEncoderMP4::renderPictureParams(EncodeTask *task) {
180 
181     VAStatus vaStatus = VA_STATUS_SUCCESS;
182     VAEncPictureParameterBufferMPEG4 mpeg4_pic_param = VAEncPictureParameterBufferMPEG4();
183     LOG_V( "Begin\n\n");
184     // set picture params for HW
185     if(mAutoReference == false){
186         mpeg4_pic_param.reference_picture = task->ref_surface;
187         mpeg4_pic_param.reconstructed_picture = task->rec_surface;
188     }else {
189         mpeg4_pic_param.reference_picture = mAutoRefSurfaces[0];
190         mpeg4_pic_param.reconstructed_picture = mAutoRefSurfaces[1];
191     }
192 
193     mpeg4_pic_param.coded_buf = task->coded_buffer;
194     mpeg4_pic_param.picture_width = mComParams.resolution.width;
195     mpeg4_pic_param.picture_height = mComParams.resolution.height;
196     mpeg4_pic_param.vop_time_increment= mFrameNum;
197     mpeg4_pic_param.picture_type = (task->type == FTYPE_I) ? VAEncPictureTypeIntra : VAEncPictureTypePredictive;
198 
199     LOG_V("======mpeg4 picture params======\n");
200     LOG_V("reference_picture = 0x%08x\n", mpeg4_pic_param.reference_picture);
201     LOG_V("reconstructed_picture = 0x%08x\n", mpeg4_pic_param.reconstructed_picture);
202     LOG_V("coded_buf = 0x%08x\n", mpeg4_pic_param.coded_buf);
203 //    LOG_I("coded_buf_index = %d\n", mCodedBufIndex);
204     LOG_V("picture_width = %d\n", mpeg4_pic_param.picture_width);
205     LOG_V("picture_height = %d\n", mpeg4_pic_param.picture_height);
206     LOG_V("vop_time_increment = %d\n", mpeg4_pic_param.vop_time_increment);
207     LOG_V("picture_type = %d\n\n", mpeg4_pic_param.picture_type);
208 
209     vaStatus = vaCreateBuffer(
210             mVADisplay, mVAContext,
211             VAEncPictureParameterBufferType,
212             sizeof(mpeg4_pic_param),
213             1,&mpeg4_pic_param,
214             &mPicParamBuf);
215     CHECK_VA_STATUS_RETURN("vaCreateBuffer");
216 
217     vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mPicParamBuf, 1);
218     CHECK_VA_STATUS_RETURN("vaRenderPicture");
219 
220     return ENCODE_SUCCESS;
221 }
222 
223 
renderSliceParams(EncodeTask * task)224 Encode_Status VideoEncoderMP4::renderSliceParams(EncodeTask *task) {
225 
226     VAStatus vaStatus = VA_STATUS_SUCCESS;
227     uint32_t sliceHeight;
228     uint32_t sliceHeightInMB;
229 
230     VAEncSliceParameterBuffer sliceParams;
231 
232     LOG_V( "Begin\n\n");
233 
234     sliceHeight = mComParams.resolution.height;
235     sliceHeight += 15;
236     sliceHeight &= (~15);
237     sliceHeightInMB = sliceHeight / 16;
238 
239     sliceParams.start_row_number = 0;
240     sliceParams.slice_height = sliceHeightInMB;
241     sliceParams.slice_flags.bits.is_intra = (task->type == FTYPE_I)?1:0;
242     sliceParams.slice_flags.bits.disable_deblocking_filter_idc = 0;
243 
244     LOG_V("======mpeg4 slice params======\n");
245     LOG_I( "start_row_number = %d\n", (int) sliceParams.start_row_number);
246     LOG_I( "sliceHeightInMB = %d\n", (int) sliceParams.slice_height);
247     LOG_I( "is_intra = %d\n", (int) sliceParams.slice_flags.bits.is_intra);
248 
249     vaStatus = vaCreateBuffer(
250             mVADisplay, mVAContext,
251             VAEncSliceParameterBufferType,
252             sizeof(VAEncSliceParameterBuffer),
253             1, &sliceParams,
254             &mSliceParamBuf);
255     CHECK_VA_STATUS_RETURN("vaCreateBuffer");
256 
257     vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSliceParamBuf, 1);
258     CHECK_VA_STATUS_RETURN("vaRenderPicture");
259 
260     LOG_V( "end\n");
261     return ENCODE_SUCCESS;
262 }
263 
sendEncodeCommand(EncodeTask * task)264 Encode_Status VideoEncoderMP4::sendEncodeCommand(EncodeTask *task) {
265     Encode_Status ret = ENCODE_SUCCESS;
266     LOG_V( "Begin\n");
267 
268     if (mFrameNum == 0) {
269         ret = renderSequenceParams(task);
270         CHECK_ENCODE_STATUS_RETURN("renderSequenceParams");
271     }
272 
273     ret = renderPictureParams(task);
274     CHECK_ENCODE_STATUS_RETURN("renderPictureParams");
275 
276     ret = renderSliceParams(task);
277     CHECK_ENCODE_STATUS_RETURN("renderPictureParams");
278 
279     LOG_V( "End\n");
280     return ENCODE_SUCCESS;
281 }
282