mirror of https://github.com/FFmpeg/FFmpeg.git
Partially fixes ticket #798 Reviewed-by: James Almer <jamrial@gmail.com> Reviewed-by: Michael Niedermayer <michael@niedermayer.cc> Reviewed-by: Paul B Mahol <onemda@gmail.com> Signed-off-by: Peter Ross <pross@xvid.org>release/7.0
parent
f084e9b0be
commit
10869cd849
11 changed files with 350 additions and 2 deletions
@ -0,0 +1,62 @@ |
||||
/*
|
||||
* LEAD MCMP decoder tables |
||||
* |
||||
* 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_LEADDATA_H |
||||
#define AVCODEC_LEADDATA_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
static const uint8_t luma_dc_len[]={ |
||||
2, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9 |
||||
}; |
||||
|
||||
static const uint8_t chroma_dc_len[]={ |
||||
2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 |
||||
}; |
||||
|
||||
static const uint8_t luma_ac_len[]={ |
||||
2, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 8, |
||||
8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, |
||||
12, 12, 12, 12, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16 |
||||
}; |
||||
|
||||
static const uint8_t chroma_ac_len[]={ |
||||
2, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, |
||||
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, |
||||
11, 11, 11, 11, 12, 12, 12, 12, 14, 15, 15, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, |
||||
16, 16 |
||||
}; |
||||
|
||||
#endif /* AVCODEC_LEADDATA_H */ |
@ -0,0 +1,270 @@ |
||||
/*
|
||||
* LEAD MCMP decoder |
||||
* |
||||
* Copyright (c) 2023 Peter Ross |
||||
* |
||||
* 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 "avcodec.h" |
||||
#include "blockdsp.h" |
||||
#include "codec_internal.h" |
||||
#include "copy_block.h" |
||||
#include "decode.h" |
||||
#include "get_bits.h" |
||||
#include "idctdsp.h" |
||||
#include "jpegquanttables.h" |
||||
#include "jpegtables.h" |
||||
#include "leaddata.h" |
||||
#include "libavutil/mem_internal.h" |
||||
#include "libavutil/thread.h" |
||||
|
||||
#define LUMA_DC_BITS 9 |
||||
#define CHROMA_DC_BITS 11 |
||||
#define LUMA_AC_BITS 10 |
||||
#define CHROMA_AC_BITS 10 |
||||
|
||||
static VLC luma_dc_vlc; |
||||
static VLC chroma_dc_vlc; |
||||
static VLC luma_ac_vlc; |
||||
static VLC chroma_ac_vlc; |
||||
|
||||
static av_cold void lead_init_static_data(void) |
||||
{ |
||||
VLC_INIT_STATIC_FROM_LENGTHS(&luma_dc_vlc, LUMA_DC_BITS, FF_ARRAY_ELEMS(luma_dc_len), |
||||
luma_dc_len, 1, |
||||
0, 0, 0, |
||||
0, 0, 1 << LUMA_DC_BITS); |
||||
VLC_INIT_STATIC_FROM_LENGTHS(&chroma_dc_vlc, CHROMA_DC_BITS, FF_ARRAY_ELEMS(chroma_dc_len), |
||||
chroma_dc_len, 1, |
||||
0, 0, 0, |
||||
0, 0, 1 << CHROMA_DC_BITS); |
||||
VLC_INIT_STATIC_FROM_LENGTHS(&luma_ac_vlc, LUMA_AC_BITS, FF_ARRAY_ELEMS(luma_ac_len), |
||||
luma_ac_len, 1, |
||||
ff_mjpeg_val_ac_luminance, 1, 1, |
||||
0, 0, 1160); |
||||
VLC_INIT_STATIC_FROM_LENGTHS(&chroma_ac_vlc, CHROMA_AC_BITS, FF_ARRAY_ELEMS(chroma_ac_len), |
||||
chroma_ac_len, 1, |
||||
ff_mjpeg_val_ac_chrominance, 1, 1, |
||||
0, 0, 1160); |
||||
} |
||||
|
||||
typedef struct LeadContext { |
||||
uint8_t *bitstream_buf; |
||||
unsigned int bitstream_buf_size; |
||||
BlockDSPContext bdsp; |
||||
IDCTDSPContext idsp; |
||||
uint8_t permutated_scantable[64]; |
||||
} LeadContext; |
||||
|
||||
static av_cold int lead_decode_init(AVCodecContext * avctx) |
||||
{ |
||||
static AVOnce init_static_once = AV_ONCE_INIT; |
||||
LeadContext *s = avctx->priv_data; |
||||
|
||||
if (avctx->extradata_size < 20) |
||||
return AVERROR_INVALIDDATA; |
||||
|
||||
ff_blockdsp_init(&s->bdsp); |
||||
ff_idctdsp_init(&s->idsp, avctx); |
||||
ff_permute_scantable(s->permutated_scantable, ff_zigzag_direct, s->idsp.idct_permutation); |
||||
|
||||
ff_thread_once(&init_static_once, lead_init_static_data); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void calc_dequant(uint16_t * dequant, const uint8_t * quant_tbl, int q) |
||||
{ |
||||
for (int i = 0; i < 64; i++) |
||||
dequant[i] = av_clip(q * quant_tbl[ff_zigzag_direct[i]] / 50, 2, 32767); |
||||
} |
||||
|
||||
static int decode_block(LeadContext * s, GetBitContext * gb, |
||||
const VLCElem * dc_table, int dc_bits, const VLCElem * ac_table, int ac_bits, |
||||
int16_t * dc_pred, const uint16_t * dequant, |
||||
uint8_t * dst, int stride) |
||||
{ |
||||
DECLARE_ALIGNED(32, int16_t, block)[64]; |
||||
int size; |
||||
|
||||
s->bdsp.clear_block(block); |
||||
|
||||
size = get_vlc2(gb, dc_table, dc_bits, 1); |
||||
if (size < 0) |
||||
return AVERROR_INVALIDDATA; |
||||
|
||||
if (size) |
||||
*dc_pred += get_xbits(gb, size); |
||||
|
||||
block[0] = (1 << 10) + *dc_pred * dequant[0]; |
||||
|
||||
for (int i = 1; i < 64; i++) { |
||||
int symbol = get_vlc2(gb, ac_table, ac_bits, 2); |
||||
if (symbol < 0) |
||||
return AVERROR_INVALIDDATA; |
||||
|
||||
if (!symbol) |
||||
break; |
||||
|
||||
i += symbol >> 4; |
||||
if (i >= 64) |
||||
return AVERROR_INVALIDDATA; |
||||
|
||||
size = symbol & 0xF; |
||||
if (size) |
||||
block[s->permutated_scantable[i]] = get_xbits(gb, size) * dequant[i]; |
||||
} |
||||
|
||||
s->idsp.idct_put(dst, stride, block); |
||||
return 0; |
||||
} |
||||
|
||||
static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, |
||||
int * got_frame, AVPacket * avpkt) |
||||
{ |
||||
LeadContext *s = avctx->priv_data; |
||||
const uint8_t * buf = avpkt->data; |
||||
int ret, format, yuv20p_half = 0, fields = 1, q, size; |
||||
GetBitContext gb; |
||||
int16_t dc_pred[3] = {0, 0, 0}; |
||||
uint16_t dequant[2][64]; |
||||
|
||||
if (avpkt->size < 8) |
||||
return AVERROR_INVALIDDATA; |
||||
|
||||
format = AV_RL16(buf + 4); |
||||
switch(format) { |
||||
case 0x8000: |
||||
yuv20p_half = 1; |
||||
// fall-through
|
||||
case 0x1000: |
||||
avctx->pix_fmt = AV_PIX_FMT_YUV420P; |
||||
break; |
||||
case 0x2000: |
||||
avctx->pix_fmt = AV_PIX_FMT_YUV444P; |
||||
break; |
||||
case 0x2006: |
||||
avctx->pix_fmt = AV_PIX_FMT_YUV444P; |
||||
fields = 2; |
||||
break; |
||||
default: |
||||
avpriv_request_sample(avctx, "unsupported format 0x%x", format); |
||||
return AVERROR_PATCHWELCOME; |
||||
} |
||||
|
||||
q = AV_RL16(buf + 6); |
||||
calc_dequant(dequant[0], ff_mjpeg_std_luminance_quant_tbl, q); |
||||
calc_dequant(dequant[1], ff_mjpeg_std_chrominance_quant_tbl, q); |
||||
|
||||
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
||||
return ret; |
||||
|
||||
frame->flags |= AV_FRAME_FLAG_KEY; |
||||
frame->pict_type = AV_PICTURE_TYPE_I; |
||||
|
||||
av_fast_padded_malloc(&s->bitstream_buf, &s->bitstream_buf_size, avpkt->size - 8); |
||||
if (!s->bitstream_buf) |
||||
return AVERROR(ENOMEM); |
||||
|
||||
size = 0; |
||||
for (int i = 8; i < avpkt->size; i++) { |
||||
int src = buf[i] ^ 0x80; |
||||
s->bitstream_buf[size++] = src; |
||||
if (src == 0xFF && i + 1 < avpkt->size && (buf[i + 1] ^ 0x80) == 0x00) |
||||
i++; |
||||
} |
||||
|
||||
init_get_bits8(&gb, s->bitstream_buf, size); |
||||
|
||||
if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { |
||||
for (int mb_y = 0; mb_y < avctx->height / 16; mb_y++) |
||||
for (int mb_x = 0; mb_x < avctx->width / 16; mb_x++) |
||||
for (int b = 0; b < (yuv20p_half ? 4 : 6); b++) { |
||||
int luma_block = yuv20p_half ? 2 : 4; |
||||
const VLCElem * dc_vlc = b < luma_block ? luma_dc_vlc.table : chroma_dc_vlc.table; |
||||
int dc_bits = b < luma_block ? LUMA_DC_BITS : CHROMA_DC_BITS; |
||||
const VLCElem * ac_vlc = b < luma_block ? luma_ac_vlc.table : chroma_ac_vlc.table; |
||||
int ac_bits = b < luma_block ? LUMA_AC_BITS : CHROMA_AC_BITS; |
||||
int plane = b < luma_block ? 0 : b - (yuv20p_half ? 1 : 3); |
||||
int x, y; |
||||
|
||||
if (b < luma_block) { |
||||
y = 16*mb_y + 8*(b >> 1); |
||||
x = 16*mb_x + 8*(b & 1); |
||||
} else { |
||||
y = 8*mb_y; |
||||
x = 8*mb_x; |
||||
} |
||||
|
||||
ret = decode_block(s, &gb, dc_vlc, dc_bits, ac_vlc, ac_bits, |
||||
dc_pred + plane, dequant[!(b < 4)], |
||||
frame->data[plane] + y*frame->linesize[plane] + x, |
||||
(yuv20p_half && b < 2 ? 2 : 1) * frame->linesize[plane]); |
||||
if (ret < 0) |
||||
return ret; |
||||
|
||||
if (yuv20p_half && b < 2) |
||||
copy_block8(frame->data[plane] + (y + 1)*frame->linesize[plane] + x, |
||||
frame->data[plane] + y*frame->linesize[plane] + x, |
||||
2*frame->linesize[plane], 2*frame->linesize[plane], 8); |
||||
} |
||||
} else { |
||||
for (int f = 0; f < fields; f++) |
||||
for (int j = 0; j < avctx->height / fields / 8; j++) |
||||
for (int i = 0; i < avctx->width / 8; i++) |
||||
for (int plane = 0; plane < 3; plane++) { |
||||
const VLCElem * dc_vlc = !plane ? luma_dc_vlc.table : chroma_dc_vlc.table; |
||||
int dc_bits = !plane ? LUMA_DC_BITS : CHROMA_DC_BITS; |
||||
const VLCElem * ac_vlc = !plane ? luma_ac_vlc.table : chroma_ac_vlc.table; |
||||
int ac_bits = !plane ? LUMA_AC_BITS : CHROMA_AC_BITS; |
||||
|
||||
ret = decode_block(s, &gb, dc_vlc, dc_bits, ac_vlc, ac_bits, |
||||
dc_pred + plane, dequant[!!plane], |
||||
frame->data[plane] + (f + 8*j*fields)*frame->linesize[plane] + 8*i, |
||||
fields * frame->linesize[plane]); |
||||
if (ret < 0) |
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
*got_frame = 1; |
||||
|
||||
return avpkt->size; |
||||
} |
||||
|
||||
static av_cold int lead_decode_end(AVCodecContext * avctx) |
||||
{ |
||||
LeadContext *s = avctx->priv_data; |
||||
|
||||
av_freep(&s->bitstream_buf); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
const FFCodec ff_lead_decoder = { |
||||
.p.name = "lead", |
||||
CODEC_LONG_NAME("LEAD MCMP"), |
||||
.p.type = AVMEDIA_TYPE_VIDEO, |
||||
.p.id = AV_CODEC_ID_LEAD, |
||||
.priv_data_size = sizeof(LeadContext), |
||||
.init = lead_decode_init, |
||||
.close = lead_decode_end, |
||||
FF_CODEC_DECODE_CB(lead_decode_frame), |
||||
.p.capabilities = AV_CODEC_CAP_DR1, |
||||
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
||||
}; |
Loading…
Reference in new issue