Update of /cvsroot/audacity/audacity-src/src/import
In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv20429/src/import
Modified Files:
ImportFFmpeg.cpp
Log Message:
Code comments and cosmetic fixes
Slight changes in stream separation code.
Index: ImportFFmpeg.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/import/ImportFFmpeg.cpp,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- ImportFFmpeg.cpp 5 Aug 2008 16:39:31 -0000 1.18
+++ ImportFFmpeg.cpp 9 Aug 2008 03:07:17 -0000 1.19
@@ -158,7 +158,7 @@
typedef struct _streamContext
{
bool m_use; // TRUE = this stream
will be loaded into Audacity
- AVStream *m_stream; // an AVStream
* in gDecFormatCtx->streams[]
+ AVStream *m_stream; // an AVStream
*
AVCodecContext *m_codecCtx; //
pointer to m_stream->codec
AVPacket m_pkt; // the
last AVPacket we read for this stream
@@ -176,6 +176,8 @@
int m_initialchannels; // number of channels
allocated when we begin the importing. Assumes that number of channels doesn't
change on the fly.
} streamContext;
+/// A representative of FFmpeg loader in
+/// the Audacity import plugin list
class FFmpegImportPlugin : public ImportPlugin
{
public:
@@ -188,9 +190,12 @@
~FFmpegImportPlugin() { }
wxString GetPluginFormatDescription();
+
+ ///! Probes the file and opens it if appropriate
ImportFileHandle *Open(wxString Filename);
};
+///! Does acual import, returned by FFmpegImportPlugin::Open
class FFmpegImportFileHandle : public ImportFileHandle
{
@@ -198,29 +203,59 @@
FFmpegImportFileHandle(const wxString & name);
~FFmpegImportFileHandle();
+ ///! Format initialization
+ ///\return true if successful, false otherwise
bool Init();
+ ///! Codec initialization
+ ///\return true if successful, false otherwise
bool InitCodecs();
wxString GetFileDescription();
int GetFileUncompressedBytes();
+
+ ///! Imports audio
+ ///\return import status (see Import.cpp)
int Import(TrackFactory *trackFactory, Track ***outTracks,
int *outNumTracks, Tags *tags);
+ ///! 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.
streamContext* ReadNextFrame();
+
+ ///! Decodes the frame
+ ///\param sc - stream context (from ReadNextFrame)
+ ///\param flushing - true if flushing (no more frames left), false otherwise
+ ///\return 0 on success, -1 if it can't decode any further
int DecodeFrame(streamContext *sc, bool flushing);
+
+ ///! Writes decoded data into WaveTracks. Called by DecodeFrame
+ ///\param sc - stream context
+ ///\return 0 on success, 1 on error or interruption
int WriteData(streamContext *sc);
+
+ ///! Writes extracted metadata to tags object
+ ///\param avf - file context
+ ///\ tags - Audacity tags object
void WriteMetadata(AVFormatContext *avf, Tags *tags);
+
+ ///! Called by Import.cpp
+ ///\return number of readable streams in the file
wxInt32 GetStreamCount()
{
return mNumStreams;
}
-
+
+ ///! Called by Import.cpp
+ ///\return array of strings - descriptions of the streams
wxArrayString *GetStreamInfo()
{
return mStreamInfo;
}
+ ///! Called by Import.cpp
+ ///\param StreamID - index of the stream in mStreamInfo and mScs arrays
+ ///\param Use - true if this stream should be imported, false otherwise
void SetStreamUsage(wxInt32 StreamID, bool Use)
{
if (StreamID < mNumStreams)
@@ -229,17 +264,17 @@
private:
- AVFormatContext *mFormatContext;
- int mNumStreams; // mNumstreams is less or equal to
mFormatContext->nb_streams
- streamContext **mScs;
- wxArrayString *mStreamInfo;
+ AVFormatContext *mFormatContext; //!< Format description, also
contains metadata and some useful info
+ int mNumStreams; //!< mNumstreams is less or equal to
mFormatContext->nb_streams
+ streamContext **mScs; //!< Array of pointers to stream
contexts. Length is mNumStreams.
+ wxArrayString *mStreamInfo; //!< Array of stream descriptions.
Length is mNumStreams
- bool mCancelled;
+ bool mCancelled; //!< True if importing was canceled
by user
wxString mName;
void *mUserData;
- uint64_t mNumSamples;
- uint64_t mSamplesDone;
- WaveTrack ***mChannels;
+ uint64_t mNumSamples; //!< Used for progress dialog. May
not really be a number of samples.
+ uint64_t mSamplesDone; //!< Used for progress dialog. May
not really be a number of samples.
+ WaveTrack ***mChannels; //!< 2-dimentional array of
WaveTrack's. First dimention - streams, second - channels of a stream. Length
is mNumStreams
};
@@ -316,11 +351,15 @@
bool FFmpegImportFileHandle::InitCodecs()
{
+ // Allocate the array of pointers to hold stream contexts pointers
+ // Some of the allocated space may be unused (corresponds to video,
subtitle, or undecodeable audio streams)
mScs =
(streamContext**)malloc(sizeof(streamContext**)*mFormatContext->nb_streams);
+ // Fill the stream contexts
for (unsigned int i = 0; i < mFormatContext->nb_streams; i++)
{
if (mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
{
+ //Create a context
streamContext *sc = new streamContext;
memset(sc,0,sizeof(*sc));
@@ -351,6 +390,7 @@
continue;
}
+ // Stream is decodeable and it is audio. Add it and it's decription
to the arrays
wxString strinfo;
strinfo.Printf(_("Index[%02x] Codec[%S], Language[%S],
Duration[%d]"),sc->m_stream->id,codec->name,sc->m_stream->language,sc->m_stream->duration);
mStreamInfo->Add(strinfo);
@@ -358,6 +398,7 @@
}
//for video and unknown streams do nothing
}
+ //It doesn't really returns false, but GetStreamCount() will return 0 if
file is composed entierly of unreadable streams
return true;
}
@@ -382,6 +423,7 @@
CreateProgress();
+ // Remove stream contexts which are not marked for importing and adjust
mScs and mNumStreams accordingly
for (int i = 0; i < mNumStreams;)
{
if (!mScs[i]->m_use)
@@ -401,7 +443,10 @@
for (int s = 0; s < mNumStreams; s++)
{
+ // As you can see, it's really a number of frames.
+ // TODO: use something other than nb_frames for progress reporting
(nb_frames is not available for some formats). Maybe something from the format
context?
mNumSamples += mScs[s]->m_stream->nb_frames;
+ // There is a possibility that number of channels will change over time,
but we do not have WaveTracks for new channels. Remember the number of channels
and stick to it.
mScs[s]->m_initialchannels = mScs[s]->m_stream->codec->channels;
mChannels[s] = new WaveTrack *[mScs[s]->m_stream->codec->channels];
int c;
@@ -430,51 +475,50 @@
}
}
- int64_t delay = 0;
- if (mFormatContext->start_time != AV_NOPTS_VALUE)
- {
- delay = mFormatContext->start_time;
- wxLogMessage(wxT("Container start_time = %d, that would be %d
milliseconds."),mFormatContext->start_time,double(mFormatContext->start_time)/AV_TIME_BASE*1000);
- //wxLogMessage(wxT("start_time support is not implemented in FFmpeg
import plugin. Patches are welcome."));
- }
-
+ // Handles the start_time by creating silence. This may or may not be
correct.
+ // There is a possibility that we should ignore first N milliseconds of
audio instead. I do not know.
+ // TODO: Nag FFmpeg devs about start_time until they finally say WHAT is
this and HOW to handle it.
for (int s = 0; s < mNumStreams; s++)
{
int64_t stream_delay = 0;
if (mScs[s]->m_stream->start_time != AV_NOPTS_VALUE)
{
stream_delay = mScs[s]->m_stream->start_time;
- wxLogMessage(wxT("Stream %d start_time = %d, that would be %f
milliseconds."), s, mScs[s]->m_stream->start_time,
double(mScs[s]->m_stream->start_time)/AV_TIME_BASE*1000);
+ wxLogMessage(wxT("Stream %d start_time = %d, that would be %f
milliseconds."), s, mScs[s]->m_stream->start_time,
double(mScs[s]->m_stream->start_time)/AV_TIME_BASE*1000);
}
- if (delay != 0 || stream_delay != 0)
+ if (stream_delay != 0)
{
for (int c = 0; c < mScs[s]->m_stream->codec->channels; c++)
{
WaveTrack *t = mChannels[s][c];
- double len = double(delay+stream_delay)/AV_TIME_BASE;
- t->InsertSilence(0,double(delay+stream_delay)/AV_TIME_BASE);
+ double len = double(stream_delay)/AV_TIME_BASE;
+ t->InsertSilence(0,double(stream_delay)/AV_TIME_BASE);
}
}
}
-
+ // This is the heart of the importing process
streamContext *sc = NULL;
+ // The result of Import() to be returend. It will be something other than
zero if user canceled or some error appears.
int res = 0;
+ // Read next frame.
while ((sc = ReadNextFrame()) != NULL && (res == 0))
{
+ // ReadNextFrame returns 1 if stream is not to be imported
if (sc != (streamContext*)1)
{
+ // Decode frame until it is not possible to decode any further
while (sc->m_pktRemainingSiz > 0 && (res == 0))
{
if (DecodeFrame(sc,false) < 0)
break;
-
+ // If something useable was decoded - write it to mChannels
if (sc->m_frameValid)
res = WriteData(sc);
-
}
+ // Cleanup after frame decoding
if (sc->m_pktValid)
{
av_free_packet(&sc->m_pkt);
@@ -488,7 +532,7 @@
{
for (int i = 0; i < mNumStreams; i++)
{
- if (DecodeFrame(mScs[i], 1) == 0)
+ if (DecodeFrame(mScs[i], true) == 0)
{
WriteData(mScs[i]);
@@ -501,6 +545,7 @@
}
}
+ // Something bad happened - destroy everything!
if (res)
{
for (int s = 0; s < mNumStreams; s++)
@@ -521,8 +566,10 @@
*outNumTracks += mScs[s]->m_stream->codec->channels;
}
+ // Create new tracks
*outTracks = new Track *[*outNumTracks];
+ // Copy audio from mChannels to newly created tracks (destroying mChannels
elements in process)
int trackindex = 0;
for (int s = 0; s < mNumStreams; s++)
{
@@ -535,7 +582,7 @@
}
delete[] mChannels;
-
+ // Save metadata
WriteMetadata(mFormatContext,tags);
return eImportSuccess;
@@ -551,20 +598,22 @@
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.
+ // 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;
@@ -603,7 +652,7 @@
// 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 }
+ // 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 =
(int16_t*)FFmpegLibsInst->av_fast_realloc(sc->m_decodedAudioSamples,
&sc->m_decodedAudioSamplesSiz,
@@ -621,9 +670,9 @@
// also returns the number of bytes it decoded in the same parameter.
sc->m_decodedAudioSamplesValidSiz = sc->m_decodedAudioSamplesSiz;
nBytesDecoded = FFmpegLibsInst->avcodec_decode_audio2(sc->m_codecCtx,
- sc->m_decodedAudioSamples, // out
+ sc->m_decodedAudioSamples, // out
&sc->m_decodedAudioSamplesValidSiz, // in/out
- pDecode, nDecodeSiz); // in
+ pDecode, nDecodeSiz); // in
if (nBytesDecoded < 0)
{
@@ -650,6 +699,7 @@
{
size_t pos = 0;
+ // Find the stream index in mScs array
int streamid = -1;
for (int i = 0; i < mNumStreams; i++)
{
@@ -659,29 +709,34 @@
break;
}
}
+ // Stream is not found. This should not really happen
if (streamid == -1)
{
return 1;
}
+ // Allocate the buffer to store audio.
int nChannels = sc->m_stream->codec->channels < sc->m_initialchannels ?
sc->m_stream->codec->channels : sc->m_initialchannels;
int16_t **tmp = (int16_t**)malloc(sizeof(short*)*nChannels);
for (int chn = 0; chn < nChannels; chn++)
{
- tmp[chn] =
(int16_t*)malloc(sizeof(int16_t)*sc->m_decodedAudioSamplesValidSiz/sizeof(int16_t)/nChannels);
+ tmp[chn] =
(int16_t*)malloc(sizeof(int16_t)*sc->m_decodedAudioSamplesValidSiz/sizeof(int16_t)/sc->m_stream->codec->channels);
}
+ // Separate the channels
int index = 0;
while (pos < sc->m_decodedAudioSamplesValidSiz/sizeof(int16_t))
{
- for (int chn=0; chn < nChannels; chn++)
+ for (int chn=0; chn < sc->m_stream->codec->channels; chn++)
{
- tmp[chn][index] = sc->m_decodedAudioSamples[pos];
+ if (chn < nChannels)
+ tmp[chn][index] = sc->m_decodedAudioSamples[pos];
pos++;
}
index++;
}
+ // Write audio into WaveTracks
for (int chn=0; chn < nChannels; chn++)
{
mChannels[streamid][chn]->Append((samplePtr)tmp[chn],int16Sample,index);
@@ -690,6 +745,7 @@
free(tmp);
+ // Try to update the progress indicator (and see if user wants to cancel)
int tsize = FFmpegLibsInst->url_fsize(mFormatContext->pb);
if (!mProgress->Update((wxLongLong)this->mFormatContext->pb->pos,
(wxLongLong)(tsize > 0 ? tsize : 1))) {
mCancelled = true;
@@ -701,10 +757,10 @@
void FFmpegImportFileHandle::WriteMetadata(AVFormatContext *avf,Tags *tags)
{
-
tags->Clear();
-
+ // We are assuming that tags are in UTF8.
+ // TODO: for some formats tags are not in UTF8. Detect and handle that.
tags->SetTag(TAG_TITLE,wxString::FromUTF8(avf->title));
tags->SetTag(TAG_ARTIST,wxString::FromUTF8(avf->author));
//tags->SetTag(TAG_COPYRIGHT,avf->copyright);
@@ -713,7 +769,6 @@
tags->SetTag(TAG_YEAR,avf->year);
tags->SetTag(TAG_TRACK,avf->track);
tags->SetTag(TAG_GENRE,wxString::FromUTF8(avf->genre));
-
}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Audacity-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/audacity-cvs