Audaspace: add support for latest ffmpeg.

This commit is contained in:
2018-06-08 23:10:52 +02:00
parent 528dc6440b
commit dd2e187344
5 changed files with 276 additions and 88 deletions

View File

@@ -23,7 +23,9 @@ AUD_NAMESPACE_BEGIN
FFMPEG::FFMPEG() FFMPEG::FFMPEG()
{ {
#if LIBAVCODEC_VERSION_MAJOR < 58
av_register_all(); av_register_all();
#endif
} }
void FFMPEG::registerPlugin() void FFMPEG::registerPlugin()

View File

@@ -22,37 +22,37 @@
extern "C" { extern "C" {
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavformat/avio.h> #include <libavformat/avio.h>
#include <libavutil/avutil.h>
} }
AUD_NAMESPACE_BEGIN AUD_NAMESPACE_BEGIN
#if LIBAVCODEC_VERSION_MAJOR < 58
#define FFMPEG_OLD_CODE
#endif
int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer) int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
{ {
AVFrame* frame = nullptr; int buf_size = buffer.getSize();
int buf_pos = 0;
#ifdef FFMPEG_OLD_CODE
int got_frame; int got_frame;
int read_length; int read_length;
uint8_t* orig_data = packet.data; uint8_t* orig_data = packet.data;
int orig_size = packet.size; int orig_size = packet.size;
int buf_size = buffer.getSize();
int buf_pos = 0;
while(packet.size > 0) while(packet.size > 0)
{ {
got_frame = 0; got_frame = 0;
if(!frame) read_length = avcodec_decode_audio4(m_codecCtx, m_frame, &got_frame, &packet);
frame = av_frame_alloc();
else
av_frame_unref(frame);
read_length = avcodec_decode_audio4(m_codecCtx, frame, &got_frame, &packet);
if(read_length < 0) if(read_length < 0)
break; break;
if(got_frame) if(got_frame)
{ {
int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, frame->nb_samples, m_codecCtx->sample_fmt, 1); int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1);
if(buf_size - buf_pos < data_size) if(buf_size - buf_pos < data_size)
{ {
@@ -62,18 +62,18 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
if(m_tointerleave) if(m_tointerleave)
{ {
int single_size = data_size / m_codecCtx->channels / frame->nb_samples; int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples;
for(int channel = 0; channel < m_codecCtx->channels; channel++) for(int channel = 0; channel < m_codecCtx->channels; channel++)
{ {
for(int i = 0; i < frame->nb_samples; i++) for(int i = 0; i < m_frame->nb_samples; i++)
{ {
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size, std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
frame->data[channel] + i * single_size, single_size); m_frame->data[channel] + i * single_size, single_size);
} }
} }
} }
else else
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[0], data_size); std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size);
buf_pos += data_size; buf_pos += data_size;
} }
@@ -83,7 +83,42 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
packet.data = orig_data; packet.data = orig_data;
packet.size = orig_size; packet.size = orig_size;
av_free(frame); #else
avcodec_send_packet(m_codecCtx, &packet);
while(true)
{
auto ret = avcodec_receive_frame(m_codecCtx, m_frame);
if(ret != 0)
break;
int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1);
if(buf_size - buf_pos < data_size)
{
buffer.resize(buf_size + data_size, true);
buf_size += data_size;
}
if(m_tointerleave)
{
int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples;
for(int channel = 0; channel < m_codecCtx->channels; channel++)
{
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
m_frame->data[channel] + i * single_size, single_size);
}
}
}
else
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size);
buf_pos += data_size;
}
#endif
return buf_pos; return buf_pos;
} }
@@ -101,7 +136,11 @@ void FFMPEGReader::init()
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++) for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
{ {
#ifdef FFMPEG_OLD_CODE
if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#else
if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
#endif
&& (m_stream < 0)) && (m_stream < 0))
{ {
m_stream=i; m_stream=i;
@@ -112,12 +151,34 @@ void FFMPEGReader::init()
if(m_stream == -1) if(m_stream == -1)
AUD_THROW(FileException, "File couldn't be read, no audio stream found by ffmpeg."); AUD_THROW(FileException, "File couldn't be read, no audio stream found by ffmpeg.");
m_codecCtx = m_formatCtx->streams[m_stream]->codec;
// get a decoder and open it // get a decoder and open it
AVCodec* aCodec = avcodec_find_decoder(m_codecCtx->codec_id); #ifndef FFMPEG_OLD_CODE
AVCodec* aCodec = avcodec_find_decoder(m_formatCtx->streams[m_stream]->codecpar->codec_id);
if(!aCodec) if(!aCodec)
AUD_THROW(FileException, "File couldn't be read, no decoder found with ffmpeg."); AUD_THROW(FileException, "File couldn't be read, no decoder found with ffmpeg.");
#endif
m_frame = av_frame_alloc();
if(!m_frame)
AUD_THROW(FileException, "File couldn't be read, ffmpeg frame couldn't be allocated.");
#ifdef FFMPEG_OLD_CODE
m_codecCtx = m_formatCtx->streams[m_stream]->codec;
AVCodec* aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
#else
m_codecCtx = avcodec_alloc_context3(aCodec);
#endif
if(!m_codecCtx)
AUD_THROW(FileException, "File couldn't be read, ffmpeg context couldn't be allocated.");
#ifndef FFMPEG_OLD_CODE
if(avcodec_parameters_to_context(m_codecCtx, m_formatCtx->streams[m_stream]->codecpar) < 0)
AUD_THROW(FileException, "File couldn't be read, ffmpeg decoder parameters couldn't be copied to decoder context.");
#endif
if(avcodec_open2(m_codecCtx, aCodec, nullptr) < 0) if(avcodec_open2(m_codecCtx, aCodec, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be read, ffmpeg codec couldn't be opened."); AUD_THROW(FileException, "File couldn't be read, ffmpeg codec couldn't be opened.");
@@ -157,6 +218,8 @@ void FFMPEGReader::init()
FFMPEGReader::FFMPEGReader(std::string filename) : FFMPEGReader::FFMPEGReader(std::string filename) :
m_pkgbuf(), m_pkgbuf(),
m_formatCtx(nullptr), m_formatCtx(nullptr),
m_codecCtx(nullptr),
m_frame(nullptr),
m_aviocontext(nullptr), m_aviocontext(nullptr),
m_membuf(nullptr) m_membuf(nullptr)
{ {
@@ -177,12 +240,14 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) : FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
m_pkgbuf(), m_pkgbuf(),
m_codecCtx(nullptr),
m_frame(nullptr),
m_membuffer(buffer), m_membuffer(buffer),
m_membufferpos(0) m_membufferpos(0)
{ {
m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE)); m_membuf = reinterpret_cast<data_t*>(av_malloc(AV_INPUT_BUFFER_MIN_SIZE + AV_INPUT_BUFFER_PADDING_SIZE));
m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this, read_packet, nullptr, seek_packet); m_aviocontext = avio_alloc_context(m_membuf, AV_INPUT_BUFFER_MIN_SIZE, 0, this, read_packet, nullptr, seek_packet);
if(!m_aviocontext) if(!m_aviocontext)
{ {
@@ -212,7 +277,14 @@ FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
FFMPEGReader::~FFMPEGReader() FFMPEGReader::~FFMPEGReader()
{ {
if(m_frame)
av_frame_free(&m_frame);
#ifdef FFMPEG_OLD_CODE
avcodec_close(m_codecCtx); avcodec_close(m_codecCtx);
#else
if(m_codecCtx)
avcodec_free_context(&m_codecCtx);
#endif
avformat_close_input(&m_formatCtx); avformat_close_input(&m_formatCtx);
} }
@@ -312,7 +384,7 @@ void FFMPEGReader::seek(int position)
} }
} }
} }
av_free_packet(&packet); av_packet_unref(&packet);
} }
} }
else else
@@ -343,7 +415,7 @@ Specs FFMPEGReader::getSpecs() const
void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer) void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
{ {
// read packages and decode them // read packages and decode them
AVPacket packet; AVPacket packet = {};
int data_size = 0; int data_size = 0;
int pkgbuf_pos; int pkgbuf_pos;
int left = length; int left = length;
@@ -359,7 +431,7 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
data_size = std::min(pkgbuf_pos, left * sample_size); data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format)); m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format); buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size/sample_size; left -= data_size / sample_size;
} }
// for each frame read as long as there isn't enough data already // for each frame read as long as there isn't enough data already
@@ -375,9 +447,9 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
data_size = std::min(pkgbuf_pos, left * sample_size); data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format)); m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format); buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size/sample_size; left -= data_size / sample_size;
} }
av_free_packet(&packet); av_packet_unref(&packet);
} }
// read more data than necessary? // read more data than necessary?
if(pkgbuf_pos > data_size) if(pkgbuf_pos > data_size)

