blob: 47076c33dc257e20bb79d8caa251b4b3a0cc8b5b [file] [log] [blame]
/* ------------------------------------------------------------------
* 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 */