diff options
author | Andreas Rheinhardt <andreas.rheinhardt@gmail.com> | 2021-02-17 23:16:58 +0100 |
---|---|---|
committer | Andreas Rheinhardt <andreas.rheinhardt@gmail.com> | 2021-02-23 10:14:25 +0100 |
commit | bab6b88ebf6aadf3036d6d998e3e0e8b4389b6b1 (patch) | |
tree | 60f2e33736c4aa82c480e236683ee6d6d4332b67 /libavcodec/mjpegenc.c | |
parent | 6eae9c1d3946771c577faeda9e4394a26063dd22 (diff) |
avcodec/mjpegenc_common: Move stuff only used by mjpegenc.c to it
This allows to make ff_init_uni_ac_vlc static;
ff_mjpeg_encode_picture_frame has also been made static, but it could
always have been made static.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
Diffstat (limited to 'libavcodec/mjpegenc.c')
-rw-r--r-- | libavcodec/mjpegenc.c | 191 |
1 files changed, 189 insertions, 2 deletions
diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index 466f48eba9..22af094da7 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -35,11 +35,198 @@ #include "avcodec.h" #include "jpegtables.h" #include "mjpegenc_common.h" +#include "mjpegenc_huffman.h" #include "mpegvideo.h" #include "mjpeg.h" #include "mjpegenc.h" #include "profiles.h" +static av_cold void init_uni_ac_vlc(const uint8_t huff_size_ac[256], + uint8_t *uni_ac_vlc_len) +{ + for (int i = 0; i < 128; i++) { + int level = i - 64; + if (!level) + continue; + for (int run = 0; run < 64; run++) { + int len, code, nbits; + int alevel = FFABS(level); + + len = (run >> 4) * huff_size_ac[0xf0]; + + nbits= av_log2_16bit(alevel) + 1; + code = ((15&run) << 4) | nbits; + + len += huff_size_ac[code] + nbits; + + uni_ac_vlc_len[UNI_AC_ENC_INDEX(run, i)] = len; + // We ignore EOB as its just a constant which does not change generally + } + } +} + +/** + * Encodes and outputs the entire frame in the JPEG format. + * + * @param s The MpegEncContext. + */ +static void mjpeg_encode_picture_frame(MpegEncContext *s) +{ + int nbits, code, table_id; + MJpegContext *m = s->mjpeg_ctx; + uint8_t *huff_size[4] = { m->huff_size_dc_luminance, + m->huff_size_dc_chrominance, + m->huff_size_ac_luminance, + m->huff_size_ac_chrominance }; + uint16_t *huff_code[4] = { m->huff_code_dc_luminance, + m->huff_code_dc_chrominance, + m->huff_code_ac_luminance, + m->huff_code_ac_chrominance }; + size_t total_bits = 0; + size_t bytes_needed; + + s->header_bits = get_bits_diff(s); + // Estimate the total size first + for (int i = 0; i < m->huff_ncode; i++) { + table_id = m->huff_buffer[i].table_id; + code = m->huff_buffer[i].code; + nbits = code & 0xf; + + total_bits += huff_size[table_id][code] + nbits; + } + + bytes_needed = (total_bits + 7) / 8; + ff_mpv_reallocate_putbitbuffer(s, bytes_needed, bytes_needed); + + for (int i = 0; i < m->huff_ncode; i++) { + table_id = m->huff_buffer[i].table_id; + code = m->huff_buffer[i].code; + nbits = code & 0xf; + + put_bits(&s->pb, huff_size[table_id][code], huff_code[table_id][code]); + if (nbits != 0) { + put_sbits(&s->pb, nbits, m->huff_buffer[i].mant); + } + } + + m->huff_ncode = 0; + s->i_tex_bits = get_bits_diff(s); +} + +/** + * Builds all 4 optimal Huffman tables. + * + * Uses the data stored in the JPEG buffer to compute the tables. + * Stores the Huffman tables in the bits_* and val_* arrays in the MJpegContext. + * + * @param m MJpegContext containing the JPEG buffer. + */ +static void mjpeg_build_optimal_huffman(MJpegContext *m) +{ + MJpegEncHuffmanContext dc_luminance_ctx; + MJpegEncHuffmanContext dc_chrominance_ctx; + MJpegEncHuffmanContext ac_luminance_ctx; + MJpegEncHuffmanContext ac_chrominance_ctx; + MJpegEncHuffmanContext *ctx[4] = { &dc_luminance_ctx, + &dc_chrominance_ctx, + &ac_luminance_ctx, + &ac_chrominance_ctx }; + for (int i = 0; i < 4; i++) + ff_mjpeg_encode_huffman_init(ctx[i]); + + for (int i = 0; i < m->huff_ncode; i++) { + int table_id = m->huff_buffer[i].table_id; + int code = m->huff_buffer[i].code; + + ff_mjpeg_encode_huffman_increment(ctx[table_id], code); + } + + ff_mjpeg_encode_huffman_close(&dc_luminance_ctx, + m->bits_dc_luminance, + m->val_dc_luminance, 12); + ff_mjpeg_encode_huffman_close(&dc_chrominance_ctx, + m->bits_dc_chrominance, + m->val_dc_chrominance, 12); + ff_mjpeg_encode_huffman_close(&ac_luminance_ctx, + m->bits_ac_luminance, + m->val_ac_luminance, 256); + ff_mjpeg_encode_huffman_close(&ac_chrominance_ctx, + m->bits_ac_chrominance, + m->val_ac_chrominance, 256); + + ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance, + m->huff_code_dc_luminance, + m->bits_dc_luminance, + m->val_dc_luminance); + ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance, + m->huff_code_dc_chrominance, + m->bits_dc_chrominance, + m->val_dc_chrominance); + ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance, + m->huff_code_ac_luminance, + m->bits_ac_luminance, + m->val_ac_luminance); + ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance, + m->huff_code_ac_chrominance, + m->bits_ac_chrominance, + m->val_ac_chrominance); +} + +/** + * Writes the complete JPEG frame when optimal huffman tables are enabled, + * otherwise writes the stuffing. + * + * Header + values + stuffing. + * + * @param s The MpegEncContext. + * @return int Error code, 0 if successful. + */ +int ff_mjpeg_encode_stuffing(MpegEncContext *s) +{ + PutBitContext *pbc = &s->pb; + int mb_y = s->mb_y - !s->mb_x; + int ret; + MJpegContext *m; + + m = s->mjpeg_ctx; + + if (s->huffman == HUFFMAN_TABLE_OPTIMAL) { + mjpeg_build_optimal_huffman(m); + + // Replace the VLCs with the optimal ones. + // The default ones may be used for trellis during quantization. + init_uni_ac_vlc(m->huff_size_ac_luminance, m->uni_ac_vlc_len); + init_uni_ac_vlc(m->huff_size_ac_chrominance, m->uni_chroma_ac_vlc_len); + s->intra_ac_vlc_length = + s->intra_ac_vlc_last_length = m->uni_ac_vlc_len; + s->intra_chroma_ac_vlc_length = + s->intra_chroma_ac_vlc_last_length = m->uni_chroma_ac_vlc_len; + + ff_mjpeg_encode_picture_header(s->avctx, &s->pb, &s->intra_scantable, + s->pred, s->intra_matrix, s->chroma_intra_matrix); + mjpeg_encode_picture_frame(s); + } + + ret = ff_mpv_reallocate_putbitbuffer(s, put_bits_count(&s->pb) / 8 + 100, + put_bits_count(&s->pb) / 4 + 1000); + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Buffer reallocation failed\n"); + goto fail; + } + + ff_mjpeg_escape_FF(pbc, s->esc_pos); + + if ((s->avctx->active_thread_type & FF_THREAD_SLICE) && mb_y < s->mb_height - 1) + put_marker(pbc, RST0 + (mb_y&7)); + s->esc_pos = put_bits_count(pbc) >> 3; + +fail: + for (int i = 0; i < 3; i++) + s->last_dc[i] = 128 << s->intra_dc_precision; + + return ret; +} + static int alloc_huffman(MpegEncContext *s) { MJpegContext *m = s->mjpeg_ctx; @@ -106,8 +293,8 @@ av_cold int ff_mjpeg_encode_init(MpegEncContext *s) avpriv_mjpeg_bits_ac_chrominance, avpriv_mjpeg_val_ac_chrominance); - ff_init_uni_ac_vlc(m->huff_size_ac_luminance, m->uni_ac_vlc_len); - ff_init_uni_ac_vlc(m->huff_size_ac_chrominance, m->uni_chroma_ac_vlc_len); + init_uni_ac_vlc(m->huff_size_ac_luminance, m->uni_ac_vlc_len); + init_uni_ac_vlc(m->huff_size_ac_chrominance, m->uni_chroma_ac_vlc_len); s->intra_ac_vlc_length = s->intra_ac_vlc_last_length = m->uni_ac_vlc_len; s->intra_chroma_ac_vlc_length = |