mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-31 23:15:43 +00:00
Merge the stream struct into the parent decoder
This commit is contained in:
parent
5fff1c4e47
commit
1a771ae671
2 changed files with 71 additions and 84 deletions
|
@ -15,23 +15,6 @@ static void fail(const std::string &msg)
|
||||||
{ throw std::runtime_error("FFmpeg exception: "+msg); }
|
{ throw std::runtime_error("FFmpeg exception: "+msg); }
|
||||||
|
|
||||||
|
|
||||||
struct FFmpeg_Decoder::MyStream {
|
|
||||||
AVCodecContext *mCodecCtx;
|
|
||||||
int mStreamIdx;
|
|
||||||
|
|
||||||
AVPacket mPacket;
|
|
||||||
AVFrame *mFrame;
|
|
||||||
|
|
||||||
int mFrameSize;
|
|
||||||
int mFramePos;
|
|
||||||
|
|
||||||
FFmpeg_Decoder *mParent;
|
|
||||||
|
|
||||||
bool getAVAudioData();
|
|
||||||
size_t readAVAudioData(void *data, size_t length);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
|
int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
Ogre::DataStreamPtr stream = static_cast<FFmpeg_Decoder*>(user_data)->mDataStream;
|
Ogre::DataStreamPtr stream = static_cast<FFmpeg_Decoder*>(user_data)->mDataStream;
|
||||||
|
@ -69,35 +52,36 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence)
|
||||||
* handle for. */
|
* handle for. */
|
||||||
bool FFmpeg_Decoder::getNextPacket()
|
bool FFmpeg_Decoder::getNextPacket()
|
||||||
{
|
{
|
||||||
if(!mStream.get())
|
if(!mStream)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while(av_read_frame(mFormatCtx, &mStream->mPacket) >= 0)
|
int stream_idx = mStream - mFormatCtx->streams;
|
||||||
|
while(av_read_frame(mFormatCtx, &mPacket) >= 0)
|
||||||
{
|
{
|
||||||
/* Check if the packet belongs to this stream */
|
/* Check if the packet belongs to this stream */
|
||||||
if(mStream->mStreamIdx == mStream->mPacket.stream_index)
|
if(stream_idx == mPacket.stream_index)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Free the packet and look for another */
|
/* Free the packet and look for another */
|
||||||
av_free_packet(&mStream->mPacket);
|
av_free_packet(&mPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FFmpeg_Decoder::MyStream::getAVAudioData()
|
bool FFmpeg_Decoder::getAVAudioData()
|
||||||
{
|
{
|
||||||
int got_frame, len;
|
int got_frame, len;
|
||||||
|
|
||||||
if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
|
if((*mStream)->codec->codec_type != AVMEDIA_TYPE_AUDIO)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(mPacket.size == 0 && !mParent->getNextPacket())
|
if(mPacket.size == 0 && !getNextPacket())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Decode some data, and check for errors */
|
/* Decode some data, and check for errors */
|
||||||
if((len=avcodec_decode_audio4(mCodecCtx, mFrame, &got_frame, &mPacket)) < 0)
|
if((len=avcodec_decode_audio4((*mStream)->codec, mFrame, &got_frame, &mPacket)) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Move the unread data to the front and clear the end bits */
|
/* Move the unread data to the front and clear the end bits */
|
||||||
|
@ -114,7 +98,7 @@ bool FFmpeg_Decoder::MyStream::getAVAudioData()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length)
|
size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length)
|
||||||
{
|
{
|
||||||
size_t dec = 0;
|
size_t dec = 0;
|
||||||
|
|
||||||
|
@ -126,8 +110,8 @@ size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length)
|
||||||
if(!getAVAudioData())
|
if(!getAVAudioData())
|
||||||
break;
|
break;
|
||||||
mFramePos = 0;
|
mFramePos = 0;
|
||||||
mFrameSize = mFrame->nb_samples * mCodecCtx->channels *
|
mFrameSize = mFrame->nb_samples * (*mStream)->codec->channels *
|
||||||
av_get_bytes_per_sample(mCodecCtx->sample_fmt);
|
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the amount of bytes remaining to be written, and clamp to
|
/* Get the amount of bytes remaining to be written, and clamp to
|
||||||
|
@ -167,55 +151,46 @@ void FFmpeg_Decoder::open(const std::string &fname)
|
||||||
if(avformat_find_stream_info(mFormatCtx, NULL) < 0)
|
if(avformat_find_stream_info(mFormatCtx, NULL) < 0)
|
||||||
fail("Failed to find stream info in "+fname);
|
fail("Failed to find stream info in "+fname);
|
||||||
|
|
||||||
int audio_idx = -1;
|
|
||||||
for(size_t j = 0;j < mFormatCtx->nb_streams;j++)
|
for(size_t j = 0;j < mFormatCtx->nb_streams;j++)
|
||||||
{
|
{
|
||||||
if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||||
{
|
{
|
||||||
audio_idx = j;
|
mStream = &mFormatCtx->streams[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(audio_idx == -1)
|
if(!mStream)
|
||||||
fail("No audio streams in "+fname);
|
fail("No audio streams in "+fname);
|
||||||
|
|
||||||
std::auto_ptr<MyStream> stream(new MyStream);
|
memset(&mPacket, 0, sizeof(mPacket));
|
||||||
stream->mCodecCtx = mFormatCtx->streams[audio_idx]->codec;
|
|
||||||
stream->mStreamIdx = audio_idx;
|
|
||||||
memset(&stream->mPacket, 0, sizeof(stream->mPacket));
|
|
||||||
|
|
||||||
AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id);
|
AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id);
|
||||||
if(!codec)
|
if(!codec)
|
||||||
{
|
{
|
||||||
std::stringstream ss("No codec found for id ");
|
std::stringstream ss("No codec found for id ");
|
||||||
ss << stream->mCodecCtx->codec_id;
|
ss << (*mStream)->codec->codec_id;
|
||||||
fail(ss.str());
|
fail(ss.str());
|
||||||
}
|
}
|
||||||
if(avcodec_open2(stream->mCodecCtx, codec, NULL) < 0)
|
if(avcodec_open2((*mStream)->codec, codec, NULL) < 0)
|
||||||
fail("Failed to open audio codec " + std::string(codec->long_name));
|
fail("Failed to open audio codec " + std::string(codec->long_name));
|
||||||
|
|
||||||
stream->mFrame = avcodec_alloc_frame();
|
mFrame = avcodec_alloc_frame();
|
||||||
|
|
||||||
stream->mParent = this;
|
|
||||||
mStream = stream;
|
|
||||||
}
|
}
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
avformat_close_input(&mFormatCtx);
|
avformat_close_input(&mFormatCtx);
|
||||||
mFormatCtx = NULL;
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpeg_Decoder::close()
|
void FFmpeg_Decoder::close()
|
||||||
{
|
{
|
||||||
if(mStream.get())
|
if(mStream)
|
||||||
{
|
avcodec_close((*mStream)->codec);
|
||||||
av_free_packet(&mStream->mPacket);
|
mStream = NULL;
|
||||||
avcodec_close(mStream->mCodecCtx);
|
|
||||||
av_free(mStream->mFrame);
|
av_free_packet(&mPacket);
|
||||||
}
|
av_freep(&mFrame);
|
||||||
mStream.reset();
|
|
||||||
|
|
||||||
if(mFormatCtx)
|
if(mFormatCtx)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +198,6 @@ void FFmpeg_Decoder::close()
|
||||||
avformat_close_input(&mFormatCtx);
|
avformat_close_input(&mFormatCtx);
|
||||||
av_free(context);
|
av_free(context);
|
||||||
}
|
}
|
||||||
mFormatCtx = NULL;
|
|
||||||
|
|
||||||
mDataStream.setNull();
|
mDataStream.setNull();
|
||||||
}
|
}
|
||||||
|
@ -235,83 +209,82 @@ std::string FFmpeg_Decoder::getName()
|
||||||
|
|
||||||
void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
|
void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
|
||||||
{
|
{
|
||||||
if(!mStream.get())
|
if(!mStream)
|
||||||
fail("No audio stream info");
|
fail("No audio stream info");
|
||||||
|
|
||||||
if(mStream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8)
|
if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8)
|
||||||
*type = SampleType_UInt8;
|
*type = SampleType_UInt8;
|
||||||
else if(mStream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16)
|
else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16)
|
||||||
*type = SampleType_Int16;
|
*type = SampleType_Int16;
|
||||||
else
|
else
|
||||||
fail(std::string("Unsupported sample format: ")+
|
fail(std::string("Unsupported sample format: ")+
|
||||||
av_get_sample_fmt_name(mStream->mCodecCtx->sample_fmt));
|
av_get_sample_fmt_name((*mStream)->codec->sample_fmt));
|
||||||
|
|
||||||
if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO)
|
if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_MONO)
|
||||||
*chans = ChannelConfig_Mono;
|
*chans = ChannelConfig_Mono;
|
||||||
else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO)
|
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_STEREO)
|
||||||
*chans = ChannelConfig_Stereo;
|
*chans = ChannelConfig_Stereo;
|
||||||
else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_QUAD)
|
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_QUAD)
|
||||||
*chans = ChannelConfig_Quad;
|
*chans = ChannelConfig_Quad;
|
||||||
else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1)
|
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_5POINT1)
|
||||||
*chans = ChannelConfig_5point1;
|
*chans = ChannelConfig_5point1;
|
||||||
else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1)
|
else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_7POINT1)
|
||||||
*chans = ChannelConfig_7point1;
|
*chans = ChannelConfig_7point1;
|
||||||
else if(mStream->mCodecCtx->channel_layout == 0)
|
else if((*mStream)->codec->channel_layout == 0)
|
||||||
{
|
{
|
||||||
/* Unknown channel layout. Try to guess. */
|
/* Unknown channel layout. Try to guess. */
|
||||||
if(mStream->mCodecCtx->channels == 1)
|
if((*mStream)->codec->channels == 1)
|
||||||
*chans = ChannelConfig_Mono;
|
*chans = ChannelConfig_Mono;
|
||||||
else if(mStream->mCodecCtx->channels == 2)
|
else if((*mStream)->codec->channels == 2)
|
||||||
*chans = ChannelConfig_Stereo;
|
*chans = ChannelConfig_Stereo;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::stringstream sstr("Unsupported raw channel count: ");
|
std::stringstream sstr("Unsupported raw channel count: ");
|
||||||
sstr << mStream->mCodecCtx->channels;
|
sstr << (*mStream)->codec->channels;
|
||||||
fail(sstr.str());
|
fail(sstr.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char str[1024];
|
char str[1024];
|
||||||
av_get_channel_layout_string(str, sizeof(str), mStream->mCodecCtx->channels,
|
av_get_channel_layout_string(str, sizeof(str), (*mStream)->codec->channels,
|
||||||
mStream->mCodecCtx->channel_layout);
|
(*mStream)->codec->channel_layout);
|
||||||
fail(std::string("Unsupported channel layout: ")+str);
|
fail(std::string("Unsupported channel layout: ")+str);
|
||||||
}
|
}
|
||||||
|
|
||||||
*samplerate = mStream->mCodecCtx->sample_rate;
|
*samplerate = (*mStream)->codec->sample_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
|
size_t FFmpeg_Decoder::read(char *buffer, size_t bytes)
|
||||||
{
|
{
|
||||||
if(!mStream.get())
|
if(!mStream)
|
||||||
fail("No audio stream");
|
fail("No audio stream");
|
||||||
|
|
||||||
size_t got = mStream->readAVAudioData(buffer, bytes);
|
size_t got = readAVAudioData(buffer, bytes);
|
||||||
mSamplesRead += got / mStream->mCodecCtx->channels /
|
mSamplesRead += got / (*mStream)->codec->channels /
|
||||||
av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt);
|
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
|
||||||
return got;
|
return got;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpeg_Decoder::readAll(std::vector<char> &output)
|
void FFmpeg_Decoder::readAll(std::vector<char> &output)
|
||||||
{
|
{
|
||||||
if(!mStream.get())
|
if(!mStream)
|
||||||
fail("No audio stream");
|
fail("No audio stream");
|
||||||
|
|
||||||
while(mStream->getAVAudioData())
|
while(getAVAudioData())
|
||||||
{
|
{
|
||||||
size_t got = mStream->mFrame->nb_samples * mStream->mCodecCtx->channels *
|
size_t got = mFrame->nb_samples * (*mStream)->codec->channels *
|
||||||
av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt);
|
av_get_bytes_per_sample((*mStream)->codec->sample_fmt);
|
||||||
const char *inbuf = reinterpret_cast<char*>(mStream->mFrame->data[0]);
|
const char *inbuf = reinterpret_cast<char*>(mFrame->data[0]);
|
||||||
output.insert(output.end(), inbuf, inbuf+got);
|
output.insert(output.end(), inbuf, inbuf+got);
|
||||||
mSamplesRead += mStream->mFrame->nb_samples;
|
mSamplesRead += mFrame->nb_samples;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpeg_Decoder::rewind()
|
void FFmpeg_Decoder::rewind()
|
||||||
{
|
{
|
||||||
av_seek_frame(mFormatCtx, -1, 0, 0);
|
av_seek_frame(mFormatCtx, -1, 0, 0);
|
||||||
if(mStream.get())
|
av_free_packet(&mPacket);
|
||||||
av_free_packet(&mStream->mPacket);
|
|
||||||
mSamplesRead = 0;
|
mSamplesRead = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,12 +293,19 @@ size_t FFmpeg_Decoder::getSampleOffset()
|
||||||
return mSamplesRead;
|
return mSamplesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL), mSamplesRead(0)
|
FFmpeg_Decoder::FFmpeg_Decoder()
|
||||||
|
: mFormatCtx(NULL)
|
||||||
|
, mStream(NULL)
|
||||||
|
, mFrame(NULL)
|
||||||
|
, mFrameSize(0)
|
||||||
|
, mFramePos(0)
|
||||||
|
, mSamplesRead(0)
|
||||||
{
|
{
|
||||||
static bool done_init = false;
|
memset(&mPacket, 0, sizeof(mPacket));
|
||||||
|
|
||||||
/* We need to make sure ffmpeg is initialized. Optionally silence warning
|
/* We need to make sure ffmpeg is initialized. Optionally silence warning
|
||||||
* output from the lib */
|
* output from the lib */
|
||||||
|
static bool done_init = false;
|
||||||
if(!done_init)
|
if(!done_init)
|
||||||
{
|
{
|
||||||
av_register_all();
|
av_register_all();
|
||||||
|
|
|
@ -21,11 +21,15 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
class FFmpeg_Decoder : public Sound_Decoder
|
class FFmpeg_Decoder : public Sound_Decoder
|
||||||
{
|
{
|
||||||
struct MyStream;
|
|
||||||
|
|
||||||
AVFormatContext *mFormatCtx;
|
AVFormatContext *mFormatCtx;
|
||||||
|
AVStream **mStream;
|
||||||
|
|
||||||
|
AVPacket mPacket;
|
||||||
|
AVFrame *mFrame;
|
||||||
|
|
||||||
|
int mFrameSize;
|
||||||
|
int mFramePos;
|
||||||
|
|
||||||
std::auto_ptr<MyStream> mStream;
|
|
||||||
size_t mSamplesRead;
|
size_t mSamplesRead;
|
||||||
|
|
||||||
bool getNextPacket();
|
bool getNextPacket();
|
||||||
|
@ -35,6 +39,9 @@ namespace MWSound
|
||||||
static int writePacket(void *user_data, uint8_t *buf, int buf_size);
|
static int writePacket(void *user_data, uint8_t *buf, int buf_size);
|
||||||
static int64_t seek(void *user_data, int64_t offset, int whence);
|
static int64_t seek(void *user_data, int64_t offset, int whence);
|
||||||
|
|
||||||
|
bool getAVAudioData();
|
||||||
|
size_t readAVAudioData(void *data, size_t length);
|
||||||
|
|
||||||
virtual void open(const std::string &fname);
|
virtual void open(const std::string &fname);
|
||||||
virtual void close();
|
virtual void close();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue