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