* see http://www.pcisys.net/~melanson/codecs/huffyuv.txt for a description of
* the algorithm used
*
- * This file is part of FFmpeg.
+ * This file is part of Libav.
*
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav 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,
+ * Libav 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
+ * License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
- * @file libavcodec/huffyuv.c
+ * @file
* huffyuv codec for libavcodec.
*/
#include "get_bits.h"
#include "put_bits.h"
#include "dsputil.h"
+#include "thread.h"
#define VLC_BITS 11
#define B 3
#define G 2
#define R 1
+#define A 0
#else
#define B 0
#define G 1
#define R 2
+#define A 3
#endif
typedef enum Predictor{
DSPContext dsp;
}HYuvContext;
-static const unsigned char classic_shift_luma[] = {
+#define classic_shift_luma_table_size 42
+static const unsigned char classic_shift_luma[classic_shift_luma_table_size + FF_INPUT_BUFFER_PADDING_SIZE] = {
34,36,35,69,135,232,9,16,10,24,11,23,12,16,13,10,14,8,15,8,
16,8,17,20,16,10,207,206,205,236,11,8,10,21,9,23,8,8,199,70,
69,68, 0
};
-static const unsigned char classic_shift_chroma[] = {
+#define classic_shift_chroma_table_size 59
+static const unsigned char classic_shift_chroma[classic_shift_chroma_table_size + FF_INPUT_BUFFER_PADDING_SIZE] = {
66,36,37,38,39,40,41,75,76,77,110,239,144,81,82,83,84,85,118,183,
56,57,88,89,56,89,154,57,58,57,26,141,57,56,58,57,58,57,184,119,
214,245,116,83,82,49,80,79,78,77,44,75,41,40,39,38,37,36,34, 0
if(repeat==0)
repeat= get_bits(gb, 8);
//printf("%d %d\n", val, repeat);
- if(i+repeat > 256) {
+ if(i+repeat > 256 || get_bits_left(gb) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error reading huffman table\n");
return -1;
}
return 0;
}
-static int generate_bits_table(uint32_t *dst, uint8_t *len_table){
+static int generate_bits_table(uint32_t *dst, const uint8_t *len_table){
int len, index;
uint32_t bits=0;
}
}
-static void generate_len_table(uint8_t *dst, uint64_t *stats, int size){
- HeapElem h[size];
- int up[2*size];
- int len[2*size];
+static void generate_len_table(uint8_t *dst, const uint64_t *stats){
+ HeapElem h[256];
+ int up[2*256];
+ int len[2*256];
int offset, i, next;
+ int size = 256;
for(offset=1; ; offset<<=1){
for(i=0; i<size; i++){
i++;
}
}
- free_vlc(&s->vlc[3+p]);
- init_vlc_sparse(&s->vlc[3+p], VLC_BITS, i, len, 1, 1, bits, 2, 2, symbols, 2, 2, 0);
+ ff_free_vlc(&s->vlc[3+p]);
+ ff_init_vlc_sparse(&s->vlc[3+p], VLC_BITS, i, len, 1, 1, bits, 2, 2, symbols, 2, 2, 0);
}
}else{
uint8_t (*map)[4] = (uint8_t(*)[4])s->pix_bgr_map;
}
}
}
- free_vlc(&s->vlc[3]);
+ ff_free_vlc(&s->vlc[3]);
init_vlc(&s->vlc[3], VLC_BITS, i, len, 1, 1, bits, 2, 2, 0);
}
}
-static int read_huffman_tables(HYuvContext *s, uint8_t *src, int length){
+static int read_huffman_tables(HYuvContext *s, const uint8_t *src, int length){
GetBitContext gb;
int i;
if(generate_bits_table(s->bits[i], s->len[i])<0){
return -1;
}
-#if 0
-for(j=0; j<256; j++){
-printf("%6X, %2d, %3d\n", s->bits[i][j], s->len[i][j], j);
-}
-#endif
- free_vlc(&s->vlc[i]);
+ ff_free_vlc(&s->vlc[i]);
init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1, s->bits[i], 4, 4, 0);
}
GetBitContext gb;
int i;
- init_get_bits(&gb, classic_shift_luma, sizeof(classic_shift_luma)*8);
+ init_get_bits(&gb, classic_shift_luma, classic_shift_luma_table_size*8);
if(read_len_table(s->len[0], &gb)<0)
return -1;
- init_get_bits(&gb, classic_shift_chroma, sizeof(classic_shift_chroma)*8);
+ init_get_bits(&gb, classic_shift_chroma, classic_shift_chroma_table_size*8);
if(read_len_table(s->len[1], &gb)<0)
return -1;
memcpy(s->len[2] , s->len [1], 256*sizeof(uint8_t));
for(i=0; i<3; i++){
- free_vlc(&s->vlc[i]);
+ ff_free_vlc(&s->vlc[i]);
init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1, s->bits[i], 4, 4, 0);
}
s->temp[i]= av_malloc(s->width + 16);
}
}else{
- s->temp[0]= av_malloc(4*s->width + 16);
+ s->temp[0]= av_mallocz(4*s->width + 16);
}
}
s->avctx= avctx;
s->flags= avctx->flags;
- dsputil_init(&s->dsp, avctx);
+ ff_dsputil_init(&s->dsp, avctx);
s->width= avctx->width;
s->height= avctx->height;
if(s->version==2){
int method, interlace;
+ if (avctx->extradata_size < 4)
+ return -1;
+
method= ((uint8_t*)avctx->extradata)[0];
s->decorrelate= method&64 ? 1 : 0;
s->predictor= method&63;
s->interlaced= (interlace==1) ? 1 : (interlace==2) ? 0 : s->interlaced;
s->context= ((uint8_t*)avctx->extradata)[2] & 0x40 ? 1 : 0;
- if(read_huffman_tables(s, ((uint8_t*)avctx->extradata)+4, avctx->extradata_size) < 0)
+ if(read_huffman_tables(s, ((uint8_t*)avctx->extradata)+4, avctx->extradata_size-4) < 0)
return -1;
}else{
switch(avctx->bits_per_coded_sample&7){
}
break;
default:
- assert(0);
+ return AVERROR_INVALIDDATA;
}
alloc_temp(s);
return 0;
}
+
+static av_cold int decode_init_thread_copy(AVCodecContext *avctx)
+{
+ HYuvContext *s = avctx->priv_data;
+ int i;
+
+ avctx->coded_frame= &s->picture;
+ alloc_temp(s);
+
+ for (i = 0; i < 6; i++)
+ s->vlc[i].table = NULL;
+
+ if(s->version==2){
+ if(read_huffman_tables(s, ((uint8_t*)avctx->extradata)+4, avctx->extradata_size) < 0)
+ return -1;
+ }else{
+ if(read_old_huffman_tables(s) < 0)
+ return -1;
+ }
+
+ return 0;
+}
#endif /* CONFIG_HUFFYUV_DECODER || CONFIG_FFVHUFF_DECODER */
#if CONFIG_HUFFYUV_ENCODER || CONFIG_FFVHUFF_ENCODER
-static int store_table(HYuvContext *s, uint8_t *len, uint8_t *buf){
+static int store_table(HYuvContext *s, const uint8_t *len, uint8_t *buf){
int i;
int index= 0;
}
for(i=0; i<3; i++){
- generate_len_table(s->len[i], s->stats[i], 256);
+ generate_len_table(s->len[i], s->stats[i]);
if(generate_bits_table(s->bits[i], s->len[i])<0){
return -1;
count/=2;
if(count >= (get_bits_left(&s->gb))/(31*4)){
- for(i=0; i<count && get_bits_count(&s->gb) < s->gb.size_in_bits; i++){
+ for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) {
READ_2PIX(s->temp[0][2*i ], s->temp[1][i], 1);
READ_2PIX(s->temp[0][2*i+1], s->temp[2][i], 2);
}
count/=2;
if(count >= (get_bits_left(&s->gb))/(31*2)){
- for(i=0; i<count && get_bits_count(&s->gb) < s->gb.size_in_bits; i++){
+ for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) {
READ_2PIX(s->temp[0][2*i ], s->temp[0][2*i+1], 0);
}
}else{
s->temp[0][4*i+R] = get_vlc2(&s->gb, s->vlc[2].table, VLC_BITS, 3);
}
if(alpha)
- get_vlc2(&s->gb, s->vlc[2].table, VLC_BITS, 3); //?!
+ s->temp[0][4*i+A] = get_vlc2(&s->gb, s->vlc[2].table, VLC_BITS, 3);
}
}
#if CONFIG_HUFFYUV_DECODER || CONFIG_FFVHUFF_DECODER
static void draw_slice(HYuvContext *s, int y){
- int h, cy;
- int offset[4];
+ int h, cy, i;
+ int offset[AV_NUM_DATA_POINTERS];
if(s->avctx->draw_horiz_band==NULL)
return;
offset[0] = s->picture.linesize[0]*y;
offset[1] = s->picture.linesize[1]*cy;
offset[2] = s->picture.linesize[2]*cy;
- offset[3] = 0;
+ for (i = 3; i < AV_NUM_DATA_POINTERS; i++)
+ offset[i] = 0;
emms_c();
s->avctx->draw_horiz_band(s->avctx, &s->picture, offset, y, 3, h);
s->dsp.bswap_buf((uint32_t*)s->bitstream_buffer, (const uint32_t*)buf, buf_size/4);
if(p->data[0])
- avctx->release_buffer(avctx, p);
+ ff_thread_release_buffer(avctx, p);
p->reference= 0;
- if(avctx->get_buffer(avctx, p) < 0){
+ if(ff_thread_get_buffer(avctx, p) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
}
}else{
int y;
- int leftr, leftg, leftb;
+ int leftr, leftg, leftb, lefta;
const int last_line= (height-1)*p->linesize[0];
if(s->bitstream_bpp==32){
- skip_bits(&s->gb, 8);
+ lefta= p->data[0][last_line+A]= get_bits(&s->gb, 8);
leftr= p->data[0][last_line+R]= get_bits(&s->gb, 8);
leftg= p->data[0][last_line+G]= get_bits(&s->gb, 8);
leftb= p->data[0][last_line+B]= get_bits(&s->gb, 8);
leftr= p->data[0][last_line+R]= get_bits(&s->gb, 8);
leftg= p->data[0][last_line+G]= get_bits(&s->gb, 8);
leftb= p->data[0][last_line+B]= get_bits(&s->gb, 8);
+ lefta= p->data[0][last_line+A]= 255;
skip_bits(&s->gb, 8);
}
case LEFT:
case PLANE:
decode_bgr_bitstream(s, width-1);
- s->dsp.add_hfyu_left_prediction_bgr32(p->data[0] + last_line+4, s->temp[0], width-1, &leftr, &leftg, &leftb);
+ s->dsp.add_hfyu_left_prediction_bgr32(p->data[0] + last_line+4, s->temp[0], width-1, &leftr, &leftg, &leftb, &lefta);
for(y=s->height-2; y>=0; y--){ //Yes it is stored upside down.
decode_bgr_bitstream(s, width);
- s->dsp.add_hfyu_left_prediction_bgr32(p->data[0] + p->linesize[0]*y, s->temp[0], width, &leftr, &leftg, &leftb);
+ s->dsp.add_hfyu_left_prediction_bgr32(p->data[0] + p->linesize[0]*y, s->temp[0], width, &leftr, &leftg, &leftb, &lefta);
if(s->predictor == PLANE){
+ if(s->bitstream_bpp!=32) lefta=0;
if((y&s->interlaced)==0 && y<s->height-1-s->interlaced){
s->dsp.add_bytes(p->data[0] + p->linesize[0]*y,
p->data[0] + p->linesize[0]*y + fake_ystride, fake_ystride);
av_freep(&s->bitstream_buffer);
for(i=0; i<6; i++){
- free_vlc(&s->vlc[i]);
+ ff_free_vlc(&s->vlc[i]);
}
return 0;
#endif /* CONFIG_HUFFYUV_DECODER || CONFIG_FFVHUFF_DECODER */
#if CONFIG_HUFFYUV_ENCODER || CONFIG_FFVHUFF_ENCODER
-static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
HYuvContext *s = avctx->priv_data;
- AVFrame *pict = data;
const int width= s->width;
const int width2= s->width>>1;
const int height= s->height;
const int fake_ustride= s->interlaced ? pict->linesize[1]*2 : pict->linesize[1];
const int fake_vstride= s->interlaced ? pict->linesize[2]*2 : pict->linesize[2];
AVFrame * const p= &s->picture;
- int i, j, size=0;
+ int i, j, size = 0, ret;
+
+ if (!pkt->data &&
+ (ret = av_new_packet(pkt, width * height * 3 * 4 + FF_MIN_BUFFER_SIZE)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Error allocating output packet.\n");
+ return ret;
+ }
*p = *pict;
- p->pict_type= FF_I_TYPE;
+ p->pict_type= AV_PICTURE_TYPE_I;
p->key_frame= 1;
if(s->context){
for(i=0; i<3; i++){
- generate_len_table(s->len[i], s->stats[i], 256);
+ generate_len_table(s->len[i], s->stats[i]);
if(generate_bits_table(s->bits[i], s->len[i])<0)
return -1;
- size+= store_table(s, s->len[i], &buf[size]);
+ size += store_table(s, s->len[i], &pkt->data[size]);
}
for(i=0; i<3; i++)
s->stats[i][j] >>= 1;
}
- init_put_bits(&s->pb, buf+size, buf_size-size);
+ init_put_bits(&s->pb, pkt->data + size, pkt->size - size);
if(avctx->pix_fmt == PIX_FMT_YUV422P || avctx->pix_fmt == PIX_FMT_YUV420P){
int lefty, leftu, leftv, y, cy;
avctx->stats_out[0] = '\0';
if(!(s->avctx->flags2 & CODEC_FLAG2_NO_OUTPUT)){
flush_put_bits(&s->pb);
- s->dsp.bswap_buf((uint32_t*)buf, (uint32_t*)buf, size);
+ s->dsp.bswap_buf((uint32_t*)pkt->data, (uint32_t*)pkt->data, size);
}
s->picture_number++;
- return size*4;
+ pkt->size = size*4;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ return 0;
}
static av_cold int encode_end(AVCodecContext *avctx)
#endif /* CONFIG_HUFFYUV_ENCODER || CONFIG_FFVHUFF_ENCODER */
#if CONFIG_HUFFYUV_DECODER
-AVCodec huffyuv_decoder = {
- "huffyuv",
- CODEC_TYPE_VIDEO,
- CODEC_ID_HUFFYUV,
- sizeof(HYuvContext),
- decode_init,
- NULL,
- decode_end,
- decode_frame,
- CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND,
- NULL,
- .long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"),
+AVCodec ff_huffyuv_decoder = {
+ .name = "huffyuv",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = CODEC_ID_HUFFYUV,
+ .priv_data_size = sizeof(HYuvContext),
+ .init = decode_init,
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND |
+ CODEC_CAP_FRAME_THREADS,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
+ .long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"),
};
#endif
#if CONFIG_FFVHUFF_DECODER
-AVCodec ffvhuff_decoder = {
- "ffvhuff",
- CODEC_TYPE_VIDEO,
- CODEC_ID_FFVHUFF,
- sizeof(HYuvContext),
- decode_init,
- NULL,
- decode_end,
- decode_frame,
- CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND,
- NULL,
- .long_name = NULL_IF_CONFIG_SMALL("Huffyuv FFmpeg variant"),
+AVCodec ff_ffvhuff_decoder = {
+ .name = "ffvhuff",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = CODEC_ID_FFVHUFF,
+ .priv_data_size = sizeof(HYuvContext),
+ .init = decode_init,
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND |
+ CODEC_CAP_FRAME_THREADS,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
+ .long_name = NULL_IF_CONFIG_SMALL("Huffyuv FFmpeg variant"),
};
#endif
#if CONFIG_HUFFYUV_ENCODER
-AVCodec huffyuv_encoder = {
- "huffyuv",
- CODEC_TYPE_VIDEO,
- CODEC_ID_HUFFYUV,
- sizeof(HYuvContext),
- encode_init,
- encode_frame,
- encode_end,
- .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV422P, PIX_FMT_RGB32, PIX_FMT_NONE},
- .long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"),
+AVCodec ff_huffyuv_encoder = {
+ .name = "huffyuv",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = CODEC_ID_HUFFYUV,
+ .priv_data_size = sizeof(HYuvContext),
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_end,
+ .pix_fmts = (const enum PixelFormat[]){
+ PIX_FMT_YUV422P, PIX_FMT_RGB32, PIX_FMT_NONE
+ },
+ .long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"),
};
#endif
#if CONFIG_FFVHUFF_ENCODER
-AVCodec ffvhuff_encoder = {
- "ffvhuff",
- CODEC_TYPE_VIDEO,
- CODEC_ID_FFVHUFF,
- sizeof(HYuvContext),
- encode_init,
- encode_frame,
- encode_end,
- .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_RGB32, PIX_FMT_NONE},
- .long_name = NULL_IF_CONFIG_SMALL("Huffyuv FFmpeg variant"),
+AVCodec ff_ffvhuff_encoder = {
+ .name = "ffvhuff",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = CODEC_ID_FFVHUFF,
+ .priv_data_size = sizeof(HYuvContext),
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_end,
+ .pix_fmts = (const enum PixelFormat[]){
+ PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_RGB32, PIX_FMT_NONE
+ },
+ .long_name = NULL_IF_CONFIG_SMALL("Huffyuv FFmpeg variant"),
};
#endif