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.

205 lines
5.5KB

  1. /*
  2. * Copyright (C) 2017 foo86
  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 "avformat.h"
  22. #include "spdif.h"
  23. #define MARKER_16LE 0x72F81F4E
  24. #define MARKER_20LE 0x20876FF0E154
  25. #define MARKER_24LE 0x72F8961F4EA5
  26. #define IS_16LE_MARKER(state) ((state & 0xFFFFFFFF) == MARKER_16LE)
  27. #define IS_20LE_MARKER(state) ((state & 0xF0FFFFF0FFFF) == MARKER_20LE)
  28. #define IS_24LE_MARKER(state) ((state & 0xFFFFFFFFFFFF) == MARKER_24LE)
  29. #define IS_LE_MARKER(state) (IS_16LE_MARKER(state) || IS_20LE_MARKER(state) || IS_24LE_MARKER(state))
  30. static int s337m_get_offset_and_codec(void *avc,
  31. uint64_t state,
  32. int data_type, int data_size,
  33. int *offset, enum AVCodecID *codec)
  34. {
  35. int word_bits;
  36. if (IS_16LE_MARKER(state)) {
  37. word_bits = 16;
  38. } else if (IS_20LE_MARKER(state)) {
  39. data_type >>= 8;
  40. data_size >>= 4;
  41. word_bits = 20;
  42. } else {
  43. data_type >>= 8;
  44. word_bits = 24;
  45. }
  46. if ((data_type & 0x1F) != 0x1C) {
  47. if (avc)
  48. avpriv_report_missing_feature(avc, "Data type %#x in SMPTE 337M", data_type & 0x1F);
  49. return AVERROR_PATCHWELCOME;
  50. }
  51. if (codec)
  52. *codec = AV_CODEC_ID_DOLBY_E;
  53. switch (data_size / word_bits) {
  54. case 3648:
  55. *offset = 1920;
  56. break;
  57. case 3644:
  58. *offset = 2002;
  59. break;
  60. case 3640:
  61. *offset = 2000;
  62. break;
  63. case 3040:
  64. *offset = 1601;
  65. break;
  66. default:
  67. if (avc)
  68. avpriv_report_missing_feature(avc, "Dolby E data size %d in SMPTE 337M", data_size);
  69. return AVERROR_PATCHWELCOME;
  70. }
  71. *offset -= 4;
  72. *offset *= (word_bits + 7 >> 3) * 2;
  73. return 0;
  74. }
  75. static int s337m_probe(const AVProbeData *p)
  76. {
  77. uint64_t state = 0;
  78. int markers[3] = { 0 };
  79. int i, pos, sum, max, data_type, data_size, offset;
  80. uint8_t *buf;
  81. for (pos = 0; pos < p->buf_size; pos++) {
  82. state = (state << 8) | p->buf[pos];
  83. if (!IS_LE_MARKER(state))
  84. continue;
  85. buf = p->buf + pos + 1;
  86. if (IS_16LE_MARKER(state)) {
  87. data_type = AV_RL16(buf );
  88. data_size = AV_RL16(buf + 2);
  89. } else {
  90. data_type = AV_RL24(buf );
  91. data_size = AV_RL24(buf + 3);
  92. }
  93. if (s337m_get_offset_and_codec(NULL, state, data_type, data_size, &offset, NULL))
  94. continue;
  95. i = IS_16LE_MARKER(state) ? 0 : IS_20LE_MARKER(state) ? 1 : 2;
  96. markers[i]++;
  97. pos += IS_16LE_MARKER(state) ? 4 : 6;
  98. pos += offset;
  99. state = 0;
  100. }
  101. sum = max = 0;
  102. for (i = 0; i < FF_ARRAY_ELEMS(markers); i++) {
  103. sum += markers[i];
  104. if (markers[max] < markers[i])
  105. max = i;
  106. }
  107. if (markers[max] > 3 && markers[max] * 4 > sum * 3)
  108. return AVPROBE_SCORE_EXTENSION + 1;
  109. return 0;
  110. }
  111. static int s337m_read_header(AVFormatContext *s)
  112. {
  113. s->ctx_flags |= AVFMTCTX_NOHEADER;
  114. return 0;
  115. }
  116. static void bswap_buf24(uint8_t *data, int size)
  117. {
  118. int i;
  119. for (i = 0; i < size / 3; i++, data += 3)
  120. FFSWAP(uint8_t, data[0], data[2]);
  121. }
  122. static int s337m_read_packet(AVFormatContext *s, AVPacket *pkt)
  123. {
  124. AVIOContext *pb = s->pb;
  125. uint64_t state = 0;
  126. int ret, data_type, data_size, offset;
  127. enum AVCodecID codec;
  128. int64_t pos;
  129. while (!IS_LE_MARKER(state)) {
  130. state = (state << 8) | avio_r8(pb);
  131. if (avio_feof(pb))
  132. return AVERROR_EOF;
  133. }
  134. if (IS_16LE_MARKER(state)) {
  135. data_type = avio_rl16(pb);
  136. data_size = avio_rl16(pb);
  137. } else {
  138. data_type = avio_rl24(pb);
  139. data_size = avio_rl24(pb);
  140. }
  141. pos = avio_tell(pb);
  142. if ((ret = s337m_get_offset_and_codec(s, state, data_type, data_size, &offset, &codec)) < 0)
  143. return ret;
  144. if ((ret = av_new_packet(pkt, offset)) < 0)
  145. return ret;
  146. pkt->pos = pos;
  147. if (avio_read(pb, pkt->data, pkt->size) < pkt->size) {
  148. return AVERROR_EOF;
  149. }
  150. if (IS_16LE_MARKER(state))
  151. ff_spdif_bswap_buf16((uint16_t *)pkt->data, (uint16_t *)pkt->data, pkt->size >> 1);
  152. else
  153. bswap_buf24(pkt->data, pkt->size);
  154. if (!s->nb_streams) {
  155. AVStream *st = avformat_new_stream(s, NULL);
  156. if (!st) {
  157. return AVERROR(ENOMEM);
  158. }
  159. st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
  160. st->codecpar->codec_id = codec;
  161. }
  162. return 0;
  163. }
  164. AVInputFormat ff_s337m_demuxer = {
  165. .name = "s337m",
  166. .long_name = NULL_IF_CONFIG_SMALL("SMPTE 337M"),
  167. .read_probe = s337m_probe,
  168. .read_header = s337m_read_header,
  169. .read_packet = s337m_read_packet,
  170. .flags = AVFMT_GENERIC_INDEX,
  171. };