1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-30 15:18:42 +02:00

integrate OD FFmpeg to work with multiple formats, including wav

also move streamContext to ffmpeg.h to allow for refactoring of import code
This commit is contained in:
mchinen 2012-06-01 06:11:07 +00:00
parent 8cb2a38fbe
commit 816b58bc08
5 changed files with 228 additions and 296 deletions

View File

@ -420,6 +420,136 @@ fail:
return err;
}
streamContext *import_ffmpeg_read_next_frame(AVFormatContext* formatContext,
streamContext** streams,
unsigned int numStreams)
{
streamContext *sc = NULL;
AVPacket pkt;
if (av_read_frame(formatContext,&pkt) < 0)
{
return NULL;
}
// Find a stream to which this frame belongs to
for (int i = 0; i < numStreams; i++)
{
if (streams[i]->m_stream->index == pkt.stream_index)
sc = streams[i];
}
// Off-stream packet. Don't panic, just skip it.
// When not all streams are selected for import this will happen very often.
if (sc == NULL)
{
av_free_packet(&pkt);
return (streamContext*)1;
}
// Copy the frame to the stream context
memcpy(&sc->m_pkt, &pkt, sizeof(AVPacket));
sc->m_pktValid = 1;
sc->m_pktDataPtr = pkt.data;
sc->m_pktRemainingSiz = pkt.size;
return sc;
}
int import_ffmpeg_decode_frame(streamContext *sc, bool flushing)
{
int nBytesDecoded;
wxUint8 *pDecode = sc->m_pktDataPtr;
int nDecodeSiz = sc->m_pktRemainingSiz;
sc->m_frameValid = 0;
if (flushing)
{
// If we're flushing the decoders we don't actually have any new data to decode.
pDecode = NULL;
nDecodeSiz = 0;
}
else
{
if (!sc->m_pktValid || (sc->m_pktRemainingSiz <= 0))
{
//No more data
return -1;
}
}
sc->m_samplefmt = sc->m_codecCtx->sample_fmt;
sc->m_samplesize = av_get_bits_per_sample_fmt(sc->m_samplefmt) / 8;
unsigned int newsize = FFMAX(sc->m_pkt.size * sc->m_samplesize, AVCODEC_MAX_AUDIO_FRAME_SIZE);
// Reallocate the audio sample buffer if it's smaller than the frame size.
if (newsize > sc->m_decodedAudioSamplesSiz )
{
if (sc->m_decodedAudioSamples)
{
av_free(sc->m_decodedAudioSamples);
}
sc->m_decodedAudioSamples = (uint8_t *) av_malloc(newsize);
sc->m_decodedAudioSamplesSiz = newsize;
if (sc->m_decodedAudioSamples == NULL)
{
//Can't allocate bytes
return -1;
}
}
sc->m_decodedAudioSamplesValidSiz = sc->m_decodedAudioSamplesSiz;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(52, 25, 0)
// avcodec_decode_audio3() expects the size of the output buffer as the 3rd parameter but
// also returns the number of bytes it decoded in the same parameter.
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = pDecode;
avpkt.size = nDecodeSiz;
nBytesDecoded =
avcodec_decode_audio3(sc->m_codecCtx,
(int16_t *)sc->m_decodedAudioSamples, // out
&sc->m_decodedAudioSamplesValidSiz, // in/out
&avpkt); // in
#else
// avcodec_decode_audio2() expects the size of the output buffer as the 3rd parameter but
// also returns the number of bytes it decoded in the same parameter.
nBytesDecoded =
avcodec_decode_audio2(sc->m_codecCtx,
(int16_t *) sc->m_decodedAudioSamples, // out
&sc->m_decodedAudioSamplesValidSiz, // in/out
pDecode, // in
nDecodeSiz); // in
#endif
if (nBytesDecoded < 0)
{
// Decoding failed. Don't stop.
return -1;
}
// We may not have read all of the data from this packet. If so, the user can call again.
// Whether or not they do depends on if m_pktRemainingSiz == 0 (they can check).
sc->m_pktDataPtr += nBytesDecoded;
sc->m_pktRemainingSiz -= nBytesDecoded;
// At this point it's normally safe to assume that we've read some samples. However, the MPEG
// audio decoder is broken. If this is the case then we just return with m_frameValid == 0
// but m_pktRemainingSiz perhaps != 0, so the user can call again.
if (sc->m_decodedAudioSamplesValidSiz > 0)
{
sc->m_frameValid = 1;
}
return 0;
}
/*******************************************************/
class FFmpegNotFoundDialog;