View File

@@ -79,6 +79,11 @@ private:
*/ */
AVCodecContext* m_codecCtx; AVCodecContext* m_codecCtx;
/**
* The AVFrame structure for using ffmpeg.
*/
AVFrame* m_frame;
/** /**
* The AVIOContext to read the data from. * The AVIOContext to read the data from.
*/ */

View File

@@ -27,6 +27,10 @@ extern "C" {
AUD_NAMESPACE_BEGIN AUD_NAMESPACE_BEGIN
#if LIBAVCODEC_VERSION_MAJOR < 58
#define FFMPEG_OLD_CODE
#endif
void FFMPEGWriter::encode() void FFMPEGWriter::encode()
{ {
sample_t* data = m_input_buffer.getBuffer(); sample_t* data = m_input_buffer.getBuffer();
@@ -58,82 +62,106 @@ void FFMPEGWriter::encode()
if(m_input_size) if(m_input_size)
m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_samples * m_specs.channels); m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_samples * m_specs.channels);
AVPacket packet; #ifdef FFMPEG_OLD_CODE
m_packet->data = nullptr;
m_packet->size = 0;
packet.data = nullptr; av_init_packet(m_packet);
packet.size = 0;
av_init_packet(&packet); av_frame_unref(m_frame);
AVFrame* frame = av_frame_alloc();
av_frame_unref(frame);
int got_packet; int got_packet;
#endif
frame->nb_samples = m_input_samples; m_frame->nb_samples = m_input_samples;
frame->format = m_codecCtx->sample_fmt; m_frame->format = m_codecCtx->sample_fmt;
frame->channel_layout = m_codecCtx->channel_layout; m_frame->channel_layout = m_codecCtx->channel_layout;
if(avcodec_fill_audio_frame(frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0) if(avcodec_fill_audio_frame(m_frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0)
AUD_THROW(FileException, "File couldn't be written, filling the audio frame failed with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, filling the audio frame failed with ffmpeg.");
AVRational sample_time = { 1, static_cast<int>(m_specs.rate) }; AVRational sample_time = { 1, static_cast<int>(m_specs.rate) };
frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time); m_frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time);
if(avcodec_encode_audio2(m_codecCtx, &packet, frame, &got_packet)) #ifdef FFMPEG_OLD_CODE
if(avcodec_encode_audio2(m_codecCtx, m_packet, m_frame, &got_packet))
{ {
av_frame_free(&frame);
AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");
} }
if(got_packet) if(got_packet)
{ {
packet.flags |= AV_PKT_FLAG_KEY; m_packet->flags |= AV_PKT_FLAG_KEY;
packet.stream_index = m_stream->index; m_packet->stream_index = m_stream->index;
if(av_write_frame(m_formatCtx, &packet) < 0) if(av_write_frame(m_formatCtx, m_packet) < 0)
{ {
av_free_packet(&packet); av_free_packet(m_packet);
av_frame_free(&frame);
AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg."); AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
} }
av_free_packet(&packet); av_free_packet(m_packet);
} }
#else
if(avcodec_send_frame(m_codecCtx, m_frame) < 0)
AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");
av_frame_free(&frame); while(avcodec_receive_packet(m_codecCtx, m_packet) == 0)
{
m_packet->stream_index = m_stream->index;
if(av_write_frame(m_formatCtx, m_packet) < 0)
AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
}
#endif
} }
void FFMPEGWriter::close() void FFMPEGWriter::close()
{ {
#ifdef FFMPEG_OLD_CODE
int got_packet = true; int got_packet = true;
while(got_packet) while(got_packet)
{ {
AVPacket packet; m_packet->data = nullptr;
m_packet->size = 0;
packet.data = nullptr; av_init_packet(m_packet);
packet.size = 0;
av_init_packet(&packet); if(avcodec_encode_audio2(m_codecCtx, m_packet, nullptr, &got_packet))
if(avcodec_encode_audio2(m_codecCtx, &packet, nullptr, &got_packet))
AUD_THROW(FileException, "File end couldn't be written, audio encoding failed with ffmpeg."); AUD_THROW(FileException, "File end couldn't be written, audio encoding failed with ffmpeg.");
if(got_packet) if(got_packet)
{ {
packet.flags |= AV_PKT_FLAG_KEY; m_packet->flags |= AV_PKT_FLAG_KEY;
packet.stream_index = m_stream->index; m_packet->stream_index = m_stream->index;
if(av_write_frame(m_formatCtx, &packet)) if(av_write_frame(m_formatCtx, m_packet))
{ {
av_free_packet(&packet); av_free_packet(m_packet);
AUD_THROW(FileException, "Final frames couldn't be writen to the file with ffmpeg."); AUD_THROW(FileException, "Final frames couldn't be writen to the file with ffmpeg.");
} }
av_free_packet(&packet); av_free_packet(m_packet);
} }
} }
#else
if(avcodec_send_frame(m_codecCtx, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");
while(avcodec_receive_packet(m_codecCtx, m_packet) == 0)
{
m_packet->stream_index = m_stream->index;
if(av_write_frame(m_formatCtx, m_packet) < 0)
AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
}
#endif
} }
FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate) : FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate) :
m_position(0), m_position(0),
m_specs(specs), m_specs(specs),
m_formatCtx(nullptr),
m_codecCtx(nullptr),
m_stream(nullptr),
m_packet(nullptr),
m_frame(nullptr),
m_input_samples(0), m_input_samples(0),
m_deinterleave(false) m_deinterleave(false)
{ {
@@ -142,75 +170,105 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
if(avformat_alloc_output_context2(&m_formatCtx, nullptr, formats[format], filename.c_str()) < 0) if(avformat_alloc_output_context2(&m_formatCtx, nullptr, formats[format], filename.c_str()) < 0)
AUD_THROW(FileException, "File couldn't be written, format couldn't be found with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, format couldn't be found with ffmpeg.");
m_outputFmt = m_formatCtx->oformat; AVOutputFormat* outputFmt = m_formatCtx->oformat;
if(!m_outputFmt) { if(!outputFmt) {
avformat_free_context(m_formatCtx); avformat_free_context(m_formatCtx);
AUD_THROW(FileException, "File couldn't be written, output format couldn't be found with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, output format couldn't be found with ffmpeg.");
} }
m_outputFmt->audio_codec = AV_CODEC_ID_NONE; outputFmt->audio_codec = AV_CODEC_ID_NONE;
switch(codec) switch(codec)
{ {
case CODEC_AAC: case CODEC_AAC:
m_outputFmt->audio_codec = AV_CODEC_ID_AAC; outputFmt->audio_codec = AV_CODEC_ID_AAC;
break; break;
case CODEC_AC3: case CODEC_AC3:
m_outputFmt->audio_codec = AV_CODEC_ID_AC3; outputFmt->audio_codec = AV_CODEC_ID_AC3;
break; break;
case CODEC_FLAC: case CODEC_FLAC:
m_outputFmt->audio_codec = AV_CODEC_ID_FLAC; outputFmt->audio_codec = AV_CODEC_ID_FLAC;
break; break;
case CODEC_MP2: case CODEC_MP2:
m_outputFmt->audio_codec = AV_CODEC_ID_MP2; outputFmt->audio_codec = AV_CODEC_ID_MP2;
break; break;
case CODEC_MP3: case CODEC_MP3:
m_outputFmt->audio_codec = AV_CODEC_ID_MP3; outputFmt->audio_codec = AV_CODEC_ID_MP3;
break; break;
case CODEC_OPUS: case CODEC_OPUS:
m_outputFmt->audio_codec = AV_CODEC_ID_OPUS; outputFmt->audio_codec = AV_CODEC_ID_OPUS;
break; break;
case CODEC_PCM: case CODEC_PCM:
switch(specs.format) switch(specs.format)
{ {
case FORMAT_U8: case FORMAT_U8:
m_outputFmt->audio_codec = AV_CODEC_ID_PCM_U8; outputFmt->audio_codec = AV_CODEC_ID_PCM_U8;
break; break;
case FORMAT_S16: case FORMAT_S16:
m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE; outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
break; break;
case FORMAT_S24: case FORMAT_S24:
m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE; outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE;
break; break;
case FORMAT_S32: case FORMAT_S32:
m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE; outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE;
break; break;
case FORMAT_FLOAT32: case FORMAT_FLOAT32:
m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE; outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE;
break; break;
case FORMAT_FLOAT64: case FORMAT_FLOAT64:
m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE; outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE;
break; break;
default: default:
m_outputFmt->audio_codec = AV_CODEC_ID_NONE; outputFmt->audio_codec = AV_CODEC_ID_NONE;
break; break;
} }
break; break;
case CODEC_VORBIS: case CODEC_VORBIS:
m_outputFmt->audio_codec = AV_CODEC_ID_VORBIS; outputFmt->audio_codec = AV_CODEC_ID_VORBIS;
break; break;
default: default:
m_outputFmt->audio_codec = AV_CODEC_ID_NONE; outputFmt->audio_codec = AV_CODEC_ID_NONE;
break;
}
uint64_t channel_layout = 0;
switch(m_specs.channels)
{
case CHANNELS_MONO:
channel_layout = AV_CH_LAYOUT_MONO;
break;
case CHANNELS_STEREO:
channel_layout = AV_CH_LAYOUT_STEREO;
break;
case CHANNELS_STEREO_LFE:
channel_layout = AV_CH_LAYOUT_2POINT1;
break;
case CHANNELS_SURROUND4:
channel_layout = AV_CH_LAYOUT_QUAD;
break;
case CHANNELS_SURROUND5:
channel_layout = AV_CH_LAYOUT_5POINT0_BACK;
break;
case CHANNELS_SURROUND51:
channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
break;
case CHANNELS_SURROUND61:
channel_layout = AV_CH_LAYOUT_6POINT1_BACK;
break;
case CHANNELS_SURROUND71:
channel_layout = AV_CH_LAYOUT_7POINT1;
break; break;
} }
try try
{ {
if(m_outputFmt->audio_codec == AV_CODEC_ID_NONE) if(outputFmt->audio_codec == AV_CODEC_ID_NONE)
AUD_THROW(FileException, "File couldn't be written, audio codec not found with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, audio codec not found with ffmpeg.");
AVCodec* codec = avcodec_find_encoder(m_outputFmt->audio_codec); AVCodec* codec = avcodec_find_encoder(outputFmt->audio_codec);
if(!codec) if(!codec)
AUD_THROW(FileException, "File couldn't be written, audio encoder couldn't be found with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, audio encoder couldn't be found with ffmpeg.");
@@ -220,7 +278,14 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
m_stream->id = m_formatCtx->nb_streams - 1; m_stream->id = m_formatCtx->nb_streams - 1;
#ifdef FFMPEG_OLD_CODE
m_codecCtx = m_stream->codec; m_codecCtx = m_stream->codec;
#else
m_codecCtx = avcodec_alloc_context3(codec);
#endif
if(!m_codecCtx)
AUD_THROW(FileException, "File couldn't be written, context creation failed with ffmpeg.");
switch(m_specs.format) switch(m_specs.format)
{ {
@@ -247,7 +312,7 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
} }
if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER) if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; m_codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
bool format_supported = false; bool format_supported = false;
@@ -328,9 +393,13 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
m_specs.rate = m_codecCtx->sample_rate; m_specs.rate = m_codecCtx->sample_rate;
m_codecCtx->codec_id = m_outputFmt->audio_codec; #ifdef FFMPEG_OLD_CODE
m_codecCtx->codec_id = outputFmt->audio_codec;
#endif
m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO; m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
m_codecCtx->bit_rate = bitrate; m_codecCtx->bit_rate = bitrate;
m_codecCtx->channel_layout = channel_layout;
m_codecCtx->channels = m_specs.channels; m_codecCtx->channels = m_specs.channels;
m_stream->time_base.num = m_codecCtx->time_base.num = 1; m_stream->time_base.num = m_codecCtx->time_base.num = 1;
m_stream->time_base.den = m_codecCtx->time_base.den = m_codecCtx->sample_rate; m_stream->time_base.den = m_codecCtx->time_base.den = m_codecCtx->sample_rate;
@@ -338,6 +407,11 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
if(avcodec_open2(m_codecCtx, codec, nullptr) < 0) if(avcodec_open2(m_codecCtx, codec, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be written, encoder couldn't be opened with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, encoder couldn't be opened with ffmpeg.");
#ifndef FFMPEG_OLD_CODE
if(avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx) < 0)
AUD_THROW(FileException, "File couldn't be written, codec parameters couldn't be copied to the context.");
#endif
int samplesize = std::max(int(AUD_SAMPLE_SIZE(m_specs)), AUD_DEVICE_SAMPLE_SIZE(m_specs)); int samplesize = std::max(int(AUD_SAMPLE_SIZE(m_specs)), AUD_DEVICE_SAMPLE_SIZE(m_specs));
if((m_input_size = m_codecCtx->frame_size)) if((m_input_size = m_codecCtx->frame_size))
@@ -346,13 +420,26 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE)) if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE))
AUD_THROW(FileException, "File couldn't be written, file opening failed with ffmpeg."); AUD_THROW(FileException, "File couldn't be written, file opening failed with ffmpeg.");
avformat_write_header(m_formatCtx, nullptr); if(avformat_write_header(m_formatCtx, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be written, writing the header failed.");
} }
catch(Exception&) catch(Exception&)
{ {
#ifndef FFMPEG_OLD_CODE
if(m_codecCtx)
avcodec_free_context(&m_codecCtx);
#endif
avformat_free_context(m_formatCtx); avformat_free_context(m_formatCtx);
throw; throw;
} }
#ifdef FFMPEG_OLD_CODE
m_packet = new AVPacket({});
#else
m_packet = av_packet_alloc();
#endif
m_frame = av_frame_alloc();
} }
FFMPEGWriter::~FFMPEGWriter() FFMPEGWriter::~FFMPEGWriter()
@@ -365,9 +452,26 @@ FFMPEGWriter::~FFMPEGWriter()
av_write_trailer(m_formatCtx); av_write_trailer(m_formatCtx);
avcodec_close(m_codecCtx); if(m_frame)
av_frame_free(&m_frame);
avio_close(m_formatCtx->pb); if(m_packet)
{
#ifdef FFMPEG_OLD_CODE
delete m_packet;
#else
av_packet_free(&m_packet);
#endif
}
#ifdef FFMPEG_OLD_CODE
avcodec_close(m_codecCtx);
#else
if(m_codecCtx)
avcodec_free_context(&m_codecCtx);
#endif
avio_closep(&m_formatCtx->pb);
avformat_free_context(m_formatCtx); avformat_free_context(m_formatCtx);
} }

View File

@@ -65,16 +65,21 @@ private:
*/ */
AVCodecContext* m_codecCtx; AVCodecContext* m_codecCtx;
/**
* The AVOutputFormat structure for using ffmpeg.
*/
AVOutputFormat* m_outputFmt;
/** /**
* The AVStream structure for using ffmpeg. * The AVStream structure for using ffmpeg.
*/ */
AVStream* m_stream; AVStream* m_stream;
/**
* The AVPacket structure for using ffmpeg.
*/
AVPacket* m_packet;
/**
* The AVFrame structure for using ffmpeg.
*/
AVFrame* m_frame;
/** /**
* The input buffer for the format converted data before encoding. * The input buffer for the format converted data before encoding.
*/ */