int ExportMP2::Export(AudacityProject *project, int channels, const wxString &fName, bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, const Tags *metadata, int WXUNUSED(subformat)) { bool stereo = (channels == 2); long bitrate = gPrefs->Read(wxT("/FileFormats/MP2Bitrate"), 160); double rate = project->GetRate(); const TrackList *tracks = project->GetTracks(); wxLogNull logNo; /* temporarily disable wxWidgets error messages */ twolame_options *encodeOptions; encodeOptions = twolame_init(); twolame_set_in_samplerate(encodeOptions, (int)(rate + 0.5)); twolame_set_out_samplerate(encodeOptions, (int)(rate + 0.5)); twolame_set_bitrate(encodeOptions, bitrate); twolame_set_num_channels(encodeOptions, stereo ? 2 : 1); if (twolame_init_params(encodeOptions) != 0) { wxMessageBox(_("Cannot export MP2 with this sample rate and bit rate"), _("Error"), wxICON_STOP); twolame_close(&encodeOptions); return false; } // Put ID3 tags at beginning of file if (metadata == NULL) metadata = project->GetTags(); FileIO outFile(fName, FileIO::Output); if (!outFile.IsOpened()) { wxMessageBox(_("Unable to open target file for writing")); twolame_close(&encodeOptions); return false; } char *id3buffer = NULL; int id3len; bool endOfFile; id3len = AddTags(project, &id3buffer, &endOfFile, metadata); if (id3len && !endOfFile) outFile.Write(id3buffer, id3len); // Values taken from the twolame simple encoder sample const int pcmBufferSize = 9216 / 2; // number of samples const int mp2BufferSize = 16384; // bytes // We allocate a buffer which is twice as big as the // input buffer, which should always be enough. // We have to multiply by 4 because one sample is 2 bytes wide! unsigned char* mp2Buffer = new unsigned char[mp2BufferSize]; const WaveTrackConstArray waveTracks = tracks->GetWaveTrackConstArray(selectionOnly, false); int updateResult = eProgressSuccess; { auto mixer = CreateMixer(waveTracks, tracks->GetTimeTrack(), t0, t1, stereo ? 2 : 1, pcmBufferSize, true, rate, int16Sample, true, mixerSpec); ProgressDialog progress(wxFileName(fName).GetName(), selectionOnly ? wxString::Format(_("Exporting selected audio at %ld kbps"), bitrate) : wxString::Format(_("Exporting entire file at %ld kbps"), bitrate)); while (updateResult == eProgressSuccess) { sampleCount pcmNumSamples = mixer->Process(pcmBufferSize); if (pcmNumSamples == 0) break; short *pcmBuffer = (short *)mixer->GetBuffer(); int mp2BufferNumBytes = twolame_encode_buffer_interleaved( encodeOptions, pcmBuffer, pcmNumSamples, mp2Buffer, mp2BufferSize); outFile.Write(mp2Buffer, mp2BufferNumBytes); updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0); } } int mp2BufferNumBytes = twolame_encode_flush( encodeOptions, mp2Buffer, mp2BufferSize); if (mp2BufferNumBytes > 0) outFile.Write(mp2Buffer, mp2BufferNumBytes); twolame_close(&encodeOptions); delete[] mp2Buffer; /* Write ID3 tag if it was supposed to be at the end of the file */ if (id3len && endOfFile) outFile.Write(id3buffer, id3len); if (id3buffer) { free(id3buffer); } /* Close file */ outFile.Close(); return updateResult; }
bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, Tags *metadata) { int err; //FFmpegLibsInst->LoadLibs(NULL,true); //Loaded at startup or from Prefs now if (!FFmpegLibsInst->ValidLibsLoaded()) return false; FFmpegLibsInst->av_log_set_callback(av_log_wx_callback); AVFormatParameters fpOutFile; // See if libavformat has modules that can write our output format. If so, mEncFormatDesc // will describe the functions used to write the format (used internally by libavformat) // and the default video/audio codecs that the format uses. if ((mEncFormatDesc = FFmpegLibsInst->guess_format(shortname, OSINPUT(mName), NULL)) == NULL) { wxLogMessage(wxT("FFmpeg : ERROR - Can't determine format description for file \"%s\"."), mName.c_str()); return false; } // mEncFormatCtx is used by libavformat to carry around context data re our output file. if ((mEncFormatCtx = FFmpegLibsInst->av_alloc_format_context()) == NULL) { wxLogMessage(wxT("FFmpeg : ERROR - Can't allocate output format context.")); return false; } // Initialise the output format context. mEncFormatCtx->oformat = mEncFormatDesc; memcpy(mEncFormatCtx->filename, OSINPUT(mName), strlen(OSINPUT(mName))+1); // At the moment Audacity can export only one audio stream if ((mEncAudioStream = FFmpegLibsInst->av_new_stream(mEncFormatCtx, 1)) == NULL) { wxLogMessage(wxT("FFmpeg : ERROR - Can't add audio stream to output file \"%s\"."), mName.c_str()); return false; } mEncAudioStream->id = 0; mEncFormatCtx->timestamp = 0; // Open the output file. if (!(mEncFormatDesc->flags & AVFMT_NOFILE)) { if ((err = ufile_fopen(&mEncFormatCtx->pb, mName, URL_WRONLY)) < 0) { wxLogMessage(wxT("FFmpeg : ERROR - Can't open output file \"%s\" to write. Error code is %d."), mName.c_str(),err); return false; } } // Set default parameters on the format context. memset(&fpOutFile, 0, sizeof(AVFormatParameters)); if ((err = FFmpegLibsInst->av_set_parameters(mEncFormatCtx, &fpOutFile)) < 0) { wxLogMessage(wxT("FFmpeg : ERROR - Can't set output parameters for output file \"%s\". Error code is %d."), mName.c_str(),err); return false; } // I have no idea what is this mEncFormatCtx->preload = (int)(0.5 * AV_TIME_BASE); mEncFormatCtx->max_delay = (int)(0.7 * AV_TIME_BASE); // Open the audio stream's codec and initialise any stream related data. if (!InitCodecs(project)) return false; if (metadata == NULL) metadata = project->GetTags(); // Add metadata BEFORE writing the header. // At the moment that works with ffmpeg-git and ffmpeg-0.5 for MP4. if (ExportFFmpegOptions::fmts[mSubFormat].canmetadata) { mSupportsUTF8 = ExportFFmpegOptions::fmts[mSubFormat].canutf8; AddTags(metadata); } // Write headers to the output file. if ((err = FFmpegLibsInst->av_write_header(mEncFormatCtx)) < 0) { wxLogMessage(wxT("FFmpeg : ERROR - Can't write headers to output file \"%s\". Error code is %d."), mName.c_str(),err); return false; } return true; }
bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat) { int err; //FFmpegLibsInst->LoadLibs(NULL,true); //Loaded at startup or from Prefs now if (!FFmpegLibsInst->ValidLibsLoaded()) return false; av_log_set_callback(av_log_wx_callback); // See if libavformat has modules that can write our output format. If so, mEncFormatDesc // will describe the functions used to write the format (used internally by libavformat) // and the default video/audio codecs that the format uses. if ((mEncFormatDesc = av_guess_format(shortname, OSINPUT(mName), NULL)) == NULL) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't determine format description for file \"%s\"."), mName.c_str()), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } // mEncFormatCtx is used by libavformat to carry around context data re our output file. if ((mEncFormatCtx = avformat_alloc_context()) == NULL) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't allocate output format context.")), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } // Initialise the output format context. mEncFormatCtx->oformat = mEncFormatDesc; memcpy(mEncFormatCtx->filename, OSINPUT(mName), strlen(OSINPUT(mName))+1); // At the moment Audacity can export only one audio stream if ((mEncAudioStream = avformat_new_stream(mEncFormatCtx, NULL)) == NULL) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't add audio stream to output file \"%s\"."), mName.c_str()), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } mEncAudioStream->id = 0; // Open the output file. if (!(mEncFormatDesc->flags & AVFMT_NOFILE)) { if ((err = ufile_fopen(&mEncFormatCtx->pb, mName, AVIO_FLAG_WRITE)) < 0) { wxMessageBox(wxString::Format(wxT("FFmpeg : ERROR - Can't open output file \"%s\" to write. Error code is %d."), mName.c_str(), err), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } } // Open the audio stream's codec and initialise any stream related data. if (!InitCodecs(project)) return false; if (metadata == NULL) metadata = project->GetTags(); // Add metadata BEFORE writing the header. // At the moment that works with ffmpeg-git and ffmpeg-0.5 for MP4. if (GetCanMetaData(subformat)) { mSupportsUTF8 = ExportFFmpegOptions::fmts[mSubFormat].canutf8; AddTags(metadata); } // Write headers to the output file. if ((err = avformat_write_header(mEncFormatCtx, NULL)) < 0) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't write headers to output file \"%s\". Error code is %d."), mName.c_str(),err), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } return true; }
void EntityManager::AddTags(Entity::ID id, const std::string& first, const std::string& second, const Args& ... args) { AUTO_PROFILE("EntityManager::AddTags"); AddTags(id, first); AddTags(id, second, args ...); }
bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat) { // This will undo the acquisition of resources along any early exit path: auto deleter = [](ExportFFmpeg *This) { if (This) This->FreeResources(); }; std::unique_ptr<ExportFFmpeg, decltype(deleter)> cleanup{ this, deleter }; int err; //FFmpegLibsInst->LoadLibs(NULL,true); //Loaded at startup or from Prefs now if (!FFmpegLibsInst->ValidLibsLoaded()) return false; av_log_set_callback(av_log_wx_callback); // See if libavformat has modules that can write our output format. If so, mEncFormatDesc // will describe the functions used to write the format (used internally by libavformat) // and the default video/audio codecs that the format uses. if ((mEncFormatDesc = av_guess_format(shortname, OSINPUT(mName), NULL)) == NULL) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't determine format description for file \"%s\"."), mName.c_str()), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } // mEncFormatCtx is used by libavformat to carry around context data re our output file. mEncFormatCtx.reset(avformat_alloc_context()); if (!mEncFormatCtx) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't allocate output format context.")), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } // Initialise the output format context. mEncFormatCtx->oformat = mEncFormatDesc; memcpy(mEncFormatCtx->filename, OSINPUT(mName), strlen(OSINPUT(mName))+1); // At the moment Audacity can export only one audio stream if ((mEncAudioStream = avformat_new_stream(mEncFormatCtx.get(), NULL)) == NULL) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't add audio stream to output file \"%s\"."), mName.c_str()), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } // Documentation for avformat_new_stream says // "User is required to call avcodec_close() and avformat_free_context() to clean // up the allocation by avformat_new_stream()." // We use smart pointers that ensure these cleanups either in their destructors or // sooner if they are reset. These are std::unique_ptr with nondefault deleter // template parameters. // mEncFormatCtx takes care of avformat_free_context(), so // mEncAudioStream can be a plain pointer. // mEncAudioCodecCtx now becomes responsible for closing the codec: mEncAudioCodecCtx.reset(mEncAudioStream->codec); mEncAudioStream->id = 0; // Open the output file. if (!(mEncFormatDesc->flags & AVFMT_NOFILE)) { if ((err = ufile_fopen(&mEncFormatCtx->pb, mName, AVIO_FLAG_WRITE)) < 0) { wxMessageBox(wxString::Format(wxT("FFmpeg : ERROR - Can't open output file \"%s\" to write. Error code is %d."), mName.c_str(), err), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } // Give mUfileCloser responsibility mUfileCloser.reset(mEncFormatCtx->pb); } // Open the audio stream's codec and initialise any stream related data. if (!InitCodecs(project)) return false; if (metadata == NULL) metadata = project->GetTags(); // Add metadata BEFORE writing the header. // At the moment that works with ffmpeg-git and ffmpeg-0.5 for MP4. if (GetCanMetaData(subformat)) { mSupportsUTF8 = ExportFFmpegOptions::fmts[mSubFormat].canutf8; AddTags(metadata); } // Write headers to the output file. if ((err = avformat_write_header(mEncFormatCtx.get(), NULL)) < 0) { wxMessageBox(wxString::Format(_("FFmpeg : ERROR - Can't write headers to output file \"%s\". Error code is %d."), mName.c_str(),err), _("FFmpeg Error"), wxOK|wxCENTER|wxICON_EXCLAMATION); return false; } // Only now, we can keep all the resources until Finalize(). // Cancel the local cleanup. cleanup.release(); return true; }