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