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.

191 lines
5.7KB

  1. /*
  2. * JPEG2000 parser
  3. * Copyright (c) 2020 Gautam Ramakrishnan
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. /**
  22. * @file
  23. * JPEG2000 parser.
  24. */
  25. #include "parser.h"
  26. /* Whether frame is jp2 file or codestream
  27. */
  28. enum frame_type {
  29. jp2_file = 1,
  30. j2k_cstream
  31. };
  32. typedef struct JPEG2000ParserContext {
  33. ParseContext pc;
  34. uint64_t bytes_read;
  35. uint64_t fheader_state;
  36. uint32_t skip_bytes; // skip bytes inside codestream data
  37. enum frame_type ft; // 1 if file, 2 if codestream
  38. uint8_t fheader_read; // are we reading
  39. uint8_t reading_file_header;
  40. uint8_t skipped_codestream;
  41. uint8_t codestream_frame_end;
  42. uint8_t read_tp;
  43. uint8_t in_codestream;
  44. } JPEG2000ParserContext;
  45. static inline void reset_context(JPEG2000ParserContext *m)
  46. {
  47. ParseContext *pc = &m->pc;
  48. pc->frame_start_found= 0;
  49. pc->state = 0;
  50. m->bytes_read = 0;
  51. m->ft = 0;
  52. m->skipped_codestream = 0;
  53. m->fheader_read = 0;
  54. m->codestream_frame_end = 0;
  55. m->skip_bytes = 0;
  56. m->read_tp = 0;
  57. m->in_codestream = 0;
  58. }
  59. /* Returns 1 if marker has any data which can be skipped
  60. */
  61. static uint8_t info_marker(uint16_t marker)
  62. {
  63. if (marker == 0xFF92 || marker == 0xFF4F ||
  64. marker == 0xFF90 || marker == 0xFF93 ||
  65. marker == 0xFFD9)
  66. return 0;
  67. else
  68. if (marker > 0xFF00) return 1;
  69. return 0;
  70. }
  71. /**
  72. * Find the end of the current frame in the bitstream.
  73. * @return the position of the first byte of the next frame, or -1
  74. */
  75. static int find_frame_end(JPEG2000ParserContext *m, const uint8_t *buf, int buf_size)
  76. {
  77. ParseContext *pc= &m->pc;
  78. int i;
  79. uint32_t state;
  80. uint64_t state64;
  81. state= pc->state;
  82. state64 = pc->state64;
  83. if (buf_size == 0) {
  84. return 0;
  85. }
  86. for (i = 0; i < buf_size; i++) {
  87. state = state << 8 | buf[i];
  88. state64 = state64 << 8 | buf[i];
  89. m->bytes_read++;
  90. if (m->skip_bytes) {
  91. m->skip_bytes--;
  92. continue;
  93. }
  94. if (m->codestream_frame_end) {
  95. reset_context(m);
  96. return i;
  97. }
  98. if (m->read_tp) { // Find out how many bytes inside Tile part codestream to skip.
  99. if (m->read_tp == 1) {
  100. m->skip_bytes = (state64 & 0xFFFFFFFF) - 10 > 0?
  101. (state64 & 0xFFFFFFFF) - 10 : 0;
  102. }
  103. m->read_tp--;
  104. }
  105. if (m->fheader_read) {
  106. if (m->fheader_read == 1) {
  107. if (state64 == 0x6A5020200D0A870A) { // JP2 signature box value.
  108. if (pc->frame_start_found) {
  109. pc->frame_start_found = 0;
  110. reset_context(m);
  111. return i - 11;
  112. } else {
  113. pc->frame_start_found = 1;
  114. m->ft = jp2_file;
  115. }
  116. }
  117. }
  118. m->fheader_read--;
  119. }
  120. if (state == 0x0000000C && m->bytes_read >= 3) { // Indicates start of JP2 file. Check signature next.
  121. m->fheader_read = 8;
  122. } else if ((state & 0xFFFF) == 0xFF4F) {
  123. m->in_codestream = 1;
  124. if (!pc->frame_start_found) {
  125. pc->frame_start_found = 1;
  126. m->ft = j2k_cstream;
  127. } else if (pc->frame_start_found && m->ft == jp2_file && m->skipped_codestream) {
  128. reset_context(m);
  129. return i - 1;
  130. }
  131. } else if ((state & 0xFFFF) == 0xFFD9) {
  132. if (pc->frame_start_found && m->ft == jp2_file) {
  133. m->skipped_codestream = 1;
  134. } else if (pc->frame_start_found && m->ft == j2k_cstream) {
  135. m->codestream_frame_end = 1;
  136. }
  137. m->in_codestream = 0;
  138. } else if (m->in_codestream && (state & 0xFFFF) == 0xFF90) { // Are we in tile part header?
  139. m->read_tp = 8;
  140. } else if (pc->frame_start_found && info_marker((state & 0xFFFF0000)>>16) && m->in_codestream) {
  141. m->skip_bytes = (state & 0xFFFF) - 2;
  142. }
  143. }
  144. pc->state = state;
  145. pc->state64 = state64;
  146. return END_NOT_FOUND;
  147. }
  148. static int jpeg2000_parse(AVCodecParserContext *s,
  149. AVCodecContext *avctx,
  150. const uint8_t **poutbuf, int *poutbuf_size,
  151. const uint8_t *buf, int buf_size)
  152. {
  153. JPEG2000ParserContext *m = s->priv_data;
  154. ParseContext *pc = &m->pc;
  155. int next;
  156. if(s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
  157. next= buf_size;
  158. } else {
  159. next= find_frame_end(m, buf, buf_size);
  160. if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
  161. *poutbuf = NULL;
  162. *poutbuf_size = 0;
  163. return buf_size;
  164. }
  165. }
  166. *poutbuf = buf;
  167. *poutbuf_size = buf_size;
  168. return next;
  169. }
  170. AVCodecParser ff_jpeg2000_parser = {
  171. .codec_ids = { AV_CODEC_ID_JPEG2000 },
  172. .priv_data_size = sizeof(JPEG2000ParserContext),
  173. .parser_parse = jpeg2000_parse,
  174. .parser_close = ff_parse_close,
  175. };