| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * 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 "mp4def.h" |
| #include "mp4lib_int.h" |
| #include "mp4enc_lib.h" |
| #include "bitstream_io.h" |
| #include "m4venc_oscl.h" |
| |
| PV_STATUS EncodeShortHeader(BitstreamEncVideo *stream, Vop *currVop); |
| PV_STATUS EncodeVOPHeader(BitstreamEncVideo *stream, Vol *currVol, Vop *currVop); |
| PV_STATUS EncodeGOVHeader(BitstreamEncVideo *stream, UInt seconds); |
| |
| PV_STATUS EncodeVop_BXRC(VideoEncData *video); |
| PV_STATUS EncodeVop_NoME(VideoEncData *video); |
| |
| /* ======================================================================== */ |
| /* Function : DecodeVop() */ |
| /* Date : 08/23/2000 */ |
| /* Purpose : Encode VOP Header */ |
| /* In/out : */ |
| /* Return : */ |
| /* Modified : */ |
| /* ======================================================================== */ |
| PV_STATUS EncodeVop(VideoEncData *video) |
| { |
| |
| PV_STATUS status; |
| Int currLayer = video->currLayer; |
| Vol *currVol = video->vol[currLayer]; |
| Vop *currVop = video->currVop; |
| // BitstreamEncVideo *stream=video->bitstream1; |
| UChar *Mode = video->headerInfo.Mode; |
| rateControl **rc = video->rc; |
| // UInt time=0; |
| |
| /*******************/ |
| /* Initialize mode */ |
| /*******************/ |
| |
| switch (currVop->predictionType) |
| { |
| case I_VOP: |
| M4VENC_MEMSET(Mode, MODE_INTRA, sizeof(UChar)*currVol->nTotalMB); |
| break; |
| case P_VOP: |
| M4VENC_MEMSET(Mode, MODE_INTER, sizeof(UChar)*currVol->nTotalMB); |
| break; |
| case B_VOP: |
| /*M4VENC_MEMSET(Mode, MODE_INTER_B,sizeof(UChar)*nTotalMB);*/ |
| return PV_FAIL; |
| default: |
| return PV_FAIL; |
| } |
| |
| /*********************/ |
| /* Motion Estimation */ |
| /* compute MVs, scene change detection, edge padding, */ |
| /* intra refresh, compute block activity */ |
| /*********************/ |
| MotionEstimation(video); /* do ME for the whole frame */ |
| |
| /***************************/ |
| /* rate Control (assign QP) */ |
| /* 4/11/01, clean-up, and put into a separate function */ |
| /***************************/ |
| status = RC_VopQPSetting(video, rc); |
| if (status == PV_FAIL) |
| return PV_FAIL; |
| |
| /**********************/ |
| /* Encode VOP */ |
| /**********************/ |
| if (video->slice_coding) /* end here */ |
| { |
| /* initialize state variable for slice-based APIs */ |
| video->totalSAD = 0; |
| video->mbnum = 0; |
| video->sliceNo[0] = 0; |
| video->numIntra = 0; |
| video->offset = 0; |
| video->end_of_buf = 0; |
| video->hp_guess = -1; |
| return status; |
| } |
| |
| status = EncodeVop_NoME(video); |
| |
| /******************************/ |
| /* rate control (update stat) */ |
| /* 6/2/01 separate function */ |
| /******************************/ |
| |
| RC_VopUpdateStat(video, rc[currLayer]); |
| |
| return status; |
| } |
| |
| /* ======================================================================== */ |
| /* Function : EncodeVop_NoME() */ |
| /* Date : 08/28/2001 */ |
| /* History : */ |
| /* Purpose : EncodeVop without motion est. */ |
| /* In/out : */ |
| /* Return : */ |
| /* Modified : */ |
| /* */ |
| /* ======================================================================== */ |
| |
| PV_STATUS EncodeVop_NoME(VideoEncData *video) |
| { |
| Vop *currVop = video->currVop; |
| Vol *currVol = video->vol[video->currLayer]; |
| BitstreamEncVideo *stream = video->bitstream1; |
| Int time = 0; /* follows EncodeVop value */ |
| PV_STATUS status = PV_SUCCESS; |
| |
| if (currVol->shortVideoHeader) /* Short Video Header = 1 */ |
| { |
| |
| status = EncodeShortHeader(stream, currVop); /* Encode Short Header */ |
| |
| video->header_bits = BitstreamGetPos(stream); /* Header Bits */ |
| |
| status = EncodeFrameCombinedMode(video); |
| |
| } |
| #ifndef H263_ONLY |
| else /* Short Video Header = 0 */ |
| { |
| |
| if (currVol->GOVStart && currVop->predictionType == I_VOP) |
| status = EncodeGOVHeader(stream, time); /* Encode GOV Header */ |
| |
| status = EncodeVOPHeader(stream, currVol, currVop); /* Encode VOP Header */ |
| |
| video->header_bits = BitstreamGetPos(stream); /* Header Bits */ |
| |
| if (currVop->vopCoded) |
| { |
| if (!currVol->scalability) |
| { |
| if (currVol->dataPartitioning) |
| { |
| status = EncodeFrameDataPartMode(video); /* Encode Data Partitioning Mode VOP */ |
| } |
| else |
| { |
| status = EncodeFrameCombinedMode(video); /* Encode Combined Mode VOP */ |
| } |
| } |
| else |
| status = EncodeFrameCombinedMode(video); /* Encode Combined Mode VOP */ |
| } |
| else /* Vop Not coded */ |
| { |
| |
| return status; |
| } |
| } |
| #endif /* H263_ONLY */ |
| return status; |
| |
| } |
| |
| #ifndef NO_SLICE_ENCODE |
| /* ======================================================================== */ |
| /* Function : EncodeSlice() */ |
| /* Date : 04/19/2002 */ |
| /* History : */ |
| /* Purpose : Encode one slice. */ |
| /* In/out : */ |
| /* Return : */ |
| /* Modified : */ |
| /* */ |
| /* ======================================================================== */ |
| |
| PV_STATUS EncodeSlice(VideoEncData *video) |
| { |
| Vop *currVop = video->currVop; |
| Int currLayer = video->currLayer; |
| Vol *currVol = video->vol[currLayer]; |
| BitstreamEncVideo *stream = video->bitstream1; /* different from frame-based */ |
| Int time = 0; /* follows EncodeVop value */ |
| PV_STATUS status = PV_SUCCESS; |
| rateControl **rc = video->rc; |
| |
| if (currVol->shortVideoHeader) /* Short Video Header = 1 */ |
| { |
| |
| if (video->mbnum == 0) |
| { |
| status = EncodeShortHeader(stream, currVop); /* Encode Short Header */ |
| |
| video->header_bits = BitstreamGetPos(stream); /* Header Bits */ |
| } |
| |
| status = EncodeSliceCombinedMode(video); |
| |
| } |
| #ifndef H263_ONLY |
| else /* Short Video Header = 0 */ |
| { |
| |
| if (video->mbnum == 0) |
| { |
| if (currVol->GOVStart) |
| status = EncodeGOVHeader(stream, time); /* Encode GOV Header */ |
| |
| status = EncodeVOPHeader(stream, currVol, currVop); /* Encode VOP Header */ |
| |
| video->header_bits = BitstreamGetPos(stream); /* Header Bits */ |
| } |
| |
| if (currVop->vopCoded) |
| { |
| if (!currVol->scalability) |
| { |
| if (currVol->dataPartitioning) |
| { |
| status = EncodeSliceDataPartMode(video); /* Encode Data Partitioning Mode VOP */ |
| } |
| else |
| { |
| status = EncodeSliceCombinedMode(video); /* Encode Combined Mode VOP */ |
| } |
| } |
| else |
| status = EncodeSliceCombinedMode(video); /* Encode Combined Mode VOP */ |
| } |
| else /* Vop Not coded */ |
| { |
| |
| return status; |
| } |
| } |
| #endif /* H263_ONLY */ |
| if (video->mbnum >= currVol->nTotalMB && status != PV_END_OF_BUF) /* end of Vop */ |
| { |
| /******************************/ |
| /* rate control (update stat) */ |
| /* 6/2/01 separate function */ |
| /******************************/ |
| |
| status = RC_VopUpdateStat(video, rc[currLayer]); |
| } |
| |
| return status; |
| |
| } |
| #endif /* NO_SLICE_ENCODE */ |
| |
| #ifndef H263_ONLY |
| /* ======================================================================== */ |
| /* Function : EncodeGOVHeader() */ |
| /* Date : 08/23/2000 */ |
| /* Purpose : Encode GOV Header */ |
| /* In/out : */ |
| /* Return : */ |
| /* Modified : */ |
| /* ======================================================================== */ |
| PV_STATUS EncodeGOVHeader(BitstreamEncVideo *stream, UInt seconds) |
| { |
| PV_STATUS status; |
| // int temp; |
| UInt tmpvar; |
| |
| /********************************/ |
| /* Group_of_VideoObjectPlane() */ |
| /********************************/ |
| |
| status = BitstreamPutGT16Bits(stream, 32, GROUP_START_CODE); |
| /* time_code */ |
| tmpvar = seconds / 3600; |
| status = BitstreamPutBits(stream, 5, tmpvar); /* Hours*/ |
| |
| tmpvar = (seconds - tmpvar * 3600) / 60; |
| status = BitstreamPutBits(stream, 6, tmpvar); /* Minutes*/ |
| |
| status = BitstreamPut1Bits(stream, 1); /* Marker*/ |
| |
| tmpvar = seconds % 60; |
| status = BitstreamPutBits(stream, 6, tmpvar); /* Seconds*/ |
| |
| status = BitstreamPut1Bits(stream, 1); /* closed_gov */ |
| status = BitstreamPut1Bits(stream, 0); /* broken_link */ |
| /*temp =*/ |
| BitstreamMpeg4ByteAlignStuffing(stream); /* Byte align GOV Header */ |
| |
| return status; |
| } |
| |
| #ifdef ALLOW_VOP_NOT_CODED |
| |
| 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*/ |
| |
| 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; |
| } |
| #endif |
| |
| /* ======================================================================== */ |
| /* Function : EncodeVOPHeader() */ |
| /* Date : 08/23/2000 */ |
| /* Purpose : Encode VOP Header */ |
| /* In/out : */ |
| /* Return : */ |
| /* Modified : */ |
| /* ======================================================================== */ |
| |
| PV_STATUS EncodeVOPHeader(BitstreamEncVideo *stream, Vol *currVol, Vop *currVop) |
| { |
| PV_STATUS status; |
| //int temp; |
| |
| int MTB = currVol->moduloTimeBase; |
| /************************/ |
| /* VideoObjectPlane() */ |
| /************************/ |
| |
| status = BitstreamPutGT16Bits(stream, 32, VOP_START_CODE); /*Start Code for VOP*/ |
| status = BitstreamPutBits(stream, 2, currVop->predictionType);/* VOP Coding Type*/ |
| |
| currVol->prevModuloTimeBase = currVol->moduloTimeBase; |
| |
| while (MTB) |
| { |
| status = BitstreamPut1Bits(stream, 1); |
| MTB--; |
| } |
| status = BitstreamPut1Bits(stream, 0); |
| |
| status = BitstreamPut1Bits(stream, 1); /* marker bit */ |
| status = BitstreamPutBits(stream, currVol->nbitsTimeIncRes, currVop->timeInc); /* vop_time_increment */ |
| status = BitstreamPut1Bits(stream, 1); /* marker bit */ |
| status = BitstreamPut1Bits(stream, currVop->vopCoded); /* vop_coded bit */ |
| if (currVop->vopCoded == 0) |
| { |
| /*temp =*/ |
| BitstreamMpeg4ByteAlignStuffing(stream); /* Byte align VOP Header */ |
| return status; |
| } |
| if (currVop->predictionType == P_VOP) |
| status = BitstreamPut1Bits(stream, currVop->roundingType); /* vop_rounding_type */ |
| |
| status = BitstreamPutBits(stream, 3, currVop->intraDCVlcThr); /* intra_dc_vlc_thr */ |
| status = BitstreamPutBits(stream, 5, currVop->quantizer); /* vop_quant */ |
| |
| if (currVop->predictionType != I_VOP) |
| status = BitstreamPutBits(stream, 3, currVop->fcodeForward); /* vop_fcode_forward */ |
| if (currVop->predictionType == B_VOP) |
| status = BitstreamPutBits(stream, 3, currVop->fcodeBackward);/* vop_fcode_backward */ |
| |
| if (currVol->scalability) |
| /* enhancement_type = 0 */ |
| status = BitstreamPutBits(stream, 2, currVop->refSelectCode); /* ref_select_code */ |
| |
| return status; |
| } |
| #endif /* H263_ONLY */ |
| /* ======================================================================== */ |
| /* Function : EncodeShortHeader() */ |
| /* Date : 08/23/2000 */ |
| /* Purpose : Encode VOP Header */ |
| /* In/out : */ |
| /* Return : */ |
| /* Modified : */ |
| /* ======================================================================== */ |
| |
| PV_STATUS EncodeShortHeader(BitstreamEncVideo *stream, Vop *currVop) |
| { |
| |
| PV_STATUS status; |
| |
| status = BitstreamPutGT16Bits(stream, 22, SHORT_VIDEO_START_MARKER); /* Short_video_start_marker */ |
| status = BitstreamPutBits(stream, 8, currVop->temporalRef); /* temporal_reference */ |
| status = BitstreamPut1Bits(stream, 1); /* marker bit */ |
| status = BitstreamPut1Bits(stream, 0); /* zero bit */ |
| status = BitstreamPut1Bits(stream, 0); /* split_screen_indicator=0*/ |
| status = BitstreamPut1Bits(stream, 0); /* document_camera_indicator=0*/ |
| status = BitstreamPut1Bits(stream, 0); /* full_picture_freeze_release=0*/ |
| |
| switch (currVop->width) |
| { |
| case 128: |
| if (currVop->height == 96) |
| status = BitstreamPutBits(stream, 3, 1); /* source_format = 1 */ |
| else |
| { |
| status = PV_FAIL; |
| return status; |
| } |
| break; |
| |
| case 176: |
| if (currVop->height == 144) |
| status = BitstreamPutBits(stream, 3, 2); /* source_format = 2 */ |
| else |
| { |
| status = PV_FAIL; |
| return status; |
| } |
| break; |
| |
| case 352: |
| if (currVop->height == 288) |
| status = BitstreamPutBits(stream, 3, 3); /* source_format = 3 */ |
| else |
| { |
| status = PV_FAIL; |
| return status; |
| } |
| break; |
| |
| case 704: |
| if (currVop->height == 576) |
| status = BitstreamPutBits(stream, 3, 4); /* source_format = 4 */ |
| else |
| { |
| status = PV_FAIL; |
| return status; |
| } |
| break; |
| |
| case 1408: |
| if (currVop->height == 1152) |
| status = BitstreamPutBits(stream, 3, 5); /* source_format = 5 */ |
| else |
| { |
| status = PV_FAIL; |
| return status; |
| } |
| break; |
| |
| default: |
| status = PV_FAIL; |
| return status; |
| } |
| |
| |
| status = BitstreamPut1Bits(stream, currVop->predictionType); /* picture_coding type */ |
| status = BitstreamPutBits(stream, 4, 0); /* four_reserved_zero_bits */ |
| status = BitstreamPutBits(stream, 5, currVop->quantizer); /* vop_quant*/ |
| status = BitstreamPut1Bits(stream, 0); /* zero_bit*/ |
| status = BitstreamPut1Bits(stream, 0); /* pei=0 */ |
| |
| return status; |
| } |
| |
| #ifndef H263_ONLY |
| /* ======================================================================== */ |
| /* Function : EncodeVideoPacketHeader() */ |
| /* Date : 09/05/2000 */ |
| /* History : */ |
| /* Purpose : Encode a frame of MPEG4 bitstream in Combined mode. */ |
| /* In/out : */ |
| /* Return : */ |
| /* Modified : 04/25/2002 */ |
| /* Add bitstream structure as input argument */ |
| /* */ |
| /* ======================================================================== */ |
| 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; |
| } |
| |
| #endif /* H263_ONLY */ |
| |
| |
| |