You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
6.6KB

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