| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * MagicYUV encoder | ||
| 3 | * Copyright (c) 2017 Paul B Mahol | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <stdlib.h> | ||
| 23 | #include <string.h> | ||
| 24 | |||
| 25 | #include "libavutil/cpu.h" | ||
| 26 | #include "libavutil/mem.h" | ||
| 27 | #include "libavutil/opt.h" | ||
| 28 | #include "libavutil/pixdesc.h" | ||
| 29 | #include "libavutil/qsort.h" | ||
| 30 | |||
| 31 | #include "avcodec.h" | ||
| 32 | #include "bytestream.h" | ||
| 33 | #include "codec_internal.h" | ||
| 34 | #include "encode.h" | ||
| 35 | #include "put_bits.h" | ||
| 36 | #include "lossless_videoencdsp.h" | ||
| 37 | |||
| 38 | #define MAGICYUV_EXTRADATA_SIZE 32 | ||
| 39 | |||
| 40 | typedef enum Prediction { | ||
| 41 | LEFT = 1, | ||
| 42 | GRADIENT, | ||
| 43 | MEDIAN, | ||
| 44 | } Prediction; | ||
| 45 | |||
| 46 | typedef struct HuffEntry { | ||
| 47 | uint8_t len; | ||
| 48 | uint32_t code; | ||
| 49 | } HuffEntry; | ||
| 50 | |||
| 51 | typedef struct PTable { | ||
| 52 | int value; ///< input value | ||
| 53 | int64_t prob; ///< number of occurrences of this value in input | ||
| 54 | } PTable; | ||
| 55 | |||
| 56 | typedef struct Slice { | ||
| 57 | int width; | ||
| 58 | int height; | ||
| 59 | int encode_raw; | ||
| 60 | unsigned pos; | ||
| 61 | unsigned size; | ||
| 62 | uint8_t *slice; | ||
| 63 | uint8_t *dst; | ||
| 64 | int64_t counts[256]; | ||
| 65 | } Slice; | ||
| 66 | |||
| 67 | typedef struct MagicYUVContext { | ||
| 68 | const AVClass *class; | ||
| 69 | int frame_pred; | ||
| 70 | int planes; | ||
| 71 | uint8_t format; | ||
| 72 | int slice_height; | ||
| 73 | int nb_slices; | ||
| 74 | int correlate; | ||
| 75 | int hshift[4]; | ||
| 76 | int vshift[4]; | ||
| 77 | uint8_t *decorrelate_buf[2]; | ||
| 78 | Slice *slices; | ||
| 79 | HuffEntry he[4][256]; | ||
| 80 | LLVidEncDSPContext llvidencdsp; | ||
| 81 | void (*predict)(struct MagicYUVContext *s, const uint8_t *src, uint8_t *dst, | ||
| 82 | ptrdiff_t stride, int width, int height); | ||
| 83 | } MagicYUVContext; | ||
| 84 | |||
| 85 | 1200 | static void left_predict(MagicYUVContext *s, | |
| 86 | const uint8_t *src, uint8_t *dst, ptrdiff_t stride, | ||
| 87 | int width, int height) | ||
| 88 | { | ||
| 89 | 1200 | uint8_t prev = 0; | |
| 90 | int i, j; | ||
| 91 | |||
| 92 |
2/2✓ Branch 0 taken 299200 times.
✓ Branch 1 taken 1200 times.
|
300400 | for (i = 0; i < width; i++) { |
| 93 | 299200 | dst[i] = src[i] - prev; | |
| 94 | 299200 | prev = src[i]; | |
| 95 | } | ||
| 96 | 1200 | dst += width; | |
| 97 | 1200 | src += stride; | |
| 98 |
2/2✓ Branch 0 taken 42000 times.
✓ Branch 1 taken 1200 times.
|
43200 | for (j = 1; j < height; j++) { |
| 99 | 42000 | prev = src[-stride]; | |
| 100 |
2/2✓ Branch 0 taken 12372800 times.
✓ Branch 1 taken 42000 times.
|
12414800 | for (i = 0; i < width; i++) { |
| 101 | 12372800 | dst[i] = src[i] - prev; | |
| 102 | 12372800 | prev = src[i]; | |
| 103 | } | ||
| 104 | 42000 | dst += width; | |
| 105 | 42000 | src += stride; | |
| 106 | } | ||
| 107 | 1200 | } | |
| 108 | |||
| 109 | 150 | static void gradient_predict(MagicYUVContext *s, | |
| 110 | const uint8_t *src, uint8_t *dst, ptrdiff_t stride, | ||
| 111 | int width, int height) | ||
| 112 | { | ||
| 113 | 150 | int left = 0, top, lefttop; | |
| 114 | int i, j; | ||
| 115 | |||
| 116 |
2/2✓ Branch 0 taken 52800 times.
✓ Branch 1 taken 150 times.
|
52950 | for (i = 0; i < width; i++) { |
| 117 | 52800 | dst[i] = src[i] - left; | |
| 118 | 52800 | left = src[i]; | |
| 119 | } | ||
| 120 | 150 | dst += width; | |
| 121 | 150 | src += stride; | |
| 122 |
2/2✓ Branch 0 taken 43050 times.
✓ Branch 1 taken 150 times.
|
43200 | for (j = 1; j < height; j++) { |
| 123 | 43050 | top = src[-stride]; | |
| 124 | 43050 | left = src[0] - top; | |
| 125 | 43050 | dst[0] = left; | |
| 126 |
2/2✓ Branch 0 taken 15110550 times.
✓ Branch 1 taken 43050 times.
|
15153600 | for (i = 1; i < width; i++) { |
| 127 | 15110550 | top = src[i - stride]; | |
| 128 | 15110550 | lefttop = src[i - (stride + 1)]; | |
| 129 | 15110550 | left = src[i-1]; | |
| 130 | 15110550 | dst[i] = (src[i] - top) - left + lefttop; | |
| 131 | } | ||
| 132 | 43050 | dst += width; | |
| 133 | 43050 | src += stride; | |
| 134 | } | ||
| 135 | 150 | } | |
| 136 | |||
| 137 | 150 | static void median_predict(MagicYUVContext *s, | |
| 138 | const uint8_t *src, uint8_t *dst, ptrdiff_t stride, | ||
| 139 | int width, int height) | ||
| 140 | { | ||
| 141 | 150 | int left = 0, lefttop; | |
| 142 | int i, j; | ||
| 143 | |||
| 144 |
2/2✓ Branch 0 taken 5100 times.
✓ Branch 1 taken 150 times.
|
5250 | for (i = 0; i < width; i++) { |
| 145 | 5100 | dst[i] = src[i] - left; | |
| 146 | 5100 | left = src[i]; | |
| 147 | } | ||
| 148 | 150 | dst += width; | |
| 149 | 150 | src += stride; | |
| 150 |
2/2✓ Branch 0 taken 4950 times.
✓ Branch 1 taken 150 times.
|
5100 | for (j = 1; j < height; j++) { |
| 151 | 4950 | left = lefttop = src[-stride]; | |
| 152 | 4950 | s->llvidencdsp.sub_median_pred(dst, src - stride, src, width, &left, &lefttop); | |
| 153 | 4950 | dst += width; | |
| 154 | 4950 | src += stride; | |
| 155 | } | ||
| 156 | 150 | } | |
| 157 | |||
| 158 | 4 | static av_cold int magy_encode_init(AVCodecContext *avctx) | |
| 159 | { | ||
| 160 | 4 | MagicYUVContext *s = avctx->priv_data; | |
| 161 | PutByteContext pb; | ||
| 162 | |||
| 163 |
4/8✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
4 | switch (avctx->pix_fmt) { |
| 164 | 1 | case AV_PIX_FMT_GBRP: | |
| 165 | 1 | avctx->codec_tag = MKTAG('M', '8', 'R', 'G'); | |
| 166 | 1 | s->correlate = 1; | |
| 167 | 1 | s->format = 0x65; | |
| 168 | 1 | break; | |
| 169 | ✗ | case AV_PIX_FMT_GBRAP: | |
| 170 | ✗ | avctx->codec_tag = MKTAG('M', '8', 'R', 'A'); | |
| 171 | ✗ | s->correlate = 1; | |
| 172 | ✗ | s->format = 0x66; | |
| 173 | ✗ | break; | |
| 174 | 1 | case AV_PIX_FMT_YUV420P: | |
| 175 | 1 | avctx->codec_tag = MKTAG('M', '8', 'Y', '0'); | |
| 176 | 1 | s->hshift[1] = | |
| 177 | 1 | s->vshift[1] = | |
| 178 | 1 | s->hshift[2] = | |
| 179 | 1 | s->vshift[2] = 1; | |
| 180 | 1 | s->format = 0x69; | |
| 181 | 1 | break; | |
| 182 | ✗ | case AV_PIX_FMT_YUV422P: | |
| 183 | ✗ | avctx->codec_tag = MKTAG('M', '8', 'Y', '2'); | |
| 184 | ✗ | s->hshift[1] = | |
| 185 | ✗ | s->hshift[2] = 1; | |
| 186 | ✗ | s->format = 0x68; | |
| 187 | ✗ | break; | |
| 188 | 1 | case AV_PIX_FMT_YUV444P: | |
| 189 | 1 | avctx->codec_tag = MKTAG('M', '8', 'Y', '4'); | |
| 190 | 1 | s->format = 0x67; | |
| 191 | 1 | break; | |
| 192 | ✗ | case AV_PIX_FMT_YUVA444P: | |
| 193 | ✗ | avctx->codec_tag = MKTAG('M', '8', 'Y', 'A'); | |
| 194 | ✗ | s->format = 0x6a; | |
| 195 | ✗ | break; | |
| 196 | 1 | case AV_PIX_FMT_GRAY8: | |
| 197 | 1 | avctx->codec_tag = MKTAG('M', '8', 'G', '0'); | |
| 198 | 1 | s->format = 0x6b; | |
| 199 | 1 | break; | |
| 200 | } | ||
| 201 | |||
| 202 | 4 | ff_llvidencdsp_init(&s->llvidencdsp); | |
| 203 | |||
| 204 | 4 | s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); | |
| 205 | |||
| 206 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | s->nb_slices = avctx->slices > 0 ? avctx->slices : avctx->thread_count; |
| 207 | 4 | s->nb_slices = FFMIN(s->nb_slices, avctx->height >> s->vshift[1]); | |
| 208 | 4 | s->nb_slices = FFMAX(1, s->nb_slices); | |
| 209 | 4 | s->slice_height = FFALIGN((avctx->height + s->nb_slices - 1) / s->nb_slices, 1 << s->vshift[1]); | |
| 210 | 4 | s->nb_slices = (avctx->height + s->slice_height - 1) / s->slice_height; | |
| 211 | 4 | s->nb_slices = FFMIN(256U / s->planes, s->nb_slices); | |
| 212 | 4 | s->slices = av_calloc(s->nb_slices * s->planes, sizeof(*s->slices)); | |
| 213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!s->slices) |
| 214 | ✗ | return AVERROR(ENOMEM); | |
| 215 | |||
| 216 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (s->correlate) { |
| 217 | 1 | size_t max_align = av_cpu_max_align(); | |
| 218 | 1 | size_t aligned_width = FFALIGN(avctx->width, max_align); | |
| 219 | 1 | s->decorrelate_buf[0] = av_calloc(2U * (s->nb_slices * s->slice_height), | |
| 220 | aligned_width); | ||
| 221 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!s->decorrelate_buf[0]) |
| 222 | ✗ | return AVERROR(ENOMEM); | |
| 223 | 1 | s->decorrelate_buf[1] = s->decorrelate_buf[0] + (s->nb_slices * s->slice_height) * aligned_width; | |
| 224 | } | ||
| 225 | |||
| 226 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
|
16 | for (int n = 0; n < s->nb_slices; n++) { |
| 227 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
|
42 | for (int i = 0; i < s->planes; i++) { |
| 228 | 30 | Slice *sl = &s->slices[n * s->planes + i]; | |
| 229 | |||
| 230 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 20 times.
|
30 | sl->height = n == s->nb_slices - 1 ? avctx->height - n * s->slice_height : s->slice_height; |
| 231 | 30 | sl->height = AV_CEIL_RSHIFT(sl->height, s->vshift[i]); | |
| 232 | 30 | sl->width = AV_CEIL_RSHIFT(avctx->width, s->hshift[i]); | |
| 233 | |||
| 234 | 30 | sl->slice = av_malloc(avctx->width * (s->slice_height + 2) + | |
| 235 | AV_INPUT_BUFFER_PADDING_SIZE); | ||
| 236 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (!sl->slice) |
| 237 | ✗ | return AVERROR(ENOMEM); | |
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
4 | switch (s->frame_pred) { |
| 242 | 2 | case LEFT: s->predict = left_predict; break; | |
| 243 | 1 | case GRADIENT: s->predict = gradient_predict; break; | |
| 244 | 1 | case MEDIAN: s->predict = median_predict; break; | |
| 245 | } | ||
| 246 | |||
| 247 | 4 | avctx->extradata_size = MAGICYUV_EXTRADATA_SIZE; | |
| 248 | |||
| 249 | 4 | avctx->extradata = av_mallocz(avctx->extradata_size + | |
| 250 | AV_INPUT_BUFFER_PADDING_SIZE); | ||
| 251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!avctx->extradata) |
| 252 | ✗ | return AVERROR(ENOMEM); | |
| 253 | |||
| 254 | 4 | bytestream2_init_writer(&pb, avctx->extradata, MAGICYUV_EXTRADATA_SIZE); | |
| 255 | 4 | bytestream2_put_le32u(&pb, MKTAG('M', 'A', 'G', 'Y')); | |
| 256 | 4 | bytestream2_put_le32u(&pb, 32); | |
| 257 | 4 | bytestream2_put_byteu(&pb, 7); | |
| 258 | 4 | bytestream2_put_byteu(&pb, s->format); | |
| 259 | 4 | bytestream2_put_byteu(&pb, 12); | |
| 260 | 4 | bytestream2_put_byteu(&pb, 0); | |
| 261 | |||
| 262 | 4 | bytestream2_put_byteu(&pb, 0); | |
| 263 | 4 | bytestream2_put_byteu(&pb, 0); | |
| 264 | 4 | bytestream2_put_byteu(&pb, 32); | |
| 265 | 4 | bytestream2_put_byteu(&pb, 0); | |
| 266 | |||
| 267 | 4 | bytestream2_put_le32u(&pb, avctx->width); | |
| 268 | 4 | bytestream2_put_le32u(&pb, avctx->height); | |
| 269 | 4 | bytestream2_put_le32u(&pb, avctx->width); | |
| 270 | 4 | bytestream2_put_le32u(&pb, avctx->height); | |
| 271 | |||
| 272 | 4 | return 0; | |
| 273 | } | ||
| 274 | |||
| 275 | 500 | static void calculate_codes(HuffEntry *he, uint16_t codes_count[33]) | |
| 276 | { | ||
| 277 |
2/2✓ Branch 0 taken 16000 times.
✓ Branch 1 taken 500 times.
|
16500 | for (unsigned i = 32, nb_codes = 0; i > 0; i--) { |
| 278 | 16000 | uint16_t curr = codes_count[i]; // # of leafs of length i | |
| 279 | 16000 | codes_count[i] = nb_codes / 2; // # of non-leaf nodes on level i | |
| 280 | 16000 | nb_codes = codes_count[i] + curr; // # of nodes on level i | |
| 281 | } | ||
| 282 | |||
| 283 |
2/2✓ Branch 0 taken 128000 times.
✓ Branch 1 taken 500 times.
|
128500 | for (unsigned i = 0; i < 256; i++) { |
| 284 | 128000 | he[i].code = codes_count[he[i].len]; | |
| 285 | 128000 | codes_count[he[i].len]++; | |
| 286 | } | ||
| 287 | 500 | } | |
| 288 | |||
| 289 | 1500 | static void count_usage(const uint8_t *src, int width, | |
| 290 | int height, int64_t *counts) | ||
| 291 | { | ||
| 292 |
2/2✓ Branch 0 taken 91500 times.
✓ Branch 1 taken 1500 times.
|
93000 | for (int j = 0; j < height; j++) { |
| 293 |
2/2✓ Branch 0 taken 28051800 times.
✓ Branch 1 taken 91500 times.
|
28143300 | for (int i = 0; i < width; i++) |
| 294 | 28051800 | counts[src[i]]++; | |
| 295 | 91500 | src += width; | |
| 296 | } | ||
| 297 | 1500 | } | |
| 298 | |||
| 299 | typedef struct PackageMergerList { | ||
| 300 | int nitems; ///< number of items in the list and probability ex. 4 | ||
| 301 | int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13 | ||
| 302 | int probability[514]; ///< probability of each item 3, 8, 18, 46 | ||
| 303 | int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E | ||
| 304 | } PackageMergerList; | ||
| 305 | |||
| 306 | 958500 | static int compare_by_prob(const void *a, const void *b) | |
| 307 | { | ||
| 308 | 958500 | const PTable *a2 = a; | |
| 309 | 958500 | const PTable *b2 = b; | |
| 310 | 958500 | return a2->prob - b2->prob; | |
| 311 | } | ||
| 312 | |||
| 313 | 500 | static void magy_huffman_compute_bits(PTable *prob_table, HuffEntry *distincts, | |
| 314 | uint16_t codes_counts[33], | ||
| 315 | int size, int max_length) | ||
| 316 | { | ||
| 317 | 500 | PackageMergerList list_a, list_b, *to = &list_a, *from = &list_b, *temp; | |
| 318 | int times, i, j, k; | ||
| 319 | 500 | int nbits[257] = {0}; | |
| 320 | int min; | ||
| 321 | |||
| 322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
|
500 | av_assert0(max_length > 0); |
| 323 | |||
| 324 | 500 | to->nitems = 0; | |
| 325 | 500 | from->nitems = 0; | |
| 326 | 500 | to->item_idx[0] = 0; | |
| 327 | 500 | from->item_idx[0] = 0; | |
| 328 |
44/44✓ Branch 0 taken 32850 times.
✓ Branch 1 taken 7496 times.
✓ Branch 3 taken 9871 times.
✓ Branch 4 taken 22979 times.
✓ Branch 6 taken 2624 times.
✓ Branch 7 taken 7247 times.
✓ Branch 9 taken 4327 times.
✓ Branch 10 taken 18652 times.
✓ Branch 12 taken 8987 times.
✓ Branch 13 taken 23863 times.
✓ Branch 14 taken 5305 times.
✓ Branch 15 taken 27545 times.
✓ Branch 16 taken 464472 times.
✓ Branch 17 taken 6627 times.
✓ Branch 19 taken 282426 times.
✓ Branch 20 taken 182046 times.
✓ Branch 21 taken 316985 times.
✓ Branch 22 taken 14152 times.
✓ Branch 24 taken 142464 times.
✓ Branch 25 taken 174521 times.
✓ Branch 26 taken 14152 times.
✓ Branch 27 taken 174521 times.
✓ Branch 28 taken 188673 times.
✓ Branch 29 taken 27545 times.
✓ Branch 30 taken 11876 times.
✓ Branch 31 taken 15669 times.
✓ Branch 32 taken 7875 times.
✓ Branch 33 taken 4001 times.
✓ Branch 34 taken 3497 times.
✓ Branch 35 taken 4378 times.
✓ Branch 36 taken 70997 times.
✓ Branch 37 taken 4785 times.
✓ Branch 39 taken 68284 times.
✓ Branch 40 taken 2713 times.
✓ Branch 41 taken 4785 times.
✓ Branch 42 taken 2713 times.
✓ Branch 43 taken 10891 times.
✓ Branch 44 taken 11869 times.
✓ Branch 46 taken 2488 times.
✓ Branch 47 taken 5008 times.
✓ Branch 48 taken 40346 times.
✓ Branch 49 taken 5674 times.
✓ Branch 50 taken 23260 times.
✓ Branch 51 taken 500 times.
|
755912 | AV_QSORT(prob_table, size, PTable, compare_by_prob); |
| 329 | |||
| 330 |
2/2✓ Branch 0 taken 6500 times.
✓ Branch 1 taken 500 times.
|
7000 | for (times = 0; times <= max_length; times++) { |
| 331 | 6500 | to->nitems = 0; | |
| 332 | 6500 | to->item_idx[0] = 0; | |
| 333 | |||
| 334 | 6500 | j = 0; | |
| 335 | 6500 | k = 0; | |
| 336 | |||
| 337 |
2/2✓ Branch 0 taken 6000 times.
✓ Branch 1 taken 500 times.
|
6500 | if (times < max_length) { |
| 338 | 6000 | i = 0; | |
| 339 | } | ||
| 340 |
4/4✓ Branch 0 taken 2800151 times.
✓ Branch 1 taken 148849 times.
✓ Branch 2 taken 142349 times.
✓ Branch 3 taken 6500 times.
|
2949000 | while (i < size || j + 1 < from->nitems) { |
| 341 | 2942500 | to->nitems++; | |
| 342 | 2942500 | to->item_idx[to->nitems] = to->item_idx[to->nitems - 1]; | |
| 343 |
2/2✓ Branch 0 taken 2800151 times.
✓ Branch 1 taken 142349 times.
|
2942500 | if (i < size && |
| 344 |
2/2✓ Branch 0 taken 2672151 times.
✓ Branch 1 taken 128000 times.
|
2800151 | (j + 1 >= from->nitems || |
| 345 | 2672151 | prob_table[i].prob < | |
| 346 |
2/2✓ Branch 0 taken 1408000 times.
✓ Branch 1 taken 1264151 times.
|
2672151 | from->probability[j] + from->probability[j + 1])) { |
| 347 | 1536000 | to->items[to->item_idx[to->nitems]++] = prob_table[i].value; | |
| 348 | 1536000 | to->probability[to->nitems - 1] = prob_table[i].prob; | |
| 349 | 1536000 | i++; | |
| 350 | } else { | ||
| 351 |
2/2✓ Branch 0 taken 9588724 times.
✓ Branch 1 taken 1406500 times.
|
10995224 | for (k = from->item_idx[j]; k < from->item_idx[j + 2]; k++) { |
| 352 | 9588724 | to->items[to->item_idx[to->nitems]++] = from->items[k]; | |
| 353 | } | ||
| 354 | 1406500 | to->probability[to->nitems - 1] = | |
| 355 | 1406500 | from->probability[j] + from->probability[j + 1]; | |
| 356 | 1406500 | j += 2; | |
| 357 | } | ||
| 358 | } | ||
| 359 | 6500 | temp = to; | |
| 360 | 6500 | to = from; | |
| 361 | 6500 | from = temp; | |
| 362 | } | ||
| 363 | |||
| 364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
|
500 | min = (size - 1 < from->nitems) ? size - 1 : from->nitems; |
| 365 |
2/2✓ Branch 0 taken 1345707 times.
✓ Branch 1 taken 500 times.
|
1346207 | for (i = 0; i < from->item_idx[min]; i++) { |
| 366 | 1345707 | nbits[from->items[i]]++; | |
| 367 | } | ||
| 368 | |||
| 369 |
2/2✓ Branch 0 taken 128000 times.
✓ Branch 1 taken 500 times.
|
128500 | for (i = 0; i < size; i++) { |
| 370 | 128000 | distincts[i].len = nbits[i]; | |
| 371 | 128000 | codes_counts[nbits[i]]++; | |
| 372 | } | ||
| 373 | 500 | } | |
| 374 | |||
| 375 | 1500 | static int count_plane_slice(AVCodecContext *avctx, int n, int plane) | |
| 376 | { | ||
| 377 | 1500 | MagicYUVContext *s = avctx->priv_data; | |
| 378 | 1500 | Slice *sl = &s->slices[n * s->planes + plane]; | |
| 379 | 1500 | const uint8_t *dst = sl->slice; | |
| 380 | 1500 | int64_t *counts = sl->counts; | |
| 381 | |||
| 382 | 1500 | memset(counts, 0, sizeof(sl->counts)); | |
| 383 | |||
| 384 | 1500 | count_usage(dst, sl->width, sl->height, counts); | |
| 385 | |||
| 386 | 1500 | return 0; | |
| 387 | } | ||
| 388 | |||
| 389 | 500 | static void generate_codes(AVCodecContext *avctx, | |
| 390 | HuffEntry *he, int plane) | ||
| 391 | { | ||
| 392 | 500 | MagicYUVContext *s = avctx->priv_data; | |
| 393 | PTable counts[256]; | ||
| 394 | 500 | uint16_t codes_counts[33] = { 0 }; | |
| 395 | |||
| 396 |
2/2✓ Branch 0 taken 128000 times.
✓ Branch 1 taken 500 times.
|
128500 | for (size_t i = 0; i < FF_ARRAY_ELEMS(counts); i++) { |
| 397 | 128000 | counts[i].prob = 1; | |
| 398 | 128000 | counts[i].value = i; | |
| 399 | } | ||
| 400 | |||
| 401 |
2/2✓ Branch 0 taken 1500 times.
✓ Branch 1 taken 500 times.
|
2000 | for (int n = 0; n < s->nb_slices; n++) { |
| 402 | 1500 | Slice *sl = &s->slices[n * s->planes + plane]; | |
| 403 | 1500 | int64_t *slice_counts = sl->counts; | |
| 404 | |||
| 405 |
2/2✓ Branch 0 taken 384000 times.
✓ Branch 1 taken 1500 times.
|
385500 | for (int i = 0; i < 256; i++) |
| 406 | 384000 | counts[i].prob += slice_counts[i]; | |
| 407 | } | ||
| 408 | |||
| 409 | 500 | magy_huffman_compute_bits(counts, he, codes_counts, 256, 12); | |
| 410 | |||
| 411 | 500 | calculate_codes(he, codes_counts); | |
| 412 | 500 | } | |
| 413 | |||
| 414 | 500 | static void output_codes(PutByteContext *pb, const HuffEntry he[256]) | |
| 415 | { | ||
| 416 |
2/2✓ Branch 0 taken 128000 times.
✓ Branch 1 taken 500 times.
|
128500 | for (int i = 0; i < 256; i++) { |
| 417 | // The seven low bits are len; the top bit means the run of | ||
| 418 | // codes of this length has length one. | ||
| 419 | 128000 | bytestream2_put_byteu(pb, he[i].len); | |
| 420 | } | ||
| 421 | 500 | } | |
| 422 | |||
| 423 | ✗ | static void encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, | |
| 424 | int width, int height, int prediction) | ||
| 425 | { | ||
| 426 | ✗ | unsigned count = width * height; | |
| 427 | |||
| 428 | ✗ | dst[0] = 1; | |
| 429 | ✗ | dst[1] = prediction; | |
| 430 | |||
| 431 | ✗ | memcpy(dst + 2, src, count); | |
| 432 | ✗ | } | |
| 433 | |||
| 434 | 1500 | static void encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_size, | |
| 435 | int width, int height, HuffEntry *he, int prediction) | ||
| 436 | { | ||
| 437 | PutBitContext pb; | ||
| 438 | |||
| 439 | 1500 | init_put_bits(&pb, dst, dst_size); | |
| 440 | |||
| 441 | 1500 | put_bits(&pb, 8, 0); | |
| 442 | 1500 | put_bits(&pb, 8, prediction); | |
| 443 | |||
| 444 |
2/2✓ Branch 0 taken 91500 times.
✓ Branch 1 taken 1500 times.
|
93000 | for (int j = 0; j < height; j++) { |
| 445 |
2/2✓ Branch 0 taken 28051800 times.
✓ Branch 1 taken 91500 times.
|
28143300 | for (int i = 0; i < width; i++) { |
| 446 | 28051800 | const int idx = src[i]; | |
| 447 | 28051800 | const int len = he[idx].len; | |
| 448 | 28051800 | put_bits(&pb, len, he[idx].code); | |
| 449 | } | ||
| 450 | |||
| 451 | 91500 | src += width; | |
| 452 | } | ||
| 453 | |||
| 454 | 1500 | flush_put_bits(&pb); | |
| 455 | av_assert1(put_bytes_left(&pb, 0) <= 3); | ||
| 456 | 1500 | } | |
| 457 | |||
| 458 | 600 | static int encode_slice(AVCodecContext *avctx, void *tdata, | |
| 459 | int n, int threadnr) | ||
| 460 | { | ||
| 461 | 600 | MagicYUVContext *s = avctx->priv_data; | |
| 462 | |||
| 463 |
2/2✓ Branch 0 taken 1500 times.
✓ Branch 1 taken 600 times.
|
2100 | for (int i = 0; i < s->planes; i++) { |
| 464 | 1500 | Slice *sl = &s->slices[n * s->planes + i]; | |
| 465 | |||
| 466 | // Zero the padding now | ||
| 467 | 1500 | AV_WN32(sl->dst + sl->size - 4, 0); | |
| 468 | |||
| 469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1500 times.
|
1500 | if (sl->encode_raw) |
| 470 | ✗ | encode_plane_slice_raw(sl->slice, sl->dst, | |
| 471 | sl->width, sl->height, s->frame_pred); | ||
| 472 | else | ||
| 473 | 1500 | encode_plane_slice(sl->slice, | |
| 474 | sl->dst, | ||
| 475 | sl->size, | ||
| 476 | sl->width, sl->height, | ||
| 477 | 1500 | s->he[i], s->frame_pred); | |
| 478 | } | ||
| 479 | |||
| 480 | 600 | return 0; | |
| 481 | } | ||
| 482 | |||
| 483 | 600 | static int predict_slice(AVCodecContext *avctx, void *tdata, | |
| 484 | int n, int threadnr) | ||
| 485 | { | ||
| 486 | 600 | size_t max_align = av_cpu_max_align(); | |
| 487 | 600 | const int aligned_width = FFALIGN(avctx->width, max_align); | |
| 488 | 600 | MagicYUVContext *s = avctx->priv_data; | |
| 489 | 600 | const int slice_height = s->slice_height; | |
| 490 | 600 | const int last_height = FFMIN(slice_height, avctx->height - n * slice_height); | |
| 491 |
2/2✓ Branch 0 taken 400 times.
✓ Branch 1 taken 200 times.
|
600 | const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height; |
| 492 | 600 | const int width = avctx->width; | |
| 493 | 600 | AVFrame *frame = tdata; | |
| 494 | |||
| 495 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 550 times.
|
600 | if (s->correlate) { |
| 496 | 50 | uint8_t *decorrelated[2] = { s->decorrelate_buf[0] + n * slice_height * aligned_width, | |
| 497 | 50 | s->decorrelate_buf[1] + n * slice_height * aligned_width }; | |
| 498 | 50 | const int decorrelate_linesize = aligned_width; | |
| 499 | 100 | const uint8_t *const data[4] = { decorrelated[0], frame->data[0] + n * slice_height * frame->linesize[0], | |
| 500 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | decorrelated[1], s->planes == 4 ? frame->data[3] + n * slice_height * frame->linesize[3] : NULL }; |
| 501 | const uint8_t *r, *g, *b; | ||
| 502 | 50 | const int linesize[4] = { decorrelate_linesize, frame->linesize[0], | |
| 503 | 50 | decorrelate_linesize, frame->linesize[3] }; | |
| 504 | |||
| 505 | 50 | g = frame->data[0] + n * slice_height * frame->linesize[0]; | |
| 506 | 50 | b = frame->data[1] + n * slice_height * frame->linesize[1]; | |
| 507 | 50 | r = frame->data[2] + n * slice_height * frame->linesize[2]; | |
| 508 | |||
| 509 |
2/2✓ Branch 0 taken 14400 times.
✓ Branch 1 taken 50 times.
|
14450 | for (int i = 0; i < height; i++) { |
| 510 | 14400 | s->llvidencdsp.diff_bytes(decorrelated[0], b, g, width); | |
| 511 | 14400 | s->llvidencdsp.diff_bytes(decorrelated[1], r, g, width); | |
| 512 | 14400 | g += frame->linesize[0]; | |
| 513 | 14400 | b += frame->linesize[1]; | |
| 514 | 14400 | r += frame->linesize[2]; | |
| 515 | 14400 | decorrelated[0] += decorrelate_linesize; | |
| 516 | 14400 | decorrelated[1] += decorrelate_linesize; | |
| 517 | } | ||
| 518 | |||
| 519 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 50 times.
|
200 | for (int i = 0; i < s->planes; i++) { |
| 520 | 150 | Slice *sl = &s->slices[n * s->planes + i]; | |
| 521 | |||
| 522 | 150 | s->predict(s, data[i], sl->slice, linesize[i], | |
| 523 | frame->width, height); | ||
| 524 | } | ||
| 525 | } else { | ||
| 526 |
2/2✓ Branch 0 taken 1350 times.
✓ Branch 1 taken 550 times.
|
1900 | for (int i = 0; i < s->planes; i++) { |
| 527 | 1350 | Slice *sl = &s->slices[n * s->planes + i]; | |
| 528 | |||
| 529 | 1350 | s->predict(s, frame->data[i] + n * (slice_height >> s->vshift[i]) * frame->linesize[i], | |
| 530 | sl->slice, | ||
| 531 | 1350 | frame->linesize[i], | |
| 532 | sl->width, sl->height); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 |
2/2✓ Branch 0 taken 1500 times.
✓ Branch 1 taken 600 times.
|
2100 | for (int p = 0; p < s->planes; p++) |
| 537 | 1500 | count_plane_slice(avctx, n, p); | |
| 538 | |||
| 539 | 600 | return 0; | |
| 540 | } | ||
| 541 | |||
| 542 | 200 | static int magy_encode_frame(AVCodecContext *avctx, AVPacket *pkt, | |
| 543 | const AVFrame *frame, int *got_packet) | ||
| 544 | { | ||
| 545 | 200 | MagicYUVContext *s = avctx->priv_data; | |
| 546 | PutByteContext pb; | ||
| 547 | 200 | int header_size = 32 + (4 + 1) * (s->planes * s->nb_slices + 1) | |
| 548 | 200 | + 256 * s->planes /* Hufftables */; | |
| 549 | 200 | int64_t pkt_size = header_size; | |
| 550 | int ret; | ||
| 551 | |||
| 552 | 200 | avctx->execute2(avctx, predict_slice, (void *)frame, NULL, s->nb_slices); | |
| 553 | |||
| 554 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 200 times.
|
700 | for (int i = 0; i < s->planes; i++) |
| 555 | 500 | generate_codes(avctx, s->he[i], i); | |
| 556 | |||
| 557 |
2/2✓ Branch 0 taken 600 times.
✓ Branch 1 taken 200 times.
|
800 | for (int i = 0; i < s->nb_slices; ++i) { |
| 558 |
2/2✓ Branch 0 taken 1500 times.
✓ Branch 1 taken 600 times.
|
2100 | for (int j = 0; j < s->planes; ++j) { |
| 559 | 1500 | Slice *const sl = &s->slices[i * s->planes + j]; | |
| 560 | 1500 | int64_t size = 0; | |
| 561 | |||
| 562 |
2/2✓ Branch 0 taken 384000 times.
✓ Branch 1 taken 1500 times.
|
385500 | for (size_t k = 0; k < FF_ARRAY_ELEMS(sl->counts); ++k) |
| 563 | 384000 | size += sl->counts[k] * s->he[j][k].len; | |
| 564 | 1500 | size = AV_CEIL_RSHIFT(size, 3); | |
| 565 | 1500 | sl->encode_raw = size >= sl->width * sl->height; | |
| 566 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1500 times.
|
1500 | if (sl->encode_raw) |
| 567 | ✗ | size = sl->width * sl->height; | |
| 568 | 1500 | sl->size = FFALIGN(size + 2, 4); | |
| 569 | 1500 | sl->pos = pkt_size; | |
| 570 | 1500 | pkt_size += sl->size; | |
| 571 | } | ||
| 572 | } | ||
| 573 | |||
| 574 | 200 | ret = ff_get_encode_buffer(avctx, pkt, pkt_size, 0); | |
| 575 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
|
200 | if (ret < 0) |
| 576 | ✗ | return ret; | |
| 577 | |||
| 578 | 200 | bytestream2_init_writer(&pb, pkt->data, pkt->size); | |
| 579 | 200 | bytestream2_put_le32u(&pb, MKTAG('M', 'A', 'G', 'Y')); | |
| 580 | 200 | bytestream2_put_le32u(&pb, 32); // header size | |
| 581 | 200 | bytestream2_put_byteu(&pb, 7); // version | |
| 582 | 200 | bytestream2_put_byteu(&pb, s->format); | |
| 583 | 200 | bytestream2_put_byteu(&pb, 12); // max huffman length | |
| 584 | 200 | bytestream2_put_byteu(&pb, 0); | |
| 585 | |||
| 586 | 200 | bytestream2_put_byteu(&pb, 0); | |
| 587 | 200 | bytestream2_put_byteu(&pb, 0); | |
| 588 | 200 | bytestream2_put_byteu(&pb, 32); // coder type | |
| 589 | 200 | bytestream2_put_byteu(&pb, 0); | |
| 590 | |||
| 591 | 200 | bytestream2_put_le32u(&pb, avctx->width); | |
| 592 | 200 | bytestream2_put_le32u(&pb, avctx->height); | |
| 593 | 200 | bytestream2_put_le32u(&pb, avctx->width); | |
| 594 | 200 | bytestream2_put_le32u(&pb, s->slice_height); | |
| 595 | |||
| 596 | // Slice position is relative to the current position (i.e. 32) | ||
| 597 | 200 | bytestream2_put_le32u(&pb, header_size - 32); | |
| 598 | |||
| 599 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 200 times.
|
700 | for (int i = 0; i < s->planes; ++i) { |
| 600 |
2/2✓ Branch 0 taken 1500 times.
✓ Branch 1 taken 500 times.
|
2000 | for (int j = 0; j < s->nb_slices; ++j) { |
| 601 | 1500 | Slice *const sl = &s->slices[j * s->planes + i]; | |
| 602 | 1500 | bytestream2_put_le32u(&pb, sl->pos - 32); | |
| 603 | 1500 | sl->dst = pkt->data + sl->pos; | |
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | 200 | bytestream2_put_byteu(&pb, s->planes); | |
| 608 | |||
| 609 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 200 times.
|
700 | for (int i = 0; i < s->planes; i++) { |
| 610 |
2/2✓ Branch 0 taken 1500 times.
✓ Branch 1 taken 500 times.
|
2000 | for (int n = 0; n < s->nb_slices; n++) |
| 611 | 1500 | bytestream2_put_byteu(&pb, n * s->planes + i); | |
| 612 | } | ||
| 613 | |||
| 614 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 200 times.
|
700 | for (int i = 0; i < s->planes; ++i) |
| 615 | 500 | output_codes(&pb, s->he[i]); | |
| 616 | |||
| 617 | 200 | avctx->execute2(avctx, encode_slice, NULL, NULL, s->nb_slices); | |
| 618 | |||
| 619 | 200 | *got_packet = 1; | |
| 620 | |||
| 621 | 200 | return 0; | |
| 622 | } | ||
| 623 | |||
| 624 | 4 | static av_cold int magy_encode_close(AVCodecContext *avctx) | |
| 625 | { | ||
| 626 | 4 | MagicYUVContext *s = avctx->priv_data; | |
| 627 | |||
| 628 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (s->slices) { |
| 629 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 4 times.
|
34 | for (int i = 0; i < s->planes * s->nb_slices; i++) { |
| 630 | 30 | Slice *sl = &s->slices[i]; | |
| 631 | |||
| 632 | 30 | av_freep(&sl->slice); | |
| 633 | } | ||
| 634 | 4 | av_freep(&s->slices); | |
| 635 | } | ||
| 636 | 4 | av_freep(&s->decorrelate_buf); | |
| 637 | |||
| 638 | 4 | return 0; | |
| 639 | } | ||
| 640 | |||
| 641 | #define OFFSET(x) offsetof(MagicYUVContext, x) | ||
| 642 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM | ||
| 643 | static const AVOption options[] = { | ||
| 644 | { "pred", "Prediction method", OFFSET(frame_pred), AV_OPT_TYPE_INT, {.i64=LEFT}, LEFT, MEDIAN, VE, .unit = "pred" }, | ||
| 645 | { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LEFT }, 0, 0, VE, .unit = "pred" }, | ||
| 646 | { "gradient", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = GRADIENT }, 0, 0, VE, .unit = "pred" }, | ||
| 647 | { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MEDIAN }, 0, 0, VE, .unit = "pred" }, | ||
| 648 | { NULL}, | ||
| 649 | }; | ||
| 650 | |||
| 651 | static const AVClass magicyuv_class = { | ||
| 652 | .class_name = "magicyuv", | ||
| 653 | .item_name = av_default_item_name, | ||
| 654 | .option = options, | ||
| 655 | .version = LIBAVUTIL_VERSION_INT, | ||
| 656 | }; | ||
| 657 | |||
| 658 | const FFCodec ff_magicyuv_encoder = { | ||
| 659 | .p.name = "magicyuv", | ||
| 660 | CODEC_LONG_NAME("MagicYUV video"), | ||
| 661 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
| 662 | .p.id = AV_CODEC_ID_MAGICYUV, | ||
| 663 | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | | ||
| 664 | AV_CODEC_CAP_SLICE_THREADS | | ||
| 665 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, | ||
| 666 | .priv_data_size = sizeof(MagicYUVContext), | ||
| 667 | .p.priv_class = &magicyuv_class, | ||
| 668 | .init = magy_encode_init, | ||
| 669 | .close = magy_encode_close, | ||
| 670 | FF_CODEC_ENCODE_CB(magy_encode_frame), | ||
| 671 | CODEC_PIXFMTS(AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, | ||
| 672 | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, | ||
| 673 | AV_PIX_FMT_GRAY8), | ||
| 674 | .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */ | ||
| 675 | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, | ||
| 676 | }; | ||
| 677 |