PV_STATUS EncodeVopNotCoded(VideoEncData *video, UChar *bstream, Int *size, ULong modTime) { PV_STATUS status; Vol *currVol = video->vol[0]; Vop *currVop = video->currVop; BitstreamEncVideo *stream = currVol->stream; UInt frameTick; Int timeInc; stream->bitstreamBuffer = bstream; stream->bufferSize = *size; BitstreamEncReset(stream); status = BitstreamPutGT16Bits(stream, 32, VOP_START_CODE); /*Start Code for VOP*/ status = BitstreamPutBits(stream, 2, P_VOP);/* VOP Coding Type*/ modTime += video->wrapModTime; /* wrapModTime is non zero after wrap-around */ frameTick = (Int)(((double)(modTime - video->modTimeRef) * currVol->timeIncrementResolution + 500) / 1000); timeInc = frameTick - video->refTick[0]; while (timeInc >= currVol->timeIncrementResolution) { timeInc -= currVol->timeIncrementResolution; status = BitstreamPut1Bits(stream, 1); /* do not update refTick and modTimeRef yet, do it after encoding!! */ } status = BitstreamPut1Bits(stream, 0); status = BitstreamPut1Bits(stream, 1); /* marker bit */ status = BitstreamPutBits(stream, currVol->nbitsTimeIncRes, timeInc); /* vop_time_increment */ status = BitstreamPut1Bits(stream, 1); /* marker bit */ status = BitstreamPut1Bits(stream, 0); /* vop_coded bit */ BitstreamMpeg4ByteAlignStuffing(stream); return status; }
/* ======================================================================== */ PV_STATUS EncodeFrameCombinedMode(VideoEncData *video) { PV_STATUS status = PV_SUCCESS; Vol *currVol = video->vol[video->currLayer]; Vop *currVop = video->currVop; VideoEncParams *encParams = video->encParams; Int width = currVop->width; /* has to be Vop, for multiple of 16 */ Int lx = currVop->pitch; /* with padding */ Int offset = 0; Int ind_x, ind_y; Int start_packet_header = 0; UChar *QPMB = video->QPMB; Int QP; Int mbnum = 0, slice_counter = 0, curr_slice_counter = 0; Int num_bits, packet_size = encParams->ResyncPacketsize; Int GOB_Header_Interval = encParams->GOB_Header_Interval; BitstreamEncVideo *bs1 = video->bitstream1; Int numHeaderBits; approxDCT fastDCTfunction; Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB, 5/18/2001 */ PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]); void (*MBVlcEncode)(VideoEncData*, Int[], void *); void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar); /* for H263 GOB changes */ //MP4RateControlType rc_type = encParams->RC_Type; video->QP_prev = currVop->quantizer; numHeaderBits = BitstreamGetPos(bs1); /* determine type of quantization */ #ifndef NO_MPEG_QUANT if (currVol->quantType == 0) CodeMB = &CodeMB_H263; else CodeMB = &CodeMB_MPEG; #else CodeMB = &CodeMB_H263; #endif /* determine which functions to be used, in MB-level */ if (currVop->predictionType == P_VOP) MBVlcEncode = &MBVlcEncodeCombined_P_VOP; else if (currVop->predictionType == I_VOP) MBVlcEncode = &MBVlcEncodeCombined_I_VOP; else /* B_VOP not implemented yet */ return PV_FAIL; /* determine which VLC table to be used */ #ifndef H263_ONLY if (currVol->shortVideoHeader) BlockCodeCoeff = &BlockCodeCoeff_ShortHeader; #ifndef NO_RVLC else if (currVol->useReverseVLC) BlockCodeCoeff = &BlockCodeCoeff_RVLC; #endif else BlockCodeCoeff = &BlockCodeCoeff_Normal; #else BlockCodeCoeff = &BlockCodeCoeff_ShortHeader; #endif /* gob_frame_id is the same for different vop types - the reason should be SCD */ if (currVol->shortVideoHeader && currVop->gobFrameID != currVop->predictionType) currVop->gobFrameID = currVop->predictionType; video->usePrevQP = 0; for (ind_y = 0; ind_y < currVol->nMBPerCol; ind_y++) /* Col MB Loop */ { video->outputMB->mb_y = ind_y; /* 5/28/01 */ if (currVol->shortVideoHeader) /* ShortVideoHeader Mode */ { if (slice_counter && GOB_Header_Interval && (ind_y % GOB_Header_Interval == 0)) /* Encode GOB Header */ { QP = QPMB[mbnum]; /* Get quant_scale */ video->header_bits -= BitstreamGetPos(currVol->stream); /* Header Bits */ status = EncodeGOBHeader(video, slice_counter, QP, 0); //ind_y /* Encode GOB Header */ video->header_bits += BitstreamGetPos(currVol->stream); /* Header Bits */ curr_slice_counter = slice_counter; } } for (ind_x = 0; ind_x < currVol->nMBPerRow; ind_x++) /* Row MB Loop */ { video->outputMB->mb_x = ind_x; /* 5/28/01 */ video->mbnum = mbnum; QP = QPMB[mbnum]; /* always read new QP */ if (GOB_Header_Interval) video->sliceNo[mbnum] = curr_slice_counter; /* Update MB slice number */ else video->sliceNo[mbnum] = slice_counter; /****************************************************************************************/ /* MB Prediction:Put into MC macroblock, substract from currVop, put in predMB */ /****************************************************************************************/ getMotionCompensatedMB(video, ind_x, ind_y, offset); #ifndef H263_ONLY if (start_packet_header) { slice_counter++; /* Increment slice counter */ video->sliceNo[mbnum] = slice_counter; /* Update MB slice number*/ video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */ video->QP_prev = currVop->quantizer; status = EncodeVideoPacketHeader(video, mbnum, video->QP_prev, 0); video->header_bits += BitstreamGetPos(bs1); /* Header Bits */ numHeaderBits = BitstreamGetPos(bs1); start_packet_header = 0; video->usePrevQP = 0; } #endif /***********************************************/ /* Code_MB: DCT, Q, Q^(-1), IDCT, Motion Comp */ /***********************************************/ status = (*CodeMB)(video, &fastDCTfunction, (offset << 5) + QP, ncoefblck); /************************************/ /* MB VLC Encode: VLC Encode MB */ /************************************/ (*MBVlcEncode)(video, ncoefblck, (void*)BlockCodeCoeff); /*************************************************************/ /* Assemble Packets: Assemble the MB VLC codes into Packets */ /*************************************************************/ /* Assemble_Packet(video) */ #ifndef H263_ONLY if (!currVol->shortVideoHeader) /* Not in ShortVideoHeader mode */ { if (!currVol->ResyncMarkerDisable) /* RESYNC MARKER MODE */ { num_bits = BitstreamGetPos(bs1) - numHeaderBits; if (num_bits > packet_size) { video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1); /* Byte align Packet */ status = BitstreamAppendPacket(currVol->stream, bs1); /* Put Packet to Buffer */ /* continue even if status == PV_END_OF_BUF, to get the stats */ BitstreamEncReset(bs1); start_packet_header = 1; } } else /* NO RESYNC MARKER MODE */ { status = BitstreamAppendEnc(currVol->stream, bs1); /* Initialize to 0 */ /* continue even if status == PV_END_OF_BUF, to get the stats */ BitstreamEncReset(bs1); } } else #endif /* H263_ONLY */ { /* ShortVideoHeader Mode */ status = BitstreamAppendEnc(currVol->stream, bs1); /* Initialize to 0 */ /* continue even if status == PV_END_OF_BUF, to get the stats */ BitstreamEncReset(bs1); } mbnum++; offset += 16; } /* End of For ind_x */ offset += (lx << 4) - width; if (currVol->shortVideoHeader) /* ShortVideoHeader = 1 */ { if (GOB_Header_Interval) slice_counter++; } } /* End of For ind_y */ if (currVol->shortVideoHeader) /* ShortVideoHeader = 1 */ { video->header_bits += BitstreamShortHeaderByteAlignStuffing(currVol->stream); /* Byte Align */ } #ifndef H263_ONLY else /* Combined Mode*/ { if (!currVol->ResyncMarkerDisable) /* Resync Markers */ { if (!start_packet_header) { video->header_bits += BitstreamMpeg4ByteAlignStuffing(bs1);/* Byte Align */ status = BitstreamAppendPacket(currVol->stream, bs1); /* Put Packet to Buffer */ /* continue even if status == PV_END_OF_BUF, to get the stats */ BitstreamEncReset(bs1); } } else /* No Resync Markers */ { video->header_bits += BitstreamMpeg4ByteAlignStuffing(currVol->stream); /* Byte Align */ } } #endif /* H263_ONLY */ return status; /* if status == PV_END_OF_BUF, this frame will be pre-skipped */ }
/* ======================================================================== */ PV_STATUS EncodeSliceCombinedMode(VideoEncData *video) { PV_STATUS status = PV_SUCCESS; Vol *currVol = video->vol[video->currLayer]; Vop *currVop = video->currVop; UChar mode = MODE_INTRA; UChar *Mode = video->headerInfo.Mode; VideoEncParams *encParams = video->encParams; Int nTotalMB = currVol->nTotalMB; Int width = currVop->width; /* has to be Vop, for multiple of 16 */ Int lx = currVop->pitch; /* , with padding */ // rateControl *rc = encParams->rc[video->currLayer]; UChar *QPMB = video->QPMB; Int QP; Int ind_x = video->outputMB->mb_x, ind_y = video->outputMB->mb_y; Int offset = video->offset; /* get current MB location */ Int mbnum = video->mbnum, slice_counter = video->sliceNo[mbnum]; /* get current MB location */ Int firstMB = mbnum; Int start_packet_header = 0; Int num_bits = 0; Int packet_size = encParams->ResyncPacketsize - 1; Int resync_marker = ((!currVol->shortVideoHeader) && (!currVol->ResyncMarkerDisable)); BitstreamEncVideo *bs1 = video->bitstream1; Int byteCount = 0, byteCount1 = 0, bitCount = 0; Int numHeaderBits = 0; approxDCT fastDCTfunction; Int ncoefblck[6] = {64, 64, 64, 64, 64, 64}; /* for FastCodeMB, 5/18/2001 */ UChar CBP = 0; Short outputMB[6][64]; Int k; PV_STATUS(*CodeMB)(VideoEncData *, approxDCT *, Int, Int[]); void (*MBVlcEncode)(VideoEncData*, Int[], void *); void (*BlockCodeCoeff)(RunLevelBlock*, BitstreamEncVideo*, Int, Int, UChar); video->QP_prev = 31; #define H263_GOB_CHANGES if (video->end_of_buf) /* left-over from previous run */ { status = BitstreamAppendPacketNoOffset(currVol->stream, bs1); if (status != PV_END_OF_BUF) { BitstreamEncReset(bs1); video->end_of_buf = 0; } return status; } if (mbnum == 0) /* only do this at the start of a frame */ { QPMB[0] = video->QP_prev = QP = currVop->quantizer; video->usePrevQP = 0; numHeaderBits = BitstreamGetPos(bs1); } /* Re-assign fast functions on every slice, don't have to put it in the memory */ QP = QPMB[mbnum]; if (mbnum > 0) video->QP_prev = QPMB[mbnum-1]; /* determine type of quantization */ #ifndef NO_MPEG_QUANT if (currVol->quantType == 0) CodeMB = &CodeMB_H263; else CodeMB = &CodeMB_MPEG; #else CodeMB = &CodeMB_H263; #endif /* determine which functions to be used, in MB-level */ if (currVop->predictionType == P_VOP) MBVlcEncode = &MBVlcEncodeCombined_P_VOP; else if (currVop->predictionType == I_VOP) MBVlcEncode = &MBVlcEncodeCombined_I_VOP; else /* B_VOP not implemented yet */ return PV_FAIL; /* determine which VLC table to be used */ #ifndef H263_ONLY if (currVol->shortVideoHeader) BlockCodeCoeff = &BlockCodeCoeff_ShortHeader; #ifndef NO_RVLC else if (currVol->useReverseVLC) BlockCodeCoeff = &BlockCodeCoeff_RVLC; #endif else BlockCodeCoeff = &BlockCodeCoeff_Normal; #else BlockCodeCoeff = &BlockCodeCoeff_ShortHeader; #endif /* (gob_frame_id is the same for different vop types) The reason should be SCD */ if (currVol->shortVideoHeader && currVop->gobFrameID != currVop->predictionType) currVop->gobFrameID = currVop->predictionType; if (mbnum != 0) { if (currVol->shortVideoHeader) { /* Encode GOB Header */ bitCount = BitstreamGetPos(bs1); byteCount1 = byteCount = bitCount >> 3; /* save the position before GOB header */ bitCount = bitCount & 0x7; #ifdef H263_GOB_CHANGES video->header_bits -= BitstreamGetPos(bs1); /* Header Bits */ status = EncodeGOBHeader(video, slice_counter, QP, 1); //ind_y /* Encode GOB Header */ video->header_bits += BitstreamGetPos(bs1); /* Header Bits */ #endif goto JUMP_IN_SH; } else if (currVol->ResyncMarkerDisable)
/* ======================================================================== */ PV_STATUS EncodeVideoPacketHeader(VideoEncData *video, int MB_number, int quant_scale, Int insert) { // PV_STATUS status=PV_SUCCESS; int fcode; Vop *currVop = video->currVop; Vol *currVol = video->vol[video->currLayer]; BitstreamEncVideo *bs, tmp; UChar buffer[30]; if (insert) /* insert packet header to the beginning of bs1 */ { tmp.bitstreamBuffer = buffer; /* use temporary buffer */ tmp.bufferSize = 30; BitstreamEncReset(&tmp); bs = &tmp; } else bs = video->bitstream1; if (currVop->predictionType == I_VOP) BitstreamPutGT16Bits(bs, 17, 1); /* resync_marker I_VOP */ else if (currVop->predictionType == P_VOP) { fcode = currVop->fcodeForward; BitstreamPutGT16Bits(bs, 16 + fcode, 1); /* resync_marker P_VOP */ } else { fcode = currVop->fcodeForward; if (currVop->fcodeBackward > fcode) fcode = currVop->fcodeBackward; BitstreamPutGT16Bits(bs, 16 + fcode, 1); /* resync_marker B_VOP */ } BitstreamPutBits(bs, currVol->nBitsForMBID, MB_number); /* resync_marker */ BitstreamPutBits(bs, 5, quant_scale); /* quant_scale */ BitstreamPut1Bits(bs, 0); /* header_extension_code = 0 */ if (0) /* header_extension_code = 1 */ { /* NEED modulo_time_base code here ... default 0x01 belo*/ /*status =*/ BitstreamPut1Bits(bs, 1); /*status = */ BitstreamPut1Bits(bs, 0); /*status = */ BitstreamPut1Bits(bs, 1); /* marker bit */ /*status = */ BitstreamPutBits(bs, currVol->nbitsTimeIncRes, currVop->timeInc); /* vop_time_increment */ /*status = */ BitstreamPut1Bits(bs, 1); /* marker bit */ /*status = */ BitstreamPutBits(bs, 2, currVop->predictionType);/* VOP Coding Type*/ /*status = */ BitstreamPutBits(bs, 3, currVop->intraDCVlcThr); /* intra_dc_vlc_thr */ if (currVop->predictionType != I_VOP) /*status = */ BitstreamPutBits(bs, 3, currVop->fcodeForward); if (currVop->predictionType == B_VOP) /*status = */ BitstreamPutBits(bs, 3, currVop->fcodeBackward); } #ifndef NO_SLICE_ENCODE if (insert) BitstreamPrependPacket(video->bitstream1, bs); #endif return PV_SUCCESS; }