summaryrefslogtreecommitdiffstats
path: root/media/formats/webm/webm_audio_client.cc
blob: 173d81fe95786efe64b860b502b65891fc4a202f (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2014 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/formats/webm/webm_audio_client.h"

#include "media/base/audio_decoder_config.h"
#include "media/base/channel_layout.h"
#include "media/formats/webm/webm_constants.h"

namespace media {

WebMAudioClient::WebMAudioClient(const scoped_refptr<MediaLog>& media_log)
    : media_log_(media_log) {
  Reset();
}

WebMAudioClient::~WebMAudioClient() {
}

void WebMAudioClient::Reset() {
  channels_ = -1;
  samples_per_second_ = -1;
  output_samples_per_second_ = -1;
}

bool WebMAudioClient::InitializeConfig(
    const std::string& codec_id,
    const std::vector<uint8_t>& codec_private,
    int64_t seek_preroll,
    int64_t codec_delay,
    const EncryptionScheme& encryption_scheme,
    AudioDecoderConfig* config) {
  DCHECK(config);
  SampleFormat sample_format = kSampleFormatPlanarF32;

  AudioCodec audio_codec = kUnknownAudioCodec;
  if (codec_id == "A_VORBIS") {
    audio_codec = kCodecVorbis;
  } else if (codec_id == "A_OPUS") {
    audio_codec = kCodecOpus;
  } else {
    MEDIA_LOG(ERROR, media_log_) << "Unsupported audio codec_id " << codec_id;
    return false;
  }

  if (samples_per_second_ <= 0)
    return false;

  // Set channel layout default if a Channels element was not present.
  if (channels_ == -1)
    channels_ = 1;

  ChannelLayout channel_layout =  GuessChannelLayout(channels_);

  if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) {
    MEDIA_LOG(ERROR, media_log_) << "Unsupported channel count " << channels_;
    return false;
  }

  int samples_per_second = samples_per_second_;
  if (output_samples_per_second_ > 0)
    samples_per_second = output_samples_per_second_;

  // Always use 48kHz for OPUS.  See the "Input Sample Rate" section of the
  // spec: http://tools.ietf.org/html/draft-terriberry-oggopus-01#page-11
  if (audio_codec == kCodecOpus) {
    samples_per_second = 48000;
    sample_format = kSampleFormatF32;
  }

  // Convert |codec_delay| from nanoseconds into frames.
  int codec_delay_in_frames = 0;
  if (codec_delay != -1) {
    codec_delay_in_frames =
        0.5 +
        samples_per_second * (static_cast<double>(codec_delay) /
                              base::Time::kNanosecondsPerSecond);
  }

  config->Initialize(audio_codec, sample_format, channel_layout,
                     samples_per_second, codec_private, encryption_scheme,
                     base::TimeDelta::FromMicroseconds(
                         (seek_preroll != -1 ? seek_preroll : 0) / 1000),
                     codec_delay_in_frames);
  return config->IsValidConfig();
}

bool WebMAudioClient::OnUInt(int id, int64_t val) {
  if (id == kWebMIdChannels) {
    if (channels_ != -1) {
      MEDIA_LOG(ERROR, media_log_) << "Multiple values for id " << std::hex
                                   << id << " specified. (" << channels_
                                   << " and " << val << ")";
      return false;
    }

    channels_ = val;
  }
  return true;
}

bool WebMAudioClient::OnFloat(int id, double val) {
  double* dst = NULL;

  switch (id) {
    case kWebMIdSamplingFrequency:
      dst = &samples_per_second_;
      break;
    case kWebMIdOutputSamplingFrequency:
      dst = &output_samples_per_second_;
      break;
    default:
      return true;
  }

  if (val <= 0)
    return false;

  if (*dst != -1) {
    MEDIA_LOG(ERROR, media_log_) << "Multiple values for id " << std::hex << id
                                 << " specified (" << *dst << " and " << val
                                 << ")";
    return false;
  }

  *dst = val;
  return true;
}

}  // namespace media