mirror of https://github.com/FFmpeg/FFmpeg.git
parent
4688017d9a
commit
052a5993ad
11 changed files with 428 additions and 10 deletions
@ -0,0 +1,316 @@ |
||||
/*
|
||||
* SpeedHQ encoder |
||||
* Copyright (c) 2000, 2001 Fabrice Bellard |
||||
* Copyright (c) 2003 Alex Beregszaszi |
||||
* Copyright (c) 2003-2004 Michael Niedermayer |
||||
* Copyright (c) 2020 FFmpeg |
||||
* |
||||
* 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 |
||||
* SpeedHQ encoder. |
||||
*/ |
||||
|
||||
#include "libavutil/pixdesc.h" |
||||
#include "libavutil/thread.h" |
||||
|
||||
#include "avcodec.h" |
||||
#include "mpeg12.h" |
||||
#include "mpegvideo.h" |
||||
#include "speedhqenc.h" |
||||
|
||||
extern RLTable ff_rl_speedhq; |
||||
static uint8_t speedhq_static_rl_table_store[2][2*MAX_RUN + MAX_LEVEL + 3]; |
||||
|
||||
static uint16_t mpeg12_vlc_dc_lum_code_reversed[12]; |
||||
static uint16_t mpeg12_vlc_dc_chroma_code_reversed[12]; |
||||
|
||||
/* simple include everything table for dc, first byte is bits
|
||||
* number next 3 are code */ |
||||
static uint32_t speedhq_lum_dc_uni[512]; |
||||
static uint32_t speedhq_chr_dc_uni[512]; |
||||
|
||||
static uint8_t speedhq_index_run[2][64]; |
||||
static int8_t speedhq_max_level[2][64]; |
||||
|
||||
static uint8_t uni_speedhq_ac_vlc_len[64 * 64 * 2]; |
||||
|
||||
static uint32_t reverse(uint32_t num, int bits) |
||||
{ |
||||
return bitswap_32(num) >> (32 - bits); |
||||
} |
||||
|
||||
static void reverse_code(const uint16_t *code, const uint8_t *bits, |
||||
uint16_t *reversed_code, int num_entries) |
||||
{ |
||||
for (int i = 0; i < num_entries; i++) |
||||
reversed_code[i] = reverse(code[i], bits[i]); |
||||
} |
||||
|
||||
static av_cold void speedhq_init_static_data(void) |
||||
{ |
||||
/* Exactly the same as MPEG-2, except little-endian. */ |
||||
reverse_code(ff_mpeg12_vlc_dc_lum_code, |
||||
ff_mpeg12_vlc_dc_lum_bits, |
||||
mpeg12_vlc_dc_lum_code_reversed, |
||||
12); |
||||
reverse_code(ff_mpeg12_vlc_dc_chroma_code, |
||||
ff_mpeg12_vlc_dc_chroma_bits, |
||||
mpeg12_vlc_dc_chroma_code_reversed, |
||||
12); |
||||
|
||||
ff_rl_init(&ff_rl_speedhq, speedhq_static_rl_table_store); |
||||
|
||||
for (int i = 0; i < 64; i++) { |
||||
speedhq_max_level[0][i] = ff_rl_speedhq.max_level[0][i]; |
||||
speedhq_index_run[0][i] = ff_rl_speedhq.index_run[0][i]; |
||||
} |
||||
|
||||
/* build unified dc encoding tables */ |
||||
for (int i = -255; i < 256; i++) { |
||||
int adiff, index; |
||||
int bits, code; |
||||
int diff = i; |
||||
|
||||
adiff = FFABS(diff); |
||||
if (diff < 0) |
||||
diff--; |
||||
index = av_log2(2 * adiff); |
||||
|
||||
bits = ff_mpeg12_vlc_dc_lum_bits[index] + index; |
||||
code = mpeg12_vlc_dc_lum_code_reversed[index] + |
||||
(av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index]); |
||||
speedhq_lum_dc_uni[i + 255] = bits + (code << 8); |
||||
|
||||
bits = ff_mpeg12_vlc_dc_chroma_bits[index] + index; |
||||
code = mpeg12_vlc_dc_chroma_code_reversed[index] + |
||||
(av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index]); |
||||
speedhq_chr_dc_uni[i + 255] = bits + (code << 8); |
||||
} |
||||
|
||||
ff_init_uni_ac_vlc(&ff_rl_speedhq, uni_speedhq_ac_vlc_len); |
||||
} |
||||
|
||||
av_cold int ff_speedhq_encode_init(MpegEncContext *s) |
||||
{ |
||||
static AVOnce init_static_once = AV_ONCE_INIT; |
||||
|
||||
av_assert0(s->slice_context_count == 1); |
||||
|
||||
if (s->width > 65500 || s->height > 65500) { |
||||
av_log(s, AV_LOG_ERROR, "SpeedHQ does not support resolutions above 65500x65500\n"); |
||||
return AVERROR(EINVAL); |
||||
} |
||||
|
||||
s->min_qcoeff = -2048; |
||||
s->max_qcoeff = 2047; |
||||
|
||||
ff_thread_once(&init_static_once, speedhq_init_static_data); |
||||
|
||||
s->intra_ac_vlc_length = |
||||
s->intra_ac_vlc_last_length = |
||||
s->intra_chroma_ac_vlc_length = |
||||
s->intra_chroma_ac_vlc_last_length = uni_speedhq_ac_vlc_len; |
||||
|
||||
switch (s->avctx->pix_fmt) { |
||||
case AV_PIX_FMT_YUV420P: |
||||
s->avctx->codec_tag = MKTAG('S','H','Q','0'); |
||||
break; |
||||
case AV_PIX_FMT_YUV422P: |
||||
s->avctx->codec_tag = MKTAG('S','H','Q','2'); |
||||
break; |
||||
case AV_PIX_FMT_YUV444P: |
||||
s->avctx->codec_tag = MKTAG('S','H','Q','4'); |
||||
break; |
||||
default: |
||||
av_assert0(0); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void ff_speedhq_encode_picture_header(MpegEncContext *s) |
||||
{ |
||||
put_bits_le(&s->pb, 8, 100 - s->qscale * 2); /* FIXME why doubled */ |
||||
put_bits_le(&s->pb, 24, 4); /* no second field */ |
||||
|
||||
/* length of first slice, will be filled out later */ |
||||
s->slice_start = 4; |
||||
put_bits_le(&s->pb, 24, 0); |
||||
} |
||||
|
||||
void ff_speedhq_end_slice(MpegEncContext *s) |
||||
{ |
||||
int slice_len; |
||||
|
||||
flush_put_bits_le(&s->pb); |
||||
slice_len = s->pb.buf_ptr - (s->pb.buf + s->slice_start); |
||||
AV_WL24(s->pb.buf + s->slice_start, slice_len); |
||||
|
||||
/* length of next slice, will be filled out later */ |
||||
s->slice_start = s->pb.buf_ptr - s->pb.buf; |
||||
put_bits_le(&s->pb, 24, 0); |
||||
} |
||||
|
||||
static inline void encode_dc(PutBitContext *pb, int diff, int component) |
||||
{ |
||||
unsigned int diff_u = diff + 255; |
||||
if (diff_u >= 511) { |
||||
int index; |
||||
|
||||
if (diff < 0) { |
||||
index = av_log2_16bit(-2 * diff); |
||||
diff--; |
||||
} else { |
||||
index = av_log2_16bit(2 * diff); |
||||
} |
||||
if (component == 0) |
||||
put_bits_le(pb, |
||||
ff_mpeg12_vlc_dc_lum_bits[index] + index, |
||||
mpeg12_vlc_dc_lum_code_reversed[index] + |
||||
(av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index])); |
||||
else |
||||
put_bits_le(pb, |
||||
ff_mpeg12_vlc_dc_chroma_bits[index] + index, |
||||
mpeg12_vlc_dc_chroma_code_reversed[index] + |
||||
(av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index])); |
||||
} else { |
||||
if (component == 0) |
||||
put_bits_le(pb, |
||||
speedhq_lum_dc_uni[diff + 255] & 0xFF, |
||||
speedhq_lum_dc_uni[diff + 255] >> 8); |
||||
else |
||||
put_bits_le(pb, |
||||
speedhq_chr_dc_uni[diff + 255] & 0xFF, |
||||
speedhq_chr_dc_uni[diff + 255] >> 8); |
||||
} |
||||
} |
||||
|
||||
static void encode_block(MpegEncContext *s, int16_t *block, int n) |
||||
{ |
||||
int alevel, level, last_non_zero, dc, i, j, run, last_index, sign; |
||||
int code; |
||||
int component, val; |
||||
|
||||
/* DC coef */ |
||||
component = (n <= 3 ? 0 : (n&1) + 1); |
||||
dc = block[0]; /* overflow is impossible */ |
||||
val = s->last_dc[component] - dc; /* opposite of most codecs */ |
||||
encode_dc(&s->pb, val, component); |
||||
s->last_dc[component] = dc; |
||||
|
||||
/* now quantify & encode AC coefs */ |
||||
last_non_zero = 0; |
||||
last_index = s->block_last_index[n]; |
||||
|
||||
for (i = 1; i <= last_index; i++) { |
||||
j = s->intra_scantable.permutated[i]; |
||||
level = block[j]; |
||||
|
||||
/* encode using VLC */ |
||||
if (level != 0) { |
||||
run = i - last_non_zero - 1; |
||||
|
||||
alevel = level; |
||||
MASK_ABS(sign, alevel); |
||||
sign &= 1; |
||||
|
||||
if (alevel <= speedhq_max_level[0][run]) { |
||||
code = speedhq_index_run[0][run] + alevel - 1; |
||||
/* store the VLC & sign at once */ |
||||
put_bits_le(&s->pb, ff_rl_speedhq.table_vlc[code][1] + 1, |
||||
ff_rl_speedhq.table_vlc[code][0] + (sign << ff_rl_speedhq.table_vlc[code][1])); |
||||
} else { |
||||
/* escape seems to be pretty rare <5% so I do not optimize it */ |
||||
put_bits_le(&s->pb, ff_rl_speedhq.table_vlc[121][1], ff_rl_speedhq.table_vlc[121][0]); |
||||
/* escape: only clip in this case */ |
||||
put_bits_le(&s->pb, 6, run); |
||||
put_bits_le(&s->pb, 12, level + 2048); |
||||
} |
||||
last_non_zero = i; |
||||
} |
||||
} |
||||
/* end of block */ |
||||
put_bits_le(&s->pb, ff_rl_speedhq.table_vlc[122][1], ff_rl_speedhq.table_vlc[122][0]); |
||||
} |
||||
|
||||
void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]) |
||||
{ |
||||
int i; |
||||
for(i=0;i<6;i++) { |
||||
encode_block(s, block[i], i); |
||||
} |
||||
if (s->chroma_format == CHROMA_444) { |
||||
encode_block(s, block[8], 8); |
||||
encode_block(s, block[9], 9); |
||||
|
||||
encode_block(s, block[6], 6); |
||||
encode_block(s, block[7], 7); |
||||
|
||||
encode_block(s, block[10], 10); |
||||
encode_block(s, block[11], 11); |
||||
} else if (s->chroma_format == CHROMA_422) { |
||||
encode_block(s, block[6], 6); |
||||
encode_block(s, block[7], 7); |
||||
} |
||||
|
||||
s->i_tex_bits += get_bits_diff(s); |
||||
} |
||||
|
||||
static int ff_speedhq_mb_rows_in_slice(int slice_num, int mb_height) |
||||
{ |
||||
return mb_height / 4 + (slice_num < (mb_height % 4)); |
||||
} |
||||
|
||||
int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice) |
||||
{ |
||||
int slice_num = 0; |
||||
while (mb_y_order >= ff_speedhq_mb_rows_in_slice(slice_num, mb_height)) { |
||||
mb_y_order -= ff_speedhq_mb_rows_in_slice(slice_num, mb_height); |
||||
slice_num++; |
||||
} |
||||
*first_in_slice = (mb_y_order == 0); |
||||
return mb_y_order * 4 + slice_num; |
||||
} |
||||
|
||||
#if CONFIG_SPEEDHQ_ENCODER |
||||
static const AVClass speedhq_class = { |
||||
.class_name = "speedhq encoder", |
||||
.item_name = av_default_item_name, |
||||
.option = ff_mpv_generic_options, |
||||
.version = LIBAVUTIL_VERSION_INT, |
||||
}; |
||||
|
||||
AVCodec ff_speedhq_encoder = { |
||||
.name = "speedhq", |
||||
.long_name = NULL_IF_CONFIG_SMALL("NewTek SpeedHQ"), |
||||
.type = AVMEDIA_TYPE_VIDEO, |
||||
.id = AV_CODEC_ID_SPEEDHQ, |
||||
.priv_data_size = sizeof(MpegEncContext), |
||||
.init = ff_mpv_encode_init, |
||||
.encode2 = ff_mpv_encode_picture, |
||||
.close = ff_mpv_encode_end, |
||||
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
||||
.pix_fmts = (const enum AVPixelFormat[]) { |
||||
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, |
||||
AV_PIX_FMT_NONE |
||||
}, |
||||
.priv_class = &speedhq_class, |
||||
}; |
||||
#endif |
@ -0,0 +1,48 @@ |
||||
/*
|
||||
* SpeedHQ encoder |
||||
* Copyright (c) 2000, 2001 Fabrice Bellard |
||||
* Copyright (c) 2003 Alex Beregszaszi |
||||
* Copyright (c) 2003-2004 Michael Niedermayer |
||||
* |
||||
* 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 |
||||
* SpeedHQ encoder. |
||||
*/ |
||||
|
||||
#ifndef AVCODEC_SPEEDHQENC_H |
||||
#define AVCODEC_SPEEDHQENC_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "mjpeg.h" |
||||
#include "mjpegenc_common.h" |
||||
#include "mpegvideo.h" |
||||
#include "put_bits.h" |
||||
|
||||
int ff_speedhq_encode_init(MpegEncContext *s); |
||||
void ff_speedhq_encode_close(MpegEncContext *s); |
||||
void ff_speedhq_encode_mb(MpegEncContext *s, int16_t block[12][64]); |
||||
|
||||
void ff_speedhq_encode_picture_header(MpegEncContext *s); |
||||
void ff_speedhq_end_slice(MpegEncContext *s); |
||||
|
||||
int ff_speedhq_mb_y_order_to_mb(int mb_y_order, int mb_height, int *first_in_slice); |
||||
|
||||
#endif /* AVCODEC_SPEEDHQENC_H */ |
Loading…
Reference in new issue