Skip to content
Extraits de code Groupes Projets
Vérifiée Valider c4af20c7 rédigé par Kubat's avatar Kubat
Parcourir les fichiers

UTILS: Use the C++ version of the decode audio file (because of RAII...)

parent 5bceafa8
Aucune branche associée trouvée
Aucune étiquette associée trouvée
1 requête de fusion!5Add AudioContext to AudioSubDocument
#include "AudioUtils.hh"
#include <assert.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libavcodec/avfft.h>
#define MAXPIXVALUE 7 /* Some magix AV magic stuff */
int
decodeAudioFile(const char *path, const int sample_rate, double **const data, size_t *const size)
{
AVPacket packet;
AVFormatContext *format = avformat_alloc_context();
struct SwrContext *swr = swr_alloc();
AVFrame *frame = av_frame_alloc();
int ret_code = -1;
ssize_t stream_index = -1;
AVStream *stream = NULL;
AVCodecContext *codec_ctx = NULL;
AVCodecParameters *codec_par = NULL;
AVCodec *codec = NULL;
if (!frame) {
fprintf(stderr, "Error allocating the frame\n");
goto exit_error;
}
/* Get format from audio file */
if (avformat_open_input(&format, path, NULL, NULL) != 0) {
fprintf(stderr, "Could not open file '%s'\n", path);
goto exit_error;
}
if (avformat_find_stream_info(format, NULL) < 0) {
fprintf(stderr, "Could not retrieve stream info from file '%s'\n", path);
return -1;
}
/* Find the index of the first audio stream */
for (unsigned int i = 0; i < format->nb_streams; i++) {
codec = avcodec_find_encoder(format->streams[i]->codecpar->codec_id);
if (codec->type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
break;
}
}
if (stream_index == -1) {
fprintf(stderr, "Could not retrieve audio stream from file '%s'\n", path);
goto exit_error;
}
stream = format->streams[stream_index];
/* Find & open codec */
codec_ctx = stream->codec;
codec_par = stream->codecpar;
codec = avcodec_find_decoder(codec_par->codec_id);
if (codec == NULL) {
fprintf(stderr, "Failed to find decoder for stream #%zu in file '%s'\n", stream_index,
path);
goto exit_error;
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
fprintf(stderr, "Failed to open decoder for stream #%zu in file '%s'\n", stream_index,
path);
goto exit_error;
}
/* Prepare resampler */
av_opt_set_int(swr, "in_channel_count", codec_ctx->channels, 0);
av_opt_set_int(swr, "out_channel_count", 1, 0);
av_opt_set_int(swr, "in_channel_layout", (int64_t)codec_ctx->channel_layout, 0);
av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_MONO, 0);
av_opt_set_int(swr, "in_sample_rate", codec_ctx->sample_rate, 0);
av_opt_set_int(swr, "out_sample_rate", sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", codec_ctx->sample_fmt, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
swr_init(swr);
if (!swr_is_initialized(swr)) {
fprintf(stderr, "Resampler has not been properly initialized\n");
goto exit_error;
}
/* Prepare to read data */
av_init_packet(&packet);
/* Iterate through frames */
*data = NULL;
*size = 0;
while (av_read_frame(format, &packet) >= 0) {
/* Decode one frame */
int gotFrame;
if (avcodec_decode_audio4(codec_ctx, frame, &gotFrame, &packet) < 0) {
break;
}
if (!gotFrame) {
continue;
}
/* Resample frames */
double *buffer;
av_samples_alloc((uint8_t **)&buffer, NULL, 1, frame->nb_samples, AV_SAMPLE_FMT_DBL, 0);
const int frame_count_int = swr_convert(swr, (uint8_t **)&buffer, frame->nb_samples,
(const uint8_t **)frame->data, frame->nb_samples);
assert(frame_count_int >= 0);
const size_t frame_count = (size_t)frame_count_int;
/* Append resampled frames to data */
*data = (double *)realloc(*data, (*size + (size_t)frame->nb_samples) * sizeof(double));
memcpy(*data + *size, buffer, frame_count * sizeof(double));
av_free(buffer);
*size += frame_count;
}
/* Clean up */
ret_code = 0;
exit_error:
if (frame != NULL)
av_frame_free(&frame);
if (swr != NULL)
swr_free(&swr);
if (codec_ctx != NULL)
avcodec_close(codec_ctx);
if (format != NULL)
avformat_free_context(format);
return ret_code;
}
......@@ -40,10 +40,20 @@ DecoderOption::getDecalage() const noexcept
RawImageData
RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path)
{
auto avFrameDeleter = [](AVFrame *ptr) noexcept -> void {
if (ptr)
av_frame_free(&ptr);
};
auto swrContenxtDeleter = [](SwrContext *swr) noexcept -> void {
if (swr)
swr_free(&swr);
};
AVPacket packet;
AVFormatContext *format = avformat_alloc_context();
struct SwrContext *swr = swr_alloc();
AVFrame *frame = av_frame_alloc();
std::unique_ptr<SwrContext, decltype(swrContenxtDeleter)> swr(swr_alloc(), swrContenxtDeleter);
std::unique_ptr<AVFrame, decltype(avFrameDeleter)> frame(av_frame_alloc(), avFrameDeleter);
ssize_t stream_index = -1;
AVStream *stream = nullptr;
AVCodecContext *codec_ctx = nullptr;
......@@ -98,16 +108,17 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path)
}
/* Prepare resampler */
av_opt_set_int(swr, "in_channel_count", codec_ctx->channels, 0);
av_opt_set_int(swr, "out_channel_count", 1, 0);
av_opt_set_int(swr, "in_channel_layout", static_cast<int64_t>(codec_ctx->channel_layout), 0);
av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_MONO, 0);
av_opt_set_int(swr, "in_sample_rate", codec_ctx->sample_rate, 0);
av_opt_set_int(swr, "out_sample_rate", opt.getSampleRate(), 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", codec_ctx->sample_fmt, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
swr_init(swr);
if (!swr_is_initialized(swr)) {
av_opt_set_int(swr.get(), "in_channel_count", codec_ctx->channels, 0);
av_opt_set_int(swr.get(), "out_channel_count", 1, 0);
av_opt_set_int(swr.get(), "in_channel_layout", static_cast<int64_t>(codec_ctx->channel_layout),
0);
av_opt_set_int(swr.get(), "out_channel_layout", AV_CH_LAYOUT_MONO, 0);
av_opt_set_int(swr.get(), "in_sample_rate", codec_ctx->sample_rate, 0);
av_opt_set_int(swr.get(), "out_sample_rate", opt.getSampleRate(), 0);
av_opt_set_sample_fmt(swr.get(), "in_sample_fmt", codec_ctx->sample_fmt, 0);
av_opt_set_sample_fmt(swr.get(), "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
swr_init(swr.get());
if (!swr_is_initialized(swr.get())) {
fprintf(stderr, "Resampler has not been properly initialized\n");
throw std::runtime_error("failed to initialize resampler");
}
......@@ -119,7 +130,7 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path)
while (av_read_frame(format, &packet) >= 0) {
/* Decode one frame */
int gotFrame;
if (avcodec_decode_audio4(codec_ctx, frame, &gotFrame, &packet) < 0) {
if (avcodec_decode_audio4(codec_ctx, frame.get(), &gotFrame, &packet) < 0) {
break;
}
if (!gotFrame) {
......@@ -129,7 +140,7 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path)
/* Resample frames */
double *buffer;
av_samples_alloc((uint8_t **)&buffer, NULL, 1, frame->nb_samples, AV_SAMPLE_FMT_DBL, 0);
const int frame_count_int = swr_convert(swr, (uint8_t **)&buffer, frame->nb_samples,
const int frame_count_int = swr_convert(swr.get(), (uint8_t **)&buffer, frame->nb_samples,
(const uint8_t **)frame->data, frame->nb_samples);
assert(frame_count_int >= 0);
const size_t frame_count = (size_t)frame_count_int;
......@@ -141,12 +152,6 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path)
size += frame_count;
}
/* Clean up */
exit_error:
if (frame != NULL)
av_frame_free(&frame);
if (swr != NULL)
swr_free(&swr);
if (codec_ctx != NULL)
avcodec_close(codec_ctx);
if (format != NULL)
......
#ifndef VIVY_AUDIOUTILS_H
#define VIVY_AUDIOUTILS_H
#ifdef __cplusplus
extern "C" {
#ifndef __cplusplus
#error "This is a C++ header"
#endif
extern "C" {
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libavcodec/avfft.h>
int decodeAudioFile(const char *path, const int sample_rate, double **const data,
size_t *const size);
#ifdef __cplusplus
}
#endif
/* C++ only code */
#ifdef __cplusplus
#include <QtGlobal>
#include <memory.h>
......@@ -78,6 +70,4 @@ public:
};
}
#endif
#endif // VIVY_AUDIOUTILS_H
......@@ -31,23 +31,8 @@ AudioVisualizer::fromFile(const QString &filename)
if (filename.isEmpty())
return nullptr;
const int sample_rate = 44100;
double *data = nullptr;
size_t size = 0;
int rc = decodeAudioFile(filename.toStdString().c_str(), sample_rate, &data, &size);
auto data_deleter = [](double *ptr) -> void {
if (ptr != nullptr) {
av_free(ptr);
}
};
std::unique_ptr<double, decltype(data_deleter)> data_holder(data, data_deleter);
if (rc != 0) {
printf("ERROR\n");
return nullptr;
}
Utils::RawImageData rawImage(Utils::DecoderOption{}, data, size);
Utils::RawImageData rawImage =
Utils::RawImageData::fromAudioFile(Utils::DecoderOption{}, filename);
QImage img = QImage(rawImage.releasePixels(), rawImage.getWidth(), rawImage.getHeight(),
rawImage.getWidth(), QImage::Format_Grayscale8,
Utils::RawImageData::pixelsDeleter, rawImage.releasePixels())
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter