1 /*
2 * Copyright 2003-2021 The Music Player Daemon Project
3 * http://www.musicpd.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /*
21 * Common data structures and functions used by FLAC and OggFLAC
22 */
23
24 #include "FlacCommon.hxx"
25 #include "lib/xiph/FlacStreamMetadata.hxx"
26 #include "Log.hxx"
27 #include "input/InputStream.hxx"
28
29 #include <exception>
30
31 bool
Initialize(unsigned sample_rate,unsigned bits_per_sample,unsigned channels,FLAC__uint64 total_frames)32 FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
33 unsigned channels, FLAC__uint64 total_frames)
34 {
35 assert(!initialized);
36 assert(!unsupported);
37
38 try {
39 pcm_import.Open(sample_rate, bits_per_sample,
40 channels);
41 } catch (...) {
42 LogError(std::current_exception());
43 unsupported = true;
44 return false;
45 }
46
47 const auto audio_format = pcm_import.GetAudioFormat();
48
49 const auto duration = total_frames > 0
50 ? SignedSongTime::FromScale<uint64_t>(total_frames,
51 audio_format.sample_rate)
52 : SignedSongTime::Negative();
53
54 GetClient()->Ready(audio_format,
55 GetInputStream().IsSeekable(),
56 duration);
57
58 initialized = true;
59 return true;
60 }
61
62 inline void
OnStreamInfo(const FLAC__StreamMetadata_StreamInfo & stream_info)63 FlacDecoder::OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info)
64 {
65 if (initialized)
66 return;
67
68 Initialize(stream_info.sample_rate,
69 stream_info.bits_per_sample,
70 stream_info.channels,
71 stream_info.total_samples);
72 }
73
74 inline void
OnVorbisComment(const FLAC__StreamMetadata_VorbisComment & vc)75 FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc)
76 {
77 ReplayGainInfo rgi;
78 if (flac_parse_replay_gain(rgi, vc))
79 GetClient()->SubmitReplayGain(&rgi);
80
81 if (auto mix_ramp = flac_parse_mixramp(vc);
82 mix_ramp.IsDefined())
83 GetClient()->SubmitMixRamp(std::move(mix_ramp));
84
85 tag = flac_vorbis_comments_to_tag(&vc);
86 }
87
88 void
OnMetadata(const FLAC__StreamMetadata & metadata)89 FlacDecoder::OnMetadata(const FLAC__StreamMetadata &metadata)
90 {
91 if (unsupported)
92 return;
93
94 switch (metadata.type) {
95 case FLAC__METADATA_TYPE_STREAMINFO:
96 OnStreamInfo(metadata.data.stream_info);
97 break;
98
99 case FLAC__METADATA_TYPE_VORBIS_COMMENT:
100 OnVorbisComment(metadata.data.vorbis_comment);
101 break;
102
103 default:
104 break;
105 }
106 }
107
108 inline bool
OnFirstFrame(const FLAC__FrameHeader & header)109 FlacDecoder::OnFirstFrame(const FLAC__FrameHeader &header)
110 {
111 if (unsupported)
112 return false;
113
114 return Initialize(header.sample_rate,
115 header.bits_per_sample,
116 header.channels,
117 /* unknown duration */
118 0);
119 }
120
121 FLAC__uint64
GetDeltaPosition(const FLAC__StreamDecoder & sd)122 FlacDecoder::GetDeltaPosition(const FLAC__StreamDecoder &sd)
123 {
124 FLAC__uint64 nbytes;
125 if (!FLAC__stream_decoder_get_decode_position(&sd, &nbytes))
126 return 0;
127
128 if (position > 0 && nbytes > position) {
129 nbytes -= position;
130 position += nbytes;
131 } else {
132 position = nbytes;
133 nbytes = 0;
134 }
135
136 return nbytes;
137 }
138
139 FLAC__StreamDecoderWriteStatus
OnWrite(const FLAC__Frame & frame,const FLAC__int32 * const buf[],FLAC__uint64 nbytes)140 FlacDecoder::OnWrite(const FLAC__Frame &frame,
141 const FLAC__int32 *const buf[],
142 FLAC__uint64 nbytes)
143 {
144 if (!initialized && !OnFirstFrame(frame.header))
145 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
146
147 chunk = pcm_import.Import(buf, frame.header.blocksize);
148
149 kbit_rate = nbytes * 8 * frame.header.sample_rate /
150 (1000 * frame.header.blocksize);
151
152 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
153 }
154