mirror of https://github.com/FFmpeg/FFmpeg.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
5.9 KiB
173 lines
5.9 KiB
/* |
|
* RTJpeg decoding functions |
|
* Copyright (c) 2006 Reimar Doeffinger |
|
* |
|
* 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 "libavutil/common.h" |
|
#include "get_bits.h" |
|
#include "dsputil.h" |
|
#include "rtjpeg.h" |
|
|
|
#define PUT_COEFF(c) \ |
|
i = scan[coeff--]; \ |
|
block[i] = (c) * quant[i]; |
|
|
|
//! aligns the bitstream to the give power of two |
|
#define ALIGN(a) \ |
|
n = (-get_bits_count(gb)) & (a - 1); \ |
|
if (n) {skip_bits(gb, n);} |
|
|
|
/** |
|
* @brief read one block from stream |
|
* @param gb contains stream data |
|
* @param block where data is written to |
|
* @param scan array containing the mapping stream address -> block position |
|
* @param quant quantization factors |
|
* @return 0 means the block is not coded, < 0 means an error occurred. |
|
* |
|
* Note: GetBitContext is used to make the code simpler, since all data is |
|
* aligned this could be done faster in a different way, e.g. as it is done |
|
* in MPlayer libmpcodecs/native/rtjpegn.c. |
|
*/ |
|
static inline int get_block(GetBitContext *gb, DCTELEM *block, const uint8_t *scan, |
|
const uint32_t *quant) { |
|
int coeff, i, n; |
|
int8_t ac; |
|
uint8_t dc = get_bits(gb, 8); |
|
|
|
// block not coded |
|
if (dc == 255) |
|
return 0; |
|
|
|
// number of non-zero coefficients |
|
coeff = get_bits(gb, 6); |
|
if (get_bits_count(gb) + (coeff << 1) >= gb->size_in_bits) |
|
return -1; |
|
|
|
// normally we would only need to clear the (63 - coeff) last values, |
|
// but since we do not know where they are we just clear the whole block |
|
memset(block, 0, 64 * sizeof(DCTELEM)); |
|
|
|
// 2 bits per coefficient |
|
while (coeff) { |
|
ac = get_sbits(gb, 2); |
|
if (ac == -2) |
|
break; // continue with more bits |
|
PUT_COEFF(ac); |
|
} |
|
|
|
// 4 bits per coefficient |
|
ALIGN(4); |
|
if (get_bits_count(gb) + (coeff << 2) >= gb->size_in_bits) |
|
return -1; |
|
while (coeff) { |
|
ac = get_sbits(gb, 4); |
|
if (ac == -8) |
|
break; // continue with more bits |
|
PUT_COEFF(ac); |
|
} |
|
|
|
// 8 bits per coefficient |
|
ALIGN(8); |
|
if (get_bits_count(gb) + (coeff << 3) >= gb->size_in_bits) |
|
return -1; |
|
while (coeff) { |
|
ac = get_sbits(gb, 8); |
|
PUT_COEFF(ac); |
|
} |
|
|
|
PUT_COEFF(dc); |
|
return 1; |
|
} |
|
|
|
/** |
|
* @brief decode one rtjpeg YUV420 frame |
|
* @param c context, must be initialized via rtjpeg_decode_init |
|
* @param f AVFrame to place decoded frame into. If parts of the frame |
|
* are not coded they are left unchanged, so consider initializing it |
|
* @param buf buffer containing input data |
|
* @param buf_size length of input data in bytes |
|
* @return number of bytes consumed from the input buffer |
|
*/ |
|
int rtjpeg_decode_frame_yuv420(RTJpegContext *c, AVFrame *f, |
|
const uint8_t *buf, int buf_size) { |
|
GetBitContext gb; |
|
int w = c->w / 16, h = c->h / 16; |
|
int x, y; |
|
uint8_t *y1 = f->data[0], *y2 = f->data[0] + 8 * f->linesize[0]; |
|
uint8_t *u = f->data[1], *v = f->data[2]; |
|
init_get_bits(&gb, buf, buf_size * 8); |
|
for (y = 0; y < h; y++) { |
|
for (x = 0; x < w; x++) { |
|
DCTELEM *block = c->block; |
|
if (get_block(&gb, block, c->scan, c->lquant) > 0) |
|
c->dsp->idct_put(y1, f->linesize[0], block); |
|
y1 += 8; |
|
if (get_block(&gb, block, c->scan, c->lquant) > 0) |
|
c->dsp->idct_put(y1, f->linesize[0], block); |
|
y1 += 8; |
|
if (get_block(&gb, block, c->scan, c->lquant) > 0) |
|
c->dsp->idct_put(y2, f->linesize[0], block); |
|
y2 += 8; |
|
if (get_block(&gb, block, c->scan, c->lquant) > 0) |
|
c->dsp->idct_put(y2, f->linesize[0], block); |
|
y2 += 8; |
|
if (get_block(&gb, block, c->scan, c->cquant) > 0) |
|
c->dsp->idct_put(u, f->linesize[1], block); |
|
u += 8; |
|
if (get_block(&gb, block, c->scan, c->cquant) > 0) |
|
c->dsp->idct_put(v, f->linesize[2], block); |
|
v += 8; |
|
} |
|
y1 += 2 * 8 * (f->linesize[0] - w); |
|
y2 += 2 * 8 * (f->linesize[0] - w); |
|
u += 8 * (f->linesize[1] - w); |
|
v += 8 * (f->linesize[2] - w); |
|
} |
|
return get_bits_count(&gb) / 8; |
|
} |
|
|
|
/** |
|
* @brief initialize an RTJpegContext, may be called multiple times |
|
* @param c context to initialize |
|
* @param dsp specifies the idct to use for decoding |
|
* @param width width of image, will be rounded down to the nearest multiple |
|
* of 16 for decoding |
|
* @param height height of image, will be rounded down to the nearest multiple |
|
* of 16 for decoding |
|
* @param lquant luma quantization table to use |
|
* @param cquant chroma quantization table to use |
|
*/ |
|
void rtjpeg_decode_init(RTJpegContext *c, DSPContext *dsp, |
|
int width, int height, |
|
const uint32_t *lquant, const uint32_t *cquant) { |
|
int i; |
|
c->dsp = dsp; |
|
for (i = 0; i < 64; i++) { |
|
int z = ff_zigzag_direct[i]; |
|
int p = c->dsp->idct_permutation[i]; |
|
z = ((z << 3) | (z >> 3)) & 63; // rtjpeg uses a transposed variant |
|
|
|
// permute the scan and quantization tables for the chosen idct |
|
c->scan[i] = c->dsp->idct_permutation[z]; |
|
c->lquant[p] = lquant[i]; |
|
c->cquant[p] = cquant[i]; |
|
} |
|
c->w = width; |
|
c->h = height; |
|
}
|
|
|