| /* |
| * Copyright (c) 2009-2011 Intel Corporation. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #include "VideoEncoderLog.h" |
| #include "VideoEncoderMP4.h" |
| #include <va/va_tpi.h> |
| |
| VideoEncoderMP4::VideoEncoderMP4() |
| :mProfileLevelIndication(3) |
| ,mFixedVOPTimeIncrement(0) { |
| mComParams.profile = (VAProfile)PROFILE_MPEG4SIMPLE; |
| mAutoReferenceSurfaceNum = 2; |
| } |
| |
| Encode_Status VideoEncoderMP4::getHeaderPos( |
| uint8_t *inBuffer, uint32_t bufSize, uint32_t *headerSize) { |
| |
| uint32_t bytesLeft = bufSize; |
| |
| *headerSize = 0; |
| CHECK_NULL_RETURN_IFFAIL(inBuffer); |
| |
| if (bufSize < 4) { |
| //bufSize shoule not < 4 |
| LOG_E("Buffer size too small\n"); |
| return ENCODE_FAIL; |
| } |
| |
| while (bytesLeft > 4 && |
| (memcmp("\x00\x00\x01\xB6", &inBuffer[bufSize - bytesLeft], 4) && |
| memcmp("\x00\x00\x01\xB3", &inBuffer[bufSize - bytesLeft], 4))) { |
| --bytesLeft; |
| } |
| |
| if (bytesLeft <= 4) { |
| LOG_E("NO header found\n"); |
| *headerSize = 0; // |
| } else { |
| *headerSize = bufSize - bytesLeft; |
| } |
| |
| return ENCODE_SUCCESS; |
| } |
| |
| Encode_Status VideoEncoderMP4::outputConfigData( |
| VideoEncOutputBuffer *outBuffer) { |
| |
| Encode_Status ret = ENCODE_SUCCESS; |
| uint32_t headerSize = 0; |
| |
| ret = getHeaderPos((uint8_t *)mCurSegment->buf + mOffsetInSeg, |
| mCurSegment->size - mOffsetInSeg, &headerSize); |
| CHECK_ENCODE_STATUS_RETURN("getHeaderPos"); |
| if (headerSize == 0) { |
| outBuffer->dataSize = 0; |
| mCurSegment = NULL; |
| return ENCODE_NO_REQUEST_DATA; |
| } |
| |
| if (headerSize <= outBuffer->bufferSize) { |
| memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg, headerSize); |
| mTotalSizeCopied += headerSize; |
| mOffsetInSeg += headerSize; |
| outBuffer->dataSize = headerSize; |
| outBuffer->remainingSize = 0; |
| outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME; |
| outBuffer->flag |= ENCODE_BUFFERFLAG_CODECCONFIG; |
| outBuffer->flag |= ENCODE_BUFFERFLAG_SYNCFRAME; |
| } else { |
| // we need a big enough buffer, otherwise we won't output anything |
| outBuffer->dataSize = 0; |
| outBuffer->remainingSize = headerSize; |
| outBuffer->flag |= ENCODE_BUFFERFLAG_DATAINVALID; |
| LOG_E("Buffer size too small\n"); |
| return ENCODE_BUFFER_TOO_SMALL; |
| } |
| |
| return ret; |
| } |
| |
| Encode_Status VideoEncoderMP4::getExtFormatOutput(VideoEncOutputBuffer *outBuffer) { |
| |
| Encode_Status ret = ENCODE_SUCCESS; |
| |
| LOG_V("Begin\n"); |
| CHECK_NULL_RETURN_IFFAIL(outBuffer); |
| |
| switch (outBuffer->format) { |
| case OUTPUT_CODEC_DATA: { |
| // Output the codec config data |
| ret = outputConfigData(outBuffer); |
| CHECK_ENCODE_STATUS_CLEANUP("outputCodecData"); |
| break; |
| } |
| default: |
| LOG_E("Invalid buffer mode for MPEG-4:2\n"); |
| ret = ENCODE_FAIL; |
| break; |
| } |
| |
| LOG_I("out size is = %d\n", outBuffer->dataSize); |
| |
| |
| CLEAN_UP: |
| |
| LOG_V("End\n"); |
| return ret; |
| } |
| |
| Encode_Status VideoEncoderMP4::renderSequenceParams(EncodeTask *) { |
| |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncSequenceParameterBufferMPEG4 mp4SequenceParams = VAEncSequenceParameterBufferMPEG4(); |
| |
| uint32_t frameRateNum = mComParams.frameRate.frameRateNum; |
| uint32_t frameRateDenom = mComParams.frameRate.frameRateDenom; |
| |
| LOG_V( "Begin\n\n"); |
| // set up the sequence params for HW |
| mp4SequenceParams.profile_and_level_indication = mProfileLevelIndication; |
| mp4SequenceParams.video_object_layer_width= mComParams.resolution.width; |
| mp4SequenceParams.video_object_layer_height= mComParams.resolution.height; |
| mp4SequenceParams.vop_time_increment_resolution = |
| (unsigned int) (frameRateNum + frameRateDenom /2) / frameRateDenom; |
| mp4SequenceParams.fixed_vop_time_increment= mFixedVOPTimeIncrement; |
| mp4SequenceParams.bits_per_second= mComParams.rcParams.bitRate; |
| mp4SequenceParams.frame_rate = |
| (unsigned int) (frameRateNum + frameRateDenom /2) / frameRateDenom; |
| mp4SequenceParams.initial_qp = mComParams.rcParams.initQP; |
| mp4SequenceParams.min_qp = mComParams.rcParams.minQP; |
| mp4SequenceParams.intra_period = mComParams.intraPeriod; |
| //mpeg4_seq_param.fixed_vop_rate = 30; |
| |
| LOG_V("===mpeg4 sequence params===\n"); |
| LOG_I("profile_and_level_indication = %d\n", (uint32_t)mp4SequenceParams.profile_and_level_indication); |
| LOG_I("intra_period = %d\n", mp4SequenceParams.intra_period); |
| LOG_I("video_object_layer_width = %d\n", mp4SequenceParams.video_object_layer_width); |
| LOG_I("video_object_layer_height = %d\n", mp4SequenceParams.video_object_layer_height); |
| LOG_I("vop_time_increment_resolution = %d\n", mp4SequenceParams.vop_time_increment_resolution); |
| LOG_I("fixed_vop_rate = %d\n", mp4SequenceParams.fixed_vop_rate); |
| LOG_I("fixed_vop_time_increment = %d\n", mp4SequenceParams.fixed_vop_time_increment); |
| LOG_I("bitrate = %d\n", mp4SequenceParams.bits_per_second); |
| LOG_I("frame_rate = %d\n", mp4SequenceParams.frame_rate); |
| LOG_I("initial_qp = %d\n", mp4SequenceParams.initial_qp); |
| LOG_I("min_qp = %d\n", mp4SequenceParams.min_qp); |
| LOG_I("intra_period = %d\n\n", mp4SequenceParams.intra_period); |
| |
| vaStatus = vaCreateBuffer( |
| mVADisplay, mVAContext, |
| VAEncSequenceParameterBufferType, |
| sizeof(mp4SequenceParams), |
| 1, &mp4SequenceParams, |
| &mSeqParamBuf); |
| CHECK_VA_STATUS_RETURN("vaCreateBuffer"); |
| |
| vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSeqParamBuf, 1); |
| CHECK_VA_STATUS_RETURN("vaRenderPicture"); |
| |
| LOG_V( "end\n"); |
| return ENCODE_SUCCESS; |
| } |
| |
| Encode_Status VideoEncoderMP4::renderPictureParams(EncodeTask *task) { |
| |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAEncPictureParameterBufferMPEG4 mpeg4_pic_param = VAEncPictureParameterBufferMPEG4(); |
| LOG_V( "Begin\n\n"); |
| // set picture params for HW |
| if(mAutoReference == false){ |
| mpeg4_pic_param.reference_picture = task->ref_surface; |
| mpeg4_pic_param.reconstructed_picture = task->rec_surface; |
| }else { |
| mpeg4_pic_param.reference_picture = mAutoRefSurfaces[0]; |
| mpeg4_pic_param.reconstructed_picture = mAutoRefSurfaces[1]; |
| } |
| |
| mpeg4_pic_param.coded_buf = task->coded_buffer; |
| mpeg4_pic_param.picture_width = mComParams.resolution.width; |
| mpeg4_pic_param.picture_height = mComParams.resolution.height; |
| mpeg4_pic_param.vop_time_increment= mFrameNum; |
| mpeg4_pic_param.picture_type = (task->type == FTYPE_I) ? VAEncPictureTypeIntra : VAEncPictureTypePredictive; |
| |
| LOG_V("======mpeg4 picture params======\n"); |
| LOG_V("reference_picture = 0x%08x\n", mpeg4_pic_param.reference_picture); |
| LOG_V("reconstructed_picture = 0x%08x\n", mpeg4_pic_param.reconstructed_picture); |
| LOG_V("coded_buf = 0x%08x\n", mpeg4_pic_param.coded_buf); |
| // LOG_I("coded_buf_index = %d\n", mCodedBufIndex); |
| LOG_V("picture_width = %d\n", mpeg4_pic_param.picture_width); |
| LOG_V("picture_height = %d\n", mpeg4_pic_param.picture_height); |
| LOG_V("vop_time_increment = %d\n", mpeg4_pic_param.vop_time_increment); |
| LOG_V("picture_type = %d\n\n", mpeg4_pic_param.picture_type); |
| |
| vaStatus = vaCreateBuffer( |
| mVADisplay, mVAContext, |
| VAEncPictureParameterBufferType, |
| sizeof(mpeg4_pic_param), |
| 1,&mpeg4_pic_param, |
| &mPicParamBuf); |
| CHECK_VA_STATUS_RETURN("vaCreateBuffer"); |
| |
| vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mPicParamBuf, 1); |
| CHECK_VA_STATUS_RETURN("vaRenderPicture"); |
| |
| return ENCODE_SUCCESS; |
| } |
| |
| |
| Encode_Status VideoEncoderMP4::renderSliceParams(EncodeTask *task) { |
| |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| uint32_t sliceHeight; |
| uint32_t sliceHeightInMB; |
| |
| VAEncSliceParameterBuffer sliceParams; |
| |
| LOG_V( "Begin\n\n"); |
| |
| sliceHeight = mComParams.resolution.height; |
| sliceHeight += 15; |
| sliceHeight &= (~15); |
| sliceHeightInMB = sliceHeight / 16; |
| |
| sliceParams.start_row_number = 0; |
| sliceParams.slice_height = sliceHeightInMB; |
| sliceParams.slice_flags.bits.is_intra = (task->type == FTYPE_I)?1:0; |
| sliceParams.slice_flags.bits.disable_deblocking_filter_idc = 0; |
| |
| LOG_V("======mpeg4 slice params======\n"); |
| LOG_I( "start_row_number = %d\n", (int) sliceParams.start_row_number); |
| LOG_I( "sliceHeightInMB = %d\n", (int) sliceParams.slice_height); |
| LOG_I( "is_intra = %d\n", (int) sliceParams.slice_flags.bits.is_intra); |
| |
| vaStatus = vaCreateBuffer( |
| mVADisplay, mVAContext, |
| VAEncSliceParameterBufferType, |
| sizeof(VAEncSliceParameterBuffer), |
| 1, &sliceParams, |
| &mSliceParamBuf); |
| CHECK_VA_STATUS_RETURN("vaCreateBuffer"); |
| |
| vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSliceParamBuf, 1); |
| CHECK_VA_STATUS_RETURN("vaRenderPicture"); |
| |
| LOG_V( "end\n"); |
| return ENCODE_SUCCESS; |
| } |
| |
| Encode_Status VideoEncoderMP4::sendEncodeCommand(EncodeTask *task) { |
| Encode_Status ret = ENCODE_SUCCESS; |
| LOG_V( "Begin\n"); |
| |
| if (mFrameNum == 0) { |
| ret = renderSequenceParams(task); |
| CHECK_ENCODE_STATUS_RETURN("renderSequenceParams"); |
| } |
| |
| ret = renderPictureParams(task); |
| CHECK_ENCODE_STATUS_RETURN("renderPictureParams"); |
| |
| ret = renderSliceParams(task); |
| CHECK_ENCODE_STATUS_RETURN("renderPictureParams"); |
| |
| LOG_V( "End\n"); |
| return ENCODE_SUCCESS; |
| } |