-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathimageio_hevc.c
More file actions
1722 lines (1369 loc) · 101 KB
/
imageio_hevc.c
File metadata and controls
1722 lines (1369 loc) · 101 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
// HEVC grayscale image compress function (from memory to memory)
int HEVCImageEncoder ( // return HEVC stream length (in bytes)
unsigned char *pbuffer, // buffer to save HEVC stream
const unsigned char *img, // 2-D array in 1-D buffer, height=ysz, width=xsz. Input the image to be compressed.
unsigned char *img_rcon, // 2-D array in 1-D buffer, height=ysz, width=xsz. The HEVC encoder will save the reconstructed image here.
int *ysz, // point to image height, will be modified (clip to a multiple of CTU_SZ)
int *xsz, // point to image width , will be modified (clip to a multiple of CTU_SZ)
const int qpd6 // quant value, must be 0~4. The larger, the higher compression ratio, but the lower quality.
);
// return: 0 : success 1 : failed
int writeHEVCImageFile (const char *p_filename, const uint8_t *p_buf, int is_rgb, uint32_t height, uint32_t width, int qpd6) {
int hevc_size;
unsigned char *p_hevc = (unsigned char*)malloc(2*(width+32)*(height+32)+65536 + ((width+32)*(height+32)+1048576)*2);
unsigned char *p_img_orig = p_hevc + 2*(width+32)*(height+32)+65536;
unsigned char *p_img_rcon = p_img_orig + ((width+32)*(height+32)+1048576);
if (p_hevc == NULL)
return 1;
if (is_rgb) {
size_t i;
for (i=0; i<(size_t)height*width; i++) {
p_img_orig[i] = p_buf[i*3+1];
}
printf(" warning: this HEVCencoder currently only support gray 8-bit image instead of RGB image. Only compress the green channel of this image.\n");
} else {
size_t i;
for (i=0; i<(size_t)height*width; i++) {
p_img_orig[i] = p_buf[i];
}
}
{
int h = (int)height;
int w = (int)width;
hevc_size = HEVCImageEncoder(p_hevc, p_img_orig, p_img_rcon, &h, &w, qpd6);
if (hevc_size<=0 || h<=0 || w<=0) {
free(p_hevc);
return 1;
}
}
{
int failed=1;
FILE *fp = fopen(p_filename, "wb");
if (fp) {
failed = ((size_t)hevc_size != fwrite(p_hevc, sizeof(uint8_t), (size_t)hevc_size, fp));
fclose(fp);
}
free(p_hevc);
return failed;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HEVC grayscale image compressor
//
// Copyright : github.com/WangXuan95
//
// A light-weight H.265/HEVC intra frame encoder for monochrome (grayscale) still image compression.
// This code may be the most understandable HEVC implementation in the world.
//
//
// definations of abbr. :
//
// pix : pixel
// coef : coefficient
//
// hor : horizontal
// ver : vertical
// sz : size
// pos : position
//
// orig : original
// pred : predicted
// quat : quantized
// rcon : reconstructed
//
// img : image
// CTU : code tree unit (32x32)
// CU : code unit (8x8, 16x16, or 32x32)
// blk : block
// CG : coefficient group (4x4)
// pix : pixel
//
// bla : border on left-above (which contains 1 pixel)
// blb : border on left and left-below (which contains 2*CU-size pixels)
// bar : border on above and above-right (which contains 2*CU-size pixels)
// Note: If the prefix "u" is added to the above abbr., it means "unfiltered", and the prefix "f" means "filtered". For example: ublb, fblb
// pmode : prediction mode (0~34)
//
// rdcost: RD-cost (Rate-Distortion Cost)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// data type definations. This HEVC encoder will only use these data types
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef unsigned char BOOL; // unsigned integer, 8-bit, used as boolean: 0=false 1=true
typedef unsigned char UI8; // unsigned integer, 8-bit
typedef int I32; // signed integer, must be at least 32 bits
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// common used definations and functions
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef NULL
#define NULL 0
#endif
#define MAX_YSZ 8192 // max image height
#define MAX_XSZ 8192 // max image width
#define CTU_SZ 32 // CTU : 32x32
#define MIN_CU_SZ 8 // minimal CU : 8x8
#define MIN_TU_SZ 4 // minimal TU : 4x4
#define GETnTU(i) ((i) / MIN_TU_SZ)
#define nTUinCTU GETnTU(CTU_SZ) // number of rows/colums of minimal TU in a CTU , =8
#define nTUinROW GETnTU(MAX_XSZ) // number of columns of minimal TU in image row
#define CG_SZ 4 // coefficient group (CG) size
#define CG_SZxSZ (CG_SZ*CG_SZ)
#define GETnCG(i) ((i) / CG_SZ) // input a pixel vertical or horizontal position, output its CG's vertical or horizontal position
#define GETn_inCG(i) ((i) % CG_SZ) // input a pixel vertical or horizontal position, output its vertical or horizontal position in the CG
#define GETi_inCG(i) ((i) % CG_SZxSZ) // input a pixel scan index, output its scan index in the CG
typedef enum {
SCAN_TYPE_DIAG = 0, // CG scan order : diag
SCAN_TYPE_HOR = 1, // CG scan order : horizontal
SCAN_TYPE_VER = 2 // CG scan order : vertical
} ScanType ;
typedef enum {
CH_Y = 0, // Y : luma channel
CH_U = 1, // U : chroma-blue channel (Cb)
CH_V = 2 // V : chroma-red channel (Cr)
} ChannelType ;
#define PMODE_PLANAR 0 // planar prediction mode
#define PMODE_DC 1 // DC prediction mode
#define PMODE_DEG45 2 // angular prediction mode : up right ( 45 degree)
#define PMODE_HOR 10 // angular prediction mode : right ( 90 degree)
#define PMODE_DEG135 18 // angular prediction mode : down right (135 degree)
#define PMODE_VER 26 // angular prediction mode : down (180 degree)
#define PMODE_DEG225 34 // angular prediction mode : down left (225 degree)
#define PMODE_COUNT 35 // there are total 35 prediction modes (0~34)
#define I32_MAX_VALUE ((I32)(0x7fffffff))
#define PIX_MIN_VALUE ((UI8)( 0))
#define PIX_MAX_VALUE ((UI8)(255))
#define PIX_MIDDLE_VALUE ((UI8)(128))
#define COEF_MIN_VALUE ((I32)(-32768))
#define COEF_MAX_VALUE ((I32)( 32767))
#define ABS(x) ( ((x) < 0) ? (-(x)) : (x) ) // get absolute value
#define MAX(x, y) ( ((x)<(y)) ? (y) : (x) ) // get the minimum value of x, y
#define MIN(x, y) ( ((x)<(y)) ? (x) : (y) ) // get the maximum value of x, y
#define CLIP(x, min, max) ( MIN(MAX((x), (min)), (max)) ) // clip x between min~max
#define PIX_CLIP(x) ( (UI8)CLIP((x), PIX_MIN_VALUE, PIX_MAX_VALUE) ) // clip x between 0~255 , and convert it to UI8 type (pixel type)
#define COEF_CLIP(x) ( (I32)CLIP((x), COEF_MIN_VALUE, COEF_MAX_VALUE) ) // clip x between -32768~32767 (HEVC-specified coefficient range)
#define GET2D(ptr, ysz, xsz, y, x) ( *( (ptr) + (xsz)*CLIP((y),0,(ysz)-1) + CLIP((x),0,(xsz)-1) ) ) // regard a 1-D array (ptr) as a 2-D array, and get value from position (y,x)
#define BLK_SET(sz, value, dst) { \
I32 i, j; \
for (i=0; i<(sz); i++) \
for (j=0; j<(sz); j++) \
(dst)[i][j] = (value); \
}
#define BLK_COPY(sz, src, dst) { \
I32 i, j; \
for (i=0; i<(sz); i++) \
for (j=0; j<(sz); j++) \
(dst)[i][j] = (src)[i][j]; \
}
#define BLK_SUB(sz, src1, src2, dst) { \
I32 i, j; \
for (i=0; i<(sz); i++) \
for (j=0; j<(sz); j++) \
(dst)[i][j] = ((I32)(src1)[i][j]) - (src2)[i][j]; \
}
#define BLK_ADD_CLIP_TO_PIX(sz, src1, src2, dst) { \
I32 i, j; \
for (i=0; i<(sz); i++) \
for (j=0; j<(sz); j++) \
(dst)[i][j] = PIX_CLIP( (src1)[i][j] + (src2)[i][j] ); \
}
BOOL blkNotAllZero (const I32 sz, const I32 src [][CTU_SZ]) {
I32 i, j;
for (i=0; i<sz; i++)
for (j=0; j<sz; j++)
if (src[i][j] != 0)
return 1;
return 0;
}
// calculate SSE (sum of squared error) as distortion, the result will be save on result
#define CALC_BLK_SSE(sz, src1, src2, result) { \
I32 i, j, diff; \
(result) = 0; \
for (i=0; i<(sz); i++) { \
for (j=0; j<(sz); j++) { \
diff = ABS( (I32)(src1)[i][j] - (src2)[i][j] ) ; \
(result) += diff * diff; \
} \
} \
}
static I32 calcRDcost (I32 qpd6, I32 dist, I32 bits) { // calculate RD-cost, avoid overflow from 32-bit integer
static const I32 RDCOST_WEIGHT_DIST [] = {11, 11, 11, 5, 1};
static const I32 RDCOST_WEIGHT_BITS [] = { 1, 4, 16, 29, 23};
const I32 weight1 = RDCOST_WEIGHT_DIST[qpd6];
const I32 weight2 = RDCOST_WEIGHT_BITS[qpd6];
const I32 cost1 = (I32_MAX_VALUE / weight1 <= dist) ? I32_MAX_VALUE : weight1 * dist; // avoiding multiply overflow
const I32 cost2 = (I32_MAX_VALUE / weight2 <= bits) ? I32_MAX_VALUE : weight2 * bits; // avoiding multiply overflow
return (I32_MAX_VALUE - cost1 <= cost2) ? I32_MAX_VALUE : cost1 + cost2; // avoiding add overflow
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// prediction
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// description : get border pixels (ubla, ublb, ubar) from the reconstructed image for prediction.
static void getBorder (
const I32 sz, // block size
const BOOL bll_exist,
const BOOL blb_exist,
const BOOL baa_exist,
const BOOL bar_exist,
const UI8 blk_rcon [][1+CTU_SZ*2],
UI8 ubla [1],
UI8 ublb [CTU_SZ*2],
UI8 ubar [CTU_SZ*2],
UI8 fbla [1],
UI8 fblb [CTU_SZ*2],
UI8 fbar [CTU_SZ*2]
) {
I32 i;
if (bll_exist && baa_exist) // 1st, construct border on left-above pixel
ubla[0] = blk_rcon[-1][-1];
else if (bll_exist)
ubla[0] = blk_rcon[ 0][-1];
else if (baa_exist)
ubla[0] = blk_rcon[-1][ 0];
else
ubla[0] = PIX_MIDDLE_VALUE;
for (i=0; i<sz; i++) // 2nd, construct border on left pixels
if (bll_exist)
ublb[i] = blk_rcon[i][-1];
else
ublb[i] = ubla[0];
for (i=sz; i<sz*2; i++) // 3rd, construct border on left-below pixels
if (blb_exist)
ublb[i] = blk_rcon[i][-1];
else
ublb[i] = ublb[sz-1];
for (i=0; i<sz; i++) // 4th, construct border on above pixels
if (baa_exist)
ubar[i] = blk_rcon[-1][i];
else
ubar[i] = ubla[0];
for (i=sz; i<sz*2; i++) // 5th, construct border on above-right pixels
if (bar_exist)
ubar[i] = blk_rcon[-1][i];
else
ubar[i] = ubar[sz-1];
// filter border ---------------------------------------------------------------------------------------
fbla[0] = ( 2 + ublb[0] + ubar[0] + 2*ubla[0] ) >> 2;
fblb[0] = ( 2 + 2*ublb[0] + ublb[1] + ubla[0] ) >> 2;
fbar[0] = ( 2 + 2*ubar[0] + ubar[1] + ubla[0] ) >> 2;
for (i=1; i<sz*2-1; i++) {
fblb[i] = ( 2 + 2*ublb[i] + ublb[i-1] + ublb[i+1] ) >> 2;
fbar[i] = ( 2 + 2*ubar[i] + ubar[i-1] + ubar[i+1] ) >> 2;
}
fblb[sz*2-1] = ublb[sz*2-1];
fbar[sz*2-1] = ubar[sz*2-1];
}
// description : do prediction, getting the predicted block
static void predict (
const I32 sz,
const ChannelType ch,
const I32 pmode,
const UI8 ubla,
const UI8 ublb [CTU_SZ*2],
const UI8 ubar [CTU_SZ*2],
const UI8 fbla,
const UI8 fblb [CTU_SZ*2],
const UI8 fbar [CTU_SZ*2],
UI8 dst [CTU_SZ][CTU_SZ] // the predict result block will be put here
) {
static const BOOL WHETHER_FILTER_BORDER_FOR_Y_TABLE [][35] = {
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, // sz = 4x4 , pmode = 0~34
{ 1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }, // sz = 8x8 , pmode = 0~34
{ 1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1 }, // sz = 16x16 , pmode = 0~34
{ 0 },
{ 1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1 } // sz = 32x32 , pmode = 0~34
};
static const I32 ANGLE_TABLE [] = {0, 0, 32, 26, 21, 17, 13, 9, 5, 2 , 0, -2, -5, -9, -13, -17, -21, -26, -32, -26, -21, -17, -13, -9, -5, -2, 0, 2, 5, 9, 13, 17, 21, 26, 32 };
static const I32 ABS_INV_ANGLE_TABLE [] = {0, 0, 256, 315, 390, 482, 630, 910, 1638, 4096, 0, 4096, 1638, 910, 630, 482, 390, 315, 256, 315, 390, 482, 630, 910, 1638, 4096, 0, 4096, 1638, 910, 630, 482, 390, 315, 256 };
const BOOL whether_filter_edge = (ch==CH_Y) && (sz <= 16);
const BOOL whether_filter_border = (ch==CH_Y) && WHETHER_FILTER_BORDER_FOR_Y_TABLE[sz/8][pmode];
const UI8 bla = whether_filter_border ? fbla : ubla;
const UI8 *blb = whether_filter_border ? fblb : ublb;
const UI8 *bar = whether_filter_border ? fbar : ubar;
I32 i, j;
if ( pmode == PMODE_PLANAR ) { // planar mode
for (i=0; i<sz; i++) {
for (j=0; j<sz; j++) {
const I32 hor_pred = (sz-j-1) * blb[i] + (j+1) * bar[sz];
const I32 ver_pred = (sz-i-1) * bar[j] + (i+1) * blb[sz];
dst[i][j] = (UI8)( (sz + hor_pred + ver_pred) / (sz*2) );
}
}
} else if ( pmode == PMODE_DC ) { // DC mode
I32 dc_pix = sz;
for (i=0; i<sz; i++)
dc_pix += blb[i] + bar[i];
dc_pix /= (sz*2); // calculate the DC value (mean value of border pixels)
for (i=0; i<sz; i++)
for (j=0; j<sz; j++)
dst[i][j] = (UI8)dc_pix; // fill all predict pixels with dc_pix
if (whether_filter_edge) { // apply the edge filter for DC mode
dst[0][0] = (UI8)( (2 + 2*dc_pix + blb[0] + bar[0]) >> 2 ); // filter the top-left pixel of the predicted CU
for (i=1; i<sz; i++) {
dst[0][i] = (UI8)( (2 + 3*dc_pix + bar[i] ) >> 2 ); // filter the pixels in top row of the predicted CU (except the top-left pixel)
dst[i][0] = (UI8)( (2 + 3*dc_pix + blb[i] ) >> 2 ); // filter the pixels in left column of the predicted CU (except the top-left pixel)
}
}
} else if ( pmode == PMODE_HOR ) { // angular mode : pure horizontal
for (i=0; i<sz; i++)
for (j=0; j<sz; j++)
dst[i][j] = blb[i];
if (whether_filter_edge)
for (j=0; j<sz; j++) {
const I32 bias = (bar[j] - bla) >> 1;
dst[0][j] = PIX_CLIP( bias + dst[0][j] );
}
} else if ( pmode == PMODE_VER ) { // angular mode : pure vertical
for (i=0; i<sz; i++)
for (j=0; j<sz; j++)
dst[i][j] = bar[j];
if (whether_filter_edge)
for (i=0; i<sz; i++) {
const I32 bias = (blb[i] - bla) >> 1;
dst[i][0] = PIX_CLIP( bias + dst[i][0] );
}
} else { // pmode = 2~9, 11~25, 27~34 (angular mode without pure horizontal and pure vertical)
const BOOL is_horizontal = (pmode < PMODE_DEG135);
const I32 angle = ANGLE_TABLE [pmode];
const I32 abs_inv_angle = ABS_INV_ANGLE_TABLE[pmode];
const UI8 *bmain = is_horizontal ? blb : bar;
const UI8 *bside = is_horizontal ? bar : blb;
UI8 ref_buff0 [CTU_SZ*4+1] ;
UI8 *ref_buff = ref_buff0 + CTU_SZ*2;
ref_buff[0] = bla;
for (i=0; i<sz*2; i++)
ref_buff[1+i] = bside[i];
for (i=-1; i>((sz*angle)>>5); i--) {
j = (128 - abs_inv_angle * i) >> 8;
ref_buff[i] = ref_buff[j];
}
for (i=0; i<sz*2; i++)
ref_buff[1+i] = bmain[i];
for (i=0; i<sz; i++) {
const I32 offset = angle * (i+1);
const I32 offset_i = offset >> 5;
const I32 offset_f = offset & 0x1f;
for (j=0; j<sz; j++) {
const UI8 pix1 = ref_buff[offset_i+j+1];
const UI8 pix2 = ref_buff[offset_i+j+2];
const UI8 pix = (UI8)( ( (32-offset_f)*pix1 + offset_f*pix2 + 16 ) >> 5 );
if (is_horizontal)
dst[j][i] = pix;
else
dst[i][j] = pix;
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// transform and inverse transform
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const I32 DST4_MAT [][CTU_SZ] = { // DST matrix for block 4x4
{ 29, 55, 74, 84 },
{ 74, 74, 0, -74 },
{ 84, -29, -74, 55 },
{ 55, -84, 74, -29 }
};
const I32 DCT8_MAT [][CTU_SZ] = { // DCT matrix for block 8x8
{ 64, 64, 64, 64, 64, 64, 64, 64 },
{ 89, 75, 50, 18, -18, -50, -75, -89 },
{ 83, 36, -36, -83, -83, -36, 36, 83 },
{ 75, -18, -89, -50, 50, 89, 18, -75 },
{ 64, -64, -64, 64, 64, -64, -64, 64 },
{ 50, -89, 18, 75, -75, -18, 89, -50 },
{ 36, -83, 83, -36, -36, 83, -83, 36 },
{ 18, -50, 75, -89, 89, -75, 50, -18 }
};
const I32 DCT16_MAT [][CTU_SZ] = { // DCT matrix for block 16x16
{ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
{ 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90 },
{ 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89 },
{ 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87 },
{ 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83 },
{ 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80 },
{ 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75 },
{ 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70 },
{ 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64 },
{ 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57 },
{ 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50 },
{ 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43 },
{ 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36 },
{ 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25 },
{ 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18 },
{ 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9 }
};
const I32 DCT32_MAT [][CTU_SZ] = { // DCT matrix for block 32x32
{ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
{ 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4, -4, -13, -22, -31, -38, -46, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90 },
{ 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90, -90, -87, -80, -70, -57, -43, -25, -9, 9, 25, 43, 57, 70, 80, 87, 90 },
{ 90, 82, 67, 46, 22, -4, -31, -54, -73, -85, -90, -88, -78, -61, -38, -13, 13, 38, 61, 78, 88, 90, 85, 73, 54, 31, 4, -22, -46, -67, -82, -90 },
{ 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89 },
{ 88, 67, 31, -13, -54, -82, -90, -78, -46, -4, 38, 73, 90, 85, 61, 22, -22, -61, -85, -90, -73, -38, 4, 46, 78, 90, 82, 54, 13, -31, -67, -88 },
{ 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87, -87, -57, -9, 43, 80, 90, 70, 25, -25, -70, -90, -80, -43, 9, 57, 87 },
{ 85, 46, -13, -67, -90, -73, -22, 38, 82, 88, 54, -4, -61, -90, -78, -31, 31, 78, 90, 61, 4, -54, -88, -82, -38, 22, 73, 90, 67, 13, -46, -85 },
{ 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83 },
{ 82, 22, -54, -90, -61, 13, 78, 85, 31, -46, -90, -67, 4, 73, 88, 38, -38, -88, -73, -4, 67, 90, 46, -31, -85, -78, -13, 61, 90, 54, -22, -82 },
{ 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80, -80, -9, 70, 87, 25, -57, -90, -43, 43, 90, 57, -25, -87, -70, 9, 80 },
{ 78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 31, 90, 54, -38, -90, -46, 46, 90, 38, -54, -90, -31, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78 },
{ 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75 },
{ 73, -31, -90, -22, 78, 67, -38, -90, -13, 82, 61, -46, -88, -4, 85, 54, -54, -85, 4, 88, 46, -61, -82, 13, 90, 38, -67, -78, 22, 90, 31, -73 },
{ 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70, -70, 43, 87, -9, -90, -25, 80, 57, -57, -80, 25, 90, 9, -87, -43, 70 },
{ 67, -54, -78, 38, 85, -22, -90, 4, 90, 13, -88, -31, 82, 46, -73, -61, 61, 73, -46, -82, 31, 88, -13, -90, -4, 90, 22, -85, -38, 78, 54, -67 },
{ 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64 },
{ 61, -73, -46, 82, 31, -88, -13, 90, -4, -90, 22, 85, -38, -78, 54, 67, -67, -54, 78, 38, -85, -22, 90, 4, -90, 13, 88, -31, -82, 46, 73, -61 },
{ 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57, -57, 80, 25, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -25, -80, 57 },
{ 54, -85, -4, 88, -46, -61, 82, 13, -90, 38, 67, -78, -22, 90, -31, -73, 73, 31, -90, 22, 78, -67, -38, 90, -13, -82, 61, 46, -88, 4, 85, -54 },
{ 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50 },
{ 46, -90, 38, 54, -90, 31, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78, -78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -31, 90, -54, -38, 90, -46 },
{ 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43, -43, 90, -57, -25, 87, -70, -9, 80, -80, 9, 70, -87, 25, 57, -90, 43 },
{ 38, -88, 73, -4, -67, 90, -46, -31, 85, -78, 13, 61, -90, 54, 22, -82, 82, -22, -54, 90, -61, -13, 78, -85, 31, 46, -90, 67, 4, -73, 88, -38 },
{ 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36 },
{ 31, -78, 90, -61, 4, 54, -88, 82, -38, -22, 73, -90, 67, -13, -46, 85, -85, 46, 13, -67, 90, -73, 22, 38, -82, 88, -54, -4, 61, -90, 78, -31 },
{ 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25, -25, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 25 },
{ 22, -61, 85, -90, 73, -38, -4, 46, -78, 90, -82, 54, -13, -31, 67, -88, 88, -67, 31, 13, -54, 82, -90, 78, -46, 4, 38, -73, 90, -85, 61, -22 },
{ 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18 },
{ 13, -38, 61, -78, 88, -90, 85, -73, 54, -31, 4, 22, -46, 67, -82, 90, -90, 82, -67, 46, -22, -4, 31, -54, 73, -85, 90, -88, 78, -61, 38, -13 },
{ 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9, -9, 25, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -25, 9 },
{ 4, -13, 22, -31, 38, -46, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90, 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4 }
};
// description : matrix multiply
static void matMul (
const I32 sz,
const BOOL src1_transpose,
const BOOL src2_transpose,
const I32 dst_sft,
const BOOL dst_clip,
const I32 src1 [][CTU_SZ],
const I32 src2 [][CTU_SZ],
I32 dst [][CTU_SZ]
) {
const I32 dst_add = 1 << dst_sft >> 1;
I32 i, j, k, s;
for (i=0; i<sz; i++) {
for (j=0; j<sz; j++) {
s = dst_add;
for (k=0; k<sz; k++)
s += (src1_transpose ? src1[k][i] : src1[i][k]) * (src2_transpose ? src2[j][k] : src2[k][j]);
s >>= dst_sft;
if (dst_clip)
s = COEF_CLIP(s);
dst[i][j] = s;
}
}
}
// description : do transform (DCT or 4x4 DST) , or inverse transform (inv-DCT or 4x4 inv-DST)
static void transform (
const I32 sz, // block size
const BOOL inverse, // 0:transform 1:inverse transform
const I32 src [][CTU_SZ],
I32 dst [][CTU_SZ]
) {
// TU size 4x4 8x8 16x16 32x32
static const I32 TABLE_A_FOR_TRANSFORM [] = { 1 , 2, 3, -1, 4};
static const I32 (*TABLE_TRANSFORM_MAT[5]) [CTU_SZ] = {DST4_MAT, DCT8_MAT, DCT16_MAT, NULL, DCT32_MAT};
I32 tmp [CTU_SZ][CTU_SZ];
const I32 (*mat) [CTU_SZ] = TABLE_TRANSFORM_MAT[sz/8];
const I32 a = inverse ? 7 : TABLE_A_FOR_TRANSFORM[sz/8];
const I32 b = inverse ? 12 : a + 7;
matMul(sz, inverse, 0, a, inverse, mat, src, tmp); // (W = C * X) for transform , (W = CT * X) for inverse-transform
matMul(sz, 0, !inverse, b, inverse, tmp, mat, dst);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// quantize and de-quantize
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static I32 estimateCoeffRate (I32 level) {
static const I32 LEVEL_RATE_TABLE [] = {0, 70000, 90000, 92000, 157536, 190304};
I32 i;
if ( level < 6 )
return LEVEL_RATE_TABLE[level];
level -= 6;
for (i=0; (1<<i)<=level; i++)
level -= 1<<i;
return 92000 + ((3+i*2+1)<<15);
}
// description : simplified rate-distortion optimized quantize (RDOQ) for a TU
static void quantize (
const I32 qpd6,
const I32 sz,
const I32 src [][CTU_SZ],
I32 dst [][CTU_SZ]
) {
// TU size 4x4 8x8 16x16 32x32
static const I32 DIST_SHIFT_TABLE [] = { 8 , 7, 6, -1, 5};
static const I32 LEVEL_SHIFT_TABLE [] = { 19 , 18, 17, -1, 16};
const I32 dist_sft = DIST_SHIFT_TABLE[sz/8];
const I32 sft = LEVEL_SHIFT_TABLE[sz/8] + qpd6;
const I32 add = (1<<sft>>1);
const I32 max_dlevel = I32_MAX_VALUE - add;
const I32 cg_dlevel_threshold = 9 << sft >> 2;
I32 yc, xc, y, x;
for (yc=0; yc<sz; yc+=CG_SZ) { // for all CGs
for (xc=0; xc<sz; xc+=CG_SZ) {
I32 cg_sum_dlevel = 0;
for (y=yc; y<yc+CG_SZ; y++) { // for all coefficients in this CG
for (x=xc; x<xc+CG_SZ; x++) {
I32 absval = ABS(src[y][x]);
I32 dlevel = (absval>0x1ffff) ? max_dlevel : MIN( (absval & 0x1ffff)<<14 , max_dlevel );
I32 level = COEF_CLIP( (dlevel+add) >> sft );
I32 min_level = MAX(0, level-2);
I32 best_cost = I32_MAX_VALUE;
for (; level>=min_level; level--) {
I32 dist1 = ABS( dlevel-(level<<sft) ) >> dist_sft;
I32 dist = ( (dist1<46340) ? (dist1*dist1) : I32_MAX_VALUE ) >> 7; // 46340^2 ~= I32_MAX_VALUE
I32 cost = calcRDcost(qpd6, dist, estimateCoeffRate(level));
if (cost < best_cost) { // if current cost is smaller than previous cost
best_cost = cost;
dst[y][x] = level;
}
}
if (src[y][x] < 0)
dst[y][x] *= -1; // recover the sign
cg_sum_dlevel += MIN( dlevel , cg_dlevel_threshold );
}
}
if ( cg_sum_dlevel < cg_dlevel_threshold ) // if this CG is too weak
for (y=yc; y<yc+CG_SZ; y++)
for (x=xc; x<xc+CG_SZ; x++)
dst[y][x] = 0; // clear all items in CG
}
}
}
// description : de-quantize
static void deQuantize (
const I32 qpd6,
const I32 sz,
const I32 src [][CTU_SZ],
I32 dst [][CTU_SZ]
) {
// TU size 4x4 8x8 16x16 32x32
static const I32 Q_SHIFT_TABLE [5] = { 5 , 4, 3, -1, 2};
const I32 q_sft = Q_SHIFT_TABLE[sz/8] + qpd6;
I32 i, j;
for (i=0; i<sz; i++)
for (j=0; j<sz; j++)
dst[i][j] = COEF_CLIP( src[i][j] << q_sft );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// functions for putting HEVC header to a buffer (byte array)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void putBitsToBuffer (UI8 **ppbuf, I32 *bitpos, I32 bits, I32 len) {
for (len--; len>=0; len--) {
UI8 bit = (bits>>len) & 1;
if (bit)
**ppbuf |= (1<<(*bitpos)); // set the bit to 1, and do not effect other bits of this byte
else
**ppbuf &= ~(1<<(*bitpos)); // set the bit to 0, and do not effect other bits of this byte
if ((*bitpos) > 0) { // current byte not end
(*bitpos) --;
} else { // current byte end
(*bitpos) = 7;
(*ppbuf) ++; // move to next byte
}
}
}
static void putUVLCtoBuffer (UI8 **ppbuf, I32 *bitpos, I32 val) {
I32 tmp, len = 1;
val ++;
for (tmp=val+1; tmp!=1; tmp>>=1)
len += 2;
putBitsToBuffer(ppbuf, bitpos, (val & ((1<<((len+1)>>1))-1)) , ((len>>1) + ((len+1)>>1)) );
}
static void alignBitsToByte (UI8 **ppbuf, I32 *bitpos) {
if ( (*bitpos) < 7 )
*((*ppbuf)++) &= 0xfe << (*bitpos); // set all tail bits to 0, and move the buffer pointer to next byte
(*bitpos) = 7;
}
static void putBytesToBuffer (UI8 **ppbuf, const UI8 *bytes, I32 len) {
I32 i;
for (i=0; i<len; i++)
*((*ppbuf)++) = bytes[i];
}
static void putHeaderToBuffer (UI8 **ppbuf, const I32 qpd6, const I32 ysz, const I32 xsz) {
static const UI8 VPS [] = {0x00, 0x00, 0x01, 0x40, 0x01, 0x0C, 0x01, 0xFF, 0xFF, 0x03, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0xB4, 0xF0, 0x24};
static const UI8 SPS [] = {0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x03, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0xB4};
static const UI8 PPS [] = {0x00, 0x00, 0x01, 0x44, 0x01, 0xC0, 0x90, 0x91, 0x81, 0xD9, 0x20};
static const UI8 SLICE_HEADERS [][8] = {
{0x00, 0x00, 0x01, 0x26, 0x01, 0xAC, 0x16, 0xDE} , // qpd6=0
{0x00, 0x00, 0x01, 0x26, 0x01, 0xAC, 0x10, 0xDE} , // qpd6=1
{0x00, 0x00, 0x01, 0x26, 0x01, 0xAC, 0x2B, 0x78} , // qpd6=2
{0x00, 0x00, 0x01, 0x26, 0x01, 0xAC, 0x4D, 0xE0} , // qpd6=3
{0x00, 0x00, 0x01, 0x26, 0x01, 0xAC, 0x97, 0x80} // qpd6=4
};
I32 bitpos = 7;
putBytesToBuffer(ppbuf, VPS, sizeof(VPS));
putBytesToBuffer(ppbuf, SPS, sizeof(SPS));
putBitsToBuffer (ppbuf, &bitpos, 0x0A, 4);
putUVLCtoBuffer (ppbuf, &bitpos, xsz);
putUVLCtoBuffer (ppbuf, &bitpos, ysz);
putBitsToBuffer (ppbuf, &bitpos, 0x197EE4, 22);
//putBitsToBuffer (ppbuf, &bitpos, 0x707B44, 24); // max_transform_hierarchy_depth_intra = 0
putBitsToBuffer (ppbuf, &bitpos, 0x681ED1, 24); // max_transform_hierarchy_depth_intra = 1
alignBitsToByte (ppbuf, &bitpos);
putBytesToBuffer(ppbuf, PPS, sizeof(PPS));
putBytesToBuffer(ppbuf, SLICE_HEADERS[qpd6], sizeof(SLICE_HEADERS[qpd6]));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// definations and operations for CABAC context value
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const UI8 CONTEXT_NEXT_STATE_MPS [] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 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,124,125,126,127};
const UI8 CONTEXT_NEXT_STATE_LPS [] = {1, 0, 0, 1, 2, 3, 4, 5, 4, 5, 8, 9, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 18, 19, 22, 23, 22, 23, 24, 25, 26, 27, 26, 27, 30, 31, 30, 31, 32, 33, 32, 33, 36, 37, 36, 37, 38, 39, 38, 39, 42, 43, 42, 43, 44, 45, 44, 45, 46, 47, 48, 49, 48, 49, 50, 51, 52, 53, 52, 53, 54, 55, 54, 55, 56, 57, 58, 59, 58, 59, 60, 61, 60, 61, 60, 61, 62, 63, 64, 65, 64, 65, 66, 67, 66, 67, 66, 67, 68, 69, 68, 69, 70, 71, 70, 71, 70, 71, 72, 73, 72, 73, 72, 73, 74, 75, 74, 75, 74, 75, 76, 77, 76, 77,126,127};
const UI8 CABAC_LPS_TABLE [][4] = {
{128, 176, 208, 240}, {128, 167, 197, 227}, {128, 158, 187, 216}, {123, 150, 178, 205}, {116, 142, 169, 195}, {111, 135, 160, 185}, {105, 128, 152, 175}, {100, 122, 144, 166},
{ 95, 116, 137, 158}, { 90, 110, 130, 150}, { 85, 104, 123, 142}, { 81, 99, 117, 135}, { 77, 94, 111, 128}, { 73, 89, 105, 122}, { 69, 85, 100, 116}, { 66, 80, 95, 110},
{ 62, 76, 90, 104}, { 59, 72, 86, 99}, { 56, 69, 81, 94}, { 53, 65, 77, 89}, { 51, 62, 73, 85}, { 48, 59, 69, 80}, { 46, 56, 66, 76}, { 43, 53, 63, 72},
{ 41, 50, 59, 69}, { 39, 48, 56, 65}, { 37, 45, 54, 62}, { 35, 43, 51, 59}, { 33, 41, 48, 56}, { 32, 39, 46, 53}, { 30, 37, 43, 50}, { 29, 35, 41, 48},
{ 27, 33, 39, 45}, { 26, 31, 37, 43}, { 24, 30, 35, 41}, { 23, 28, 33, 39}, { 22, 27, 32, 37}, { 21, 26, 30, 35}, { 20, 24, 29, 33}, { 19, 23, 27, 31},
{ 18, 22, 26, 30}, { 17, 21, 25, 28}, { 16, 20, 23, 27}, { 15, 19, 22, 25}, { 14, 18, 21, 24}, { 14, 17, 20, 23}, { 13, 16, 19, 22}, { 12, 15, 18, 21},
{ 12, 14, 17, 20}, { 11, 14, 16, 19}, { 11, 13, 15, 18}, { 10, 12, 15, 17}, { 10, 12, 14, 16}, { 9, 11, 13, 15}, { 9, 11, 12, 14}, { 8, 10, 12, 14},
{ 8, 9, 11, 13}, { 7, 9, 11, 12}, { 7, 9, 10, 12}, { 7, 8, 10, 11}, { 6, 8, 9, 11}, { 6, 7, 9, 10}, { 6, 7, 8, 9}, { 2, 2, 2, 2}
};
const UI8 CABAC_RENORM_TABLE [] = { 6, 5, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
// operations for context value (ctx_val), note that ctx_val must be UI8 type
#define UPDATE_LPS(ctx_val) { (ctx_val) = CONTEXT_NEXT_STATE_LPS[(ctx_val)]; }
#define UPDATE_MPS(ctx_val) { (ctx_val) = CONTEXT_NEXT_STATE_MPS[(ctx_val)]; }
#define GET_CTX_STATE(ctx_val) ( (ctx_val)>>1 )
#define GET_CTX_MPS(ctx_val) ( (ctx_val)&1 )
#define GET_LPS(ctx_val,range) ( CABAC_LPS_TABLE[GET_CTX_STATE(ctx_val)][((range)>>6)&3] )
#define GET_NBIT(lps) ( CABAC_RENORM_TABLE[(lps)>>3] )
static UI8 initContextValue (UI8 init_val, I32 qpd6) {
I32 qp = qpd6 * 6 + 4;
I32 init_state = ((((init_val>>4)*5-45)*qp) >> 4) + ((init_val&15) << 3) - 16;
init_state = CLIP(init_state, 1, 126);
if (init_state >= 64)
return (UI8)( ((init_state-64)<<1) | 1 );
else
return (UI8)( ((63-init_state)<<1) );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HEVC CABAC context set
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct { // context set for HEVC encoder
UI8 split_cu_flag [3];
UI8 partsize ;
UI8 Y_pmode ;
UI8 UV_pmode ;
UI8 split_tu_flag [3];
UI8 Y_qt_cbf [2];
UI8 UV_qt_cbf [5];
UI8 last_x [5][5];
UI8 last_y [5][5];
UI8 sig_map [2];
UI8 sig_sc [44];
UI8 one_sc [24];
UI8 abs_sc [6];
} ContextSet;
static ContextSet newContextSet (I32 qpd6) {
ContextSet tCtxs = {
{139, 141, 157},
184,
184,
63,
{153, 138, 138},
{111, 141},
{94, 138, 182, 154, 154},
{{110, 110, 124}, {125, 140, 153}, {125, 127, 140, 109}, {111, 143, 127, 111, 79}, {108, 123, 63, 154}},
{{110, 110, 124}, {125, 140, 153}, {125, 127, 140, 109}, {111, 143, 127, 111, 79}, {108, 123, 63, 154}},
{91, 171},
{111, 111, 125, 110, 110, 94, 124, 108, 124, 107, 125, 141, 179, 153, 125, 107, 125, 141, 179, 153, 125, 107, 125, 141, 179, 153, 125, 141, 140, 139, 182, 182, 152, 136, 152, 136, 153, 136, 139, 111, 136, 139, 111, 111},
{140, 92, 137, 138, 140, 152, 138, 139, 153, 74, 149, 92, 139, 107, 122, 152, 140, 179, 166, 182, 140, 227, 122, 197},
{138, 153, 136, 167, 152, 152}
};
UI8 *ptr = (UI8*)&tCtxs;
UI8 *endptr = ptr + sizeof(tCtxs);
for(; ptr<endptr; ptr++)
*ptr = initContextValue(*ptr, qpd6); // initial all the UI8 items in ctxs using function initContextValue
return tCtxs;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CABAC coder
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define TMPBUF_LEN (CTU_SZ*CTU_SZ*3+128)
typedef struct {
UI8 tmpbuf [TMPBUF_LEN]; // internal temporary buffer of CABAC coder
I32 tmpcnt ; // indicate the byte count in tmpbuf
I32 count00 ; // indicate the number of 0x00 that has been just put to tmpbuf, if the last byte is not 0x00, set count0x00=0
I32 range ;
I32 low ;
I32 nbits ;
I32 nbytes ;
I32 bufbyte ;
} CABACcoder;
static CABACcoder newCABACcoder (void) {
CABACcoder tCABAC = { {0x00}, 0, 0, 510, 0, 23, 0, 0xFF };
return tCABAC;
}
static void CABACsubmitToBuffer (CABACcoder *p, UI8 **ppbuf) {
putBytesToBuffer(ppbuf, p->tmpbuf, p->tmpcnt); // move all bytes from tmpbuf to ppbuf
p->tmpcnt = 0; // now tmpbuf as no bytes, so set tmpcnt=0
}
static void CABACput (CABACcoder *p, I32 byte) {
if ( p->count00 >= 2 && (UI8)byte <= 0x03 ) {
p->tmpbuf[ p->tmpcnt++ ] = 0x03;
p->count00 = 0;
}
p->tmpbuf[ p->tmpcnt++ ] = (UI8)byte;
if ( (UI8)byte == 0x00 )
p->count00 ++;
else
p->count00 = 0;
//if ( p->tmpcnt >= TMPBUF_LEN ) {} // overflow: should never, since p->tmpbuf (internal buffer of CABAC coder) is large enough
}
static I32 CABAClen (const CABACcoder *p) {
return 8 * (p->tmpcnt + p->nbytes) + 23 - p->nbits ;
}
static void CABACfinish (CABACcoder *p) {
I32 tmp = 0x00;
if ( ( (p->low) >> (32-p->nbits) ) > 0 ) {
CABACput(p, p->bufbyte+1);
p->low -= (1<<(32-p->nbits));
} else {
if (p->nbytes > 0)
CABACput(p, p->bufbyte);
tmp = 0xff;
}
for (; p->nbytes>1; p->nbytes--)
CABACput(p, tmp);
tmp = (p->low >> 8) << p->nbits ;
CABACput(p, tmp >> 16 );
CABACput(p, tmp >> 8 );
CABACput(p, tmp );
}
static void CABACupdate (CABACcoder *p) {
if (p->nbits < 12) {
I32 lead_byte = p->low >> (24-p->nbits);
p->nbits += 8;
p->low &= (0xFFFFFFFF >> p->nbits);
if (lead_byte == 0xFF) {
p->nbytes ++;
} else if ( p->nbytes > 0 ) {
I32 carry = lead_byte >> 8;
I32 byte = carry + p->bufbyte;
p->bufbyte = lead_byte & 0xFF;
CABACput(p, byte);
byte = (0xFF + carry) & 0xFF;
for (; p->nbytes>1; p->nbytes--)
CABACput(p, byte);
} else {
p->nbytes = 1;
p->bufbyte = lead_byte;
}
}
}
static void CABACputTerminate (CABACcoder *p, BOOL bin) {
bin = !!bin;
p->range -= 2;
if (bin) {
p->low += p->range;
p->low <<= 7;
p->range = 2<<7;
p->nbits -= 7;
} else if (p->range < 256) {
p->low <<= 1;
p->range <<= 1;
p->nbits --;
}
CABACupdate(p);
}
static void CABACputBins (CABACcoder *p, I32 bins, I32 len) { // put bins without context model
bins &= ((1<<len)-1);
while (len > 0) {
const I32 len_curr = MIN(len, 8);
I32 bins_curr;
len -= len_curr;
bins_curr = (bins>>len) & ((1<<len_curr)-1);
p->low <<= len_curr;
p->low += p->range * bins_curr;
p->nbits -= len_curr;
CABACupdate(p);
}
}
static void CABACputBin (CABACcoder *p, BOOL bin, UI8 *pCtx) { // put bin with context model
I32 lps = GET_LPS(*pCtx, p->range);
I32 nbit = GET_NBIT(lps);
bin = !!bin;
p->range -= lps;
if ( bin != GET_CTX_MPS(*pCtx) ) {
UPDATE_LPS(*pCtx);
p->low = ( p->low + p->range ) << nbit;
p->range = lps << nbit;
p->nbits -= nbit;
} else {
UPDATE_MPS(*pCtx);
if (p->range < 256) {