| @@ -26,6 +26,7 @@ · 25 unmodified lines |
| 26 | #include "config_components.h" | 26 | #include "config_components.h" |
| 27 | | 27 | |
| 28 | #include "libavutil/attributes.h" | 28 | #include "libavutil/attributes.h" |
| | 29 | #include "libavutil/intreadwrite.h" |
| 29 | #include "libavutil/mem.h" | 30 | #include "libavutil/mem.h" |
| 30 | #include "libavutil/mem_internal.h" | 31 | #include "libavutil/mem_internal.h" |
| 31 | | 32 | |
| @@ -228,55 +229,65 @@ static inline void dct_get(ASVEncContext *a, const AVFrame *frame, · 196 unmodified lines |
| 228 | } | 229 | } |
| 229 | } | 230 | } |
| 230 | | 231 | |
| 231 | static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, | 232 | static void handle_partial_mb(ASVEncContext *a, const uint8_t *const data[3], |
| 232 | const AVFrame *pict, int *got_packet) | 233 | const int linesizes[3], |
| | 234 | int valid_width, int valid_height) |
| 233 | { | 235 | { |
| 234 | ASVEncContext *const a = avctx->priv_data; | 236 | const int nb_blocks = a->c.avctx->flags & AV_CODEC_FLAG_GRAY ? 4 : 6; |
| 235 | const ASVCommonContext *const c = &a->c; | 237 | static const struct Descriptor { |
| 236 | int size, ret; | 238 | uint8_t x_offset, y_offset; |
| 237 | | 239 | uint8_t component, subsampling; |
| 238 | if (pict->width % 16 || pict->height % 16) { | 240 | } block_descriptor[] = { |
| 239 | AVFrame *clone = av_frame_alloc(); | 241 | { 0, 0, 0, 0 }, { 8, 0, 0, 0 }, { 0, 8, 0, 0 }, { 8, 8, 0, 0 }, |
| 240 | int i; | 242 | { 0, 0, 1, 1 }, { 0, 0, 2, 1 }, |
| 241 | | 243 | }; |
| 242 | if (!clone) | 244 | |
| 243 | return AVERROR(ENOMEM); | 245 | for (int i = 0; i < nb_blocks; ++i) { |
| 244 | clone->format = pict->format; | 246 | const struct Descriptor *const desc = block_descriptor + i; |
| 245 | clone->width = FFALIGN(pict->width, 16); | 247 | int width_avail = AV_CEIL_RSHIFT(valid_width, desc->subsampling) - desc->x_offset; |
| 246 | clone->height = FFALIGN(pict->height, 16); | 248 | int height_avail = AV_CEIL_RSHIFT(valid_height, desc->subsampling) - desc->y_offset; |
| 247 | ret = av_frame_get_buffer(clone, 0); | 249 | |
| 248 | if (ret < 0) { | 250 | if (width_avail <= 0 || height_avail <= 0) { |
| 249 | av_frame_free(&clone); | 251 | // This block is outside of the visible part; don't replicate pixels, |
| 250 | return ret; | 252 | // just zero the block, so that only the dc value will be coded. |
| | 253 | memset(a->block[i], 0, sizeof(a->block[i])); |
| | 254 | continue; |
| 251 | } | 255 | } |
| 252 | | 256 | width_avail = FFMIN(width_avail, 8); |
| 253 | ret = av_frame_copy(clone, pict); | 257 | height_avail = FFMIN(height_avail, 8); |
| 254 | if (ret < 0) { | 258 | |
| 255 | av_frame_free(&clone); | 259 | ptrdiff_t linesize = linesizes[desc->component]; |
| 256 | return ret; | 260 | const uint8_t *src = data[desc->component] + desc->y_offset * linesize + desc->x_offset; |
| | 261 | int16_t *block = a->block[i]; |
| | 262 | |
| | 263 | for (int h = 0;; block += 8, src += linesize) { |
| | 264 | int16_t last; |
| | 265 | for (int w = 0; w < width_avail; ++w) |
| | 266 | last = block[w] = src[w]; |
| | 267 | for (int w = width_avail; w < 8; ++w) |
| | 268 | block[w] = last; |
| | 269 | if (++h == height_avail) |
| | 270 | break; |
| 257 | } | 271 | } |
| 258 | | 272 | const int16_t *const last_row = block; |
| 259 | for (i = 0; i<3; i++) { | 273 | for (int h = height_avail; h < 8; ++h) { |
| 260 | int x, y; | 274 | block += 8; |
| 261 | int w = AV_CEIL_RSHIFT(pict->width, !!i); | 275 | AV_COPY128(block, last_row); |
| 262 | int h = AV_CEIL_RSHIFT(pict->height, !!i); | | |
| 263 | int w2 = AV_CEIL_RSHIFT(clone->width, !!i); | | |
| 264 | int h2 = AV_CEIL_RSHIFT(clone->height, !!i); | | |
| 265 | for (y=0; y<h; y++) | | |
| 266 | for (x=w; x<w2; x++) | | |
| 267 | clone->data[i][x + y*clone->linesize[i]] = | | |
| 268 | clone->data[i][w - 1 + y*clone->linesize[i]]; | | |
| 269 | for (y=h; y<h2; y++) | | |
| 270 | for (x=0; x<w2; x++) | | |
| 271 | clone->data[i][x + y*clone->linesize[i]] = | | |
| 272 | clone->data[i][x + (h-1)*clone->linesize[i]]; | | |
| 273 | } | 276 | } |
| 274 | ret = encode_frame(avctx, pkt, clone, got_packet); | | |
| 275 | | 277 | |
| 276 | av_frame_free(&clone); | 278 | a->fdsp.fdct(a->block[i]); |
| 277 | return ret; | | |
| 278 | } | 279 | } |
| 279 | | 280 | |
| | 281 | encode_mb(a, a->block); |
| | 282 | } |
| | 283 | |
| | 284 | static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
| | 285 | const AVFrame *pict, int *got_packet) |
| | 286 | { |
| | 287 | ASVEncContext *const a = avctx->priv_data; |
| | 288 | const ASVCommonContext *const c = &a->c; |
| | 289 | int size, ret; |
| | 290 | |
| 280 | ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + 3); | 291 | ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + 3); |
| 281 | if (ret < 0) | 292 | if (ret < 0) |
| 282 | return ret; | 293 | return ret; |
| @@ -290,19 +301,37 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, · 7 unmodified lines |
| 290 | } | 301 | } |
| 291 | } | 302 | } |
| 292 | | 303 | |
| 293 | if (c->mb_width2 != c->mb_width) { | 304 | if (avctx->width & 15) { |
| 294 | int mb_x = c->mb_width2; | 305 | const uint8_t *src[3] = { |
| | 306 | pict->data[0] + c->mb_width2 * 16, |
| | 307 | pict->data[1] + c->mb_width2 * 8, |
| | 308 | pict->data[2] + c->mb_width2 * 8, |
| | 309 | }; |
| | 310 | int available_width = avctx->width & 15; |
| | 311 | |
| 295 | for (int mb_y = 0; mb_y < c->mb_height2; mb_y++) { | 312 | for (int mb_y = 0; mb_y < c->mb_height2; mb_y++) { |
| 296 | dct_get(a, pict, mb_x, mb_y); | 313 | handle_partial_mb(a, src, pict->linesize, available_width, 16); |
| 297 | encode_mb(a, a->block); | 314 | src[0] += 16 * pict->linesize[0]; |
| | 315 | src[1] += 8 * pict->linesize[1]; |
| | 316 | src[2] += 8 * pict->linesize[2]; |
| 298 | } | 317 | } |
| 299 | } | 318 | } |
| 300 | | 319 | |
| 301 | if (c->mb_height2 != c->mb_height) { | 320 | if (avctx->height & 15) { |
| 302 | int mb_y = c->mb_height2; | 321 | const uint8_t *src[3] = { |
| 303 | for (int mb_x = 0; mb_x < c->mb_width; mb_x++) { | 322 | pict->data[0] + c->mb_height2 * 16 * pict->linesize[0], |
| 304 | dct_get(a, pict, mb_x, mb_y); | 323 | pict->data[1] + c->mb_height2 * 8 * pict->linesize[1], |
| 305 | encode_mb(a, a->block); | 324 | pict->data[2] + c->mb_height2 * 8 * pict->linesize[2], |
| | 325 | }; |
| | 326 | int available_height = avctx->height & 15; |
| | 327 | |
| | 328 | for (int remaining = avctx->width;; remaining -= 16) { |
| | 329 | handle_partial_mb(a, src, pict->linesize, remaining, available_height); |
| | 330 | if (remaining <= 16) |
| | 331 | break; |
| | 332 | src[0] += 16; |
| | 333 | src[1] += 8; |
| | 334 | src[2] += 8; |
| 306 | } | 335 | } |
| 307 | } | 336 | } |
| 308 | | 337 | |