Home | History | Annotate | Download | only in src
      1 /* ------------------------------------------------------------------
      2  * Copyright (C) 1998-2009 PacketVideo
      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
     13  * express or implied.
     14  * See the License for the specific language governing permissions
     15  * and limitations under the License.
     16  * -------------------------------------------------------------------
     17  */
     18 #ifndef H263_ONLY
     19 
     20 #include "mp4def.h"
     21 #include "mp4lib_int.h"
     22 #include "bitstream_io.h"
     23 #include "mp4enc_lib.h"
     24 #include "m4venc_oscl.h"
     25 
     26 /* ======================================================================== */
     27 /*  Function : EncodeFrameDataPartMode()                                    */
     28 /*  Date     : 09/6/2000                                                    */
     29 /*  History  :                                                              */
     30 /*  Purpose  : Encode a frame of MPEG4 bitstream in datapartitioning mode.  */
     31 /*  In/out   :                                                              */
     32 /*  Return   :  PV_SUCCESS if successful else PV_FAIL                       */
     33 /*  Modified :                                                              */
     34 /*                                                                          */
     35 /* ======================================================================== */
     36 PV_STATUS EncodeFrameDataPartMode(VideoEncData *video)
     37 {
     38     PV_STATUS status = PV_SUCCESS;
     39     Vol *currVol = video->vol[video->currLayer];
     40     Vop *currVop = video->currVop;
     41     VideoEncParams *encParams = video->encParams;
     42     Int width = currVop->width; /* has to be Vop, for multiple of 16 */
     43     Int lx = currVop->pitch; /*  with padding */
     44     Int offset = 0;
     45     Int ind_x, ind_y;
     46     Int start_packet_header = 0;
     47     UChar *QPMB = video->QPMB;
     48     Int QP;
     49     Int mbnum = 0, slice_counter = 0;
     50     Int num_bits, packet_size = encParams->ResyncPacketsize;
     51     BitstreamEncVideo *bs1 = video->bitstream1;
     52     BitstreamEncVideo *bs2 = video->bitstream2;
     53     BitstreamEncVideo *bs3 = video->bitstream3;
     54     Int numHeaderBits;
     55     approxDCT fastDCTfunction;
     56     Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB,  5/18/2001 */
     57     PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]);
     58     void (*MBVlcEncode)(VideoEncData*, Int[], void *);
     59     void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar);
     60 
     61     video->QP_prev = currVop->quantizer;
     62 
     63     numHeaderBits = BitstreamGetPos(bs1); /* Number of bits in VOP Header */
     64 
     65     /* determine type of quantization   */
     66 #ifndef NO_MPEG_QUANT
     67     if (currVol->quantType == 0)
     68         CodeMB = &CodeMB_H263;
     69     else
     70         CodeMB = &CodeMB_MPEG;
     71 #else
     72     CodeMB = &CodeMB_H263;
     73 #endif
     74 
     75     /* determine which functions to be used, in MB-level */
     76     if (currVop->predictionType == P_VOP)
     77         MBVlcEncode = &MBVlcEncodeDataPar_P_VOP;
     78     else if (currVop->predictionType == I_VOP)
     79         MBVlcEncode = &MBVlcEncodeDataPar_I_VOP;
     80     else /* B_VOP not implemented yet */
     81         return PV_FAIL;
     82 
     83     /* determine which VLC table to be used */
     84     if (currVol->shortVideoHeader)
     85         BlockCodeCoeff = &BlockCodeCoeff_ShortHeader;
     86 #ifndef NO_RVLC
     87     else if (currVol->useReverseVLC)
     88         BlockCodeCoeff = &BlockCodeCoeff_RVLC;
     89 #endif
     90     else
     91         BlockCodeCoeff = &BlockCodeCoeff_Normal;
     92 
     93     video->usePrevQP = 0;
     94 
     95     for (ind_y = 0; ind_y < currVol->nMBPerCol; ind_y++)    /* Col MB Loop */
     96     {
     97 
     98         video->outputMB->mb_y = ind_y; /*  5/28/01 */
     99 
    100         for (ind_x = 0; ind_x < currVol->nMBPerRow; ind_x++)  /* Row MB Loop */
    101         {
    102             video->outputMB->mb_x = ind_x; /*  5/28/01 */
    103             video->mbnum = mbnum;
    104             video->sliceNo[mbnum] = slice_counter;      /* Update MB slice number */
    105             QP = QPMB[mbnum];   /* always read new QP */
    106 
    107             /****************************************************************************************/
    108             /* MB Prediction:Put into MC macroblock, substract from currVop, put in predMB */
    109             /****************************************************************************************/
    110 
    111             getMotionCompensatedMB(video, ind_x, ind_y, offset);
    112 
    113             if (start_packet_header)
    114             {
    115                 slice_counter++;                        /* Increment slice counter */
    116                 video->sliceNo[mbnum] = slice_counter;  /* Update MB slice number*/
    117                 video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */
    118                 video->QP_prev = currVop->quantizer;                        /* store QP */
    119                 status = EncodeVideoPacketHeader(video, mbnum, video->QP_prev, 0);
    120                 video->header_bits += BitstreamGetPos(bs1); /* Header Bits */
    121                 numHeaderBits = BitstreamGetPos(bs1);
    122                 start_packet_header = 0;
    123                 video->usePrevQP = 0;
    124             }
    125 
    126             /***********************************************/
    127             /* Code_MB:  DCT, Q, Q^(-1), IDCT, Motion Comp */
    128             /***********************************************/
    129 
    130             status = (*CodeMB)(video, &fastDCTfunction, (offset << 5) + QP, ncoefblck);
    131 
    132             /************************************/
    133             /* MB VLC Encode: VLC Encode MB     */
    134             /************************************/
    135 
    136             MBVlcEncode(video, ncoefblck, (void*)BlockCodeCoeff);
    137 
    138             /*************************************************************/
    139             /* Assemble Packets:  Assemble the MB VLC codes into Packets */
    140             /*************************************************************/
    141 
    142             /* INCLUDE VOP HEADER IN COUNT */
    143 
    144             num_bits = BitstreamGetPos(bs1) + BitstreamGetPos(bs2) +
    145                        BitstreamGetPos(bs3) - numHeaderBits;
    146 
    147             /* Assemble_Packet(video) */
    148 
    149             if (num_bits > packet_size)
    150             {
    151                 if (video->currVop->predictionType == I_VOP)
    152                     BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
    153                 else
    154                     BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /*Add motion_marker*/
    155                 BitstreamAppendEnc(bs1, bs2);   /* Combine bs1 and bs2 */
    156                 BitstreamAppendEnc(bs1, bs3);   /* Combine bs1 and bs3 */
    157                 video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
    158 
    159                 status = BitstreamAppendPacket(currVol->stream, bs1); /* Put Packet to Buffer */
    160                 /* continue even if status == PV_END_OF_BUF, to get the stats */
    161 
    162                 BitstreamEncReset(bs1); /* Initialize to 0 */
    163                 BitstreamEncReset(bs2);
    164                 BitstreamEncReset(bs3);
    165                 start_packet_header = 1;
    166             }
    167             mbnum++;
    168             offset += 16;
    169         } /* End of For ind_x */
    170 
    171         offset += (lx << 4) - width;
    172     } /* End of For ind_y */
    173 
    174     if (!start_packet_header)
    175     {
    176         if (video->currVop->predictionType == I_VOP)
    177         {
    178             BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
    179             video->header_bits += 19;
    180         }
    181         else
    182         {
    183             BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /* Add motion_marker */
    184             video->header_bits += 17;
    185         }
    186         BitstreamAppendEnc(bs1, bs2);
    187         BitstreamAppendEnc(bs1, bs3);
    188         video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
    189         status = BitstreamAppendPacket(currVol->stream, bs1); /* Put Packet to Buffer */
    190         /* continue even if status == PV_END_OF_BUF, to get the stats */
    191         BitstreamEncReset(bs1); /* Initialize to 0 */
    192         BitstreamEncReset(bs2);
    193         BitstreamEncReset(bs3);
    194     }
    195 
    196     return status; /* if status == PV_END_OF_BUF, this frame will be pre-skipped */
    197 }
    198 
    199 #ifndef  NO_SLICE_ENCODE
    200 /* ======================================================================== */
    201 /*  Function : EncodeSliceDataPartMode()                                    */
    202 /*  Date     : 04/19/2002                                                   */
    203 /*  History  :                                                              */
    204 /*  Purpose  : Encode a slice of MPEG4 bitstream in DataPar mode and save   */
    205 /*              the current MB to continue next time it is called.          */
    206 /*  In/out   :                                                              */
    207 /*  Return   :  PV_SUCCESS if successful else PV_FAIL                       */
    208 /*  Modified :                                                              */
    209 /*                                                                          */
    210 /* ======================================================================== */
    211 PV_STATUS EncodeSliceDataPartMode(VideoEncData *video)
    212 {
    213     PV_STATUS status = PV_SUCCESS;
    214     Vol *currVol = video->vol[video->currLayer];
    215     Vop *currVop = video->currVop;
    216     UChar mode, *Mode = video->headerInfo.Mode;
    217     VideoEncParams *encParams = video->encParams;
    218     Int nTotalMB = currVol->nTotalMB;
    219     Int width = currVop->width; /* has to be Vop, for multiple of 16 */
    220     Int lx = currVop->pitch; /* , with pading */
    221     UChar *QPMB = video->QPMB;
    222     Int QP;
    223     Int ind_x = video->outputMB->mb_x, ind_y = video->outputMB->mb_y;
    224     Int offset = video->offset;                 /* get current MB location */
    225     Int mbnum = video->mbnum, slice_counter = video->sliceNo[mbnum]; /* get current MB location */
    226     Int firstMB = mbnum;
    227     Int start_packet_header = (mbnum != 0);
    228     Int num_bits = 0;
    229     Int packet_size = encParams->ResyncPacketsize - 1 - (currVop->predictionType == I_VOP ? 19 : 17);
    230     BitstreamEncVideo *bs1 = video->bitstream1;
    231     BitstreamEncVideo *bs2 = video->bitstream2;
    232     BitstreamEncVideo *bs3 = video->bitstream3;
    233     Int bitCount1 = 0, bitCount2 = 0, bitCount3 = 0, byteCount1 = 0, byteCount2 = 0, byteCount3 = 0;
    234     Int numHeaderBits = 0;
    235     approxDCT fastDCTfunction;
    236     Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB,  5/18/2001 */
    237     UChar CBP;
    238     Short outputMB[6][64];
    239     PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]);
    240     void (*MBVlcEncode)(VideoEncData*, Int[], void *);
    241     void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar);
    242     Int k;
    243 
    244     video->QP_prev = 31;
    245 
    246     if (video->end_of_buf) /* left-over from previous run */
    247     {
    248         status = BitstreamAppendPacketNoOffset(currVol->stream, bs1);
    249         if (status != PV_END_OF_BUF)
    250         {
    251             BitstreamEncReset(bs1);
    252             video->end_of_buf = 0;
    253         }
    254         return status;
    255     }
    256 
    257     if (mbnum == 0) /* only do this at the start of a frame */
    258     {
    259         QPMB[0] = video->QP_prev = QP = currVop->quantizer;
    260         video->usePrevQP = 0;
    261 
    262         numHeaderBits = BitstreamGetPos(bs1); /* Number of bits in VOP Header */
    263 
    264     }
    265 
    266 
    267     /* Re-assign fast functions on every slice, don't have to put it in the memory */
    268     QP = QPMB[mbnum];
    269     if (mbnum > 0)   video->QP_prev = QPMB[mbnum-1];
    270 
    271     /* determine type of quantization   */
    272 #ifndef NO_MPEG_QUANT
    273     if (currVol->quantType == 0)
    274         CodeMB = &CodeMB_H263;
    275     else
    276         CodeMB = &CodeMB_MPEG;
    277 #else
    278     CodeMB = &CodeMB_H263;
    279 #endif
    280 
    281     /* determine which functions to be used, in MB-level */
    282     if (currVop->predictionType == P_VOP)
    283         MBVlcEncode = &MBVlcEncodeDataPar_P_VOP;
    284     else if (currVop->predictionType == I_VOP)
    285         MBVlcEncode = &MBVlcEncodeDataPar_I_VOP;
    286     else /* B_VOP not implemented yet */
    287         return PV_FAIL;
    288 
    289     /* determine which VLC table to be used */
    290 #ifndef NO_RVLC
    291     if (currVol->useReverseVLC)
    292         BlockCodeCoeff = &BlockCodeCoeff_RVLC;
    293     else
    294 #endif
    295         BlockCodeCoeff = &BlockCodeCoeff_Normal;
    296 
    297     if (mbnum != 0)
    298     {
    299         goto JUMP_IN;
    300     }
    301 
    302     for (ind_y = 0; ind_y < currVol->nMBPerCol; ind_y++)    /* Col MB Loop */
    303     {
    304 
    305         video->outputMB->mb_y = ind_y; /*  5/28/01 */
    306 
    307         for (ind_x = 0; ind_x < currVol->nMBPerRow; ind_x++)  /* Row MB Loop */
    308         {
    309 
    310             video->outputMB->mb_x = ind_x; /*  5/28/01 */
    311             video->mbnum = mbnum;
    312             video->sliceNo[mbnum] = slice_counter;      /* Update MB slice number */
    313 
    314             /****************************************************************************************/
    315             /* MB Prediction:Put into MC macroblock, substract from currVop, put in predMB */
    316             /****************************************************************************************/
    317             getMotionCompensatedMB(video, ind_x, ind_y, offset);
    318 
    319 JUMP_IN:
    320 
    321             QP = QPMB[mbnum];   /* always read new QP */
    322 
    323             if (start_packet_header)
    324             {
    325                 slice_counter++;                        /* Increment slice counter */
    326                 video->sliceNo[mbnum] = slice_counter;  /* Update MB slice number*/
    327                 video->QP_prev = currVop->quantizer;                        /* store QP */
    328                 num_bits = BitstreamGetPos(bs1);
    329                 status = EncodeVideoPacketHeader(video, mbnum, video->QP_prev, 0);
    330                 numHeaderBits = BitstreamGetPos(bs1) - num_bits;
    331                 video->header_bits += numHeaderBits; /* Header Bits */
    332                 start_packet_header = 0;
    333                 video->usePrevQP = 0;
    334             }
    335             else  /* don't encode the first MB in packet again */
    336             {
    337                 /***********************************************/
    338                 /* Code_MB:  DCT, Q, Q^(-1), IDCT, Motion Comp */
    339                 /***********************************************/
    340 
    341                 status = (*CodeMB)(video, &fastDCTfunction, (offset << 5) + QP, ncoefblck);
    342                 for (k = 0; k < 6; k++)
    343                 {
    344                     M4VENC_MEMCPY(outputMB[k], video->outputMB->block[k], sizeof(Short) << 6);
    345                 }
    346             }
    347 
    348             /************************************/
    349             /* MB VLC Encode: VLC Encode MB     */
    350             /************************************/
    351 
    352             /* save the state before VLC encoding */
    353             bitCount1 = BitstreamGetPos(bs1);
    354             bitCount2 = BitstreamGetPos(bs2);
    355             bitCount3 = BitstreamGetPos(bs3);
    356             byteCount1 = bitCount1 >> 3;
    357             byteCount2 = bitCount2 >> 3;
    358             byteCount3 = bitCount3 >> 3;
    359             bitCount1 &= 0x7;
    360             bitCount2 &= 0x7;
    361             bitCount3 &= 0x7;
    362             mode = Mode[mbnum];
    363             CBP = video->headerInfo.CBP[mbnum];
    364 
    365             /*************************************/
    366 
    367             MBVlcEncode(video, ncoefblck, (void*)BlockCodeCoeff);
    368 
    369             /*************************************************************/
    370             /* Assemble Packets:  Assemble the MB VLC codes into Packets */
    371             /*************************************************************/
    372 
    373             num_bits = BitstreamGetPos(bs1) + BitstreamGetPos(bs2) +
    374                        BitstreamGetPos(bs3);// - numHeaderBits; //include header bits
    375 
    376             /* Assemble_Packet(video) */
    377             if (num_bits > packet_size && mbnum != firstMB)  /* encoding at least one more MB*/
    378             {
    379 
    380                 BitstreamRepos(bs1, byteCount1, bitCount1); /* rewind one MB */
    381                 BitstreamRepos(bs2, byteCount2, bitCount2); /* rewind one MB */
    382                 BitstreamRepos(bs3, byteCount3, bitCount3); /* rewind one MB */
    383 
    384                 if (video->currVop->predictionType == I_VOP)
    385                 {
    386                     BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
    387                     video->header_bits += 19;
    388                 }
    389                 else
    390                 {
    391                     BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /*Add motion_marker*/
    392                     video->header_bits += 17;
    393                 }
    394 
    395                 status = BitstreamAppendEnc(bs1, bs2);  /* Combine with bs2 */
    396                 status = BitstreamAppendEnc(bs1, bs3);  /* Combine with bs3 */
    397 
    398                 video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
    399                 status = BitstreamAppendPacketNoOffset(currVol->stream, bs1);
    400 
    401                 BitstreamEncReset(bs2);
    402                 BitstreamEncReset(bs3);
    403 
    404                 if (status == PV_END_OF_BUF) /* if cannot fit a buffer */
    405                 {
    406                     video->end_of_buf = 1;
    407                 }
    408                 else
    409                 {
    410                     BitstreamEncReset(bs1);
    411                 }
    412 
    413                 start_packet_header = 1;
    414 
    415                 if (mbnum < nTotalMB || video->end_of_buf) /* return here */
    416                 {
    417                     video->mbnum = mbnum;
    418                     video->sliceNo[mbnum] = slice_counter;
    419                     video->offset = offset;
    420                     Mode[mbnum] = mode;
    421                     video->headerInfo.CBP[mbnum] = CBP;
    422 
    423                     for (k = 0; k < 6; k++)
    424                     {
    425                         M4VENC_MEMCPY(video->outputMB->block[k], outputMB[k], sizeof(Short) << 6);
    426                     }
    427 
    428                     return status;
    429                 }
    430             }
    431 
    432             offset += 16;
    433             mbnum++; /* has to increment before SCD, to preserve Mode[mbnum] */
    434         } /* End of For ind_x */
    435 
    436         offset += (lx << 4) - width;
    437 
    438     } /* End of For ind_y */
    439 
    440     if (!start_packet_header)
    441     {
    442         if (video->currVop->predictionType == I_VOP)
    443         {
    444             BitstreamPutGT16Bits(bs1, 19, DC_MARKER);   /* Add dc_marker */
    445             video->header_bits += 19;
    446         }
    447         else
    448         {
    449             BitstreamPutGT16Bits(bs1, 17, MOTION_MARKER_COMB); /*Add motion_marker*/
    450             video->header_bits += 17;
    451         }
    452 
    453         status = BitstreamAppendEnc(bs1, bs2);  /* Combine with bs2 */
    454         status = BitstreamAppendEnc(bs1, bs3);  /* Combine with bs3 */
    455 
    456         video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */
    457         status = BitstreamAppendPacketNoOffset(currVol->stream, bs1);
    458 
    459         BitstreamEncReset(bs2);
    460         BitstreamEncReset(bs3);
    461 
    462         if (status == PV_END_OF_BUF)
    463         {
    464             video->end_of_buf = 1;
    465         }
    466         else
    467         {
    468             BitstreamEncReset(bs1);
    469         }
    470     }
    471 
    472     video->mbnum = mbnum;
    473     if (mbnum < nTotalMB)
    474         video->sliceNo[mbnum] = slice_counter;
    475     video->offset = offset;
    476 
    477     return status;
    478 }
    479 #endif /* NO_SLICE_ENCODE */
    480 #endif /* H263_ONLY */
    481 
    482 
    483