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#include "VideoEncoderLog.h"
20#include "VideoEncoderAVC.h"
21#include <va/va_tpi.h>
22#include <va/va_enc_h264.h>
23#include <bitstream.h>
24
25VideoEncoderAVC::VideoEncoderAVC()
26    :VideoEncoderBase() {
27    if(VideoEncoderBase::queryProfileLevelConfig(mVADisplay, VAProfileH264High) == ENCODE_SUCCESS){
28        mComParams.profile = VAProfileH264High;
29        mComParams.level = 42;
30    }else if(VideoEncoderBase::queryProfileLevelConfig(mVADisplay, VAProfileH264Main) == ENCODE_SUCCESS){
31        mComParams.profile = VAProfileH264Main;
32        mComParams.level = 41;
33    }
34    mVideoParamsAVC.basicUnitSize = 0;
35    mVideoParamsAVC.VUIFlag = 0;
36    mVideoParamsAVC.sliceNum.iSliceNum = 2;
37    mVideoParamsAVC.sliceNum.pSliceNum = 2;
38    mVideoParamsAVC.idrInterval = 2;
39    mVideoParamsAVC.ipPeriod = 1;
40    mVideoParamsAVC.maxSliceSize = 0;
41    mVideoParamsAVC.delimiterType = AVC_DELIMITER_ANNEXB;
42    mSliceNum = 2;
43    mVideoParamsAVC.crop.LeftOffset = 0;
44    mVideoParamsAVC.crop.RightOffset = 0;
45    mVideoParamsAVC.crop.TopOffset = 0;
46    mVideoParamsAVC.crop.BottomOffset = 0;
47    mVideoParamsAVC.SAR.SarWidth = 0;
48    mVideoParamsAVC.SAR.SarHeight = 0;
49    mVideoParamsAVC.bEntropyCodingCABAC = 0;
50    mVideoParamsAVC.bWeightedPPrediction = 0;
51    mVideoParamsAVC.bDirect8x8Inference = 0;
52    mVideoParamsAVC.bConstIpred = 0;
53    mAutoReferenceSurfaceNum = 4;
54
55    packed_seq_header_param_buf_id = VA_INVALID_ID;
56    packed_seq_buf_id = VA_INVALID_ID;
57    packed_pic_header_param_buf_id = VA_INVALID_ID;
58    packed_pic_buf_id = VA_INVALID_ID;
59    packed_sei_header_param_buf_id = VA_INVALID_ID;   /* the SEI buffer */
60    packed_sei_buf_id = VA_INVALID_ID;
61}
62
63Encode_Status VideoEncoderAVC::start() {
64
65    Encode_Status ret = ENCODE_SUCCESS;
66    LOG_V( "Begin\n");
67
68    if (mComParams.rcMode == VA_RC_VCM) {
69        // If we are in VCM, we will set slice num to max value
70        // mVideoParamsAVC.sliceNum.iSliceNum = (mComParams.resolution.height + 15) / 16;
71        // mVideoParamsAVC.sliceNum.pSliceNum = mVideoParamsAVC.sliceNum.iSliceNum;
72    }
73
74    ret = VideoEncoderBase::start ();
75    CHECK_ENCODE_STATUS_RETURN("VideoEncoderBase::start");
76
77    LOG_V( "end\n");
78    return ret;
79}
80
81Encode_Status VideoEncoderAVC::derivedSetParams(VideoParamConfigSet *videoEncParams) {
82
83    CHECK_NULL_RETURN_IFFAIL(videoEncParams);
84    VideoParamsAVC *encParamsAVC = reinterpret_cast <VideoParamsAVC *> (videoEncParams);
85
86    // AVC parames
87    if (encParamsAVC->size != sizeof (VideoParamsAVC)) {
88        return ENCODE_INVALID_PARAMS;
89    }
90
91    if(encParamsAVC->ipPeriod == 0 || encParamsAVC->ipPeriod >4)
92        return ENCODE_INVALID_PARAMS;
93
94    if((mComParams.intraPeriod >1)&&(mComParams.intraPeriod % encParamsAVC->ipPeriod !=0))
95        return ENCODE_INVALID_PARAMS;
96
97    mVideoParamsAVC = *encParamsAVC;
98    if(mComParams.profile == VAProfileH264Baseline){
99        mVideoParamsAVC.bEntropyCodingCABAC = 0;
100        mVideoParamsAVC.bDirect8x8Inference = 0;
101        mVideoParamsAVC.bWeightedPPrediction = 0;
102    }
103    return ENCODE_SUCCESS;
104}
105
106Encode_Status VideoEncoderAVC:: derivedGetParams(VideoParamConfigSet *videoEncParams) {
107
108    CHECK_NULL_RETURN_IFFAIL(videoEncParams);
109    VideoParamsAVC *encParamsAVC = reinterpret_cast <VideoParamsAVC *> (videoEncParams);
110
111    // AVC parames
112    if (encParamsAVC->size != sizeof (VideoParamsAVC)) {
113        return ENCODE_INVALID_PARAMS;
114    }
115
116    *encParamsAVC = mVideoParamsAVC;
117    return ENCODE_SUCCESS;
118
119}
120
121Encode_Status VideoEncoderAVC::derivedSetConfig(VideoParamConfigSet *videoEncConfig) {
122
123    CHECK_NULL_RETURN_IFFAIL(videoEncConfig);
124    LOG_V("Config type = %d\n", (int)videoEncConfig->type);
125
126    switch (videoEncConfig->type) {
127        case VideoConfigTypeAVCIntraPeriod: {
128
129            VideoConfigAVCIntraPeriod *configAVCIntraPeriod =
130                    reinterpret_cast <VideoConfigAVCIntraPeriod *> (videoEncConfig);
131            // Config Intra Peroid
132            if (configAVCIntraPeriod->size != sizeof (VideoConfigAVCIntraPeriod)) {
133                return ENCODE_INVALID_PARAMS;
134            }
135
136            if(configAVCIntraPeriod->ipPeriod == 0 || configAVCIntraPeriod->ipPeriod >4)
137                return ENCODE_INVALID_PARAMS;
138            if((configAVCIntraPeriod->intraPeriod >1)&&(configAVCIntraPeriod->intraPeriod % configAVCIntraPeriod->ipPeriod !=0))
139                return ENCODE_INVALID_PARAMS;
140
141            mVideoParamsAVC.idrInterval = configAVCIntraPeriod->idrInterval;
142            mVideoParamsAVC.ipPeriod = configAVCIntraPeriod->ipPeriod;
143            mComParams.intraPeriod = configAVCIntraPeriod->intraPeriod;
144            mNewHeader = true;
145            break;
146        }
147        case VideoConfigTypeNALSize: {
148            // Config MTU
149            VideoConfigNALSize *configNALSize =
150                    reinterpret_cast <VideoConfigNALSize *> (videoEncConfig);
151            if (configNALSize->size != sizeof (VideoConfigNALSize)) {
152                return ENCODE_INVALID_PARAMS;
153            }
154
155            mVideoParamsAVC.maxSliceSize = configNALSize->maxSliceSize;
156            mRenderMaxSliceSize = true;
157            break;
158        }
159        case VideoConfigTypeIDRRequest: {
160            if(mVideoParamsAVC.ipPeriod >1)
161                return ENCODE_FAIL;
162            else
163                mNewHeader = true;
164            break;
165        }
166        case VideoConfigTypeSliceNum: {
167
168            VideoConfigSliceNum *configSliceNum =
169                    reinterpret_cast <VideoConfigSliceNum *> (videoEncConfig);
170            // Config Slice size
171            if (configSliceNum->size != sizeof (VideoConfigSliceNum)) {
172                return ENCODE_INVALID_PARAMS;
173            }
174
175            mVideoParamsAVC.sliceNum = configSliceNum->sliceNum;
176            break;
177        }
178        default: {
179            LOG_E ("Invalid Config Type");
180            break;
181        }
182    }
183
184    return ENCODE_SUCCESS;
185}
186
187Encode_Status VideoEncoderAVC:: derivedGetConfig(
188        VideoParamConfigSet *videoEncConfig) {
189
190    CHECK_NULL_RETURN_IFFAIL(videoEncConfig);
191    LOG_V("Config type = %d\n", (int)videoEncConfig->type);
192
193    switch (videoEncConfig->type) {
194
195        case VideoConfigTypeAVCIntraPeriod: {
196
197            VideoConfigAVCIntraPeriod *configAVCIntraPeriod =
198                    reinterpret_cast <VideoConfigAVCIntraPeriod *> (videoEncConfig);
199            if (configAVCIntraPeriod->size != sizeof (VideoConfigAVCIntraPeriod)) {
200                return ENCODE_INVALID_PARAMS;
201            }
202
203            configAVCIntraPeriod->idrInterval = mVideoParamsAVC.idrInterval;
204            configAVCIntraPeriod->intraPeriod = mComParams.intraPeriod;
205            configAVCIntraPeriod->ipPeriod = mVideoParamsAVC.ipPeriod;
206
207            break;
208        }
209        case VideoConfigTypeNALSize: {
210
211            VideoConfigNALSize *configNALSize =
212                    reinterpret_cast <VideoConfigNALSize *> (videoEncConfig);
213            if (configNALSize->size != sizeof (VideoConfigNALSize)) {
214                return ENCODE_INVALID_PARAMS;
215            }
216
217            configNALSize->maxSliceSize = mVideoParamsAVC.maxSliceSize;
218            break;
219        }
220        case VideoConfigTypeIDRRequest: {
221            break;
222
223        }
224        case VideoConfigTypeSliceNum: {
225
226            VideoConfigSliceNum *configSliceNum =
227                    reinterpret_cast <VideoConfigSliceNum *> (videoEncConfig);
228            if (configSliceNum->size != sizeof (VideoConfigSliceNum)) {
229                return ENCODE_INVALID_PARAMS;
230            }
231
232            configSliceNum->sliceNum = mVideoParamsAVC.sliceNum;
233            break;
234        }
235        default: {
236            LOG_E ("Invalid Config Type");
237            break;
238        }
239    }
240
241    return ENCODE_SUCCESS;
242}
243
244Encode_Status VideoEncoderAVC::updateFrameInfo(EncodeTask* task) {
245    uint32_t idrPeroid = mComParams.intraPeriod * mVideoParamsAVC.idrInterval;
246    FrameType frametype;
247    uint32_t frame_num = mFrameNum;
248    uint32_t intraPeriod = mComParams.intraPeriod;
249
250    if (idrPeroid != 0) {
251        if(mVideoParamsAVC.ipPeriod > 1)
252            frame_num = frame_num % (idrPeroid + 1);
253        else
254            frame_num = frame_num % idrPeroid ;
255    }else{
256        if (mComParams.intraPeriod == 0)
257            intraPeriod = 0xFFFFFFFF;
258    }
259
260
261    if(frame_num ==0){
262        frametype = FTYPE_IDR;
263    }else if(intraPeriod ==1)
264        // only I frame need intraPeriod=idrInterval=ipPeriod=0
265        frametype = FTYPE_I;
266    else if(mVideoParamsAVC.ipPeriod == 1){ // no B frame
267        if((frame_num >  1) &&((frame_num -1)%intraPeriod == 0))
268            frametype = FTYPE_I;
269        else
270            frametype = FTYPE_P;
271    } else {
272        if(((frame_num-1)%intraPeriod == 0)&&(frame_num >intraPeriod))
273            frametype = FTYPE_I;
274        else{
275            frame_num = frame_num%intraPeriod;
276            if(frame_num == 0)
277                frametype = FTYPE_B;
278            else if((frame_num-1)%mVideoParamsAVC.ipPeriod == 0)
279                frametype = FTYPE_P;
280            else
281                frametype = FTYPE_B;
282        }
283    }
284
285    if (frametype == FTYPE_IDR || frametype == FTYPE_I)
286        task->flag |= ENCODE_BUFFERFLAG_SYNCFRAME;
287
288    if (frametype != task->type) {
289        const char* FrameTypeStr[10] = {"UNKNOWN", "I", "P", "B", "SI", "SP", "EI", "EP", "S", "IDR"};
290        if ((uint32_t) task->type < 9)
291            LOG_V("libMIX thinks it is %s Frame, the input is %s Frame", FrameTypeStr[frametype], FrameTypeStr[task->type]);
292        else
293            LOG_V("Wrong Frame type %d, type may not be initialized ?\n", task->type);
294    }
295
296//temparily comment out to avoid uninitialize error
297//    if (task->type == FTYPE_UNKNOWN || (uint32_t) task->type > 9)
298        task->type = frametype;
299
300    return ENCODE_SUCCESS;
301}
302
303Encode_Status VideoEncoderAVC::getExtFormatOutput(VideoEncOutputBuffer *outBuffer) {
304
305    Encode_Status ret = ENCODE_SUCCESS;
306
307    LOG_V("Begin\n");
308
309    switch (outBuffer->format) {
310        case OUTPUT_CODEC_DATA: {
311            // Output the codec data
312            ret = outputCodecData(outBuffer);
313            CHECK_ENCODE_STATUS_CLEANUP("outputCodecData");
314            break;
315        }
316
317        case OUTPUT_ONE_NAL: {
318            // Output only one NAL unit
319            ret = outputOneNALU(outBuffer, true);
320            CHECK_ENCODE_STATUS_CLEANUP("outputOneNALU");
321            break;
322        }
323
324        case OUTPUT_ONE_NAL_WITHOUT_STARTCODE: {
325            ret = outputOneNALU(outBuffer, false);
326            CHECK_ENCODE_STATUS_CLEANUP("outputOneNALU");
327            break;
328        }
329
330        case OUTPUT_LENGTH_PREFIXED: {
331            // Output length prefixed
332            ret = outputLengthPrefixed(outBuffer);
333            CHECK_ENCODE_STATUS_CLEANUP("outputLengthPrefixed");
334            break;
335        }
336
337        case OUTPUT_NALULENGTHS_PREFIXED: {
338            // Output nalu lengths ahead of bitstream
339            ret = outputNaluLengthsPrefixed(outBuffer);
340            CHECK_ENCODE_STATUS_CLEANUP("outputNaluLengthsPrefixed");
341            break;
342        }
343
344        default:
345            LOG_E("Invalid buffer mode\n");
346            ret = ENCODE_FAIL;
347            break;
348    }
349
350    LOG_V("out size is = %d\n", outBuffer->dataSize);
351
352
353CLEAN_UP:
354
355
356    LOG_V("End\n");
357    return ret;
358}
359
360Encode_Status VideoEncoderAVC::getOneNALUnit(
361        uint8_t *inBuffer, uint32_t bufSize, uint32_t *nalSize,
362        uint32_t *nalType, uint32_t *nalOffset, uint32_t status) {
363    uint32_t pos = 0;
364    uint32_t zeroByteCount = 0;
365    uint32_t singleByteTable[3][2] = {{1,0},{2,0},{2,3}};
366    uint32_t dataRemaining = 0;
367    uint8_t *dataPtr;
368
369    // Don't need to check parameters here as we just checked by caller
370    while ((inBuffer[pos++] == 0x00)) {
371        zeroByteCount ++;
372        if (pos >= bufSize)  //to make sure the buffer to be accessed is valid
373            break;
374    }
375
376    if (inBuffer[pos - 1] != 0x01 || zeroByteCount < 2) {
377        LOG_E("The stream is not AnnexB format \n");
378        LOG_E("segment status is %x \n", status);
379        return ENCODE_FAIL; //not AnnexB, we won't process it
380    }
381
382    *nalType = (*(inBuffer + pos)) & 0x1F;
383    LOG_V ("NAL type = 0x%x\n", *nalType);
384
385    zeroByteCount = 0;
386    *nalOffset = pos;
387
388    if (status & VA_CODED_BUF_STATUS_SINGLE_NALU) {
389        *nalSize = bufSize - pos;
390        return ENCODE_SUCCESS;
391    }
392
393    dataPtr  = inBuffer + pos;
394    dataRemaining = bufSize - pos + 1;
395
396    while ((dataRemaining > 0) && (zeroByteCount < 3)) {
397        if (((((intptr_t)dataPtr) & 0xF ) == 0) && (0 == zeroByteCount)
398               && (dataRemaining > 0xF)) {
399
400            __asm__  (
401                //Data input
402                "movl %1, %%ecx\n\t"//data_ptr=>ecx
403                "movl %0, %%eax\n\t"//data_remaing=>eax
404                //Main compare loop
405                //
406                "0:\n\t"   //MATCH_8_ZERO:
407                "pxor %%xmm0,%%xmm0\n\t"//set 0=>xmm0
408                "pcmpeqb (%%ecx),%%xmm0\n\t"//data_ptr=xmm0,(byte==0)?0xFF:0x00
409                "pmovmskb %%xmm0, %%edx\n\t"//edx[0]=xmm0[7],edx[1]=xmm0[15],...,edx[15]=xmm0[127]
410                "test $0xAAAA, %%edx\n\t"//edx& 1010 1010 1010 1010b
411                "jnz 2f\n\t"//Not equal to zero means that at least one byte 0x00
412
413                "1:\n\t"  //PREPARE_NEXT_MATCH:
414                "sub $0x10, %%eax\n\t"//16 + ecx --> ecx
415                "add $0x10, %%ecx\n\t"//eax-16 --> eax
416                "cmp $0x10, %%eax\n\t"
417                "jge 0b\n\t"//search next 16 bytes
418
419                "2:\n\t"   //DATA_RET:
420                "movl %%ecx, %1\n\t"//output ecx->data_ptr
421                "movl %%eax, %0\n\t"//output eax->data_remaining
422                : "+m"(dataRemaining), "+m"(dataPtr)
423                :
424                :"eax", "ecx", "edx", "xmm0"
425                );
426            if (0 >= dataRemaining) {
427                break;
428            }
429
430        }
431        //check the value of each byte
432        if ((*dataPtr) >= 2) {
433
434            zeroByteCount = 0;
435
436        }
437        else {
438            zeroByteCount = singleByteTable[zeroByteCount][*dataPtr];
439         }
440
441        dataPtr ++;
442        dataRemaining --;
443    }
444
445    if ((3 == zeroByteCount) && (dataRemaining > 0)) {
446
447        *nalSize =  bufSize - dataRemaining - *nalOffset - 3;
448
449    } else if (0 == dataRemaining) {
450
451        *nalSize = bufSize - *nalOffset;
452    }
453    return ENCODE_SUCCESS;
454}
455
456Encode_Status VideoEncoderAVC::getHeader(
457        uint8_t *inBuffer, uint32_t bufSize, uint32_t *headerSize, uint32_t status) {
458
459    uint32_t nalType = 0;
460    uint32_t nalSize = 0;
461    uint32_t nalOffset = 0;
462    uint32_t size = 0;
463    uint8_t *buf = inBuffer;
464    Encode_Status ret = ENCODE_SUCCESS;
465
466    *headerSize = 0;
467    CHECK_NULL_RETURN_IFFAIL(inBuffer);
468
469    if (bufSize == 0) {
470        //bufSize shoule not be 0, error happens
471        LOG_E("Buffer size is 0\n");
472        return ENCODE_FAIL;
473    }
474
475    while (1) {
476        nalType = nalSize = nalOffset = 0;
477        ret = getOneNALUnit(buf, bufSize, &nalSize, &nalType, &nalOffset, status);
478        CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");
479
480        LOG_V("NAL type = %d, NAL size = %d, offset = %d\n", nalType, nalSize, nalOffset);
481        size = nalSize + nalOffset;
482
483        // Codec_data should be SPS or PPS
484        if (nalType == 7 || nalType == 8) {
485            *headerSize += size;
486            buf += size;
487            bufSize -= size;
488        } else {
489            LOG_V("No header found or no header anymore\n");
490            break;
491        }
492    }
493
494    return ENCODE_SUCCESS;
495}
496
497Encode_Status VideoEncoderAVC::outputCodecData(
498        VideoEncOutputBuffer *outBuffer) {
499
500    Encode_Status ret = ENCODE_SUCCESS;
501    uint32_t headerSize = 0;
502
503    ret = getHeader((uint8_t *)mCurSegment->buf + mOffsetInSeg,
504            mCurSegment->size - mOffsetInSeg, &headerSize, mCurSegment->status);
505    CHECK_ENCODE_STATUS_RETURN("getHeader");
506    if (headerSize == 0) {
507        outBuffer->dataSize = 0;
508        mCurSegment = NULL;
509        return ENCODE_NO_REQUEST_DATA;
510    }
511
512    if (headerSize <= outBuffer->bufferSize) {
513        memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg, headerSize);
514        mTotalSizeCopied += headerSize;
515        mOffsetInSeg += headerSize;
516        outBuffer->dataSize = headerSize;
517        outBuffer->remainingSize = 0;
518        outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
519        outBuffer->flag |= ENCODE_BUFFERFLAG_CODECCONFIG;
520        outBuffer->flag |= ENCODE_BUFFERFLAG_SYNCFRAME;
521    } else {
522        // we need a big enough buffer, otherwise we won't output anything
523        outBuffer->dataSize = 0;
524        outBuffer->remainingSize = headerSize;
525        outBuffer->flag |= ENCODE_BUFFERFLAG_DATAINVALID;
526        LOG_E("Buffer size too small\n");
527        return ENCODE_BUFFER_TOO_SMALL;
528    }
529
530    return ret;
531}
532
533Encode_Status VideoEncoderAVC::outputOneNALU(
534        VideoEncOutputBuffer *outBuffer, bool startCode) {
535
536    uint32_t nalType = 0;
537    uint32_t nalSize = 0;
538    uint32_t nalOffset = 0;
539    uint32_t sizeToBeCopied = 0;
540
541    Encode_Status ret = ENCODE_SUCCESS;
542    CHECK_NULL_RETURN_IFFAIL(mCurSegment->buf);
543
544    ret = getOneNALUnit((uint8_t *)mCurSegment->buf + mOffsetInSeg,
545            mCurSegment->size - mOffsetInSeg, &nalSize, &nalType, &nalOffset, mCurSegment->status);
546    CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");
547
548    // check if we need startcode along with the payload
549    if (startCode) {
550        sizeToBeCopied = nalSize + nalOffset;
551    } else {
552        sizeToBeCopied = nalSize;
553    }
554
555    if (sizeToBeCopied <= outBuffer->bufferSize) {
556        if (startCode) {
557            memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg, sizeToBeCopied);
558        } else {
559            memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg + nalOffset,
560                   sizeToBeCopied);
561        }
562        mTotalSizeCopied += sizeToBeCopied;
563        mOffsetInSeg += (nalSize + nalOffset);
564        outBuffer->dataSize = sizeToBeCopied;
565        outBuffer->flag |= ENCODE_BUFFERFLAG_PARTIALFRAME;
566        outBuffer->remainingSize = 0;
567    } else {
568        // if nothing to be copied out, set flag to invalid
569        outBuffer->dataSize = 0;
570        outBuffer->flag |= ENCODE_BUFFERFLAG_DATAINVALID;
571        outBuffer->remainingSize = sizeToBeCopied;
572        LOG_W("Buffer size too small\n");
573        return ENCODE_BUFFER_TOO_SMALL;
574    }
575
576    // check if all data in current segment has been copied out
577    if (mCurSegment->size == mOffsetInSeg) {
578        if (mCurSegment->next != NULL) {
579            mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
580            mOffsetInSeg = 0;
581        } else {
582            LOG_V("End of stream\n");
583            outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
584            mCurSegment = NULL;
585        }
586    }
587
588    return ENCODE_SUCCESS;
589}
590
591Encode_Status VideoEncoderAVC::outputLengthPrefixed(VideoEncOutputBuffer *outBuffer) {
592
593    Encode_Status ret = ENCODE_SUCCESS;
594    uint32_t nalType = 0;
595    uint32_t nalSize = 0;
596    uint32_t nalOffset = 0;
597    uint32_t sizeCopiedHere = 0;
598
599    CHECK_NULL_RETURN_IFFAIL(mCurSegment->buf);
600
601    while (1) {
602
603        if (mCurSegment->size < mOffsetInSeg || outBuffer->bufferSize < sizeCopiedHere) {
604            LOG_E("mCurSegment->size < mOffsetInSeg  || outBuffer->bufferSize < sizeCopiedHere\n");
605            return ENCODE_FAIL;
606        }
607
608        // we need to handle the whole bitstream NAL by NAL
609        ret = getOneNALUnit(
610                (uint8_t *)mCurSegment->buf + mOffsetInSeg,
611                mCurSegment->size - mOffsetInSeg, &nalSize, &nalType, &nalOffset, mCurSegment->status);
612        CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");
613
614        if (nalSize + 4 <= outBuffer->bufferSize - sizeCopiedHere) {
615            // write the NAL length to bit stream
616            outBuffer->data[sizeCopiedHere] = (nalSize >> 24) & 0xff;
617            outBuffer->data[sizeCopiedHere + 1] = (nalSize >> 16) & 0xff;
618            outBuffer->data[sizeCopiedHere + 2] = (nalSize >> 8)  & 0xff;
619            outBuffer->data[sizeCopiedHere + 3] = nalSize   & 0xff;
620
621            sizeCopiedHere += 4;
622            mTotalSizeCopied += 4;
623
624            memcpy(outBuffer->data + sizeCopiedHere,
625                   (uint8_t *)mCurSegment->buf + mOffsetInSeg + nalOffset, nalSize);
626
627            sizeCopiedHere += nalSize;
628            mTotalSizeCopied += nalSize;
629            mOffsetInSeg += (nalSize + nalOffset);
630
631        } else {
632            outBuffer->dataSize = sizeCopiedHere;
633            // In case the start code is 3-byte length but we use 4-byte for length prefixed
634            // so the remainingSize size may larger than the remaining data size
635            outBuffer->remainingSize = mTotalSize - mTotalSizeCopied + 100;
636            outBuffer->flag |= ENCODE_BUFFERFLAG_PARTIALFRAME;
637            LOG_E("Buffer size too small\n");
638            return ENCODE_BUFFER_TOO_SMALL;
639        }
640
641        // check if all data in current segment has been copied out
642        if (mCurSegment->size == mOffsetInSeg) {
643            if (mCurSegment->next != NULL) {
644                mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
645                mOffsetInSeg = 0;
646            } else {
647                LOG_V("End of stream\n");
648                outBuffer->dataSize = sizeCopiedHere;
649                outBuffer->remainingSize = 0;
650                outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
651                mCurSegment = NULL;
652                break;
653            }
654        }
655    }
656
657    return ENCODE_SUCCESS;
658}
659
660Encode_Status VideoEncoderAVC::outputNaluLengthsPrefixed(VideoEncOutputBuffer *outBuffer) {
661
662    Encode_Status ret = ENCODE_SUCCESS;
663    uint32_t nalType = 0;
664    uint32_t nalSize = 0;
665    uint32_t nalOffset = 0;
666    uint32_t sizeCopiedHere = 0;
667    const uint32_t NALUINFO_OFFSET = 256;
668    uint32_t nalNum = 0;
669
670    CHECK_NULL_RETURN_IFFAIL(mCurSegment->buf);
671
672    while (1) {
673
674        if (mCurSegment->size < mOffsetInSeg || outBuffer->bufferSize < sizeCopiedHere) {
675            LOG_E("mCurSegment->size < mOffsetInSeg  || outBuffer->bufferSize < sizeCopiedHere\n");
676            return ENCODE_FAIL;
677        }
678
679        // we need to handle the whole bitstream NAL by NAL
680        ret = getOneNALUnit(
681                (uint8_t *)mCurSegment->buf + mOffsetInSeg,
682                mCurSegment->size - mOffsetInSeg, &nalSize, &nalType, &nalOffset, mCurSegment->status);
683        CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");
684
685        if (nalSize + 4 <= outBuffer->bufferSize - NALUINFO_OFFSET - sizeCopiedHere) {
686
687            memcpy(outBuffer->data + NALUINFO_OFFSET + sizeCopiedHere,
688                   (uint8_t *)mCurSegment->buf + mOffsetInSeg, nalSize + nalOffset);
689
690            sizeCopiedHere += nalSize + nalOffset;
691            mTotalSizeCopied += nalSize + nalOffset;
692            mOffsetInSeg += (nalSize + nalOffset);
693
694        } else {
695            outBuffer->dataSize = sizeCopiedHere;
696            // In case the start code is 3-byte length but we use 4-byte for length prefixed
697            // so the remainingSize size may larger than the remaining data size
698            outBuffer->remainingSize = mTotalSize - mTotalSizeCopied + 100;
699            outBuffer->flag |= ENCODE_BUFFERFLAG_PARTIALFRAME;
700            LOG_E("Buffer size too small\n");
701            return ENCODE_BUFFER_TOO_SMALL;
702        }
703
704        nalNum ++;
705        uint32_t *nalLength = (uint32_t *) (outBuffer->data + (nalNum+1) * 4);
706
707        *nalLength = nalSize + nalOffset;
708
709        // check if all data in current segment has been copied out
710        if (mCurSegment->size == mOffsetInSeg) {
711            if (mCurSegment->next != NULL) {
712                mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
713                mOffsetInSeg = 0;
714            } else {
715                LOG_V("End of stream\n");
716                outBuffer->dataSize = sizeCopiedHere;
717                outBuffer->remainingSize = 0;
718                outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
719                mCurSegment = NULL;
720                break;
721            }
722        }
723    }
724
725    outBuffer->offset = NALUINFO_OFFSET;
726    uint32_t *nalHead = (uint32_t *) outBuffer->data;
727    *nalHead = 0x4E414C4C; //'nall'
728    *(++nalHead) = nalNum;
729
730    return ENCODE_SUCCESS;
731}
732
733Encode_Status VideoEncoderAVC::sendEncodeCommand(EncodeTask *task) {
734    Encode_Status ret = ENCODE_SUCCESS;
735
736    LOG_V( "Begin\n");
737
738    if (mFrameNum == 0 || mNewHeader) {
739        if (mRenderHrd) {
740            ret = renderHrd();
741            mRenderHrd = false;
742            CHECK_ENCODE_STATUS_RETURN("renderHrd");
743        }
744
745        mFrameNum = 0;
746        ret = renderSequenceParams(task);
747        CHECK_ENCODE_STATUS_RETURN("renderSequenceParams");
748        if (mNewHeader) {
749            mNewHeader = false; //Set to require new header filed to false
750            mFrameNum = 0; //reset mFrameNum to 0
751            updateFrameInfo(task); //recalculate frame info if mNewHeader is set true after PrepareFrameInfo in encode()
752        }
753    }
754
755    if (mRenderMaxSliceSize && mVideoParamsAVC.maxSliceSize != 0) {
756        ret = renderMaxSliceSize();
757        CHECK_ENCODE_STATUS_RETURN("renderMaxSliceSize");
758        mRenderMaxSliceSize = false;
759    }
760
761    if (mComParams.rcParams.enableIntraFrameQPControl && (task->type == FTYPE_IDR || task->type == FTYPE_I))
762        mRenderBitRate = true;
763
764    if (mRenderBitRate) {
765        ret = VideoEncoderBase::renderDynamicBitrate(task);
766        CHECK_ENCODE_STATUS_RETURN("renderDynamicBitrate");
767    }
768
769    if (mRenderAIR &&
770        (mComParams.refreshType == VIDEO_ENC_AIR ||
771        mComParams.refreshType == VIDEO_ENC_BOTH)) {
772
773        ret = renderAIR();
774        CHECK_ENCODE_STATUS_RETURN("renderAIR");
775
776        mRenderAIR = false;
777    }
778
779    if (mRenderCIR) {
780
781        ret = renderCIR();
782        CHECK_ENCODE_STATUS_RETURN("renderCIR");
783
784        mRenderCIR = false;
785    }
786
787    if (mRenderFrameRate) {
788
789        ret = VideoEncoderBase::renderDynamicFrameRate();
790        CHECK_ENCODE_STATUS_RETURN("renderDynamicFrameRate");
791
792        mRenderFrameRate = false;
793    }
794
795    ret = renderPictureParams(task);
796    CHECK_ENCODE_STATUS_RETURN("renderPictureParams");
797
798    if (mFrameNum == 0 && (mEncPackedHeaders != VA_ATTRIB_NOT_SUPPORTED)) {
799        ret = renderPackedSequenceParams(task);
800        CHECK_ENCODE_STATUS_RETURN("renderPackedSequenceParams");
801
802        ret = renderPackedPictureParams(task);
803        CHECK_ENCODE_STATUS_RETURN("renderPackedPictureParams");
804    }
805
806    ret = renderSliceParams(task);
807    CHECK_ENCODE_STATUS_RETURN("renderSliceParams");
808
809    LOG_V( "End\n");
810    return ENCODE_SUCCESS;
811}
812
813
814Encode_Status VideoEncoderAVC::renderMaxSliceSize() {
815
816    VAStatus vaStatus = VA_STATUS_SUCCESS;
817    LOG_V( "Begin\n\n");
818
819    if (mComParams.rcMode != RATE_CONTROL_VCM) {
820        LOG_W ("Not in VCM mode, but call send_max_slice_size\n");
821        return ENCODE_SUCCESS;
822    }
823
824    VAEncMiscParameterBuffer *miscEncParamBuf;
825    VAEncMiscParameterMaxSliceSize *maxSliceSizeParam;
826    VABufferID miscParamBufferID;
827
828    vaStatus = vaCreateBuffer(
829            mVADisplay, mVAContext,
830            VAEncMiscParameterBufferType,
831            sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterMaxSliceSize),
832            1, NULL, &miscParamBufferID);
833    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
834
835    vaStatus = vaMapBuffer(mVADisplay, miscParamBufferID, (void **)&miscEncParamBuf);
836    CHECK_VA_STATUS_RETURN("vaMapBuffer");
837
838    miscEncParamBuf->type = VAEncMiscParameterTypeMaxSliceSize;
839    maxSliceSizeParam = (VAEncMiscParameterMaxSliceSize *)miscEncParamBuf->data;
840
841    maxSliceSizeParam->max_slice_size = mVideoParamsAVC.maxSliceSize;
842
843    vaStatus = vaUnmapBuffer(mVADisplay, miscParamBufferID);
844    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
845
846    LOG_I( "max slice size = %d\n", maxSliceSizeParam->max_slice_size);
847
848    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferID, 1);
849    CHECK_VA_STATUS_RETURN("vaRenderPicture");
850
851    return ENCODE_SUCCESS;
852}
853
854Encode_Status VideoEncoderAVC::renderCIR(){
855    VAStatus vaStatus = VA_STATUS_SUCCESS;
856    LOG_V( "%s Begin\n", __FUNCTION__);
857
858    VABufferID miscParamBufferCIRid;
859    VAEncMiscParameterBuffer *misc_param;
860    VAEncMiscParameterCIR *misc_cir_param;
861
862    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
863            VAEncMiscParameterBufferType,
864            sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterCIR),
865            1,
866            NULL,
867            &miscParamBufferCIRid);
868    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
869
870    vaStatus = vaMapBuffer(mVADisplay, miscParamBufferCIRid,  (void **)&misc_param);
871    CHECK_VA_STATUS_RETURN("vaMapBuffer");
872
873    misc_param->type = VAEncMiscParameterTypeCIR;
874    misc_cir_param = (VAEncMiscParameterCIR *)misc_param->data;
875    misc_cir_param->cir_num_mbs = mComParams.cirParams.cir_num_mbs;
876    LOG_I( "cir_num_mbs %d \n", misc_cir_param->cir_num_mbs);
877
878    vaUnmapBuffer(mVADisplay, miscParamBufferCIRid);
879    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
880
881    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferCIRid, 1);
882    CHECK_VA_STATUS_RETURN("vaRenderPicture");
883
884    return ENCODE_SUCCESS;
885}
886
887Encode_Status VideoEncoderAVC::renderAIR() {
888    VAStatus vaStatus = VA_STATUS_SUCCESS;
889    LOG_V( "Begin\n\n");
890
891    VAEncMiscParameterBuffer   *miscEncParamBuf;
892    VAEncMiscParameterAIR *airParams;
893    VABufferID miscParamBufferID;
894
895    vaStatus = vaCreateBuffer(
896            mVADisplay, mVAContext,
897            VAEncMiscParameterBufferType,
898            sizeof(miscEncParamBuf) + sizeof(VAEncMiscParameterAIR),
899            1, NULL, &miscParamBufferID);
900    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
901
902    vaStatus = vaMapBuffer(mVADisplay, miscParamBufferID, (void **)&miscEncParamBuf);
903    CHECK_VA_STATUS_RETURN("vaMapBuffer");
904
905    miscEncParamBuf->type = VAEncMiscParameterTypeAIR;
906    airParams = (VAEncMiscParameterAIR *)miscEncParamBuf->data;
907
908    airParams->air_num_mbs = mComParams.airParams.airMBs;
909    airParams->air_threshold= mComParams.airParams.airThreshold;
910    airParams->air_auto = mComParams.airParams.airAuto;
911
912    vaStatus = vaUnmapBuffer(mVADisplay, miscParamBufferID);
913    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
914
915    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferID, 1);
916    CHECK_VA_STATUS_RETURN("vaRenderPicture");
917
918    LOG_I( "airThreshold = %d\n", airParams->air_threshold);
919    return ENCODE_SUCCESS;
920}
921
922int VideoEncoderAVC::calcLevel(int numMbs) {
923    int level = 30;
924
925    if (numMbs < 1620) {
926        level = 30;
927    } else if (numMbs < 3600) {
928        level = 31;
929    } else if (numMbs < 5120) {
930        level = 32;
931    } else if (numMbs < 8192) {
932        level = 41;
933    } else if (numMbs < 8704) {
934        level = 42;
935    } else if (numMbs < 22080) {
936        level = 50;
937    } else if (numMbs < 36864) {
938        level = 51;
939    } else {
940        LOG_W("No such level can support that resolution");
941        level = 51;
942    }
943    return level;
944}
945
946Encode_Status VideoEncoderAVC::renderSequenceParams(EncodeTask *) {
947
948    VAStatus vaStatus = VA_STATUS_SUCCESS;
949    VAEncSequenceParameterBufferH264 avcSeqParams = VAEncSequenceParameterBufferH264();
950    VAEncMiscParameterBuffer   *miscEncRCParamBuf;
951    VAEncMiscParameterBuffer   *miscEncFrameRateParamBuf;
952    VAEncMiscParameterRateControl *rcMiscParam;
953    VAEncMiscParameterFrameRate *framerateParam;
954    int level;
955    uint32_t frameRateNum = mComParams.frameRate.frameRateNum;
956    uint32_t frameRateDenom = mComParams.frameRate.frameRateDenom;
957
958    LOG_V( "Begin\n\n");
959    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
960            VAEncMiscParameterBufferType,
961            sizeof (VAEncMiscParameterBuffer) + sizeof (VAEncMiscParameterRateControl),
962            1, NULL,
963            &mRcParamBuf);
964    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
965    vaStatus = vaMapBuffer(mVADisplay, mRcParamBuf, (void **)&miscEncRCParamBuf);
966    CHECK_VA_STATUS_RETURN("vaMapBuffer");
967
968    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
969            VAEncMiscParameterBufferType,
970            sizeof (VAEncMiscParameterBuffer) + sizeof (VAEncMiscParameterFrameRate),
971            1, NULL,
972            &mFrameRateParamBuf);
973    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
974    vaStatus = vaMapBuffer(mVADisplay, mFrameRateParamBuf, (void **)&miscEncFrameRateParamBuf);
975    CHECK_VA_STATUS_RETURN("vaMapBuffer");
976
977    miscEncRCParamBuf->type = VAEncMiscParameterTypeRateControl;
978    rcMiscParam = (VAEncMiscParameterRateControl  *)miscEncRCParamBuf->data;
979    miscEncFrameRateParamBuf->type = VAEncMiscParameterTypeFrameRate;
980    framerateParam = (VAEncMiscParameterFrameRate *)miscEncFrameRateParamBuf->data;
981    // set up the sequence params for HW
982    // avcSeqParams.level_idc = mLevel;
983    avcSeqParams.intra_period = mComParams.intraPeriod;
984    avcSeqParams.intra_idr_period = mVideoParamsAVC.idrInterval;
985    avcSeqParams.ip_period = mVideoParamsAVC.ipPeriod;
986    avcSeqParams.picture_width_in_mbs = (mComParams.resolution.width + 15) / 16;
987    avcSeqParams.picture_height_in_mbs = (mComParams.resolution.height + 15) / 16;
988
989    level = calcLevel (avcSeqParams.picture_width_in_mbs * avcSeqParams.picture_height_in_mbs);
990    avcSeqParams.level_idc = level;
991    avcSeqParams.bits_per_second = mComParams.rcParams.bitRate;
992    framerateParam->framerate =
993            (unsigned int) (frameRateNum + frameRateDenom /2 ) / frameRateDenom;
994    rcMiscParam->initial_qp = mComParams.rcParams.initQP;
995    rcMiscParam->min_qp = mComParams.rcParams.minQP;
996    rcMiscParam->max_qp = mComParams.rcParams.maxQP;
997    if (mComParams.rcParams.enableIntraFrameQPControl) {
998        rcMiscParam->min_qp = mComParams.rcParams.I_minQP;
999        rcMiscParam->max_qp = mComParams.rcParams.I_maxQP;
1000    }
1001    rcMiscParam->window_size = mComParams.rcParams.windowSize;
1002    //target bitrate is sent to libva through Sequence Parameter Buffer
1003    rcMiscParam->bits_per_second = 0;
1004    rcMiscParam->basic_unit_size = mVideoParamsAVC.basicUnitSize; //for rate control usage
1005    avcSeqParams.intra_period = mComParams.intraPeriod;
1006    //avcSeqParams.vui_flag = 248;
1007    avcSeqParams.vui_parameters_present_flag = mVideoParamsAVC.VUIFlag;
1008    avcSeqParams.num_units_in_tick = frameRateDenom;
1009    avcSeqParams.time_scale = 2 * frameRateNum;
1010    avcSeqParams.seq_parameter_set_id = 0;
1011    if (mVideoParamsAVC.crop.LeftOffset ||
1012            mVideoParamsAVC.crop.RightOffset ||
1013            mVideoParamsAVC.crop.TopOffset ||
1014            mVideoParamsAVC.crop.BottomOffset) {
1015        avcSeqParams.frame_cropping_flag = true;
1016        avcSeqParams.frame_crop_left_offset = mVideoParamsAVC.crop.LeftOffset;
1017        avcSeqParams.frame_crop_right_offset = mVideoParamsAVC.crop.RightOffset;
1018        avcSeqParams.frame_crop_top_offset = mVideoParamsAVC.crop.TopOffset;
1019        avcSeqParams.frame_crop_bottom_offset = mVideoParamsAVC.crop.BottomOffset;
1020    } else {
1021        avcSeqParams.frame_cropping_flag = false;
1022
1023        if (mComParams.resolution.width & 0xf) {
1024            avcSeqParams.frame_cropping_flag = true;
1025            uint32_t AWidth = (mComParams.resolution.width + 0xf) & (~0xf);
1026            avcSeqParams.frame_crop_right_offset = ( AWidth - mComParams.resolution.width ) / 2;
1027        }
1028
1029        if (mComParams.resolution.height & 0xf) {
1030            avcSeqParams.frame_cropping_flag = true;
1031            uint32_t AHeight = (mComParams.resolution.height + 0xf) & (~0xf);
1032            avcSeqParams.frame_crop_bottom_offset = ( AHeight - mComParams.resolution.height ) / 2;
1033        }
1034    }
1035
1036    if(avcSeqParams.vui_parameters_present_flag && (mVideoParamsAVC.SAR.SarWidth || mVideoParamsAVC.SAR.SarHeight)) {
1037        avcSeqParams.vui_fields.bits.aspect_ratio_info_present_flag = true;
1038        avcSeqParams.aspect_ratio_idc = 0xff /* Extended_SAR */;
1039        avcSeqParams.sar_width = mVideoParamsAVC.SAR.SarWidth;
1040        avcSeqParams.sar_height = mVideoParamsAVC.SAR.SarHeight;
1041    }
1042
1043    avcSeqParams.max_num_ref_frames = 1;
1044
1045    if(avcSeqParams.ip_period > 1)
1046        avcSeqParams.max_num_ref_frames = 2;
1047
1048    LOG_V("===h264 sequence params===\n");
1049    LOG_V( "seq_parameter_set_id = %d\n", (uint32_t)avcSeqParams.seq_parameter_set_id);
1050    LOG_V( "level_idc = %d\n", (uint32_t)avcSeqParams.level_idc);
1051    LOG_V( "intra_period = %d\n", avcSeqParams.intra_period);
1052    LOG_V( "idr_interval = %d\n", avcSeqParams.intra_idr_period);
1053    LOG_V( "picture_width_in_mbs = %d\n", avcSeqParams.picture_width_in_mbs);
1054    LOG_V( "picture_height_in_mbs = %d\n", avcSeqParams.picture_height_in_mbs);
1055    LOG_V( "bitrate = %d\n", rcMiscParam->bits_per_second);
1056    LOG_V( "frame_rate = %d\n", framerateParam->framerate);
1057    LOG_V( "initial_qp = %d\n", rcMiscParam->initial_qp);
1058    LOG_V( "min_qp = %d\n", rcMiscParam->min_qp);
1059    LOG_V( "basic_unit_size = %d\n", rcMiscParam->basic_unit_size);
1060    LOG_V( "bDirect8x8Inference = %d\n",mVideoParamsAVC.bDirect8x8Inference);
1061
1062    // Not sure whether these settings work for all drivers
1063    avcSeqParams.seq_fields.bits.frame_mbs_only_flag = 1;
1064    avcSeqParams.seq_fields.bits.pic_order_cnt_type = 0;
1065    avcSeqParams.seq_fields.bits.direct_8x8_inference_flag = mVideoParamsAVC.bDirect8x8Inference;
1066
1067    avcSeqParams.seq_fields.bits.log2_max_frame_num_minus4 = 0;
1068    avcSeqParams.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
1069//    avcSeqParams.time_scale = 900;
1070//    avcSeqParams.num_units_in_tick = 15;			/* Tc = num_units_in_tick / time_sacle */
1071    // Not sure whether these settings work for all drivers
1072
1073    vaStatus = vaUnmapBuffer(mVADisplay, mRcParamBuf);
1074    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
1075    vaStatus = vaUnmapBuffer(mVADisplay, mFrameRateParamBuf);
1076    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
1077    vaStatus = vaCreateBuffer(
1078            mVADisplay, mVAContext,
1079            VAEncSequenceParameterBufferType,
1080            sizeof(avcSeqParams), 1, &avcSeqParams,
1081            &mSeqParamBuf);
1082    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
1083    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mFrameRateParamBuf, 1);
1084    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1085    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSeqParamBuf, 1);
1086    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1087    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mRcParamBuf, 1);
1088    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1089
1090    return ENCODE_SUCCESS;
1091}
1092
1093Encode_Status VideoEncoderAVC::renderPackedSequenceParams(EncodeTask *) {
1094
1095    VAStatus vaStatus = VA_STATUS_SUCCESS;
1096    VAEncSequenceParameterBufferH264 *avcSeqParams;
1097    VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
1098    unsigned char *packed_seq_buffer = NULL;
1099    unsigned int length_in_bits;
1100
1101    LOG_V("Begin\n");
1102
1103    vaStatus = vaMapBuffer(mVADisplay, mSeqParamBuf, (void **)&avcSeqParams);
1104    CHECK_VA_STATUS_RETURN("vaMapBuffer");
1105
1106    length_in_bits = build_packed_seq_buffer(&packed_seq_buffer, mComParams.profile, avcSeqParams);
1107    packed_header_param_buffer.type = VAEncPackedHeaderSequence;
1108    packed_header_param_buffer.bit_length = length_in_bits;
1109    packed_header_param_buffer.has_emulation_bytes = 0;
1110    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
1111            VAEncPackedHeaderParameterBufferType,
1112            sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
1113            &packed_seq_header_param_buf_id);
1114    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
1115
1116    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
1117            VAEncPackedHeaderDataBufferType,
1118            (length_in_bits + 7) / 8, 1, packed_seq_buffer,
1119            &packed_seq_buf_id);
1120    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
1121
1122    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_seq_header_param_buf_id, 1);
1123    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1124
1125    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_seq_buf_id, 1);
1126    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1127
1128    vaStatus = vaUnmapBuffer(mVADisplay, mSeqParamBuf);
1129    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
1130
1131    free(packed_seq_buffer);
1132
1133    LOG_V("End\n");
1134
1135    return vaStatus;
1136}
1137
1138Encode_Status VideoEncoderAVC::renderPictureParams(EncodeTask *task) {
1139
1140    VAStatus vaStatus = VA_STATUS_SUCCESS;
1141    VAEncPictureParameterBufferH264 avcPicParams = VAEncPictureParameterBufferH264();
1142    uint32_t RefFrmIdx;
1143
1144    LOG_V( "Begin\n\n");
1145    // set picture params for HW
1146    if (mAutoReference == false) {
1147        for (RefFrmIdx = 0; RefFrmIdx < 16; RefFrmIdx++) {
1148            avcPicParams.ReferenceFrames[RefFrmIdx].picture_id = VA_INVALID_ID;
1149            avcPicParams.ReferenceFrames[RefFrmIdx].flags = VA_PICTURE_H264_INVALID;
1150        }
1151        avcPicParams.ReferenceFrames[0].picture_id= task->ref_surface;
1152        avcPicParams.ReferenceFrames[0].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE;
1153        avcPicParams.CurrPic.picture_id= task->rec_surface;
1154        // Not sure whether these settings work for all drivers
1155        avcPicParams.CurrPic.TopFieldOrderCnt = mFrameNum * 2;
1156
1157        avcPicParams.pic_fields.bits.transform_8x8_mode_flag = 0;
1158        avcPicParams.seq_parameter_set_id = 0;
1159        avcPicParams.pic_parameter_set_id = 0;
1160
1161        avcPicParams.last_picture = 0;
1162        avcPicParams.frame_num = 0;
1163
1164        avcPicParams.pic_init_qp = 26;
1165        avcPicParams.num_ref_idx_l0_active_minus1 = 0;
1166        avcPicParams.num_ref_idx_l1_active_minus1 = 0;
1167
1168        avcPicParams.pic_fields.bits.idr_pic_flag = 0;
1169        avcPicParams.pic_fields.bits.reference_pic_flag = 0;
1170        avcPicParams.pic_fields.bits.entropy_coding_mode_flag = 0;
1171        avcPicParams.pic_fields.bits.weighted_pred_flag = 0;
1172        avcPicParams.pic_fields.bits.weighted_bipred_idc = 0;
1173        avcPicParams.pic_fields.bits.transform_8x8_mode_flag = 0;
1174        avcPicParams.pic_fields.bits.deblocking_filter_control_present_flag = 1;
1175
1176        avcPicParams.frame_num = mFrameNum;
1177        avcPicParams.pic_fields.bits.reference_pic_flag = 1;
1178        // Not sure whether these settings work for all drivers
1179    }else {
1180        avcPicParams.CurrPic.picture_id= VA_INVALID_SURFACE;
1181        for(uint32_t i =0; i< mAutoReferenceSurfaceNum; i++)
1182            avcPicParams.ReferenceFrames[i].picture_id = mAutoRefSurfaces[i];
1183    }
1184
1185    avcPicParams.pic_fields.bits.idr_pic_flag = (mFrameNum == 0);
1186    avcPicParams.pic_fields.bits.entropy_coding_mode_flag = mVideoParamsAVC.bEntropyCodingCABAC;
1187    avcPicParams.coded_buf = task->coded_buffer;
1188    avcPicParams.last_picture = 0;
1189
1190    LOG_V("======h264 picture params======\n");
1191    LOG_V( "reference_picture = 0x%08x\n", avcPicParams.ReferenceFrames[0].picture_id);
1192    LOG_V( "reconstructed_picture = 0x%08x\n", avcPicParams.CurrPic.picture_id);
1193    LOG_V( "coded_buf = 0x%08x\n", avcPicParams.coded_buf);
1194    //LOG_I( "picture_width = %d\n", avcPicParams.picture_width);
1195    //LOG_I( "picture_height = %d\n\n", avcPicParams.picture_height);
1196
1197    vaStatus = vaCreateBuffer(
1198            mVADisplay, mVAContext,
1199            VAEncPictureParameterBufferType,
1200            sizeof(avcPicParams),
1201            1,&avcPicParams,
1202            &mPicParamBuf);
1203    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
1204
1205    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mPicParamBuf, 1);
1206    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1207
1208    LOG_V( "end\n");
1209    return ENCODE_SUCCESS;
1210}
1211
1212Encode_Status VideoEncoderAVC::renderPackedPictureParams(EncodeTask *) {
1213
1214    VAStatus vaStatus = VA_STATUS_SUCCESS;
1215    VAEncPictureParameterBufferH264 *avcPicParams;
1216    VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
1217    unsigned char *packed_pic_buffer = NULL;
1218    unsigned int length_in_bits;
1219
1220    LOG_V("Begin\n");
1221
1222    vaStatus = vaMapBuffer(mVADisplay, mPicParamBuf, (void **)&avcPicParams);
1223    CHECK_VA_STATUS_RETURN("vaMapBuffer");
1224
1225    length_in_bits = build_packed_pic_buffer(&packed_pic_buffer, avcPicParams);
1226    packed_header_param_buffer.type = VAEncPackedHeaderPicture;
1227    packed_header_param_buffer.bit_length = length_in_bits;
1228    packed_header_param_buffer.has_emulation_bytes = 0;
1229    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
1230            VAEncPackedHeaderParameterBufferType,
1231            sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
1232            &packed_pic_header_param_buf_id);
1233    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
1234
1235    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
1236            VAEncPackedHeaderDataBufferType,
1237            (length_in_bits + 7) / 8, 1, packed_pic_buffer,
1238            &packed_pic_buf_id);
1239    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
1240
1241    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_pic_header_param_buf_id, 1);
1242    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1243
1244    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_pic_buf_id, 1);
1245    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1246
1247    vaStatus = vaUnmapBuffer(mVADisplay, mSeqParamBuf);
1248    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
1249
1250    free(packed_pic_buffer);
1251
1252    LOG_V("End\n");
1253
1254    return vaStatus;
1255}
1256
1257Encode_Status VideoEncoderAVC::renderSliceParams(EncodeTask *task) {
1258
1259    VAStatus vaStatus = VA_STATUS_SUCCESS;
1260
1261    uint32_t sliceNum = 0;
1262    uint32_t sliceIndex = 0;
1263    uint32_t sliceHeightInMB = 0;
1264    uint32_t maxSliceNum = 0;
1265    uint32_t minSliceNum = 0;
1266    uint32_t actualSliceHeightInMB = 0;
1267    uint32_t startRowInMB = 0;
1268    uint32_t modulus = 0;
1269    uint32_t RefFrmIdx;
1270
1271    LOG_V( "Begin\n\n");
1272
1273    maxSliceNum = (mComParams.resolution.height + 15) / 16;
1274    minSliceNum = 1;
1275
1276    if (task->type == FTYPE_I || task->type == FTYPE_IDR) {
1277        sliceNum = mVideoParamsAVC.sliceNum.iSliceNum;
1278    } else {
1279        sliceNum = mVideoParamsAVC.sliceNum.pSliceNum;
1280    }
1281
1282    if (sliceNum < minSliceNum) {
1283        LOG_W("Slice Number is too small");
1284        sliceNum = minSliceNum;
1285    }
1286
1287    if (sliceNum > maxSliceNum) {
1288        LOG_W("Slice Number is too big");
1289        sliceNum = maxSliceNum;
1290    }
1291
1292    mSliceNum= sliceNum;
1293    modulus = maxSliceNum % sliceNum;
1294    sliceHeightInMB = (maxSliceNum - modulus) / sliceNum ;
1295
1296    vaStatus = vaCreateBuffer(
1297            mVADisplay, mVAContext,
1298            VAEncSliceParameterBufferType,
1299            sizeof(VAEncSliceParameterBufferH264),
1300            sliceNum, NULL,
1301            &mSliceParamBuf);
1302    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
1303
1304    VAEncSliceParameterBufferH264 *sliceParams, *currentSlice;
1305
1306    vaStatus = vaMapBuffer(mVADisplay, mSliceParamBuf, (void **)&sliceParams);
1307    CHECK_VA_STATUS_RETURN("vaMapBuffer");
1308    if(!sliceParams)
1309        return ENCODE_NULL_PTR;
1310    memset(sliceParams, 0 , sizeof(VAEncSliceParameterBufferH264));
1311    if(!sliceParams)
1312        return ENCODE_NULL_PTR;
1313
1314    currentSlice = sliceParams;
1315    startRowInMB = 0;
1316    for (sliceIndex = 0; sliceIndex < sliceNum; sliceIndex++) {
1317        currentSlice = sliceParams + sliceIndex;
1318        actualSliceHeightInMB = sliceHeightInMB;
1319        if (sliceIndex < modulus) {
1320            actualSliceHeightInMB ++;
1321        }
1322
1323        // starting MB row number for this slice, suppose macroblock 16x16
1324        currentSlice->macroblock_address = startRowInMB * ((mComParams.resolution.width + 0xf) & ~0xf) / 16;
1325        // slice height measured in MB
1326        currentSlice->num_macroblocks = actualSliceHeightInMB * ((mComParams.resolution.width + 0xf) & ~0xf) / 16;
1327        if(task->type == FTYPE_I||task->type == FTYPE_IDR)
1328            currentSlice->slice_type = 2;
1329        else if(task->type == FTYPE_P)
1330            currentSlice->slice_type = 0;
1331        else if(task->type == FTYPE_B)
1332            currentSlice->slice_type = 1;
1333        currentSlice->disable_deblocking_filter_idc = mComParams.disableDeblocking;
1334
1335        // This is a temporary fix suggested by Binglin for bad encoding quality issue
1336        // TODO: We need a long term design for this field
1337        //currentSlice->slice_flags.bits.uses_long_term_ref = 0;
1338        //currentSlice->slice_flags.bits.is_long_term_ref = 0;
1339
1340        LOG_V("======AVC slice params======\n");
1341        LOG_V( "slice_index = %d\n", (int) sliceIndex);
1342        LOG_V( "macroblock_address = %d\n", (int) currentSlice->macroblock_address);
1343        LOG_V( "slice_height_in_mb = %d\n", (int) currentSlice->num_macroblocks);
1344        LOG_V( "slice.type = %d\n", (int) currentSlice->slice_type);
1345        LOG_V("disable_deblocking_filter_idc = %d\n\n", (int) currentSlice->disable_deblocking_filter_idc);
1346
1347        // Not sure whether these settings work for all drivers
1348        currentSlice->pic_parameter_set_id = 0;
1349        currentSlice->pic_order_cnt_lsb = mFrameNum * 2;
1350        currentSlice->direct_spatial_mv_pred_flag = 0;
1351        currentSlice->num_ref_idx_l0_active_minus1 = 0;      /* FIXME: ??? */
1352        currentSlice->num_ref_idx_l1_active_minus1 = 0;
1353        currentSlice->cabac_init_idc = 0;
1354        currentSlice->slice_qp_delta = 0;
1355        currentSlice->disable_deblocking_filter_idc = 0;
1356        currentSlice->slice_alpha_c0_offset_div2 = 2;
1357        currentSlice->slice_beta_offset_div2 = 2;
1358        currentSlice->idr_pic_id = 0;
1359        for (RefFrmIdx = 0; RefFrmIdx < 32; RefFrmIdx++) {
1360            currentSlice->RefPicList0[RefFrmIdx].picture_id = VA_INVALID_ID;
1361            currentSlice->RefPicList0[RefFrmIdx].flags = VA_PICTURE_H264_INVALID;
1362        }
1363        currentSlice->RefPicList0[0].picture_id = task->ref_surface;
1364        currentSlice->RefPicList0[0].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE;
1365        // Not sure whether these settings work for all drivers
1366
1367        startRowInMB += actualSliceHeightInMB;
1368    }
1369
1370    vaStatus = vaUnmapBuffer(mVADisplay, mSliceParamBuf);
1371    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
1372
1373    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSliceParamBuf, 1);
1374    CHECK_VA_STATUS_RETURN("vaRenderPicture");
1375    LOG_V( "end\n");
1376    return ENCODE_SUCCESS;
1377}
1378