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
24VideoEncoderMP4::VideoEncoderMP4()
25    :mProfileLevelIndication(3)
26    ,mFixedVOPTimeIncrement(0) {
27    mComParams.profile = (VAProfile)PROFILE_MPEG4SIMPLE;
28    mAutoReferenceSurfaceNum = 2;
29}
30
31Encode_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
61Encode_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
97Encode_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
120CLEAN_UP:
121
122    LOG_V("End\n");
123    return ret;
124}
125
126Encode_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
179Encode_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
224Encode_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
264Encode_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