Merge remote-tracking branch 'qatar/master'

* qatar/master:
  Mirillis FIC video decoder

Conflicts:
	Changelog
	configure
	libavcodec/Makefile
	libavcodec/avcodec.h
	libavcodec/version.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>
pull/43/merge
Michael Niedermayer 11 years ago
commit 0c4bf87b29
  1. 1
      Changelog
  2. 1
      configure
  3. 2
      doc/general.texi
  4. 1
      libavcodec/Makefile
  5. 1
      libavcodec/allcodecs.c
  6. 1
      libavcodec/avcodec.h
  7. 7
      libavcodec/codec_desc.c
  8. 298
      libavcodec/fic.c
  9. 4
      libavcodec/version.h
  10. 1
      libavformat/riff.c

@ -24,6 +24,7 @@ version <next>
- OpenGL device - OpenGL device
- Use metadata_header_padding to control padding in ID3 tags (currently used in - Use metadata_header_padding to control padding in ID3 tags (currently used in
MP3, AIFF, and OMA files), FLAC header, and the AVI "junk" block. MP3, AIFF, and OMA files), FLAC header, and the AVI "junk" block.
- Mirillis FIC video decoder
version 2.1: version 2.1:

1
configure vendored

@ -1915,6 +1915,7 @@ ffv1_decoder_select="dsputil golomb rangecoder"
ffv1_encoder_select="dsputil rangecoder" ffv1_encoder_select="dsputil rangecoder"
ffvhuff_decoder_select="dsputil llviddsp" ffvhuff_decoder_select="dsputil llviddsp"
ffvhuff_encoder_select="dsputil huffman llviddsp" ffvhuff_encoder_select="dsputil huffman llviddsp"
fic_decoder_select="dsputil golomb"
flac_decoder_select="golomb" flac_decoder_select="golomb"
flac_encoder_select="dsputil golomb lpc" flac_encoder_select="dsputil golomb lpc"
flashsv_decoder_select="zlib" flashsv_decoder_select="zlib"

@ -301,6 +301,8 @@ library:
@tab also known as DVB Transport Stream @tab also known as DVB Transport Stream
@item MPEG-4 @tab X @tab X @item MPEG-4 @tab X @tab X
@tab MPEG-4 is a variant of QuickTime. @tab MPEG-4 is a variant of QuickTime.
@item Mirillis FIC video @tab @tab X
@tab No cursor rendering.
@item MIME multipart JPEG @tab X @tab @item MIME multipart JPEG @tab X @tab
@item MSN TCP webcam @tab @tab X @item MSN TCP webcam @tab @tab X
@tab Used by MSN Messenger webcam streams. @tab Used by MSN Messenger webcam streams.

@ -206,6 +206,7 @@ OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o
OBJS-$(CONFIG_FFVHUFF_DECODER) += huffyuv.o huffyuvdec.o OBJS-$(CONFIG_FFVHUFF_DECODER) += huffyuv.o huffyuvdec.o
OBJS-$(CONFIG_FFVHUFF_ENCODER) += huffyuv.o huffyuvenc.o OBJS-$(CONFIG_FFVHUFF_ENCODER) += huffyuv.o huffyuvenc.o
OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o
OBJS-$(CONFIG_FIC_DECODER) += fic.o
OBJS-$(CONFIG_FLAC_DECODER) += flacdec.o flacdata.o flac.o flacdsp.o OBJS-$(CONFIG_FLAC_DECODER) += flacdec.o flacdata.o flac.o flacdsp.o
OBJS-$(CONFIG_FLAC_ENCODER) += flacenc.o flacdata.o flac.o flacdsp.o vorbis_data.o OBJS-$(CONFIG_FLAC_ENCODER) += flacenc.o flacdata.o flac.o flacdsp.o vorbis_data.o
OBJS-$(CONFIG_FLASHSV_DECODER) += flashsv.o OBJS-$(CONFIG_FLASHSV_DECODER) += flashsv.o

