Message ID | 20190716121922.24390-1-onemda@gmail.com |
---|---|
State | Superseded |
Headers | show |
Paul B Mahol: > Signed-off-by: Paul B Mahol <onemda@gmail.com> > --- > configure | 1 + > libavcodec/Makefile | 1 + > libavcodec/allcodecs.c | 1 + > libavcodec/avcodec.h | 1 + > libavcodec/codec_desc.c | 7 ++ > libavcodec/imm5.c | 171 ++++++++++++++++++++++++++++++++++++++++ > libavformat/riff.c | 1 + > 7 files changed, 183 insertions(+) > create mode 100644 libavcodec/imm5.c > > diff --git a/configure b/configure > index 5a4f507246..d03cf43350 100755 > --- a/configure > +++ b/configure > @@ -2714,6 +2714,7 @@ huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" > hymt_decoder_select="huffyuv_decoder" > iac_decoder_select="imc_decoder" > imc_decoder_select="bswapdsp fft mdct sinewin" > +imm5_decoder_select="h264_decoder hevc_decoder" > indeo3_decoder_select="hpeldsp" > indeo4_decoder_select="ividsp" > indeo5_decoder_select="ividsp" > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index 3cd73fbcc6..39f4d9118c 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -393,6 +393,7 @@ OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o > OBJS-$(CONFIG_ILBC_DECODER) += ilbcdec.o > OBJS-$(CONFIG_IMC_DECODER) += imc.o > OBJS-$(CONFIG_IMM4_DECODER) += imm4.o > +OBJS-$(CONFIG_IMM5_DECODER) += imm5.o > OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o > OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o > OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c > index d2f9a39ce5..fe7f773925 100644 > --- a/libavcodec/allcodecs.c > +++ b/libavcodec/allcodecs.c > @@ -158,6 +158,7 @@ extern AVCodec ff_hymt_decoder; > extern AVCodec ff_idcin_decoder; > extern AVCodec ff_iff_ilbm_decoder; > extern AVCodec ff_imm4_decoder; > +extern AVCodec ff_imm5_decoder; > extern AVCodec ff_indeo2_decoder; > extern AVCodec ff_indeo3_decoder; > extern AVCodec ff_indeo4_decoder; > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > index 2528bd89ab..da6f92b443 100644 > --- a/libavcodec/avcodec.h > +++ b/libavcodec/avcodec.h > @@ -457,6 +457,7 @@ enum AVCodecID { > AV_CODEC_ID_AGM, > AV_CODEC_ID_LSCR, > AV_CODEC_ID_VP4, > + AV_CODEC_ID_IMM5, > > /* various PCM "codecs" */ > AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs > diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c > index 4d033c20ff..e6373be504 100644 > --- a/libavcodec/codec_desc.c > +++ b/libavcodec/codec_desc.c > @@ -1726,6 +1726,13 @@ static const AVCodecDescriptor codec_descriptors[] = { > .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), > .props = AV_CODEC_PROP_LOSSY, > }, > + { > + .id = AV_CODEC_ID_IMM5, > + .type = AVMEDIA_TYPE_VIDEO, > + .name = "imm5", > + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), > + .props = AV_CODEC_PROP_LOSSY, > + }, > > /* various PCM "codecs" */ > { > diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c > new file mode 100644 > index 0000000000..d1bac342d0 > --- /dev/null > +++ b/libavcodec/imm5.c > @@ -0,0 +1,171 @@ > +/* > + * Copyright (c) 2019 Paul B Mahol > + * > + * 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/intreadwrite.h" > + > +#include "avcodec.h" > +#include "internal.h" > + > +typedef struct IMM5Context { > + AVCodecContext *h264_avctx; // wrapper context for H264 > + AVCodecContext *hevc_avctx; // wrapper context for HEVC > +} IMM5Context; > + > +static const struct IMM5_unit { > + uint8_t bits[14]; > + uint8_t len; > +} IMM5_units[14] = { > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x0F, 0x88 }, 12 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x83, 0xE2 }, 12 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0xE8, 0x80 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x04, 0xA2 }, 12 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0x28, 0x80 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x80, 0x92, 0x20 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x0F, 0xC8 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x83, 0xF2 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0xEC, 0x80 }, 14 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x04, 0xB2 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0x2C, 0x80 }, 14 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x80, 0x93, 0x20 }, 14 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xDE, 0x3C, 0x80 }, 8 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x32, 0x28 }, 8 }, > +}; > + > +static av_cold int imm5_init(AVCodecContext *avctx) > +{ > + IMM5Context *ctx = avctx->priv_data; > + const AVCodec *codec; > + int ret; > + > + codec = avcodec_find_decoder(AV_CODEC_ID_H264); > + if (!codec) > + return AVERROR_BUG; > + ctx->h264_avctx = avcodec_alloc_context3(codec); > + if (!ctx->h264_avctx) > + return AVERROR(ENOMEM); > + ctx->h264_avctx->thread_count = 1; > + ctx->h264_avctx->flags = avctx->flags; > + ctx->h264_avctx->flags2 = avctx->flags2; > + ret = ff_codec_open2_recursive(ctx->h264_avctx, codec, NULL); > + if (ret < 0) > + return ret; > + > + codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); > + if (!codec) > + return AVERROR_BUG; > + ctx->hevc_avctx = avcodec_alloc_context3(codec); > + if (!ctx->hevc_avctx) > + return AVERROR(ENOMEM); > + ctx->hevc_avctx->thread_count = 1; > + ctx->hevc_avctx->flags = avctx->flags; > + ctx->hevc_avctx->flags2 = avctx->flags2; > + ret = ff_codec_open2_recursive(ctx->hevc_avctx, codec, NULL); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > +static int imm5_decode_frame(AVCodecContext *avctx, void *data, > + int *got_frame, AVPacket *avpkt) > +{ > + IMM5Context *ctx = avctx->priv_data; > + AVFrame *frame = data; > + AVCodecContext *codec_avctx = ctx->h264_avctx; > + int ret; > + > + if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + 4) + 24ULL <= avpkt->size) { > + int codec_type = avpkt->data[1]; > + int index = avpkt->data[10]; > + int new_size = AV_RL32(avpkt->data + 4); > + int offset, off; Nit: These variables are only used in the block below and could therefore be moved there. > + > + if (codec_type == 0xA) > + codec_avctx = ctx->hevc_avctx; > + > + if (index >= 1 && index <= 12) { > + ret = av_packet_make_writable(avpkt); Making the packet writable here will copy the whole buffer; if new_size is much smaller than avpkt->size (I don't know if this really happens), it will copy lots of unnecessary data. Move this call directly before memcpy to avoid this. > + if (ret < 0) > + return ret; > + > + index -= 1; > + off = offset = IMM5_units[index].len; > + if (codec_type == 2) { > + offset += IMM5_units[12].len; > + } else { > + offset += IMM5_units[13].len; > + } > + > + avpkt->data += 24 - offset; > + avpkt->size = new_size + offset; > + > + memcpy(avpkt->data, IMM5_units[index].bits, IMM5_units[index].len); > + if (codec_type == 2) { > + memcpy(avpkt->data + off, IMM5_units[12].bits, IMM5_units[12].len); > + } else { > + memcpy(avpkt->data + off, IMM5_units[13].bits, IMM5_units[13].len); > + } > + } else { > + avpkt->data += 24; > + avpkt->size -= 24; Is the new_size only valid if 1 <= index <= 12? I'm wondering whether the above should not really be avpkt->size = new_size; > + } > + } > + > + ret = avcodec_send_packet(codec_avctx, avpkt); > + if (ret < 0) { > + av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); > + return ret; > + } > + > + ret = avcodec_receive_frame(codec_avctx, frame); > + if (ret < 0) > + return ret; > + > + avctx->pix_fmt = codec_avctx->pix_fmt; > + avctx->width = codec_avctx->width; > + avctx->height = codec_avctx->height; > + > + *got_frame = 1; > + > + return avpkt->size; > +} > + > +static av_cold int imm5_close(AVCodecContext *avctx) > +{ > + IMM5Context *ctx = avctx->priv_data; > + > + avcodec_free_context(&ctx->h264_avctx); > + avcodec_free_context(&ctx->hevc_avctx); > + > + return 0; > +} > + > +AVCodec ff_imm5_decoder = { > + .name = "imm5", > + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), > + .type = AVMEDIA_TYPE_VIDEO, > + .id = AV_CODEC_ID_IMM5, > + .init = imm5_init, > + .decode = imm5_decode_frame, > + .close = imm5_close, > + .priv_data_size = sizeof(IMM5Context), > + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | > + FF_CODEC_CAP_INIT_CLEANUP, > +}; > diff --git a/libavformat/riff.c b/libavformat/riff.c > index e755ad8d5f..610974ebf0 100644 > --- a/libavformat/riff.c > +++ b/libavformat/riff.c > @@ -488,6 +488,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { > { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, > { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, > { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') }, > + { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') }, > { AV_CODEC_ID_NONE, 0 } > }; > >
On 7/16/2019 9:19 AM, Paul B Mahol wrote: > Signed-off-by: Paul B Mahol <onemda@gmail.com> > --- > configure | 1 + > libavcodec/Makefile | 1 + > libavcodec/allcodecs.c | 1 + > libavcodec/avcodec.h | 1 + > libavcodec/codec_desc.c | 7 ++ > libavcodec/imm5.c | 171 ++++++++++++++++++++++++++++++++++++++++ > libavformat/riff.c | 1 + > 7 files changed, 183 insertions(+) > create mode 100644 libavcodec/imm5.c > > diff --git a/configure b/configure > index 5a4f507246..d03cf43350 100755 > --- a/configure > +++ b/configure > @@ -2714,6 +2714,7 @@ huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" > hymt_decoder_select="huffyuv_decoder" > iac_decoder_select="imc_decoder" > imc_decoder_select="bswapdsp fft mdct sinewin" > +imm5_decoder_select="h264_decoder hevc_decoder" > indeo3_decoder_select="hpeldsp" > indeo4_decoder_select="ividsp" > indeo5_decoder_select="ividsp" > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index 3cd73fbcc6..39f4d9118c 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -393,6 +393,7 @@ OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o > OBJS-$(CONFIG_ILBC_DECODER) += ilbcdec.o > OBJS-$(CONFIG_IMC_DECODER) += imc.o > OBJS-$(CONFIG_IMM4_DECODER) += imm4.o > +OBJS-$(CONFIG_IMM5_DECODER) += imm5.o > OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o > OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o > OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c > index d2f9a39ce5..fe7f773925 100644 > --- a/libavcodec/allcodecs.c > +++ b/libavcodec/allcodecs.c > @@ -158,6 +158,7 @@ extern AVCodec ff_hymt_decoder; > extern AVCodec ff_idcin_decoder; > extern AVCodec ff_iff_ilbm_decoder; > extern AVCodec ff_imm4_decoder; > +extern AVCodec ff_imm5_decoder; > extern AVCodec ff_indeo2_decoder; > extern AVCodec ff_indeo3_decoder; > extern AVCodec ff_indeo4_decoder; > diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h > index 2528bd89ab..da6f92b443 100644 > --- a/libavcodec/avcodec.h > +++ b/libavcodec/avcodec.h > @@ -457,6 +457,7 @@ enum AVCodecID { > AV_CODEC_ID_AGM, > AV_CODEC_ID_LSCR, > AV_CODEC_ID_VP4, > + AV_CODEC_ID_IMM5, > > /* various PCM "codecs" */ > AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs > diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c > index 4d033c20ff..e6373be504 100644 > --- a/libavcodec/codec_desc.c > +++ b/libavcodec/codec_desc.c > @@ -1726,6 +1726,13 @@ static const AVCodecDescriptor codec_descriptors[] = { > .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), > .props = AV_CODEC_PROP_LOSSY, > }, > + { > + .id = AV_CODEC_ID_IMM5, > + .type = AVMEDIA_TYPE_VIDEO, > + .name = "imm5", > + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), > + .props = AV_CODEC_PROP_LOSSY, > + }, > > /* various PCM "codecs" */ > { > diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c > new file mode 100644 > index 0000000000..d1bac342d0 > --- /dev/null > +++ b/libavcodec/imm5.c > @@ -0,0 +1,171 @@ > +/* > + * Copyright (c) 2019 Paul B Mahol > + * > + * 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/intreadwrite.h" > + > +#include "avcodec.h" > +#include "internal.h" > + > +typedef struct IMM5Context { > + AVCodecContext *h264_avctx; // wrapper context for H264 > + AVCodecContext *hevc_avctx; // wrapper context for HEVC > +} IMM5Context; > + > +static const struct IMM5_unit { > + uint8_t bits[14]; > + uint8_t len; > +} IMM5_units[14] = { > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x0F, 0x88 }, 12 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x83, 0xE2 }, 12 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0xE8, 0x80 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x04, 0xA2 }, 12 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0x28, 0x80 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x80, 0x92, 0x20 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x0F, 0xC8 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x83, 0xF2 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0xEC, 0x80 }, 14 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x04, 0xB2 }, 13 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0x2C, 0x80 }, 14 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x80, 0x93, 0x20 }, 14 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xDE, 0x3C, 0x80 }, 8 }, > + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x32, 0x28 }, 8 }, > +}; > + > +static av_cold int imm5_init(AVCodecContext *avctx) > +{ > + IMM5Context *ctx = avctx->priv_data; > + const AVCodec *codec; > + int ret; > + > + codec = avcodec_find_decoder(AV_CODEC_ID_H264); > + if (!codec) > + return AVERROR_BUG; > + ctx->h264_avctx = avcodec_alloc_context3(codec); > + if (!ctx->h264_avctx) > + return AVERROR(ENOMEM); > + ctx->h264_avctx->thread_count = 1; > + ctx->h264_avctx->flags = avctx->flags; > + ctx->h264_avctx->flags2 = avctx->flags2; > + ret = ff_codec_open2_recursive(ctx->h264_avctx, codec, NULL); > + if (ret < 0) > + return ret; > + > + codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); > + if (!codec) > + return AVERROR_BUG; > + ctx->hevc_avctx = avcodec_alloc_context3(codec); > + if (!ctx->hevc_avctx) > + return AVERROR(ENOMEM); > + ctx->hevc_avctx->thread_count = 1; > + ctx->hevc_avctx->flags = avctx->flags; > + ctx->hevc_avctx->flags2 = avctx->flags2; > + ret = ff_codec_open2_recursive(ctx->hevc_avctx, codec, NULL); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > +static int imm5_decode_frame(AVCodecContext *avctx, void *data, > + int *got_frame, AVPacket *avpkt) > +{ > + IMM5Context *ctx = avctx->priv_data; > + AVFrame *frame = data; > + AVCodecContext *codec_avctx = ctx->h264_avctx; > + int ret; > + > + if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + 4) + 24ULL <= avpkt->size) { > + int codec_type = avpkt->data[1]; > + int index = avpkt->data[10]; > + int new_size = AV_RL32(avpkt->data + 4); > + int offset, off; > + > + if (codec_type == 0xA) > + codec_avctx = ctx->hevc_avctx; > + > + if (index >= 1 && index <= 12) { > + ret = av_packet_make_writable(avpkt); > + if (ret < 0) > + return ret; > + > + index -= 1; > + off = offset = IMM5_units[index].len; > + if (codec_type == 2) { > + offset += IMM5_units[12].len; > + } else { > + offset += IMM5_units[13].len; > + } > + > + avpkt->data += 24 - offset; > + avpkt->size = new_size + offset; > + > + memcpy(avpkt->data, IMM5_units[index].bits, IMM5_units[index].len); > + if (codec_type == 2) { > + memcpy(avpkt->data + off, IMM5_units[12].bits, IMM5_units[12].len); > + } else { > + memcpy(avpkt->data + off, IMM5_units[13].bits, IMM5_units[13].len); > + } > + } else { > + avpkt->data += 24; > + avpkt->size -= 24; > + } > + } > + > + ret = avcodec_send_packet(codec_avctx, avpkt); > + if (ret < 0) { > + av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); > + return ret; > + } > + > + ret = avcodec_receive_frame(codec_avctx, frame); > + if (ret < 0) > + return ret; avcodec_receive_frame() can return EAGAIN when the packet was consumed and there was no output, but you're using it within a decode2 API based decoder, which in that scenario must return avpkt->size with got_frame == 0. Both h264 and hevc set AV_CODEC_CAP_DELAY, but by setting threads to 1 you may be effectively forcing a 1:1 input/output scenario. Did you make sure no frames are lost at the end when decoding your samples, and that this function isn't returning EAGAIN at any point? > + > + avctx->pix_fmt = codec_avctx->pix_fmt; > + avctx->width = codec_avctx->width; > + avctx->height = codec_avctx->height; coded_width/height as well. Or just use ff_set_dimensions(). And what about other fields like sample_aspect_ratio, bit_rate, color information? > + > + *got_frame = 1; > + > + return avpkt->size; > +} > + > +static av_cold int imm5_close(AVCodecContext *avctx) > +{ > + IMM5Context *ctx = avctx->priv_data; > + > + avcodec_free_context(&ctx->h264_avctx); > + avcodec_free_context(&ctx->hevc_avctx); > + > + return 0; > +} > + > +AVCodec ff_imm5_decoder = { > + .name = "imm5", > + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), > + .type = AVMEDIA_TYPE_VIDEO, > + .id = AV_CODEC_ID_IMM5, > + .init = imm5_init, > + .decode = imm5_decode_frame, > + .close = imm5_close, Missing a flush callback. > + .priv_data_size = sizeof(IMM5Context), > + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | > + FF_CODEC_CAP_INIT_CLEANUP, You could set DR1, and set both h264_avctx->get_buffer2 and hevc_avctx->get_buffer2 to avctx->get_buffer2, i think. > +}; > diff --git a/libavformat/riff.c b/libavformat/riff.c > index e755ad8d5f..610974ebf0 100644 > --- a/libavformat/riff.c > +++ b/libavformat/riff.c > @@ -488,6 +488,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { > { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, > { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, > { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') }, > + { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') }, > { AV_CODEC_ID_NONE, 0 } > }; > >
On Tue, Jul 16, 2019 at 3:26 PM James Almer <jamrial@gmail.com> wrote: > > > + .priv_data_size = sizeof(IMM5Context), > > + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | > > + FF_CODEC_CAP_INIT_CLEANUP, > > You could set DR1, and set both h264_avctx->get_buffer2 and > hevc_avctx->get_buffer2 to avctx->get_buffer2, i think. > Not sure thats safe, since the caller would then get called on the internal avctx, which might be rather unexpected. If you really wanted to offer get_buffer2, there would probably need to be a dummy call in between that takes it from the internal avctx and then re-calls get_buffer2 on the public avctx. - Hendrik
On 7/16/19, James Almer <jamrial@gmail.com> wrote: > On 7/16/2019 9:19 AM, Paul B Mahol wrote: >> Signed-off-by: Paul B Mahol <onemda@gmail.com> >> --- >> configure | 1 + >> libavcodec/Makefile | 1 + >> libavcodec/allcodecs.c | 1 + >> libavcodec/avcodec.h | 1 + >> libavcodec/codec_desc.c | 7 ++ >> libavcodec/imm5.c | 171 ++++++++++++++++++++++++++++++++++++++++ >> libavformat/riff.c | 1 + >> 7 files changed, 183 insertions(+) >> create mode 100644 libavcodec/imm5.c >> >> diff --git a/configure b/configure >> index 5a4f507246..d03cf43350 100755 >> --- a/configure >> +++ b/configure >> @@ -2714,6 +2714,7 @@ huffyuv_encoder_select="bswapdsp huffman >> huffyuvencdsp llvidencdsp" >> hymt_decoder_select="huffyuv_decoder" >> iac_decoder_select="imc_decoder" >> imc_decoder_select="bswapdsp fft mdct sinewin" >> +imm5_decoder_select="h264_decoder hevc_decoder" >> indeo3_decoder_select="hpeldsp" >> indeo4_decoder_select="ividsp" >> indeo5_decoder_select="ividsp" >> diff --git a/libavcodec/Makefile b/libavcodec/Makefile >> index 3cd73fbcc6..39f4d9118c 100644 >> --- a/libavcodec/Makefile >> +++ b/libavcodec/Makefile >> @@ -393,6 +393,7 @@ OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o >> OBJS-$(CONFIG_ILBC_DECODER) += ilbcdec.o >> OBJS-$(CONFIG_IMC_DECODER) += imc.o >> OBJS-$(CONFIG_IMM4_DECODER) += imm4.o >> +OBJS-$(CONFIG_IMM5_DECODER) += imm5.o >> OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o >> OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o >> OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o >> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c >> index d2f9a39ce5..fe7f773925 100644 >> --- a/libavcodec/allcodecs.c >> +++ b/libavcodec/allcodecs.c >> @@ -158,6 +158,7 @@ extern AVCodec ff_hymt_decoder; >> extern AVCodec ff_idcin_decoder; >> extern AVCodec ff_iff_ilbm_decoder; >> extern AVCodec ff_imm4_decoder; >> +extern AVCodec ff_imm5_decoder; >> extern AVCodec ff_indeo2_decoder; >> extern AVCodec ff_indeo3_decoder; >> extern AVCodec ff_indeo4_decoder; >> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h >> index 2528bd89ab..da6f92b443 100644 >> --- a/libavcodec/avcodec.h >> +++ b/libavcodec/avcodec.h >> @@ -457,6 +457,7 @@ enum AVCodecID { >> AV_CODEC_ID_AGM, >> AV_CODEC_ID_LSCR, >> AV_CODEC_ID_VP4, >> + AV_CODEC_ID_IMM5, >> >> /* various PCM "codecs" */ >> AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at >> the start of audio codecs >> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c >> index 4d033c20ff..e6373be504 100644 >> --- a/libavcodec/codec_desc.c >> +++ b/libavcodec/codec_desc.c >> @@ -1726,6 +1726,13 @@ static const AVCodecDescriptor codec_descriptors[] >> = { >> .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), >> .props = AV_CODEC_PROP_LOSSY, >> }, >> + { >> + .id = AV_CODEC_ID_IMM5, >> + .type = AVMEDIA_TYPE_VIDEO, >> + .name = "imm5", >> + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), >> + .props = AV_CODEC_PROP_LOSSY, >> + }, >> >> /* various PCM "codecs" */ >> { >> diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c >> new file mode 100644 >> index 0000000000..d1bac342d0 >> --- /dev/null >> +++ b/libavcodec/imm5.c >> @@ -0,0 +1,171 @@ >> +/* >> + * Copyright (c) 2019 Paul B Mahol >> + * >> + * 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/intreadwrite.h" >> + >> +#include "avcodec.h" >> +#include "internal.h" >> + >> +typedef struct IMM5Context { >> + AVCodecContext *h264_avctx; // wrapper context for H264 >> + AVCodecContext *hevc_avctx; // wrapper context for HEVC >> +} IMM5Context; >> + >> +static const struct IMM5_unit { >> + uint8_t bits[14]; >> + uint8_t len; >> +} IMM5_units[14] = { >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x0F, >> 0x88 }, 12 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x83, >> 0xE2 }, 12 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, >> 0xE8, 0x80 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x04, >> 0xA2 }, 12 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, >> 0x28, 0x80 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x80, >> 0x92, 0x20 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, >> 0x0F, 0xC8 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x83, 0xF2 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x81, 0xEC, 0x80 }, 14 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, >> 0x04, 0xB2 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x81, 0x2C, 0x80 }, 14 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x80, 0x93, 0x20 }, 14 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xDE, 0x3C, 0x80 }, 8 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x32, 0x28 }, 8 }, >> +}; >> + >> +static av_cold int imm5_init(AVCodecContext *avctx) >> +{ >> + IMM5Context *ctx = avctx->priv_data; >> + const AVCodec *codec; >> + int ret; >> + >> + codec = avcodec_find_decoder(AV_CODEC_ID_H264); >> + if (!codec) >> + return AVERROR_BUG; >> + ctx->h264_avctx = avcodec_alloc_context3(codec); >> + if (!ctx->h264_avctx) >> + return AVERROR(ENOMEM); >> + ctx->h264_avctx->thread_count = 1; >> + ctx->h264_avctx->flags = avctx->flags; >> + ctx->h264_avctx->flags2 = avctx->flags2; >> + ret = ff_codec_open2_recursive(ctx->h264_avctx, codec, NULL); >> + if (ret < 0) >> + return ret; >> + >> + codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); >> + if (!codec) >> + return AVERROR_BUG; >> + ctx->hevc_avctx = avcodec_alloc_context3(codec); >> + if (!ctx->hevc_avctx) >> + return AVERROR(ENOMEM); >> + ctx->hevc_avctx->thread_count = 1; >> + ctx->hevc_avctx->flags = avctx->flags; >> + ctx->hevc_avctx->flags2 = avctx->flags2; >> + ret = ff_codec_open2_recursive(ctx->hevc_avctx, codec, NULL); >> + if (ret < 0) >> + return ret; >> + >> + return 0; >> +} >> + >> +static int imm5_decode_frame(AVCodecContext *avctx, void *data, >> + int *got_frame, AVPacket *avpkt) >> +{ >> + IMM5Context *ctx = avctx->priv_data; >> + AVFrame *frame = data; >> + AVCodecContext *codec_avctx = ctx->h264_avctx; >> + int ret; >> + >> + if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + >> 4) + 24ULL <= avpkt->size) { >> + int codec_type = avpkt->data[1]; >> + int index = avpkt->data[10]; >> + int new_size = AV_RL32(avpkt->data + 4); >> + int offset, off; >> + >> + if (codec_type == 0xA) >> + codec_avctx = ctx->hevc_avctx; >> + >> + if (index >= 1 && index <= 12) { >> + ret = av_packet_make_writable(avpkt); >> + if (ret < 0) >> + return ret; >> + >> + index -= 1; >> + off = offset = IMM5_units[index].len; >> + if (codec_type == 2) { >> + offset += IMM5_units[12].len; >> + } else { >> + offset += IMM5_units[13].len; >> + } >> + >> + avpkt->data += 24 - offset; >> + avpkt->size = new_size + offset; >> + >> + memcpy(avpkt->data, IMM5_units[index].bits, >> IMM5_units[index].len); >> + if (codec_type == 2) { >> + memcpy(avpkt->data + off, IMM5_units[12].bits, >> IMM5_units[12].len); >> + } else { >> + memcpy(avpkt->data + off, IMM5_units[13].bits, >> IMM5_units[13].len); >> + } >> + } else { >> + avpkt->data += 24; >> + avpkt->size -= 24; >> + } >> + } >> + >> + ret = avcodec_send_packet(codec_avctx, avpkt); >> + if (ret < 0) { >> + av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for >> decoding\n"); >> + return ret; >> + } >> + >> + ret = avcodec_receive_frame(codec_avctx, frame); >> + if (ret < 0) >> + return ret; > > avcodec_receive_frame() can return EAGAIN when the packet was consumed > and there was no output, but you're using it within a decode2 API based > decoder, which in that scenario must return avpkt->size with got_frame == 0. > > Both h264 and hevc set AV_CODEC_CAP_DELAY, but by setting threads to 1 > you may be effectively forcing a 1:1 input/output scenario. Did you make > sure no frames are lost at the end when decoding your samples, and that > this function isn't returning EAGAIN at any point? It does not return EAGAIN for any sample that I have. > >> + >> + avctx->pix_fmt = codec_avctx->pix_fmt; >> + avctx->width = codec_avctx->width; >> + avctx->height = codec_avctx->height; > > coded_width/height as well. Or just use ff_set_dimensions(). > > And what about other fields like sample_aspect_ratio, bit_rate, color > information? All relevant stuff should be in AVFrame itself. I will add more of missing stuff you mentioned. > >> + >> + *got_frame = 1; >> + >> + return avpkt->size; >> +} >> + >> +static av_cold int imm5_close(AVCodecContext *avctx) >> +{ >> + IMM5Context *ctx = avctx->priv_data; >> + >> + avcodec_free_context(&ctx->h264_avctx); >> + avcodec_free_context(&ctx->hevc_avctx); >> + >> + return 0; >> +} >> + >> +AVCodec ff_imm5_decoder = { >> + .name = "imm5", >> + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), >> + .type = AVMEDIA_TYPE_VIDEO, >> + .id = AV_CODEC_ID_IMM5, >> + .init = imm5_init, >> + .decode = imm5_decode_frame, >> + .close = imm5_close, > > Missing a flush callback. And what would it do? > >> + .priv_data_size = sizeof(IMM5Context), >> + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | >> + FF_CODEC_CAP_INIT_CLEANUP, > > You could set DR1, and set both h264_avctx->get_buffer2 and > hevc_avctx->get_buffer2 to avctx->get_buffer2, i think. > Will try. > > >> +}; >> diff --git a/libavformat/riff.c b/libavformat/riff.c >> index e755ad8d5f..610974ebf0 100644 >> --- a/libavformat/riff.c >> +++ b/libavformat/riff.c >> @@ -488,6 +488,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { >> { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, >> { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, >> { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') }, >> + { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') }, >> { AV_CODEC_ID_NONE, 0 } >> }; >> >> > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
On 7/16/19, Andreas Rheinhardt <andreas.rheinhardt@gmail.com> wrote: > Paul B Mahol: >> Signed-off-by: Paul B Mahol <onemda@gmail.com> >> --- >> configure | 1 + >> libavcodec/Makefile | 1 + >> libavcodec/allcodecs.c | 1 + >> libavcodec/avcodec.h | 1 + >> libavcodec/codec_desc.c | 7 ++ >> libavcodec/imm5.c | 171 ++++++++++++++++++++++++++++++++++++++++ >> libavformat/riff.c | 1 + >> 7 files changed, 183 insertions(+) >> create mode 100644 libavcodec/imm5.c >> >> diff --git a/configure b/configure >> index 5a4f507246..d03cf43350 100755 >> --- a/configure >> +++ b/configure >> @@ -2714,6 +2714,7 @@ huffyuv_encoder_select="bswapdsp huffman >> huffyuvencdsp llvidencdsp" >> hymt_decoder_select="huffyuv_decoder" >> iac_decoder_select="imc_decoder" >> imc_decoder_select="bswapdsp fft mdct sinewin" >> +imm5_decoder_select="h264_decoder hevc_decoder" >> indeo3_decoder_select="hpeldsp" >> indeo4_decoder_select="ividsp" >> indeo5_decoder_select="ividsp" >> diff --git a/libavcodec/Makefile b/libavcodec/Makefile >> index 3cd73fbcc6..39f4d9118c 100644 >> --- a/libavcodec/Makefile >> +++ b/libavcodec/Makefile >> @@ -393,6 +393,7 @@ OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o >> OBJS-$(CONFIG_ILBC_DECODER) += ilbcdec.o >> OBJS-$(CONFIG_IMC_DECODER) += imc.o >> OBJS-$(CONFIG_IMM4_DECODER) += imm4.o >> +OBJS-$(CONFIG_IMM5_DECODER) += imm5.o >> OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o >> OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o >> OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o >> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c >> index d2f9a39ce5..fe7f773925 100644 >> --- a/libavcodec/allcodecs.c >> +++ b/libavcodec/allcodecs.c >> @@ -158,6 +158,7 @@ extern AVCodec ff_hymt_decoder; >> extern AVCodec ff_idcin_decoder; >> extern AVCodec ff_iff_ilbm_decoder; >> extern AVCodec ff_imm4_decoder; >> +extern AVCodec ff_imm5_decoder; >> extern AVCodec ff_indeo2_decoder; >> extern AVCodec ff_indeo3_decoder; >> extern AVCodec ff_indeo4_decoder; >> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h >> index 2528bd89ab..da6f92b443 100644 >> --- a/libavcodec/avcodec.h >> +++ b/libavcodec/avcodec.h >> @@ -457,6 +457,7 @@ enum AVCodecID { >> AV_CODEC_ID_AGM, >> AV_CODEC_ID_LSCR, >> AV_CODEC_ID_VP4, >> + AV_CODEC_ID_IMM5, >> >> /* various PCM "codecs" */ >> AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at >> the start of audio codecs >> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c >> index 4d033c20ff..e6373be504 100644 >> --- a/libavcodec/codec_desc.c >> +++ b/libavcodec/codec_desc.c >> @@ -1726,6 +1726,13 @@ static const AVCodecDescriptor codec_descriptors[] >> = { >> .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), >> .props = AV_CODEC_PROP_LOSSY, >> }, >> + { >> + .id = AV_CODEC_ID_IMM5, >> + .type = AVMEDIA_TYPE_VIDEO, >> + .name = "imm5", >> + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), >> + .props = AV_CODEC_PROP_LOSSY, >> + }, >> >> /* various PCM "codecs" */ >> { >> diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c >> new file mode 100644 >> index 0000000000..d1bac342d0 >> --- /dev/null >> +++ b/libavcodec/imm5.c >> @@ -0,0 +1,171 @@ >> +/* >> + * Copyright (c) 2019 Paul B Mahol >> + * >> + * 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/intreadwrite.h" >> + >> +#include "avcodec.h" >> +#include "internal.h" >> + >> +typedef struct IMM5Context { >> + AVCodecContext *h264_avctx; // wrapper context for H264 >> + AVCodecContext *hevc_avctx; // wrapper context for HEVC >> +} IMM5Context; >> + >> +static const struct IMM5_unit { >> + uint8_t bits[14]; >> + uint8_t len; >> +} IMM5_units[14] = { >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x0F, >> 0x88 }, 12 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x83, >> 0xE2 }, 12 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, >> 0xE8, 0x80 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x04, >> 0xA2 }, 12 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, >> 0x28, 0x80 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x80, >> 0x92, 0x20 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, >> 0x0F, 0xC8 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x83, 0xF2 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x81, 0xEC, 0x80 }, 14 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, >> 0x04, 0xB2 }, 13 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x81, 0x2C, 0x80 }, 14 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, >> 0x80, 0x93, 0x20 }, 14 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xDE, 0x3C, 0x80 }, 8 }, >> + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x32, 0x28 }, 8 }, >> +}; >> + >> +static av_cold int imm5_init(AVCodecContext *avctx) >> +{ >> + IMM5Context *ctx = avctx->priv_data; >> + const AVCodec *codec; >> + int ret; >> + >> + codec = avcodec_find_decoder(AV_CODEC_ID_H264); >> + if (!codec) >> + return AVERROR_BUG; >> + ctx->h264_avctx = avcodec_alloc_context3(codec); >> + if (!ctx->h264_avctx) >> + return AVERROR(ENOMEM); >> + ctx->h264_avctx->thread_count = 1; >> + ctx->h264_avctx->flags = avctx->flags; >> + ctx->h264_avctx->flags2 = avctx->flags2; >> + ret = ff_codec_open2_recursive(ctx->h264_avctx, codec, NULL); >> + if (ret < 0) >> + return ret; >> + >> + codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); >> + if (!codec) >> + return AVERROR_BUG; >> + ctx->hevc_avctx = avcodec_alloc_context3(codec); >> + if (!ctx->hevc_avctx) >> + return AVERROR(ENOMEM); >> + ctx->hevc_avctx->thread_count = 1; >> + ctx->hevc_avctx->flags = avctx->flags; >> + ctx->hevc_avctx->flags2 = avctx->flags2; >> + ret = ff_codec_open2_recursive(ctx->hevc_avctx, codec, NULL); >> + if (ret < 0) >> + return ret; >> + >> + return 0; >> +} >> + >> +static int imm5_decode_frame(AVCodecContext *avctx, void *data, >> + int *got_frame, AVPacket *avpkt) >> +{ >> + IMM5Context *ctx = avctx->priv_data; >> + AVFrame *frame = data; >> + AVCodecContext *codec_avctx = ctx->h264_avctx; >> + int ret; >> + >> + if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + >> 4) + 24ULL <= avpkt->size) { >> + int codec_type = avpkt->data[1]; >> + int index = avpkt->data[10]; >> + int new_size = AV_RL32(avpkt->data + 4); >> + int offset, off; > Nit: These variables are only used in the block below and could > therefore be moved there. >> + >> + if (codec_type == 0xA) >> + codec_avctx = ctx->hevc_avctx; >> + >> + if (index >= 1 && index <= 12) { >> + ret = av_packet_make_writable(avpkt); > Making the packet writable here will copy the whole buffer; if > new_size is much smaller than avpkt->size (I don't know if this really > happens), it will copy lots of unnecessary data. Move this call > directly before memcpy to avoid this. Not needed. New size is always by 24 less than packet size. >> + if (ret < 0) >> + return ret; >> + >> + index -= 1; >> + off = offset = IMM5_units[index].len; >> + if (codec_type == 2) { >> + offset += IMM5_units[12].len; >> + } else { >> + offset += IMM5_units[13].len; >> + } >> + >> + avpkt->data += 24 - offset; >> + avpkt->size = new_size + offset; >> + >> + memcpy(avpkt->data, IMM5_units[index].bits, >> IMM5_units[index].len); >> + if (codec_type == 2) { >> + memcpy(avpkt->data + off, IMM5_units[12].bits, >> IMM5_units[12].len); >> + } else { >> + memcpy(avpkt->data + off, IMM5_units[13].bits, >> IMM5_units[13].len); >> + } >> + } else { >> + avpkt->data += 24; >> + avpkt->size -= 24; > Is the new_size only valid if 1 <= index <= 12? I'm wondering whether > the above should not really be avpkt->size = new_size; It could be, but it does not make a difference. >> + } >> + } >> + >> + ret = avcodec_send_packet(codec_avctx, avpkt); >> + if (ret < 0) { >> + av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for >> decoding\n"); >> + return ret; >> + } >> + >> + ret = avcodec_receive_frame(codec_avctx, frame); >> + if (ret < 0) >> + return ret; >> + >> + avctx->pix_fmt = codec_avctx->pix_fmt; >> + avctx->width = codec_avctx->width; >> + avctx->height = codec_avctx->height; >> + >> + *got_frame = 1; >> + >> + return avpkt->size; >> +} >> + >> +static av_cold int imm5_close(AVCodecContext *avctx) >> +{ >> + IMM5Context *ctx = avctx->priv_data; >> + >> + avcodec_free_context(&ctx->h264_avctx); >> + avcodec_free_context(&ctx->hevc_avctx); >> + >> + return 0; >> +} >> + >> +AVCodec ff_imm5_decoder = { >> + .name = "imm5", >> + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), >> + .type = AVMEDIA_TYPE_VIDEO, >> + .id = AV_CODEC_ID_IMM5, >> + .init = imm5_init, >> + .decode = imm5_decode_frame, >> + .close = imm5_close, >> + .priv_data_size = sizeof(IMM5Context), >> + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | >> + FF_CODEC_CAP_INIT_CLEANUP, >> +}; >> diff --git a/libavformat/riff.c b/libavformat/riff.c >> index e755ad8d5f..610974ebf0 100644 >> --- a/libavformat/riff.c >> +++ b/libavformat/riff.c >> @@ -488,6 +488,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { >> { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, >> { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, >> { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') }, >> + { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') }, >> { AV_CODEC_ID_NONE, 0 } >> }; >> >> > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
On 7/16/2019 10:42 AM, Paul B Mahol wrote: > On 7/16/19, James Almer <jamrial@gmail.com> wrote: >> On 7/16/2019 9:19 AM, Paul B Mahol wrote: >>> + ret = avcodec_receive_frame(codec_avctx, frame); >>> + if (ret < 0) >>> + return ret; >> >> avcodec_receive_frame() can return EAGAIN when the packet was consumed >> and there was no output, but you're using it within a decode2 API based >> decoder, which in that scenario must return avpkt->size with got_frame == 0. >> >> Both h264 and hevc set AV_CODEC_CAP_DELAY, but by setting threads to 1 >> you may be effectively forcing a 1:1 input/output scenario. Did you make >> sure no frames are lost at the end when decoding your samples, and that >> this function isn't returning EAGAIN at any point? > > It does not return EAGAIN for any sample that I have. Ok, good, so by keeping threads to 1 it should be safe. > >> >>> + >>> + avctx->pix_fmt = codec_avctx->pix_fmt; >>> + avctx->width = codec_avctx->width; >>> + avctx->height = codec_avctx->height; >> >> coded_width/height as well. Or just use ff_set_dimensions(). >> >> And what about other fields like sample_aspect_ratio, bit_rate, color >> information? > > All relevant stuff should be in AVFrame itself. > I will add more of missing stuff you mentioned. > >> >>> + >>> + *got_frame = 1; >>> + >>> + return avpkt->size; >>> +} >>> + >>> +static av_cold int imm5_close(AVCodecContext *avctx) >>> +{ >>> + IMM5Context *ctx = avctx->priv_data; >>> + >>> + avcodec_free_context(&ctx->h264_avctx); >>> + avcodec_free_context(&ctx->hevc_avctx); >>> + >>> + return 0; >>> +} >>> + >>> +AVCodec ff_imm5_decoder = { >>> + .name = "imm5", >>> + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), >>> + .type = AVMEDIA_TYPE_VIDEO, >>> + .id = AV_CODEC_ID_IMM5, >>> + .init = imm5_init, >>> + .decode = imm5_decode_frame, >>> + .close = imm5_close, >> >> Missing a flush callback. > > And what would it do? Call avcodec_flush_buffers() on both h264 and hevc contexts. > >> >>> + .priv_data_size = sizeof(IMM5Context), >>> + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | >>> + FF_CODEC_CAP_INIT_CLEANUP, >> >> You could set DR1, and set both h264_avctx->get_buffer2 and >> hevc_avctx->get_buffer2 to avctx->get_buffer2, i think. >> > > Will try. > > >> >> >>> +}; >>> diff --git a/libavformat/riff.c b/libavformat/riff.c >>> index e755ad8d5f..610974ebf0 100644 >>> --- a/libavformat/riff.c >>> +++ b/libavformat/riff.c >>> @@ -488,6 +488,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { >>> { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, >>> { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, >>> { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') }, >>> + { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') }, >>> { AV_CODEC_ID_NONE, 0 } >>> }; >>> >>> >> _______________________________________________ >> ffmpeg-devel mailing list >> ffmpeg-devel@ffmpeg.org >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> >> To unsubscribe, visit link above, or email >> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". >
diff --git a/configure b/configure index 5a4f507246..d03cf43350 100755 --- a/configure +++ b/configure @@ -2714,6 +2714,7 @@ huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" hymt_decoder_select="huffyuv_decoder" iac_decoder_select="imc_decoder" imc_decoder_select="bswapdsp fft mdct sinewin" +imm5_decoder_select="h264_decoder hevc_decoder" indeo3_decoder_select="hpeldsp" indeo4_decoder_select="ividsp" indeo5_decoder_select="ividsp" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 3cd73fbcc6..39f4d9118c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -393,6 +393,7 @@ OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o OBJS-$(CONFIG_ILBC_DECODER) += ilbcdec.o OBJS-$(CONFIG_IMC_DECODER) += imc.o OBJS-$(CONFIG_IMM4_DECODER) += imm4.o +OBJS-$(CONFIG_IMM5_DECODER) += imm5.o OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index d2f9a39ce5..fe7f773925 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -158,6 +158,7 @@ extern AVCodec ff_hymt_decoder; extern AVCodec ff_idcin_decoder; extern AVCodec ff_iff_ilbm_decoder; extern AVCodec ff_imm4_decoder; +extern AVCodec ff_imm5_decoder; extern AVCodec ff_indeo2_decoder; extern AVCodec ff_indeo3_decoder; extern AVCodec ff_indeo4_decoder; diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 2528bd89ab..da6f92b443 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -457,6 +457,7 @@ enum AVCodecID { AV_CODEC_ID_AGM, AV_CODEC_ID_LSCR, AV_CODEC_ID_VP4, + AV_CODEC_ID_IMM5, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 4d033c20ff..e6373be504 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1726,6 +1726,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_IMM5, + .type = AVMEDIA_TYPE_VIDEO, + .name = "imm5", + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), + .props = AV_CODEC_PROP_LOSSY, + }, /* various PCM "codecs" */ { diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c new file mode 100644 index 0000000000..d1bac342d0 --- /dev/null +++ b/libavcodec/imm5.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * 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/intreadwrite.h" + +#include "avcodec.h" +#include "internal.h" + +typedef struct IMM5Context { + AVCodecContext *h264_avctx; // wrapper context for H264 + AVCodecContext *hevc_avctx; // wrapper context for HEVC +} IMM5Context; + +static const struct IMM5_unit { + uint8_t bits[14]; + uint8_t len; +} IMM5_units[14] = { + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x0F, 0x88 }, 12 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x83, 0xE2 }, 12 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0xE8, 0x80 }, 13 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x04, 0xA2 }, 12 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0x28, 0x80 }, 13 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x80, 0x92, 0x20 }, 13 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x0F, 0xC8 }, 13 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x83, 0xF2 }, 13 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0xEC, 0x80 }, 14 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x04, 0xB2 }, 13 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0x2C, 0x80 }, 14 }, + { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x80, 0x93, 0x20 }, 14 }, + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xDE, 0x3C, 0x80 }, 8 }, + { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x32, 0x28 }, 8 }, +}; + +static av_cold int imm5_init(AVCodecContext *avctx) +{ + IMM5Context *ctx = avctx->priv_data; + const AVCodec *codec; + int ret; + + codec = avcodec_find_decoder(AV_CODEC_ID_H264); + if (!codec) + return AVERROR_BUG; + ctx->h264_avctx = avcodec_alloc_context3(codec); + if (!ctx->h264_avctx) + return AVERROR(ENOMEM); + ctx->h264_avctx->thread_count = 1; + ctx->h264_avctx->flags = avctx->flags; + ctx->h264_avctx->flags2 = avctx->flags2; + ret = ff_codec_open2_recursive(ctx->h264_avctx, codec, NULL); + if (ret < 0) + return ret; + + codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); + if (!codec) + return AVERROR_BUG; + ctx->hevc_avctx = avcodec_alloc_context3(codec); + if (!ctx->hevc_avctx) + return AVERROR(ENOMEM); + ctx->hevc_avctx->thread_count = 1; + ctx->hevc_avctx->flags = avctx->flags; + ctx->hevc_avctx->flags2 = avctx->flags2; + ret = ff_codec_open2_recursive(ctx->hevc_avctx, codec, NULL); + if (ret < 0) + return ret; + + return 0; +} + +static int imm5_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + IMM5Context *ctx = avctx->priv_data; + AVFrame *frame = data; + AVCodecContext *codec_avctx = ctx->h264_avctx; + int ret; + + if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + 4) + 24ULL <= avpkt->size) { + int codec_type = avpkt->data[1]; + int index = avpkt->data[10]; + int new_size = AV_RL32(avpkt->data + 4); + int offset, off; + + if (codec_type == 0xA) + codec_avctx = ctx->hevc_avctx; + + if (index >= 1 && index <= 12) { + ret = av_packet_make_writable(avpkt); + if (ret < 0) + return ret; + + index -= 1; + off = offset = IMM5_units[index].len; + if (codec_type == 2) { + offset += IMM5_units[12].len; + } else { + offset += IMM5_units[13].len; + } + + avpkt->data += 24 - offset; + avpkt->size = new_size + offset; + + memcpy(avpkt->data, IMM5_units[index].bits, IMM5_units[index].len); + if (codec_type == 2) { + memcpy(avpkt->data + off, IMM5_units[12].bits, IMM5_units[12].len); + } else { + memcpy(avpkt->data + off, IMM5_units[13].bits, IMM5_units[13].len); + } + } else { + avpkt->data += 24; + avpkt->size -= 24; + } + } + + ret = avcodec_send_packet(codec_avctx, avpkt); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); + return ret; + } + + ret = avcodec_receive_frame(codec_avctx, frame); + if (ret < 0) + return ret; + + avctx->pix_fmt = codec_avctx->pix_fmt; + avctx->width = codec_avctx->width; + avctx->height = codec_avctx->height; + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int imm5_close(AVCodecContext *avctx) +{ + IMM5Context *ctx = avctx->priv_data; + + avcodec_free_context(&ctx->h264_avctx); + avcodec_free_context(&ctx->hevc_avctx); + + return 0; +} + +AVCodec ff_imm5_decoder = { + .name = "imm5", + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_IMM5, + .init = imm5_init, + .decode = imm5_decode_frame, + .close = imm5_close, + .priv_data_size = sizeof(IMM5Context), + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavformat/riff.c b/libavformat/riff.c index e755ad8d5f..610974ebf0 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -488,6 +488,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') }, + { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') }, { AV_CODEC_ID_NONE, 0 } };
Signed-off-by: Paul B Mahol <onemda@gmail.com> --- configure | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 ++ libavcodec/imm5.c | 171 ++++++++++++++++++++++++++++++++++++++++ libavformat/riff.c | 1 + 7 files changed, 183 insertions(+) create mode 100644 libavcodec/imm5.c