On Mon, Jan 04, 2016 at 12:04:08AM +0000, Kieran Kunhya wrote: > Decodes YUV422P10 samples in AVI and MOV (Gopro Studio) > Older files with more subbands, skips, Bayer not supported > --- > libavcodec/Makefile | 1 + > libavcodec/allcodecs.c | 1 + > libavcodec/avcodec.h | 1 + > libavcodec/cfhd.c | 567 > ++++++++++++++++++++++++++++++++++++++++++++++++ > libavcodec/cfhd.h | 97 +++++++++ > libavcodec/cfhddata.c | 466 +++++++++++++++++++++++++++++++++++++++ > libavcodec/codec_desc.c | 6 +
> libavformat/riff.c | 1 + ideally the avformat change should be a seperate commit > 8 files changed, 1140 insertions(+) > create mode 100644 libavcodec/cfhd.c > create mode 100644 libavcodec/cfhd.h > create mode 100644 libavcodec/cfhddata.c > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index a18ca5b..9db88d7 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -212,6 +212,7 @@ OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o > OBJS-$(CONFIG_CDXL_DECODER) += cdxl.o > OBJS-$(CONFIG_CINEPAK_DECODER) += cinepak.o > OBJS-$(CONFIG_CINEPAK_ENCODER) += cinepakenc.o elbg.o > +OBJS-$(CONFIG_CFHD_DECODER) += cfhd.o cfhddata.o > OBJS-$(CONFIG_CLJR_DECODER) += cljrdec.o > OBJS-$(CONFIG_CLJR_ENCODER) += cljrenc.o > OBJS-$(CONFIG_CLLC_DECODER) += cllc.o canopus.o > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c > index 4eeb6f3..ca6e4c2 100644 > --- a/libavcodec/allcodecs.c > +++ b/libavcodec/allcodecs.c > @@ -147,6 +147,7 @@ void avcodec_register_all(void) > REGISTER_DECODER(CAVS, cavs); > REGISTER_DECODER(CDGRAPHICS, cdgraphics); > REGISTER_DECODER(CDXL, cdxl); > + REGISTER_DECODER(CFHD, cfhd); > REGISTER_ENCDEC (CINEPAK, cinepak); > REGISTER_ENCDEC (CLJR, cljr); > REGISTER_DECODER(CLLC, cllc); > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > index f365775..b958a6c 100644 > --- a/libavcodec/avcodec.h > +++ b/libavcodec/avcodec.h > @@ -315,6 +315,7 @@ enum AVCodecID { > AV_CODEC_ID_SMVJPEG, > AV_CODEC_ID_APNG, > AV_CODEC_ID_DAALA, > + AV_CODEC_ID_CFHD, > > /* various PCM "codecs" */ > AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the > start of audio codecs > diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c > new file mode 100644 > index 0000000..0f1bcd3 > --- /dev/null > +++ b/libavcodec/cfhd.c > @@ -0,0 +1,567 @@ > +/* > + * Copyright (c) 2015 Kieran Kunhya > + * > + * 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 > + */ > + > +/** > + * @file > + * CFHD Video Decoder > + */ > + > +#include "avcodec.h" > +#include "bswapdsp.h" > +#include "internal.h" > +#include "cfhd.h" > +#include "libavutil/avassert.h" > +#include "libavutil/buffer.h" > +#include "libavutil/common.h" > +#include "libavutil/intreadwrite.h" > +#include "libavutil/imgutils.h" > +#include "libavutil/opt.h" > + > +static av_cold int cfhd_init_decoder(AVCodecContext *avctx) > +{ > + CFHDContext *s = avctx->priv_data; > + > + ff_cfhd_init_vlcs(s); > + > + avctx->pix_fmt = AV_PIX_FMT_YUV422P10; > + avctx->bits_per_raw_sample = 16; > + s->avctx = avctx; > + > + return 0; > +} > + > +static void init_plane_defaults(CFHDContext *s) > +{ > + s->subband_num = 0; > + s->level = 0; > + s->subband_num_actual = 0; > +} > + > +static void init_frame_defaults(CFHDContext *s) > +{ > + s->bpc = 10; > + s->channel_cnt = 4; > + s->subband_cnt = 10; > + s->channel_num = 0; > + s->lowpass_precision = 16; > + s->quantisation = 1; > + s->wavelet_depth = 3; > + s->pshift = 1; > + s->codebook = 0; > + init_plane_defaults(s); > +} > + > +static inline int dequant_and_decompand(int level, int quantisation) > +{ > + int abslevel = abs(level); > + return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 > * 255))) * FFSIGN(level) * quantisation; > +} > + > +static inline void filter(int16_t *output, int out_stride, int16_t *low, int > low_stride, > + int16_t *high, int high_stride, int len) > +{ > + int32_t tmp, tmp2; > + int16_t tmp3, tmp4; > + > + /* these refer to the coefficients for the *next* iteration */ > + int16_t l_0, l_1, l_2, l_m1, l_m2; > + int16_t h_0; > + > + int i; > + for (i = 0; i < len; i++) { > + if (i == 0) { > + l_2 = low[3 * low_stride]; > + l_1 = low[2 * low_stride]; > + l_0 = low[1 * low_stride]; > + l_m1 = low[0 * low_stride]; > + l_m2 = 0; > + h_0 = high[1 * high_stride]; > + > + tmp = (11 * l_m1 - 4 * l_0 + l_1 + 4) >> 3; > + tmp2 = (5 * l_m1 + 4 * l_0 - l_1 + 4) >> 3; > + > + output[(2 * i + 0) * out_stride] = (tmp + high[0 * high_stride]) > >> 1; > + output[(2 * i + 1) * out_stride] = (tmp2 - high[0 * > high_stride]) >> 1; > + } else if (i == len - 1) { > + tmp = (5 * l_0 + 4 * l_m1 - l_m2 + 4) >> 3; > + output[(2 * i + 0) * out_stride] = (tmp + h_0) >> 1; > + tmp = (11 * l_0 - 4 * l_m1 + l_m2 + 4) >> 3; > + output[(2 * i + 1) * out_stride] = (tmp - h_0) >> 1; > + } else { > + tmp = (l_m1 - l_1 + 4) >> 3; > + tmp2 = (l_1 - l_m1 + 4) >> 3; > + > + tmp3 = (tmp + l_0 + h_0) >> 1; > + tmp4 = (tmp2 + l_0 - h_0) >> 1; > + > + l_m2 = l_m1; > + l_m1 = l_0; > + l_0 = l_1; > + l_1 = l_2; > + l_2 = low[(i + 3) * low_stride]; > + h_0 = high[(i + 1) * high_stride]; > + > + output[(2 * i + 0) * out_stride] = tmp3; > + output[(2 * i + 1) * out_stride] = tmp4; > + } > + } > +} > + > +static void horiz_filter(int16_t *output, int16_t *low, int16_t *high, int > width) > +{ > + filter(output, 1, low, 1, high, 1, width); > +} > + > +static void vert_filter(int16_t *output, int out_stride, int16_t *low, int > low_stride, > + int16_t *high, int high_stride, int len) > +{ > + filter(output, out_stride, low, low_stride, high, high_stride, len); > +} > + > +static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, > + AVPacket *avpkt) > +{ > + CFHDContext *s = avctx->priv_data; > + uint8_t *bs = avpkt->data; > + int cnt = 0; > + AVFrame *pic = data; > + int ret = 0, i, j; > + int16_t *plane[3]; > + int16_t *tmp[3]; > + int16_t *subband[3][10] = {{0}}; > + int16_t *l_h[3][8]; > + > + avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, > &s->chroma_y_shift); > + > + for (i = 0; i < 3; i++) { > + int width = i ? avctx->width >> s->chroma_x_shift : avctx->width; > + int height = i ? avctx->height >> s->chroma_y_shift : avctx->height; > + height = FFALIGN(height / 8, 2) * 8; > + int stride = FFALIGN(width / 8, 8) * 8; > + s->plane[i].width = width; > + s->plane[i].height = height; > + s->plane[i].stride = stride; > + > + int w8 = FFALIGN(s->plane[i].width / 8, 8); > + int h8 = FFALIGN(s->plane[i].height / 8, 2); > + int w4 = w8 * 2; > + int h4 = h8 * 2; > + int w2 = w4 * 2; > + int h2 = h4 * 2; > + > + plane[i] = av_malloc(height * stride * sizeof(*plane[i])); > + tmp[i] = av_malloc(height * stride * sizeof(*plane[i])); > + > + subband[i][0] = plane[i]; missing malloc failure checks > + subband[i][1] = plane[i] + 2 * w8 * h8; > + subband[i][2] = plane[i] + 1 * w8 * h8; > + subband[i][3] = plane[i] + 3 * w8 * h8; > + subband[i][4] = plane[i] + 2 * w4 * h4; > + subband[i][5] = plane[i] + 1 * w4 * h4; > + subband[i][6] = plane[i] + 3 * w4 * h4; > + subband[i][7] = plane[i] + 2 * w2 * h2; > + subband[i][8] = plane[i] + 1 * w2 * h2; > + subband[i][9] = plane[i] + 3 * w2 * h2; > + > + l_h[i][0] = tmp[i]; > + l_h[i][1] = tmp[i] + 2 * w8 * h8; > + //l_h[i][2] = ll2; > + l_h[i][3] = tmp[i]; > + l_h[i][4] = tmp[i] + 2 * w4 * h4; > + //l_h[i][5] = ll1; > + l_h[i][6] = tmp[i]; > + l_h[i][7] = tmp[i] + 2 * w2 * h2; > + } > + > + init_frame_defaults(s); > + > + if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) > + return ret; > + > + while (cnt < avpkt->size) { > + int16_t tag = AV_RB16(&bs[cnt]); > + int8_t tag8 = (int8_t)bs[cnt]; > + uint16_t abstag = abs(tag); > + int8_t abs_tag8 = abs(tag8); > + uint16_t data = AV_RB16(&bs[cnt + 2]); > + if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) { > + av_log(avctx, AV_LOG_DEBUG, "large len %x \n", AV_RB24(&bs[cnt + > 1])); > + } else if (tag == 20) { > + av_log(avctx, AV_LOG_DEBUG, "Width %u %x \n", data, cnt); > + avctx->width = data; > + } else if (tag == 21) { > + av_log(avctx, AV_LOG_DEBUG, "Height %u %x \n", data, cnt); > + avctx->height = data; > + } else if (tag == 101) { > + av_log(avctx, AV_LOG_DEBUG, "Bits per component: %u \n", data); > + s->bpc = data; the debug av_logs could be put under some if (avctx->debug & FF_DEBUG_*) that way they can be enabled when needed and dont clutter the output when not > + } else if (tag == 12) { > + av_log(avctx, AV_LOG_DEBUG, "Channel Count: %u \n", data); > + s->channel_cnt = data; > + if (data != 3) { > + av_log(avctx, AV_LOG_ERROR, "Channel Count of %u is > unsupported\n", data); > + ret = AVERROR_PATCHWELCOME; > + break; > + } > + } else if (tag == 14) { > + av_log(avctx, AV_LOG_DEBUG, "Subband Count: %u \n", data); > + if (data != 10) { > + av_log(avctx, AV_LOG_ERROR, "Subband Count of %u is > unsupported\n", data); > + ret = AVERROR_PATCHWELCOME; > + break; > + } > + } > + else if (tag == 62) { > + s->channel_num = data; > + av_log(avctx, AV_LOG_DEBUG, "Channel number %u \n", data); > + init_plane_defaults(s); > + } else if (tag == 48) { > + if (s->subband_num != 0 && data == 1) // hack > + s->level++; > + av_log(avctx, AV_LOG_DEBUG, "Subband number %u \n", data); > + s->subband_num = data; > + } else if (tag == 51) { > + av_log(avctx, AV_LOG_DEBUG, "Subband number actual %u \n", data); > + s->subband_num_actual = data; > + } else if (tag == 35) > + av_log(avctx, AV_LOG_DEBUG, "Lowpass precision bits: %u \n", > data); > + else if (tag == 53) { > + s->quantisation = data; > + av_log(avctx, AV_LOG_DEBUG, "Quantisation: %u \n", data); > + } else if (tag == 109) { > + s->prescale_shift[0] = (data >> 0) & 0x7; > + s->prescale_shift[1] = (data >> 3) & 0x7; > + s->prescale_shift[2] = (data >> 6) & 0x7; > + av_log(avctx, AV_LOG_DEBUG, "Prescale shift (VC-5): %x \n", > data); > + } else if (tag == 27) { > + s->plane[s->channel_num].band[0][0].width = data; > + s->plane[s->channel_num].band[0][0].stride = data; > + av_log(avctx, AV_LOG_DEBUG, "Lowpass width %u \n", data); > + } else if (tag == 28) { > + s->plane[s->channel_num].band[0][0].height = data; > + av_log(avctx, AV_LOG_DEBUG, "Lowpass height %u \n", data); > + } else if (tag == 1) > + av_log(avctx, AV_LOG_DEBUG, "Sample type? %u \n", data); > + else if (tag == 10) { > + if (data != 0) { > + av_log(avctx, AV_LOG_ERROR, "Transform type of %u is > unsupported\n", data); > + ret = AVERROR_PATCHWELCOME; > + break; > + } > + av_log(avctx, AV_LOG_DEBUG, "Transform-type? %u \n", data); > + } > + else if (abstag >= 0x4000 && abstag <= 0x40ff) { > + av_log(avctx, AV_LOG_DEBUG, "Small chunk length %u %s \n", data > * 4, tag < 0 ? "optional" : "required"); > + cnt += data * 4; > + } else if (tag == 23) { > + av_log(avctx, AV_LOG_DEBUG, "Skip frame \n"); > + av_log(avctx, AV_LOG_ERROR, "Skip frame not supported \n"); > + ret = AVERROR_PATCHWELCOME; > + break; > + } else if (tag == 2) { > + av_log(avctx, AV_LOG_DEBUG, "tag=2 header - skipping %i > tag/value pairs \n", data); > + for (i = 0; i < data + 1; i++) { > + av_log(avctx, AV_LOG_DEBUG, "Tag/Value = %x %x \n", > AV_RB16(&bs[cnt]), AV_RB16(&bs[cnt + 2])); > + cnt += 4; > + } > + } else if (tag == 41) { > + s->plane[s->channel_num].band[s->level][s->subband_num].width = > data; > + s->plane[s->channel_num].band[s->level][s->subband_num].stride = > FFALIGN(data, 8); > + av_log(avctx, AV_LOG_DEBUG, "Highpass width %i channel %i level > %i subband %i \n", data, s->channel_num, s->level, s->subband_num); > + } else if (tag == 42) { > + s->plane[s->channel_num].band[s->level][s->subband_num].height = > data; > + av_log(avctx, AV_LOG_DEBUG, "Highpass height %i \n", data); > + } else if (tag == 49) { > + s->plane[s->channel_num].band[s->level][s->subband_num].width = > data; > + s->plane[s->channel_num].band[s->level][s->subband_num].stride = > FFALIGN(data, 8); > + av_log(avctx, AV_LOG_DEBUG, "Highpass width2 %i \n", data); > + } else if (tag == 50) { > + s->plane[s->channel_num].band[s->level][s->subband_num].height = > data; > + av_log(avctx, AV_LOG_DEBUG, "Highpass height2 %i \n", data); > + } else if (tag == 71) { > + s->codebook = data; > + av_log(avctx, AV_LOG_DEBUG, "Codebook %i \n", s->codebook); > + } else if (tag == 72) { > + s->codebook = data; > + av_log(avctx, AV_LOG_DEBUG, "Other codebook? %i \n", > s->codebook); > + } else > + av_log(avctx, AV_LOG_DEBUG, "Unknown tag %i data %x \n", tag, > data); > + cnt += 4; > + > + int16_t *coeff_data = subband[s->channel_num][s->subband_num_actual]; this produces: "warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]" > + > + /* Lowpass coefficients */ > + if (tag == 4 && data == 0xf0f) { > + int lowpass_height = s->plane[s->channel_num].band[0][0].height; > + int lowpass_width = s->plane[s->channel_num].band[0][0].width; > + uint16_t coeffs = 0; > + av_log(avctx, AV_LOG_DEBUG, "Start of lowpass coeffs component > %u \n", s->channel_num); > + for (i = 0; i < lowpass_height; i++) { > + for (j = 0; j < lowpass_width; j++) { > + coeff_data[j] = AV_RB16(&bs[cnt]); > + > + coeffs++; > + cnt += 2; > + } > + coeff_data += lowpass_width; > + } have the lowpass_height and lowpass_width been checked somewhere so this wont write ove the array end ? also the bs array could be too small causin a overread [...] > diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h > new file mode 100644 > index 0000000..1a5830e > --- /dev/null > +++ b/libavcodec/cfhd.h > @@ -0,0 +1,97 @@ > +/* > + * Copyright (c) 2015 Kieran Kunhya > + * > + * 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 "get_bits.h" > + > +#define VLC_BITS 9 > +#define NB_VLC_TABLE_9 (71+3) > +#define NB_VLC_TABLE_18 (263+1) > + > +typedef struct CFHD_RL_VLC_ELEM { > + int16_t level; > + int8_t len; > + uint16_t run; > +} CFHD_RL_VLC_ELEM; > + > +#define DWT_LEVELS 3 > + > +#define CALC_PADDING(size, depth) \ > + (((size + (1 << depth) - 1) >> depth) << depth) size ande depth should be protected by () so that when passing expressions the evaluation order works out [...] > +av_cold int ff_cfhd_init_vlcs(CFHDContext *s) > +{ > + int i, j; > + uint32_t new_cfhd_vlc_bits[NB_VLC_TABLE_18 * 2]; > + uint8_t new_cfhd_vlc_len[NB_VLC_TABLE_18 * 2]; > + uint16_t new_cfhd_vlc_run[NB_VLC_TABLE_18 * 2]; > + int16_t new_cfhd_vlc_level[NB_VLC_TABLE_18 * 2]; > + > + /** Similar to dv.c, generate signed VLC tables **/ > + > + /* Table 9 */ > + for (i = 0, j = 0; i < NB_VLC_TABLE_9; i++, j++) { > + new_cfhd_vlc_bits[j] = table_9_vlc_bits[i]; > + new_cfhd_vlc_len[j] = table_9_vlc_len[i]; > + new_cfhd_vlc_run[j] = table_9_vlc_run[i]; > + new_cfhd_vlc_level[j] = table_9_vlc_level[i]; > + > + /* Don't include the zero level nor escape bits */ > + if (table_9_vlc_level[i] && > + new_cfhd_vlc_bits[j] != table_9_vlc_bits[NB_VLC_TABLE_9-1]) { > + new_cfhd_vlc_bits[j] <<= 1; > + new_cfhd_vlc_len[j]++; > + j++; > + new_cfhd_vlc_bits[j] = (table_9_vlc_bits[i] << 1) | 1; > + new_cfhd_vlc_len[j] = table_9_vlc_len[i] + 1; > + new_cfhd_vlc_run[j] = table_9_vlc_run[i]; > + new_cfhd_vlc_level[j] = -table_9_vlc_level[i]; > + } > + } > + > + init_vlc(&s->vlc_9, VLC_BITS, j, new_cfhd_vlc_len, > + 1, 1, new_cfhd_vlc_bits, 4, 4, 0); > + for (i = 0; i < s->vlc_9.table_size; i++) { > + int code = s->vlc_9.table[i][0]; > + int len = s->vlc_9.table[i][1]; > + int level, run; > + > + if (len < 0) { // more bits needed > + run = 0; > + level = code; > + } else { > + run = new_cfhd_vlc_run[code]; > + level = new_cfhd_vlc_level[code]; > + } > + s->table_9_rl_vlc[i].len = len; > + s->table_9_rl_vlc[i].level = level; > + s->table_9_rl_vlc[i].run = run; > + } > + > + /* Table 18 */ > + for (i = 0, j = 0; i < NB_VLC_TABLE_18; i++, j++) { > + new_cfhd_vlc_bits[j] = table_18_vlc_bits[i]; > + new_cfhd_vlc_len[j] = table_18_vlc_len[i]; > + new_cfhd_vlc_run[j] = table_18_vlc_run[i]; > + new_cfhd_vlc_level[j] = table_18_vlc_level[i]; > + > + /* Don't include the zero level nor escape bits */ > + if (table_18_vlc_level[i] && > + new_cfhd_vlc_bits[j] != table_18_vlc_bits[NB_VLC_TABLE_18-1]) { > + new_cfhd_vlc_bits[j] <<= 1; > + new_cfhd_vlc_len[j]++; > + j++; > + new_cfhd_vlc_bits[j] = (table_18_vlc_bits[i] << 1) | 1; > + new_cfhd_vlc_len[j] = table_18_vlc_len[i] + 1; > + new_cfhd_vlc_run[j] = table_18_vlc_run[i]; > + new_cfhd_vlc_level[j] = -table_18_vlc_level[i]; > + } > + } > + > + init_vlc(&s->vlc_18, VLC_BITS, j, new_cfhd_vlc_len, > + 1, 1, new_cfhd_vlc_bits, 4, 4, 0); > + assert(s->vlc_18.table_size == 4572); should probably be some av_assert [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Avoid a single point of failure, be that a person or equipment.
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel