1a00e98661
--- more thorough commit message which was generated by the wonderful copilot AI tool: Refactor and enhance audio encoding and decoding pipelines - Introduced CodecUtils.h for utility functions related to audio codec selection, including sample format and bitrate clamping. - Added DecoderPipeline.h to manage audio decoding, including opening files and retrieving audio stream information. - Implemented EncoderPipeline.h to handle audio encoding, including encoder setup, resampling, and writing output files. - Created OutputPathBuilder.h to generate output file paths based on reencode job specifications. - Refactored SpectrogramWidget to improve OpenGL handling and ensure safe context usage. - Updated ReencodeDialog.h to enhance code readability and maintainability. - Improved error handling and logging throughout the audio processing components.
85 lines
2.5 KiB
C++
85 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include "FfmpegGuards.h"
|
|
|
|
#include <QString>
|
|
|
|
extern "C" {
|
|
#include <libavformat/avformat.h>
|
|
#include <libavcodec/avcodec.h>
|
|
}
|
|
|
|
namespace engine {
|
|
|
|
|
|
struct DecoderPipeline
|
|
{
|
|
FmtCtxIn fmtCtx; // owns AVFormatContext*
|
|
CodecCtxGuard ctx; // owns AVCodecContext*
|
|
AVStream *stream = nullptr; // non-owning; lifetime == fmtCtx
|
|
|
|
// open filelPath find audiostream and open decoder for it, returns false and sets errorout on any failure
|
|
bool open(const QString &filePath, QString *errorOut)
|
|
{
|
|
AVDictionary *opts = nullptr;
|
|
av_dict_set(&opts, "probesize", "5000000", 0);
|
|
av_dict_set(&opts, "analyzeduration", "5000000", 0);
|
|
int err = avformat_open_input(&fmtCtx.p,
|
|
filePath.toUtf8().constData(),
|
|
nullptr, &opts);
|
|
av_dict_free(&opts);
|
|
if (err < 0) {
|
|
if (errorOut) *errorOut = "Cannot open input file";
|
|
return false;
|
|
}
|
|
|
|
if (avformat_find_stream_info(fmtCtx.p, nullptr) < 0) {
|
|
if (errorOut) *errorOut = "Cannot read stream info";
|
|
return false;
|
|
}
|
|
|
|
const int audioIdx = av_find_best_stream(
|
|
fmtCtx.p, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
|
|
if (audioIdx < 0) {
|
|
if (errorOut) *errorOut = "No audio stream found";
|
|
return false;
|
|
}
|
|
|
|
stream = fmtCtx.p->streams[audioIdx];
|
|
|
|
const AVCodec *decoder =
|
|
avcodec_find_decoder(stream->codecpar->codec_id);
|
|
if (!decoder) {
|
|
if (errorOut) *errorOut = "No decoder for input codec";
|
|
return false;
|
|
}
|
|
|
|
ctx.p = avcodec_alloc_context3(decoder);
|
|
if (!ctx.p) {
|
|
if (errorOut) *errorOut = "OOM: decoder context";
|
|
return false;
|
|
}
|
|
|
|
avcodec_parameters_to_context(ctx.p, stream->codecpar);
|
|
ctx.p->pkt_timebase = stream->time_base;
|
|
|
|
if (avcodec_open2(ctx.p, decoder, nullptr) < 0) {
|
|
if (errorOut) *errorOut = "Cannot open decoder";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// accessors after successful open()
|
|
int audioStreamIndex() const
|
|
{
|
|
return stream ? static_cast<int>(stream - fmtCtx.p->streams[0]) : -1;
|
|
}
|
|
|
|
int channels() const { return ctx.p ? ctx.p->ch_layout.nb_channels : 0; }
|
|
int sampleRate() const { return ctx.p ? ctx.p->sample_rate : 0; }
|
|
};
|
|
|
|
} // namespace engine
|