diff options
Diffstat (limited to 'intern/audaspace/ffmpeg')
-rw-r--r-- | intern/audaspace/ffmpeg/AUD_FFMPEGFactory.cpp | 55 | ||||
-rw-r--r-- | intern/audaspace/ffmpeg/AUD_FFMPEGFactory.h | 78 | ||||
-rw-r--r-- | intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp | 483 | ||||
-rw-r--r-- | intern/audaspace/ffmpeg/AUD_FFMPEGReader.h | 169 | ||||
-rw-r--r-- | intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp | 395 | ||||
-rw-r--r-- | intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h | 160 |
6 files changed, 0 insertions, 1340 deletions
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGFactory.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGFactory.cpp deleted file mode 100644 index 403c367fccc..00000000000 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGFactory.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * Copyright 2009-2011 Jörg Hermann Müller - * - * This file is part of AudaSpace. - * - * Audaspace is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * AudaSpace is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Audaspace; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file audaspace/ffmpeg/AUD_FFMPEGFactory.cpp - * \ingroup audffmpeg - */ - - -// needed for INT64_C -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif - -#include "AUD_FFMPEGFactory.h" -#include "AUD_FFMPEGReader.h" - -AUD_FFMPEGFactory::AUD_FFMPEGFactory(std::string filename) : - m_filename(filename) -{ -} - -AUD_FFMPEGFactory::AUD_FFMPEGFactory(const data_t* buffer, int size) : - m_buffer(new AUD_Buffer(size)) -{ - memcpy(m_buffer->getBuffer(), buffer, size); -} - -boost::shared_ptr<AUD_IReader> AUD_FFMPEGFactory::createReader() -{ - if(m_buffer.get()) - return boost::shared_ptr<AUD_IReader>(new AUD_FFMPEGReader(m_buffer)); - else - return boost::shared_ptr<AUD_IReader>(new AUD_FFMPEGReader(m_filename)); -} diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGFactory.h b/intern/audaspace/ffmpeg/AUD_FFMPEGFactory.h deleted file mode 100644 index 23d0f07ed0b..00000000000 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGFactory.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * Copyright 2009-2011 Jörg Hermann Müller - * - * This file is part of AudaSpace. - * - * Audaspace is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * AudaSpace is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Audaspace; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file audaspace/ffmpeg/AUD_FFMPEGFactory.h - * \ingroup audffmpeg - */ - - -#ifndef __AUD_FFMPEGFACTORY_H__ -#define __AUD_FFMPEGFACTORY_H__ - -#include "AUD_IFactory.h" -#include "AUD_Buffer.h" - -#include <string> -#include <boost/shared_ptr.hpp> - -/** - * This factory reads a sound file via ffmpeg. - * \warning Notice that the needed formats and codecs have to be registered - * for ffmpeg before this class can be used. - */ -class AUD_FFMPEGFactory : public AUD_IFactory -{ -private: - /** - * The filename of the sound source file. - */ - const std::string m_filename; - - /** - * The buffer to read from. - */ - boost::shared_ptr<AUD_Buffer> m_buffer; - - // hide copy constructor and operator= - AUD_FFMPEGFactory(const AUD_FFMPEGFactory&); - AUD_FFMPEGFactory& operator=(const AUD_FFMPEGFactory&); - -public: - /** - * Creates a new factory. - * \param filename The sound file path. - */ - AUD_FFMPEGFactory(std::string filename); - - /** - * Creates a new factory. - * \param buffer The buffer to read from. - * \param size The size of the buffer. - */ - AUD_FFMPEGFactory(const data_t* buffer, int size); - - virtual boost::shared_ptr<AUD_IReader> createReader(); -}; - -#endif //__AUD_FFMPEGFACTORY_H__ diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp deleted file mode 100644 index e9eea195208..00000000000 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * Copyright 2009-2011 Jörg Hermann Müller - * - * This file is part of AudaSpace. - * - * Audaspace is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * AudaSpace is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Audaspace; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file audaspace/ffmpeg/AUD_FFMPEGReader.cpp - * \ingroup audffmpeg - */ - - -// needed for INT64_C -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif - -#include "AUD_FFMPEGReader.h" - -extern "C" { -#include <libavcodec/avcodec.h> -#include <libavformat/avformat.h> -#include <libavformat/avio.h> -#include "ffmpeg_compat.h" -} - -int AUD_FFMPEGReader::decode(AVPacket& packet, AUD_Buffer& buffer) -{ -#ifdef FFMPEG_HAVE_DECODE_AUDIO4 - AVFrame* frame = NULL; - int got_frame; - int read_length; - uint8_t* orig_data = packet.data; - int orig_size = packet.size; - - int buf_size = buffer.getSize(); - int buf_pos = 0; - - while(packet.size > 0) - { - got_frame = 0; - - if(!frame) - frame = av_frame_alloc(); - else - av_frame_unref(frame); - - read_length = avcodec_decode_audio4(m_codecCtx, frame, &got_frame, &packet); - if(read_length < 0) - break; - - if(got_frame) - { - int data_size = av_samples_get_buffer_size(NULL, m_codecCtx->channels, 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 / frame->nb_samples; - for(int channel = 0; channel < m_codecCtx->channels; channel++) - { - for(int i = 0; i < frame->nb_samples; i++) - { - memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size, - frame->data[channel] + i * single_size, single_size); - } - } - } - else - memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[0], data_size); - - buf_pos += data_size; - } - packet.size -= read_length; - packet.data += read_length; - } - - packet.data = orig_data; - packet.size = orig_size; - av_free(frame); - - return buf_pos; -#else - // save packet parameters - uint8_t *audio_pkg_data = packet.data; - int audio_pkg_size = packet.size; - - int buf_size = buffer.getSize(); - int buf_pos = 0; - - int read_length, data_size; - - AVPacket tmp_pkt; - - av_init_packet(&tmp_pkt); - - // as long as there is still data in the package - while(audio_pkg_size > 0) - { - // resize buffer if needed - if(buf_size - buf_pos < AVCODEC_MAX_AUDIO_FRAME_SIZE) - { - buffer.resize(buf_size + AVCODEC_MAX_AUDIO_FRAME_SIZE, true); - buf_size += AVCODEC_MAX_AUDIO_FRAME_SIZE; - } - - // read samples from the packet - data_size = buf_size - buf_pos; - - tmp_pkt.data = audio_pkg_data; - tmp_pkt.size = audio_pkg_size; - - read_length = avcodec_decode_audio3( - m_codecCtx, - (int16_t*)(((data_t*)buffer.getBuffer()) + buf_pos), - &data_size, &tmp_pkt); - - // read error, next packet! - if(read_length < 0) - break; - - buf_pos += data_size; - - // move packet parameters - audio_pkg_data += read_length; - audio_pkg_size -= read_length; - } - - return buf_pos; -#endif -} - -static const char* streaminfo_error = "AUD_FFMPEGReader: Stream info couldn't " - "be found."; -static const char* noaudio_error = "AUD_FFMPEGReader: File doesn't include an " - "audio stream."; -static const char* nodecoder_error = "AUD_FFMPEGReader: No decoder found for " - "the audio stream."; -static const char* codecopen_error = "AUD_FFMPEGReader: Codec couldn't be " - "opened."; -static const char* format_error = "AUD_FFMPEGReader: Unsupported sample " - "format."; - -void AUD_FFMPEGReader::init() -{ - m_position = 0; - m_pkgbuf_left = 0; - - if(avformat_find_stream_info(m_formatCtx, NULL) < 0) - AUD_THROW(AUD_ERROR_FFMPEG, streaminfo_error); - - // find audio stream and codec - m_stream = -1; - - for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++) - { - if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - && (m_stream < 0)) - { - m_stream=i; - break; - } - } - - if(m_stream == -1) - AUD_THROW(AUD_ERROR_FFMPEG, noaudio_error); - - m_codecCtx = m_formatCtx->streams[m_stream]->codec; - - // get a decoder and open it - AVCodec *aCodec = avcodec_find_decoder(m_codecCtx->codec_id); - if(!aCodec) - AUD_THROW(AUD_ERROR_FFMPEG, nodecoder_error); - - if(avcodec_open2(m_codecCtx, aCodec, NULL) < 0) - AUD_THROW(AUD_ERROR_FFMPEG, codecopen_error); - - // XXX this prints file information to stdout: - //dump_format(m_formatCtx, 0, NULL, 0); - - m_specs.channels = (AUD_Channels) m_codecCtx->channels; - m_tointerleave = av_sample_fmt_is_planar(m_codecCtx->sample_fmt); - - switch(av_get_packed_sample_fmt(m_codecCtx->sample_fmt)) - { - case AV_SAMPLE_FMT_U8: - m_convert = AUD_convert_u8_float; - m_specs.format = AUD_FORMAT_U8; - break; - case AV_SAMPLE_FMT_S16: - m_convert = AUD_convert_s16_float; - m_specs.format = AUD_FORMAT_S16; - break; - case AV_SAMPLE_FMT_S32: - m_convert = AUD_convert_s32_float; - m_specs.format = AUD_FORMAT_S32; - break; - case AV_SAMPLE_FMT_FLT: - m_convert = AUD_convert_copy<float>; - m_specs.format = AUD_FORMAT_FLOAT32; - break; - case AV_SAMPLE_FMT_DBL: - m_convert = AUD_convert_double_float; - m_specs.format = AUD_FORMAT_FLOAT64; - break; - default: - AUD_THROW(AUD_ERROR_FFMPEG, format_error); - } - - m_specs.rate = (AUD_SampleRate) m_codecCtx->sample_rate; -} - -static const char* fileopen_error = "AUD_FFMPEGReader: File couldn't be " - "opened."; - -AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) : - m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), - m_formatCtx(NULL), - m_aviocontext(NULL), - m_membuf(NULL) -{ - // open file - if(avformat_open_input(&m_formatCtx, filename.c_str(), NULL, NULL)!=0) - AUD_THROW(AUD_ERROR_FILE, fileopen_error); - - try - { - init(); - } - catch(AUD_Exception&) - { - avformat_close_input(&m_formatCtx); - throw; - } -} - -static const char* streamopen_error = "AUD_FFMPEGReader: Stream couldn't be " - "opened."; - -AUD_FFMPEGReader::AUD_FFMPEGReader(boost::shared_ptr<AUD_Buffer> buffer) : - m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), - m_membuffer(buffer), - m_membufferpos(0) -{ - m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE)); - - m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this, - read_packet, NULL, seek_packet); - - if(!m_aviocontext) - { - av_free(m_aviocontext); - AUD_THROW(AUD_ERROR_FILE, fileopen_error); - } - - m_formatCtx = avformat_alloc_context(); - m_formatCtx->pb = m_aviocontext; - if(avformat_open_input(&m_formatCtx, "", NULL, NULL)!=0) - { - av_free(m_aviocontext); - AUD_THROW(AUD_ERROR_FILE, streamopen_error); - } - - try - { - init(); - } - catch(AUD_Exception&) - { - avformat_close_input(&m_formatCtx); - av_free(m_aviocontext); - throw; - } -} - -AUD_FFMPEGReader::~AUD_FFMPEGReader() -{ - avcodec_close(m_codecCtx); - avformat_close_input(&m_formatCtx); -} - -int AUD_FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size) -{ - AUD_FFMPEGReader* reader = reinterpret_cast<AUD_FFMPEGReader*>(opaque); - - int size = AUD_MIN(buf_size, reader->m_membuffer->getSize() - reader->m_membufferpos); - - if(size < 0) - return -1; - - memcpy(buf, ((data_t*)reader->m_membuffer->getBuffer()) + reader->m_membufferpos, size); - reader->m_membufferpos += size; - - return size; -} - -int64_t AUD_FFMPEGReader::seek_packet(void* opaque, int64_t offset, int whence) -{ - AUD_FFMPEGReader* reader = reinterpret_cast<AUD_FFMPEGReader*>(opaque); - - switch(whence) - { - case SEEK_SET: - reader->m_membufferpos = 0; - break; - case SEEK_END: - reader->m_membufferpos = reader->m_membuffer->getSize(); - break; - case AVSEEK_SIZE: - return reader->m_membuffer->getSize(); - } - - return (reader->m_membufferpos += offset); -} - -bool AUD_FFMPEGReader::isSeekable() const -{ - return true; -} - -void AUD_FFMPEGReader::seek(int position) -{ - if(position >= 0) - { - uint64_t st_time = m_formatCtx->start_time; - uint64_t seek_pos = ((uint64_t)position) * ((uint64_t)AV_TIME_BASE) / ((uint64_t)m_specs.rate); - - if (st_time != AV_NOPTS_VALUE) { - seek_pos += st_time; - } - - double pts_time_base = - av_q2d(m_formatCtx->streams[m_stream]->time_base); - uint64_t pts_st_time = - ((st_time != AV_NOPTS_VALUE) ? st_time : 0) - / pts_time_base / (uint64_t) AV_TIME_BASE; - - // a value < 0 tells us that seeking failed - if(av_seek_frame(m_formatCtx, -1, seek_pos, - AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0) - { - avcodec_flush_buffers(m_codecCtx); - m_position = position; - - AVPacket packet; - bool search = true; - - while(search && av_read_frame(m_formatCtx, &packet) >= 0) - { - // is it a frame from the audio stream? - if(packet.stream_index == m_stream) - { - // decode the package - m_pkgbuf_left = decode(packet, m_pkgbuf); - search = false; - - // check position - if(packet.pts != AV_NOPTS_VALUE) - { - // calculate real position, and read to frame! - m_position = (packet.pts - - pts_st_time) * pts_time_base * m_specs.rate; - - if(m_position < position) - { - // read until we're at the right position - int length = AUD_DEFAULT_BUFFER_SIZE; - AUD_Buffer buffer(length * AUD_SAMPLE_SIZE(m_specs)); - bool eos; - for(int len = position - m_position; len > 0; len -= AUD_DEFAULT_BUFFER_SIZE) - { - if(len < AUD_DEFAULT_BUFFER_SIZE) - length = len; - read(length, eos, buffer.getBuffer()); - } - } - } - } - av_free_packet(&packet); - } - } - else - { - fprintf(stderr, "seeking failed!\n"); - // Seeking failed, do nothing. - } - } -} - -int AUD_FFMPEGReader::getLength() const -{ - // return approximated remaning size - return (int)((m_formatCtx->duration * m_codecCtx->sample_rate) - / AV_TIME_BASE)-m_position; -} - -int AUD_FFMPEGReader::getPosition() const -{ - return m_position; -} - -AUD_Specs AUD_FFMPEGReader::getSpecs() const -{ - return m_specs.specs; -} - -void AUD_FFMPEGReader::read(int& length, bool& eos, sample_t* buffer) -{ - // read packages and decode them - AVPacket packet; - int data_size = 0; - int pkgbuf_pos; - int left = length; - int sample_size = AUD_DEVICE_SAMPLE_SIZE(m_specs); - - sample_t* buf = buffer; - pkgbuf_pos = m_pkgbuf_left; - m_pkgbuf_left = 0; - - // there may still be data in the buffer from the last call - if(pkgbuf_pos > 0) - { - data_size = AUD_MIN(pkgbuf_pos, left * sample_size); - 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); - left -= data_size/sample_size; - } - - // for each frame read as long as there isn't enough data already - while((left > 0) && (av_read_frame(m_formatCtx, &packet) >= 0)) - { - // is it a frame from the audio stream? - if(packet.stream_index == m_stream) - { - // decode the package - pkgbuf_pos = decode(packet, m_pkgbuf); - - // copy to output buffer - data_size = AUD_MIN(pkgbuf_pos, left * sample_size); - 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); - left -= data_size/sample_size; - } - av_free_packet(&packet); - } - // read more data than necessary? - if(pkgbuf_pos > data_size) - { - m_pkgbuf_left = pkgbuf_pos-data_size; - memmove(m_pkgbuf.getBuffer(), - ((data_t*)m_pkgbuf.getBuffer())+data_size, - pkgbuf_pos-data_size); - } - - if((eos = (left > 0))) - length -= left; - - m_position += length; -} diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h deleted file mode 100644 index 377086e2625..00000000000 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * Copyright 2009-2011 Jörg Hermann Müller - * - * This file is part of AudaSpace. - * - * Audaspace is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * AudaSpace is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Audaspace; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file audaspace/ffmpeg/AUD_FFMPEGReader.h - * \ingroup audffmpeg - */ - - -#ifndef __AUD_FFMPEGREADER_H__ -#define __AUD_FFMPEGREADER_H__ - -#include "AUD_ConverterFunctions.h" -#include "AUD_IReader.h" -#include "AUD_Buffer.h" - -#include <string> -#include <boost/shared_ptr.hpp> - -struct AVCodecContext; -extern "C" { -#include <libavformat/avformat.h> -} - -/** - * This class reads a sound file via ffmpeg. - * \warning Seeking may not be accurate! Moreover the position is updated after - * a buffer reading call. So calling getPosition right after seek - * normally results in a wrong value. - */ -class AUD_FFMPEGReader : public AUD_IReader -{ -private: - /** - * The current position in samples. - */ - int m_position; - - /** - * The specification of the audio data. - */ - AUD_DeviceSpecs m_specs; - - /** - * The buffer for package reading. - */ - AUD_Buffer m_pkgbuf; - - /** - * The count of samples still available from the last read package. - */ - int m_pkgbuf_left; - - /** - * The AVFormatContext structure for using ffmpeg. - */ - AVFormatContext* m_formatCtx; - - /** - * The AVCodecContext structure for using ffmpeg. - */ - AVCodecContext* m_codecCtx; - - /** - * The AVIOContext to read the data from. - */ - AVIOContext* m_aviocontext; - - /** - * The stream ID in the file. - */ - int m_stream; - - /** - * Converter function. - */ - AUD_convert_f m_convert; - - /** - * The memory file to read from. - */ - boost::shared_ptr<AUD_Buffer> m_membuffer; - - /** - * The buffer to read with. - */ - data_t* m_membuf; - - /** - * Reading position of the buffer. - */ - int64_t m_membufferpos; - - /** - * Whether the audio data has to be interleaved after reading. - */ - bool m_tointerleave; - - /** - * Decodes a packet into the given buffer. - * \param packet The AVPacket to decode. - * \param buffer The target buffer. - * \return The count of read bytes. - */ - int decode(AVPacket& packet, AUD_Buffer& buffer); - - /** - * Initializes the object. - */ - void init(); - - // hide copy constructor and operator= - AUD_FFMPEGReader(const AUD_FFMPEGReader&); - AUD_FFMPEGReader& operator=(const AUD_FFMPEGReader&); - -public: - /** - * Creates a new reader. - * \param filename The path to the file to be read. - * \exception AUD_Exception Thrown if the file specified does not exist or - * cannot be read with ffmpeg. - */ - AUD_FFMPEGReader(std::string filename); - - /** - * Creates a new reader. - * \param buffer The buffer to read from. - * \exception AUD_Exception Thrown if the buffer specified cannot be read - * with ffmpeg. - */ - AUD_FFMPEGReader(boost::shared_ptr<AUD_Buffer> buffer); - - /** - * Destroys the reader and closes the file. - */ - virtual ~AUD_FFMPEGReader(); - - static int read_packet(void* opaque, uint8_t* buf, int buf_size); - static int64_t seek_packet(void* opaque, int64_t offset, int whence); - - virtual bool isSeekable() const; - virtual void seek(int position); - virtual int getLength() const; - virtual int getPosition() const; - virtual AUD_Specs getSpecs() const; - virtual void read(int& length, bool& eos, sample_t* buffer); -}; - -#endif //__AUD_FFMPEGREADER_H__ diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp deleted file mode 100644 index 3f95ac7a4da..00000000000 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * Copyright 2009-2011 Jörg Hermann Müller - * - * This file is part of AudaSpace. - * - * Audaspace is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * AudaSpace is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Audaspace; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file audaspace/ffmpeg/AUD_FFMPEGWriter.cpp - * \ingroup audffmpeg - */ - - -// needed for INT64_C -#ifndef __STDC_CONSTANT_MACROS -#define __STDC_CONSTANT_MACROS -#endif - -#include "AUD_FFMPEGWriter.h" - -extern "C" { -#include <libavcodec/avcodec.h> -#include <libavformat/avformat.h> -#include <libavformat/avio.h> -#include "ffmpeg_compat.h" -} - -static const char* context_error = "AUD_FFMPEGWriter: Couldn't allocate context."; -static const char* codec_error = "AUD_FFMPEGWriter: Invalid codec or codec not found."; -static const char* stream_error = "AUD_FFMPEGWriter: Couldn't allocate stream."; -static const char* format_error = "AUD_FFMPEGWriter: Unsupported sample format."; -static const char* file_error = "AUD_FFMPEGWriter: File couldn't be written."; -static const char* write_error = "AUD_FFMPEGWriter: Error writing packet."; - -AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate) : - m_position(0), - m_specs(specs), - m_input_samples(0) -{ - static const char* formats[] = { NULL, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" }; - - m_formatCtx = avformat_alloc_context(); - if (!m_formatCtx) AUD_THROW(AUD_ERROR_FFMPEG, context_error); - - strcpy(m_formatCtx->filename, filename.c_str()); - m_outputFmt = m_formatCtx->oformat = av_guess_format(formats[format], filename.c_str(), NULL); - if (!m_outputFmt) { - avformat_free_context(m_formatCtx); - AUD_THROW(AUD_ERROR_FFMPEG, context_error); - } - - switch(codec) - { - case AUD_CODEC_AAC: - m_outputFmt->audio_codec = AV_CODEC_ID_AAC; - break; - case AUD_CODEC_AC3: - m_outputFmt->audio_codec = AV_CODEC_ID_AC3; - break; - case AUD_CODEC_FLAC: - m_outputFmt->audio_codec = AV_CODEC_ID_FLAC; - break; - case AUD_CODEC_MP2: - m_outputFmt->audio_codec = AV_CODEC_ID_MP2; - break; - case AUD_CODEC_MP3: - m_outputFmt->audio_codec = AV_CODEC_ID_MP3; - break; - case AUD_CODEC_PCM: - switch(specs.format) - { - case AUD_FORMAT_U8: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_U8; - break; - case AUD_FORMAT_S16: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE; - break; - case AUD_FORMAT_S24: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE; - break; - case AUD_FORMAT_S32: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE; - break; - case AUD_FORMAT_FLOAT32: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE; - break; - case AUD_FORMAT_FLOAT64: - m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE; - break; - default: - m_outputFmt->audio_codec = AV_CODEC_ID_NONE; - break; - } - break; - case AUD_CODEC_VORBIS: - m_outputFmt->audio_codec = AV_CODEC_ID_VORBIS; - break; - default: - m_outputFmt->audio_codec = AV_CODEC_ID_NONE; - break; - } - - try - { - if(m_outputFmt->audio_codec == AV_CODEC_ID_NONE) - AUD_THROW(AUD_ERROR_SPECS, codec_error); - - m_stream = avformat_new_stream(m_formatCtx, NULL); - if(!m_stream) - AUD_THROW(AUD_ERROR_FFMPEG, stream_error); - - m_codecCtx = m_stream->codec; - m_codecCtx->codec_id = m_outputFmt->audio_codec; - m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO; - m_codecCtx->bit_rate = bitrate; - m_codecCtx->sample_rate = int(m_specs.rate); - m_codecCtx->channels = m_specs.channels; - m_codecCtx->time_base.num = 1; - m_codecCtx->time_base.den = m_codecCtx->sample_rate; - - switch(m_specs.format) - { - case AUD_FORMAT_U8: - m_convert = AUD_convert_float_u8; - m_codecCtx->sample_fmt = AV_SAMPLE_FMT_U8; - break; - case AUD_FORMAT_S16: - m_convert = AUD_convert_float_s16; - m_codecCtx->sample_fmt = AV_SAMPLE_FMT_S16; - break; - case AUD_FORMAT_S32: - m_convert = AUD_convert_float_s32; - m_codecCtx->sample_fmt = AV_SAMPLE_FMT_S32; - break; - case AUD_FORMAT_FLOAT32: - m_convert = AUD_convert_copy<float>; - m_codecCtx->sample_fmt = AV_SAMPLE_FMT_FLT; - break; - case AUD_FORMAT_FLOAT64: - m_convert = AUD_convert_float_double; - m_codecCtx->sample_fmt = AV_SAMPLE_FMT_DBL; - break; - default: - AUD_THROW(AUD_ERROR_FFMPEG, format_error); - } - - try - { - if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER) - m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; - - AVCodec* codec = avcodec_find_encoder(m_codecCtx->codec_id); - if(!codec) - AUD_THROW(AUD_ERROR_FFMPEG, codec_error); - - if(codec->sample_fmts) { - // Check if the preferred sample format for this codec is supported. - const enum AVSampleFormat *p = codec->sample_fmts; - for(; *p != -1; p++) { - if(*p == m_stream->codec->sample_fmt) - break; - } - if(*p == -1) { - // Sample format incompatible with codec. Defaulting to a format known to work. - m_stream->codec->sample_fmt = codec->sample_fmts[0]; - } - } - - if(avcodec_open2(m_codecCtx, codec, NULL)) - AUD_THROW(AUD_ERROR_FFMPEG, codec_error); - - m_output_buffer.resize(FF_MIN_BUFFER_SIZE); - int samplesize = AUD_MAX(AUD_SAMPLE_SIZE(m_specs), AUD_DEVICE_SAMPLE_SIZE(m_specs)); - - if(m_codecCtx->frame_size <= 1) { - m_input_size = FF_MIN_BUFFER_SIZE * 8 / m_codecCtx->bits_per_coded_sample / m_codecCtx->channels; - m_input_buffer.resize(m_input_size * samplesize); - } - else - { - m_input_buffer.resize(m_codecCtx->frame_size * samplesize); - m_input_size = m_codecCtx->frame_size; - } - -#ifdef FFMPEG_HAVE_ENCODE_AUDIO2 - m_frame = av_frame_alloc(); - if (!m_frame) - AUD_THROW(AUD_ERROR_FFMPEG, codec_error); - av_frame_unref(m_frame); - m_frame->linesize[0] = m_input_size * samplesize; - m_frame->format = m_codecCtx->sample_fmt; - m_frame->nb_samples = m_input_size; -# ifdef FFMPEG_HAVE_AVFRAME_SAMPLE_RATE - m_frame->sample_rate = m_codecCtx->sample_rate; -# endif -# ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT - m_frame->channel_layout = m_codecCtx->channel_layout; -# endif - m_sample_size = av_get_bytes_per_sample(m_codecCtx->sample_fmt); - m_frame_pts = 0; - m_deinterleave = av_sample_fmt_is_planar(m_codecCtx->sample_fmt); - if(m_deinterleave) - m_deinterleave_buffer.resize(m_input_size * m_codecCtx->channels * m_sample_size); -#endif - - try - { - if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE)) - AUD_THROW(AUD_ERROR_FILE, file_error); - - if(avformat_write_header(m_formatCtx, NULL) < 0) { - throw; - } - } - catch(AUD_Exception&) - { - avcodec_close(m_codecCtx); - av_freep(&m_formatCtx->streams[0]->codec); - throw; - } - } - catch(AUD_Exception&) - { - av_freep(&m_formatCtx->streams[0]); - throw; - } - } - catch(AUD_Exception&) - { - av_free(m_formatCtx); - throw; - } -} - -AUD_FFMPEGWriter::~AUD_FFMPEGWriter() -{ - // writte missing data - if(m_input_samples) - { - sample_t* buf = m_input_buffer.getBuffer(); - memset(buf + m_specs.channels * m_input_samples, 0, - (m_input_size - m_input_samples) * AUD_DEVICE_SAMPLE_SIZE(m_specs)); - - encode(buf); - } - - av_write_trailer(m_formatCtx); - - avcodec_close(m_codecCtx); - - av_freep(&m_formatCtx->streams[0]->codec); - av_freep(&m_formatCtx->streams[0]); - -#ifdef FFMPEG_HAVE_ENCODE_AUDIO2 - av_frame_free(&m_frame); -#endif - - avio_close(m_formatCtx->pb); - av_free(m_formatCtx); -} - -int AUD_FFMPEGWriter::getPosition() const -{ - return m_position; -} - -AUD_DeviceSpecs AUD_FFMPEGWriter::getSpecs() const -{ - return m_specs; -} - -void AUD_FFMPEGWriter::encode(sample_t* data) -{ - // convert first - if(m_input_size) - m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_size * m_specs.channels); - - AVPacket packet = { 0 }; - av_init_packet(&packet); - -#ifdef FFMPEG_HAVE_ENCODE_AUDIO2 - int got_output, ret; - m_frame->pts = m_frame_pts / av_q2d(m_codecCtx->time_base); - m_frame_pts++; -#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT - m_frame->channel_layout = m_codecCtx->channel_layout; -#endif - - if(m_deinterleave) { - for(int channel = 0; channel < m_codecCtx->channels; channel++) { - for(int i = 0; i < m_frame->nb_samples; i++) { - memcpy(reinterpret_cast<uint8_t*>(m_deinterleave_buffer.getBuffer()) + (i + channel * m_frame->nb_samples) * m_sample_size, - reinterpret_cast<uint8_t*>(data) + (m_codecCtx->channels * i + channel) * m_sample_size, m_sample_size); - } - } - - data = m_deinterleave_buffer.getBuffer(); - } - - avcodec_fill_audio_frame(m_frame, m_codecCtx->channels, m_codecCtx->sample_fmt, reinterpret_cast<uint8_t*>(data), - m_frame->nb_samples * av_get_bytes_per_sample(m_codecCtx->sample_fmt) * m_codecCtx->channels, 1); - - ret = avcodec_encode_audio2(m_codecCtx, &packet, m_frame, &got_output); - if(ret < 0) - AUD_THROW(AUD_ERROR_FFMPEG, codec_error); - - if(!got_output) - return; -#else - sample_t* outbuf = m_output_buffer.getBuffer(); - - packet.size = avcodec_encode_audio(m_codecCtx, reinterpret_cast<uint8_t*>(outbuf), m_output_buffer.getSize(), reinterpret_cast<short*>(data)); - if(m_codecCtx->coded_frame && m_codecCtx->coded_frame->pts != AV_NOPTS_VALUE) - packet.pts = av_rescale_q(m_codecCtx->coded_frame->pts, m_codecCtx->time_base, m_stream->time_base); - packet.flags |= AV_PKT_FLAG_KEY; - packet.data = reinterpret_cast<uint8_t*>(outbuf); -#endif - - if(packet.pts != AV_NOPTS_VALUE) - packet.pts = av_rescale_q(packet.pts, m_codecCtx->time_base, m_stream->time_base); - if(packet.dts != AV_NOPTS_VALUE) - packet.dts = av_rescale_q(packet.dts, m_codecCtx->time_base, m_stream->time_base); - if(packet.duration > 0) - packet.duration = av_rescale_q(packet.duration, m_codecCtx->time_base, m_stream->time_base); - - packet.stream_index = m_stream->index; - - packet.flags |= AV_PKT_FLAG_KEY; - - if(av_interleaved_write_frame(m_formatCtx, &packet)) { - av_free_packet(&packet); - AUD_THROW(AUD_ERROR_FFMPEG, write_error); - } - - av_free_packet(&packet); -} - -void AUD_FFMPEGWriter::write(unsigned int length, sample_t* buffer) -{ - unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs); - - if(m_input_size) - { - sample_t* inbuf = m_input_buffer.getBuffer(); - - while(length) - { - unsigned int len = AUD_MIN(m_input_size - m_input_samples, length); - - memcpy(inbuf + m_input_samples * m_specs.channels, buffer, len * samplesize); - - buffer += len * m_specs.channels; - m_input_samples += len; - m_position += len; - length -= len; - - if(m_input_samples == m_input_size) - { - encode(inbuf); - - m_input_samples = 0; - } - } - } - else // PCM data, can write directly! - { - int samplesize = AUD_SAMPLE_SIZE(m_specs); - if(m_output_buffer.getSize() != length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8) - m_output_buffer.resize(length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8); - m_input_buffer.assureSize(length * AUD_MAX(AUD_DEVICE_SAMPLE_SIZE(m_specs), samplesize)); - - sample_t* buf = m_input_buffer.getBuffer(); - m_convert(reinterpret_cast<data_t*>(buf), reinterpret_cast<data_t*>(buffer), length * m_specs.channels); - - encode(buf); - - m_position += length; - } -} diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h deleted file mode 100644 index 492aa35ff12..00000000000 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * Copyright 2009-2011 Jörg Hermann Müller - * - * This file is part of AudaSpace. - * - * Audaspace is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * AudaSpace is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Audaspace; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file audaspace/ffmpeg/AUD_FFMPEGWriter.h - * \ingroup audffmpeg - */ - - -#ifndef __AUD_FFMPEGWRITER_H__ -#define __AUD_FFMPEGWRITER_H__ - -#include "AUD_ConverterFunctions.h" -#include "AUD_Buffer.h" -#include "AUD_IWriter.h" - -#include <string> - -struct AVCodecContext; -extern "C" { -#include <libavformat/avformat.h> -} - -/** - * This class writes a sound file via ffmpeg. - */ -class AUD_FFMPEGWriter : public AUD_IWriter -{ -private: - /** - * The current position in samples. - */ - int m_position; - - /** - * The specification of the audio data. - */ - AUD_DeviceSpecs m_specs; - - /** - * The AVFormatContext structure for using ffmpeg. - */ - AVFormatContext* m_formatCtx; - - /** - * The AVCodecContext structure for using ffmpeg. - */ - AVCodecContext* m_codecCtx; - - /** - * The AVOutputFormat structure for using ffmpeg. - */ - AVOutputFormat* m_outputFmt; - - /** - * The AVStream structure for using ffmpeg. - */ - AVStream* m_stream; - - /** - * Frame sent to the encoder. - */ - AVFrame *m_frame; - - /** - * PTS of next frame to write. - */ - int m_frame_pts; - - /** - * Number of bytes per sample. - */ - int m_sample_size; - - /** - * Need to de-interleave audio for planar sample formats. - */ - bool m_deinterleave; - - AUD_Buffer m_deinterleave_buffer; - - /** - * The input buffer for the format converted data before encoding. - */ - AUD_Buffer m_input_buffer; - - /** - * The output buffer for the encoded audio data. - */ - AUD_Buffer m_output_buffer; - - /** - * The count of input samples we have so far. - */ - unsigned int m_input_samples; - - /** - * The count of input samples necessary to encode a packet. - */ - unsigned int m_input_size; - - /** - * Converter function. - */ - AUD_convert_f m_convert; - - // hide copy constructor and operator= - AUD_FFMPEGWriter(const AUD_FFMPEGWriter&); - AUD_FFMPEGWriter& operator=(const AUD_FFMPEGWriter&); - - /** - * Encodes to the output buffer. - * \param data Pointer to the data to encode. - */ - void encode(sample_t* data); - -public: - /** - * Creates a new writer. - * \param filename The path to the file to be read. - * \param specs The file's audio specification. - * \param format The file's container format. - * \param codec The codec used for encoding the audio data. - * \param bitrate The bitrate for encoding. - * \exception AUD_Exception Thrown if the file specified does not exist or - * cannot be read with ffmpeg. - */ - AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate); - - /** - * Destroys the writer and closes the file. - */ - virtual ~AUD_FFMPEGWriter(); - - virtual int getPosition() const; - virtual AUD_DeviceSpecs getSpecs() const; - virtual void write(unsigned int length, sample_t* buffer); -}; - -#endif //__AUD_FFMPEGWRITER_H__ |