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.

134 lines
3.8KB

  1. /*
  2. * Copyright (c) 2012 Laurent Aimar
  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. #include "dvaudio.h"
  24. typedef struct DVAudioContext {
  25. int block_size;
  26. int is_12bit;
  27. int is_pal;
  28. int16_t shuffle[2000];
  29. } DVAudioContext;
  30. static av_cold int decode_init(AVCodecContext *avctx)
  31. {
  32. DVAudioContext *s = avctx->priv_data;
  33. int i;
  34. if (avctx->channels != 2) {
  35. av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
  36. return AVERROR(EINVAL);
  37. }
  38. if (avctx->codec_tag == 0x0215) {
  39. s->block_size = 7200;
  40. } else if (avctx->codec_tag == 0x0216) {
  41. s->block_size = 8640;
  42. } else if (avctx->block_align == 7200 ||
  43. avctx->block_align == 8640) {
  44. s->block_size = avctx->block_align;
  45. } else {
  46. return AVERROR(EINVAL);
  47. }
  48. s->is_pal = s->block_size == 8640;
  49. s->is_12bit = avctx->bits_per_coded_sample == 12;
  50. avctx->sample_fmt = AV_SAMPLE_FMT_S16;
  51. avctx->channel_layout = AV_CH_LAYOUT_STEREO;
  52. for (i = 0; i < FF_ARRAY_ELEMS(s->shuffle); i++) {
  53. const unsigned a = s->is_pal ? 18 : 15;
  54. const unsigned b = 3 * a;
  55. s->shuffle[i] = 80 * ((21 * (i % 3) + 9 * (i / 3) + ((i / a) % 3)) % b) +
  56. (2 + s->is_12bit) * (i / b) + 8;
  57. }
  58. return 0;
  59. }
  60. static inline uint16_t dv_audio_12to16(uint16_t sample)
  61. {
  62. uint16_t shift, result;
  63. sample = (sample < 0x800) ? sample : sample | 0xf000;
  64. shift = (sample & 0xf00) >> 8;
  65. if (shift < 0x2 || shift > 0xd) {
  66. result = sample;
  67. } else if (shift < 0x8) {
  68. shift--;
  69. result = (sample - (256 * shift)) << shift;
  70. } else {
  71. shift = 0xe - shift;
  72. result = ((sample + ((256 * shift) + 1)) << shift) - 1;
  73. }
  74. return result;
  75. }
  76. static int decode_frame(AVCodecContext *avctx, void *data,
  77. int *got_frame_ptr, AVPacket *pkt)
  78. {
  79. DVAudioContext *s = avctx->priv_data;
  80. AVFrame *frame = data;
  81. const uint8_t *src = pkt->data;
  82. int16_t *dst;
  83. int ret, i;
  84. if (pkt->size < s->block_size)
  85. return AVERROR_INVALIDDATA;
  86. frame->nb_samples = dv_get_audio_sample_count(pkt->data + 244, s->is_pal);
  87. if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
  88. return ret;
  89. dst = (int16_t *)frame->data[0];
  90. for (i = 0; i < frame->nb_samples; i++) {
  91. const uint8_t *v = &src[s->shuffle[i]];
  92. if (s->is_12bit) {
  93. *dst++ = dv_audio_12to16((v[0] << 4) | ((v[2] >> 4) & 0x0f));
  94. *dst++ = dv_audio_12to16((v[1] << 4) | ((v[2] >> 0) & 0x0f));
  95. } else {
  96. *dst++ = AV_RB16(&v[0]);
  97. *dst++ = AV_RB16(&v[s->is_pal ? 4320 : 3600]);
  98. }
  99. }
  100. *got_frame_ptr = 1;
  101. return s->block_size;
  102. }
  103. AVCodec ff_dvaudio_decoder = {
  104. .name = "dvaudio",
  105. .long_name = NULL_IF_CONFIG_SMALL("Ulead DV Audio"),
  106. .type = AVMEDIA_TYPE_AUDIO,
  107. .id = AV_CODEC_ID_DVAUDIO,
  108. .init = decode_init,
  109. .decode = decode_frame,
  110. .capabilities = AV_CODEC_CAP_DR1,
  111. .priv_data_size = sizeof(DVAudioContext),
  112. };