spek-audio.cc (11740B)
1 #include <assert.h> 2 3 extern "C" { 4 #define __STDC_CONSTANT_MACROS 5 #define __STDC_LIMIT_MACROS 6 #include <libavformat/avformat.h> 7 #include <libavcodec/avcodec.h> 8 #include <libavutil/mathematics.h> 9 } 10 11 #include "spek-audio.h" 12 13 class AudioFileImpl : public AudioFile 14 { 15 public: 16 AudioFileImpl( 17 AudioError error, AVFormatContext *format_context, AVCodecContext *codec_context, 18 int audio_stream, const std::string& codec_name, int bit_rate, int sample_rate, 19 int bits_per_sample, int streams, int channels, double duration 20 ); 21 ~AudioFileImpl() override; 22 void start(int channel, int samples) override; 23 int read() override; 24 25 AudioError get_error() const override { return this->error; } 26 std::string get_codec_name() const override { return this->codec_name; } 27 int get_bit_rate() const override { return this->bit_rate; } 28 int get_sample_rate() const override { return this->sample_rate; } 29 int get_bits_per_sample() const override { return this->bits_per_sample; } 30 int get_streams() const override { return this->streams; } 31 int get_channels() const override { return this->channels; } 32 double get_duration() const override { return this->duration; } 33 const float *get_buffer() const override { return this->buffer; } 34 int64_t get_frames_per_interval() const override { return this->frames_per_interval; } 35 int64_t get_error_per_interval() const override { return this->error_per_interval; } 36 int64_t get_error_base() const override { return this->error_base; } 37 38 private: 39 AudioError error; 40 AVFormatContext *format_context; 41 AVCodecContext *codec_context; 42 int audio_stream; 43 std::string codec_name; 44 int bit_rate; 45 int sample_rate; 46 int bits_per_sample; 47 int streams; 48 int channels; 49 double duration; 50 51 int channel; 52 53 AVPacket packet; 54 int offset; 55 AVFrame *frame; 56 int buffer_len; 57 float *buffer; 58 // TODO: these guys don't belong here, move them somewhere else when revamping the pipeline 59 int64_t frames_per_interval; 60 int64_t error_per_interval; 61 int64_t error_base; 62 }; 63 64 65 Audio::Audio() 66 { 67 av_register_all(); 68 } 69 70 Audio::~Audio() 71 { 72 // This prevents a memory leak. 73 av_lockmgr_register(nullptr); 74 } 75 76 std::unique_ptr<AudioFile> Audio::open(const std::string& file_name, int stream) 77 { 78 AudioError error = AudioError::OK; 79 80 AVFormatContext *format_context = nullptr; 81 if (avformat_open_input(&format_context, file_name.c_str(), nullptr, nullptr) != 0) { 82 error = AudioError::CANNOT_OPEN_FILE; 83 } 84 85 if (!error && avformat_find_stream_info(format_context, nullptr) < 0) { 86 // 24-bit APE returns an error but parses the stream info just fine. 87 // TODO: old comment, verify 88 if (format_context->nb_streams <= 0) { 89 error = AudioError::NO_STREAMS; 90 } 91 } 92 93 int audio_stream = -1; 94 int streams = 0; 95 if (!error) { 96 for (unsigned int i = 0; i < format_context->nb_streams; i++) { 97 if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { 98 if (stream == streams) { 99 audio_stream = i; 100 } 101 streams++; 102 } 103 } 104 if (audio_stream == -1) { 105 error = AudioError::NO_AUDIO; 106 } 107 } 108 109 AVStream *avstream = nullptr; 110 AVCodecParameters *codecpar = nullptr; 111 AVCodec *codec = nullptr; 112 if (!error) { 113 avstream = format_context->streams[audio_stream]; 114 codecpar = avstream->codecpar; 115 codec = avcodec_find_decoder(codecpar->codec_id); 116 if (!codec) { 117 error = AudioError::NO_DECODER; 118 } 119 } 120 121 std::string codec_name; 122 int bit_rate = 0; 123 int sample_rate = 0; 124 int bits_per_sample = 0; 125 int channels = 0; 126 double duration = 0; 127 if (!error) { 128 // We can already fill in the stream info even if the codec won't be able to open it. 129 codec_name = codec->long_name; 130 bit_rate = codecpar->bit_rate; 131 sample_rate = codecpar->sample_rate; 132 bits_per_sample = codecpar->bits_per_raw_sample; 133 if (!bits_per_sample) { 134 // APE uses bpcs, FLAC uses bprs. 135 bits_per_sample = codecpar->bits_per_coded_sample; 136 } 137 if (codecpar->codec_id == AV_CODEC_ID_AAC || 138 codecpar->codec_id == AV_CODEC_ID_MUSEPACK8 || 139 codecpar->codec_id == AV_CODEC_ID_WMAV1 || 140 codecpar->codec_id == AV_CODEC_ID_WMAV2) { 141 // These decoders set both bps and bitrate. 142 bits_per_sample = 0; 143 } 144 if (bits_per_sample) { 145 bit_rate = 0; 146 } 147 channels = codecpar->channels; 148 149 if (avstream->duration != AV_NOPTS_VALUE) { 150 duration = avstream->duration * av_q2d(avstream->time_base); 151 } else if (format_context->duration != AV_NOPTS_VALUE) { 152 duration = format_context->duration / (double) AV_TIME_BASE; 153 } else { 154 error = AudioError::NO_DURATION; 155 } 156 157 if (!error && channels <= 0) { 158 error = AudioError::NO_CHANNELS; 159 } 160 } 161 162 AVCodecContext *codec_context = nullptr; 163 if (!error) { 164 error = AudioError::CANNOT_OPEN_DECODER; 165 // Allocate a codec context for the decoder. 166 codec_context = avcodec_alloc_context3(codec); 167 if (codec_context) { 168 // Copy codec parameters from input stream to output codec context. 169 if (avcodec_parameters_to_context(codec_context, codecpar) == 0) { 170 // Finally, init the decoder. 171 if (avcodec_open2(codec_context, codec, nullptr) == 0) { 172 error = AudioError::OK; 173 } 174 } 175 } 176 } 177 178 if (!error) { 179 AVSampleFormat fmt = (AVSampleFormat)codecpar->format; 180 if (fmt != AV_SAMPLE_FMT_S16 && fmt != AV_SAMPLE_FMT_S16P && 181 fmt != AV_SAMPLE_FMT_S32 && fmt != AV_SAMPLE_FMT_S32P && 182 fmt != AV_SAMPLE_FMT_FLT && fmt != AV_SAMPLE_FMT_FLTP && 183 fmt != AV_SAMPLE_FMT_DBL && fmt != AV_SAMPLE_FMT_DBLP ) { 184 error = AudioError::BAD_SAMPLE_FORMAT; 185 } 186 } 187 188 return std::unique_ptr<AudioFile>(new AudioFileImpl( 189 error, format_context, codec_context, 190 audio_stream, codec_name, bit_rate, sample_rate, 191 bits_per_sample, streams, channels, duration 192 )); 193 } 194 195 AudioFileImpl::AudioFileImpl( 196 AudioError error, AVFormatContext *format_context, AVCodecContext *codec_context, 197 int audio_stream, const std::string& codec_name, int bit_rate, int sample_rate, 198 int bits_per_sample, int streams, int channels, double duration 199 ) : 200 error(error), format_context(format_context), codec_context(codec_context), 201 audio_stream(audio_stream), codec_name(codec_name), bit_rate(bit_rate), 202 sample_rate(sample_rate), 203 bits_per_sample(bits_per_sample), streams(streams), channels(channels), duration(duration) 204 { 205 av_init_packet(&this->packet); 206 this->packet.data = nullptr; 207 this->packet.size = 0; 208 this->offset = 0; 209 this->frame = av_frame_alloc(); 210 this->buffer_len = 0; 211 this->buffer = nullptr; 212 this->frames_per_interval = 0; 213 this->error_per_interval = 0; 214 this->error_base = 0; 215 } 216 217 AudioFileImpl::~AudioFileImpl() 218 { 219 if (this->buffer) { 220 av_freep(&this->buffer); 221 } 222 if (this->frame) { 223 av_frame_free(&this->frame); 224 } 225 if (this->packet.data) { 226 this->packet.data -= this->offset; 227 this->packet.size += this->offset; 228 this->offset = 0; 229 av_packet_unref(&this->packet); 230 } 231 if (this->codec_context) { 232 avcodec_free_context(&codec_context); 233 } 234 if (this->format_context) { 235 avformat_close_input(&this->format_context); 236 } 237 } 238 239 void AudioFileImpl::start(int channel, int samples) 240 { 241 this->channel = channel; 242 if (channel < 0 || channel >= this->channels) { 243 assert(false); 244 this->error = AudioError::NO_CHANNELS; 245 } 246 247 AVStream *stream = this->format_context->streams[this->audio_stream]; 248 int64_t rate = this->sample_rate * (int64_t)stream->time_base.num; 249 int64_t duration = (int64_t)(this->duration * stream->time_base.den / stream->time_base.num); 250 this->error_base = samples * (int64_t)stream->time_base.den; 251 this->frames_per_interval = av_rescale_rnd(duration, rate, this->error_base, AV_ROUND_DOWN); 252 this->error_per_interval = (duration * rate) % this->error_base; 253 } 254 255 int AudioFileImpl::read() 256 { 257 if (!!this->error) { 258 return -1; 259 } 260 261 for (;;) { 262 while (this->packet.size > 0) { 263 av_frame_unref(this->frame); 264 int got_frame = 0; 265 int len = avcodec_decode_audio4( 266 this->codec_context, this->frame, &got_frame, &this->packet 267 ); 268 if (len < 0) { 269 // Error, skip the frame. 270 break; 271 } 272 this->packet.data += len; 273 this->packet.size -= len; 274 this->offset += len; 275 if (!got_frame) { 276 // No data yet, get more frames. 277 continue; 278 } 279 // We have data, return it and come back for more later. 280 int samples = this->frame->nb_samples; 281 if (samples > this->buffer_len) { 282 this->buffer = static_cast<float*>( 283 av_realloc(this->buffer, samples * sizeof(float)) 284 ); 285 this->buffer_len = samples; 286 } 287 288 AVSampleFormat format = static_cast<AVSampleFormat>(this->frame->format); 289 int is_planar = av_sample_fmt_is_planar(format); 290 for (int sample = 0; sample < samples; ++sample) { 291 uint8_t *data; 292 int offset; 293 if (is_planar) { 294 data = this->frame->data[this->channel]; 295 offset = sample; 296 } else { 297 data = this->frame->data[0]; 298 offset = sample * this->channels; 299 } 300 float value; 301 switch (format) { 302 case AV_SAMPLE_FMT_S16: 303 case AV_SAMPLE_FMT_S16P: 304 value = reinterpret_cast<int16_t*>(data)[offset] 305 / static_cast<float>(INT16_MAX); 306 break; 307 case AV_SAMPLE_FMT_S32: 308 case AV_SAMPLE_FMT_S32P: 309 value = reinterpret_cast<int32_t*>(data)[offset] 310 / static_cast<float>(INT32_MAX); 311 break; 312 case AV_SAMPLE_FMT_FLT: 313 case AV_SAMPLE_FMT_FLTP: 314 value = reinterpret_cast<float*>(data)[offset]; 315 break; 316 case AV_SAMPLE_FMT_DBL: 317 case AV_SAMPLE_FMT_DBLP: 318 value = reinterpret_cast<double*>(data)[offset]; 319 break; 320 default: 321 value = 0.0f; 322 break; 323 } 324 this->buffer[sample] = value; 325 } 326 return samples; 327 } 328 if (this->packet.data) { 329 this->packet.data -= this->offset; 330 this->packet.size += this->offset; 331 this->offset = 0; 332 av_packet_unref(&this->packet); 333 } 334 335 int res = 0; 336 while ((res = av_read_frame(this->format_context, &this->packet)) >= 0) { 337 if (this->packet.stream_index == this->audio_stream) { 338 break; 339 } 340 av_packet_unref(&this->packet); 341 } 342 if (res < 0) { 343 // End of file or error. 344 return 0; 345 } 346 } 347 }