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
132
133
134
|
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <utility>
#include "result.hpp"
#include "sample.hpp"
#include "types.hpp"
#include "memory_resource.hpp"
namespace codecs {
/*
* Interface for an abstract source of file-like data.
*/
class IStream {
public:
IStream(StreamType t) : t_(t) {}
virtual ~IStream() {}
auto type() -> StreamType { return t_; }
virtual auto Read(std::span<std::byte> dest) -> ssize_t = 0;
virtual auto CanSeek() -> bool = 0;
enum class SeekFrom {
kStartOfStream,
kEndOfStream,
kCurrentPosition,
};
virtual auto SeekTo(int64_t destination, SeekFrom from) -> void = 0;
virtual auto CurrentPosition() -> int64_t = 0;
virtual auto Size() -> std::optional<int64_t> = 0;
/*
* Called by codecs to indicate that they've finished parsing any header data
* within this stream, and are about to begin decoding.
*
* Currently used as a hint to the readahead stream to begin prefetching file
* data.
*/
virtual auto SetPreambleFinished() -> void {}
protected:
StreamType t_;
};
/*
* Common interface to be implemented by all audio decoders.
*/
class ICodec {
public:
virtual ~ICodec() {}
/* Errors that may be returned by codecs. */
enum class Error {
// Indicates that more data is required before this codec can finish its
// operation. E.g. the input buffer ends with a truncated frame.
kOutOfInput,
// Indicates that the data within the input buffer is fatally malformed.
kMalformedData,
// Indicated that the format is unsupported
kUnsupportedFormat,
kInternalError,
};
static auto ErrorString(Error err) -> std::pmr::string {
switch (err) {
case Error::kOutOfInput:
return "out of input";
case Error::kMalformedData:
return "malformed data";
case Error::kInternalError:
return "internal error";
case Error::kUnsupportedFormat:
return "unsupported format";
}
return "uhh";
}
/*
* Alias for more readable return types. All codec methods, success or
* failure, should also return the number of bytes they consumed.
*/
template <typename T>
using Result = std::pair<std::size_t, cpp::result<T, Error>>;
struct OutputFormat {
uint8_t num_channels;
uint32_t sample_rate_hz;
std::optional<uint32_t> total_samples;
bool operator==(const OutputFormat&) const = default;
};
/*
* Decodes metadata or headers from the given input stream, and returns the
* format for the samples that will be decoded from it.
*/
virtual auto OpenStream(std::shared_ptr<IStream> input, uint32_t offset)
-> cpp::result<OutputFormat, Error> = 0;
struct OutputInfo {
std::size_t samples_written;
bool is_stream_finished;
};
/*
* Writes PCM samples to the given output buffer.
*/
virtual auto DecodeTo(std::span<sample::Sample> destination)
-> cpp::result<OutputInfo, Error> = 0;
};
auto CreateCodecForType(StreamType type) -> std::optional<ICodec*>;
} // namespace codecs
|