pxmlw6n2f/Gazebo_Distributed/gazebo/common/AudioDecoder.cc

291 lines
6.8 KiB
C++

/*
* Copyright (C) 2012 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <gazebo/gazebo_config.h>
#include <gazebo/common/AudioDecoder.hh>
#include <gazebo/common/Console.hh>
#include <gazebo/common/ffmpeg_inc.h>
#define AUDIO_INBUF_SIZE (20480 * 2)
#define AUDIO_REFILL_THRESH 4096
using namespace gazebo;
using namespace common;
/////////////////////////////////////////////////
AudioDecoder::AudioDecoder()
{
this->formatCtx = NULL;
this->codecCtx = NULL;
this->codec = NULL;
this->audioStream = 0;
}
/////////////////////////////////////////////////
AudioDecoder::~AudioDecoder()
{
this->Cleanup();
}
/////////////////////////////////////////////////
void AudioDecoder::Cleanup()
{
#ifdef HAVE_FFMPEG
// Close the codec
if (this->codecCtx)
avcodec_close(this->codecCtx);
// Close the audio file
if (this->formatCtx)
avformat_close_input(&this->formatCtx);
#endif
}
/////////////////////////////////////////////////
#ifdef HAVE_FFMPEG
bool AudioDecoder::Decode(uint8_t **_outBuffer, unsigned int *_outBufferSize)
{
AVPacket packet, packet1;
int bytesDecoded = 0;
unsigned int maxBufferSize = 0;
AVFrame *decodedFrame = NULL;
if (this->codec == NULL)
{
gzerr << "Set an audio file before decoding.\n";
return false;
}
if (_outBufferSize == NULL)
{
gzerr << "outBufferSize is NULL!!\n";
return false;
}
*_outBufferSize = 0;
if (*_outBuffer)
{
delete [] *_outBuffer;
*_outBuffer = NULL;
}
bool result = true;
if (!decodedFrame)
{
if (!(decodedFrame = common::AVFrameAlloc()))
{
gzerr << "Audio decoder out of memory\n";
result = false;
}
}
else
common::AVFrameUnref(decodedFrame);
av_init_packet(&packet);
while (av_read_frame(this->formatCtx, &packet) == 0)
{
if (packet.stream_index == this->audioStream)
{
int gotFrame = 0;
packet1 = packet;
while (packet1.size)
{
// Some frames rely on multiple packets, so we have to make sure
// the frame is finished before we can use it
#ifndef _WIN32
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
bytesDecoded = avcodec_decode_audio4(this->codecCtx, decodedFrame,
&gotFrame, &packet1);
#ifndef _WIN32
# pragma GCC diagnostic pop
#endif
if (gotFrame)
{
// Total size of the data. Some padding can be added to
// decodedFrame->data[0], which is why we can't use
// decodedFrame->linesize[0].
int size = decodedFrame->nb_samples *
av_get_bytes_per_sample(this->codecCtx->sample_fmt) *
this->codecCtx->channels;
// Resize the audio buffer as necessary
if (*_outBufferSize + size > maxBufferSize)
{
maxBufferSize += size * 5;
*_outBuffer = reinterpret_cast<uint8_t*>(realloc(*_outBuffer,
maxBufferSize * sizeof(*_outBuffer[0])));
}
memcpy(*_outBuffer + *_outBufferSize, decodedFrame->data[0],
size);
*_outBufferSize += size;
}
packet1.data += bytesDecoded;
packet1.size -= bytesDecoded;
}
}
AVPacketUnref(&packet);
}
AVPacketUnref(&packet);
// Seek to the beginning so that it can be decoded again, if necessary.
av_seek_frame(this->formatCtx, this->audioStream, 0, 0);
return result;
}
#else
bool AudioDecoder::Decode(uint8_t ** /*_outBuffer*/,
unsigned int * /*_outBufferSize*/)
{
return true;
}
#endif
/////////////////////////////////////////////////
int AudioDecoder::GetSampleRate()
{
#ifdef HAVE_FFMPEG
return this->codecCtx->sample_rate;
#else
return 0;
#endif
}
/////////////////////////////////////////////////
#ifdef HAVE_FFMPEG
bool AudioDecoder::SetFile(const std::string &_filename)
{
unsigned int i;
this->formatCtx = avformat_alloc_context();
// Open file
if (avformat_open_input(&this->formatCtx, _filename.c_str(), NULL, NULL) < 0)
{
gzerr << "Unable to open audio file[" << _filename << "]\n";
this->formatCtx = NULL;
return false;
}
// Hide av logging
av_log_set_level(0);
// Retrieve some information
if (avformat_find_stream_info(this->formatCtx, NULL) < 0)
{
gzerr << "Unable to find stream info.\n";
avformat_close_input(&this->formatCtx);
this->formatCtx = NULL;
return false;
}
// Dump information about file onto standard error.
// dump_format(this->formatCtx, 0, "dump.txt", false);
// Find audio stream;
this->audioStream = -1;
for (i = 0; i < this->formatCtx->nb_streams; ++i)
{
#ifndef _WIN32
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
if (this->formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#ifndef _WIN32
# pragma GCC diagnostic pop
#endif
{
this->audioStream = i;
break;
}
}
if (this->audioStream == -1)
{
gzerr << "Couldn't find audio stream.\n";
avformat_close_input(&this->formatCtx);
this->formatCtx = NULL;
return false;
}
// Get the audio stream codec
#ifndef _WIN32
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
this->codecCtx = this->formatCtx->streams[audioStream]->codec;
#ifndef _WIN32
# pragma GCC diagnostic pop
#endif
// Find a decoder
this->codec = avcodec_find_decoder(codecCtx->codec_id);
if (this->codec == NULL)
{
gzerr << "Couldn't find codec for audio stream.\n";
avformat_close_input(&this->formatCtx);
this->formatCtx = NULL;
return false;
}
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 60, 100)
if (this->codec->capabilities & AV_CODEC_CAP_TRUNCATED)
this->codecCtx->flags |= AV_CODEC_FLAG_TRUNCATED;
#else
if (this->codec->capabilities & CODEC_CAP_TRUNCATED)
this->codecCtx->flags |= CODEC_FLAG_TRUNCATED;
#endif
// Open codec
if (avcodec_open2(this->codecCtx, this->codec, NULL) < 0)
{
gzerr << "Couldn't open audio codec.\n";
avformat_close_input(&this->formatCtx);
this->formatCtx = NULL;
return false;
}
this->filename = _filename;
return true;
}
#else
bool AudioDecoder::SetFile(const std::string & /*_filename*/)
{
return false;
}
#endif
/////////////////////////////////////////////////
std::string AudioDecoder::GetFile() const
{
return this->filename;
}