summaryrefslogtreecommitdiff
path: root/chromium/media/filters/passthrough_dts_audio_decoder.cc
blob: a1cb03ed3f07e36279602731b6484fd87bf9288f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/passthrough_dts_audio_decoder.h"

#include "media/base/audio_buffer.h"
#include "media/base/bind_to_current_loop.h"
#include "media/formats/dts/dts_util.h"

namespace media {

PassthroughDTSAudioDecoder::PassthroughDTSAudioDecoder(
    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
    MediaLog* media_log)
    : task_runner_(task_runner),
      media_log_(media_log),
      pool_(new AudioBufferMemoryPool()) {
  DETACH_FROM_SEQUENCE(sequence_checker_);
}

PassthroughDTSAudioDecoder::~PassthroughDTSAudioDecoder() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

AudioDecoderType PassthroughDTSAudioDecoder::GetDecoderType() const {
  return AudioDecoderType::kPassthroughDTS;
}

void PassthroughDTSAudioDecoder::Initialize(const AudioDecoderConfig& config,
                                            CdmContext* /* cdm_context */,
                                            InitCB init_cb,
                                            const OutputCB& output_cb,
                                            const WaitingCB& /* waiting_cb */) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(config.IsValidConfig());
  InitCB bound_init_cb = BindToCurrentLoop(std::move(init_cb));
  if (config.is_encrypted()) {
    std::move(bound_init_cb)
        .Run(DecoderStatus(DecoderStatus::Codes::kUnsupportedEncryptionMode,
                           "PassthroughDTSAudioDecoder does not support "
                           "encrypted content"));
    return;
  }

  if (config.target_output_sample_format() != kSampleFormatDts) {
    std::move(bound_init_cb)
        .Run(
            DecoderStatus(DecoderStatus::Codes::kUnsupportedConfig,
                          "PassthroughDTSAudioDecoder does not support codec"));
    return;
  }

  // Success!
  config_ = config;
  output_cb_ = BindToCurrentLoop(output_cb);
  std::move(bound_init_cb).Run(OkStatus());
}

void PassthroughDTSAudioDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
                                        DecodeCB decode_cb) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(decode_cb);
  DecodeCB decode_cb_bound = BindToCurrentLoop(std::move(decode_cb));

  if (buffer->end_of_stream()) {
    std::move(decode_cb_bound).Run(DecoderStatus::Codes::kOk);
    return;
  }

  ProcessBuffer(*buffer, std::move(decode_cb_bound));
}

void PassthroughDTSAudioDecoder::Reset(base::OnceClosure closure) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  task_runner_->PostTask(FROM_HERE, std::move(closure));
}

void PassthroughDTSAudioDecoder::ProcessBuffer(const DecoderBuffer& buffer,
                                               DecodeCB decode_cb) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  // Make sure we are notified if http://crbug.com/49709 returns.  Issue also
  // occurs with some damaged files.
  if (!buffer.end_of_stream() && buffer.timestamp() == kNoTimestamp) {
    DVLOG(1) << "Received a buffer without timestamps!";
    std::move(decode_cb).Run(DecoderStatus::Codes::kFailed);
    return;
  }
  EncapsulateFrame(buffer);

  std::move(decode_cb).Run(DecoderStatus::Codes::kOk);
}

void PassthroughDTSAudioDecoder::EncapsulateFrame(const DecoderBuffer& buffer) {
  if (config_.target_output_sample_format() != kSampleFormatDts)
    return;
  const size_t samples_per_frame = dts::GetDTSSamplesPerFrame(config_.codec());
  const size_t dts_frame_size = 2 * 2 * samples_per_frame;
  std::vector<uint8_t> output_buffer(dts_frame_size);

  // Encapsulated a compressed DTS frame per IEC61937
  base::span<const uint8_t> input_data;
  input_data = base::span<const uint8_t>(buffer.data(), buffer.data_size());
  dts::WrapDTSWithIEC61937(input_data, output_buffer, config_.codec());

  // Create a mono channel "buffer" to hold IEC encapsulated bitstream
  uint8_t* output_channels[1] = {output_buffer.data()};
  scoped_refptr<AudioBuffer> output = AudioBuffer::CopyBitstreamFrom(
      kSampleFormatIECDts, CHANNEL_LAYOUT_MONO, 1, config_.samples_per_second(),
      samples_per_frame, output_channels, dts_frame_size, buffer.timestamp());
  output_cb_.Run(output);
}

}  // namespace media