@ -150,6 +150,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(EXR, exr); REGISTER_DECODER(EXR, exr);
REGISTER_ENCDEC (FFV1, ffv1); REGISTER_ENCDEC (FFV1, ffv1);
REGISTER_ENCDEC (FFVHUFF, ffvhuff); REGISTER_ENCDEC (FFVHUFF, ffvhuff);
REGISTER_DECODER(FIC, fic);
REGISTER_ENCDEC (FLASHSV, flashsv); REGISTER_ENCDEC (FLASHSV, flashsv);
REGISTER_ENCDEC (FLASHSV2, flashsv2); REGISTER_ENCDEC (FLASHSV2, flashsv2);
REGISTER_DECODER(FLIC, flic); REGISTER_DECODER(FLIC, flic);

@ -285,6 +285,7 @@ enum AVCodecID {
AV_CODEC_ID_WEBP_DEPRECATED, AV_CODEC_ID_WEBP_DEPRECATED,
AV_CODEC_ID_HNM4_VIDEO, AV_CODEC_ID_HNM4_VIDEO,
AV_CODEC_ID_HEVC_DEPRECATED, AV_CODEC_ID_HEVC_DEPRECATED,
AV_CODEC_ID_FIC,
AV_CODEC_ID_BRENDER_PIX= MKBETAG('B','P','I','X'), AV_CODEC_ID_BRENDER_PIX= MKBETAG('B','P','I','X'),
AV_CODEC_ID_Y41P = MKBETAG('Y','4','1','P'), AV_CODEC_ID_Y41P = MKBETAG('Y','4','1','P'),

@ -1403,6 +1403,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC (High Efficiency Video Coding)"), .long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC (High Efficiency Video Coding)"),
.props = AV_CODEC_PROP_LOSSY, .props = AV_CODEC_PROP_LOSSY,
}, },
{
.id = AV_CODEC_ID_FIC,
.type = AVMEDIA_TYPE_VIDEO,
.name = "fic",
.long_name = NULL_IF_CONFIG_SMALL("Mirillis FIC"),
.props = AV_CODEC_PROP_LOSSY,
},
/* various PCM "codecs" */ /* various PCM "codecs" */
{ {

@ -0,0 +1,298 @@
/*
* Mirillis FIC decoder
*
* Copyright (c) 2014 Konstantin Shishkov
* Copyright (c) 2014 Derek Buitenhuis
*
* 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 "avcodec.h"
#include "internal.h"
#include "dsputil.h"
#include "get_bits.h"
#include "golomb.h"
typedef struct FICThreadContext {
DECLARE_ALIGNED(16, int16_t, block)[64];
uint8_t *src;
int slice_h;
int src_size;
int y_off;
} FICThreadContext;
typedef struct FICContext {
AVCodecContext *avctx;
AVFrame *frame;
DSPContext dsp;
ScanTable scantable;
FICThreadContext *slice_data;
int slice_data_size;
const uint8_t *qmat;
enum AVPictureType cur_frame_type;
int aligned_width, aligned_height;
int num_slices, slice_h;
} FICContext;
static const uint8_t fic_qmat_hq[64] = {
1, 2, 2, 2, 3, 3, 3, 4,
2, 2, 2, 3, 3, 3, 4, 4,
2, 2, 3, 3, 3, 4, 4, 4,
2, 2, 3, 3, 3, 4, 4, 5,
2, 3, 3, 3, 4, 4, 5, 6,
3, 3, 3, 4, 4, 5, 6, 7,
3, 3, 3, 4, 4, 5, 7, 7,
3, 3, 4, 4, 5, 7, 7, 7,
};
static const uint8_t fic_qmat_lq[64] = {
1, 5, 6, 7, 8, 9, 9, 11,
5, 5, 7, 8, 9, 9, 11, 12,
6, 7, 8, 9, 9, 11, 11, 12,
7, 7, 8, 9, 9, 11, 12, 13,
7, 8, 9, 9, 10, 11, 13, 16,
8, 9, 9, 10, 11, 13, 16, 19,
8, 9, 9, 11, 12, 15, 18, 23,
9, 9, 11, 12, 15, 18, 23, 27
};
static const uint8_t fic_header[7] = { 0, 0, 1, 'F', 'I', 'C', 'V' };
#define FIC_HEADER_SIZE 27
static int fic_decode_block(FICContext *ctx, GetBitContext *gb,
uint8_t *dst, int stride, int16_t *block)
{
int i, num_coeff;
/* Is it a skip block? */
if (get_bits1(gb)) {
/* This is a P-frame. */
ctx->frame->key_frame = 0;
ctx->frame->pict_type = AV_PICTURE_TYPE_P;
return 0;
}
ctx->dsp.clear_block(block);
num_coeff = get_bits(gb, 7);
if (num_coeff > 64)
return AVERROR_INVALIDDATA;
for (i = 0; i < num_coeff; i++)
block[ctx->scantable.permutated[i]] = get_se_golomb(gb) * ctx->qmat[i];
ctx->dsp.idct_put(dst, stride, block);
return 0;
}
static int fic_decode_slice(AVCodecContext *avctx, void *tdata)
{
FICContext *ctx = avctx->priv_data;
FICThreadContext *tctx = tdata;
GetBitContext gb;
uint8_t *src = tctx->src;
int slice_h = tctx->slice_h;
int src_size = tctx->src_size;
int y_off = tctx->y_off;
int x, y, p;
init_get_bits(&gb, src, src_size * 8);
for (p = 0; p < 3; p++) {
int stride = ctx->frame->linesize[p];
uint8_t* dst = ctx->frame->data[p] + (y_off >> !!p) * stride;
for (y = 0; y < (slice_h >> !!p); y += 8) {
for (x = 0; x < (ctx->aligned_width >> !!p); x += 8) {
int ret;
if ((ret = fic_decode_block(ctx, &gb, dst + x, stride, tctx->block)) != 0)
return ret;
}
dst += 8 * stride;
}
}
return 0;
}
static int fic_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
FICContext *ctx = avctx->priv_data;
uint8_t *src = avpkt->data;
int ret;
int slice, nslices;
int msize;
int tsize;
uint8_t *sdata;
if ((ret = ff_reget_buffer(avctx, ctx->frame)) < 0) {
av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
return ret;
}
/* Header + at least one slice (4) */
if (avpkt->size < FIC_HEADER_SIZE + 4) {
av_log(avctx, AV_LOG_ERROR, "Frame data is too small.\n");
return AVERROR_INVALIDDATA;
}
/* Check for header. */
if (memcmp(src, fic_header, 7))
av_log(avctx, AV_LOG_WARNING, "Invalid FIC Header.\n");
nslices = src[13];
if (!nslices) {
av_log(avctx, AV_LOG_ERROR, "Zero slices found.\n");
return AVERROR_INVALIDDATA;
}
/* High or Low Quality Matrix? */
ctx->qmat = src[23] ? fic_qmat_hq : fic_qmat_lq;
/* Skip cursor data. */
tsize = AV_RB24(src + 24);
if (tsize > avpkt->size - FIC_HEADER_SIZE) {
av_log(avctx, AV_LOG_ERROR, "Invalid cursor data size.\n");
return AVERROR_INVALIDDATA;
}
/* Slice height for all but the last slice. */
ctx->slice_h = 16 * (ctx->aligned_height >> 4) / nslices;
if (ctx->slice_h % 16)
ctx->slice_h = FFALIGN(ctx->slice_h - 16, 16);
/* First slice offset and remaining data. */
sdata = src + tsize + FIC_HEADER_SIZE + 4 * nslices;
msize = avpkt->size - nslices * 4 - tsize - FIC_HEADER_SIZE;
if (msize <= 0) {
av_log(avctx, AV_LOG_ERROR, "Not enough frame data to decode.\n");
return AVERROR_INVALIDDATA;
}
/*
* Set the frametype to I initially. It will be set to P if the frame
* has any dependencies (skip blocks). There will be a race condition
* inside the slice decode function to set these, but we do not care.
* since they will only ever be set to 0/P.
*/
ctx->frame->key_frame = 1;
ctx->frame->pict_type = AV_PICTURE_TYPE_I;
/* Allocate slice data. */
av_fast_malloc(&ctx->slice_data, &ctx->slice_data_size,
nslices * sizeof(ctx->slice_data[0]));
if (!ctx->slice_data_size) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate slice data.\n");
return AVERROR(ENOMEM);
}
for (slice = 0; slice < nslices; slice++) {
int slice_off = AV_RB32(src + tsize + FIC_HEADER_SIZE + slice * 4);
int slice_size;
int y_off = ctx->slice_h * slice;
int slice_h = ctx->slice_h;
/*
* Either read the slice size, or consume all data left.
* Also, special case the last slight height.
*/
if (slice == nslices - 1) {
slice_size = msize;
slice_h = FFALIGN(avctx->height - ctx->slice_h * (nslices - 1), 16);
} else {
slice_size = AV_RB32(src + tsize + FIC_HEADER_SIZE + slice * 4 + 4);
}
slice_size -= slice_off;
if (slice_off > msize || slice_off + slice_size > msize)
continue;
ctx->slice_data[slice].src = sdata + slice_off;
ctx->slice_data[slice].src_size = slice_size;
ctx->slice_data[slice].slice_h = slice_h;
ctx->slice_data[slice].y_off = y_off;
}
if (ret = avctx->execute(avctx, fic_decode_slice, ctx->slice_data,
NULL, nslices, sizeof(ctx->slice_data[0])) < 0)
return ret;
*got_frame = 1;
if ((ret = av_frame_ref(data, ctx->frame)) < 0)
return ret;
return avpkt->size;
}
static av_cold int fic_decode_close(AVCodecContext *avctx)
{
FICContext *ctx = avctx->priv_data;
av_freep(&ctx->slice_data);
av_frame_free(&ctx->frame);
return 0;
}
static av_cold int fic_decode_init(AVCodecContext *avctx)
{
FICContext *ctx = avctx->priv_data;
/* Initialize various context values */
ctx->avctx = avctx;
ctx->aligned_width = FFALIGN(avctx->width, 16);
ctx->aligned_height = FFALIGN(avctx->height, 16);
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
avctx->bits_per_raw_sample = 8;
ctx->frame = av_frame_alloc();
if (!ctx->frame)
return AVERROR(ENOMEM);
ff_dsputil_init(&ctx->dsp, avctx);
ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable, ff_zigzag_direct);
return 0;
}
AVCodec ff_fic_decoder = {
.name = "fic",
.long_name = NULL_IF_CONFIG_SMALL("Mirillis FIC"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_FIC,
.priv_data_size = sizeof(FICContext),
.init = fic_decode_init,
.decode = fic_decode_frame,
.close = fic_decode_close,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
};

@ -29,8 +29,8 @@
#include "libavutil/version.h" #include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 55 #define LIBAVCODEC_VERSION_MAJOR 55
#define LIBAVCODEC_VERSION_MINOR 49 #define LIBAVCODEC_VERSION_MINOR 50
#define LIBAVCODEC_VERSION_MICRO 101 #define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \ LIBAVCODEC_VERSION_MINOR, \

@ -356,6 +356,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') }, { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') }, { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') }, { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') },
{ AV_CODEC_ID_FIC, MKTAG('F', 'I', 'C', 'V') },
{ AV_CODEC_ID_NONE, 0 } { AV_CODEC_ID_NONE, 0 }
}; };

Loading…
Cancel
Save