| @@ -26,6 +26,7 @@ · 25 unmodified lines |
| 26 | 26 | #include "config_components.h" |
| 27 | 27 | |
| 28 | 28 | #include "libavutil/attributes.h" |
| 29 | +#include "libavutil/intreadwrite.h" |
| 29 | 30 | #include "libavutil/mem.h" |
| 30 | 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 | | − const AVFrame *pict, int *got_packet) |
| 232 | +static void handle_partial_mb(ASVEncContext *a, const uint8_t *const data[3], |
| 233 | + const int linesizes[3], |
| 234 | + int valid_width, int valid_height) |
| 233 | 235 | { |
| 234 | | − ASVEncContext *const a = avctx->priv_data; |
| 235 | | − const ASVCommonContext *const c = &a->c; |
| 236 | | − int size, ret; |
| 237 | | − |
| 238 | | − if (pict->width % 16 || pict->height % 16) { |
| 239 | | − AVFrame *clone = av_frame_alloc(); |
| 240 | | − int i; |
| 241 | | − |
| 242 | | − if (!clone) |
| 243 | | − return AVERROR(ENOMEM); |
| 244 | | − clone->format = pict->format; |
| 245 | | − clone->width = FFALIGN(pict->width, 16); |
| 246 | | − clone->height = FFALIGN(pict->height, 16); |
| 247 | | − ret = av_frame_get_buffer(clone, 0); |
| 248 | | − if (ret < 0) { |
| 249 | | − av_frame_free(&clone); |
| 250 | | − return ret; |
| 236 | + const int nb_blocks = a->c.avctx->flags & AV_CODEC_FLAG_GRAY ? 4 : 6; |
| 237 | + static const struct Descriptor { |
| 238 | + uint8_t x_offset, y_offset; |
| 239 | + uint8_t component, subsampling; |
| 240 | + } block_descriptor[] = { |
| 241 | + { 0, 0, 0, 0 }, { 8, 0, 0, 0 }, { 0, 8, 0, 0 }, { 8, 8, 0, 0 }, |
| 242 | + { 0, 0, 1, 1 }, { 0, 0, 2, 1 }, |
| 243 | + }; |
| 244 | + |
| 245 | + for (int i = 0; i < nb_blocks; ++i) { |
| 246 | + const struct Descriptor *const desc = block_descriptor + i; |
| 247 | + int width_avail = AV_CEIL_RSHIFT(valid_width, desc->subsampling) - desc->x_offset; |
| 248 | + int height_avail = AV_CEIL_RSHIFT(valid_height, desc->subsampling) - desc->y_offset; |
| 249 | + |
| 250 | + if (width_avail <= 0 || height_avail <= 0) { |
| 251 | + // This block is outside of the visible part; don't replicate pixels, |
| 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 | | − |
| 253 | | − ret = av_frame_copy(clone, pict); |
| 254 | | − if (ret < 0) { |
| 255 | | − av_frame_free(&clone); |
| 256 | | − return ret; |
| 256 | + width_avail = FFMIN(width_avail, 8); |
| 257 | + height_avail = FFMIN(height_avail, 8); |
| 258 | + |
| 259 | + ptrdiff_t linesize = linesizes[desc->component]; |
| 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 | | − |
| 259 | | − for (i = 0; i<3; i++) { |
| 260 | | − int x, y; |
| 261 | | − int w = AV_CEIL_RSHIFT(pict->width, !!i); |
| 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]]; |
| 272 | + const int16_t *const last_row = block; |
| 273 | + for (int h = height_avail; h < 8; ++h) { |
| 274 | + block += 8; |
| 275 | + AV_COPY128(block, last_row); |
| 273 | 276 | } |
| 274 | | − ret = encode_frame(avctx, pkt, clone, got_packet); |
| 275 | 277 | |
| 276 | | − av_frame_free(&clone); |
| 277 | | − return ret; |
| 278 | + a->fdsp.fdct(a->block[i]); |
| 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 | 291 | ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + 3); |
| 281 | 292 | if (ret < 0) |
| 282 | 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) { |
| 294 | | − int mb_x = c->mb_width2; |
| 304 | + if (avctx->width & 15) { |
| 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 | 312 | for (int mb_y = 0; mb_y < c->mb_height2; mb_y++) { |
| 296 | | − dct_get(a, pict, mb_x, mb_y); |
| 297 | | − encode_mb(a, a->block); |
| 313 | + handle_partial_mb(a, src, pict->linesize, available_width, 16); |
| 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) { |
| 302 | | − int mb_y = c->mb_height2; |
| 303 | | − for (int mb_x = 0; mb_x < c->mb_width; mb_x++) { |
| 304 | | − dct_get(a, pict, mb_x, mb_y); |
| 305 | | − encode_mb(a, a->block); |
| 320 | + if (avctx->height & 15) { |
| 321 | + const uint8_t *src[3] = { |
| 322 | + pict->data[0] + c->mb_height2 * 16 * pict->linesize[0], |
| 323 | + pict->data[1] + c->mb_height2 * 8 * pict->linesize[1], |
| 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 | |