mirror of https://github.com/FFmpeg/FFmpeg.git
* commit '22526c1f557a72b3285d295bd8b30c40eb65d437': Canopus HQ/HQA decoder Conflicts: Changelog libavcodec/version.h Merged-by: Michael Niedermayer <michaelni@gmx.at>pull/133/head
commit
5a284d076f
17 changed files with 9029 additions and 1 deletions
@ -0,0 +1,384 @@ |
|||||||
|
/*
|
||||||
|
* Canopus HQ/HQA decoder |
||||||
|
* |
||||||
|
* This file is part of FFmpeg. |
||||||
|
* |
||||||
|
* FFmpeg is free software; you can redistribute it and/or |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* FFmpeg is distributed in the hope that it will be useful, |
||||||
|
* 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 |
||||||
|
* License along with FFmpeg; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include "libavutil/attributes.h" |
||||||
|
#include "libavutil/intreadwrite.h" |
||||||
|
|
||||||
|
#include "avcodec.h" |
||||||
|
#include "canopus.h" |
||||||
|
#include "internal.h" |
||||||
|
|
||||||
|
#include "hq_hqa.h" |
||||||
|
#include "hq_hqadsp.h" |
||||||
|
|
||||||
|
/* HQ/HQA slices are a set of macroblocks belonging to a frame, and
|
||||||
|
* they usually form a pseudorandom pattern (probably because it is |
||||||
|
* nicer to display on partial decode). |
||||||
|
* |
||||||
|
* For HQA it just happens that each slice is on every 8th macroblock, |
||||||
|
* but they can be on any frame width like |
||||||
|
* X.......X. |
||||||
|
* ......X... |
||||||
|
* ....X..... |
||||||
|
* ..X....... |
||||||
|
* etc. |
||||||
|
* |
||||||
|
* The original decoder has special handling for edge macroblocks, |
||||||
|
* while lavc simply aligns coded_width and coded_height. |
||||||
|
*/ |
||||||
|
|
||||||
|
static inline void put_blocks(HQContext *c, AVFrame *pic, |
||||||
|
int plane, int x, int y, int ilace, |
||||||
|
int16_t *block0, int16_t *block1) |
||||||
|
{ |
||||||
|
uint8_t *p = pic->data[plane] + x; |
||||||
|
|
||||||
|
c->hqhqadsp.idct_put(p + y * pic->linesize[plane], |
||||||
|
pic->linesize[plane] << ilace, block0); |
||||||
|
c->hqhqadsp.idct_put(p + (y + (ilace ? 1 : 8)) * pic->linesize[plane], |
||||||
|
pic->linesize[plane] << ilace, block1); |
||||||
|
} |
||||||
|
|
||||||
|
static int hq_decode_block(HQContext *c, GetBitContext *gb, int16_t block[64], |
||||||
|
int qsel, int is_chroma, int is_hqa) |
||||||
|
{ |
||||||
|
const int32_t *q; |
||||||
|
int val, pos = 1; |
||||||
|
|
||||||
|
memset(block, 0, 64 * sizeof(*block)); |
||||||
|
|
||||||
|
if (!is_hqa) { |
||||||
|
block[0] = get_sbits(gb, 9) << 6; |
||||||
|
q = ff_hq_quants[qsel][is_chroma][get_bits(gb, 2)]; |
||||||
|
} else { |
||||||
|
q = ff_hq_quants[qsel][is_chroma][get_bits(gb, 2)]; |
||||||
|
block[0] = get_sbits(gb, 9) << 6; |
||||||
|
} |
||||||
|
|
||||||
|
for (;;) { |
||||||
|
val = get_vlc2(gb, c->hq_ac_vlc.table, 9, 2); |
||||||
|
pos += ff_hq_ac_skips[val]; |
||||||
|
if (pos >= 64) |
||||||
|
break; |
||||||
|
block[ff_zigzag_direct[pos]] = (ff_hq_ac_syms[val] * q[pos]) >> 12; |
||||||
|
pos++; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int hq_decode_mb(HQContext *c, AVFrame *pic, |
||||||
|
GetBitContext *gb, int x, int y) |
||||||
|
{ |
||||||
|
int qgroup, flag; |
||||||
|
int i, ret; |
||||||
|
|
||||||
|
qgroup = get_bits(gb, 4); |
||||||
|
flag = get_bits1(gb); |
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) { |
||||||
|
ret = hq_decode_block(c, gb, c->block[i], qgroup, i >= 4, 0); |
||||||
|
if (ret < 0) |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
put_blocks(c, pic, 0, x, y, flag, c->block[0], c->block[2]); |
||||||
|
put_blocks(c, pic, 0, x + 8, y, flag, c->block[1], c->block[3]); |
||||||
|
put_blocks(c, pic, 2, x >> 1, y, flag, c->block[4], c->block[5]); |
||||||
|
put_blocks(c, pic, 1, x >> 1, y, flag, c->block[6], c->block[7]); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int hq_decode_frame(HQContext *ctx, AVFrame *pic, |
||||||
|
int prof_num, size_t data_size) |
||||||
|
{ |
||||||
|
const HQProfile *profile; |
||||||
|
GetBitContext gb; |
||||||
|
const uint8_t *perm, *src = ctx->gbc.buffer; |
||||||
|
uint32_t slice_off[21]; |
||||||
|
int slice, start_off, next_off, i, ret; |
||||||
|
|
||||||
|
if (prof_num >= NUM_HQ_PROFILES) { |
||||||
|
profile = &ff_hq_profile[0]; |
||||||
|
avpriv_request_sample(ctx->avctx, "HQ Profile %d", prof_num); |
||||||
|
} else { |
||||||
|
profile = &ff_hq_profile[prof_num]; |
||||||
|
av_log(ctx->avctx, AV_LOG_VERBOSE, "HQ Profile %d\n", prof_num); |
||||||
|
} |
||||||
|
|
||||||
|
ctx->avctx->coded_width = FFALIGN(profile->width, 16); |
||||||
|
ctx->avctx->coded_height = FFALIGN(profile->height, 16); |
||||||
|
ctx->avctx->width = profile->width; |
||||||
|
ctx->avctx->height = profile->height; |
||||||
|
ctx->avctx->bits_per_raw_sample = 8; |
||||||
|
ctx->avctx->pix_fmt = AV_PIX_FMT_YUV422P; |
||||||
|
|
||||||
|
ret = ff_get_buffer(ctx->avctx, pic, 0); |
||||||
|
if (ret < 0) { |
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR, "Could not allocate buffer.\n"); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Offsets are stored from CUV position, so adjust them accordingly. */ |
||||||
|
for (i = 0; i < profile->num_slices + 1; i++) |
||||||
|
slice_off[i] = bytestream2_get_be24(&ctx->gbc) - 4; |
||||||
|
|
||||||
|
next_off = 0; |
||||||
|
for (slice = 0; slice < profile->num_slices; slice++) { |
||||||
|
start_off = next_off; |
||||||
|
next_off = profile->tab_h * (slice + 1) / profile->num_slices; |
||||||
|
perm = profile->perm_tab + start_off * profile->tab_w * 2; |
||||||
|
|
||||||
|
if (slice_off[slice] < (profile->num_slices + 1) * 3 || |
||||||
|
slice_off[slice] >= slice_off[slice + 1] || |
||||||
|
slice_off[slice + 1] > data_size) { |
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR, |
||||||
|
"Invalid slice size %zu.\n", data_size); |
||||||
|
break; |
||||||
|
} |
||||||
|
init_get_bits(&gb, src + slice_off[slice], |
||||||
|
(slice_off[slice + 1] - slice_off[slice]) * 8); |
||||||
|
|
||||||
|
for (i = 0; i < (next_off - start_off) * profile->tab_w; i++) { |
||||||
|
ret = hq_decode_mb(ctx, pic, &gb, perm[0] * 16, perm[1] * 16); |
||||||
|
if (ret < 0) { |
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR, |
||||||
|
"Error decoding macroblock %d at slice %d.\n", i, slice); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
perm += 2; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int hqa_decode_mb(HQContext *c, AVFrame *pic, int qgroup, |
||||||
|
GetBitContext *gb, int x, int y) |
||||||
|
{ |
||||||
|
int flag = 0; |
||||||
|
int i, ret, cbp; |
||||||
|
|
||||||
|
cbp = get_vlc2(gb, c->hqa_cbp_vlc.table, 5, 1); |
||||||
|
|
||||||
|
for (i = 0; i < 12; i++) |
||||||
|
memset(c->block[i], 0, sizeof(*c->block)); |
||||||
|
for (i = 0; i < 12; i++) |
||||||
|
c->block[i][0] = -128 * (1 << 6); |
||||||
|
|
||||||
|
if (cbp) { |
||||||
|
flag = get_bits1(gb); |
||||||
|
|
||||||
|
cbp |= cbp << 4; |
||||||
|
if (cbp & 0x3) |
||||||
|
cbp |= 0x500; |
||||||
|
if (cbp & 0xC) |
||||||
|
cbp |= 0xA00; |
||||||
|
for (i = 0; i < 12; i++) { |
||||||
|
if (!(cbp & (1 << i))) |
||||||
|
continue; |
||||||
|
ret = hq_decode_block(c, gb, c->block[i], qgroup, i >= 8, 1); |
||||||
|
if (ret < 0) |
||||||
|
return ret; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
put_blocks(c, pic, 3, x, y, flag, c->block[ 0], c->block[ 2]); |
||||||
|
put_blocks(c, pic, 3, x + 8, y, flag, c->block[ 1], c->block[ 3]); |
||||||
|
put_blocks(c, pic, 0, x, y, flag, c->block[ 4], c->block[ 6]); |
||||||
|
put_blocks(c, pic, 0, x + 8, y, flag, c->block[ 5], c->block[ 7]); |
||||||
|
put_blocks(c, pic, 2, x >> 1, y, flag, c->block[ 8], c->block[ 9]); |
||||||
|
put_blocks(c, pic, 1, x >> 1, y, flag, c->block[10], c->block[11]); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int hqa_decode_slice(HQContext *ctx, AVFrame *pic, GetBitContext *gb, |
||||||
|
int quant, int slice_no, int w, int h) |
||||||
|
{ |
||||||
|
int i, j, off; |
||||||
|
int ret; |
||||||
|
|
||||||
|
for (i = 0; i < h; i += 16) { |
||||||
|
off = (slice_no * 16 + i * 3) & 0x70; |
||||||
|
for (j = off; j < w; j += 128) { |
||||||
|
ret = hqa_decode_mb(ctx, pic, quant, gb, j, i); |
||||||
|
if (ret < 0) { |
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR, |
||||||
|
"Error decoding macroblock at %dx%d.\n", i, j); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, size_t data_size) |
||||||
|
{ |
||||||
|
GetBitContext gb; |
||||||
|
const int num_slices = 8; |
||||||
|
uint32_t slice_off[9]; |
||||||
|
int i, slice, ret; |
||||||
|
int width, height, quant; |
||||||
|
const uint8_t *src = ctx->gbc.buffer; |
||||||
|
|
||||||
|
width = bytestream2_get_be16(&ctx->gbc); |
||||||
|
height = bytestream2_get_be16(&ctx->gbc); |
||||||
|
|
||||||
|
ctx->avctx->coded_width = FFALIGN(width, 16); |
||||||
|
ctx->avctx->coded_height = FFALIGN(height, 16); |
||||||
|
ctx->avctx->width = width; |
||||||
|
ctx->avctx->height = height; |
||||||
|
ctx->avctx->bits_per_raw_sample = 8; |
||||||
|
ctx->avctx->pix_fmt = AV_PIX_FMT_YUVA422P; |
||||||
|
|
||||||
|
av_log(ctx->avctx, AV_LOG_VERBOSE, "HQA Profile\n"); |
||||||
|
|
||||||
|
quant = bytestream2_get_be32(&ctx->gbc); |
||||||
|
if (quant >= NUM_HQ_QUANTS) { |
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR, |
||||||
|
"Invalid quantization matrix %d.\n", quant); |
||||||
|
return AVERROR_INVALIDDATA; |
||||||
|
} |
||||||
|
|
||||||
|
ret = ff_get_buffer(ctx->avctx, pic, 0); |
||||||
|
if (ret < 0) { |
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR, "Could not allocate buffer.\n"); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Offsets are stored from HQA1 position, so adjust them accordingly. */ |
||||||
|
for (i = 0; i < num_slices + 1; i++) |
||||||
|
slice_off[i] = bytestream2_get_be32(&ctx->gbc) - 4; |
||||||
|
|
||||||
|
for (slice = 0; slice < num_slices; slice++) { |
||||||
|
if (slice_off[slice] < (num_slices + 1) * 3 || |
||||||
|
slice_off[slice] >= slice_off[slice + 1] || |
||||||
|
slice_off[slice + 1] > data_size) { |
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR, |
||||||
|
"Invalid slice size %zu.\n", data_size); |
||||||
|
break; |
||||||
|
} |
||||||
|
init_get_bits(&gb, src + slice_off[slice], |
||||||
|
(slice_off[slice + 1] - slice_off[slice]) * 8); |
||||||
|
|
||||||
|
ret = hqa_decode_slice(ctx, pic, &gb, quant, slice, width, height); |
||||||
|
if (ret < 0) |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int hq_hqa_decode_frame(AVCodecContext *avctx, void *data, |
||||||
|
int *got_frame, AVPacket *avpkt) |
||||||
|
{ |
||||||
|
HQContext *ctx = avctx->priv_data; |
||||||
|
AVFrame *pic = data; |
||||||
|
uint32_t info_tag; |
||||||
|
unsigned int data_size; |
||||||
|
int tag, ret; |
||||||
|
|
||||||
|
bytestream2_init(&ctx->gbc, avpkt->data, avpkt->size); |
||||||
|
if (bytestream2_get_bytes_left(&ctx->gbc) < 4 + 4) { |
||||||
|
av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).\n", avpkt->size); |
||||||
|
return AVERROR_INVALIDDATA; |
||||||
|
} |
||||||
|
|
||||||
|
info_tag = bytestream2_get_le32(&ctx->gbc); |
||||||
|
if (info_tag == MKTAG('I', 'N', 'F', 'O')) { |
||||||
|
int info_size = bytestream2_get_le32(&ctx->gbc); |
||||||
|
if (bytestream2_get_bytes_left(&ctx->gbc) < info_size) { |
||||||
|
av_log(avctx, AV_LOG_ERROR, "Invalid INFO size (%d).\n", info_size); |
||||||
|
return AVERROR_INVALIDDATA; |
||||||
|
} |
||||||
|
ff_canopus_parse_info_tag(avctx, ctx->gbc.buffer, info_size); |
||||||
|
|
||||||
|
bytestream2_skip(&ctx->gbc, info_size); |
||||||
|
} |
||||||
|
|
||||||
|
data_size = bytestream2_get_bytes_left(&ctx->gbc); |
||||||
|
if (data_size < 4) { |
||||||
|
av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).\n", data_size); |
||||||
|
return AVERROR_INVALIDDATA; |
||||||
|
} |
||||||
|
|
||||||
|
/* HQ defines dimensions and number of slices, and thus slice traversal
|
||||||
|
* order. HQA has no size constraint and a fixed number of slices, so it |
||||||
|
* needs a separate scheme for it. */ |
||||||
|
tag = bytestream2_get_le32(&ctx->gbc); |
||||||
|
if ((tag & 0x00FFFFFF) == (MKTAG('U', 'V', 'C', ' ') & 0x00FFFFFF)) { |
||||||
|
ret = hq_decode_frame(ctx, pic, tag >> 24, data_size); |
||||||
|
} else if (tag == MKTAG('H', 'Q', 'A', '1')) { |
||||||
|
ret = hqa_decode_frame(ctx, pic, data_size); |
||||||
|
} else { |
||||||
|
av_log(avctx, AV_LOG_ERROR, "Not a HQ/HQA frame.\n"); |
||||||
|
return AVERROR_INVALIDDATA; |
||||||
|
} |
||||||
|
if (ret < 0) { |
||||||
|
av_log(avctx, AV_LOG_ERROR, "Error decoding frame.\n"); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
pic->key_frame = 1; |
||||||
|
pic->pict_type = AV_PICTURE_TYPE_I; |
||||||
|
|
||||||
|
*got_frame = 1; |
||||||
|
|
||||||
|
return avpkt->size; |
||||||
|
} |
||||||
|
|
||||||
|
static av_cold int hq_hqa_decode_init(AVCodecContext *avctx) |
||||||
|
{ |
||||||
|
HQContext *ctx = avctx->priv_data; |
||||||
|
ctx->avctx = avctx; |
||||||
|
|
||||||
|
ff_hqdsp_init(&ctx->hqhqadsp); |
||||||
|
|
||||||
|
return ff_hq_init_vlcs(ctx); |
||||||
|
} |
||||||
|
|
||||||
|
static av_cold int hq_hqa_decode_close(AVCodecContext *avctx) |
||||||
|
{ |
||||||
|
HQContext *ctx = avctx->priv_data; |
||||||
|
|
||||||
|
ff_free_vlc(&ctx->hq_ac_vlc); |
||||||
|
ff_free_vlc(&ctx->hqa_cbp_vlc); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
AVCodec ff_hq_hqa_decoder = { |
||||||
|
.name = "hq_hqa", |
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("Canopus HQ/HQA"), |
||||||
|
.type = AVMEDIA_TYPE_VIDEO, |
||||||
|
.id = AV_CODEC_ID_HQ_HQA, |
||||||
|
.priv_data_size = sizeof(HQContext), |
||||||
|
.init = hq_hqa_decode_init, |
||||||
|
.decode = hq_hqa_decode_frame, |
||||||
|
.close = hq_hqa_decode_close, |
||||||
|
.capabilities = CODEC_CAP_DR1, |
||||||
|
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | |
||||||
|
FF_CODEC_CAP_INIT_CLEANUP, |
||||||
|
}; |
@ -0,0 +1,60 @@ |
|||||||
|
/*
|
||||||
|
* Canopus HQ/HQA decoder |
||||||
|
* |
||||||
|
* This file is part of FFmpeg. |
||||||
|
* |
||||||
|
* FFmpeg is free software; you can redistribute it and/or |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* FFmpeg is distributed in the hope that it will be useful, |
||||||
|
* 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 |
||||||
|
* License along with FFmpeg; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef AVCODEC_HQ_HQA_H |
||||||
|
#define AVCODEC_HQ_HQA_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include "avcodec.h" |
||||||
|
#include "get_bits.h" |
||||||
|
#include "bytestream.h" |
||||||
|
#include "hq_hqadsp.h" |
||||||
|
|
||||||
|
#define NUM_HQ_AC_ENTRIES 746 |
||||||
|
#define NUM_HQ_PROFILES 22 |
||||||
|
#define NUM_HQ_QUANTS 16 |
||||||
|
|
||||||
|
typedef struct HQContext { |
||||||
|
AVCodecContext *avctx; |
||||||
|
HQDSPContext hqhqadsp; |
||||||
|
GetByteContext gbc; |
||||||
|
|
||||||
|
VLC hq_ac_vlc; |
||||||
|
VLC hqa_cbp_vlc; |
||||||
|
DECLARE_ALIGNED(16, int16_t, block)[12][64]; |
||||||
|
} HQContext; |
||||||
|
|
||||||
|
typedef struct HQProfile { |
||||||
|
const uint8_t *perm_tab; |
||||||
|
int width, height; |
||||||
|
int num_slices; |
||||||
|
int tab_w, tab_h; |
||||||
|
} HQProfile; |
||||||
|
|
||||||
|
extern const int32_t * const ff_hq_quants[16][2][4]; |
||||||
|
extern const HQProfile ff_hq_profile[NUM_HQ_PROFILES]; |
||||||
|
|
||||||
|
extern const uint8_t ff_hq_ac_skips[NUM_HQ_AC_ENTRIES]; |
||||||
|
extern const int16_t ff_hq_ac_syms [NUM_HQ_AC_ENTRIES]; |
||||||
|
|
||||||
|
int ff_hq_init_vlcs(HQContext *c); |
||||||
|
|
||||||
|
#endif /* AVCODEC_HQ_HQA_H */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,130 @@ |
|||||||
|
/*
|
||||||
|
* Canopus HQ/HQA decoder |
||||||
|
* |
||||||
|
* This file is part of FFmpeg. |
||||||
|
* |
||||||
|
* FFmpeg is free software; you can redistribute it and/or |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* FFmpeg is distributed in the hope that it will be useful, |
||||||
|
* 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 |
||||||
|
* License along with FFmpeg; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include "libavutil/attributes.h" |
||||||
|
#include "libavutil/common.h" |
||||||
|
|
||||||
|
#include "hq_hqadsp.h" |
||||||
|
|
||||||
|
#define FIX_1_082 17734 |
||||||
|
#define FIX_1_847 30274 |
||||||
|
#define FIX_1_414 23170 |
||||||
|
#define FIX_2_613 21407 // divided by two to fit the range
|
||||||
|
|
||||||
|
#define IDCTMUL(a, b) ((a) * (b) >> 16) |
||||||
|
|
||||||
|
static inline void idct_row(int16_t *blk) |
||||||
|
{ |
||||||
|
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmpA; |
||||||
|
int tmpB, tmpC, tmpD, tmpE, tmpF, tmp10, tmp11, tmp12, tmp13, tmp14; |
||||||
|
|
||||||
|
tmp0 = blk[5] - blk[3]; |
||||||
|
tmp1 = blk[5] + blk[3]; |
||||||
|
tmp2 = blk[1] - blk[7]; |
||||||
|
tmp3 = blk[1] + blk[7]; |
||||||
|
tmp4 = tmp3 - tmp1; |
||||||
|
tmp5 = IDCTMUL(tmp0 + tmp2, FIX_1_847); |
||||||
|
tmp6 = IDCTMUL(tmp2, FIX_1_082) - tmp5; |
||||||
|
tmp7 = tmp5 - IDCTMUL(tmp0, FIX_2_613) * 2; |
||||||
|
tmp8 = tmp3 + tmp1; |
||||||
|
tmp9 = tmp7 * 4 - tmp8; |
||||||
|
tmpA = IDCTMUL(tmp4, FIX_1_414) * 4 - tmp9; |
||||||
|
tmpB = tmp6 * 4 + tmpA; |
||||||
|
tmpC = blk[2] + blk[6]; |
||||||
|
tmpD = blk[2] - blk[6]; |
||||||
|
tmpE = blk[0] - blk[4]; |
||||||
|
tmpF = blk[0] + blk[4]; |
||||||
|
|
||||||
|
tmp10 = IDCTMUL(tmpD, FIX_1_414) * 4 - tmpC; |
||||||
|
tmp11 = tmpE - tmp10; |
||||||
|
tmp12 = tmpF - tmpC; |
||||||
|
tmp13 = tmpE + tmp10; |
||||||
|
tmp14 = tmpF + tmpC; |
||||||
|
|
||||||
|
blk[0] = tmp14 + tmp8; |
||||||
|
blk[1] = tmp13 + tmp9; |
||||||
|
blk[2] = tmp11 + tmpA; |
||||||
|
blk[3] = tmp12 - tmpB; |
||||||
|
blk[4] = tmp12 + tmpB; |
||||||
|
blk[5] = tmp11 - tmpA; |
||||||
|
blk[6] = tmp13 - tmp9; |
||||||
|
blk[7] = tmp14 - tmp8; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void idct_col(int16_t *blk) |
||||||
|
{ |
||||||
|
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmpA; |
||||||
|
int tmpB, tmpC, tmpD, tmpE, tmpF, tmp10, tmp11, tmp12, tmp13, tmp14; |
||||||
|
|
||||||
|
tmp0 = blk[5 * 8] - blk[3 * 8]; |
||||||
|
tmp1 = blk[5 * 8] + blk[3 * 8]; |
||||||
|
tmp2 = blk[1 * 8] * 2 - (blk[7 * 8] >> 2); |
||||||
|
tmp3 = blk[1 * 8] * 2 + (blk[7 * 8] >> 2); |
||||||
|
tmp4 = tmp3 - tmp1; |
||||||
|
tmp5 = IDCTMUL(tmp0 + tmp2, FIX_1_847); |
||||||
|
tmp6 = IDCTMUL(tmp2, FIX_1_082) - tmp5; |
||||||
|
tmp7 = tmp5 - IDCTMUL(tmp0, FIX_2_613) * 2; |
||||||
|
tmp8 = (tmp3 + tmp1) >> 1; |
||||||
|
tmp9 = tmp7 * 2 - tmp8; |
||||||
|
tmpA = IDCTMUL(tmp4, FIX_1_414) * 2 - tmp9; |
||||||
|
tmpB = tmp6 * 2 + tmpA; |
||||||
|
tmpC = blk[2 * 8] + (blk[6 * 8] >> 1) >> 1; |
||||||
|
tmpD = blk[2 * 8] - (blk[6 * 8] >> 1); |
||||||
|
tmpE = (blk[0 * 8] >> 1) - (blk[4 * 8] >> 1) + 0x2020; |
||||||
|
tmpF = (blk[0 * 8] >> 1) + (blk[4 * 8] >> 1) + 0x2020; |
||||||
|
|
||||||
|
tmp10 = IDCTMUL(tmpD, FIX_1_414) * 2 - tmpC; |
||||||
|
tmp11 = tmpE - tmp10; |
||||||
|
tmp12 = tmpF - tmpC; |
||||||
|
tmp13 = tmpE + tmp10; |
||||||
|
tmp14 = tmpF + tmpC; |
||||||
|
|
||||||
|
blk[0 * 8] = (tmp14 + tmp8) >> 6; |
||||||
|
blk[1 * 8] = (tmp13 + tmp9) >> 6; |
||||||
|
blk[2 * 8] = (tmp11 + tmpA) >> 6; |
||||||
|
blk[3 * 8] = (tmp12 - tmpB) >> 6; |
||||||
|
blk[4 * 8] = (tmp12 + tmpB) >> 6; |
||||||
|
blk[5 * 8] = (tmp11 - tmpA) >> 6; |
||||||
|
blk[6 * 8] = (tmp13 - tmp9) >> 6; |
||||||
|
blk[7 * 8] = (tmp14 - tmp8) >> 6; |
||||||
|
} |
||||||
|
|
||||||
|
static void hq_idct_put(uint8_t *dst, int stride, int16_t *block) |
||||||
|
{ |
||||||
|
int i, j; |
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) |
||||||
|
idct_row(block + i * 8); |
||||||
|
for (i = 0; i < 8; i++) |
||||||
|
idct_col(block + i); |
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) { |
||||||
|
for (j = 0; j < 8; j++) |
||||||
|
dst[j] = av_clip_uint8(block[j + i * 8]); |
||||||
|
dst += stride; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
av_cold void ff_hqdsp_init(HQDSPContext *c) |
||||||
|
{ |
||||||
|
c->idct_put = hq_idct_put; |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
/*
|
||||||
|
* Canopus HQ/HQA decoder |
||||||
|
* |
||||||
|
* This file is part of FFmpeg. |
||||||
|
* |
||||||
|
* FFmpeg is free software; you can redistribute it and/or |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* FFmpeg is distributed in the hope that it will be useful, |
||||||
|
* 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 |
||||||
|
* License along with FFmpeg; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||||
|
*/ |
||||||
|
|
||||||
|
/**
|
||||||
|
* @file |
||||||
|
* HQ/HQA variant of AAN IDCT |
||||||
|
* It differs from the standard AAN IDCT in precision and in the second stage. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef AVCODEC_HQ_HQADSP_H |
||||||
|
#define AVCODEC_HQ_HQADSP_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
typedef struct HQDSPContext { |
||||||
|
void (*idct_put)(uint8_t *dst, int stride, int16_t *block); |
||||||
|
} HQDSPContext; |
||||||
|
|
||||||
|
void ff_hqdsp_init(HQDSPContext *c); |
||||||
|
|
||||||
|
#endif /* AVCODEC_HQ_HQADSP_H */ |
@ -0,0 +1,9 @@ |
|||||||
|
#tb 0: 1/25 |
||||||
|
0, 0, 0, 1, 829440, 0x8b6b2f6d |
||||||
|
0, 1, 1, 1, 829440, 0x70382bf0 |
||||||
|
0, 2, 2, 1, 829440, 0xbfdf1f8d |
||||||
|
0, 3, 3, 1, 829440, 0x27587282 |
||||||
|
0, 4, 4, 1, 829440, 0x54655f5d |
||||||
|
0, 5, 5, 1, 829440, 0xe31bff92 |
||||||
|
0, 6, 6, 1, 829440, 0x10ec4a8b |
||||||
|
0, 7, 7, 1, 829440, 0x0a5773e7 |
@ -0,0 +1,2 @@ |
|||||||
|
#tb 0: 1/25 |
||||||
|
0, 0, 0, 1, 6220800, 0x2b2b17cc |
@ -0,0 +1,2 @@ |
|||||||
|
#tb 0: 1/25 |
||||||
|
0, 0, 0, 1, 4147200, 0x418ecfe5 |
Loading…
Reference in new issue