From patchwork Mon Jul 15 21:20:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 13954 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 22BED449F8A for ; Tue, 16 Jul 2019 00:28:55 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id EC12068A569; Tue, 16 Jul 2019 00:28:54 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f68.google.com (mail-ed1-f68.google.com [209.85.208.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2421268A430 for ; Tue, 16 Jul 2019 00:28:49 +0300 (EEST) Received: by mail-ed1-f68.google.com with SMTP id w20so16839766edd.2 for ; Mon, 15 Jul 2019 14:28:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=zX8K5Va1Kkqad3gy751KdipqxIoRK3m7qzuZaay9btI=; b=VA9JKsE++/HinH9SJKmGxdBWyIHesFNXxt3p8edx+o80NjHfyOgc1kHPSQbYVkt8S+ q9gLWAiYAB1byvkX27pHur/YB/XHJhBtgWAbSBL8FlgFk6RmL4rf7ZAy07hMNLQLB1UH Umlc4UuCIhY9UVrawRVAWVcxRIq2rjCQSd1P3SGPSWdSJ7EFAMKAfHsS9k71X2nl/fuB 7SSqWpZhJHfWwG0dQ93MZF7/H2/ZNY5Tpmdtz4PKUNj9tZmAYJasFo6F3AfVfWr+rAhr d5V2dC4fRD1l8Kk0bOIyVKOXiGoiZc4gcgVEpjDVN1uMXdRsW3Jl9gixW01u6v/3S93a 8nsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=zX8K5Va1Kkqad3gy751KdipqxIoRK3m7qzuZaay9btI=; b=CXB/+zmmQxA7kDMuMngserbS83bge2WpOVdLAHwCrkJWdxG77ZbLMovwuIMfmI/epN 9FqkU8AOg43mIiid+W0hXNSgKtFf9iS5bKXMMnnGsvA/GbT05dfPMUJorKhTKiNDUijS eBcwzh3jCmtWLlWZCocP23piEpMGL1d2iin8oQtEsJGeZgMcKmjUFul9t6fjilnl79Ix dUqAgB/orIN8LlZrMuD5RCun8k8ptQMiYFJlSZJN/Uq9TOy9EGtNEtWmtjEqc+thtmSm 4s+7ZHecYnhlsFJjrVHdpMmu7ny5H4cdog7MBmzh8LH3BeOKIN8g+rKwr4rwUpRsutdV M0yw== X-Gm-Message-State: APjAAAUKhd1LvqPmmeoNx0Rm3QogzkRRKD+z5ABYUCJ6U36Kj1U1pXRm znE38kmncByjCjiAyouWLU0yXOnZ X-Google-Smtp-Source: APXvYqzp+/R2VzGDk3tRqbfqTqmqz+mb1FflxpJFu/gV58wrS1dV4oqao/yU2hQ5sdvySXG6J0mzdQ== X-Received: by 2002:a50:f781:: with SMTP id h1mr26418818edn.240.1563225653862; Mon, 15 Jul 2019 14:20:53 -0700 (PDT) Received: from localhost.localdomain ([77.237.109.181]) by smtp.gmail.com with ESMTPSA id b19sm3919010eje.80.2019.07.15.14.20.52 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 15 Jul 2019 14:20:53 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Mon, 15 Jul 2019 23:20:45 +0200 Message-Id: <20190715212045.22529-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avcodec: add IMM5 decoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- configure | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 ++ libavcodec/imm5.c | 234 ++++++++++++++++++++++++++++++++++++++++ libavformat/riff.c | 1 + 7 files changed, 246 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..f6b2ce691c --- /dev/null +++ b/libavcodec/imm5.c @@ -0,0 +1,234 @@ +/* + * 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 "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +typedef struct IMM5Context { + AVCodecContext *h264_avctx; // wrapper context for H264 + AVCodecContext *hevc_avctx; // wrapper context for HEVC + + int width, height; + GetByteContext gbc; + + uint8_t *imm5_buffer; + int imm5_buffer_size; +} 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->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->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; + AVCodecContext *codec_avctx = ctx->h264_avctx; + int buf_size = avpkt->size; + uint8_t *buf = avpkt->data; + AVPacket hpkt; + int ret; + + if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + 4) < avpkt->size) { + int codec_type = avpkt->data[1]; + int index = avpkt->data[10]; + int new_size = AV_RL32(avpkt->data + 4); + int height, width, offset; + + if (codec_type == 0xA) + codec_avctx = ctx->hevc_avctx; + + switch (index) { + case 1: + width = 352; + height = 240; + break; + case 2: + height = 240; + width = 704; + break; + case 4: + case 132: + height = 480; + width = 704; + break; + case 17: + width = 352; + height = 288; + break; + case 18: + height = 288; + width = 704; + index = codec_type ? 11 : 5; + break; + case 133: + width = 640; + height = 480; + break; + case 134: + width = 720; + height = 480; + break; + case 135: + width = 720; + height = 576; + break; + case 136: + width = 800; + height = 600; + break; + case 137: + width = 1024; + height = 768; + break; + case 138: + width = 1280; + height = 1024; + break; + case 139: + width = 1600; + height = 1200; + break; + default: + height = 576; + width = 704; + break; + } + + if (index >= 1 && index <= 12) { + index -= 1; + av_fast_padded_malloc(&ctx->imm5_buffer, &ctx->imm5_buffer_size, buf_size); + memcpy(ctx->imm5_buffer, IMM5_units[index].bits, IMM5_units[index].len); + offset = IMM5_units[index].len; + if (avpkt->data[1] == 2) { + memcpy(ctx->imm5_buffer + offset, IMM5_units[12].bits, IMM5_units[12].len); + offset += IMM5_units[12].len; + } else { + memcpy(ctx->imm5_buffer + offset, IMM5_units[13].bits, IMM5_units[13].len); + offset += IMM5_units[13].len; + } + memcpy(ctx->imm5_buffer + offset, avpkt->data + 24, new_size); + buf = ctx->imm5_buffer; + buf_size = new_size + offset; + } else { + buf += 24; + buf_size -= 24; + } + } + + frame = av_frame_alloc(); + + av_init_packet(&hpkt); + hpkt.data = buf; + hpkt.size = buf_size; + + ret = avcodec_send_packet(codec_avctx, &hpkt); + 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; + ret = av_frame_ref(data, frame); + if (ret < 0) + return ret; + + *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 } };