mirror of
https://github.com/cookiengineer/audacity
synced 2025-12-16 09:31:14 +01:00
Make EXPERIMENTAL_OD_FFMPEG compilable, and change some memory management
This commit is contained in:
@@ -23,6 +23,9 @@
|
||||
#ifdef USE_FFMPEG
|
||||
#ifdef EXPERIMENTAL_OD_FFMPEG
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "../FFmpeg.h" // which brings in avcodec.h, avformat.h
|
||||
#include "../import/ImportFFmpeg.h"
|
||||
|
||||
@@ -54,11 +57,13 @@ typedef struct _FFmpegDecodeCache
|
||||
///class to decode a particular file (one per file). Saves info such as filename and length (after the header is read.)
|
||||
class ODFFmpegDecoder final : public ODFileDecoder
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
///This should handle unicode converted to UTF-8 on mac/linux, but OD TODO:check on windows
|
||||
ODFFmpegDecoder(const wxString & fileName, streamContext** scs, int numStreams,WaveTrack*** channels, AVFormatContext* formatContext, int streamIndex);
|
||||
ODFFmpegDecoder(const wxString & fileName,
|
||||
const ScsPtr &scs,
|
||||
ODDecodeFFmpegTask::Streams &&channels,
|
||||
AVFormatContext* formatContext,
|
||||
int streamIndex);
|
||||
virtual ~ODFFmpegDecoder();
|
||||
|
||||
///Decodes the samples for this blockfile from the real file into a float buffer.
|
||||
@@ -92,9 +97,8 @@ private:
|
||||
///\return 0 on success, -1 if it can't decode any further
|
||||
int DecodeFrame(streamContext *sc, bool flushing);
|
||||
|
||||
int mNumStreams;
|
||||
streamContext **mScs; //!< Array of pointers to stream contexts. Length is mNumStreams.
|
||||
WaveTrack*** mChannels;
|
||||
ScsPtr mScs; //!< Pointer to array of pointers to stream contexts.
|
||||
ODDecodeFFmpegTask::Streams mChannels;
|
||||
AVFormatContext *mFormatContext; //!< Format description, also contains metadata and some useful info
|
||||
std::vector<FFMpegDecodeCache*> mDecodeCache;
|
||||
int mNumSamplesInCache;
|
||||
@@ -105,33 +109,44 @@ private:
|
||||
int mStreamIndex;
|
||||
};
|
||||
|
||||
auto ODDecodeFFmpegTask::FromList(const std::list<TrackHolders> &channels) -> Streams
|
||||
{
|
||||
Streams streams;
|
||||
streams.reserve(channels.size());
|
||||
using namespace std;
|
||||
transform(channels.begin(), channels.end(), back_inserter(streams),
|
||||
[](const TrackHolders &holders) {
|
||||
Channels channels;
|
||||
channels.reserve(holders.size());
|
||||
transform(holders.begin(), holders.end(), back_inserter(channels),
|
||||
mem_fun_ref(&TrackHolders::value_type::get)
|
||||
);
|
||||
return channels;
|
||||
}
|
||||
);
|
||||
return streams;
|
||||
}
|
||||
|
||||
//------ ODDecodeFFmpegTask definitions
|
||||
ODDecodeFFmpegTask::ODDecodeFFmpegTask(void* scs,int numStreams, WaveTrack*** channels, void* formatContext, int streamIndex)
|
||||
ODDecodeFFmpegTask::ODDecodeFFmpegTask(const ScsPtr &scs, Streams &&channels, void* formatContext, int streamIndex)
|
||||
: mChannels(std::move(channels))
|
||||
{
|
||||
mScs=scs;
|
||||
mNumStreams=numStreams;
|
||||
mChannels=channels;
|
||||
mFormatContext = formatContext;
|
||||
mStreamIndex = streamIndex;
|
||||
//TODO we probably need to create a NEW WaveTrack*** pointer and copy.
|
||||
//same for streamContext, but we should also use a ref counting system - this should be added to streamContext
|
||||
// mScs = (streamContext**)malloc(sizeof(streamContext**)*mFormatContext->nb_streams);
|
||||
}
|
||||
ODDecodeFFmpegTask::~ODDecodeFFmpegTask()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ODTask* ODDecodeFFmpegTask::Clone()
|
||||
ODTask *ODDecodeFFmpegTask::Clone()
|
||||
{
|
||||
//we need to create copies of mScs. It would be better to use a reference counter system.
|
||||
|
||||
ODDecodeFFmpegTask* clone = new ODDecodeFFmpegTask((void*)mScs,mNumStreams,mChannels,mFormatContext,mStreamIndex);
|
||||
auto clone = std::make_unique<ODDecodeFFmpegTask>(mScs, Streams{ mChannels }, mFormatContext, mStreamIndex);
|
||||
clone->mDemandSample=GetDemandSample();
|
||||
|
||||
//the decoders and blockfiles should not be copied. They are created as the task runs.
|
||||
return clone;
|
||||
return clone.release();
|
||||
}
|
||||
|
||||
///Creates an ODFileDecoder that decodes a file of filetype the subclass handles.
|
||||
@@ -140,7 +155,9 @@ ODTask* ODDecodeFFmpegTask::Clone()
|
||||
ODFileDecoder* ODDecodeFFmpegTask::CreateFileDecoder(const wxString & fileName)
|
||||
{
|
||||
// Open the file for import
|
||||
ODFFmpegDecoder *decoder = new ODFFmpegDecoder(fileName, (streamContext**) mScs,mNumStreams,mChannels,(AVFormatContext*)mFormatContext, mStreamIndex);
|
||||
ODFFmpegDecoder *decoder =
|
||||
new ODFFmpegDecoder(fileName, mScs, ODDecodeFFmpegTask::Streams{ mChannels },
|
||||
(AVFormatContext*)mFormatContext, mStreamIndex);
|
||||
|
||||
mDecoders.push_back(decoder);
|
||||
return decoder;
|
||||
@@ -219,10 +236,13 @@ test_failed:
|
||||
|
||||
|
||||
//------ ODDecodeFFmpegFileDecoder
|
||||
ODFFmpegDecoder::ODFFmpegDecoder(const wxString & fileName, streamContext** scs,int numStreams,WaveTrack*** channels, AVFormatContext* formatContext, int streamIndex)
|
||||
ODFFmpegDecoder::ODFFmpegDecoder(const wxString & fileName,
|
||||
const ScsPtr &scs,
|
||||
ODDecodeFFmpegTask::Streams &&channels,
|
||||
AVFormatContext* formatContext,
|
||||
int streamIndex)
|
||||
:ODFileDecoder(fileName),
|
||||
//mSamplesDone(0),
|
||||
mNumStreams(numStreams),
|
||||
mScs(scs),
|
||||
mFormatContext(formatContext),
|
||||
mNumSamplesInCache(0),
|
||||
@@ -233,22 +253,14 @@ mStreamIndex(streamIndex)
|
||||
PickFFmpegLibs();
|
||||
|
||||
//do a shallow copy of the 2d array.
|
||||
mChannels = new WaveTrack **[mNumStreams];
|
||||
mChannels = std::move(channels);
|
||||
|
||||
for (int s = 0; s < mNumStreams; s++)
|
||||
{
|
||||
mChannels[s] = new WaveTrack *[mScs[s]->m_stream->codec->channels];
|
||||
int c;
|
||||
for (c = 0; c < mScs[s]->m_stream->codec->channels; c++)
|
||||
{
|
||||
mChannels[s][c] = channels[s][c];
|
||||
}
|
||||
}
|
||||
// get the current stream start time.
|
||||
int64_t stream_delay = 0;
|
||||
if (mScs[streamIndex]->m_stream->start_time != int64_t(AV_NOPTS_VALUE) &&
|
||||
mScs[streamIndex]->m_stream->start_time > 0) {
|
||||
stream_delay = mScs[streamIndex]->m_stream->start_time;
|
||||
const auto sc = mScs->get()[streamIndex].get();
|
||||
if (sc->m_stream->start_time != int64_t(AV_NOPTS_VALUE) &&
|
||||
sc->m_stream->start_time > 0) {
|
||||
stream_delay = sc->m_stream->start_time;
|
||||
}
|
||||
mCurrentPos = double(stream_delay) / AV_TIME_BASE;
|
||||
|
||||
@@ -265,15 +277,6 @@ ODFFmpegDecoder::~ODFFmpegDecoder()
|
||||
av_log_set_callback(av_log_default_callback);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mNumStreams; i++)
|
||||
{
|
||||
if (mScs[i]->m_decodedAudioSamples != NULL)
|
||||
av_free(mScs[i]->m_decodedAudioSamples);
|
||||
|
||||
delete mScs[i];
|
||||
}
|
||||
free(mScs);
|
||||
|
||||
//DELETE our caches.
|
||||
while(mDecodeCache.size())
|
||||
{
|
||||
@@ -282,12 +285,6 @@ ODFFmpegDecoder::~ODFFmpegDecoder()
|
||||
mDecodeCache.erase(mDecodeCache.begin());
|
||||
}
|
||||
|
||||
//free the channel pointer arrays
|
||||
for (int s = 0; s < mNumStreams; s++)
|
||||
{
|
||||
delete[] mChannels[s];
|
||||
}
|
||||
delete[] mChannels;
|
||||
DropFFmpegLibs();
|
||||
}
|
||||
|
||||
@@ -298,7 +295,9 @@ ODFFmpegDecoder::~ODFFmpegDecoder()
|
||||
#define kMaxSeekRewindAttempts 8
|
||||
int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCount start, sampleCount len, unsigned int channel)
|
||||
{
|
||||
format = mScs[mStreamIndex]->m_osamplefmt;
|
||||
auto scs = mScs->get();
|
||||
auto sci = scs[mStreamIndex].get();
|
||||
format = sci->m_osamplefmt;
|
||||
|
||||
data.Allocate(len, format);
|
||||
samplePtr bufStart = data.ptr();
|
||||
@@ -315,7 +314,7 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo
|
||||
bool seeking = false;
|
||||
//look at the decoding timestamp and see if the next sample that will be decoded is not the next sample we need.
|
||||
if(len && (mCurrentPos > start + len || mCurrentPos + kDecodeSampleAllowance < start ) && SeekingAllowed()) {
|
||||
sc = mScs[mStreamIndex];
|
||||
sc = sci;
|
||||
AVStream* st = sc->m_stream;
|
||||
int stindex = -1;
|
||||
uint64_t targetts;
|
||||
@@ -404,9 +403,9 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo
|
||||
// 16 bit int out.
|
||||
// 32 bit int, float, double mean float out.
|
||||
if (format == int16Sample)
|
||||
cache->samplefmt = SAMPLE_FMT_S16;
|
||||
cache->samplefmt = AV_SAMPLE_FMT_S16;
|
||||
else
|
||||
cache->samplefmt = SAMPLE_FMT_FLT;
|
||||
cache->samplefmt = AV_SAMPLE_FMT_FLT;
|
||||
|
||||
cache->samplePtr = (uint8_t*) malloc(amt * cache->numChannels * SAMPLE_SIZE(format));
|
||||
|
||||
@@ -435,14 +434,15 @@ int ODFFmpegDecoder::Decode(SampleBuffer & data, sampleFormat & format, sampleCo
|
||||
// Flush the decoders if we're done.
|
||||
if((!sc || sc == (streamContext*) 1)&& len>0)
|
||||
{
|
||||
for (int i = 0; i < mNumStreams; i++)
|
||||
for (int i = 0; i < mChannels.size(); i++)
|
||||
{
|
||||
if (DecodeFrame(mScs[i], true) == 0)
|
||||
sc = scs[i].get();
|
||||
if (DecodeFrame(sc, true) == 0)
|
||||
{
|
||||
if (mScs[i]->m_pktValid)
|
||||
if (sc->m_pktValid)
|
||||
{
|
||||
av_free_packet(&mScs[i]->m_pkt);
|
||||
mScs[i]->m_pktValid = 0;
|
||||
av_free_packet(&sc->m_pkt);
|
||||
sc->m_pktValid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -530,27 +530,27 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
inIndex = (hitStartInCache + j) * nChannels + channel;
|
||||
switch (mDecodeCache[i]->samplefmt)
|
||||
{
|
||||
case SAMPLE_FMT_U8:
|
||||
case AV_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:
|
||||
case AV_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:
|
||||
case AV_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:
|
||||
case AV_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:
|
||||
case AV_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;
|
||||
@@ -588,7 +588,11 @@ int ODFFmpegDecoder::FillDataFromCache(samplePtr & data, sampleFormat outFormat,
|
||||
//get the right stream pointer.
|
||||
streamContext* ODFFmpegDecoder::ReadNextFrame()
|
||||
{
|
||||
return import_ffmpeg_read_next_frame(mFormatContext, mScs, mNumStreams);
|
||||
// Get pointer to array of contiguous unique_ptrs
|
||||
auto scs = mScs->get();
|
||||
// This reinterpret_cast to array of plain pointers is innocent
|
||||
return import_ffmpeg_read_next_frame
|
||||
(mFormatContext, reinterpret_cast<streamContext**>(scs), mChannels.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
******************************************************************/
|
||||
|
||||
#include "../Experimental.h"
|
||||
#include "../MemoryX.h"
|
||||
|
||||
#ifdef EXPERIMENTAL_OD_FFMPEG
|
||||
|
||||
@@ -25,13 +26,17 @@ class WaveTrack;
|
||||
/// A class representing a modular task to be used with the On-Demand structures.
|
||||
class ODDecodeFFmpegTask final : public ODDecodeTask
|
||||
{
|
||||
public:
|
||||
public:
|
||||
using Channels = std::vector < WaveTrack* >;
|
||||
using Streams = std::vector < Channels >;
|
||||
|
||||
static Streams FromList(const std::list<TrackHolders> &channels);
|
||||
|
||||
/// Constructs an ODTask
|
||||
ODDecodeFFmpegTask(void* scs,int numStreams, WaveTrack*** channels, void* formatContext, int streamIndex);
|
||||
ODDecodeFFmpegTask(const ScsPtr &scs, Streams &&channels, void* formatContext, int streamIndex);
|
||||
virtual ~ODDecodeFFmpegTask();
|
||||
|
||||
ODTask* Clone() override;
|
||||
ODTask *Clone() override;
|
||||
///Creates an ODFileDecoder that decodes a file of filetype the subclass handles.
|
||||
ODFileDecoder* CreateFileDecoder(const wxString & fileName) override;
|
||||
|
||||
@@ -39,10 +44,11 @@ class ODDecodeFFmpegTask final : public ODDecodeTask
|
||||
///Subclasses should override to return respective type.
|
||||
unsigned int GetODType() override {return eODFFMPEG;}
|
||||
|
||||
protected:
|
||||
WaveTrack*** mChannels;
|
||||
int mNumStreams;
|
||||
void* mScs;
|
||||
protected:
|
||||
// non-owning pointers to WaveTracks:
|
||||
Streams mChannels;
|
||||
|
||||
ScsPtr mScs;
|
||||
void* mFormatContext;
|
||||
int mStreamIndex;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user