mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-02 16:49:41 +02:00
Bug1829, more: check all errors flushing and closing export files...
... MP3 export already did this, the other five needed work.
This commit is contained in:
parent
b3b4ace739
commit
38568f611d
@ -209,10 +209,17 @@ int ufile_close(AVIOContext *pb)
|
|||||||
{
|
{
|
||||||
std::unique_ptr<wxFile> f{ (wxFile *)pb->opaque };
|
std::unique_ptr<wxFile> f{ (wxFile *)pb->opaque };
|
||||||
|
|
||||||
if (f)
|
bool success = true;
|
||||||
f->Close();
|
if (f) {
|
||||||
|
success = f->Flush() && f->Close();
|
||||||
|
pb->opaque = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
// We're not certain that a close error is for want of space, but we'll
|
||||||
|
// guess that
|
||||||
|
return success ? 0 : -ENOSPC;
|
||||||
|
|
||||||
|
// Implicitly destroy the wxFile object here
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open a file with a (possibly) Unicode filename
|
// Open a file with a (possibly) Unicode filename
|
||||||
|
26
src/FFmpeg.h
26
src/FFmpeg.h
@ -928,6 +928,18 @@ private:
|
|||||||
|
|
||||||
// Deleter adaptor for functions like av_free that take a pointer
|
// Deleter adaptor for functions like av_free that take a pointer
|
||||||
template<typename T, typename R, R(*Fn)(T*)> struct AV_Deleter {
|
template<typename T, typename R, R(*Fn)(T*)> struct AV_Deleter {
|
||||||
|
inline R operator() (T* p) const
|
||||||
|
{
|
||||||
|
R result{};
|
||||||
|
if (p)
|
||||||
|
result = Fn(p);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization of previous for void return
|
||||||
|
template<typename T, void(*Fn)(T*)>
|
||||||
|
struct AV_Deleter<T, void, Fn> {
|
||||||
inline void operator() (T* p) const
|
inline void operator() (T* p) const
|
||||||
{
|
{
|
||||||
if (p)
|
if (p)
|
||||||
@ -959,9 +971,19 @@ using AVCodecContextHolder = std::unique_ptr<
|
|||||||
using AVDictionaryCleanup = std::unique_ptr<
|
using AVDictionaryCleanup = std::unique_ptr<
|
||||||
AVDictionary*, AV_Deleter<AVDictionary*, void, av_dict_free>
|
AVDictionary*, AV_Deleter<AVDictionary*, void, av_dict_free>
|
||||||
>;
|
>;
|
||||||
using UFileHolder = std::unique_ptr<
|
struct UFileHolder : public std::unique_ptr<
|
||||||
AVIOContext, AV_Deleter<AVIOContext, int, ufile_close>
|
AVIOContext, AV_Deleter<AVIOContext, int, ufile_close>
|
||||||
>;
|
>
|
||||||
|
{
|
||||||
|
// Close explicitly, not ignoring return values.
|
||||||
|
int close()
|
||||||
|
{
|
||||||
|
auto result = get_deleter() ( get() );
|
||||||
|
release();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T> using AVMallocHolder = std::unique_ptr<
|
template<typename T> using AVMallocHolder = std::unique_ptr<
|
||||||
T, AV_Deleter<void, void, av_free>
|
T, AV_Deleter<void, void, av_free>
|
||||||
>;
|
>;
|
||||||
|
@ -288,7 +288,7 @@ OSType sf_header_mactype(int format)
|
|||||||
|
|
||||||
ODLock libSndFileMutex;
|
ODLock libSndFileMutex;
|
||||||
|
|
||||||
void SFFileCloser::operator() (SNDFILE *sf) const
|
int SFFileCloser::operator() (SNDFILE *sf) const
|
||||||
{
|
{
|
||||||
auto err = SFCall<int>(sf_close, sf);
|
auto err = SFCall<int>(sf_close, sf);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -299,4 +299,5 @@ void SFFileCloser::operator() (SNDFILE *sf) const
|
|||||||
(_("Error (file may not have been written): %s"),
|
(_("Error (file may not have been written): %s"),
|
||||||
buffer));
|
buffer));
|
||||||
}
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,16 @@ inline R SFCall(F fun, Args&&... args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//RAII for SNDFILE*
|
//RAII for SNDFILE*
|
||||||
struct SFFileCloser { void operator () (SNDFILE*) const; };
|
struct SFFileCloser { int operator () (SNDFILE*) const; };
|
||||||
using SFFile = std::unique_ptr<SNDFILE, SFFileCloser>;
|
struct SFFile : public std::unique_ptr<SNDFILE, SFFileCloser>
|
||||||
|
{
|
||||||
|
// Close explicitly, not ignoring return values.
|
||||||
|
int close()
|
||||||
|
{
|
||||||
|
auto result = get_deleter() ( get() );
|
||||||
|
release();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -52,11 +52,18 @@ bool FileIO::IsOpened()
|
|||||||
return mOpen;
|
return mOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileIO::Close()
|
bool FileIO::Close()
|
||||||
{
|
{
|
||||||
mOutputStream.reset();
|
bool success = true;
|
||||||
|
if (mOutputStream) {
|
||||||
|
// mOutputStream->Sync() returns void! Rrr!
|
||||||
|
success = mOutputStream->GetFile()->Flush() &&
|
||||||
|
mOutputStream->Close();
|
||||||
|
mOutputStream.reset();
|
||||||
|
}
|
||||||
mInputStream.reset();
|
mInputStream.reset();
|
||||||
mOpen = false;
|
mOpen = false;
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxInputStream & FileIO::Read(void *buf, size_t size)
|
wxInputStream & FileIO::Read(void *buf, size_t size)
|
||||||
|
@ -32,7 +32,7 @@ class FileIO
|
|||||||
|
|
||||||
bool IsOpened();
|
bool IsOpened();
|
||||||
|
|
||||||
void Close();
|
bool Close();
|
||||||
|
|
||||||
wxInputStream & Read(void *buffer, size_t size);
|
wxInputStream & Read(void *buffer, size_t size);
|
||||||
wxOutputStream & Write(const void *buffer, size_t size);
|
wxOutputStream & Write(const void *buffer, size_t size);
|
||||||
@ -41,7 +41,7 @@ class FileIO
|
|||||||
wxString mName;
|
wxString mName;
|
||||||
FileIOMode mMode;
|
FileIOMode mMode;
|
||||||
std::unique_ptr<wxInputStream> mInputStream;
|
std::unique_ptr<wxInputStream> mInputStream;
|
||||||
std::unique_ptr<wxOutputStream> mOutputStream;
|
std::unique_ptr<wxFFileOutputStream> mOutputStream;
|
||||||
bool mOpen;
|
bool mOpen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -945,6 +945,12 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project,
|
|||||||
if ( !Finalize() ) // Finalize makes its own messages
|
if ( !Finalize() ) // Finalize makes its own messages
|
||||||
return ProgressResult::Cancelled;
|
return ProgressResult::Cancelled;
|
||||||
|
|
||||||
|
if ( mUfileCloser.close() != 0 ) {
|
||||||
|
// TODO: more precise message
|
||||||
|
AudacityMessageBox(_("Unable to export"));
|
||||||
|
return ProgressResult::Cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
return updateResult;
|
return updateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,10 +335,13 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
|
|||||||
mMetadata.reset();
|
mMetadata.reset();
|
||||||
|
|
||||||
auto cleanup2 = finally( [&] {
|
auto cleanup2 = finally( [&] {
|
||||||
|
if (!(updateResult == ProgressResult::Success ||
|
||||||
|
updateResult == ProgressResult::Stopped)) {
|
||||||
#ifndef LEGACY_FLAC
|
#ifndef LEGACY_FLAC
|
||||||
f.Detach(); // libflac closes the file
|
f.Detach(); // libflac closes the file
|
||||||
#endif
|
#endif
|
||||||
encoder.finish();
|
encoder.finish();
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const WaveTrackConstArray waveTracks =
|
const WaveTrackConstArray waveTracks =
|
||||||
@ -389,6 +392,20 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updateResult == ProgressResult::Success ||
|
||||||
|
updateResult == ProgressResult::Stopped) {
|
||||||
|
#ifndef LEGACY_FLAC
|
||||||
|
f.Detach(); // libflac closes the file
|
||||||
|
#endif
|
||||||
|
if (!encoder.finish())
|
||||||
|
// Do not reassign updateResult, see cleanup2
|
||||||
|
return ProgressResult::Failed;
|
||||||
|
#ifdef LEGACY_FLAC
|
||||||
|
if (!f.Flush() || !f.Close())
|
||||||
|
return ProgressResult::Failed;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return updateResult;
|
return updateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +330,11 @@ ProgressResult ExportMP2::Export(AudacityProject *project,
|
|||||||
return ProgressResult::Cancelled;
|
return ProgressResult::Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
outFile.Close();
|
if ( !outFile.Close() ) {
|
||||||
|
// TODO: more precise message
|
||||||
|
AudacityMessageBox(_("Unable to export"));
|
||||||
|
return ProgressResult::Cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
return updateResult;
|
return updateResult;
|
||||||
}
|
}
|
||||||
|
@ -359,7 +359,11 @@ ProgressResult ExportOGG::Export(AudacityProject *project,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outFile.Close();
|
if ( !outFile.Close() ) {
|
||||||
|
updateResult = ProgressResult::Cancelled;
|
||||||
|
// TODO: more precise message
|
||||||
|
AudacityMessageBox(_("Unable to export"));
|
||||||
|
}
|
||||||
|
|
||||||
return updateResult;
|
return updateResult;
|
||||||
}
|
}
|
||||||
|
@ -530,7 +530,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
|
|||||||
|
|
||||||
// Install the WAV metata in a "LIST" chunk at the end of the file
|
// Install the WAV metata in a "LIST" chunk at the end of the file
|
||||||
if (updateResult == ProgressResult::Success ||
|
if (updateResult == ProgressResult::Success ||
|
||||||
updateResult == ProgressResult::Stopped)
|
updateResult == ProgressResult::Stopped) {
|
||||||
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
|
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
|
||||||
(sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX) {
|
(sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX) {
|
||||||
if (!AddStrings(project, sf.get(), metadata, sf_format)) {
|
if (!AddStrings(project, sf.get(), metadata, sf_format)) {
|
||||||
@ -538,6 +538,12 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
|
|||||||
AudacityMessageBox(_("Unable to export"));
|
AudacityMessageBox(_("Unable to export"));
|
||||||
return ProgressResult::Cancelled;
|
return ProgressResult::Cancelled;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (0 != sf.close()) {
|
||||||
|
// TODO: more precise message
|
||||||
|
AudacityMessageBox(_("Unable to export"));
|
||||||
|
return ProgressResult::Cancelled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,6 +551,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
|
|||||||
updateResult == ProgressResult::Stopped)
|
updateResult == ProgressResult::Stopped)
|
||||||
if (((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) ||
|
if (((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) ||
|
||||||
((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV))
|
((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV))
|
||||||
|
// Note: file has closed, and gets reopened and closed again here:
|
||||||
if (!AddID3Chunk(fName, metadata, sf_format) ) {
|
if (!AddID3Chunk(fName, metadata, sf_format) ) {
|
||||||
// TODO: more precise message
|
// TODO: more precise message
|
||||||
AudacityMessageBox(_("Unable to export"));
|
AudacityMessageBox(_("Unable to export"));
|
||||||
@ -845,6 +852,9 @@ bool ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
|||||||
if (4 != f.Write(&sz, 4))
|
if (4 != f.Write(&sz, 4))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!f.Flush())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!f.Close())
|
if (!f.Close())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user