| Line | Branch | Exec | Source |
|---|---|---|---|
| 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/attributes.h" | ||
| 22 | #include "libavutil/attributes_internal.h" | ||
| 23 | #include "libavutil/intreadwrite.h" | ||
| 24 | |||
| 25 | #include "avcodec.h" | ||
| 26 | #include "codec_internal.h" | ||
| 27 | |||
| 28 | typedef struct IMM5Context { | ||
| 29 | AVCodecContext *h264_avctx; // wrapper context for H264 | ||
| 30 | AVCodecContext *hevc_avctx; // wrapper context for HEVC | ||
| 31 | } IMM5Context; | ||
| 32 | |||
| 33 | static const struct IMM5_unit { | ||
| 34 | uint8_t bits[14]; | ||
| 35 | uint8_t len; | ||
| 36 | } IMM5_units[14] = { | ||
| 37 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x0F, 0x88 }, 12 }, | ||
| 38 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x83, 0xE2 }, 12 }, | ||
| 39 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0xE8, 0x80 }, 13 }, | ||
| 40 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x0B, 0x04, 0xA2 }, 12 }, | ||
| 41 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x81, 0x28, 0x80 }, 13 }, | ||
| 42 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x1E, 0xF4, 0x05, 0x80, 0x92, 0x20 }, 13 }, | ||
| 43 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x0F, 0xC8 }, 13 }, | ||
| 44 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x83, 0xF2 }, 13 }, | ||
| 45 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0xEC, 0x80 }, 14 }, | ||
| 46 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x0B, 0x04, 0xB2 }, 13 }, | ||
| 47 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x81, 0x2C, 0x80 }, 14 }, | ||
| 48 | { { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1E, 0x9A, 0x74, 0x05, 0x80, 0x93, 0x20 }, 14 }, | ||
| 49 | { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xDE, 0x3C, 0x80 }, 8 }, | ||
| 50 | { { 0x00, 0x00, 0x00, 0x01, 0x68, 0xCE, 0x32, 0x28 }, 8 }, | ||
| 51 | }; | ||
| 52 | |||
| 53 | ✗ | static av_cold int imm5_init(AVCodecContext *avctx) | |
| 54 | { | ||
| 55 | ✗ | IMM5Context *ctx = avctx->priv_data; | |
| 56 | int ret; | ||
| 57 | |||
| 58 | EXTERN const FFCodec ff_h264_decoder; | ||
| 59 | ✗ | ctx->h264_avctx = avcodec_alloc_context3(&ff_h264_decoder.p); | |
| 60 | ✗ | if (!ctx->h264_avctx) | |
| 61 | ✗ | return AVERROR(ENOMEM); | |
| 62 | ✗ | ctx->h264_avctx->thread_count = 1; | |
| 63 | ✗ | ctx->h264_avctx->flags = avctx->flags; | |
| 64 | ✗ | ctx->h264_avctx->flags2 = avctx->flags2; | |
| 65 | ✗ | ret = avcodec_open2(ctx->h264_avctx, NULL, NULL); | |
| 66 | ✗ | if (ret < 0) | |
| 67 | ✗ | return ret; | |
| 68 | |||
| 69 | EXTERN const FFCodec ff_hevc_decoder; | ||
| 70 | ✗ | ctx->hevc_avctx = avcodec_alloc_context3(&ff_hevc_decoder.p); | |
| 71 | ✗ | if (!ctx->hevc_avctx) | |
| 72 | ✗ | return AVERROR(ENOMEM); | |
| 73 | ✗ | ctx->hevc_avctx->thread_count = 1; | |
| 74 | ✗ | ctx->hevc_avctx->flags = avctx->flags; | |
| 75 | ✗ | ctx->hevc_avctx->flags2 = avctx->flags2; | |
| 76 | ✗ | ret = avcodec_open2(ctx->hevc_avctx, NULL, NULL); | |
| 77 | ✗ | if (ret < 0) | |
| 78 | ✗ | return ret; | |
| 79 | |||
| 80 | ✗ | return 0; | |
| 81 | } | ||
| 82 | |||
| 83 | ✗ | static int imm5_decode_frame(AVCodecContext *avctx, AVFrame *frame, | |
| 84 | int *got_frame, AVPacket *avpkt) | ||
| 85 | { | ||
| 86 | ✗ | IMM5Context *ctx = avctx->priv_data; | |
| 87 | ✗ | AVCodecContext *codec_avctx = ctx->h264_avctx; | |
| 88 | int ret; | ||
| 89 | |||
| 90 | ✗ | if (avpkt->size > 24 && avpkt->data[8] <= 1 && AV_RL32(avpkt->data + 4) + 24ULL <= avpkt->size) { | |
| 91 | ✗ | int codec_type = avpkt->data[1]; | |
| 92 | ✗ | int index = avpkt->data[10]; | |
| 93 | ✗ | int new_size = AV_RL32(avpkt->data + 4); | |
| 94 | int offset, off; | ||
| 95 | |||
| 96 | ✗ | if (codec_type == 0xA) { | |
| 97 | ✗ | codec_avctx = ctx->hevc_avctx; | |
| 98 | ✗ | } else if (index == 17) { | |
| 99 | ✗ | index = 4; | |
| 100 | ✗ | } else if (index == 18) { | |
| 101 | ✗ | index = 5; | |
| 102 | } | ||
| 103 | |||
| 104 | ✗ | if (index >= 1 && index <= 12) { | |
| 105 | ✗ | ret = av_packet_make_writable(avpkt); | |
| 106 | ✗ | if (ret < 0) | |
| 107 | ✗ | return ret; | |
| 108 | |||
| 109 | ✗ | index -= 1; | |
| 110 | ✗ | off = offset = IMM5_units[index].len; | |
| 111 | ✗ | if (codec_type == 2) { | |
| 112 | ✗ | offset += IMM5_units[12].len; | |
| 113 | } else { | ||
| 114 | ✗ | offset += IMM5_units[13].len; | |
| 115 | } | ||
| 116 | |||
| 117 | ✗ | avpkt->data += 24 - offset; | |
| 118 | ✗ | avpkt->size = new_size + offset; | |
| 119 | |||
| 120 | ✗ | memcpy(avpkt->data, IMM5_units[index].bits, IMM5_units[index].len); | |
| 121 | ✗ | if (codec_type == 2) { | |
| 122 | ✗ | memcpy(avpkt->data + off, IMM5_units[12].bits, IMM5_units[12].len); | |
| 123 | } else { | ||
| 124 | ✗ | memcpy(avpkt->data + off, IMM5_units[13].bits, IMM5_units[13].len); | |
| 125 | } | ||
| 126 | } else { | ||
| 127 | ✗ | avpkt->data += 24; | |
| 128 | ✗ | avpkt->size -= 24; | |
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | ✗ | ret = avcodec_send_packet(codec_avctx, avpkt); | |
| 133 | ✗ | if (ret < 0) { | |
| 134 | ✗ | av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); | |
| 135 | ✗ | return ret; | |
| 136 | } | ||
| 137 | |||
| 138 | ✗ | ret = avcodec_receive_frame(codec_avctx, frame); | |
| 139 | ✗ | if (ret < 0) | |
| 140 | ✗ | return ret; | |
| 141 | |||
| 142 | ✗ | avctx->pix_fmt = codec_avctx->pix_fmt; | |
| 143 | ✗ | avctx->coded_width = codec_avctx->coded_width; | |
| 144 | ✗ | avctx->coded_height = codec_avctx->coded_height; | |
| 145 | ✗ | avctx->width = codec_avctx->width; | |
| 146 | ✗ | avctx->height = codec_avctx->height; | |
| 147 | ✗ | avctx->bit_rate = codec_avctx->bit_rate; | |
| 148 | ✗ | avctx->colorspace = codec_avctx->colorspace; | |
| 149 | ✗ | avctx->color_range = codec_avctx->color_range; | |
| 150 | ✗ | avctx->color_trc = codec_avctx->color_trc; | |
| 151 | ✗ | avctx->color_primaries = codec_avctx->color_primaries; | |
| 152 | ✗ | avctx->chroma_sample_location = codec_avctx->chroma_sample_location; | |
| 153 | |||
| 154 | ✗ | *got_frame = 1; | |
| 155 | |||
| 156 | ✗ | return avpkt->size; | |
| 157 | } | ||
| 158 | |||
| 159 | ✗ | static av_cold void imm5_flush(AVCodecContext *avctx) | |
| 160 | { | ||
| 161 | ✗ | IMM5Context *ctx = avctx->priv_data; | |
| 162 | |||
| 163 | ✗ | avcodec_flush_buffers(ctx->h264_avctx); | |
| 164 | ✗ | avcodec_flush_buffers(ctx->hevc_avctx); | |
| 165 | ✗ | } | |
| 166 | |||
| 167 | ✗ | static av_cold int imm5_close(AVCodecContext *avctx) | |
| 168 | { | ||
| 169 | ✗ | IMM5Context *ctx = avctx->priv_data; | |
| 170 | |||
| 171 | ✗ | avcodec_free_context(&ctx->h264_avctx); | |
| 172 | ✗ | avcodec_free_context(&ctx->hevc_avctx); | |
| 173 | |||
| 174 | ✗ | return 0; | |
| 175 | } | ||
| 176 | |||
| 177 | const FFCodec ff_imm5_decoder = { | ||
| 178 | .p.name = "imm5", | ||
| 179 | CODEC_LONG_NAME("Infinity IMM5"), | ||
| 180 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
| 181 | .p.id = AV_CODEC_ID_IMM5, | ||
| 182 | .init = imm5_init, | ||
| 183 | FF_CODEC_DECODE_CB(imm5_decode_frame), | ||
| 184 | .close = imm5_close, | ||
| 185 | .flush = imm5_flush, | ||
| 186 | .priv_data_size = sizeof(IMM5Context), | ||
| 187 | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, | ||
| 188 | }; | ||
| 189 |