├── .gitignore ├── AnnexBReader.cpp ├── AnnexBReader.h ├── Array.hpp ├── BitStream.cpp ├── BitStream.h ├── Cabac.cpp ├── Cabac.h ├── CalvcTable.h ├── Common.cpp ├── Common.h ├── DPB.cpp ├── DPB.h ├── FileReader.cpp ├── FileReader.h ├── Macroblock.cpp ├── Macroblock.h ├── NaluType.h ├── ParseNalu.cpp ├── ParseNalu.h ├── ParsePPS.cpp ├── ParsePPS.h ├── ParseSEI.cpp ├── ParseSEI.h ├── ParseSPS.cpp ├── ParseSPS.h ├── ParseSlice.cpp ├── ParseSlice.h ├── Picture.cpp ├── Picture.h ├── README.md ├── ResidualBlockCavlc.cpp ├── ResidualBlockCavlc.h ├── SliceData.cpp ├── SliceData.h ├── SliceHeader.cpp ├── SliceHeader.h ├── data ├── baseline.264 ├── bnalu.bin └── test.264 ├── h264.sln ├── h264.vcxproj ├── h264.vcxproj.filters ├── h264.vcxproj.user ├── main.cpp └── xf /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Debug/ 3 | .vs/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vs 11 | .vscode 12 | *.suo 13 | *.ntvs* 14 | *.njsproj 15 | *.vs 16 | *.yuv 17 | *.h264 18 | *.bmp 19 | demo.h264.1615788140067.yuv -------------------------------------------------------------------------------- /AnnexBReader.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/AnnexBReader.cpp -------------------------------------------------------------------------------- /AnnexBReader.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/AnnexBReader.h -------------------------------------------------------------------------------- /Array.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/Array.hpp -------------------------------------------------------------------------------- /BitStream.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/BitStream.cpp -------------------------------------------------------------------------------- /BitStream.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/BitStream.h -------------------------------------------------------------------------------- /Cabac.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/Cabac.h -------------------------------------------------------------------------------- /CalvcTable.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/CalvcTable.h -------------------------------------------------------------------------------- /Common.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/Common.cpp -------------------------------------------------------------------------------- /Common.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/Common.h -------------------------------------------------------------------------------- /DPB.cpp: -------------------------------------------------------------------------------- 1 | #include "DPB.h" 2 | #include "ParseSlice.h" 3 | 4 | 5 | //短期参考和长期参考,因为DPB容量不可能无限存储下去,所以要标记某些帧为长期还是短期,长期除非遇到特定指令才会移除,短期当容量满的时候移除,或者特定指令 6 | DPB::DPB() :dpb(16), RefPicList0(16), RefPicList1(16) 7 | { 8 | previous = nullptr; 9 | } 10 | 11 | DPB::~DPB() 12 | { 13 | if (previous) 14 | { 15 | delete previous; 16 | previous = nullptr; 17 | } 18 | 19 | dpb.clear(); 20 | RefPicList0.deletePointer(0); 21 | RefPicList0.deletePointer(0); 22 | } 23 | 24 | void DPB::Decoding_process_for_picture_numbers(const SliceHeader& sHeader) 25 | { 26 | 27 | for (size_t i = 0; i < dpb.length; i++) 28 | { 29 | //对每一个短期参考图像 30 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 31 | { 32 | //FrameNum 设置成相应短期参考图像的片头中解码所得得语法元素frame_num 33 | if (dpb[i]->FrameNum > sHeader.frame_num) 34 | { 35 | dpb[i]->FrameNumWrap = dpb[i]->FrameNum - dpb[i]->MaxFrameNum; 36 | } 37 | else 38 | { 39 | dpb[i]->FrameNumWrap = dpb[i]->FrameNum; 40 | } 41 | } 42 | 43 | //LongTermFrameIdx 长期参考图像已经在图像解码完成的时候指定 44 | } 45 | 46 | 47 | //field_pic_flag==0 参考帧或互补参考场对 48 | for (size_t i = 0; i < dpb.length; i++) 49 | { 50 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 51 | { 52 | //解码器使用图像序号 PicNum 标记一个短期参考图像 53 | dpb[i]->PicNum = dpb[i]->FrameNumWrap; 54 | } 55 | 56 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 57 | { 58 | //使用长期图像序号 LongTermPicNum 标记一个长期参考图像 59 | dpb[i]->LongTermPicNum = dpb[i]->LongTermFrameIdx; 60 | } 61 | } 62 | 63 | } 64 | 65 | //参考帧列表初始化 66 | void DPB::Initialisation_process_for_reference_picture_lists(const ParseSlice* slice) 67 | { 68 | SliceHeader& sHeader = slice->sHeader; 69 | SLIECETYPE slice_type = (SLIECETYPE)sHeader.slice_type; 70 | 71 | 72 | if (slice_type == SLIECETYPE::H264_SLIECE_TYPE_P || slice_type == SLIECETYPE::H264_SLIECE_TYPE_SP) 73 | { 74 | Initialisation_process_for_the_reference_picture_list_for_P_and_SP_slices_in_frames(); 75 | } 76 | else if (slice_type == SLIECETYPE::H264_SLIECE_TYPE_B) 77 | { 78 | Initialisation_process_for_reference_picture_lists_for_B_slices_in_frames(slice->PicOrderCnt); 79 | } 80 | 81 | 82 | //num_ref_idx_l0_active_minus1是前向参考的最大参考索引 83 | if (RefPicList0.length > sHeader.num_ref_idx_l0_active_minus1 + 1) 84 | { 85 | RefPicList0.deletePointer(sHeader.num_ref_idx_l0_active_minus1 + 1); 86 | } 87 | 88 | if (RefPicList1.length > sHeader.num_ref_idx_l1_active_minus1 + 1) 89 | { 90 | RefPicList1.deletePointer(sHeader.num_ref_idx_l1_active_minus1 + 1); 91 | } 92 | } 93 | 94 | void DPB::Initialisation_process_for_the_reference_picture_list_for_P_and_SP_slices_in_frames() 95 | { 96 | size_t shortTermlength = 0; 97 | Picture* shortTerm[16] = { 0 }; 98 | 99 | size_t longTermLength = 0; 100 | Picture* longTerm[16] = { 0 }; 101 | 102 | //把所有的短期参考帧放前面,长期参考放后面 103 | for (size_t i = 0; i < dpb.length; i++) 104 | { 105 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 106 | { 107 | shortTerm[shortTermlength] = dpb[i]; 108 | shortTermlength++; 109 | } 110 | else if (dpb[i]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 111 | { 112 | longTerm[longTermLength] = dpb[i]; 113 | longTermLength++; 114 | } 115 | else //不用做参考的 116 | { 117 | 118 | } 119 | } 120 | 121 | 122 | if (shortTermlength > 0) 123 | { 124 | for (size_t i = 0; i < shortTermlength - 1; i++) 125 | { 126 | for (size_t j = 0; j < shortTermlength - i - 1; j++) 127 | { 128 | if (shortTerm[j]->PicNum < shortTerm[j + 1]->PicNum)//降序排列 129 | { 130 | Picture* temp = shortTerm[j]; 131 | shortTerm[j] = shortTerm[j + 1]; 132 | shortTerm[j + 1] = temp; 133 | } 134 | } 135 | } 136 | } 137 | 138 | if (longTermLength > 0) 139 | { 140 | for (size_t i = 0; i < longTermLength - 1; i++) 141 | { 142 | for (size_t j = 0; j < longTermLength - i - 1; j++) 143 | { 144 | if (longTerm[j]->LongTermPicNum > longTerm[j + 1]->LongTermPicNum)//升序排列 145 | { 146 | Picture* temp = longTerm[j]; 147 | longTerm[j] = longTerm[j + 1]; 148 | longTerm[j + 1] = temp; 149 | } 150 | } 151 | } 152 | } 153 | 154 | for (size_t i = 0; i < shortTermlength; i++) 155 | { 156 | RefPicList0.push(shortTerm[i]); 157 | } 158 | 159 | for (size_t i = 0; i < longTermLength; i++) 160 | { 161 | RefPicList0.push(longTerm[i]); 162 | } 163 | 164 | } 165 | 166 | void DPB::Initialisation_process_for_reference_picture_lists_for_B_slices_in_frames(int POC) 167 | { 168 | size_t shortTermLeftLength = 0; 169 | Picture* shortTermLeft[16] = { 0 }; 170 | size_t shortTermRightLength = 0; 171 | Picture* shortTermRight[16] = { 0 }; 172 | 173 | 174 | size_t longTermLength = 0; 175 | Picture* longTerm[16] = { 0 }; 176 | 177 | //把所有的短期参考帧放前面,长期参考放后面 178 | for (size_t i = 0; i < dpb.length; i++) 179 | { 180 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 181 | { 182 | if (dpb[i]->PicOrderCnt < POC) 183 | { 184 | shortTermLeft[shortTermLeftLength] = dpb[i]; 185 | shortTermLeftLength++; 186 | } 187 | else //if (dpb[i]->PicOrderCnt >= POC) 188 | { 189 | shortTermRight[shortTermRightLength] = dpb[i]; 190 | shortTermRightLength++; 191 | } 192 | } 193 | else if (dpb[i]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 194 | { 195 | longTerm[longTermLength] = dpb[i]; 196 | longTermLength++; 197 | } 198 | else 199 | { 200 | //不用做参考 201 | } 202 | } 203 | 204 | if (shortTermLeftLength > 0) 205 | { 206 | for (size_t i = 0; i < shortTermLeftLength - 1; i++) 207 | { 208 | for (size_t j = 0; j < shortTermLeftLength - i - 1; j++) 209 | { 210 | if (shortTermLeft[j]->PicOrderCnt < shortTermLeft[j + 1]->PicOrderCnt)//降序排列 211 | { 212 | Picture* temp = shortTermLeft[j]; 213 | shortTermLeft[j] = shortTermLeft[j + 1]; 214 | shortTermLeft[j + 1] = temp; 215 | } 216 | } 217 | } 218 | } 219 | 220 | if (shortTermRightLength > 0) 221 | { 222 | for (size_t i = 0; i < shortTermRightLength - 1; i++) 223 | { 224 | for (size_t j = 0; j < shortTermRightLength - i - 1; j++) 225 | { 226 | if (shortTermRight[j]->PicOrderCnt > shortTermRight[j + 1]->PicOrderCnt)//升序排列 227 | { 228 | Picture* temp = shortTermRight[j]; 229 | shortTermRight[j] = shortTermRight[j + 1]; 230 | shortTermRight[j + 1] = temp; 231 | } 232 | } 233 | } 234 | } 235 | 236 | if (longTermLength > 0) 237 | { 238 | for (size_t i = 0; i < longTermLength - 1; i++) 239 | { 240 | for (size_t j = 0; j < longTermLength - i - 1; j++) 241 | { 242 | if (longTerm[j]->LongTermPicNum > longTerm[j + 1]->LongTermPicNum)//升序排列 243 | { 244 | Picture* temp = longTerm[j]; 245 | longTerm[j] = longTerm[j + 1]; 246 | longTerm[j + 1] = temp; 247 | } 248 | } 249 | } 250 | } 251 | 252 | 253 | for (size_t i = 0; i < shortTermLeftLength; i++) 254 | { 255 | RefPicList0.push(shortTermLeft[i]); 256 | } 257 | 258 | for (size_t i = 0; i < shortTermRightLength; i++) 259 | { 260 | RefPicList0.push(shortTermRight[i]); 261 | } 262 | 263 | for (size_t i = 0; i < longTermLength; i++) 264 | { 265 | RefPicList0.push(longTerm[i]); 266 | } 267 | 268 | 269 | shortTermLeftLength = 0; 270 | memset(shortTermLeft, NULL, sizeof(Picture*) * 16); 271 | shortTermRightLength = 0; 272 | memset(shortTermRight, NULL, sizeof(Picture*) * 16); 273 | 274 | longTermLength = 0; 275 | memset(longTerm, NULL, sizeof(Picture*) * 16); 276 | 277 | 278 | for (size_t i = 0; i < dpb.length; i++) 279 | { 280 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 281 | { 282 | if (dpb[i]->PicOrderCnt > POC) 283 | { 284 | shortTermLeft[shortTermLeftLength] = dpb[i]; 285 | shortTermLeftLength++; 286 | } 287 | else //if (dpb[i]->PicOrderCnt <= POC) 288 | { 289 | shortTermRight[shortTermRightLength] = dpb[i]; 290 | shortTermRightLength++; 291 | } 292 | } 293 | else if (dpb[i]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 294 | { 295 | longTerm[longTermLength] = dpb[i]; 296 | longTermLength++; 297 | } 298 | else 299 | { 300 | //不用做参考 301 | } 302 | } 303 | 304 | 305 | if (shortTermLeftLength > 0) 306 | { 307 | for (size_t i = 0; i < shortTermLeftLength - 1; i++) 308 | { 309 | for (size_t j = 0; j < shortTermLeftLength - i - 1; j++) 310 | { 311 | if (shortTermLeft[j]->PicOrderCnt > shortTermLeft[j + 1]->PicOrderCnt)//升序排列 312 | { 313 | Picture* temp = shortTermLeft[j]; 314 | shortTermLeft[j] = shortTermLeft[j + 1]; 315 | shortTermLeft[j + 1] = temp; 316 | } 317 | } 318 | } 319 | } 320 | 321 | 322 | if (shortTermRightLength > 0) 323 | { 324 | for (size_t i = 0; i < shortTermRightLength - 1; i++) 325 | { 326 | for (size_t j = 0; j < shortTermRightLength - i - 1; j++) 327 | { 328 | if (shortTermRight[j]->PicOrderCnt < shortTermRight[j + 1]->PicOrderCnt)//降序排列 329 | { 330 | Picture* temp = shortTermRight[j]; 331 | shortTermRight[j] = shortTermRight[j + 1]; 332 | shortTermRight[j + 1] = temp; 333 | } 334 | } 335 | } 336 | } 337 | 338 | 339 | if (longTermLength > 0) 340 | { 341 | for (size_t i = 0; i < longTermLength - 1; i++) 342 | { 343 | for (size_t j = 0; j < longTermLength - i - 1; j++) 344 | { 345 | if (longTerm[j]->LongTermPicNum > longTerm[j + 1]->LongTermPicNum)//升序排列 346 | { 347 | Picture* temp = longTerm[j]; 348 | longTerm[j] = longTerm[j + 1]; 349 | longTerm[j + 1] = temp; 350 | } 351 | } 352 | } 353 | } 354 | 355 | 356 | for (size_t i = 0; i < shortTermLeftLength; i++) 357 | { 358 | RefPicList1.push(shortTermLeft[i]); 359 | } 360 | 361 | for (size_t i = 0; i < shortTermRightLength; i++) 362 | { 363 | RefPicList1.push(shortTermRight[i]); 364 | } 365 | 366 | for (size_t i = 0; i < longTermLength; i++) 367 | { 368 | RefPicList1.push(longTerm[i]); 369 | } 370 | 371 | 372 | bool flag = false; 373 | 374 | if (RefPicList1.length > 1 && RefPicList1.length == RefPicList0.length) 375 | { 376 | const size_t length = RefPicList1.length; 377 | 378 | for (size_t i = 0; i < length; i++) 379 | { 380 | if (RefPicList1[i] == RefPicList0[i]) 381 | { 382 | flag = true; 383 | } 384 | else 385 | { 386 | flag = false; 387 | break; 388 | } 389 | } 390 | } 391 | 392 | 393 | if (flag) 394 | { 395 | Picture* tmp = RefPicList1[0]; 396 | RefPicList1[0] = RefPicList1[1]; 397 | RefPicList1[1] = tmp; 398 | } 399 | } 400 | 401 | 402 | void DPB::Modification_process_for_reference_picture_lists(const SliceHeader& sHeader) 403 | { 404 | if (sHeader.ref_pic_list_modification_flag_l0) 405 | { 406 | int refIdxL0 = 0; 407 | int picNumL0Pred = sHeader.CurrPicNum; 408 | //读取对应的modification_of_pic_nums_idc 409 | for (size_t i = 0; i < sHeader.ref_pic_list_modification_count_l0; i++) 410 | { 411 | if (sHeader.modification_of_pic_nums_idc[0][i] == 0 || sHeader.modification_of_pic_nums_idc[0][i] == 1) 412 | { 413 | //短期参考帧的重排序 414 | Modification_process_of_reference_picture_lists_for_short_term_reference_pictures(refIdxL0, picNumL0Pred, 415 | sHeader.abs_diff_pic_num_minus1[0][i], sHeader.modification_of_pic_nums_idc[0][i], sHeader.num_ref_idx_l0_active_minus1, RefPicList0, sHeader); 416 | } 417 | else if (sHeader.modification_of_pic_nums_idc[0][i] == 2) 418 | { 419 | ////长期参考帧的重排序 420 | Modification_process_of_reference_picture_lists_for_long_term_reference_pictures(refIdxL0, picNumL0Pred, 421 | sHeader.long_term_pic_num[0][i], sHeader.num_ref_idx_l0_active_minus1, RefPicList0, sHeader); 422 | } 423 | else // ==3 424 | { 425 | break; 426 | } 427 | } 428 | } 429 | } 430 | 431 | void DPB::Modification_process_of_reference_picture_lists_for_short_term_reference_pictures(int& refIdxLX, int& picNumLXPred, 432 | uint16_t abs_diff_pic_num_minus1, uint16_t modification_of_pic_nums_idc, uint8_t num_ref_idx_lX_active_minus1, Array& RefPicListX, const SliceHeader& sHeader) 433 | { 434 | int picNumLXNoWrap = 0; 435 | // picNumLXPred 是变量 picNumLXNoWrap 的预测值 436 | 437 | 438 | if (modification_of_pic_nums_idc == 0) 439 | { 440 | //预测值小于实际值 441 | if (picNumLXPred - (abs_diff_pic_num_minus1 + 1) < 0) 442 | { 443 | picNumLXNoWrap = picNumLXPred - (abs_diff_pic_num_minus1 + 1) + sHeader.MaxPicNum; 444 | } 445 | else 446 | { 447 | picNumLXNoWrap = picNumLXPred - (abs_diff_pic_num_minus1 + 1); 448 | } 449 | } 450 | else//modification_of_pic_nums_idc == 1 451 | { 452 | //预测值与实际值之和 大于MaxPicNum 453 | if (picNumLXPred + (abs_diff_pic_num_minus1 + 1) >= sHeader.MaxPicNum) 454 | { 455 | picNumLXNoWrap = picNumLXPred + (abs_diff_pic_num_minus1 + 1) - sHeader.MaxPicNum; 456 | } 457 | else 458 | { 459 | picNumLXNoWrap = picNumLXPred + (abs_diff_pic_num_minus1 + 1); 460 | } 461 | } 462 | //picNumLXPred是变量picNumLXNoWrap的预测值。 463 | //当第一次为一个片调用此子句中指定的进程时(即,当在ref_pic_list_modify()语法中第一次出现modification_of_pic_nums_idc等于0或1时), 464 | //picNumL0Pred和picNumL1Pred最初被设置为等于CurrPicNum。 每次赋值picNumLXNoWrap后,picNumLXNoWrap的值被赋给picNumLXPred。 465 | picNumLXPred = picNumLXNoWrap; 466 | 467 | //picNumLX应等于标记为“用于短期参考”的参考图片的PicNum 468 | int picNumLX = 0; 469 | if (picNumLXNoWrap > sHeader.CurrPicNum) 470 | { 471 | picNumLX = picNumLXNoWrap - sHeader.MaxPicNum; 472 | } 473 | else 474 | { 475 | picNumLX = picNumLXNoWrap; 476 | } 477 | 478 | //num_ref_idx_lX_active_minus1最大参考序号,加1是最大参考数目,不是实际参考数目 479 | //将具有短期图片号picNumLX的图片放置到索引位置refIdxLX,将列表中任何其他剩余图片的位置移动到稍后,并增加refIdxLX的值。 480 | 481 | const size_t length = (num_ref_idx_lX_active_minus1 + 1) < RefPicListX.length ? (num_ref_idx_lX_active_minus1 + 1) : RefPicListX.length; 482 | for (size_t cIdx = length; cIdx > refIdxLX; cIdx--) 483 | { 484 | RefPicListX[cIdx] = RefPicListX[cIdx - 1]; 485 | } 486 | 487 | size_t idx = 0; 488 | for (; idx < length; idx++) 489 | { 490 | if (RefPicListX[idx]->PicNum == picNumLX && RefPicListX[idx]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 491 | { 492 | break; 493 | } 494 | } 495 | RefPicListX[refIdxLX++] = RefPicListX[idx]; 496 | int nIdx = refIdxLX; 497 | for (size_t cIdx = refIdxLX; cIdx < length; cIdx++) 498 | { 499 | 500 | int PicNumF = (RefPicListX[cIdx]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 501 | ? RefPicListX[cIdx]->PicNum : sHeader.MaxPicNum; 502 | if (PicNumF != picNumLX) //if ( PicNumF( RefPicListX[ cIdx ] ) != picNumLX ) 503 | { 504 | RefPicListX[nIdx++] = RefPicListX[cIdx]; 505 | } 506 | 507 | } 508 | 509 | RefPicListX.deletePointer(num_ref_idx_lX_active_minus1 + 1); 510 | } 511 | 512 | void DPB::Modification_process_of_reference_picture_lists_for_long_term_reference_pictures(int& refIdxLX, int& picNumL0Pred, uint16_t long_term_pic_num, 513 | uint8_t num_ref_idx_lX_active_minus1, Array& RefPicListX, const SliceHeader& sHeader) 514 | { 515 | 516 | const size_t length = (num_ref_idx_lX_active_minus1 + 1) < RefPicListX.length ? (num_ref_idx_lX_active_minus1 + 1) : RefPicListX.length; 517 | for (size_t cIdx = length; cIdx > refIdxLX; cIdx--) 518 | { 519 | RefPicListX[cIdx] = RefPicListX[cIdx - 1]; 520 | } 521 | 522 | size_t idx = 0; 523 | for (; idx < length; idx++) 524 | { 525 | if (RefPicListX[idx]->LongTermPicNum == long_term_pic_num) 526 | { 527 | break; 528 | } 529 | } 530 | RefPicListX[refIdxLX++] = RefPicListX[idx]; 531 | 532 | int nIdx = refIdxLX; 533 | 534 | for (size_t cIdx = refIdxLX; cIdx < length; cIdx++) 535 | { 536 | int LongTermPicNumF = (RefPicListX[cIdx]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 537 | ? RefPicListX[cIdx]->LongTermPicNum : 0;//(2 * (MaxLongTermFrameIdx + 1)); 538 | 539 | 540 | if (LongTermPicNumF != long_term_pic_num) 541 | { 542 | RefPicListX[nIdx++] = RefPicListX[cIdx]; 543 | } 544 | } 545 | 546 | RefPicListX.deletePointer(num_ref_idx_lX_active_minus1 + 1); 547 | } 548 | 549 | void DPB::Decoding_process_for_reference_picture_lists_construction(ParseSlice* slice) 550 | { 551 | const SliceHeader& sHeader = slice->sHeader; 552 | RefPicList0.deletePointer(0); 553 | RefPicList1.deletePointer(0); 554 | //图像序号的计算 555 | Decoding_process_for_picture_numbers(sHeader); 556 | 557 | //参考图像是通过 8.4.2.1 节中定义的参考索引来定位的 558 | //参考图像列表的初始化过程 559 | Initialisation_process_for_reference_picture_lists(slice); 560 | 561 | 562 | //参考帧列表重排序 563 | 564 | //由于在解码每个(P/B)MB时,都要用到参考帧的索引ref_idx_l0 或 ref_idx_l1。 565 | //假如有个参考帧(短期参考帧或者长期参考帧)对于解码一个图像特别有用,但是这个参考帧在缺省的队列中并不位于索引值为0的位置,所以编码数值较大的索引值需要花费更多比特。 566 | //参考帧的重排序可以使这个参考帧位于索引值比较小的位置,以节省编码比特数。 567 | 568 | //重排序过程可以这么理解:与该解码slice关联较大的几个参考帧不在短期、长期参考帧队列序号靠前位置, 569 | //或者新增参考帧时,根据g得到想要放在队列前的参考帧frameNum,然后把该参考帧放在队列头,同时队列中的后续参考帧逐一后移。 570 | //参考资料 https://blog.csdn.net/qq_42139383/article/details/109489999 571 | Modification_process_for_reference_picture_lists(sHeader); 572 | 573 | 574 | //修改过的参考图像列表 RefPicList0 中条目总数目为 num_ref_idx_l0_active_minus1 + 1, 575 | //对 B 条带来说,修改 过的参考图像列表RefPicList1 中条目总数目为num_ref_idx_l1_active_minus1 + 1。 576 | } 577 | 578 | void DPB::Decoded_reference_picture_marking_process(Picture* pic, const SliceHeader& sHeader) 579 | { 580 | 581 | if (sHeader.nalu.IdrPicFlag) 582 | { 583 | //所有参考图像需要被标记为"不用于参考" 584 | dpb.clear(); 585 | RefPicList0.deletePointer(0); 586 | RefPicList1.deletePointer(0); 587 | /*for (size_t i = 0; i < dpb.length; i++) 588 | { 589 | dpb[i]->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 590 | }*/ 591 | 592 | if (sHeader.long_term_reference_flag) 593 | { 594 | //该IDR图像需要 被标记为"用于长期参考" 595 | pic->reference_marked_type = PICTURE_MARKING::LONG_TERM_REFERENCE; 596 | pic->LongTermFrameIdx = 0; 597 | pic->MaxLongTermFrameIdx = 0; 598 | 599 | } 600 | else//sHeader.long_term_reference_flag=0 601 | { 602 | //该IDR图像将被标记为"用于短期参考" 603 | pic->reference_marked_type = PICTURE_MARKING::SHORT_TERM_REFERENCE; 604 | pic->MaxLongTermFrameIdx = NA; //设置为没有长期索引 605 | } 606 | } 607 | else 608 | { 609 | // =0 先入先出(FIFO):使用滑动窗的机制,先入先出,在这种模式下没有办法对长期参考帧进行操作。 610 | // =1 自适应标记(marking):后续码流中会有一系列句法元素显式指明操作的步骤。自适应是指编码器可根据情况随机灵活地作出决策。 611 | if (sHeader.adaptive_ref_pic_marking_mode_flag) 612 | { 613 | //自适应标记过程 614 | Adaptive_memory_control_decoded_reference_picture_marking_process(sHeader, pic); 615 | } 616 | else 617 | { 618 | //滑动窗口解码参考图像的标识过程 619 | Sliding_window_decoded_reference_picture_marking_process(sHeader.sps.max_num_ref_frames); 620 | } 621 | } 622 | 623 | if (!sHeader.nalu.IdrPicFlag && !pic->memory_management_control_operation_6_flag) 624 | { 625 | pic->reference_marked_type = PICTURE_MARKING::SHORT_TERM_REFERENCE; 626 | pic->MaxLongTermFrameIdx = NA; //设置为没有长期索引 627 | } 628 | 629 | } 630 | 631 | 632 | void DPB::Decoding_to_complete(ParseSlice* slice, const SliceHeader& sHeader) 633 | { 634 | 635 | if (previous) 636 | { 637 | delete previous; 638 | } 639 | previous = new Picture(slice, sHeader); 640 | 641 | if (sHeader.nalu.nal_ref_idc != 0) 642 | { 643 | Picture* pic = new Picture(slice, sHeader); 644 | //标记当前解码完成的帧是什么类型,然后放到DBP里去管理 645 | Decoded_reference_picture_marking_process(pic, sHeader); 646 | 647 | dpb.push(pic); 648 | 649 | } 650 | 651 | } 652 | 653 | 654 | 655 | void DPB::Sliding_window_decoded_reference_picture_marking_process(uint8_t max_num_ref_frames) 656 | { 657 | //如果当前编码场是一个互补参考场对的第二个场,并且第一个场已经被标记为“用于短期参考”时,当前图像也应该被标记为“用于短期参考” 658 | // TODO 659 | //否则 660 | int numShortTerm = 0; 661 | int numLongTerm = 0; 662 | 663 | for (size_t i = 0; i < dpb.length; i++) 664 | { 665 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 666 | { 667 | numShortTerm++; 668 | } 669 | 670 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 671 | { 672 | numLongTerm++; 673 | } 674 | } 675 | 676 | if (numShortTerm + numLongTerm == std::max(max_num_ref_frames, (uint8_t)1) && numShortTerm > 0) 677 | { 678 | //有着最小 FrameNumWrap 值的短期参考帧必须标记为“不用于参考” 679 | int FrameNumWrap = -1; 680 | Picture* pic = nullptr; 681 | int idx = -1; 682 | for (size_t i = 0; i < dpb.length; i++) 683 | { 684 | if (dpb[i]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE) 685 | { 686 | if (FrameNumWrap == -1) 687 | { 688 | idx = i; 689 | pic = dpb[i]; 690 | FrameNumWrap = dpb[i]->FrameNumWrap; 691 | } 692 | 693 | if (dpb[i]->FrameNumWrap < FrameNumWrap) 694 | { 695 | idx = i; 696 | pic = dpb[i]; 697 | FrameNumWrap = dpb[i]->FrameNumWrap; 698 | } 699 | } 700 | } 701 | 702 | 703 | if (pic != nullptr && idx >= 0) 704 | { 705 | dpb.splice(idx, 1); 706 | //pic->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 707 | } 708 | //如它是一个帧或场对,那么它的两个场必须均标记为“不用于参考”。 709 | } 710 | } 711 | 712 | void DPB::Adaptive_memory_control_decoded_reference_picture_marking_process(const SliceHeader& sHeader, Picture* pic) 713 | { 714 | 715 | for (size_t i = 0; i < sHeader.dec_ref_pic_markings_size; i++) 716 | { 717 | //将一个短期参考图像标记为非参考图像,也即将一个短期参考图像移出参考帧队列 718 | if (sHeader.dec_ref_pic_markings[i].memory_management_control_operation == 1) 719 | { 720 | int picNumX = sHeader.CurrPicNum - (sHeader.dec_ref_pic_markings[i].difference_of_pic_nums_minus1 + 1); 721 | //如果field_pic_flag等于0, 则picNumX指定的短期参考帧被标记为“unused for reference”。 722 | 723 | for (size_t j = 0; j < dpb.length; j++) 724 | { 725 | if (dpb[j]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE && dpb[j]->PicNum == picNumX) 726 | { 727 | dpb.splice(j, 1); 728 | //dpb[j]->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 729 | } 730 | } 731 | } 732 | 733 | //将一个长期参考图像标记为非参考图像,也 即将一个长期参考图像移出参考帧队列 734 | if (sHeader.dec_ref_pic_markings[i].memory_management_control_operation == 2) 735 | { 736 | //如果field_pic_flag为0,则LongTermPicNum等于long_term_pic_num的长期参考帧被标记为“不用于参考” 737 | for (size_t j = 0; j < dpb.length; j++) 738 | { 739 | if (dpb[j]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE && dpb[j]->LongTermPicNum == sHeader.dec_ref_pic_markings[i].long_term_pic_num) 740 | { 741 | dpb.splice(j, 1); 742 | //dpb[j]->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 743 | } 744 | } 745 | } 746 | 747 | //将一个短期参考图像转为长期参考图像 748 | if (sHeader.dec_ref_pic_markings[i].memory_management_control_operation == 3) 749 | { 750 | int picNumX = sHeader.CurrPicNum - (sHeader.dec_ref_pic_markings[i].difference_of_pic_nums_minus1 + 1); 751 | //当LongTermFrameIdx等于long_term_frame_idx已经被分配给一个长期参考帧,该帧被标记为“未使用的参考” 752 | for (size_t j = 0; j < dpb.length; j++) 753 | { 754 | if (dpb[j]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE 755 | && dpb[j]->LongTermFrameIdx == sHeader.dec_ref_pic_markings[i].long_term_frame_idx) 756 | { 757 | dpb.splice(j, 1); 758 | //dpb[j]->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 759 | } 760 | } 761 | 762 | //如果field_pic_flag等于0,则PicNumX所确定的短期参考帧将从“用于短期参考”转化为“用于长期参考” 763 | for (size_t j = 0; j < dpb.length; j++) 764 | { 765 | if (dpb[j]->reference_marked_type == PICTURE_MARKING::SHORT_TERM_REFERENCE && dpb[j]->PicNum == picNumX) 766 | { 767 | dpb[j]->reference_marked_type = PICTURE_MARKING::LONG_TERM_REFERENCE; 768 | } 769 | } 770 | 771 | } 772 | 773 | //指明长期参考帧的最大数目。 774 | if (sHeader.dec_ref_pic_markings[i].memory_management_control_operation == 4) 775 | { 776 | for (size_t j = 0; j < dpb.length; j++) 777 | { 778 | if ((dpb[j]->LongTermFrameIdx > sHeader.dec_ref_pic_markings[i].max_long_term_frame_idx_plus1 - 1) && dpb[j]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 779 | { 780 | dpb.splice(j, 1); 781 | //dpb[j]->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 782 | } 783 | } 784 | if (sHeader.dec_ref_pic_markings[i].max_long_term_frame_idx_plus1 == 0) 785 | { 786 | pic->MaxLongTermFrameIdx = NA;//非长期帧索引 787 | } 788 | else 789 | { 790 | pic->MaxLongTermFrameIdx = sHeader.dec_ref_pic_markings[i].max_long_term_frame_idx_plus1 - 1; 791 | } 792 | } 793 | 794 | //清空参考帧队列,将所有参考图像移出参考帧队列,并禁用长期参考机制 795 | if (sHeader.dec_ref_pic_markings[i].memory_management_control_operation == 5) 796 | { 797 | dpb.clear(); 798 | /*for (size_t j = 0; j < dpb.length; j++) 799 | { 800 | dpb[j]->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 801 | }*/ 802 | pic->MaxLongTermFrameIdx = NA; 803 | pic->memory_management_control_operation_5_flag = true; 804 | } 805 | 806 | //将当前图像存为一个长期参考帧 807 | if (sHeader.dec_ref_pic_markings[i].memory_management_control_operation == 6) 808 | { 809 | for (size_t j = 0; j < dpb.length; j++) 810 | { 811 | if (dpb[j]->LongTermFrameIdx == sHeader.dec_ref_pic_markings[i].long_term_frame_idx && dpb[j]->reference_marked_type == PICTURE_MARKING::LONG_TERM_REFERENCE) 812 | { 813 | dpb.splice(j, 1); 814 | //dpb[j]->reference_marked_type = PICTURE_MARKING::UNUSED_FOR_REFERENCE; 815 | } 816 | } 817 | 818 | pic->reference_marked_type = PICTURE_MARKING::LONG_TERM_REFERENCE; 819 | pic->LongTermFrameIdx = sHeader.dec_ref_pic_markings[i].long_term_frame_idx; 820 | pic->memory_management_control_operation_6_flag = true; 821 | } 822 | } 823 | } 824 | -------------------------------------------------------------------------------- /DPB.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/DPB.h -------------------------------------------------------------------------------- /FileReader.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/FileReader.cpp -------------------------------------------------------------------------------- /FileReader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Common.h" 3 | 4 | class FileReader 5 | { 6 | private: 7 | static const size_t MAX_BUFFER_SIZE; 8 | FILE* file; 9 | uint8_t* bufferStart; 10 | uint8_t* bufferPosition; 11 | uint8_t* bufferEnd; 12 | 13 | private: 14 | static int getNextStartCode(uint8_t* bufPtr, const uint8_t* end, uint8_t*& pos1, uint8_t*& pos2, int& startCodeLen1, 15 | int& startCodeLen2); 16 | 17 | static size_t EBSP_TO_RBSP(uint8_t* src, size_t length); 18 | public: 19 | explicit FileReader(const char* filename); 20 | void readNalUint(uint8_t*& data, size_t& size, bool& isStopLoop); 21 | ~FileReader(); 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /Macroblock.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include "Macroblock.h" 4 | #include "ParseSlice.h" 5 | #include "SliceData.h" 6 | #include "Picture.h" 7 | 8 | MB_TYPE_SLICES_I mb_type_slices_I[27] = 9 | { 10 | { 0, H264_MB_TYPE::I_NxN, 0, H264_MB_PART_PRED_MODE::Intra_4x4, NA, NA, NA }, 11 | { 0, H264_MB_TYPE::I_NxN, 1, H264_MB_PART_PRED_MODE::Intra_8x8, NA, NA, NA }, 12 | { 1, H264_MB_TYPE::I_16x16_0_0_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 0, 0, 0 }, 13 | { 2, H264_MB_TYPE::I_16x16_1_0_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 1, 0, 0 }, 14 | { 3, H264_MB_TYPE::I_16x16_2_0_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 2, 0, 0 }, 15 | { 4, H264_MB_TYPE::I_16x16_3_0_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 3, 0, 0 }, 16 | { 5, H264_MB_TYPE::I_16x16_0_1_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 0, 1, 0 }, 17 | { 6, H264_MB_TYPE::I_16x16_1_1_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 1, 1, 0 }, 18 | { 7, H264_MB_TYPE::I_16x16_2_1_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 2, 1, 0 }, 19 | { 8, H264_MB_TYPE::I_16x16_3_1_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 3, 1, 0 }, 20 | { 9, H264_MB_TYPE::I_16x16_0_2_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 0, 2, 0 }, 21 | { 10, H264_MB_TYPE::I_16x16_1_2_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 1, 2, 0 }, 22 | { 11, H264_MB_TYPE::I_16x16_2_2_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 2, 2, 0 }, 23 | { 12, H264_MB_TYPE::I_16x16_3_2_0, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 3, 2, 0 }, 24 | { 13, H264_MB_TYPE::I_16x16_0_0_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 0, 0, 15 }, 25 | { 14, H264_MB_TYPE::I_16x16_1_0_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 1, 0, 15 }, 26 | { 15, H264_MB_TYPE::I_16x16_2_0_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 2, 0, 15 }, 27 | { 16, H264_MB_TYPE::I_16x16_3_0_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 3, 0, 15 }, 28 | { 17, H264_MB_TYPE::I_16x16_0_1_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 0, 1, 15 }, 29 | { 18, H264_MB_TYPE::I_16x16_1_1_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 1, 1, 15 }, 30 | { 19, H264_MB_TYPE::I_16x16_2_1_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 2, 1, 15 }, 31 | { 20, H264_MB_TYPE::I_16x16_3_1_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 3, 1, 15 }, 32 | { 21, H264_MB_TYPE::I_16x16_0_2_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 0, 2, 15 }, 33 | { 22, H264_MB_TYPE::I_16x16_1_2_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 1, 2, 15 }, 34 | { 23, H264_MB_TYPE::I_16x16_2_2_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 2, 2, 15 }, 35 | { 24, H264_MB_TYPE::I_16x16_3_2_1, NA, H264_MB_PART_PRED_MODE::Intra_16x16, 3, 2, 15 }, 36 | { 25, H264_MB_TYPE::I_PCM, NA, H264_MB_PART_PRED_MODE::NA, NA, NA, NA } 37 | }; 38 | MB_TYPE_SLICES_SP_P mb_type_sleces_sp_p[6] = 39 | { 40 | {0, H264_MB_TYPE::P_L0_16x16, 1, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::NA, 16, 16}, 41 | {1, H264_MB_TYPE::P_L0_L0_16x8, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::Pred_L0, 16, 8}, 42 | {2, H264_MB_TYPE::P_L0_L0_8x16, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::Pred_L0, 8, 16}, 43 | {3, H264_MB_TYPE::P_8x8, 4, H264_MB_PART_PRED_MODE::NA, H264_MB_PART_PRED_MODE::NA, 8, 8}, 44 | {4, H264_MB_TYPE::P_8x8ref0, 4, H264_MB_PART_PRED_MODE::NA, H264_MB_PART_PRED_MODE::NA, 8, 8}, 45 | {5, H264_MB_TYPE::P_Skip, 1, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::NA, 16, 16} 46 | }; 47 | 48 | MB_TYPE_SLICES_B mb_type_sleces_b[24] = 49 | { 50 | { 0, H264_MB_TYPE::B_Direct_16x16, NA, H264_MB_PART_PRED_MODE::Direct, H264_MB_PART_PRED_MODE::NA, 8, 8 }, 51 | { 1, H264_MB_TYPE::B_L0_16x16, 1, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::NA, 16, 16 }, 52 | { 2, H264_MB_TYPE::B_L1_16x16, 1, H264_MB_PART_PRED_MODE::Pred_L1, H264_MB_PART_PRED_MODE::NA, 16, 16 }, 53 | { 3, H264_MB_TYPE::B_Bi_16x16, 1, H264_MB_PART_PRED_MODE::BiPred, H264_MB_PART_PRED_MODE::NA, 16, 16 }, 54 | { 4, H264_MB_TYPE::B_L0_L0_16x8, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::Pred_L0, 16, 8 }, 55 | { 5, H264_MB_TYPE::B_L0_L0_8x16, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::Pred_L0, 8, 16 }, 56 | { 6, H264_MB_TYPE::B_L1_L1_16x8, 2, H264_MB_PART_PRED_MODE::Pred_L1, H264_MB_PART_PRED_MODE::Pred_L1, 16, 8 }, 57 | { 7, H264_MB_TYPE::B_L1_L1_8x16, 2, H264_MB_PART_PRED_MODE::Pred_L1, H264_MB_PART_PRED_MODE::Pred_L1, 8, 16 }, 58 | { 8, H264_MB_TYPE::B_L0_L1_16x8, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::Pred_L1, 16, 8 }, 59 | { 9, H264_MB_TYPE::B_L0_L1_8x16, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::Pred_L1, 8, 16 }, 60 | { 10, H264_MB_TYPE::B_L1_L0_16x8, 2, H264_MB_PART_PRED_MODE::Pred_L1, H264_MB_PART_PRED_MODE::Pred_L0, 16, 8 }, 61 | { 11, H264_MB_TYPE::B_L1_L0_8x16, 2, H264_MB_PART_PRED_MODE::Pred_L1, H264_MB_PART_PRED_MODE::Pred_L0, 8, 16 }, 62 | { 12, H264_MB_TYPE::B_L0_Bi_16x8, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::BiPred, 16, 8 }, 63 | { 13, H264_MB_TYPE::B_L0_Bi_8x16, 2, H264_MB_PART_PRED_MODE::Pred_L0, H264_MB_PART_PRED_MODE::BiPred, 8, 16 }, 64 | { 14, H264_MB_TYPE::B_L1_Bi_16x8, 2, H264_MB_PART_PRED_MODE::Pred_L1, H264_MB_PART_PRED_MODE::BiPred, 16, 8 }, 65 | { 15, H264_MB_TYPE::B_L1_Bi_8x16, 2, H264_MB_PART_PRED_MODE::Pred_L1, H264_MB_PART_PRED_MODE::BiPred, 8, 16 }, 66 | { 16, H264_MB_TYPE::B_Bi_L0_16x8, 2, H264_MB_PART_PRED_MODE::BiPred, H264_MB_PART_PRED_MODE::Pred_L0, 16, 8 }, 67 | { 17, H264_MB_TYPE::B_Bi_L0_8x16, 2, H264_MB_PART_PRED_MODE::BiPred, H264_MB_PART_PRED_MODE::Pred_L0, 8, 16 }, 68 | { 18, H264_MB_TYPE::B_Bi_L1_16x8, 2, H264_MB_PART_PRED_MODE::BiPred, H264_MB_PART_PRED_MODE::Pred_L1, 16, 8 }, 69 | { 19, H264_MB_TYPE::B_Bi_L1_8x16, 2, H264_MB_PART_PRED_MODE::BiPred, H264_MB_PART_PRED_MODE::Pred_L1, 8, 16 }, 70 | { 20, H264_MB_TYPE::B_Bi_Bi_16x8, 2, H264_MB_PART_PRED_MODE::BiPred, H264_MB_PART_PRED_MODE::BiPred, 16, 8 }, 71 | { 21, H264_MB_TYPE::B_Bi_Bi_8x16, 2, H264_MB_PART_PRED_MODE::BiPred, H264_MB_PART_PRED_MODE::BiPred, 8, 16 }, 72 | { 22, H264_MB_TYPE::B_8x8, 4, H264_MB_PART_PRED_MODE::NA, H264_MB_PART_PRED_MODE::NA, 8, 8 }, 73 | { 23, H264_MB_TYPE::B_Skip, NA, H264_MB_PART_PRED_MODE::Direct, H264_MB_PART_PRED_MODE::NA, 8, 8 } 74 | }; 75 | MB_TYPE_SLICES_SI mb_type_sleces_si[1] = 76 | { 77 | { 0, H264_MB_TYPE::SI, H264_MB_PART_PRED_MODE::Intra_4x4, NA, NA, NA } 78 | }; 79 | SUB_MB_TYPE_MBS_P sub_mb_type_mbs_p[4] = 80 | { 81 | { 0, H264_MB_TYPE::P_L0_8x8, 1, H264_MB_PART_PRED_MODE::Pred_L0, 8, 8 }, 82 | { 1, H264_MB_TYPE::P_L0_8x4, 2, H264_MB_PART_PRED_MODE::Pred_L0, 8, 4 }, 83 | { 2, H264_MB_TYPE::P_L0_4x8, 2, H264_MB_PART_PRED_MODE::Pred_L0, 4, 8 }, 84 | { 3, H264_MB_TYPE::P_L0_4x4, 4, H264_MB_PART_PRED_MODE::Pred_L0, 4, 4 } 85 | }; 86 | 87 | 88 | SUB_MB_TYPE_MBS_B sub_mb_type_mbs_b[13] = 89 | { 90 | { 0, H264_MB_TYPE::B_Direct_8x8, 4, H264_MB_PART_PRED_MODE::Direct, 4, 4 }, 91 | { 1, H264_MB_TYPE::B_L0_8x8, 1, H264_MB_PART_PRED_MODE::Pred_L0, 8, 8 }, 92 | { 2, H264_MB_TYPE::B_L1_8x8, 1, H264_MB_PART_PRED_MODE::Pred_L1, 8, 8 }, 93 | { 3, H264_MB_TYPE::B_Bi_8x8, 1, H264_MB_PART_PRED_MODE::BiPred, 8, 8 }, 94 | { 4, H264_MB_TYPE::B_L0_8x4, 2, H264_MB_PART_PRED_MODE::Pred_L0, 8, 4 }, 95 | { 5, H264_MB_TYPE::B_L0_4x8, 2, H264_MB_PART_PRED_MODE::Pred_L0, 4, 8 }, 96 | { 6, H264_MB_TYPE::B_L1_8x4, 2, H264_MB_PART_PRED_MODE::Pred_L1, 8, 4 }, 97 | { 7, H264_MB_TYPE::B_L1_4x8, 2, H264_MB_PART_PRED_MODE::Pred_L1, 4, 8 }, 98 | { 8, H264_MB_TYPE::B_Bi_8x4, 2, H264_MB_PART_PRED_MODE::BiPred, 8, 4 }, 99 | { 9, H264_MB_TYPE::B_Bi_4x8, 2, H264_MB_PART_PRED_MODE::BiPred, 4, 8 }, 100 | { 10, H264_MB_TYPE::B_L0_4x4, 4, H264_MB_PART_PRED_MODE::Pred_L0, 4, 4 }, 101 | { 11, H264_MB_TYPE::B_L1_4x4, 4, H264_MB_PART_PRED_MODE::Pred_L1, 4, 4 }, 102 | { 12, H264_MB_TYPE::B_Bi_4x4, 4, H264_MB_PART_PRED_MODE::BiPred, 4, 4 } 103 | }; 104 | 105 | Macroblock::Macroblock() 106 | { 107 | currRefPtr = nullptr; 108 | 109 | sliceBase = nullptr; 110 | pcm_alignment_zero_bit = 0; 111 | transform_size_8x8_flag = 0; 112 | memset(pcm_sample_luma, 0, sizeof(uint8_t) * 256); 113 | pcm_sample_chroma = nullptr; 114 | 115 | mb_type = 0; 116 | memset(sub_mb_type, 0, sizeof(uint8_t) * 4); 117 | mbType = H264_MB_TYPE::NA; 118 | memset(subMbType, 0, sizeof(H264_MB_TYPE) * 4); 119 | mode = H264_MB_PART_PRED_MODE::NA; 120 | memset(subMode, 0, sizeof(H264_MB_PART_PRED_MODE) * 4); 121 | 122 | NumMbPart = 0; 123 | memset(NumSubMbPart, 0, sizeof(uint8_t) * 4); 124 | MbPartWidth = 0; 125 | MbPartHeight = 0; 126 | memset(SubMbPartWidth, 0, sizeof(uint8_t) * 4); 127 | memset(SubMbPartHeight, 0, sizeof(uint8_t) * 4); 128 | 129 | coded_block_pattern = 0; 130 | 131 | CodedBlockPatternChroma = -1; 132 | CodedBlockPatternLuma = -1; 133 | mb_qp_delta = 0; 134 | 135 | 136 | isAe = false; 137 | 138 | fix_mb_type = 0; 139 | fix_slice_type = SLIECETYPE::H264_SLIECE_TYPE_I; 140 | 141 | 142 | memset(prev_intra4x4_pred_mode_flag, 0, sizeof(uint8_t) * 16); 143 | memset(rem_intra4x4_pred_mode, 0, sizeof(uint8_t) * 16); 144 | memset(prev_intra8x8_pred_mode_flag, 0, sizeof(uint8_t) * 4); 145 | memset(rem_intra8x8_pred_mode, 0, sizeof(uint8_t) * 4); 146 | 147 | 148 | 149 | 150 | memset(mb_luma_4x4_non_zero_count_coeff, 0, sizeof(uint8_t) * 16); 151 | memset(mb_luma_8x8_non_zero_count_coeff, 0, sizeof(uint8_t) * 4); 152 | 153 | 154 | //预测模式 155 | memset(Intra4x4PredMode, 0, sizeof(uint8_t) * 16); 156 | memset(Intra8x8PredMode, 0, sizeof(uint8_t) * 4); 157 | Intra16x16PredMode = 0; 158 | 159 | 160 | //样点预测值 161 | memset(lumaPredSamples, 0, sizeof(uint8_t) * 16 * 4 * 4); 162 | memset(luma8x8PredSamples, 0, sizeof(uint8_t) * 4 * 8 * 8); 163 | memset(luma16x16PredSamples, 0, sizeof(uint8_t) * 16 * 16); 164 | //色度样点预测值 165 | memset(chromaPredSamples, 0, sizeof(uint8_t) * 8 * 16); 166 | 167 | 168 | 169 | intra_chroma_pred_mode = 0; 170 | QPY = 0; 171 | QP1Y = 0; 172 | 173 | QP1C = 0; 174 | QPC = 0; 175 | 176 | 177 | QSY = 0; 178 | QSC = 0; 179 | 180 | 181 | 182 | sliceNumber = 0; 183 | 184 | mb_skip_flag = 0; 185 | 186 | 187 | FilterOffsetA = 0; 188 | FilterOffsetB = 0; 189 | 190 | //coded_block_flag_DC_pattern = 0x07; 191 | //coded_block_flag_AC_pattern[0] = 0xFFFF; //cabac: coded_block_flag-luma 192 | //coded_block_flag_AC_pattern[1] = 0xFFFF; //cabac: coded_block_flag-cb 193 | //coded_block_flag_AC_pattern[2] = 0xFFFF; //cabac: coded_block_flag-cr 194 | 195 | coded_block_flag_DC_pattern = 0; 196 | coded_block_flag_AC_pattern[0] = 0; //cabac: coded_block_flag-luma 197 | coded_block_flag_AC_pattern[1] = 0; //cabac: coded_block_flag-cb 198 | coded_block_flag_AC_pattern[2] = 0; //cabac: coded_block_flag-cr 199 | 200 | 201 | memset(ref_idx_l0, 0, sizeof(uint8_t) * 4); 202 | memset(ref_idx_l1, 0, sizeof(uint8_t) * 4); 203 | memset(mvd_l0, 0, sizeof(int) * 4 * 4 * 2); 204 | memset(mvd_l1, 0, sizeof(int) * 4 * 4 * 2); 205 | 206 | memset(mvL0, 0, sizeof(int) * 4 * 4 * 2); 207 | memset(mvL1, 0, sizeof(int) * 4 * 4 * 2); 208 | 209 | memset(predFlagL0, 0, sizeof(int) * 4); 210 | memset(predFlagL1, 0, sizeof(int) * 4); 211 | memset(refIdxL0, 0, sizeof(int) * 4); 212 | memset(refIdxL1, 0, sizeof(int) * 4); 213 | 214 | } 215 | 216 | 217 | //slice type 五种类型 218 | //I slice中的宏块类型只能是I宏块类型 219 | //P slice中包含了I宏块类型,与P宏块类型 220 | //B slice中包含了I宏块类型,与B宏块类型 221 | //sp slice中包含了I宏块类型,与p宏块类型 222 | //si 仅包含si宏块 223 | //Intra16x16PredMode 如果当前宏块类型采用的预测方式为Intra_16x16,那么该字段有效,它用0~3表示了Intra_16x16中的四种模式 224 | 225 | 226 | //CodedBlockPatternLuma 如果当前宏块类型采用的预测方式为Intra_16x16,那么该字段有效,它表示了Luma宏块中的CBP。 227 | //从h.264语法结构分析的residual部分,我们知道当预测模式为Intra_16x16时,宏块需要分开AC level与DC level进行熵编码。 228 | //0:表示宏块内的16个4x4块中的AC level全部都为0,15:宏块内的16个4x4块中至少有一个块的AC level不全为0 229 | 230 | 231 | 232 | //CodedBlockPatternChroma :如果当前宏块类型采用的预测方式为Intra_16x16,那么该字段有效,它表示了Luma宏块中的CBP 233 | // 234 | //一个宏块的色度分量的coded_block_pattern,Cb、Cr的CodedBlockPatternChroma相同 235 | bool Macroblock::macroblock_layer(BitStream& bs, ParseSlice* Slice, SliceData* sliceData, Cabac& cabac, int nal_cnt) 236 | { 237 | 238 | sliceBase = Slice; 239 | 240 | SliceHeader& sHeader = sliceBase->sHeader; 241 | 242 | sliceNumber = sliceBase->sliceNumber; 243 | 244 | FilterOffsetA = sHeader.FilterOffsetA; 245 | FilterOffsetB = sHeader.FilterOffsetB; 246 | mb_skip_flag = sliceData->mb_skip_flag; 247 | 248 | isAe = sHeader.pps.entropy_coding_mode_flag; //ae(v)表示CABAC编码 249 | 250 | 251 | if (isAe) // ae(v) 表示CABAC编码 252 | { 253 | mb_type = cabac.decode_mb_type(bs, Slice); 254 | } 255 | else // ue(v) 表示CAVLC编码 256 | { 257 | //确定该 MB 是帧内或帧间(P 或 B)编码模式,确定该 MB 分割的尺寸 258 | mb_type = bs.readUE(); //2 ue(v) | ae(v) 259 | } 260 | 261 | 262 | uint8_t slice_type = sHeader.slice_type; 263 | 264 | //修正过后的 265 | fix_mb_type = mb_type; 266 | 267 | //当前宏块是什么类型 //修正过后的 268 | fix_slice_type = (SLIECETYPE)(slice_type); 269 | 270 | 271 | 272 | //修正mb_type,因为p,SI里可能包含了i宏块 273 | fixed_mb_type(slice_type, fix_mb_type, fix_slice_type); 274 | 275 | 276 | //获取当前宏块的预测模式 277 | mode = MbPartPredMode(0); 278 | 279 | /*uint8_t numMbPart = NumMbPart(fix_mb_type, fix_slice_type);*/ 280 | 281 | if (mbType == H264_MB_TYPE::I_PCM) //I_PCM 不经过预测,变换,量化 282 | { 283 | while (!byte_aligned(bs)) 284 | { 285 | /*当熵编码模式是CABAC时, 286 | 此时要求数据字节对齐, 即数据从下一个字节的第一个比特开始, 287 | 如果还没有字节对齐将出现若干个 pcm_alignment_zero_bit 作为填充。*/ 288 | pcm_alignment_zero_bit = bs.readBit(); //2 f(1) 289 | } 290 | 291 | for (size_t i = 0; i < 256; i++) 292 | { 293 | int v = sHeader.sps.BitDepthY; 294 | /*pcm_sample_luma[i]是一个样点值。第一个 pcm_sample_luma[i]值代表宏块里光栅扫描中的亮度样点值。 295 | 比特的数目通常代表这些样点每一个都是BitDepthY 。 296 | 当 profile_idc 不等于 100, 110, 122 或 144 时, pcm_sample_luma[i]不能等于0*/ 297 | pcm_sample_luma[i] = bs.readMultiBit(v); //3 u(v) 298 | } 299 | 300 | //MbWidthC MbHeightC色度阵列的宽度和高度 301 | pcm_sample_chroma = new uint32_t[2 * sHeader.sps.MbWidthC * sHeader.sps.MbHeightC](); 302 | for (size_t i = 0; i < 2 * sHeader.sps.MbWidthC * sHeader.sps.MbHeightC; i++) 303 | { 304 | int v = sHeader.sps.BitDepthC; 305 | /*pcm_sample_ chroma[i]是一个样点值。色度 306 | 第一个 MbWidthC* MbHeightC pcm_sample_ chroma[i]值代表宏块里光栅扫描中的Cb样点值且其余的MbWidthC* MbHeightC 307 | pcm_sample_chroma[i]值代表宏块里光栅扫描中 的 Cr 样点值。比特的数目通常代表这些样点每一个都是 BitDepthC 308 | 当 profile_idc 不等于 100, 110, 122 或 144 时,pcm_sample_ chroma[i]不能等于0。 309 | */ 310 | pcm_sample_chroma[i] = bs.readMultiBit(v); //3 u(v) 311 | } 312 | } 313 | else 314 | { 315 | 316 | bool noSubMbPartSizeLessThan8x8Flag = true; 317 | //子宏块 //(只对 8×8MB 分割的帧内 MB)确定每一子宏块的子宏块分割,每一宏块分割的表 0 和 / 或表1的参考图象;每一宏块子分割的差分编码运动矢量。 318 | if (mbType != H264_MB_TYPE::I_NxN && 319 | mode != H264_MB_PART_PRED_MODE::Intra_16x16 && 320 | NumMbPart == 4) 321 | { 322 | sub_mb_pred(bs, cabac, nal_cnt); 323 | 324 | for (int mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) 325 | { 326 | if (subMbType[mbPartIdx] != H264_MB_TYPE::B_Direct_8x8) 327 | { 328 | 329 | if (NumSubMbPart[mbPartIdx] > 1) 330 | { 331 | noSubMbPartSizeLessThan8x8Flag = false; 332 | } 333 | } 334 | else if (!sHeader.sps.direct_8x8_inference_flag) 335 | { 336 | noSubMbPartSizeLessThan8x8Flag = false; 337 | 338 | } 339 | } 340 | } 341 | else 342 | { 343 | //8x8解码 344 | if (sHeader.pps.transform_8x8_mode_flag && mbType == H264_MB_TYPE::I_NxN) 345 | { 346 | 347 | //使用8x8变换解码 348 | if (isAe) 349 | { 350 | transform_size_8x8_flag = cabac.decode_transform_size_8x8_flag(bs, Slice); 351 | } 352 | else 353 | { 354 | /*等于1表示对于当前宏块,亮度样点中变换系数解码过程和图像构建过程的调用, 355 | 应在残余的 8x8 块的去块效应滤波过程之前完成。transform_size_8x8_flag 等于 0 表示对于当前宏块, 356 | 亮度样点当中变换系数解码过程和图像构建过程的调用在剩余的4x4块的去块效应滤波过程之前完成。 357 | 如果 transform_size_8x8_flag 在比特流中不存在,则默认其值为0。*/ 358 | transform_size_8x8_flag = bs.readBit(); 359 | } 360 | 361 | mode = MbPartPredMode(0); 362 | } 363 | 364 | 365 | 366 | mb_pred(bs, cabac, nal_cnt); 367 | 368 | 369 | 370 | } 371 | 372 | 373 | 374 | if (mode != H264_MB_PART_PRED_MODE::Intra_16x16) 375 | { 376 | if (isAe) 377 | { 378 | 379 | coded_block_pattern = cabac.decode_coded_block_pattern(bs, Slice); 380 | } 381 | else 382 | { 383 | //宏块预测模式等于 Intra_4x4, Intra_8x8 或者 Inter 时,coded_block_pattern 的值不同 384 | coded_block_pattern = bs.readME(sHeader.sps.ChromaArrayType, mode); 385 | 386 | } 387 | //公式7-33 388 | //1、8x8 亮度块中的四个 4x4 亮度块的所有变换系数幅值都等于 0 👉残差(DC、AC)全部不编码 389 | //2、8x8 亮度块中的一个或多个 4x4 亮度块的一个或多个变换系数幅值不为 0👉残差(DC、AC)全部编码 390 | CodedBlockPatternLuma = coded_block_pattern % 16; 391 | 392 | /*CodedBlockPatternChroma 393 | 描述 394 | 0 所有色度变换系数幅值都等于 0。 395 | 1 一个或多个色度 DC 变换系数幅值不为0。所有色度AC变换系数幅值都等 于 0。 396 | 2 零个或多个色度 DC 变换系数幅值不为0。一个或多个色度AC变换系数幅 值不为 0。*/ 397 | CodedBlockPatternChroma = coded_block_pattern / 16; 398 | 399 | if ( 400 | CodedBlockPatternLuma > 0 && 401 | sHeader.pps.transform_8x8_mode_flag && 402 | mbType != H264_MB_TYPE::I_NxN && 403 | noSubMbPartSizeLessThan8x8Flag && 404 | (mbType != H264_MB_TYPE::B_Direct_16x16 || sHeader.sps.direct_8x8_inference_flag) 405 | ) 406 | { 407 | if (isAe) 408 | { 409 | transform_size_8x8_flag = cabac.decode_transform_size_8x8_flag(bs, Slice); 410 | } 411 | else 412 | { 413 | transform_size_8x8_flag = bs.readBit(); 414 | } 415 | mode = MbPartPredMode(0); 416 | 417 | } 418 | } 419 | 420 | //16x16 421 | if (CodedBlockPatternLuma > 0 || CodedBlockPatternChroma > 0 || mode == H264_MB_PART_PRED_MODE::Intra_16x16) 422 | { 423 | if (isAe) 424 | { 425 | mb_qp_delta = cabac.decode_mb_qp_delta(bs, Slice); 426 | } 427 | else 428 | { 429 | //能改变宏块层 中 QPY 的值 。mb_qp_delta 解码后的值应包含在–( 26 + QpBdOffsetY / 2) 到 +( 25 + QpBdOffsetY / 2 )范围内。 430 | //当任何宏块(包括 P_Skip 和 B_Skip 宏块类型)中都不存在 mb_qp_delta 时, mb_qp_delta 默认为0 431 | //量化参数的改变值。 432 | mb_qp_delta = bs.readSE(); 433 | } 434 | 435 | residual(bs, 0, 15, cabac); 436 | } 437 | } 438 | 439 | 440 | 441 | //QPY = ( ( QPY,PREV + mb_qp_delta + 52 + 2 * QpBdOffsetY ) % ( 52 + QpBdOffsetY ) ) -QpBdOffsetY 442 | //QpBdOffsetY 亮度偏移 443 | QPY = ((sHeader.QPY_prev + mb_qp_delta + 52 + 2 * sHeader.sps.QpBdOffsetY) % (52 + sHeader.sps.QpBdOffsetY)) - sHeader.sps.QpBdOffsetY; 444 | //对于条带中的第一个宏块,QPY_prev 的初始值为SliceQPY,QPY_prev是当前条带中按解码顺序排列的前一个宏块的亮度量化参数 QPY 445 | sHeader.QPY_prev = QPY; 446 | 447 | QP1Y = QPY + sHeader.sps.QpBdOffsetY; 448 | 449 | //只有HP模式下才有qpprime_y_zero_transform_bypass_flag这个变量 450 | //qpprime_y_zero_transform_bypass_flag 等于 1 是指当 QP1Y 等于 0 时变换系数解码过程的变换旁路操作和图像构建过程将会在第8.5 节给出的去块效应滤波过程之前执行 451 | if (sHeader.sps.qpprime_y_zero_transform_bypass_flag && QP1Y == 0) 452 | { 453 | TransformBypassModeFlag = true; 454 | } 455 | else 456 | { 457 | TransformBypassModeFlag = false; 458 | } 459 | 460 | return false; 461 | } 462 | 463 | bool Macroblock::macroblock_layer_skip(ParseSlice* Slice, SliceData* slice_data) 464 | { 465 | sliceBase = Slice; 466 | SliceHeader& sHeader = Slice->sHeader; 467 | sliceNumber = sliceBase->sliceNumber; 468 | 469 | FilterOffsetA = sHeader.FilterOffsetA; 470 | FilterOffsetB = sHeader.FilterOffsetB; 471 | mb_skip_flag = slice_data->mb_skip_flag; 472 | 473 | isAe = Slice->sHeader.pps.entropy_coding_mode_flag; 474 | SLIECETYPE sliceTtpy = (SLIECETYPE)(Slice->sHeader.slice_type); 475 | 476 | if (sliceTtpy == SLIECETYPE::H264_SLIECE_TYPE_P || sliceTtpy == SLIECETYPE::H264_SLIECE_TYPE_SP) 477 | { 478 | mb_type = 5; //inferred: P_Skip 479 | } 480 | else if (sliceTtpy == SLIECETYPE::H264_SLIECE_TYPE_B) 481 | { 482 | mb_type = 23; //inferred: B_Skip 483 | } 484 | 485 | 486 | //修正过后的 487 | fix_mb_type = mb_type; 488 | 489 | //当前宏块是什么类型 //修正过后的 490 | fix_slice_type = (SLIECETYPE)(sliceTtpy); 491 | 492 | MbPartPredMode(0); 493 | 494 | mb_qp_delta = 0; 495 | 496 | QPY = ((sHeader.QPY_prev + mb_qp_delta + 52 + 2 * sHeader.sps.QpBdOffsetY) % (52 + sHeader.sps.QpBdOffsetY)) - sHeader.sps.QpBdOffsetY; // (7-37) 497 | sHeader.QPY_prev = QPY; 498 | QP1Y = QPY + sHeader.sps.QpBdOffsetY; 499 | 500 | 501 | if (sHeader.sps.qpprime_y_zero_transform_bypass_flag && QP1Y == 0) 502 | { 503 | TransformBypassModeFlag = true; 504 | } 505 | else 506 | { 507 | TransformBypassModeFlag = false; 508 | } 509 | return false; 510 | } 511 | 512 | 513 | //宏块预测语法 514 | bool Macroblock::mb_pred(BitStream& bs, Cabac& cabac, int nal_cnt) 515 | { 516 | const SliceHeader& sHeader = sliceBase->sHeader; 517 | //Direct 直接预测:一种不用解码运动矢量的块的帧间预测模式。针对空域预测和时域预测又两种直接预测模式。 518 | if (mode == H264_MB_PART_PRED_MODE::Intra_4x4 || mode == H264_MB_PART_PRED_MODE::Intra_8x8 || mode == H264_MB_PART_PRED_MODE::Intra_16x16) 519 | { 520 | 521 | if (mode == H264_MB_PART_PRED_MODE::Intra_4x4) 522 | { 523 | for (size_t luma4x4BlkIdx = 0; luma4x4BlkIdx < 16; luma4x4BlkIdx++) 524 | { 525 | 526 | //表示序号为 luma4x4BlkIdx = 0到15 的4x4 亮度块的帧内Intra_4x4 预测。 527 | if (isAe) // ae(v) 表示CABAC编码 528 | { 529 | prev_intra4x4_pred_mode_flag[luma4x4BlkIdx] = cabac.decode_prev_intra4x4_pred_mode_flag_or_prev_intra8x8_pred_mode_flag(bs); 530 | } 531 | else 532 | { 533 | 534 | //表示帧内预测模式预测标识。如果该标识位为1,表示帧内预测模式的预测值就是实际的模式,否则就需要另外传递实际的帧内预测模式。 535 | prev_intra4x4_pred_mode_flag[luma4x4BlkIdx] = bs.readBit(); 536 | } 537 | 538 | if (!prev_intra4x4_pred_mode_flag[luma4x4BlkIdx]) { 539 | if (isAe) // ae(v) 表示CABAC编码 540 | { 541 | rem_intra4x4_pred_mode[luma4x4BlkIdx] = cabac.decode_rem_intra4x4_pred_mode_or_rem_intra8x8_pred_mode(bs); 542 | } 543 | else 544 | { 545 | //有9种预测模式 546 | /*模式0:垂直模式,条件:A~D可用。 547 | 模式1:水平模式,条件:I~L可用。 548 | 模式2:DC模式,条件:A~D或I~L可用。 549 | 模式3~8:方向模式,各个像素是由A到L像素通过权重不等的公式加权计算的。*/ 550 | //表示额外传递的实际帧内预测模式。 551 | rem_intra4x4_pred_mode[luma4x4BlkIdx] = bs.readMultiBit(3); 552 | } 553 | 554 | } 555 | } 556 | } 557 | 558 | 559 | if (mode == H264_MB_PART_PRED_MODE::Intra_8x8) 560 | { 561 | for (size_t luma8x8BlkIdx = 0; luma8x8BlkIdx < 4; luma8x8BlkIdx++) { 562 | //表示序号为 luma8x8BlkIdx = 0到3 的8x8 亮度块的Intra_8x8 预测 563 | if (isAe) // ae(v) 表示CABAC编码 564 | { 565 | prev_intra8x8_pred_mode_flag[luma8x8BlkIdx] = cabac.decode_prev_intra4x4_pred_mode_flag_or_prev_intra8x8_pred_mode_flag(bs); 566 | } 567 | else 568 | { 569 | prev_intra8x8_pred_mode_flag[luma8x8BlkIdx] = bs.readBit(); 570 | } 571 | 572 | if (!prev_intra8x8_pred_mode_flag[luma8x8BlkIdx]) { 573 | if (isAe) // ae(v) 表示CABAC编码 574 | { 575 | rem_intra8x8_pred_mode[luma8x8BlkIdx] = cabac.decode_rem_intra4x4_pred_mode_or_rem_intra8x8_pred_mode(bs); 576 | } 577 | else 578 | { 579 | rem_intra8x8_pred_mode[luma8x8BlkIdx] = bs.readMultiBit(3); 580 | } 581 | 582 | } 583 | } 584 | } 585 | 586 | 587 | // YUV 4 : 2 : 0 || YUV 4 : 2 : 2,yuv一起编码 588 | if (sHeader.sps.ChromaArrayType == 1 || sHeader.sps.ChromaArrayType == 2) 589 | { 590 | //宏块中用于色度的空间预测类型使用Intra_4x4 或 Intra_16x16 预测 591 | //intra_chroma_pred_mode 的取值范围为0 到 3。 592 | // 0 = DC 又被称之为均值模式。均值模式下,4 x 4 子块中 16 个像素都是相同的值, 593 | // 是上方的四个像素 A B C D 和左边四个像素 I J K L 的均值。 594 | // 1 = 水平的 595 | // 2 = 垂直的 596 | // 3 = 平面的 597 | if (isAe) // ae(v) 表示CABAC编码 598 | { 599 | intra_chroma_pred_mode = cabac.decode_intra_chroma_pred_mode(bs, sliceBase); 600 | } 601 | else 602 | { 603 | intra_chroma_pred_mode = bs.readUE(); 604 | } 605 | } 606 | } 607 | else if (mode != H264_MB_PART_PRED_MODE::Direct) 608 | { 609 | 610 | for (size_t mbPartIdx = 0; mbPartIdx < NumMbPart; mbPartIdx++) 611 | { 612 | //ref_idx_l0[ mbPartIdx ] 用参考帧队列 L0 进行预测,即前向预测时 613 | //不支持帧场自适应变量mb_field_decoding_flag=false 614 | bool mb_field_decoding_flag = false; 615 | if ((sHeader.num_ref_idx_l0_active_minus1 > 0 || false)//(mb_field_decoding_flag) 616 | && MbPartPredMode(mbPartIdx) != H264_MB_PART_PRED_MODE::Pred_L1 617 | ) 618 | { 619 | if (isAe) 620 | { 621 | bool is_ref_idx_l0 = true; 622 | cabac.decode_ref_idx_lX(sliceBase, bs, mbPartIdx, is_ref_idx_l0, ref_idx_l0[mbPartIdx]); 623 | } 624 | else 625 | { 626 | 627 | //sHeader.num_ref_idx_l1_active_minus1 - 1; 628 | //ref_idx_l0[ mbPartIdx ]的取值范围将是0到num_ref_idx_l0_active_minus 629 | ref_idx_l0[mbPartIdx] = bs.readTE(sHeader.num_ref_idx_l0_active_minus1); 630 | } 631 | } 632 | } 633 | 634 | 635 | //这个句法元素用于参考帧队列 L1,即后向预测 636 | for (size_t mbPartIdx = 0; mbPartIdx < NumMbPart; mbPartIdx++) 637 | { 638 | if ((sHeader.num_ref_idx_l1_active_minus1 > 0 || false) && MbPartPredMode(mbPartIdx) != H264_MB_PART_PRED_MODE::Pred_L0) 639 | { 640 | if (isAe) 641 | { 642 | bool is_ref_idx_l0 = false; 643 | cabac.decode_ref_idx_lX(sliceBase, bs, mbPartIdx, is_ref_idx_l0, ref_idx_l1[mbPartIdx]); 644 | } 645 | else 646 | { 647 | ref_idx_l1[mbPartIdx] = bs.readTE(sHeader.num_ref_idx_l1_active_minus1); 648 | } 649 | 650 | } 651 | } 652 | 653 | //运动矢量残差MVD 654 | for (size_t mbPartIdx = 0; mbPartIdx < NumMbPart; mbPartIdx++) 655 | { 656 | if (MbPartPredMode(mbPartIdx) != H264_MB_PART_PRED_MODE::Pred_L1) 657 | { 658 | for (size_t compIdx = 0; compIdx < 2; compIdx++) 659 | { 660 | if (isAe) 661 | { 662 | 663 | int mvd_flag = compIdx; 664 | int subMbPartIdx = 0; 665 | cabac.decode_mvd_lX(sliceBase, bs, mbPartIdx, subMbPartIdx, mvd_flag, mvd_l0[mbPartIdx][0][compIdx]); 666 | 667 | } 668 | else 669 | { 670 | mvd_l0[mbPartIdx][0][compIdx] = bs.readSE(); 671 | } 672 | } 673 | } 674 | } 675 | 676 | 677 | 678 | for (size_t mbPartIdx = 0; mbPartIdx < NumMbPart; mbPartIdx++) 679 | { 680 | if (MbPartPredMode(mbPartIdx) != H264_MB_PART_PRED_MODE::Pred_L0) 681 | { 682 | for (size_t compIdx = 0; compIdx < 2; compIdx++) 683 | { 684 | if (isAe) 685 | { 686 | int mvd_flag = 2 + compIdx; 687 | int subMbPartIdx = 0; 688 | cabac.decode_mvd_lX(sliceBase, bs, mbPartIdx, subMbPartIdx, mvd_flag, mvd_l1[mbPartIdx][0][compIdx]); 689 | } 690 | else 691 | { 692 | mvd_l1[mbPartIdx][0][compIdx] = bs.readSE(); 693 | } 694 | } 695 | } 696 | } 697 | 698 | } 699 | return false; 700 | } 701 | 702 | 703 | bool Macroblock::sub_mb_pred(BitStream& bs, Cabac& cabac, int nal_cnt) 704 | { 705 | 706 | for (size_t mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) 707 | { 708 | if (isAe) 709 | { 710 | 711 | sub_mb_type[mbPartIdx] = cabac.decode_sub_mb_type(bs, sliceBase); 712 | } 713 | else 714 | { 715 | sub_mb_type[mbPartIdx] = bs.readUE(); 716 | } 717 | 718 | 719 | if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_P && sub_mb_type[mbPartIdx] >= 0 && sub_mb_type[mbPartIdx] <= 3) 720 | { 721 | subMbType[mbPartIdx] = sub_mb_type_mbs_p[sub_mb_type[mbPartIdx]].name; 722 | subMode[mbPartIdx] = sub_mb_type_mbs_p[sub_mb_type[mbPartIdx]].SubMbPredMode; 723 | NumSubMbPart[mbPartIdx] = sub_mb_type_mbs_p[sub_mb_type[mbPartIdx]].NumSubMbPart; 724 | SubMbPartWidth[mbPartIdx] = sub_mb_type_mbs_p[sub_mb_type[mbPartIdx]].SubMbPartWidth; 725 | SubMbPartHeight[mbPartIdx] = sub_mb_type_mbs_p[sub_mb_type[mbPartIdx]].SubMbPartHeight; 726 | } 727 | else if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_B && sub_mb_type[mbPartIdx] >= 0 && sub_mb_type[mbPartIdx] <= 12) 728 | { 729 | subMbType[mbPartIdx] = sub_mb_type_mbs_b[sub_mb_type[mbPartIdx]].name; 730 | subMode[mbPartIdx] = sub_mb_type_mbs_b[sub_mb_type[mbPartIdx]].SubMbPredMode; 731 | NumSubMbPart[mbPartIdx] = sub_mb_type_mbs_b[sub_mb_type[mbPartIdx]].NumSubMbPart; 732 | SubMbPartWidth[mbPartIdx] = sub_mb_type_mbs_b[sub_mb_type[mbPartIdx]].SubMbPartWidth; 733 | SubMbPartHeight[mbPartIdx] = sub_mb_type_mbs_b[sub_mb_type[mbPartIdx]].SubMbPartHeight; 734 | } 735 | else 736 | { 737 | printError("子宏块sub_mb_type错误"); 738 | exit(-1); 739 | } 740 | } 741 | 742 | 743 | for (size_t mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) 744 | { 745 | if ((sliceBase->sHeader.num_ref_idx_l0_active_minus1 > 0 || false) 746 | && mbType != H264_MB_TYPE::P_8x8ref0 747 | && subMbType[mbPartIdx] != H264_MB_TYPE::B_Direct_8x8 748 | && subMode[mbPartIdx] != H264_MB_PART_PRED_MODE::Pred_L1 749 | ) 750 | { 751 | if (isAe) 752 | { 753 | bool is_ref_idx_l0 = true; 754 | cabac.decode_ref_idx_lX(sliceBase, bs, mbPartIdx, is_ref_idx_l0, ref_idx_l0[mbPartIdx]); 755 | } 756 | else 757 | { 758 | //sHeader.num_ref_idx_l1_active_minus1 - 1; 759 | //ref_idx_l0[ mbPartIdx ]的取值范围将是0到num_ref_idx_l0_active_minus 760 | ref_idx_l0[mbPartIdx] = bs.readTE(sliceBase->sHeader.num_ref_idx_l0_active_minus1); 761 | } 762 | } 763 | } 764 | 765 | 766 | 767 | //这个句法元素用于参考帧队列 L1,即后向预测 768 | for (size_t mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) 769 | { 770 | if ((sliceBase->sHeader.num_ref_idx_l1_active_minus1 > 0 || false) 771 | && mbType != H264_MB_TYPE::P_8x8ref0 772 | && subMbType[mbPartIdx] != H264_MB_TYPE::B_Direct_8x8 773 | && subMode[mbPartIdx] != H264_MB_PART_PRED_MODE::Pred_L0 774 | ) 775 | { 776 | if (isAe) 777 | { 778 | bool is_ref_idx_l0 = false; 779 | cabac.decode_ref_idx_lX(sliceBase, bs, mbPartIdx, is_ref_idx_l0, ref_idx_l1[mbPartIdx]); 780 | } 781 | else 782 | { 783 | //sHeader.num_ref_idx_l1_active_minus1 - 1; 784 | //ref_idx_l0[ mbPartIdx ]的取值范围将是0到num_ref_idx_l0_active_minus 785 | ref_idx_l1[mbPartIdx] = bs.readTE(sliceBase->sHeader.num_ref_idx_l1_active_minus1); 786 | } 787 | } 788 | } 789 | 790 | 791 | for (size_t mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) 792 | { 793 | if (subMbType[mbPartIdx] != H264_MB_TYPE::B_Direct_8x8 794 | && subMode[mbPartIdx] != H264_MB_PART_PRED_MODE::Pred_L1 795 | ) 796 | { 797 | for (size_t subMbPartIdx = 0; subMbPartIdx < NumSubMbPart[mbPartIdx]; subMbPartIdx++) 798 | { 799 | for (size_t compIdx = 0; compIdx < 2; compIdx++) 800 | { 801 | if (isAe) 802 | { 803 | int mvd_flag = compIdx; 804 | cabac.decode_mvd_lX(sliceBase, bs, mbPartIdx, subMbPartIdx, mvd_flag, mvd_l0[mbPartIdx][subMbPartIdx][compIdx]); 805 | } 806 | else 807 | { 808 | mvd_l0[mbPartIdx][subMbPartIdx][compIdx] = bs.readSE(); 809 | } 810 | } 811 | 812 | } 813 | 814 | } 815 | } 816 | 817 | 818 | for (size_t mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++) 819 | { 820 | if (subMbType[mbPartIdx] != H264_MB_TYPE::B_Direct_8x8 821 | && subMode[mbPartIdx] != H264_MB_PART_PRED_MODE::Pred_L0 822 | ) 823 | { 824 | for (size_t subMbPartIdx = 0; subMbPartIdx < NumSubMbPart[mbPartIdx]; subMbPartIdx++) 825 | { 826 | for (size_t compIdx = 0; compIdx < 2; compIdx++) 827 | { 828 | if (isAe) 829 | { 830 | 831 | int mvd_flag = 2 + compIdx; 832 | cabac.decode_mvd_lX(sliceBase, bs, mbPartIdx, subMbPartIdx, mvd_flag, mvd_l1[mbPartIdx][subMbPartIdx][compIdx]); 833 | } 834 | else 835 | { 836 | mvd_l1[mbPartIdx][subMbPartIdx][compIdx] = bs.readSE(); 837 | } 838 | } 839 | 840 | } 841 | 842 | } 843 | } 844 | 845 | 846 | return false; 847 | } 848 | //获得当前宏块类型所采用的Intra预测方式 849 | H264_MB_PART_PRED_MODE Macroblock::MbPartPredMode(uint8_t mbPartIdx) 850 | { 851 | H264_MB_PART_PRED_MODE mode = H264_MB_PART_PRED_MODE::NA; 852 | 853 | if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_I) 854 | { 855 | //mb_type == I_NxN 856 | if (fix_mb_type == 0) { 857 | if (transform_size_8x8_flag) { 858 | mode = mb_type_slices_I[1].MbPartPredMode; 859 | mbType = mb_type_slices_I[1].name; 860 | } 861 | else { 862 | mode = mb_type_slices_I[0].MbPartPredMode; 863 | mbType = mb_type_slices_I[1].name; 864 | } 865 | } 866 | else if (fix_mb_type == 25) 867 | { 868 | mode = mb_type_slices_I[fix_mb_type].MbPartPredMode; //na 869 | mbType = mb_type_slices_I[fix_mb_type].name; 870 | } 871 | else { 872 | mode = mb_type_slices_I[fix_mb_type + 1].MbPartPredMode; 873 | CodedBlockPatternLuma = mb_type_slices_I[fix_mb_type + 1].CodedBlockPatternLuma; 874 | CodedBlockPatternChroma = mb_type_slices_I[fix_mb_type + 1].CodedBlockPatternChroma; 875 | Intra16x16PredMode = mb_type_slices_I[fix_mb_type + 1].Intra16x16PredMode; 876 | mbType = mb_type_slices_I[fix_mb_type + 1].name; 877 | } 878 | 879 | 880 | } 881 | else if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_P || fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_SP) 882 | { 883 | 884 | if (mbPartIdx == 1) 885 | { 886 | mode = mb_type_sleces_sp_p[fix_mb_type].MbPartPredMode1; 887 | } 888 | else { 889 | mode = mb_type_sleces_sp_p[fix_mb_type].MbPartPredMode0; 890 | } 891 | mbType = mb_type_sleces_sp_p[fix_mb_type].name; 892 | 893 | MbPartWidth = mb_type_sleces_sp_p[fix_mb_type].MbPartWidth; 894 | MbPartHeight = mb_type_sleces_sp_p[fix_mb_type].MbPartHeight; 895 | 896 | 897 | NumMbPart = mb_type_sleces_sp_p[mb_type].NumMbPart; 898 | } 899 | else if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_B) 900 | { 901 | if (mbPartIdx == 1) 902 | { 903 | mode = mb_type_sleces_b[fix_mb_type].MbPartPredMode1; 904 | } 905 | else { 906 | mode = mb_type_sleces_b[fix_mb_type].MbPartPredMode0; 907 | } 908 | mbType = mb_type_sleces_b[fix_mb_type].name; 909 | MbPartWidth = mb_type_sleces_b[fix_mb_type].MbPartWidth; 910 | MbPartHeight = mb_type_sleces_b[fix_mb_type].MbPartHeight; 911 | 912 | NumMbPart = mb_type_sleces_b[mb_type].NumMbPart; 913 | } 914 | else if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_SI) 915 | { 916 | mode = mb_type_sleces_si[fix_mb_type].MbPartPredMode; 917 | mbType = mb_type_sleces_si[fix_mb_type].name; 918 | } 919 | return mode; 920 | } 921 | 922 | H264_MB_PART_PRED_MODE Macroblock::getMbPartPredMode(SLIECETYPE fix_slice_type, uint8_t fix_mb_type, bool transform_size_8x8_flag, uint8_t mbPartIdx) 923 | { 924 | H264_MB_PART_PRED_MODE mode = H264_MB_PART_PRED_MODE::NA; 925 | 926 | if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_I) 927 | { 928 | //mb_type == I_NxN 929 | if (fix_mb_type == 0) { 930 | if (transform_size_8x8_flag) { 931 | mode = mb_type_slices_I[1].MbPartPredMode; 932 | } 933 | else { 934 | mode = mb_type_slices_I[0].MbPartPredMode; 935 | } 936 | } 937 | else if (fix_mb_type == 25) 938 | { 939 | mode = mb_type_slices_I[fix_mb_type].MbPartPredMode; //na 940 | } 941 | else { 942 | mode = mb_type_slices_I[fix_mb_type + 1].MbPartPredMode; 943 | } 944 | 945 | 946 | } 947 | else if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_P || fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_SP) 948 | { 949 | 950 | if (mbPartIdx == 0) 951 | { 952 | mode = mb_type_sleces_sp_p[fix_mb_type].MbPartPredMode0; 953 | } 954 | else 955 | { 956 | mode = mb_type_sleces_sp_p[fix_mb_type].MbPartPredMode1; 957 | } 958 | } 959 | else if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_B) 960 | { 961 | if (mbPartIdx == 0) 962 | { 963 | mode = mb_type_sleces_b[fix_mb_type].MbPartPredMode0; 964 | 965 | } 966 | else //B_Direct_16x16,B_Skip =1, =2, =3,无效的 967 | { 968 | mode = mb_type_sleces_b[fix_mb_type].MbPartPredMode1; 969 | } 970 | } 971 | else if (fix_slice_type == SLIECETYPE::H264_SLIECE_TYPE_SI) 972 | { 973 | mode = mb_type_sleces_si[fix_mb_type].MbPartPredMode; 974 | } 975 | 976 | return mode; 977 | } 978 | 979 | //修正slice_type和mb_type 980 | int Macroblock::fixed_mb_type(uint32_t slice_type, uint8_t& fix_mb_type, SLIECETYPE& fix_slice_type) 981 | { 982 | 983 | if ((SLIECETYPE)(slice_type % 5) == SLIECETYPE::H264_SLIECE_TYPE_SI) 984 | { 985 | if (mb_type >= 1 && mb_type <= 26)//说明包含了i宏块 986 | { 987 | fix_mb_type = mb_type - 1; 988 | fix_slice_type = SLIECETYPE::H264_SLIECE_TYPE_I; //说明包含了I宏块 989 | } 990 | } 991 | else if ((SLIECETYPE)(slice_type % 5) == SLIECETYPE::H264_SLIECE_TYPE_SP || 992 | (SLIECETYPE)(slice_type % 5) == SLIECETYPE::H264_SLIECE_TYPE_P) 993 | { 994 | if (mb_type >= 5 && mb_type <= 30) 995 | { 996 | fix_mb_type = mb_type - 5; 997 | fix_slice_type = SLIECETYPE::H264_SLIECE_TYPE_I; //说明包含了I宏块 998 | } 999 | } 1000 | else if ((SLIECETYPE)(slice_type % 5) == SLIECETYPE::H264_SLIECE_TYPE_B) 1001 | { 1002 | if (mb_type >= 23 && mb_type <= 48) 1003 | { 1004 | fix_mb_type = mb_type - 23; 1005 | fix_slice_type = SLIECETYPE::H264_SLIECE_TYPE_I; //说明包含了I宏块 1006 | } 1007 | } 1008 | 1009 | 1010 | return 0; 1011 | } 1012 | 1013 | 1014 | //计算残差数据 1015 | bool Macroblock::residual(BitStream& bs, int startIdx, int endIdx, Cabac& cabac) 1016 | { 1017 | 1018 | 1019 | int TotalCoeff = 0; 1020 | const SliceHeader& sHeader = sliceBase->sHeader; 1021 | ResidualBlockCavlc residual_block(sliceBase); 1022 | 1023 | 1024 | //解析量度 1025 | residual_luma(bs, i16x16DClevel, i16x16AClevel, level4x4, level8x8, startIdx, endIdx, cabac); 1026 | 1027 | //chroma_format_idc = 0 单色 1028 | //chroma_format_idc = 1 YUV 4 : 2 : 0 1029 | //chroma_format_idc = 2 YUV 4 : 2 : 2 1030 | //chroma_format_idc = 3 YUV 4 : 4 : 4 1031 | 1032 | //CodedBlockPatternChroma 只会有0,1,2三个值 1033 | //解析色度 1034 | if (sHeader.sps.ChromaArrayType == 1 || sHeader.sps.ChromaArrayType == 2) 1035 | { 1036 | TotalCoeff = 0; 1037 | //sps.SubWidthC=2, sHeader.sps.SubHeightC=1 //422 1038 | //sps.SubWidthC=2, sHeader.sps.SubHeightC=2 //420 1039 | int NumC8x8 = 4 / (sHeader.sps.SubWidthC * sHeader.sps.SubHeightC); 1040 | //420对应一个u,一个v 1041 | for (size_t iCbCr = 0; iCbCr < 2; iCbCr++) 1042 | { 1043 | //有CodedBlockPatternChroma这个值才能进行解码 解码器把所有残差系数赋为0 1044 | if ((CodedBlockPatternChroma & 3) && startIdx == 0) 1045 | { 1046 | 1047 | if (isAe) 1048 | { 1049 | cabac.residual_block_cabac(bs, sliceBase, ChromaDCLevel[iCbCr], 0, 4 * NumC8x8 - 1, 4 * NumC8x8, RESIDUAL_LEVEL::ChromaDCLevel, TotalCoeff, 0, iCbCr); 1050 | } 1051 | else 1052 | { 1053 | //解码色度DC系数,这是必有的 DC是固定码表 1054 | //420最大系数有4个 422最大系数有8个 444最大系数有16个 1055 | residual_block.residual_block_cavlc(bs, ChromaDCLevel[iCbCr], 0, 4 * NumC8x8 - 1, 4 * NumC8x8, TotalCoeff, RESIDUAL_LEVEL::ChromaDCLevel); 1056 | } 1057 | mb_chroma_4x4_non_zero_count_coeff[iCbCr][0] = TotalCoeff; 1058 | } 1059 | else 1060 | { 1061 | //所有残差都不被传送,解码器把所有残差系数赋为0。 1062 | for (size_t i = 0; i < 4 * NumC8x8; i++) 1063 | { 1064 | ChromaDCLevel[iCbCr][i] = 0; 1065 | } 1066 | } 1067 | } 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | for (size_t iCbCr = 0; iCbCr < 2; iCbCr++) 1074 | { 1075 | //420是4个y对应一组uv,422是两个y对应一组uv,如果这里是420的就u和v各读一个,如果422的就各读两个 如果444的就各读四个,所以最多有16个 1076 | for (size_t i8x8 = 0; i8x8 < NumC8x8; i8x8++) 1077 | { 1078 | for (size_t i4x4 = 0; i4x4 < 4; i4x4++) 1079 | { 1080 | const size_t BlkIdx = i8x8 * 4 + i4x4;//第几个块 1081 | //AC系数解码 1082 | if (CodedBlockPatternChroma & 2) 1083 | { 1084 | TotalCoeff = 0; 1085 | if (isAe) 1086 | { 1087 | cabac.residual_block_cabac(bs, sliceBase, ChromaACLevel[iCbCr][BlkIdx], std::max(0, startIdx - 1), endIdx - 1, 15, RESIDUAL_LEVEL::ChromaACLevel, TotalCoeff, BlkIdx, iCbCr); 1088 | } 1089 | else 1090 | { 1091 | 1092 | RESIDUAL_LEVEL level = iCbCr == 0 ? RESIDUAL_LEVEL::ChromaACLevelCb : RESIDUAL_LEVEL::ChromaACLevelCr; 1093 | //能走到这里DC系数最少被取走了一个,所以这里最多15 1094 | residual_block.residual_block_cavlc(bs, ChromaACLevel[iCbCr][BlkIdx], std::max(0, startIdx - 1), endIdx - 1, 15, TotalCoeff, level, BlkIdx); 1095 | 1096 | } 1097 | //色度非0系数 1098 | mb_chroma_4x4_non_zero_count_coeff[iCbCr][BlkIdx] = TotalCoeff; 1099 | } 1100 | else 1101 | { 1102 | //所有残差都不被传送,解码器把所有残差系数赋为0。 1103 | for (size_t i = 0; i < 15; i++) 1104 | { 1105 | ChromaACLevel[iCbCr][BlkIdx][i] = 0; 1106 | } 1107 | 1108 | } 1109 | 1110 | } 1111 | } 1112 | } 1113 | 1114 | 1115 | 1116 | } 1117 | else if (sHeader.sps.ChromaArrayType == 3) 1118 | { 1119 | //residual_luma(bs, i16x16DClevel, i16x16AClevel, level4x4, level8x8, startIdx, endIdx); 1120 | } 1121 | return false; 1122 | } 1123 | //亮度块预测 1124 | int Macroblock::residual_luma(BitStream& bs, int i16x16DClevel[16], int i16x16AClevel[16][16], int level4x4[16][16], int level8x8[4][64], int startIdx, int endIdx, Cabac& cabac) 1125 | { 1126 | ResidualBlockCavlc residual_block(sliceBase); 1127 | const SliceHeader& sHeader = sliceBase->sHeader; 1128 | int TotalCoeff = 0; 1129 | 1130 | //先解析16*16的DC直流分量 1131 | if (startIdx == 0 && mode == H264_MB_PART_PRED_MODE::Intra_16x16) 1132 | { 1133 | if (isAe) 1134 | { 1135 | cabac.residual_block_cabac(bs, sliceBase, i16x16DClevel, 0, 15, 16, RESIDUAL_LEVEL::Intra16x16DCLevel, TotalCoeff, 0); 1136 | } 1137 | else 1138 | { 1139 | residual_block.residual_block_cavlc(bs, i16x16DClevel, 0, 15, 16, TotalCoeff, RESIDUAL_LEVEL::Intra16x16DCLevel); 1140 | } 1141 | mb_luma_4x4_non_zero_count_coeff[0] = TotalCoeff; 1142 | } 1143 | 1144 | 1145 | 1146 | //先循环外面四个8x8 1147 | for (size_t i8x8 = 0; i8x8 < 4; i8x8++) 1148 | { 1149 | 1150 | if (!transform_size_8x8_flag || !isAe)//不是8x8解码或者是cavlc 1151 | { 1152 | //在循环里面四个4x4 1153 | for (size_t i4x4 = 0; i4x4 < 4; i4x4++) 1154 | { 1155 | const size_t BlkIdx = i8x8 * 4 + i4x4;//第几个块 1156 | 1157 | 1158 | //有亮度分量解析量度分析,4*4是不区分AC和DC 1159 | if (CodedBlockPatternLuma & (1 << i8x8)) 1160 | { 1161 | //解析16*16的AC 1162 | if (mode == H264_MB_PART_PRED_MODE::Intra_16x16) 1163 | { 1164 | if (isAe) 1165 | { 1166 | cabac.residual_block_cabac(bs, sliceBase, i16x16AClevel[BlkIdx], max(0, startIdx - 1), endIdx - 1, 15, RESIDUAL_LEVEL::Intra16x16ACLevel, TotalCoeff, BlkIdx); 1167 | } 1168 | else 1169 | { 1170 | //解析16*16AC 交流分量 剩余的最多15个系数 1171 | residual_block.residual_block_cavlc(bs, i16x16AClevel[BlkIdx], max(0, startIdx - 1), endIdx - 1, 15, TotalCoeff, RESIDUAL_LEVEL::Intra16x16ACLevel, BlkIdx); 1172 | } 1173 | 1174 | } 1175 | else 1176 | { 1177 | //4*4系数,也有可能8*8 1178 | if (isAe) 1179 | { 1180 | cabac.residual_block_cabac(bs, sliceBase, level4x4[BlkIdx], startIdx, endIdx, 16, RESIDUAL_LEVEL::LumaLevel4x4, TotalCoeff, BlkIdx); 1181 | } 1182 | else 1183 | { 1184 | residual_block.residual_block_cavlc(bs, level4x4[BlkIdx], startIdx, endIdx, 16, TotalCoeff, RESIDUAL_LEVEL::LumaLevel4x4, BlkIdx); 1185 | } 1186 | } 1187 | //存储当前4x4块非0系数数目 1188 | mb_luma_4x4_non_zero_count_coeff[BlkIdx] = TotalCoeff; 1189 | } 1190 | else if (mode == H264_MB_PART_PRED_MODE::Intra_16x16) 1191 | { 1192 | //因为取走了一个直流分量所以最多15个 1193 | for (size_t i = 0; i < 15; i++) 1194 | { 1195 | i16x16AClevel[BlkIdx][i] = 0; 1196 | } 1197 | 1198 | } 1199 | else 1200 | { 1201 | for (size_t i = 0; i < 16; i++) 1202 | { 1203 | level4x4[BlkIdx][i] = 0; 1204 | } 1205 | } 1206 | 1207 | //cavlc,并且8*8模式 1208 | if (!sHeader.pps.entropy_coding_mode_flag && transform_size_8x8_flag) 1209 | { 1210 | for (size_t i = 0; i < 16; i++) 1211 | { 1212 | //直接把4*4解码的系数给level8x8 1213 | level8x8[i8x8][4 * i + i4x4] = level4x4[i8x8 * 4 + i4x4][i]; 1214 | } 1215 | //存储当前8x8块非0系数数目 1216 | mb_luma_8x8_non_zero_count_coeff[i8x8] += mb_luma_4x4_non_zero_count_coeff[i8x8 * 4 + i4x4]; 1217 | } 1218 | } 1219 | 1220 | } 1221 | else if (CodedBlockPatternLuma & (1 << i8x8)) 1222 | { 1223 | // 8*8 cabac 1224 | cabac.residual_block_cabac(bs, sliceBase, level8x8[i8x8], 4 * startIdx, 4 * endIdx + 3, 64, RESIDUAL_LEVEL::LumaLevel8x8, TotalCoeff, i8x8); 1225 | 1226 | mb_luma_8x8_non_zero_count_coeff[i8x8] = TotalCoeff; 1227 | } 1228 | else 1229 | { 1230 | for (size_t i = 0; i < 64; i++) 1231 | { 1232 | level8x8[i8x8][i] = 0; 1233 | } 1234 | } 1235 | } 1236 | 1237 | 1238 | return 0; 1239 | } 1240 | 1241 | 1242 | 1243 | 1244 | Macroblock::~Macroblock() 1245 | { 1246 | } 1247 | -------------------------------------------------------------------------------- /Macroblock.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/Macroblock.h -------------------------------------------------------------------------------- /NaluType.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/NaluType.h -------------------------------------------------------------------------------- /ParseNalu.cpp: -------------------------------------------------------------------------------- 1 | #include "ParseNalu.h" 2 | 3 | ParseNalu::ParseNalu() 4 | { 5 | forbidden_zero_bit = 0; 6 | nal_ref_idc = 0; 7 | nal_unit_type = 0; 8 | svc_extension_flag = 0; 9 | avc_3d_extension_flag = 0; 10 | /* NumBytesInNALunit = numBytesInNALunit; 11 | NumBytesInRBSP = 0;*/ 12 | IdrPicFlag = false; 13 | //m_is_malloc_mem_self = 0; 14 | 15 | /* if (NumBytesInNALunit > 0) 16 | { 17 | rbsp_byte = (uint8_t*)my_malloc(sizeof(uint8_t) * NumBytesInNALunit); 18 | RETURN_IF_FAILED(rbsp_byte == NULL, -1); 19 | memset(rbsp_byte, 0, sizeof(uint8_t) * NumBytesInNALunit); 20 | m_is_malloc_mem_self = 1; 21 | }*/ 22 | } 23 | 24 | ParseNalu& ParseNalu::operator=(const ParseNalu& src) 25 | { 26 | memcpy(this, &src, sizeof(ParseNalu)); 27 | return *this; 28 | } 29 | 30 | bool ParseNalu::getH264RbspFromNalUnit(BitStream& bs) 31 | { 32 | forbidden_zero_bit = bs.readMultiBit(1); 33 | nal_ref_idc = bs.readMultiBit(2); 34 | nal_unit_type = bs.readMultiBit(5); 35 | 36 | if (nal_unit_type == 5) 37 | { 38 | IdrPicFlag = true; 39 | } 40 | else 41 | { 42 | IdrPicFlag = false; 43 | } 44 | 45 | 46 | return false; 47 | } 48 | 49 | ParseNalu::~ParseNalu() 50 | { 51 | } 52 | -------------------------------------------------------------------------------- /ParseNalu.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/ParseNalu.h -------------------------------------------------------------------------------- /ParsePPS.cpp: -------------------------------------------------------------------------------- 1 | #include "ParsePPS.h" 2 | 3 | 4 | 5 | /// 6 | /// 关于片组的概念:一个片组由若干个宏块组成,可以按照某种规则将一个图像中的某些宏块(这些宏块可以在图像中的任意位置,不是必须相邻)划分成一个组,就是一个片组。 7 | /// 这也就是说,图像由若干“片组”组成,片组由若干“片”组成。而我们之前一直说的“图像由若干‘片’组成”,其实是针对不使用FMO的情况, 8 | /// 当不使用FMO时,一个图像中默认只有一个片组,该片组包含整个图像的所有宏块(一般都是只有一个片组)。 9 | /// 10 | ParsePPS::ParsePPS() 11 | { 12 | pic_parameter_set_id = 0; 13 | seq_parameter_set_id = 0; 14 | entropy_coding_mode_flag = 0; 15 | bottom_field_pic_order_in_frame_present_flag = 0; 16 | num_slice_groups_minus1 = 0; 17 | slice_group_map_type = 0; 18 | memset(run_length_minus1, 0, sizeof(int32_t) * 8); 19 | memset(top_left, 0, sizeof(int32_t) * 8); 20 | memset(bottom_right, 0, sizeof(int32_t) * 8); 21 | slice_group_change_direction_flag = 0; 22 | slice_group_change_rate_minus1 = 0; 23 | pic_size_in_map_units_minus1 = 0; 24 | slice_group_id = NULL; 25 | num_ref_idx_l0_default_active_minus1 = 0; 26 | num_ref_idx_l1_default_active_minus1 = 0; 27 | weighted_pred_flag = 0; 28 | weighted_bipred_idc = 0; 29 | pic_init_qp_minus26 = 0; 30 | pic_init_qs_minus26 = 0; 31 | chroma_qp_index_offset = 0; 32 | deblocking_filter_control_present_flag = 0; 33 | constrained_intra_pred_flag = false; 34 | redundant_pic_cnt_present_flag = false; 35 | transform_8x8_mode_flag = 0; 36 | pic_scaling_matrix_present_flag = false; 37 | memset(pic_scaling_list_present_flag, 0, sizeof(bool) * 12); 38 | second_chroma_qp_index_offset = 0; 39 | memset(ScalingList4x4, 0, sizeof(int32_t) * 6 * 16); 40 | memset(ScalingList8x8, 0, sizeof(int32_t) * 6 * 64); 41 | } 42 | 43 | 44 | bool ParsePPS::pic_parameter_set_rbsp(BitStream& bs, const ParseSPS spsCache[32]) 45 | { 46 | int32_t iGroup = 0; 47 | pic_parameter_set_id = bs.readUE(); //1 ue(v) 48 | //sps ID通过这个id可以找到所引用的sps结构 49 | seq_parameter_set_id = bs.readUE(); //1 ue(v) 50 | 51 | sps = spsCache[seq_parameter_set_id]; 52 | //熵编码使用的方法,不同的语法元素在不同模式选择的方式不同的 53 | //等于0,那么采用语法表中左边的描述符所指定的方法 54 | //等于1,就采用语法表中右边的描述符所指定的方法 55 | entropy_coding_mode_flag = bs.readBit(); //1 u(1) 56 | //标识位,用于表示另外条带头中的两个语法元素delta_pic_order_cnt_bottom和delta_pic_order_cn是否存在的标识。 57 | //这两个语法元素表示了某一帧的底场的POC的计算方法。 58 | bottom_field_pic_order_in_frame_present_flag = bs.readBit(); //1 u(1) 59 | 60 | 61 | //slice groups数量减去1,为0的是时候这个slice属于所有slice group,大于0被分割成多个slice group 62 | //num_slice_groups_minus1等于0,图像只有一个片组时,则不启用FMO;其他情况下,一个图像中有多个片组,这时都使用FMO。 63 | //slice group表示一帧中红快的组成方式 64 | //加1表示一个图像中的条带组数。当 num_slice_groups_minus1 等于 0 时,图像中 所有的条带属于同一个条带组。 65 | num_slice_groups_minus1 = bs.readUE(); //1 ue(v) 66 | 67 | //图像参数集应包括取值范围0-7的num_slice_groups_minus1参数,包括0与7; 68 | //片组模式 69 | if (num_slice_groups_minus1 > 0) 70 | { 71 | //MFO前面的slice内部宏块总是连续的。FMO技术通过映射表(macroblock to slice group map)决定具体每个宏块属于哪个slice groups,突破了宏块连续的限制。 72 | 73 | /*slice groups又可以按扫描顺序分成多个slice,当不使用FMO时,就相当于整个图像是一个slice groups的情形。由于各slice groups的解码也是独立的。 74 | 当码流传输错误的时候,解码端可以根据邻近正确解码的其他slice groups宏块,进行错误隐藏。*/ 75 | 76 | /*slice_group_map_type 等于 0 表示隔行扫描的条带组。 77 | slice_group_map_type 等于 1 表示一种分散的条带组映射。 78 | slice_group_map_type 等于 2 表示一个或多个前景条带组和一个残余条带组。 79 | slice_group_map_type 的值等于 3、4 和 5 表示变换的条带组。当 num_slice_groups_minus1 不等于 1 时, slice_group_map_type 不应等于3、4 或 5。 80 | slice_group_map_type 等于 6 表示对每个条带组映射单元清楚地分配一个条带组。*/ 81 | 82 | //slice_group_map_type可以指定使用哪个规则为当前图像划分片组 83 | //如果这六种默认的规则都不能满足要求,还可以定制自己的映射规则。 84 | slice_group_map_type = bs.readUE(); //1 ue(v) 85 | if (slice_group_map_type == 0) 86 | { 87 | for (iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++) 88 | { 89 | //用来指定条带组映射单元的光栅扫描顺序中分配给第 i 个条带组的连续条带组映射单 元的数目。 90 | //run_length_minus1[ i ] 的取值范围应该在0 到 PicSizeInMapUnits – 1 内(包括边界值)。 91 | run_length_minus1[iGroup] = bs.readUE(); //1 ue(v) 92 | } 93 | } 94 | else if (slice_group_map_type == 2) 95 | { 96 | for (iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) 97 | { 98 | top_left[iGroup] = bs.readUE(); //1 ue(v) 99 | bottom_right[iGroup] = bs.readUE(); //1 ue(v) 100 | } 101 | } 102 | else if (slice_group_map_type == 3 || slice_group_map_type == 4 || slice_group_map_type == 5) 103 | { 104 | slice_group_change_direction_flag = bs.readBit(); //1 u(1) 105 | //用以指明变量 SliceGroupChangeRAte 106 | slice_group_change_rate_minus1 = bs.readUE(); //1 ue(v) 107 | } 108 | else if (slice_group_map_type == 6) 109 | { 110 | pic_size_in_map_units_minus1 = bs.readUE(); //1 ue(v) 111 | //slice_group_id = (int32_t*)malloc(pic_size_in_map_units_minus1 + 1); // PicSizeInMapUnits − 1 = PicWidthInMbs * PicHeightInMapUnits - 1; 112 | slice_group_id = new uint32_t[pic_size_in_map_units_minus1 + 1]; 113 | 114 | 115 | /*slice_group_id[i] 表示光栅扫描顺序中的第 i 个条带组映射单元的一个条带组。 116 | slice_group_id[i] 语法元素的大小是 Ceil(Log2(num_slice_groups_minus1 + 1)) 比特。 117 | slice_group_id[i] 的 值 应 该 在 0 到 num_slice_groups_minus1 范围内(包括边界值)。*/ 118 | 119 | int v = h264_log2(num_slice_groups_minus1 + 1); //Ceil( Log2( num_slice_groups_minus1 + 1 ) ); 120 | for (size_t i = 0; i <= pic_size_in_map_units_minus1; i++) 121 | { 122 | slice_group_id[i] = bs.readMultiBit(v); //1 u(v) v = Ceil( Log2( num_slice_groups_minus1 + 1 ) ) bits. 123 | } 124 | } 125 | } 126 | 127 | //表示当Slice Header中的num_ref_idx_active_override_flag标识位为0时, 128 | //P/SP/B slice的语法元素num_ref_idx_l0_active_minus1和num_ref_idx_l1_active_minus1的默认值。 129 | num_ref_idx_l0_default_active_minus1 = bs.readUE(); //1 ue(v) 130 | num_ref_idx_l1_default_active_minus1 = bs.readUE(); //1 ue(v) 131 | 132 | //是否开启加权预测 133 | weighted_pred_flag = bs.readBit(); //1 u(1) 134 | 135 | //weighted_bipred_idc 等于 0 表示 B 条带应该采用默认的加权预测。 136 | //weighted_bipred_idc 等于 1 表示 B 条带应该采用具体指明的加权预测。 137 | //weighted_bipred_idc 等于 2 表示 B 条带应该采用隐含的加权预测。 138 | //weighted_bipred_idc 的值应该在0 到 2 之间(包括0 和2) 139 | weighted_bipred_idc = bs.readMultiBit(2); //1 u(2) 140 | 141 | /* 表示每个条带的SliceQPY 初始值减 26。 142 | 当解码非0 值的slice_qp_delta 时,该初始值在 条带层被修正, 143 | 并且在宏块层解码非 0 值的 mb_qp_delta 时进一步被修正。pic_init_qp_minus26 的值应该在- (26 + QpBdOffsetY ) 到 +25 之间(包括边界值)。*/ 144 | pic_init_qp_minus26 = bs.readSE(); // /* relative to 26 */ 1 se(v) 145 | //表示在 SP 或 SI 条带中的所有宏块的 SliceQSY初始值减26 146 | pic_init_qs_minus26 = bs.readSE(); // /* relative to 26 */ 1 se(v) 147 | //计算色度量化参数的偏移量值 范围:-22 --- 22 148 | chroma_qp_index_offset = bs.readSE(); //1 se(v) 149 | //slice header中是否存在去块滤波器控制相关信息 =1存在响应去块滤波器 =0没有相应信息 150 | deblocking_filter_control_present_flag = bs.readBit(); //1 u(1) 151 | //帧内预测参考数据来源 =1某一个宏块进行帧内预测的时候只能采用 152 | 153 | /*在 P 和 B 片中,帧内编码的宏块的邻近宏块可能是采用的帧间编码。 154 | 当本句法元素等于 1 时,表示帧内编码的宏块不能用帧间编码的宏块的像素作为自己的预测, 155 | 即帧内编码的宏块只能用邻近帧内编码的宏块的像素作为自己的预测;而本句法元素等于 0 时,表示不存在这种限制。*/ 156 | constrained_intra_pred_flag = bs.readBit(); //1 u(1) 157 | //等于0表示redundant_pic_cnt语法元素不会在条带头、图像参数集中指明(直接或与相应的数据分割块A关联)的数据分割块 B 和数据分割块 C 中出现。 158 | //redundant_pic_cnt_present_flag 等 于 1 表示 redundant_pic_cnt语法元素将出现在条带头、 159 | //图像参数集中指明(直接或与相应的数据分割块 A 关联的数据分割块 B 和数据分割块 C 中。 160 | redundant_pic_cnt_present_flag = bs.readBit(); //1 u(1) 161 | 162 | //当second_chroma_qp_index_offset 不存在时,默认其值等于 chroma_qp_index_offset 163 | second_chroma_qp_index_offset = chroma_qp_index_offset; 164 | 165 | if (bs.more_rbsp_data()) 166 | { 167 | //等于1表示8x8变换解码过程可能正在使用(参见 8.5 节)。transform_8x8_mode_flag 等于 0 表示未使用 8x8 变换解码过程。 168 | //当 transform_8x8_mode_flag 不存在时,默认其值 为0。 169 | transform_8x8_mode_flag = bs.readBit(); 170 | 171 | 172 | //等于 1 表示存在用来修改在序列参数集中指定的缩放比例列表的参数。 173 | //pic_scaling_matrix_present_flag 等于 0 表示用于该图像中的缩放比例列表应等于那些由序列参数集规定的。 174 | //当 pic_scaling_matrix_present_flag 不存在时,默认其值为0。 175 | //基准档次不应该出现这个元素 176 | pic_scaling_matrix_present_flag = bs.readBit(); 177 | const int length = 6 + ((sps.chroma_format_idc != 3) ? 2 : 6) * transform_8x8_mode_flag; 178 | if (pic_scaling_matrix_present_flag) 179 | { 180 | 181 | constexpr int Default_4x4_Intra[16] = { 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42 }; 182 | constexpr int Default_4x4_Inter[16] = { 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34 }; 183 | 184 | constexpr int Default_8x8_Intra[64] = 185 | { 186 | 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23, 187 | 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 188 | 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 189 | 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42, 190 | }; 191 | 192 | constexpr int Default_8x8_Inter[64] = 193 | { 194 | 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21, 195 | 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 196 | 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 197 | 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35, 198 | }; 199 | for (size_t i = 0; i < length; i++) 200 | { 201 | /*等于1表示存在缩放比例列表的语法结构并用于指定序号为i的缩放比例列 表。 202 | pic_scaling_list_present_flag[i]等于0 表示在图像参数集中不存在缩放比例列表 i 的语法结构, 203 | 并且根据 seq_scaling_matrix_present_flag 的值,应用下列条款*/ 204 | pic_scaling_list_present_flag[i] = bs.readBit(); //1 u(1) 205 | 206 | 207 | if (pic_scaling_list_present_flag[i]) 208 | { 209 | if (i < 6) 210 | { 211 | scaling_list(bs, ScalingList4x4[i], 16, UseDefaultScalingMatrix4x4Flag[i]); 212 | if (UseDefaultScalingMatrix4x4Flag[i]) 213 | { 214 | if (i == 0 || i == 1 || i == 2) 215 | { 216 | memcpy(ScalingList4x4[i], Default_4x4_Intra, sizeof(int) * 16); 217 | } 218 | else //if (i >= 3) 219 | { 220 | memcpy(ScalingList4x4[i], Default_4x4_Inter, sizeof(int) * 16); 221 | } 222 | } 223 | } 224 | else 225 | { 226 | scaling_list(bs, ScalingList8x8[i - 6], 64, UseDefaultScalingMatrix8x8Flag[i - 6]); 227 | //当计算出 useDefaultScalingMatrixFlag 等于 1 时,应推定缩放比例列表等于表 7 - 2 给出的默认的缩放比例列 表。 228 | if (UseDefaultScalingMatrix8x8Flag[i - 6]) 229 | { 230 | if (i == 6 || i == 8 || i == 10) 231 | { 232 | memcpy(ScalingList8x8[i - 6], Default_8x8_Intra, sizeof(int) * 64); 233 | } 234 | else 235 | { 236 | memcpy(ScalingList8x8[i - 6], Default_8x8_Inter, sizeof(int) * 64); 237 | } 238 | } 239 | } 240 | } 241 | else//视频序列参数集中不存在缩放比例列表 242 | { 243 | 244 | if (i < 6) 245 | { 246 | if (i == 0 || i == 1 || i == 2) 247 | { 248 | 249 | if (sps.seq_scaling_matrix_present_flag) //表7-2 B 不知道sequence-level scaling list这个是什么东西 250 | { 251 | } 252 | else//表7-2 A 253 | { 254 | memcpy(ScalingList4x4[i], Default_4x4_Intra, sizeof(int32_t) * 16); 255 | } 256 | 257 | } 258 | else 259 | { 260 | if (sps.seq_scaling_matrix_present_flag) //表7-2 B 不知道sequence-level scaling list这个是什么东西 261 | { 262 | } 263 | else//表7-2 A 264 | { 265 | memcpy(ScalingList4x4[i], Default_4x4_Inter, sizeof(int32_t) * 16); 266 | } 267 | } 268 | } 269 | else 270 | { 271 | if (i == 6 || i == 8 || i == 10) 272 | { 273 | 274 | if (sps.seq_scaling_matrix_present_flag) //表7-2 B 不知道sequence-level scaling list这个是什么东西 275 | { 276 | } 277 | else//表7-2 A 278 | { 279 | memcpy(ScalingList8x8[i - 6], Default_8x8_Intra, sizeof(int) * 64); 280 | } 281 | 282 | } 283 | else if (i == 7 || i == 9 || i == 11) 284 | { 285 | if (sps.seq_scaling_matrix_present_flag) //表7-2 B 不知道sequence-level scaling list这个是什么东西 286 | { 287 | } 288 | else//表7-2 A 289 | { 290 | memcpy(ScalingList8x8[i - 6], Default_8x8_Inter, sizeof(int) * 64); 291 | } 292 | 293 | } 294 | } 295 | } 296 | } 297 | //表示为在 QPC 值的表格中寻找 Cr 色度分量而应加到参数 QPY 和 QSY 上的偏移。second_chroma_qp_index_offset 的值应在-12 到 +12 范围内(包括边界值) 298 | second_chroma_qp_index_offset = bs.readSE(); 299 | } 300 | 301 | } 302 | 303 | return false; 304 | } 305 | 306 | ParsePPS::~ParsePPS() 307 | { 308 | if (slice_group_id) 309 | { 310 | delete[] slice_group_id; 311 | slice_group_id = NULL; 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /ParsePPS.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/ParsePPS.h -------------------------------------------------------------------------------- /ParseSEI.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/ParseSEI.cpp -------------------------------------------------------------------------------- /ParseSEI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Common.h" 4 | class ParseSEI 5 | { 6 | public: 7 | uint8_t last_payload_type_byte; 8 | uint8_t last_payload_size_byte; 9 | public: 10 | ParseSEI(); 11 | void sei_rbsp(BitStream& bs); 12 | void sei_message(BitStream& bs); 13 | void sei_payload(BitStream& bs, int payloadType, int payloadSize); 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /ParseSPS.cpp: -------------------------------------------------------------------------------- 1 | #include "ParseSPS.h" 2 | //在 SPS 和 PPS 的语法表格中,会出现以下几种描述子: 3 | // 4 | //u(n) : 无符号整数,n bit 长度 5 | //ue(v) : 无符号指数哥伦布熵编码 6 | //se(v) : 有符号指数哥伦布熵编码 7 | 8 | 9 | 10 | 11 | CHROMA_FORMAT_IDC_T chroma_format_idcs[5] = { 12 | {0, 0, -1, -1}, //单色 13 | {1, 0, 2, 2}, //420 14 | {2, 0, 2, 1}, //422 15 | {3, 0, 1, 1}, //444 16 | {3, 1, -1, -1}, //444 分开编码 17 | }; 18 | 19 | 20 | 21 | ParseSPS::ParseSPS() 22 | { 23 | profile_idc = 0; 24 | constraint_set0_flag = 0; 25 | constraint_set1_flag = 0; 26 | constraint_set2_flag = 0; 27 | constraint_set3_flag = 0; 28 | constraint_set4_flag = 0; 29 | constraint_set5_flag = 0; 30 | reserved_zero_2bits = 0; 31 | level_idc = 0; 32 | seq_parameter_set_id = 0; 33 | chroma_format_idc = 0; 34 | separate_colour_plane_flag = false; 35 | bit_depth_luma_minus8 = 0; 36 | bit_depth_chroma_minus8 = 0; 37 | qpprime_y_zero_transform_bypass_flag = false; 38 | seq_scaling_matrix_present_flag = false; 39 | memset(seq_scaling_list_present_flag, 0, sizeof(bool) * 12); 40 | log2_max_frame_num_minus4 = 0; 41 | MaxFrameNum = 0; 42 | pic_order_cnt_type = 0; 43 | log2_max_pic_order_cnt_lsb_minus4 = 0; 44 | MaxPicOrderCntLsb = 0; 45 | delta_pic_order_always_zero_flag = 0; 46 | offset_for_non_ref_pic = 0; 47 | offset_for_top_to_bottom_field = 0; 48 | num_ref_frames_in_pic_order_cnt_cycle = 0; 49 | 50 | memset(offset_for_ref_frame, 0, sizeof(int32_t) * H264_MAX_OFFSET_REF_FRAME_COUNT); 51 | ExpectedDeltaPerPicOrderCntCycle = 0; 52 | 53 | max_num_ref_frames = 0; 54 | gaps_in_frame_num_value_allowed_flag = 0; 55 | pic_width_in_mbs_minus1 = 0; 56 | pic_height_in_map_units_minus1 = 0; 57 | frame_mbs_only_flag = false; 58 | mb_adaptive_frame_field_flag = false; 59 | direct_8x8_inference_flag = 0; 60 | frame_cropping_flag = 0; 61 | frame_crop_left_offset = 0; 62 | frame_crop_right_offset = 0; 63 | frame_crop_top_offset = 0; 64 | frame_crop_bottom_offset = 0; 65 | vui_parameters_present_flag = 0; 66 | 67 | 68 | memset(ScalingList4x4, 0, sizeof(int32_t) * 6 * 16); 69 | memset(ScalingList8x8, 0, sizeof(int32_t) * 6 * 64); 70 | PicWidthInMbs = 0; 71 | PicWidthInSamplesL = 0; 72 | PicHeightInMapUnits = 0; 73 | PicSizeInMapUnits = 0; 74 | ChromaArrayType = 0; 75 | 76 | SubWidthC = 0; 77 | SubHeightC = 0; 78 | } 79 | 80 | 81 | 82 | bool ParseSPS::seq_parameter_set_data(BitStream& bs) 83 | { 84 | 85 | int ret = 0; 86 | //编码等级 87 | /* 88 | 66 Baseline 89 | 77 Main 90 | 88 Extended 91 | 100 High(FRExt) 92 | 110 High 10 (FRExt) 93 | 122 High 4:2 : 2 (FRExt) 94 | 144 High 4 : 4 : 4 (FRExt)*/ 95 | profile_idc = bs.readMultiBit(8); 96 | constraint_set0_flag = bs.readMultiBit(1); //constraint_set0_flag 0 u(1) 97 | constraint_set1_flag = bs.readMultiBit(1); //constraint_set1_flag 0 u(1) 98 | constraint_set2_flag = bs.readMultiBit(1); //constraint_set2_flag 0 u(1) 99 | constraint_set3_flag = bs.readMultiBit(1); //constraint_set3_flag 0 u(1) 100 | constraint_set4_flag = bs.readMultiBit(1); //constraint_set4_flag 0 u(1) 101 | constraint_set5_flag = bs.readMultiBit(1); //constraint_set5_flag 0 u(1) 102 | reserved_zero_2bits = bs.readMultiBit(2); //reserved_zero_2bits /* equal to 0 */ 0 u(2) 103 | level_idc = bs.readMultiBit(8); //level_idc 0 u(8) 104 | //要解码一个 Slice,需要有 SPS 和 PPS 105 | //但是码流中会有很多个SPS和PPS 106 | //如何确定依赖的是哪个SPS和PPS呢? 107 | //那就给 SPS 和 PPS 设置一个 ID 就行了 108 | seq_parameter_set_id = bs.readUE(); 109 | 110 | //chroma_format_idc = 0 单色 111 | //chroma_format_idc = 1 YUV 4 : 2 : 0 112 | //chroma_format_idc = 2 YUV 4 : 2 : 2 113 | //chroma_format_idc = 3 YUV 4 : 4 : 4 114 | //当chroma_format_idc不存在时,它将被推断为等于1(4:2:0色度格式)。 115 | //码流是什么格式 116 | chroma_format_idc = 1; 117 | //只有当 profile_idc 等于这些值的时候,chroma_format_idc 才会被显式记录, 118 | //那么如果 profile_idc 不是这些值,chroma_format_idc 就会取默认值。 119 | if (profile_idc == 100 //A.2.4 High profile //Only I, P, and B slice types may be present. 120 | || profile_idc == 110 //A.2.5(A.2.8) High 10 (Intra) profile //Only I, P, and B slice types may be present. 121 | || profile_idc == 122 //A.2.6(A.2.9) High 4:2:2 (Intra) profile //Only I, P, and B slice types may be present. 122 | || profile_idc == 244 //A.2.7(A.2.10) High 4:4:4 Predictive/Intra profile //Only I, P, B slice types may be present. 123 | || profile_idc == 44 //A.2.11 CAVLC 4:4:4 Intra profile 124 | || profile_idc == 83 //G.10.1.2.1 Scalable Constrained High profile (SVC) //Only I, P, EI, and EP slices shall be present. 125 | || profile_idc == 86 //Scalable High Intra profile (SVC) 126 | || profile_idc == 118 //Stereo High profile (MVC) 127 | || profile_idc == 128 //Multiview High profile (MVC) 128 | || profile_idc == 138 //Multiview Depth High profile (MVCD) 129 | || profile_idc == 139 // 130 | || profile_idc == 134 // 131 | || profile_idc == 135 // 132 | ) 133 | { 134 | chroma_format_idc = bs.readUE(); 135 | //当在码流中读取到 chroma_format_idc 之后separate_colour_plane_flag 136 | //当separate_colour_plane_flag不存在时,它将被推断为等于0。 137 | separate_colour_plane_flag = false; 138 | //这个语法元素在 chroma_format_idc 等于 3,也就是 YUV 444 模式的时候才有 139 | if (chroma_format_idc == 3) 140 | { 141 | /*当图像是 YUV 444 的时候,YUV 三个分量的比重是相同的,那么就有两种编码方式了。 142 | 第一种,就是和其他格式一样,让 UV 分量依附在 Y 分量上;第二种,就是把 UV 和 Y 分开,独立出来。 143 | separate_colour_plane_flag 这个值默认是 0,表示 UV 依附于 Y,和 Y 一起编码, 144 | 如果 separate_colour_plane_flag 变成 1,则表示 UV 与 Y 分开编码。 145 | 而对于分开编码的模式,我们采用和单色模式一样的规则。*/ 146 | separate_colour_plane_flag = bs.readBit(); 147 | } 148 | //是指亮度队列样值的比特深度以及亮度量化参数范围的取值偏移 QpBdOffsetY 149 | bit_depth_luma_minus8 = bs.readUE(); 150 | //与bit_depth_luma_minus8类似,只不过是针对色度的 151 | bit_depth_chroma_minus8 = bs.readUE(); 152 | //等于1是指当 QP'Y 等于 0 时变换系数解码过程的变换旁路操作和图 像构建过程将会在第8.5 节给出的去块效应滤波过程之前执行。 153 | //qpprime_y_zero_transform_bypass_flag 等于0 是指变换系数解码过程和图像构建过程在去块效应滤波过程之前执行而不使用变换旁路操作。 154 | //当 qpprime_y_zero_transform_bypass_flag 没有特别指定时,应推定其值为0。 155 | qpprime_y_zero_transform_bypass_flag = bs.readBit(); 156 | //缩放标志位 157 | seq_scaling_matrix_present_flag = bs.readBit(); 158 | 159 | 160 | const size_t length = (this->chroma_format_idc != 3) ? 8 : 12; 161 | if (this->seq_scaling_matrix_present_flag) 162 | { 163 | constexpr int Default_4x4_Intra[16] = { 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42 }; 164 | constexpr int Default_4x4_Inter[16] = { 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34 }; 165 | 166 | constexpr int Default_8x8_Intra[64] = 167 | { 168 | 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23, 169 | 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 170 | 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 171 | 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42, 172 | }; 173 | 174 | constexpr int Default_8x8_Inter[64] = 175 | { 176 | 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21, 177 | 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 178 | 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 179 | 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35, 180 | }; 181 | for (size_t i = 0; i < length; i++) 182 | { 183 | this->seq_scaling_list_present_flag[i] = bs.readBit(); //seq_scaling_list_present_flag[ i ] 0 u(1) 184 | if (this->seq_scaling_list_present_flag[i]) 185 | { 186 | if (i < 6) 187 | { 188 | scaling_list(bs, ScalingList4x4[i], 16, UseDefaultScalingMatrix4x4Flag[i]); 189 | 190 | //当计算出 useDefaultScalingMatrixFlag 等于 1 时,应推定缩放比例列表等于表 7 - 2 给出的默认的缩放比例列 表。 191 | if (UseDefaultScalingMatrix4x4Flag[i]) 192 | { 193 | if (i == 0 || i == 1 || i == 2) 194 | { 195 | memcpy(ScalingList4x4[i], Default_4x4_Intra, sizeof(int) * 16); 196 | } 197 | else //if (i >= 3) 198 | { 199 | memcpy(ScalingList4x4[i], Default_4x4_Inter, sizeof(int) * 16); 200 | } 201 | } 202 | } 203 | else 204 | { 205 | scaling_list(bs, ScalingList8x8[i - 6], 64, UseDefaultScalingMatrix8x8Flag[i - 6]); 206 | 207 | //当计算出 useDefaultScalingMatrixFlag 等于 1 时,应推定缩放比例列表等于表 7 - 2 给出的默认的缩放比例列 表。 208 | if (UseDefaultScalingMatrix8x8Flag[i - 6]) 209 | { 210 | if (i == 6 || i == 8 || i == 10) 211 | { 212 | memcpy(ScalingList8x8[i - 6], Default_8x8_Intra, sizeof(int) * 64); 213 | } 214 | else 215 | { 216 | memcpy(ScalingList8x8[i - 6], Default_8x8_Inter, sizeof(int) * 64); 217 | } 218 | } 219 | } 220 | } 221 | else//视频序列参数集中不存在缩放比例列表 222 | { 223 | //表7-2的规定 集 A 224 | if (i < 6) 225 | { 226 | if (i == 0 || i == 1 || i == 2) 227 | { 228 | memcpy(ScalingList4x4[i], Default_4x4_Intra, sizeof(int) * 16); 229 | } 230 | else 231 | { 232 | memcpy(ScalingList4x4[i], Default_4x4_Inter, sizeof(int) * 16); 233 | } 234 | } 235 | else 236 | { 237 | if (i == 6 || i == 8 || i == 10) 238 | { 239 | memcpy(ScalingList8x8[i - 6], Default_8x8_Intra, sizeof(int) * 64); 240 | } 241 | else if (i == 7 || i == 9 || i == 11) 242 | { 243 | memcpy(ScalingList8x8[i - 6], Default_8x8_Inter, sizeof(int) * 64); 244 | } 245 | } 246 | } 247 | 248 | } 249 | } 250 | 251 | 252 | } 253 | 254 | //这个句法元素主要是为读取另一个句法元素 frame_num 服务的,frame_num 是最重要的句法元素之一,它标识所属图像的解码顺序 。 255 | //这个句法元素同时也指明了frame_num 的所能达到的最大值:MaxFrameNum = 2*exp( log2_max_frame_num_minus4 + 4 ) 256 | //最大帧率 257 | log2_max_frame_num_minus4 = bs.readUE();//0 - 12 258 | MaxFrameNum = std::pow(2, log2_max_frame_num_minus4 + 4); 259 | //指明了 poc (picture order count) 的编码方法,poc 标识图像的播放顺序。 260 | //由poc 可以由 frame-num 通过映射关系计算得来,也可以索性由编码器显式地传送。 261 | //是指解码图像顺序的计数方法(如 8.2.1 节所述)。pic_order_cnt_type 的取值范围是0 到 2(包括0 和2)。 262 | pic_order_cnt_type = bs.readUE(); 263 | 264 | if (this->pic_order_cnt_type == 0) 265 | { 266 | this->log2_max_pic_order_cnt_lsb_minus4 = bs.readUE(); //取值范围应该在0-12 267 | MaxPicOrderCntLsb = std::pow(2, log2_max_pic_order_cnt_lsb_minus4 + 4); 268 | } 269 | else if (this->pic_order_cnt_type == 1) 270 | { 271 | this->delta_pic_order_always_zero_flag = bs.readBit(); //delta_pic_order_always_zero_flag 0 u(1) 272 | //用于非参考图像的图像顺序号 273 | this->offset_for_non_ref_pic = bs.readSE(); // 274 | this->offset_for_top_to_bottom_field = bs.readSE(); //offset_for_top_to_bottom_field 0 se(v) 275 | this->num_ref_frames_in_pic_order_cnt_cycle = bs.readUE(); //num_ref_frames_in_pic_order_cnt_cycle 0 ue(v) 276 | 277 | for (size_t i = 0; i < this->num_ref_frames_in_pic_order_cnt_cycle; i++) 278 | { 279 | this->offset_for_ref_frame[i] = bs.readSE(); //offset_for_ref_frame[ i ] 0 se(v) 280 | ExpectedDeltaPerPicOrderCntCycle += offset_for_ref_frame[i]; 281 | } 282 | 283 | 284 | 285 | 286 | 287 | } 288 | 289 | //最大允许多少个参考帧 取值范围应该在 0 到 MaxDpbSize 290 | //MaxDpbSize = Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 384 ), 16 ) 291 | max_num_ref_frames = bs.readUE(); 292 | //是否允许出现不连续的情况,跳帧 293 | gaps_in_frame_num_value_allowed_flag = bs.readBit(); 294 | //以红快为单位的宽度 295 | pic_width_in_mbs_minus1 = bs.readUE(); 296 | //这里要考虑帧编码和场编码的问题,帧编码是红快高度 297 | pic_height_in_map_units_minus1 = bs.readUE(); 298 | //是否为帧编码 299 | frame_mbs_only_flag = bs.readBit(); 300 | 301 | 302 | if (!frame_mbs_only_flag) 303 | { 304 | //采用了场编码的情况下 305 | //是否采用红快级别帧场自适应的问题 ,是否可以在帧编码和场编码相互切换 //帧场自适应 306 | mb_adaptive_frame_field_flag = bs.readBit(); 307 | printError("不支持场编码 frame_mbs_only_flag"); 308 | exit(1); 309 | 310 | } 311 | 312 | //B_Skip、B_Direct_16x16 和 B_Direct_8x8 亮度运动矢量 的计算过程使用的方法 313 | direct_8x8_inference_flag = bs.readBit(); 314 | //图片进行裁剪的偏移量 如果为0那么就不需要裁剪 315 | frame_cropping_flag = bs.readBit(); 316 | 317 | if (frame_cropping_flag) 318 | { 319 | frame_crop_left_offset = bs.readUE(); //frame_crop_left_offset 0 ue(v) 320 | frame_crop_right_offset = bs.readUE(); //frame_crop_right_offset 0 ue(v) 321 | frame_crop_top_offset = bs.readUE(); //frame_crop_top_offset 0 ue(v) 322 | frame_crop_bottom_offset = bs.readUE(); //frame_crop_bottom_offset 0 ue(v) 323 | } 324 | vui_parameters_present_flag = bs.readBit(); 325 | 326 | uint8_t fps = 25; 327 | if (vui_parameters_present_flag) 328 | { 329 | //视频渲染的一些辅助信息 330 | vui_parameters(bs); 331 | 332 | if (timing_info_present_flag) 333 | { 334 | fps = time_scale / num_units_in_tick; 335 | 336 | //if (fixed_frame_rate_flag) 337 | { 338 | fps /= 2.0; 339 | } 340 | } 341 | 342 | //todo 343 | } 344 | 345 | 346 | PicWidthInMbs = pic_width_in_mbs_minus1 + 1; 347 | PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1; 348 | 349 | 350 | 351 | //总共有多少宏块 352 | PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits; 353 | //如果是场编码要*2 354 | //FrameHeightInMbs = (2 - frame_mbs_only_flag) * PicHeightInMapUnits; 355 | 356 | //表示UV依附于Y 和Y一起编码,separate_colour_plane_flag=1则表示 UV 与 Y 分开编码。 357 | if (!separate_colour_plane_flag) { 358 | ChromaArrayType = chroma_format_idc; 359 | } 360 | else { 361 | ChromaArrayType = 0; 362 | } 363 | //亮度深度,偏移 364 | BitDepthY = 8 + bit_depth_luma_minus8; 365 | QpBdOffsetY = 6 * bit_depth_luma_minus8; 366 | //色度深度,偏移 367 | BitDepthC = 8 + bit_depth_chroma_minus8; 368 | QpBdOffsetC = 6 * bit_depth_chroma_minus8; 369 | 370 | 371 | /*如果chroma_format_idc的值等于0(单色),则MbWidthC和MbHeightC均为0(单色视频没有色度 阵列)。 372 | 否则,MbWidthC和MbHeightC按下式得到: 373 | MbWidthC = 16 / SubWidthC 374 | MbHeightC = 16 / SubHeightC*/ 375 | if (chroma_format_idc == 0 || separate_colour_plane_flag) 376 | { 377 | MbWidthC = 0; 378 | MbHeightC = 0; 379 | } 380 | else 381 | { 382 | 383 | int index = chroma_format_idc; 384 | //separate_colour_plane_flag=0一起编码,=1分开编码 385 | if (chroma_format_idc == 3 && separate_colour_plane_flag) 386 | { 387 | index = 4; 388 | } 389 | //变量 SubWidthC 和 SubHeightC 在表 6-1 中规定 390 | /*在4 : 2 : 0 样点中,两个色度阵列的高度和宽度均为亮度阵列的一半。 391 | 在4 : 2 : 2 样点中,两个色度阵列的高度等于亮度阵列的高度,宽度为亮度阵列的一半。 392 | 在4 : 4 : 4 样点中,两个色度阵列的高度和宽度与亮度阵列的相等。*/ 393 | 394 | 395 | //{0, 0, -1, -1}, //单色 396 | //{ 1, 0, 2, 2 }, //420 397 | //{ 2, 0, 2, 1 }, //422 398 | //{ 3, 0, 1, 1 }, //444 399 | //{ 3, 1, -1, -1 }, //444 分开编码 400 | SubWidthC = chroma_format_idcs[index].SubWidthC; 401 | SubHeightC = chroma_format_idcs[index].SubHeightC; 402 | /*样点是以宏块为单元进行处理的。每个宏块中的样点阵列的高和宽均为 16 个样点。 403 | 变量 MbWidthC 和 MbHeightC 分别规定了每个宏块中色度阵列的宽度和高度*/ 404 | MbWidthC = 16 / SubWidthC; 405 | MbHeightC = 16 / SubHeightC; 406 | 407 | } 408 | 409 | 410 | //亮度分量的图像宽度 411 | PicWidthInSamplesL = PicWidthInMbs * 16; 412 | //亮度分量的图像高度 413 | PicHeightInSamplesL = PicHeightInMapUnits * 16; 414 | 415 | 416 | //色度分量的图像宽度 417 | PicWidthInSamplesC = PicWidthInMbs * MbWidthC; 418 | //色度分量的图像高度 419 | PicHeightInSamplesC = PicHeightInMapUnits * MbHeightC; 420 | 421 | 422 | 423 | 424 | return true; 425 | 426 | 427 | } 428 | 429 | 430 | 431 | //Table E - 1 – 样品长宽比指标的含义 432 | 433 | enum Sample_aspect_ratio { 434 | Extended_SAR = 255 435 | }; 436 | int ParseSPS::vui_parameters(BitStream& bs) 437 | { 438 | 439 | bool aspect_ratio_info_present_flag = bs.readBit(); 440 | 441 | if (aspect_ratio_info_present_flag) 442 | { 443 | /*Aspect_ratio_idc指定luma样本的样本长宽比值。 表E - 1显示了代码的含义。 444 | 当aspect_ratio_idc表示Extended_SAR时,样本长宽比用sar_width和sar_height表示。 445 | 当aspect_ratio_idc语法元素不存在时,可以推断aspect_ratio_idc的值为0 446 | */ 447 | aspect_ratio_idc = bs.readMultiBit(8); 448 | 449 | if (aspect_ratio_idc == Extended_SAR) 450 | { 451 | //Sar_width和sar_height应相对素数或等于0。 452 | //当aspect_ratio_idc等于0或sar_width等于0或sar_height等于0时,样本长宽比应被视为本推荐|国际标准未指定 453 | sar_width = bs.readMultiBit(16); 454 | sar_height = bs.readMultiBit(16); 455 | } 456 | } 457 | 458 | bool overscan_info_present_flag = bs.readBit(); 459 | if (overscan_info_present_flag) 460 | { 461 | //Overscan_appropriate_flag = 1表示经过裁剪的解码图片输出适合超扫描显示。 462 | //Overscan_appropriate_flag = 0表示经过裁剪的解码图片输出包含了从图片裁剪矩形到边缘的整个区域的重要信息,因此经过裁剪的解码图片输出不应该使用超扫描显示。 463 | //相反,它们应该使用显示区域和剪切矩形之间的精确匹配或使用下扫描来显示。 464 | overscan_appropriate_flag = bs.readBit(); 465 | } 466 | 467 | bool video_signal_type_present_flag = bs.readBit(); 468 | 469 | if (video_signal_type_present_flag) 470 | { 471 | //video_format表示表E-2中指定的图片的表示形式,然后根据本建议|国际标准进行编码。 472 | //当video_format语法元素不存在时,可以推断出video_format的值等于5。 473 | 474 | /* 475 | 表 E-2 476 | 0 Component 477 | 1 PAL 478 | 2 NTSC 479 | 3 SECAM 480 | 4 MAC 481 | 5 Unspecified video 482 | */ 483 | video_format = bs.readMultiBit(3); 484 | 485 | //video_full_range_flag 表示范围 486 | /* 487 | If video_full_range_flag is equal to 0, 488 | Y = Round( 219 * E’Y + 16 ) 489 | Cb = Round( 224 * E’PB + 128 ) 490 | Cr = Round( 224 * E’PR + 128 ) 491 | - Otherwise (video_full_range_flag is equal to 1), 492 | Y = Round( 255 * E’Y ) 493 | Cb = Round( 255 * E’PB + 128 ) 494 | Cr = Round( 255 * E’PR + 128 ) 495 | */ 496 | video_full_range_flag = bs.readBit(); 497 | bool colour_description_present_flag = bs.readBit(); 498 | if (colour_description_present_flag) 499 | { 500 | colour_primaries = bs.readMultiBit(8); 501 | transfer_characteristics = bs.readMultiBit(8); 502 | matrix_coefficients = bs.readMultiBit(8); 503 | } 504 | } 505 | 506 | bool chroma_loc_info_present_flag = bs.readBit(); 507 | 508 | if (chroma_loc_info_present_flag) 509 | { 510 | chroma_sample_loc_type_top_field = bs.readUE(); 511 | chroma_sample_loc_type_bottom_field = bs.readUE(); 512 | } 513 | 514 | 515 | timing_info_present_flag = bs.readBit(); 516 | 517 | if (timing_info_present_flag) 518 | { 519 | //一个增量所用的time units 520 | num_units_in_tick = bs.readMultiBit(32); 521 | //即将1秒分成多少份 522 | time_scale = bs.readMultiBit(32); 523 | 524 | //fixed_frame_rate_flag为1时,两个连续图像的HDR输出时间频率为单位,获取的fps是实际的2倍 525 | fixed_frame_rate_flag = bs.readBit(); 526 | } 527 | 528 | bool nal_hrd_parameters_present_flag = bs.readBit(); 529 | if (nal_hrd_parameters_present_flag) 530 | { 531 | //hrd_parameters( ) 532 | } 533 | 534 | bool vcl_hrd_parameters_present_flag = bs.readBit(); 535 | if (vcl_hrd_parameters_present_flag) 536 | { 537 | //hrd_parameters() 538 | } 539 | 540 | if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) 541 | { 542 | low_delay_hrd_flag = bs.readBit(); 543 | } 544 | 545 | bool pic_struct_present_flag = bs.readBit(); 546 | 547 | bool bitstream_restriction_flag = bs.readBit(); 548 | if (bitstream_restriction_flag) 549 | { 550 | bool motion_vectors_over_pic_boundaries_flag = bs.readBit(); 551 | uint32_t max_bytes_per_pic_denom = bs.readUE(); 552 | uint32_t max_bits_per_mb_denom = bs.readUE(); 553 | uint32_t log2_max_mv_length_horizontal = bs.readUE(); 554 | uint32_t log2_max_mv_length_vertical = bs.readUE(); 555 | uint32_t num_reorder_frames = bs.readUE(); 556 | uint32_t max_dec_frame_buffering = bs.readUE(); 557 | } 558 | return 0; 559 | } 560 | 561 | ParseSPS::~ParseSPS() 562 | { 563 | } 564 | -------------------------------------------------------------------------------- /ParseSPS.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/ParseSPS.h -------------------------------------------------------------------------------- /ParseSlice.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/ParseSlice.h -------------------------------------------------------------------------------- /Picture.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/Picture.cpp -------------------------------------------------------------------------------- /Picture.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/Picture.h -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # h264- 2 | h264解码器 3 | -------------------------------------------------------------------------------- /ResidualBlockCavlc.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/ResidualBlockCavlc.cpp -------------------------------------------------------------------------------- /ResidualBlockCavlc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Common.h" 3 | //#include "CalvcTable.h" 4 | 5 | 6 | 7 | class ParseSlice; 8 | class ResidualBlockCavlc 9 | { 10 | 11 | 12 | public: 13 | ResidualBlockCavlc(ParseSlice* slice); 14 | 15 | bool residual_block_cavlc(BitStream& bs, int* coeffLevel, int startIdx, int endIdx, uint32_t maxNumCoeff, int& TotalCoeff, RESIDUAL_LEVEL residualLevel, size_t BlkIdx = 0); 16 | 17 | int getNumberCurrent(RESIDUAL_LEVEL residualLevel, size_t BlkIdx); 18 | 19 | private: 20 | int getNumCoeffAndTrailingOnes(int nC, uint16_t coeff_token, int& coeff_token_length, int& TrailingOnes, int& TotalCoeff); 21 | int getTotalZeros(BitStream& bs, uint32_t TotalCoeff, uint32_t maxNumCoeff); 22 | int getRunbefore(BitStream& bs, uint32_t zerosLeft); 23 | int findTable(BitStream& bs, int maxNumber, int* lengthTable, int* codeTable); 24 | 25 | int findChromaAC_nA_nB(const int CbCr, const int BlkIdx, int& nA, int& nB, bool& availableLeft, bool& availableTop); 26 | public: 27 | ParseSlice* sliceBase; 28 | bool trailing_ones_sign_flag; 29 | 30 | 31 | 32 | 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /SliceData.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/SliceData.cpp -------------------------------------------------------------------------------- /SliceData.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/SliceData.h -------------------------------------------------------------------------------- /SliceHeader.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/SliceHeader.cpp -------------------------------------------------------------------------------- /SliceHeader.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/SliceHeader.h -------------------------------------------------------------------------------- /data/baseline.264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/data/baseline.264 -------------------------------------------------------------------------------- /data/bnalu.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/data/bnalu.bin -------------------------------------------------------------------------------- /data/test.264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/data/test.264 -------------------------------------------------------------------------------- /h264.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30907.101 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h264", "h264.vcxproj", "{48C63945-2ABE-4DA2-8883-D5377B8075FD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Debug|x64.ActiveCfg = Debug|x64 17 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Debug|x64.Build.0 = Debug|x64 18 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Debug|x86.ActiveCfg = Debug|Win32 19 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Debug|x86.Build.0 = Debug|Win32 20 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Release|x64.ActiveCfg = Release|x64 21 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Release|x64.Build.0 = Release|x64 22 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Release|x86.ActiveCfg = Release|Win32 23 | {48C63945-2ABE-4DA2-8883-D5377B8075FD}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {6BF888C9-2979-4CC0-85A7-783DFC9CA6D9} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /h264.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 16.0 66 | Win32Proj 67 | {48c63945-2abe-4da2-8883-d5377b8075fd} 68 | h264 69 | 10.0 70 | 71 | 72 | 73 | Application 74 | true 75 | v142 76 | Unicode 77 | 78 | 79 | Application 80 | false 81 | v142 82 | true 83 | Unicode 84 | 85 | 86 | Application 87 | true 88 | v142 89 | Unicode 90 | 91 | 92 | Application 93 | false 94 | v142 95 | true 96 | Unicode 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | true 118 | 119 | 120 | false 121 | 122 | 123 | true 124 | 125 | 126 | false 127 | 128 | 129 | 130 | Level3 131 | true 132 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | 135 | 136 | Console 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | Level3 144 | true 145 | true 146 | true 147 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 148 | true 149 | 150 | 151 | Console 152 | true 153 | true 154 | true 155 | 156 | 157 | 158 | 159 | Level3 160 | true 161 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 162 | true 163 | 164 | 165 | Console 166 | true 167 | true 168 | 169 | 170 | 171 | 172 | Level3 173 | true 174 | true 175 | true 176 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 177 | true 178 | 179 | 180 | Console 181 | true 182 | true 183 | true 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /h264.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 源文件 26 | 27 | 28 | 源文件 29 | 30 | 31 | 源文件 32 | 33 | 34 | 源文件 35 | 36 | 37 | 源文件 38 | 39 | 40 | 源文件 41 | 42 | 43 | 源文件 44 | 45 | 46 | 源文件 47 | 48 | 49 | 源文件 50 | 51 | 52 | 源文件 53 | 54 | 55 | 源文件 56 | 57 | 58 | 源文件 59 | 60 | 61 | 源文件 62 | 63 | 64 | 源文件 65 | 66 | 67 | 源文件 68 | 69 | 70 | 71 | 72 | 头文件 73 | 74 | 75 | 头文件 76 | 77 | 78 | 头文件 79 | 80 | 81 | 头文件 82 | 83 | 84 | 头文件 85 | 86 | 87 | 头文件 88 | 89 | 90 | 头文件 91 | 92 | 93 | 头文件 94 | 95 | 96 | 头文件 97 | 98 | 99 | 头文件 100 | 101 | 102 | 头文件 103 | 104 | 105 | 头文件 106 | 107 | 108 | 头文件 109 | 110 | 111 | 头文件 112 | 113 | 114 | 头文件 115 | 116 | 117 | 头文件 118 | 119 | 120 | 头文件 121 | 122 | 123 | 头文件 124 | 125 | 126 | 头文件 127 | 128 | 129 | 130 | 131 | 资源文件 132 | 133 | 134 | -------------------------------------------------------------------------------- /h264.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "AnnexBReader.h" 2 | 3 | //void printStack(void) 4 | //{ 5 | // unsigned int i; 6 | // void* stack[100]; 7 | // unsigned short frames; 8 | // SYMBOL_INFO* symbol; 9 | // HANDLE process; 10 | // 11 | // process = GetCurrentProcess(); 12 | // 13 | // SymInitialize(process, NULL, TRUE); 14 | // 15 | // frames = CaptureStackBackTrace(0, 100, stack, NULL); 16 | // symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); 17 | // symbol->MaxNameLen = 255; 18 | // symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 19 | // 20 | // for (i = 0; i < frames; i++) 21 | // { 22 | // SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); 23 | // 24 | // printf("%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address); 25 | // } 26 | // 27 | // free(symbol); 28 | //} 29 | 30 | int main() 31 | { 32 | AnnexBReader reader; 33 | bool isOpen = reader.open("./data/MP4test.h264"); 34 | 35 | return EXIT_SUCCESS; 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /xf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xfxhn/h264/729865671058a5e118e096bb04a6d11318dee027/xf --------------------------------------------------------------------------------