2012-10-08 12:03:08 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2003 Michael Niedermayer
|
|
|
|
|
*
|
2012-10-10 14:04:03 +02:00
|
|
|
* This file is part of FFmpeg.
|
2012-10-08 12:03:08 +02:00
|
|
|
*
|
2012-10-10 14:04:03 +02:00
|
|
|
* FFmpeg is free software; you can redistribute it and/or
|
2012-10-08 12:03:08 +02:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
2012-10-10 14:04:03 +02:00
|
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
2012-10-08 12:03:08 +02:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-10-10 14:04:03 +02:00
|
|
|
* License along with FFmpeg; if not, write to the Free Software
|
2012-10-08 12:03:08 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @file
|
|
|
|
|
* ASUS V1/V2 encoder.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-02-23 14:56:49 +02:00
|
|
|
#include "config_components.h"
|
|
|
|
|
|
2012-10-11 18:50:30 +02:00
|
|
|
#include "libavutil/attributes.h"
|
2025-05-22 15:57:13 +02:00
|
|
|
#include "libavutil/intreadwrite.h"
|
2012-10-08 12:03:08 +02:00
|
|
|
#include "libavutil/mem.h"
|
2022-10-01 17:05:45 +02:00
|
|
|
#include "libavutil/mem_internal.h"
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-23 15:55:24 +02:00
|
|
|
#include "aandcttab.h"
|
2012-10-08 12:03:08 +02:00
|
|
|
#include "asv.h"
|
|
|
|
|
#include "avcodec.h"
|
2022-03-16 18:18:28 +01:00
|
|
|
#include "codec_internal.h"
|
2021-05-11 15:17:13 +02:00
|
|
|
#include "encode.h"
|
2014-02-03 10:09:45 -08:00
|
|
|
#include "fdctdsp.h"
|
2012-10-08 12:03:08 +02:00
|
|
|
#include "mpeg12data.h"
|
2022-10-01 17:05:45 +02:00
|
|
|
#include "pixblockdsp.h"
|
|
|
|
|
#include "put_bits.h"
|
|
|
|
|
|
|
|
|
|
typedef struct ASVEncContext {
|
|
|
|
|
ASVCommonContext c;
|
|
|
|
|
|
|
|
|
|
PutBitContext pb;
|
|
|
|
|
|
2025-05-27 15:38:17 +02:00
|
|
|
void (*get_pixels)(int16_t *restrict block,
|
|
|
|
|
const uint8_t *pixels,
|
|
|
|
|
ptrdiff_t stride);
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
PixblockDSPContext pdsp;
|
|
|
|
|
FDCTDSPContext fdsp;
|
|
|
|
|
DECLARE_ALIGNED(32, int16_t, block)[6][64];
|
|
|
|
|
int q_intra_matrix[64];
|
|
|
|
|
} ASVEncContext;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2025-04-11 00:38:59 +02:00
|
|
|
enum {
|
|
|
|
|
ASV1_MAX_BLOCK_SIZE = 8 + 10 * FFMAX(2 /* skip */, 5 /* ccp */ + 4 * 11 /* level */) + 5,
|
|
|
|
|
ASV1_MAX_MB_SIZE = 6 * ASV1_MAX_BLOCK_SIZE,
|
|
|
|
|
ASV2_MAX_BLOCK_SIZE = 4 + 8 + 16 * (6 /* ccp */ + 4 * 13 /* level */),
|
|
|
|
|
ASV2_MAX_MB_SIZE = 6 * ASV2_MAX_BLOCK_SIZE,
|
|
|
|
|
MAX_MB_SIZE = (FFMAX(ASV1_MAX_MB_SIZE, ASV2_MAX_MB_SIZE) + 7) / 8
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
static inline void asv1_put_level(PutBitContext *pb, int level)
|
|
|
|
|
{
|
|
|
|
|
unsigned int index = level + 3;
|
2025-05-22 19:38:24 +02:00
|
|
|
unsigned n, code;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
if (index <= 6) {
|
2025-05-22 19:38:24 +02:00
|
|
|
n = ff_asv_level_tab[index][1];
|
|
|
|
|
code = ff_asv_level_tab[index][0];
|
2014-09-01 15:18:58 -04:00
|
|
|
} else {
|
2025-05-22 19:38:24 +02:00
|
|
|
n = 3 + 8;
|
|
|
|
|
code = (0 /* Escape code */ << 8) | (level & 0xFF);
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
2025-05-22 19:38:24 +02:00
|
|
|
put_bits(pb, n, code);
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
static inline void asv2_put_level(ASVEncContext *a, PutBitContext *pb, int level)
|
2014-09-01 15:18:58 -04:00
|
|
|
{
|
|
|
|
|
unsigned int index = level + 31;
|
2025-05-22 19:38:24 +02:00
|
|
|
unsigned n, code;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
if (index <= 62) {
|
2025-05-22 19:38:24 +02:00
|
|
|
n = ff_asv2_level_tab[index][1];
|
|
|
|
|
code = ff_asv2_level_tab[index][0];
|
2014-09-01 15:18:58 -04:00
|
|
|
} else {
|
2014-09-23 15:46:52 +02:00
|
|
|
if (level < -128 || level > 127) {
|
2022-10-01 17:05:45 +02:00
|
|
|
av_log(a->c.avctx, AV_LOG_WARNING, "Clipping level %d, increase qscale\n", level);
|
2014-09-23 15:46:52 +02:00
|
|
|
level = av_clip_int8(level);
|
|
|
|
|
}
|
2025-05-22 19:38:24 +02:00
|
|
|
n = 5 + 8;
|
|
|
|
|
code = (level & 0xFF) << 5 | /* Escape code */ 0;
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
2025-05-22 19:38:24 +02:00
|
|
|
put_bits_le(pb, n, code);
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
static inline void asv1_encode_block(ASVEncContext *a, int16_t block[64])
|
2014-09-01 15:18:58 -04:00
|
|
|
{
|
|
|
|
|
put_bits(&a->pb, 8, (block[0] + 32) >> 6);
|
|
|
|
|
block[0] = 0;
|
|
|
|
|
|
2025-05-22 19:38:24 +02:00
|
|
|
for (unsigned i = 0, nc_bits = 0, nc_val = 0; i < 10; i++) {
|
2014-09-01 15:18:58 -04:00
|
|
|
const int index = ff_asv_scantab[4 * i];
|
|
|
|
|
int ccp = 0;
|
|
|
|
|
|
|
|
|
|
if ((block[index + 0] = (block[index + 0] *
|
|
|
|
|
a->q_intra_matrix[index + 0] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 8;
|
|
|
|
|
if ((block[index + 8] = (block[index + 8] *
|
|
|
|
|
a->q_intra_matrix[index + 8] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 4;
|
|
|
|
|
if ((block[index + 1] = (block[index + 1] *
|
|
|
|
|
a->q_intra_matrix[index + 1] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 2;
|
|
|
|
|
if ((block[index + 9] = (block[index + 9] *
|
|
|
|
|
a->q_intra_matrix[index + 9] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 1;
|
|
|
|
|
|
|
|
|
|
if (ccp) {
|
2025-05-22 19:38:24 +02:00
|
|
|
put_bits(&a->pb, nc_bits + ff_asv_ccp_tab[ccp][1],
|
|
|
|
|
nc_val << ff_asv_ccp_tab[ccp][1] /* Skip */ |
|
|
|
|
|
ff_asv_ccp_tab[ccp][0]);
|
|
|
|
|
nc_bits = 0;
|
|
|
|
|
nc_val = 0;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
if (ccp & 8)
|
|
|
|
|
asv1_put_level(&a->pb, block[index + 0]);
|
|
|
|
|
if (ccp & 4)
|
|
|
|
|
asv1_put_level(&a->pb, block[index + 8]);
|
|
|
|
|
if (ccp & 2)
|
|
|
|
|
asv1_put_level(&a->pb, block[index + 1]);
|
|
|
|
|
if (ccp & 1)
|
|
|
|
|
asv1_put_level(&a->pb, block[index + 9]);
|
|
|
|
|
} else {
|
2025-05-22 19:38:24 +02:00
|
|
|
nc_bits += 2;
|
|
|
|
|
nc_val = (nc_val << 2) | 2;
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-12 23:22:27 +02:00
|
|
|
put_bits(&a->pb, 5, 0xF); /* End of block */
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
static inline void asv2_encode_block(ASVEncContext *a, int16_t block[64])
|
2014-09-01 15:18:58 -04:00
|
|
|
{
|
2012-10-08 12:03:08 +02:00
|
|
|
int i;
|
2014-09-01 15:18:58 -04:00
|
|
|
int count = 0;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
for (count = 63; count > 3; count--) {
|
2012-10-08 12:03:08 +02:00
|
|
|
const int index = ff_asv_scantab[count];
|
2014-09-01 15:18:58 -04:00
|
|
|
if ((block[index] * a->q_intra_matrix[index] + (1 << 15)) >> 16)
|
2012-10-08 12:03:08 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count >>= 2;
|
|
|
|
|
|
2025-05-22 19:38:24 +02:00
|
|
|
put_bits_le(&a->pb, 4 + 8, count /* 4 bits */ |
|
|
|
|
|
(/* DC */(block[0] + 32) >> 6) << 4);
|
2014-09-01 15:18:58 -04:00
|
|
|
block[0] = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i <= count; i++) {
|
|
|
|
|
const int index = ff_asv_scantab[4 * i];
|
|
|
|
|
int ccp = 0;
|
|
|
|
|
|
|
|
|
|
if ((block[index + 0] = (block[index + 0] *
|
|
|
|
|
a->q_intra_matrix[index + 0] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 8;
|
|
|
|
|
if ((block[index + 8] = (block[index + 8] *
|
|
|
|
|
a->q_intra_matrix[index + 8] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 4;
|
|
|
|
|
if ((block[index + 1] = (block[index + 1] *
|
|
|
|
|
a->q_intra_matrix[index + 1] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 2;
|
|
|
|
|
if ((block[index + 9] = (block[index + 9] *
|
|
|
|
|
a->q_intra_matrix[index + 9] + (1 << 15)) >> 16))
|
|
|
|
|
ccp |= 1;
|
|
|
|
|
|
2014-09-02 21:57:46 +02:00
|
|
|
av_assert2(i || ccp < 8);
|
2014-09-01 15:18:58 -04:00
|
|
|
if (i)
|
2020-10-13 03:11:37 +02:00
|
|
|
put_bits_le(&a->pb, ff_asv_ac_ccp_tab[ccp][1], ff_asv_ac_ccp_tab[ccp][0]);
|
2014-09-01 15:18:58 -04:00
|
|
|
else
|
2020-10-13 03:11:37 +02:00
|
|
|
put_bits_le(&a->pb, ff_asv_dc_ccp_tab[ccp][1], ff_asv_dc_ccp_tab[ccp][0]);
|
2014-09-01 15:18:58 -04:00
|
|
|
|
|
|
|
|
if (ccp) {
|
|
|
|
|
if (ccp & 8)
|
2014-09-23 15:46:52 +02:00
|
|
|
asv2_put_level(a, &a->pb, block[index + 0]);
|
2014-09-01 15:18:58 -04:00
|
|
|
if (ccp & 4)
|
2014-09-23 15:46:52 +02:00
|
|
|
asv2_put_level(a, &a->pb, block[index + 8]);
|
2014-09-01 15:18:58 -04:00
|
|
|
if (ccp & 2)
|
2014-09-23 15:46:52 +02:00
|
|
|
asv2_put_level(a, &a->pb, block[index + 1]);
|
2014-09-01 15:18:58 -04:00
|
|
|
if (ccp & 1)
|
2014-09-23 15:46:52 +02:00
|
|
|
asv2_put_level(a, &a->pb, block[index + 9]);
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
static inline int encode_mb(ASVEncContext *a, int16_t block[6][64])
|
2014-09-01 15:18:58 -04:00
|
|
|
{
|
2012-10-08 12:03:08 +02:00
|
|
|
int i;
|
|
|
|
|
|
2021-03-25 10:27:31 +01:00
|
|
|
av_assert0(put_bytes_left(&a->pb, 0) >= MAX_MB_SIZE);
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
if (a->c.avctx->codec_id == AV_CODEC_ID_ASV1) {
|
2014-09-01 15:18:58 -04:00
|
|
|
for (i = 0; i < 6; i++)
|
2012-10-08 12:03:08 +02:00
|
|
|
asv1_encode_block(a, block[i]);
|
2014-09-01 15:18:58 -04:00
|
|
|
} else {
|
2014-12-10 03:40:25 +01:00
|
|
|
for (i = 0; i < 6; i++) {
|
2012-10-08 12:03:08 +02:00
|
|
|
asv2_encode_block(a, block[i]);
|
2014-12-10 03:40:25 +01:00
|
|
|
}
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
static inline void dct_get(ASVEncContext *a, const AVFrame *frame,
|
2013-11-09 10:14:46 +01:00
|
|
|
int mb_x, int mb_y)
|
|
|
|
|
{
|
2014-09-01 15:18:58 -04:00
|
|
|
int16_t (*block)[64] = a->block;
|
2013-11-09 10:14:46 +01:00
|
|
|
int linesize = frame->linesize[0];
|
2012-10-08 12:03:08 +02:00
|
|
|
int i;
|
|
|
|
|
|
2022-07-26 09:09:44 +02:00
|
|
|
const uint8_t *ptr_y = frame->data[0] + (mb_y * 16 * linesize) + mb_x * 16;
|
|
|
|
|
const uint8_t *ptr_cb = frame->data[1] + (mb_y * 8 * frame->linesize[1]) + mb_x * 8;
|
|
|
|
|
const uint8_t *ptr_cr = frame->data[2] + (mb_y * 8 * frame->linesize[2]) + mb_x * 8;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2025-05-27 15:38:17 +02:00
|
|
|
a->get_pixels(block[0], ptr_y, linesize);
|
|
|
|
|
a->get_pixels(block[1], ptr_y + 8, linesize);
|
|
|
|
|
a->get_pixels(block[2], ptr_y + 8 * linesize, linesize);
|
|
|
|
|
a->get_pixels(block[3], ptr_y + 8 * linesize + 8, linesize);
|
2014-09-01 15:18:58 -04:00
|
|
|
for (i = 0; i < 4; i++)
|
2014-02-03 10:09:45 -08:00
|
|
|
a->fdsp.fdct(block[i]);
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
if (!(a->c.avctx->flags & AV_CODEC_FLAG_GRAY)) {
|
2025-05-27 15:38:17 +02:00
|
|
|
a->get_pixels(block[4], ptr_cb, frame->linesize[1]);
|
|
|
|
|
a->get_pixels(block[5], ptr_cr, frame->linesize[2]);
|
2014-09-01 15:18:58 -04:00
|
|
|
for (i = 4; i < 6; i++)
|
2014-02-03 10:09:45 -08:00
|
|
|
a->fdsp.fdct(block[i]);
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-22 15:57:13 +02:00
|
|
|
static void handle_partial_mb(ASVEncContext *a, const uint8_t *const data[3],
|
|
|
|
|
const int linesizes[3],
|
|
|
|
|
int valid_width, int valid_height)
|
2012-10-08 12:03:08 +02:00
|
|
|
{
|
2025-05-22 15:57:13 +02:00
|
|
|
const int nb_blocks = a->c.avctx->flags & AV_CODEC_FLAG_GRAY ? 4 : 6;
|
|
|
|
|
static const struct Descriptor {
|
|
|
|
|
uint8_t x_offset, y_offset;
|
|
|
|
|
uint8_t component, subsampling;
|
|
|
|
|
} block_descriptor[] = {
|
|
|
|
|
{ 0, 0, 0, 0 }, { 8, 0, 0, 0 }, { 0, 8, 0, 0 }, { 8, 8, 0, 0 },
|
|
|
|
|
{ 0, 0, 1, 1 }, { 0, 0, 2, 1 },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < nb_blocks; ++i) {
|
|
|
|
|
const struct Descriptor *const desc = block_descriptor + i;
|
|
|
|
|
int width_avail = AV_CEIL_RSHIFT(valid_width, desc->subsampling) - desc->x_offset;
|
|
|
|
|
int height_avail = AV_CEIL_RSHIFT(valid_height, desc->subsampling) - desc->y_offset;
|
|
|
|
|
|
|
|
|
|
if (width_avail <= 0 || height_avail <= 0) {
|
|
|
|
|
// This block is outside of the visible part; don't replicate pixels,
|
|
|
|
|
// just zero the block, so that only the dc value will be coded.
|
|
|
|
|
memset(a->block[i], 0, sizeof(a->block[i]));
|
|
|
|
|
continue;
|
2014-05-31 17:07:12 +02:00
|
|
|
}
|
2025-05-22 15:57:13 +02:00
|
|
|
width_avail = FFMIN(width_avail, 8);
|
|
|
|
|
height_avail = FFMIN(height_avail, 8);
|
|
|
|
|
|
|
|
|
|
ptrdiff_t linesize = linesizes[desc->component];
|
|
|
|
|
const uint8_t *src = data[desc->component] + desc->y_offset * linesize + desc->x_offset;
|
|
|
|
|
int16_t *block = a->block[i];
|
|
|
|
|
|
|
|
|
|
for (int h = 0;; block += 8, src += linesize) {
|
|
|
|
|
int16_t last;
|
|
|
|
|
for (int w = 0; w < width_avail; ++w)
|
|
|
|
|
last = block[w] = src[w];
|
|
|
|
|
for (int w = width_avail; w < 8; ++w)
|
|
|
|
|
block[w] = last;
|
|
|
|
|
if (++h == height_avail)
|
|
|
|
|
break;
|
2014-05-31 17:07:12 +02:00
|
|
|
}
|
2025-05-22 15:57:13 +02:00
|
|
|
const int16_t *const last_row = block;
|
|
|
|
|
for (int h = height_avail; h < 8; ++h) {
|
|
|
|
|
block += 8;
|
|
|
|
|
AV_COPY128(block, last_row);
|
2014-05-31 17:07:12 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-22 15:57:13 +02:00
|
|
|
a->fdsp.fdct(a->block[i]);
|
2014-05-31 17:07:12 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-22 15:57:13 +02:00
|
|
|
encode_mb(a, a->block);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
|
|
|
|
|
const AVFrame *pict, int *got_packet)
|
|
|
|
|
{
|
|
|
|
|
ASVEncContext *const a = avctx->priv_data;
|
|
|
|
|
const ASVCommonContext *const c = &a->c;
|
|
|
|
|
int size, ret;
|
|
|
|
|
|
2025-04-11 00:36:59 +02:00
|
|
|
ret = ff_alloc_packet(avctx, pkt, c->mb_height * c->mb_width * MAX_MB_SIZE + 3);
|
|
|
|
|
if (ret < 0)
|
2012-10-08 12:03:08 +02:00
|
|
|
return ret;
|
|
|
|
|
|
2025-05-27 21:46:06 +02:00
|
|
|
if (!PIXBLOCKDSP_8BPP_GET_PIXELS_SUPPORTS_UNALIGNED &&
|
|
|
|
|
((uintptr_t)pict->data[0] & 7 || pict->linesize[0] & 7 ||
|
|
|
|
|
(uintptr_t)pict->data[1] & 7 || pict->linesize[1] & 7 ||
|
|
|
|
|
(uintptr_t)pict->data[2] & 7 || pict->linesize[2] & 7))
|
2025-05-27 15:38:17 +02:00
|
|
|
a->get_pixels = a->pdsp.get_pixels_unaligned;
|
|
|
|
|
else
|
|
|
|
|
a->get_pixels = a->pdsp.get_pixels;
|
|
|
|
|
|
2012-10-08 12:03:08 +02:00
|
|
|
init_put_bits(&a->pb, pkt->data, pkt->size);
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
for (int mb_y = 0; mb_y < c->mb_height2; mb_y++) {
|
|
|
|
|
for (int mb_x = 0; mb_x < c->mb_width2; mb_x++) {
|
2013-11-09 10:14:46 +01:00
|
|
|
dct_get(a, pict, mb_x, mb_y);
|
2012-10-08 12:03:08 +02:00
|
|
|
encode_mb(a, a->block);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-22 15:57:13 +02:00
|
|
|
if (avctx->width & 15) {
|
|
|
|
|
const uint8_t *src[3] = {
|
|
|
|
|
pict->data[0] + c->mb_width2 * 16,
|
|
|
|
|
pict->data[1] + c->mb_width2 * 8,
|
|
|
|
|
pict->data[2] + c->mb_width2 * 8,
|
|
|
|
|
};
|
|
|
|
|
int available_width = avctx->width & 15;
|
|
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
for (int mb_y = 0; mb_y < c->mb_height2; mb_y++) {
|
2025-05-22 15:57:13 +02:00
|
|
|
handle_partial_mb(a, src, pict->linesize, available_width, 16);
|
|
|
|
|
src[0] += 16 * pict->linesize[0];
|
|
|
|
|
src[1] += 8 * pict->linesize[1];
|
|
|
|
|
src[2] += 8 * pict->linesize[2];
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-22 15:57:13 +02:00
|
|
|
if (avctx->height & 15) {
|
|
|
|
|
const uint8_t *src[3] = {
|
|
|
|
|
pict->data[0] + c->mb_height2 * 16 * pict->linesize[0],
|
|
|
|
|
pict->data[1] + c->mb_height2 * 8 * pict->linesize[1],
|
|
|
|
|
pict->data[2] + c->mb_height2 * 8 * pict->linesize[2],
|
|
|
|
|
};
|
|
|
|
|
int available_height = avctx->height & 15;
|
|
|
|
|
|
|
|
|
|
for (int remaining = avctx->width;; remaining -= 16) {
|
|
|
|
|
handle_partial_mb(a, src, pict->linesize, remaining, available_height);
|
|
|
|
|
if (remaining <= 16)
|
|
|
|
|
break;
|
|
|
|
|
src[0] += 16;
|
|
|
|
|
src[1] += 8;
|
|
|
|
|
src[2] += 8;
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 03:11:37 +02:00
|
|
|
if (avctx->codec_id == AV_CODEC_ID_ASV1)
|
|
|
|
|
flush_put_bits(&a->pb);
|
|
|
|
|
else
|
|
|
|
|
flush_put_bits_le(&a->pb);
|
2020-10-13 00:01:29 +02:00
|
|
|
AV_WN32(put_bits_ptr(&a->pb), 0);
|
2021-03-25 12:52:56 +01:00
|
|
|
size = (put_bytes_output(&a->pb) + 3) / 4;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
if (avctx->codec_id == AV_CODEC_ID_ASV1) {
|
2022-10-01 17:05:45 +02:00
|
|
|
c->bbdsp.bswap_buf((uint32_t *) pkt->data,
|
2014-02-13 17:57:05 +01:00
|
|
|
(uint32_t *) pkt->data, size);
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
pkt->size = size * 4;
|
2012-10-08 12:03:08 +02:00
|
|
|
*got_packet = 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
static av_cold int encode_init(AVCodecContext *avctx)
|
|
|
|
|
{
|
2022-10-01 17:05:45 +02:00
|
|
|
ASVEncContext *const a = avctx->priv_data;
|
2012-10-08 12:03:08 +02:00
|
|
|
int i;
|
2014-09-01 15:18:58 -04:00
|
|
|
const int scale = avctx->codec_id == AV_CODEC_ID_ASV1 ? 1 : 2;
|
2022-10-01 17:05:45 +02:00
|
|
|
int inv_qscale;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
|
|
|
|
ff_asv_common_init(avctx);
|
2014-02-03 10:09:45 -08:00
|
|
|
ff_fdctdsp_init(&a->fdsp, avctx);
|
2025-05-27 19:13:45 +02:00
|
|
|
ff_pixblockdsp_init(&a->pdsp, 8);
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-02 21:57:46 +02:00
|
|
|
if (avctx->global_quality <= 0)
|
2014-09-01 15:18:58 -04:00
|
|
|
avctx->global_quality = 4 * FF_QUALITY_SCALE;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2022-10-01 17:05:45 +02:00
|
|
|
inv_qscale = (32 * scale * FF_QUALITY_SCALE +
|
2014-09-01 15:18:58 -04:00
|
|
|
avctx->global_quality / 2) / avctx->global_quality;
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
avctx->extradata = av_mallocz(8);
|
2015-05-31 14:50:21 +02:00
|
|
|
if (!avctx->extradata)
|
|
|
|
|
return AVERROR(ENOMEM);
|
2014-09-01 15:18:58 -04:00
|
|
|
avctx->extradata_size = 8;
|
2025-05-22 22:44:56 +02:00
|
|
|
AV_WL32A(avctx->extradata, inv_qscale);
|
|
|
|
|
AV_WL32A(avctx->extradata + 4, MKTAG('A', 'S', 'U', 'S'));
|
2012-10-08 12:03:08 +02:00
|
|
|
|
2014-09-01 15:18:58 -04:00
|
|
|
for (i = 0; i < 64; i++) {
|
2014-09-23 15:55:24 +02:00
|
|
|
if (a->fdsp.fdct == ff_fdct_ifast) {
|
|
|
|
|
int q = 32LL * scale * ff_mpeg1_default_intra_matrix[i] * ff_aanscales[i];
|
2022-10-01 17:05:45 +02:00
|
|
|
a->q_intra_matrix[i] = (((int64_t)inv_qscale << 30) + q / 2) / q;
|
2014-09-23 15:55:24 +02:00
|
|
|
} else {
|
|
|
|
|
int q = 32 * scale * ff_mpeg1_default_intra_matrix[i];
|
2022-10-01 17:05:45 +02:00
|
|
|
a->q_intra_matrix[i] = ((inv_qscale << 16) + q / 2) / q;
|
2014-09-23 15:55:24 +02:00
|
|
|
}
|
2012-10-08 12:03:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if CONFIG_ASV1_ENCODER
|
2022-03-16 21:09:54 +01:00
|
|
|
const FFCodec ff_asv1_encoder = {
|
|
|
|
|
.p.name = "asv1",
|
2022-08-29 13:38:02 +02:00
|
|
|
CODEC_LONG_NAME("ASUS V1"),
|
2022-03-16 21:09:54 +01:00
|
|
|
.p.type = AVMEDIA_TYPE_VIDEO,
|
|
|
|
|
.p.id = AV_CODEC_ID_ASV1,
|
2022-11-27 13:37:10 +01:00
|
|
|
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
|
2022-10-01 17:05:45 +02:00
|
|
|
.priv_data_size = sizeof(ASVEncContext),
|
2012-10-08 12:03:08 +02:00
|
|
|
.init = encode_init,
|
2022-03-30 23:28:24 +02:00
|
|
|
FF_CODEC_ENCODE_CB(encode_frame),
|
2025-03-07 01:19:27 +01:00
|
|
|
CODEC_PIXFMTS(AV_PIX_FMT_YUV420P),
|
avcodec/internal: add FFCodec.color_ranges
I went through all codecs and put them into five basic categories:
1. JPEG range only
2. MPEG range only
3. Explicitly tagged
4. Broken (codec supports both but encoder ignores tags)
5. N/A (headerless or pseudo-formats)
Filters in category 5 remain untouched. The rest gain an explicit
assignment of their supported color ranges, with codecs in category
4 being set to MPEG-only for safety.
It might be considered redundant to distinguish between 0 (category 5)
and MPEG+JPEG (category 3), but in doing so we effectively communicate
that we can guarantee that these tags will be encoded, which is distinct
from the situation where there are some codecs that simply don't have
tagging or implied semantics (e.g. rawvideo).
A full list of codecs follows:
JPEG range only:
- amv
- roqvideo
MPEG range only:
- asv1, asv2
- avui
- cfhd
- cljr
- dnxhd
- dvvideo
- ffv1
- flv
- h261, h263, h263p
- {h263,vp8}_v4l2m2m
- huffyuv, ffvhuff
- jpeg2000
- libopenjpeg
- libtheora
- libwebp, libwebp_anim
- libx262
- libxavs, libxavs2
- libxvid
- mpeg1video, mpeg2video
- mpeg2_qsv
- mpeg2_vaapi
- mpeg4, msmpeg4, msmpeg4v2, wmv1, wmv2
- mpeg4_omx
- prores, prores_aw, prores_ks
- rv10, rv20
- snow
- speedhq
- svq1
- tiff
- utvideo
Explicitly tagged (MPEG/JPEG):
- {av1,h264,hevc}_nvenc
- {av1,h264,hevc}_vaapi
- {av1,h264,hevc,vp8,vp9,mpeg4}_mediacodec
- {av1,h264,hevc,vp9}_qsv
- h264_amf
- {h264,hevc,prores}_videotoolbox
- libaom-av1
- libkvazaar
- libopenh264
- librav1e
- libsvtav1
- libvpx, libvpx-vp9
- libx264
- libx265
- ljpeg
- mjpeg
- vc2
Broken (encoder ignores tags):
- {av1,hevc}_amf
- {h264,hevc,mpeg4}_v4l2m2m
- h264_omx
- libxeve
- magicyuv
- {vp8,vp9,mjpeg}_vaapi
N/A:
- ayuv, yuv4, y41p, v308, v210, v410, v408 (headerless)
- pgmyuv (headerless)
- rawvideo, bitpacked (headerless)
- vnull, wrapped_avframe (pseudocodecs)
2023-10-11 16:09:33 +02:00
|
|
|
.color_ranges = AVCOL_RANGE_MPEG,
|
2012-10-08 12:03:08 +02:00
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CONFIG_ASV2_ENCODER
|
2022-03-16 21:09:54 +01:00
|
|
|
const FFCodec ff_asv2_encoder = {
|
|
|
|
|
.p.name = "asv2",
|
2022-08-29 13:38:02 +02:00
|
|
|
CODEC_LONG_NAME("ASUS V2"),
|
2022-03-16 21:09:54 +01:00
|
|
|
.p.type = AVMEDIA_TYPE_VIDEO,
|
|
|
|
|
.p.id = AV_CODEC_ID_ASV2,
|
2022-11-27 13:37:10 +01:00
|
|
|
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
|
2022-10-01 17:05:45 +02:00
|
|
|
.priv_data_size = sizeof(ASVEncContext),
|
2012-10-08 12:03:08 +02:00
|
|
|
.init = encode_init,
|
2022-03-30 23:28:24 +02:00
|
|
|
FF_CODEC_ENCODE_CB(encode_frame),
|
2025-03-07 01:19:27 +01:00
|
|
|
CODEC_PIXFMTS(AV_PIX_FMT_YUV420P),
|
avcodec/internal: add FFCodec.color_ranges
I went through all codecs and put them into five basic categories:
1. JPEG range only
2. MPEG range only
3. Explicitly tagged
4. Broken (codec supports both but encoder ignores tags)
5. N/A (headerless or pseudo-formats)
Filters in category 5 remain untouched. The rest gain an explicit
assignment of their supported color ranges, with codecs in category
4 being set to MPEG-only for safety.
It might be considered redundant to distinguish between 0 (category 5)
and MPEG+JPEG (category 3), but in doing so we effectively communicate
that we can guarantee that these tags will be encoded, which is distinct
from the situation where there are some codecs that simply don't have
tagging or implied semantics (e.g. rawvideo).
A full list of codecs follows:
JPEG range only:
- amv
- roqvideo
MPEG range only:
- asv1, asv2
- avui
- cfhd
- cljr
- dnxhd
- dvvideo
- ffv1
- flv
- h261, h263, h263p
- {h263,vp8}_v4l2m2m
- huffyuv, ffvhuff
- jpeg2000
- libopenjpeg
- libtheora
- libwebp, libwebp_anim
- libx262
- libxavs, libxavs2
- libxvid
- mpeg1video, mpeg2video
- mpeg2_qsv
- mpeg2_vaapi
- mpeg4, msmpeg4, msmpeg4v2, wmv1, wmv2
- mpeg4_omx
- prores, prores_aw, prores_ks
- rv10, rv20
- snow
- speedhq
- svq1
- tiff
- utvideo
Explicitly tagged (MPEG/JPEG):
- {av1,h264,hevc}_nvenc
- {av1,h264,hevc}_vaapi
- {av1,h264,hevc,vp8,vp9,mpeg4}_mediacodec
- {av1,h264,hevc,vp9}_qsv
- h264_amf
- {h264,hevc,prores}_videotoolbox
- libaom-av1
- libkvazaar
- libopenh264
- librav1e
- libsvtav1
- libvpx, libvpx-vp9
- libx264
- libx265
- ljpeg
- mjpeg
- vc2
Broken (encoder ignores tags):
- {av1,hevc}_amf
- {h264,hevc,mpeg4}_v4l2m2m
- h264_omx
- libxeve
- magicyuv
- {vp8,vp9,mjpeg}_vaapi
N/A:
- ayuv, yuv4, y41p, v308, v210, v410, v408 (headerless)
- pgmyuv (headerless)
- rawvideo, bitpacked (headerless)
- vnull, wrapped_avframe (pseudocodecs)
2023-10-11 16:09:33 +02:00
|
|
|
.color_ranges = AVCOL_RANGE_MPEG,
|
2012-10-08 12:03:08 +02:00
|
|
|
};
|
|
|
|
|
#endif
|