| Guilhem IMBERTON | 82b428e | 2014-08-06 20:47:04 +0200 | [diff] [blame^] | 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 | |
| 24 | VideoEncoderMP4::VideoEncoderMP4() |
| 25 | :mProfileLevelIndication(3) |
| 26 | ,mFixedVOPTimeIncrement(0) { |
| 27 | mComParams.profile = (VAProfile)PROFILE_MPEG4SIMPLE; |
| 28 | mAutoReferenceSurfaceNum = 2; |
| 29 | } |
| 30 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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_I("reference_picture = 0x%08x\n", mpeg4_pic_param.reference_picture); |
| 201 | LOG_I("reconstructed_picture = 0x%08x\n", mpeg4_pic_param.reconstructed_picture); |
| 202 | LOG_I("coded_buf = 0x%08x\n", mpeg4_pic_param.coded_buf); |
| 203 | // LOG_I("coded_buf_index = %d\n", mCodedBufIndex); |
| 204 | LOG_I("picture_width = %d\n", mpeg4_pic_param.picture_width); |
| 205 | LOG_I("picture_height = %d\n", mpeg4_pic_param.picture_height); |
| 206 | LOG_I("vop_time_increment = %d\n", mpeg4_pic_param.vop_time_increment); |
| 207 | LOG_I("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 | |
| 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 | |
| 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 | } |