View File

@ -105,6 +105,7 @@ void FFmpegStartup();
bool LoadFFmpeg(bool showerror);
/// If Audacity failed to load libav*, this dialog
/// shows up and tells user about that. It will pop-up
/// again and again until it is disabled.
@ -330,8 +331,6 @@ void DropFFmpegLibs();
int ufile_fopen(AVIOContext **s, const wxString & name, int flags);
int ufile_fopen_input(AVFormatContext **ic_ptr, wxString & name);
//moving from ImportFFmpeg.cpp to FFMpeg.h so other cpp files can use this struct.
#ifdef EXPERIMENTAL_OD_FFMPEG
typedef struct _streamContext
{
bool m_use; // TRUE = this stream will be loaded into Audacity
@ -359,7 +358,14 @@ typedef struct _streamContext
sampleFormat m_osamplefmt; // output sample format
} streamContext;
#endif
// common utility functions
// utility calls that are shared with ImportFFmpeg and ODDecodeFFmpegTask
streamContext *import_ffmpeg_read_next_frame(AVFormatContext* formatContext,
streamContext** streams,
unsigned int numStreams);
int import_ffmpeg_decode_frame(streamContext *sc, bool flushing);
extern "C" {
// A little explanation of what's going on here.

View File

@ -46,8 +46,10 @@ ODDecodeBlockFile::ODDecodeBlockFile(wxFileName baseFileName,wxFileName audioFil
mAliasStart(aliasStart),
mAliasChannel(aliasChannel)
{
mDecoder = NULL;
mDataAvailable=false;
mAudioFileName = audioFileName;
mFormat = int16Sample;
}
/// Create the memory structure to refer to the given block file
@ -60,8 +62,10 @@ ODDecodeBlockFile::ODDecodeBlockFile(wxFileName existingFile, wxFileName audioFi
mAliasStart(aliasStart),
mAliasChannel(aliasChannel)
{
mDecoder = NULL;
mDataAvailable=dataAvailable;
mAudioFileName = audioFileName;
mFormat = int16Sample;
}
@ -324,8 +328,10 @@ int ODDecodeBlockFile::WriteODDecodeBlockFile()
ret = mDecoder->Decode(sampleData, mFormat, mAliasStart, mLen, mAliasChannel);
mDecoderMutex.Unlock();
if(ret < 0)
if(ret < 0) {
printf("ODDecodeBlockFile Decode failure\n");
return ret; //failure
}
//the summary is also calculated here.
mFileNameMutex.Lock();
@ -559,7 +565,7 @@ bool ODDecodeBlockFile::ReadSummary(void *data)
void ODDecodeBlockFile::SetODFileDecoder(ODFileDecoder* decoder)
{
//since this is the only place that writes to mdecoder, it is totally thread-safe to read check without the mutex
if(decoder==mDecoder)
if(decoder == mDecoder)
return;
mDecoderMutex.Lock();
mDecoder = decoder;

View File

@ -162,36 +162,7 @@ static const wxChar *exts[] =
extern FFmpegLibs *FFmpegLibsInst;
class FFmpegImportFileHandle;
//moving from ImportFFmpeg.cpp to FFMpeg.h so other cpp files can use this struct.
#ifndef EXPERIMENTAL_OD_FFMPEG
typedef struct _streamContext
{
bool m_use; // TRUE = this stream will be loaded into Audacity
AVStream *m_stream; // an AVStream *
AVCodecContext *m_codecCtx; // pointer to m_stream->codec
AVPacket m_pkt; // the last AVPacket we read for this stream
int m_pktValid; // is m_pkt valid?
uint8_t *m_pktDataPtr; // pointer into m_pkt.data
int m_pktRemainingSiz;
int64_t m_pts; // the current presentation time of the input stream
int64_t m_ptsOffset; // packets associated with stream are relative to this
int m_frameValid; // is m_decodedVideoFrame/m_decodedAudioSamples valid?
uint8_t *m_decodedAudioSamples; // decoded audio samples stored here
unsigned int m_decodedAudioSamplesSiz; // current size of m_decodedAudioSamples
int m_decodedAudioSamplesValidSiz; // # valid bytes in m_decodedAudioSamples
int m_initialchannels; // number of channels allocated when we begin the importing. Assumes that number of channels doesn't change on the fly.
int m_samplesize; // input sample size in bytes
SampleFormat m_samplefmt; // input sample format
int m_osamplesize; // output sample size in bytes
sampleFormat m_osamplefmt; // output sample format
} streamContext;
#endif
/// A representative of FFmpeg loader in
/// the Audacity import plugin list
class FFmpegImportPlugin : public ImportPlugin
@ -730,128 +701,12 @@ int FFmpegImportFileHandle::Import(TrackFactory *trackFactory,
streamContext *FFmpegImportFileHandle::ReadNextFrame()
{
streamContext *sc = NULL;
AVPacket pkt;
if (av_read_frame(mFormatContext,&pkt) < 0)
{
return NULL;
}
// Find a stream to which this frame belongs to
for (int i = 0; i < mNumStreams; i++)
{
if (mScs[i]->m_stream->index == pkt.stream_index)
sc = mScs[i];
}
// Off-stream packet. Don't panic, just skip it.
// When not all streams are selected for import this will happen very often.
if (sc == NULL)
{
av_free_packet(&pkt);
return (streamContext*)1;
}
// Copy the frame to the stream context
memcpy(&sc->m_pkt, &pkt, sizeof(AVPacket));
sc->m_pktValid = 1;
sc->m_pktDataPtr = pkt.data;
sc->m_pktRemainingSiz = pkt.size;
return sc;
return import_ffmpeg_read_next_frame(mFormatContext, mScs, mNumStreams);
}
int FFmpegImportFileHandle::DecodeFrame(streamContext *sc, bool flushing)
{
int nBytesDecoded;
wxUint8 *pDecode = sc->m_pktDataPtr;
int nDecodeSiz = sc->m_pktRemainingSiz;
sc->m_frameValid = 0;
if (flushing)
{
// If we're flushing the decoders we don't actually have any new data to decode.
pDecode = NULL;
nDecodeSiz = 0;
}
else
{
if (!sc->m_pktValid || (sc->m_pktRemainingSiz <= 0))
{
//No more data
return -1;
}
}
sc->m_samplefmt = sc->m_codecCtx->sample_fmt;
sc->m_samplesize = av_get_bits_per_sample_fmt(sc->m_samplefmt) / 8;
unsigned int newsize = FFMAX(sc->m_pkt.size * sc->m_samplesize, AVCODEC_MAX_AUDIO_FRAME_SIZE);
// Reallocate the audio sample buffer if it's smaller than the frame size.
if (newsize > sc->m_decodedAudioSamplesSiz )
{
if (sc->m_decodedAudioSamples)
{
av_free(sc->m_decodedAudioSamples);
}
sc->m_decodedAudioSamples = (uint8_t *) av_malloc(newsize);
sc->m_decodedAudioSamplesSiz = newsize;
if (sc->m_decodedAudioSamples == NULL)
{
//Can't allocate bytes
return -1;
}
}
sc->m_decodedAudioSamplesValidSiz = sc->m_decodedAudioSamplesSiz;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(52, 25, 0)
// avcodec_decode_audio3() expects the size of the output buffer as the 3rd parameter but
// also returns the number of bytes it decoded in the same parameter.
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = pDecode;
avpkt.size = nDecodeSiz;
nBytesDecoded =
avcodec_decode_audio3(sc->m_codecCtx,
(int16_t *)sc->m_decodedAudioSamples, // out
&sc->m_decodedAudioSamplesValidSiz, // in/out
&avpkt); // in
#else
// avcodec_decode_audio2() expects the size of the output buffer as the 3rd parameter but
// also returns the number of bytes it decoded in the same parameter.
nBytesDecoded =
avcodec_decode_audio2(sc->m_codecCtx,
(int16_t *) sc->m_decodedAudioSamples, // out
&sc->m_decodedAudioSamplesValidSiz, // in/out
pDecode, // in
nDecodeSiz); // in
#endif
if (nBytesDecoded < 0)
{
// Decoding failed. Don't stop.
return -1;
}
// We may not have read all of the data from this packet. If so, the user can call again.
// Whether or not they do depends on if m_pktRemainingSiz == 0 (they can check).
sc->m_pktDataPtr += nBytesDecoded;
sc->m_pktRemainingSiz -= nBytesDecoded;
// At this point it's normally safe to assume that we've read some samples. However, the MPEG
// audio decoder is broken. If this is the case then we just return with m_frameValid == 0
// but m_pktRemainingSiz perhaps != 0, so the user can call again.
if (sc->m_decodedAudioSamplesValidSiz > 0)
{
sc->m_frameValid = 1;
}
return 0;
return import_ffmpeg_decode_frame(sc, flushing);
}
int FFmpegImportFileHandle::WriteData(streamContext *sc)

View File

@ -13,6 +13,8 @@
#include "../Audacity.h" // needed before FFmpeg.h
#include "../FFmpeg.h" // which brings in avcodec.h, avformat.h
#include "../import/ImportFFmpeg.h"
#ifndef WX_PRECOMP
// Include your minimal set of headers here, or wx.h
#include <wx/window.h>
@ -32,10 +34,12 @@ extern FFmpegLibs *FFmpegLibsInst;
//struct for caching the decoded samples to be used over multiple blockfiles
typedef struct _FFmpegDecodeCache
{
int16_t* samplePtr;//interleaved samples - currently ffmpeg only uses 16 bit int
uint8_t* samplePtr;//interleaved samples
sampleCount start;
sampleCount len;
int numChannels;
SampleFormat samplefmt; // input (from libav) sample format
} FFMpegDecodeCache;
@ -70,7 +74,7 @@ private:
void InsertCache(FFMpegDecodeCache* cache);
//puts the actual audio samples into the blockfile's data array
int FillDataFromCache(samplePtr & data, sampleCount & start, sampleCount& len, unsigned int channel);
int FillDataFromCache(samplePtr & data, sampleFormat outFormat, sampleCount & start, sampleCount& len, unsigned int channel);
///REFACTORABLE CODE FROM IMPORT FFMPEG
///! Reads next audio frame
///\return pointer to the stream context structure to which the frame belongs to or NULL on error, or 1 if stream is not to be imported.
@ -262,8 +266,7 @@ ODFFmpegDecoder::~ODFFmpegDecoder()
#define kMaxSeekRewindAttempts 8
int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount start, sampleCount len, unsigned int channel)
{
//it looks like the code in importFFmpeg.cpp only imports 16 bit int - need to see why.
format = int16Sample;
format = mScs[mStreamIndex]->m_osamplefmt;
data = NewSamples(len, format);
samplePtr bufStart = data;
@ -276,7 +279,7 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
if(mCurrentPos > start && mCurrentPos <= start+len + kDecodeSampleAllowance)
{
//this next call takes data, start and len as reference variables and updates them to reflect the new area that is needed.
FillDataFromCache(bufStart,start,len,channel);
FillDataFromCache(bufStart, format, start,len,channel);
}
@ -287,7 +290,7 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
int stindex = -1;
uint64_t targetts;
printf("attempting seek to %llu\n", start);
//printf("attempting seek to %llu\n", start);
//we have to find the index for this stream.
for (unsigned int i = 0; i < mFormatContext->nb_streams; i++) {
if (mFormatContext->streams[i] == sc->m_stream )
@ -310,7 +313,7 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
mCurrentPos = actualDecodeStart;
//if the seek was past our desired position, rewind a bit.
printf("seek ok to %llu samps, float: %f\n",actualDecodeStart,actualDecodeStartDouble);
//printf("seek ok to %llu samps, float: %f\n",actualDecodeStart,actualDecodeStartDouble);
} else
break;
}
@ -336,21 +339,35 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
double actualDecodeStartdouble = 0.52 + sc->m_stream->codec->sample_rate * sc->m_pkt.dts * ((double)sc->m_stream->time_base.num/sc->m_stream->time_base.den); //this is mostly safe because den is usually 1 or low number but check for high values.
//hack to get rounding to work to neareset frame size since dts isn't exact
if (sc->m_stream->codec->frame_size) {
actualDecodeStart = ((actualDecodeStart + sc->m_stream->codec->frame_size/2) / sc->m_stream->codec->frame_size) * sc->m_stream->codec->frame_size;
}
if(actualDecodeStart != mCurrentPos)
printf("ts not matching - now:%llu (%f), last:%llu, lastlen:%llu, start %llu, len %llu\n",actualDecodeStart, actualDecodeStartdouble, mCurrentPos, mCurrentLen, start, len);
//printf("ts not matching - now:%llu (%f), last:%llu, lastlen:%llu, start %llu, len %llu\n",actualDecodeStart, actualDecodeStartdouble, mCurrentPos, mCurrentLen, start, len);
//if we've skipped over some samples, fill the gap with silence. This could happen often in the beginning of the file.
if(actualDecodeStart>start && firstpass) {
// find the number of samples for the leading silence
int amt = actualDecodeStart - start;
FFMpegDecodeCache* cache = new FFMpegDecodeCache;
printf("skipping/zeroing %i samples. - now:%llu (%f), last:%llu, lastlen:%llu, start %llu, len %llu\n",amt,actualDecodeStart, actualDecodeStartdouble, mCurrentPos, mCurrentLen, start, len);
//printf("skipping/zeroing %i samples. - now:%llu (%f), last:%llu, lastlen:%llu, start %llu, len %llu\n",amt,actualDecodeStart, actualDecodeStartdouble, mCurrentPos, mCurrentLen, start, len);
//put it in the cache so the other channels can use it.
cache->numChannels = sc->m_stream->codec->channels;
cache->len = amt;
cache->start=start;
cache->samplePtr = (int16_t*) malloc(amt * cache->numChannels * sizeof(int16_t));
memset(cache->samplePtr, 0, amt * cache->numChannels * sizeof(int16_t));
// 8 bit and 16 bit audio output from ffmpeg means
// 16 bit int out.
// 32 bit int, float, double mean float out.
if (format == int16Sample)
cache->samplefmt = SAMPLE_FMT_S16;
else
cache->samplefmt = SAMPLE_FMT_FLT;
cache->samplePtr = (uint8_t*) malloc(amt * cache->numChannels * SAMPLE_SIZE(format));
memset(cache->samplePtr, 0, amt * cache->numChannels * SAMPLE_SIZE(format));
InsertCache(cache);
}
@ -389,7 +406,7 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
}
//this next call takes data, start and len as reference variables and updates them to reflect the new area that is needed.
FillDataFromCache(bufStart,start,len,channel);
FillDataFromCache(bufStart, format, start, len, channel);
//if for some reason we couldn't get the samples, fill them with silence
int16_t* outBuf = (int16_t*) bufStart;
@ -404,11 +421,10 @@ int ODFFmpegDecoder::Decode(samplePtr & data, sampleFormat & format, sampleCount
#define kODFFmpegSearchThreshold 10
///returns the number of samples filled in from start.
//also updates data and len to reflect new unfilled area - start is unmodified.
int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleCount &start, sampleCount& len, unsigned int channel)
int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat, sampleCount &start, sampleCount& len, unsigned int channel)
{
if(mDecodeCache.size() <= 0)
return 0;
int samplesFilled=0;
//do a search for the best position to start at.
@ -442,11 +458,10 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleCount &start, sam
//we only accept cache hits that touch either end - no piecing out of the middle.
//this way the amount to be decoded remains set.
if(start < mDecodeCache[i]->start+mDecodeCache[i]->len &&
start+len > mDecodeCache[i]->start)
start + len > mDecodeCache[i]->start)
{
//ffmpeg only uses 16 bit ints
int16_t* outBuf;
outBuf = (int16_t*)data;
uint8_t* outBuf;
outBuf = (uint8_t*)data;
//reject buffers that would split us into two pieces because we don't have
//a method of dealing with this yet, and it won't happen very often.
if(start<mDecodeCache[i]->start && start+len > mDecodeCache[i]->start+mDecodeCache[i]->len)
@ -462,9 +477,43 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleCount &start, sam
hitStartInCache = FFMAX(0,start-mDecodeCache[i]->start);
//we also need to find out which end was hit - if it is the tail only we need to update from a later index.
hitStartInRequest = start <mDecodeCache[i]->start?len - samplesHit: 0;
sampleCount outIndex,inIndex;
for(int j=0;j<samplesHit;j++)
{
outBuf[j+hitStartInRequest]=mDecodeCache[i]->samplePtr[(hitStartInCache+j)*nChannels+channel];
outIndex = hitStartInRequest + j;
inIndex = (hitStartInCache + j) * nChannels + channel;
switch (mDecodeCache[i]->samplefmt)
{
case SAMPLE_FMT_U8:
//printf("u8 in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
((int16_t *)outBuf)[outIndex] = (int16_t) (((uint8_t*)mDecodeCache[i]->samplePtr)[inIndex] - 0x80) << 8;
break;
case SAMPLE_FMT_S16:
//printf("u16 in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
((int16_t *)outBuf)[outIndex] = ((int16_t*)mDecodeCache[i]->samplePtr)[inIndex];
break;
case SAMPLE_FMT_S32:
//printf("s32 in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
((float *)outBuf)[outIndex] = (float) ((int32_t*)mDecodeCache[i]->samplePtr)[inIndex] * (1.0 / (1 << 31));
break;
case SAMPLE_FMT_FLT:
//printf("f in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
((float *)outBuf)[outIndex] = (float) ((float*)mDecodeCache[i]->samplePtr)[inIndex];
break;
case SAMPLE_FMT_DBL:
//printf("dbl in %llu out %llu cachelen %llu outLen %llu\n", inIndex, outIndex, mDecodeCache[i]->len, len);
((float *)outBuf)[outIndex] = (float) ((double*)mDecodeCache[i]->samplePtr)[inIndex];
break;
default:
printf("ODDecodeFFMPEG TASK unrecognized sample format\n");
return 1;
break;
}
}
//update the cursor
samplesFilled += samplesHit;
@ -476,7 +525,7 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleCount &start, sam
else
{
//we update data pointer too- but it is a typedef'd char* so be careful with the pointer math
data+= samplesHit* (sizeof(int16_t)/sizeof(*data));
data+= samplesHit * (SAMPLE_SIZE(outFormat) / sizeof(*data));
start+=samplesHit;
len -=samplesHit;
}
@ -493,130 +542,15 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleCount &start, sam
//get the right stream pointer.
streamContext* ODFFmpegDecoder::ReadNextFrame()
{
streamContext *sc = NULL;
AVPacket pkt;
if (av_read_frame(mFormatContext,&pkt) < 0)
{
return NULL;
}
// Find a stream to which this frame belongs to
for (int i = 0; i < mNumStreams; i++)
{
if (mScs[i]->m_stream->index == pkt.stream_index)
sc = mScs[i];
}
// Off-stream packet. Don't panic, just skip it.
// When not all streams are selected for import this will happen very often.
if (sc == NULL)
{
av_free_packet(&pkt);
return (streamContext*)1;
}
// Copy the frame to the stream context
memcpy(&sc->m_pkt, &pkt, sizeof(AVPacket));
sc->m_pktValid = 1;
sc->m_pktDataPtr = pkt.data;
sc->m_pktRemainingSiz = pkt.size;
return sc;
return import_ffmpeg_read_next_frame(mFormatContext, mScs, mNumStreams);
}
int ODFFmpegDecoder::DecodeFrame(streamContext *sc, bool flushing)
{
int nBytesDecoded;
wxUint8 *pDecode = sc->m_pktDataPtr;
int nDecodeSiz = sc->m_pktRemainingSiz;
//check to see if the sc has already been decoded in our sample range
sc->m_frameValid = 0;
if (flushing)
{
// If we're flushing the decoders we don't actually have any new data to decode.
pDecode = NULL;
nDecodeSiz = 0;
}
else
{
if (!sc->m_pktValid || (sc->m_pktRemainingSiz <= 0))
{
//No more data
return -1;
}
}
// Reallocate the audio sample buffer if it's smaller than the frame size.
if (!flushing)
{
// av_fast_realloc() will only reallocate the buffer if m_decodedAudioSamplesSiz is
// smaller than third parameter. It also returns new size in m_decodedAudioSamplesSiz
//\warning { for some reason using the following macro call right in the function call
// causes Audacity to crash in some unknown place. With "newsize" it works fine }
int newsize = FFMAX(sc->m_pkt.size*sizeof(*sc->m_decodedAudioSamples), AVCODEC_MAX_AUDIO_FRAME_SIZE);
sc->m_decodedAudioSamples = (uint8_t*)av_fast_realloc(sc->m_decodedAudioSamples,
&sc->m_decodedAudioSamplesSiz,
newsize
);
if (sc->m_decodedAudioSamples == NULL)
{
//Can't allocate bytes
return -1;
}
}
// avcodec_decode_audio2() expects the size of the output buffer as the 3rd parameter but
// also returns the number of bytes it decoded in the same parameter.
sc->m_decodedAudioSamplesValidSiz = sc->m_decodedAudioSamplesSiz;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(52, 25, 0)
// avcodec_decode_audio3() expects the size of the output buffer as the 3rd parameter but
// also returns the number of bytes it decoded in the same parameter.
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = pDecode;
avpkt.size = nDecodeSiz;
nBytesDecoded =
avcodec_decode_audio3(sc->m_codecCtx,
(int16_t *)sc->m_decodedAudioSamples, // out
&sc->m_decodedAudioSamplesValidSiz, // in/out
&avpkt); // in
#else
// avcodec_decode_audio2() expects the size of the output buffer as the 3rd parameter but
// also returns the number of bytes it decoded in the same parameter.
nBytesDecoded =
avcodec_decode_audio2(sc->m_codecCtx,
(int16_t *) sc->m_decodedAudioSamples, // out
&sc->m_decodedAudioSamplesValidSiz, // in/out
pDecode, // in
nDecodeSiz); // in
#endif
if (nBytesDecoded < 0)
{
// Decoding failed. Don't stop.
return -1;
}
// We may not have read all of the data from this packet. If so, the user can call again.
// Whether or not they do depends on if m_pktRemainingSiz == 0 (they can check).
sc->m_pktDataPtr += nBytesDecoded;
sc->m_pktRemainingSiz -= nBytesDecoded;
// At this point it's normally safe to assume that we've read some samples. However, the MPEG
// audio decoder is broken. If this is the case then we just return with m_frameValid == 0
// but m_pktRemainingSiz perhaps != 0, so the user can call again.
if (sc->m_decodedAudioSamplesValidSiz > 0)
{
sc->m_frameValid = 1;
int ret = import_ffmpeg_decode_frame(sc, flushing);
if (ret == 0 && sc->m_frameValid) {
//stick it in the cache.
//TODO- consider growing/unioning a few cache buffers like WaveCache does.
//however we can't use wavecache as it isn't going to handle our stereo interleaved part, and isn't for samples
@ -624,11 +558,12 @@ int ODFFmpegDecoder::DecodeFrame(streamContext *sc, bool flushing)
FFMpegDecodeCache* cache = new FFMpegDecodeCache;
//len is number of samples per channel
cache->numChannels = sc->m_stream->codec->channels;
// Here we convert to 16 bit stero frame length
cache->len = (sc->m_decodedAudioSamplesValidSiz/sizeof(int16_t) ) / cache->numChannels;
cache->start=mCurrentPos;
cache->samplePtr = (int16_t*) malloc(sc->m_decodedAudioSamplesValidSiz);
memcpy(cache->samplePtr,sc->m_decodedAudioSamples,sc->m_decodedAudioSamplesValidSiz);
cache->len = (sc->m_decodedAudioSamplesValidSiz / sc->m_samplesize) / cache->numChannels;
cache->start = mCurrentPos;
cache->samplePtr = (uint8_t*) malloc(sc->m_decodedAudioSamplesValidSiz);
cache->samplefmt = sc->m_samplefmt;
memcpy(cache->samplePtr, sc->m_decodedAudioSamples, sc->m_decodedAudioSamplesValidSiz);
InsertCache(cache);
}