1/* 2 * Copyright (c) 2019 Paul B Mahol 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "libavutil/intreadwrite.h" 22 23#include "avcodec.h" 24#include "codec_internal.h" 25 26typedef struct IMM5Context { 27 AVCodecContext *h264_avctx; // wrapper context for H264 28 AVCodecContext *hevc_avctx; // wrapper context for HEVC 29} IMM5Context; 30 31static const struct IMM5_unit { 32 uint8_t bits[14]; 33 uint8_t len; 34} IMM5_units[14] = { 35 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x0F, 0x88 }, 12 }, 36 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x83, 0xE2 }, 12 }, 37 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0xE8, 0x80 }, 13 }, 38 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x04, 0xA2 }, 12 }, 39 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0x28, 0x80 }, 13 }, 40 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x80, 0x92, 0x20 }, 13 }, 41 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x0F, 0xC8 }, 13 }, 42 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x83, 0xF2 }, 13 }, 43 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0xEC, 0x80 }, 14 }, 44 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x04, 0xB2 }, 13 }, 45 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0x2C, 0x80 }, 14 }, 46 { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x80, 0x93, 0x20 }, 14 }, 47 { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xDE, 0x3C, 0x80 }, 8 }, 48 { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x32, 0x28 }, 8 }, 49}; 50 51static av_cold int imm5_init(AVCodecContext *avctx) 52{ 53 IMM5Context *ctx = avctx->priv_data; 54 const AVCodec *codec; 55 int ret; 56 57 codec = avcodec_find_decoder(AV_CODEC_ID_H264); 58 if (!codec) 59 return AVERROR_BUG; 60 ctx->h264_avctx = avcodec_alloc_context3(codec); 61 if (!ctx->h264_avctx) 62 return AVERROR(ENOMEM); 63 ctx->h264_avctx->thread_count = 1; 64 ctx->h264_avctx->flags = avctx->flags; 65 ctx->h264_avctx->flags2 = avctx->flags2; 66 ret = avcodec_open2(ctx->h264_avctx, codec, NULL); 67 if (ret < 0) 68 return ret; 69 70 codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); 71 if (!codec) 72 return AVERROR_BUG; 73 ctx->hevc_avctx = avcodec_alloc_context3(codec); 74 if (!ctx->hevc_avctx) 75 return AVERROR(ENOMEM); 76 ctx->hevc_avctx->thread_count = 1; 77 ctx->hevc_avctx->flags = avctx->flags; 78 ctx->hevc_avctx->flags2 = avctx->flags2; 79 ret = avcodec_open2(ctx->hevc_avctx, codec, NULL); 80 if (ret < 0) 81 return ret; 82 83 return 0; 84} 85 86static int imm5_decode_frame(AVCodecContext *avctx, AVFrame *frame, 87 int *got_frame, AVPacket *avpkt) 88{ 89 IMM5Context *ctx = avctx->priv_data; 90 AVCodecContext *codec_avctx = ctx->h264_avctx; 91 int ret; 92 93 if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + 4) + 24ULL <= avpkt->size) { 94 int codec_type = avpkt->data[1]; 95 int index = avpkt->data[10]; 96 int new_size = AV_RL32(avpkt->data + 4); 97 int offset, off; 98 99 if (codec_type == 0xA) { 100 codec_avctx = ctx->hevc_avctx; 101 } else if (index == 17) { 102 index = 4; 103 } else if (index == 18) { 104 index = 5; 105 } 106 107 if (index >= 1 && index <= 12) { 108 ret = av_packet_make_writable(avpkt); 109 if (ret < 0) 110 return ret; 111 112 index -= 1; 113 off = offset = IMM5_units[index].len; 114 if (codec_type == 2) { 115 offset += IMM5_units[12].len; 116 } else { 117 offset += IMM5_units[13].len; 118 } 119 120 avpkt->data += 24 - offset; 121 avpkt->size = new_size + offset; 122 123 memcpy(avpkt->data, IMM5_units[index].bits, IMM5_units[index].len); 124 if (codec_type == 2) { 125 memcpy(avpkt->data + off, IMM5_units[12].bits, IMM5_units[12].len); 126 } else { 127 memcpy(avpkt->data + off, IMM5_units[13].bits, IMM5_units[13].len); 128 } 129 } else { 130 avpkt->data += 24; 131 avpkt->size -= 24; 132 } 133 } 134 135 ret = avcodec_send_packet(codec_avctx, avpkt); 136 if (ret < 0) { 137 av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); 138 return ret; 139 } 140 141 ret = avcodec_receive_frame(codec_avctx, frame); 142 if (ret < 0) 143 return ret; 144 145 avctx->pix_fmt = codec_avctx->pix_fmt; 146 avctx->coded_width = codec_avctx->coded_width; 147 avctx->coded_height = codec_avctx->coded_height; 148 avctx->width = codec_avctx->width; 149 avctx->height = codec_avctx->height; 150 avctx->bit_rate = codec_avctx->bit_rate; 151 avctx->colorspace = codec_avctx->colorspace; 152 avctx->color_range = codec_avctx->color_range; 153 avctx->color_trc = codec_avctx->color_trc; 154 avctx->color_primaries = codec_avctx->color_primaries; 155 avctx->chroma_sample_location = codec_avctx->chroma_sample_location; 156 157 *got_frame = 1; 158 159 return avpkt->size; 160} 161 162static void imm5_flush(AVCodecContext *avctx) 163{ 164 IMM5Context *ctx = avctx->priv_data; 165 166 avcodec_flush_buffers(ctx->h264_avctx); 167 avcodec_flush_buffers(ctx->hevc_avctx); 168} 169 170static av_cold int imm5_close(AVCodecContext *avctx) 171{ 172 IMM5Context *ctx = avctx->priv_data; 173 174 avcodec_free_context(&ctx->h264_avctx); 175 avcodec_free_context(&ctx->hevc_avctx); 176 177 return 0; 178} 179 180const FFCodec ff_imm5_decoder = { 181 .p.name = "imm5", 182 .p.long_name = NULL_IF_CONFIG_SMALL("Infinity IMM5"), 183 .p.type = AVMEDIA_TYPE_VIDEO, 184 .p.id = AV_CODEC_ID_IMM5, 185 .init = imm5_init, 186 FF_CODEC_DECODE_CB(imm5_decode_frame), 187 .close = imm5_close, 188 .flush = imm5_flush, 189 .priv_data_size = sizeof(IMM5Context), 190 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | 191 FF_CODEC_CAP_INIT_CLEANUP, 192}; 193