diff options
Diffstat (limited to 'libavcodec/huffyuvdec.c')
-rw-r--r-- | libavcodec/huffyuvdec.c | 118 |
1 files changed, 97 insertions, 21 deletions
diff --git a/libavcodec/huffyuvdec.c b/libavcodec/huffyuvdec.c index 15fce9352c..d08aa5c4f6 100644 --- a/libavcodec/huffyuvdec.c +++ b/libavcodec/huffyuvdec.c @@ -21,6 +21,8 @@ * 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 + * + * yuva, gray, 4:4:4, 4:1:1, 4:1:0 and >8 bit per sample support sponsored by NOA */ /** @@ -88,16 +90,16 @@ static const unsigned char classic_add_chroma[256] = { 6, 12, 8, 10, 7, 9, 6, 4, 6, 2, 2, 3, 3, 3, 3, 2, }; -static int read_len_table(uint8_t *dst, GetBitContext *gb) +static int read_len_table(uint8_t *dst, GetBitContext *gb, int n) { int i, val, repeat; - for (i = 0; i < 256;) { + for (i = 0; i < n;) { repeat = get_bits(gb, 3); val = get_bits(gb, 5); if (repeat == 0) repeat = get_bits(gb, 8); - if (i + repeat > 256 || get_bits_left(gb) < 0) { + if (i + repeat > n || get_bits_left(gb) < 0) { av_log(NULL, AV_LOG_ERROR, "Error reading huffman table\n"); return -1; } @@ -118,19 +120,19 @@ static int generate_joint_tables(HYuvContext *s) int p, i, y, u; for (p = 0; p < 4; p++) { int p0 = s->version > 2 ? p : 0; - for (i = y = 0; y < 256; y++) { + for (i = y = 0; y < s->n; y++) { int len0 = s->len[p0][y]; int limit = VLC_BITS - len0; if(limit <= 0 || !len0) continue; - for (u = 0; u < 256; u++) { + for (u = 0; u < s->n; u++) { int len1 = s->len[p][u]; if (len1 > limit || !len1) continue; av_assert0(i < (1 << VLC_BITS)); len[i] = len0 + len1; bits[i] = (s->bits[p0][y] << len1) + s->bits[p][u]; - symbols[i] = (y << 8) + u; + symbols[i] = (y << 8) + u; //FIXME if(symbols[i] != 0xffff) // reserved to mean "invalid" i++; } @@ -199,13 +201,13 @@ static int read_huffman_tables(HYuvContext *s, const uint8_t *src, int length) count = 1 + s->alpha + 2*s->chroma; for (i = 0; i < count; i++) { - if (read_len_table(s->len[i], &gb) < 0) + if (read_len_table(s->len[i], &gb, s->n) < 0) return -1; - if (ff_huffyuv_generate_bits_table(s->bits[i], s->len[i]) < 0) { + if (ff_huffyuv_generate_bits_table(s->bits[i], s->len[i], s->n) < 0) { return -1; } ff_free_vlc(&s->vlc[i]); - if ((ret = init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1, + if ((ret = init_vlc(&s->vlc[i], VLC_BITS, s->n, s->len[i], 1, 1, s->bits[i], 4, 4, 0)) < 0) return ret; } @@ -224,12 +226,12 @@ static int read_old_huffman_tables(HYuvContext *s) init_get_bits(&gb, classic_shift_luma, classic_shift_luma_table_size * 8); - if (read_len_table(s->len[0], &gb) < 0) + if (read_len_table(s->len[0], &gb, 256) < 0) return -1; init_get_bits(&gb, classic_shift_chroma, classic_shift_chroma_table_size * 8); - if (read_len_table(s->len[1], &gb) < 0) + if (read_len_table(s->len[1], &gb, 256) < 0) return -1; for(i=0; i<256; i++) s->bits[0][i] = classic_add_luma [i]; @@ -397,6 +399,9 @@ static av_cold int decode_init(AVCodecContext *avctx) case 0x675: avctx->pix_fmt = AV_PIX_FMT_YUV420P; break; + case 0x695: + avctx->pix_fmt = AV_PIX_FMT_YUV420P10; + break; case 0x67A: avctx->pix_fmt = AV_PIX_FMT_YUV410P; break; @@ -409,6 +414,11 @@ static av_cold int decode_init(AVCodecContext *avctx) case 0x775: avctx->pix_fmt = AV_PIX_FMT_YUVA420P; break; + case 0x795: + avctx->pix_fmt = AV_PIX_FMT_YUVA420P10; + break; + default: + return AVERROR_INVALIDDATA; } } @@ -499,19 +509,35 @@ static void decode_422_bitstream(HYuvContext *s, int count) dst1 = get_vlc2(&s->gb, s->vlc[plane].table, VLC_BITS, 3);\ }\ } +#define READ_2PIX_PLANE16(dst0, dst1, plane){\ + dst0 = get_vlc2(&s->gb, s->vlc[plane].table, VLC_BITS, 3);\ + dst1 = get_vlc2(&s->gb, s->vlc[plane].table, VLC_BITS, 3);\ +} static void decode_plane_bitstream(HYuvContext *s, int count, int plane) { int i; count/=2; - if (count >= (get_bits_left(&s->gb)) / (31 * 2)) { - for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) { - READ_2PIX_PLANE(s->temp[0][2 * i], s->temp[0][2 * i + 1], plane); + if (s->bps <= 8) { + if (count >= (get_bits_left(&s->gb)) / (31 * 2)) { + for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) { + READ_2PIX_PLANE(s->temp[0][2 * i], s->temp[0][2 * i + 1], plane); + } + } else { + for(i=0; i<count; i++){ + READ_2PIX_PLANE(s->temp[0][2 * i], s->temp[0][2 * i + 1], plane); + } } } else { - for(i=0; i<count; i++){ - READ_2PIX_PLANE(s->temp[0][2 * i], s->temp[0][2 * i + 1], plane); + if (count >= (get_bits_left(&s->gb)) / (31 * 2)) { + for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) { + READ_2PIX_PLANE16(s->temp16[0][2 * i], s->temp16[0][2 * i + 1], plane); + } + } else { + for(i=0; i<count; i++){ + READ_2PIX_PLANE16(s->temp16[0][2 * i], s->temp16[0][2 * i + 1], plane); + } } } } @@ -601,6 +627,56 @@ static void draw_slice(HYuvContext *s, AVFrame *frame, int y) s->last_slice_end = y + h; } +static int left_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *src, int w, int acc) +{ + if (s->bps <= 8) { + return s->dsp.add_hfyu_left_prediction(dst, src, w, acc); + } else { + //FIXME optimize + unsigned mask = s->n-1; + int i; + const uint16_t *src16 = (const uint16_t *)src; + uint16_t *dst16 = ( uint16_t *)dst; + + for(i=0; i<w-1; i++){ + acc+= src16[i]; + dst16[i]= acc & mask; + i++; + acc+= src16[i]; + dst16[i]= acc & mask; + } + + for(; i<w; i++){ + acc+= src16[i]; + dst16[i]= acc & mask; + } + + return acc; + } +} + +static void add_bytes(HYuvContext *s, uint8_t *dst, uint8_t *src, int w) +{ + if (s->bps <= 8) { + s->dsp.add_bytes(dst, src, w); + } else { + //FIXME optimize + const uint16_t *src16 = (const uint16_t *)src; + uint16_t *dst16 = ( uint16_t *)dst; + long i; + unsigned long msb = 0x1000100010001ULL << (s->bps-1); + unsigned long lsb = msb - 0x1000100010001ULL; + unsigned long mask = lsb + msb; + for (i = 0; i <= w - (int)sizeof(long)/2; i += sizeof(long)/2) { + long a = *(long*)(src16+i); + long b = *(long*)(dst16+i); + *(long*)(dst16+i) = ((a&lsb) + (b&lsb)) ^ ((a^b)&msb); + } + for(; i<w; i++) + dst16[i] = (dst16[i] + src16[i]) & mask; + } +} + static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { @@ -663,16 +739,16 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, case LEFT: case PLANE: decode_plane_bitstream(s, w, plane); - left = s->dsp.add_hfyu_left_prediction(p->data[plane], s->temp[0], w, 0); + left = left_prediction(s, p->data[plane], s->temp[0], w, 0); for (y = 1; y < h; y++) { uint8_t *dst = p->data[plane] + p->linesize[plane]*y; decode_plane_bitstream(s, w, plane); - left = s->dsp.add_hfyu_left_prediction(dst, s->temp[0], w, left); + left = left_prediction(s, dst, s->temp[0], w, left); if (s->predictor == PLANE) { if (y > s->interlaced) { - s->dsp.add_bytes(dst, dst - fake_stride, w); + add_bytes(s, dst, dst - fake_stride, w); } } } @@ -680,14 +756,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case MEDIAN: decode_plane_bitstream(s, w, plane); - left= s->dsp.add_hfyu_left_prediction(p->data[plane], s->temp[0], w, 0); + left= left_prediction(s, p->data[plane], s->temp[0], w, 0); y = 1; /* second line is left predicted for interlaced case */ if (s->interlaced) { decode_plane_bitstream(s, w, plane); - left = s->dsp.add_hfyu_left_prediction(p->data[plane] + p->linesize[plane], s->temp[0], w, left); + left = left_prediction(s, p->data[plane] + p->linesize[plane], s->temp[0], w, left); y++; } |