Audacity 3.2.0
ImportFFmpeg.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5ImportFFmpeg.cpp
6
7Copyright 2008 LRN
8Based on ImportFLAC.cpp by Sami Liedes and transcode_sample.c by ANYwebcam Pty Ltd
9Licensed under the GNU General Public License v2 or later
10
11*//****************************************************************//****************************************************************//*******************************************************************/
22
23
24
25// For compilers that support precompilation, includes "wx/wx.h".
26#include <wx/wxprec.h>
27
28#include "../FFmpeg.h"
29#include "FFmpegFunctions.h"
30
31#ifndef WX_PRECOMP
32// Include your minimal set of headers here, or wx.h
33#include <wx/log.h>
34#include <wx/window.h>
35#endif
36
37#include "ProgressDialog.h"
38
39
40#define DESC XO("FFmpeg-compatible files")
41
42//TODO: remove non-audio extensions
43#if defined(USE_FFMPEG)
44static const auto exts = {
45 wxT("4xm"),
46 wxT("MTV"),
47 wxT("roq"),
48 wxT("aac"),
49 wxT("ac3"),
50 wxT("aif"),
51 wxT("aiff"),
52 wxT("afc"),
53 wxT("aifc"),
54 wxT("al"),
55 wxT("amr"),
56 wxT("apc"),
57 wxT("ape"),
58 wxT("apl"),
59 wxT("mac"),
60 wxT("asf"),
61 wxT("wmv"),
62 wxT("wma"),
63 wxT("au"),
64 wxT("avi"),
65 wxT("avs"),
66 wxT("bethsoftvid"),
67 wxT("c93"),
68 wxT("302"),
69 wxT("daud"),
70 wxT("dsicin"),
71 wxT("dts"),
72 wxT("dv"),
73 wxT("dxa"),
74 wxT("ea"),
75 wxT("cdata"),
76 wxT("ffm"),
77 wxT("film_cpk"),
78 wxT("flac"),
79 wxT("flic"),
80 wxT("flv"),
81 wxT("gif"),
82 wxT("gxf"),
83 wxT("idcin"),
84 wxT("image2"),
85 wxT("image2pipe"),
86 wxT("cgi"),
87 wxT("ipmovie"),
88 wxT("nut"),
89 wxT("lmlm4"),
90 wxT("m4v"),
91 wxT("mkv"),
92 wxT("mm"),
93 wxT("mmf"),
94 wxT("mov"),
95 wxT("mp4"),
96 wxT("m4a"),
97 wxT("m4r"),
98 wxT("3gp"),
99 wxT("3g2"),
100 wxT("mj2"),
101 wxT("mp3"),
102 wxT("mpc"),
103 wxT("mpc8"),
104 wxT("mpg"),
105 wxT("mpeg"),
106 wxT("ts"),
107 wxT("mpegtsraw"),
108 wxT("mpegvideo"),
109 wxT("msnwctcp"),
110 wxT("ul"),
111 wxT("mxf"),
112 wxT("nsv"),
113 wxT("nuv"),
114 wxT("ogg"),
115 wxT("opus"),
116 wxT("psxstr"),
117 wxT("pva"),
118 wxT("redir"),
119 wxT("rl2"),
120 wxT("rm"),
121 wxT("ra"),
122 wxT("rv"),
123 wxT("rtsp"),
124 wxT("s16be"),
125 wxT("sw"),
126 wxT("s8"),
127 wxT("sb"),
128 wxT("sdp"),
129 wxT("shn"),
130 wxT("siff"),
131 wxT("vb"),
132 wxT("son"),
133 wxT("smk"),
134 wxT("sol"),
135 wxT("swf"),
136 wxT("thp"),
137 wxT("tiertexseq"),
138 wxT("tta"),
139 wxT("txd"),
140 wxT("u16be"),
141 wxT("uw"),
142 wxT("ub"),
143 wxT("u8"),
144 wxT("vfwcap"),
145 wxT("vmd"),
146 wxT("voc"),
147 wxT("wav"),
148 wxT("wc3movie"),
149 wxT("wsaud"),
150 wxT("wsvqa"),
151 wxT("wv")
152};
153
154// all the includes live here by default
155#include "Import.h"
156#include "Tags.h"
157#include "WaveTrack.h"
158#include "ImportPlugin.h"
159
161
165{
166public:
169 {
170 }
171
173
174 wxString GetPluginStringID() override { return wxT("libav"); }
176
178 {
179 return !FFmpegFunctions::Load()
180 ? XO("Try installing FFmpeg.\n") : TranslatableString{};
181 }
182
184 std::unique_ptr<ImportFileHandle> Open(
185 const FilePath &Filename, AudacityProject*) override;
186};
187
188struct StreamContext final
189{
190 int StreamIndex { -1 };
191
192 std::unique_ptr<AVCodecContextWrapper> CodecContext;
193
196
197 bool Use { true };
198};
199
202{
203
204public:
207
210 bool Init();
213 bool InitCodecs();
214
215
218
221 ProgressResult Import(WaveTrackFactory *trackFactory, TrackHolders &outTracks,
222 Tags *tags) override;
223
227
231 void WriteMetadata(Tags *tags);
232
238 void GetMetadata(Tags &tags, const wxChar *tag, const char *name);
239
242 wxInt32 GetStreamCount() override
243 {
244 return static_cast<wxInt32>(mStreamContexts.size());
245 }
246
250 {
251 return mStreamInfo;
252 }
253
257 void SetStreamUsage(wxInt32 StreamID, bool Use) override
258 {
259 if (StreamID < static_cast<wxInt32>(mStreamContexts.size()))
260 mStreamContexts[StreamID].Use = Use;
261 }
262
263private:
264 // Construct this member first, so it is destroyed last, so the functions
265 // remain loaded while other members are destroyed
266 const std::shared_ptr<FFmpegFunctions> mFFmpeg = FFmpegFunctions::Load();
267
268 std::vector<StreamContext> mStreamContexts;
269
270 std::unique_ptr<AVFormatContextWrapper> mAVFormatContext;
271
273
274 wxInt64 mProgressPos = 0;
275 wxInt64 mProgressLen = 1;
276
277 bool mCancelled = false;
278 bool mStopped = false;
284};
285
286
288{
289 return DESC;
290}
291
292std::unique_ptr<ImportFileHandle> FFmpegImportPlugin::Open(
293 const FilePath &filename, AudacityProject*)
294{
295 auto ffmpeg = FFmpegFunctions::Load();
296
297 //Check if we're loading explicitly supported format
298 wxString extension = filename.AfterLast(wxT('.'));
299 if (SupportsExtension(extension))
300 {
301 //Audacity is trying to load something that is declared as
302 //officially supported by this plugin.
303 //If we don't have FFmpeg configured - tell the user about it.
304 //Since this will be happening often, use disableable "FFmpeg not found" dialog
305 //insdead of usual AudacityMessageBox()
306 bool newsession = NewImportingSession.Read();
307 if (!ffmpeg)
308 {
309 auto dontShowDlg = FFmpegNotFoundDontShow.Read();
310 if (dontShowDlg == 0 && newsession)
311 {
313 gPrefs->Flush();
314 FFmpegNotFoundDialog{ nullptr }.ShowModal();
315
316 ffmpeg = FFmpegFunctions::Load();
317 }
318 }
319 }
320 if (!ffmpeg)
321 {
322 return nullptr;
323 }
324
325 // Construct the handle only after any reloading of ffmpeg functions
326 auto handle = std::make_unique<FFmpegImportFileHandle>(filename);
327
328 // Open the file for import
329 bool success = handle->Init();
330
331 if (!success) {
332 return nullptr;
333 }
334
335 return handle;
336}
337
339 std::make_unique< FFmpegImportPlugin >()
340};
341
342
345, mName{ name }
346{
347}
348
350{
351 if (!mFFmpeg)
352 return false;
353
354 mAVFormatContext = mFFmpeg->CreateAVFormatContext();
355
356 const auto err = mAVFormatContext->OpenInputContext(mName, nullptr, AVDictionaryWrapper(*mFFmpeg));
357
359 {
360 wxLogError(wxT("FFmpeg : AVFormatContextWrapper::OpenInputContext() failed for file %s"), mName);
361 return false;
362 }
363
364 if (!InitCodecs())
365 return false;
366
367 return true;
368}
369
371{
372 for (unsigned int i = 0; i < mAVFormatContext->GetStreamsCount(); i++)
373 {
374 const AVStreamWrapper* stream = mAVFormatContext->GetStream(i);
375
376 if (stream->IsAudio())
377 {
378 const AVCodecIDFwd id = mAVFormatContext->GetStream(i)->GetAVCodecID();
379
380 auto codec = mFFmpeg->CreateDecoder(id);
381 auto name = mFFmpeg->avcodec_get_name(id);
382
383 if (codec == NULL)
384 {
385 wxLogError(
386 wxT("FFmpeg : CreateDecoder() failed. Index[%02d], Codec[%02x - %s]"),
387 i, id, name);
388 //FFmpeg can't decode this stream, skip it
389 continue;
390 }
391
392 auto codecContextPtr = stream->GetAVCodecContext();
393
394 if ( codecContextPtr->Open( codecContextPtr->GetCodec() ) < 0 )
395 {
396 wxLogError(wxT("FFmpeg : Open() failed. Index[%02d], Codec[%02x - %s]"),i,id,name);
397 //Can't open decoder - skip this stream
398 continue;
399 }
400
401 const int channels = codecContextPtr->GetChannels();
402 const sampleFormat preferredFormat =
403 codecContextPtr->GetPreferredAudacitySampleFormat();
404
405 auto codecContext = codecContextPtr.get();
406
407 mStreamContexts.emplace_back(
408 StreamContext { stream->GetIndex(), std::move(codecContextPtr),
409 channels, preferredFormat, true });
410
411 // Stream is decodeable and it is audio. Add it and its description to the arrays
412 int duration = 0;
413 if (stream->GetDuration() > 0)
414 duration = stream->GetDuration() * stream->GetTimeBase().num / stream->GetTimeBase().den;
415 else
416 duration = mAVFormatContext->GetDuration() / AUDACITY_AV_TIME_BASE;
417
418 wxString bitrate;
419 if (codecContext->GetBitRate() > 0)
420 bitrate.Printf(wxT("%d"),(int)codecContext->GetBitRate());
421 else
422 bitrate.Printf(wxT("?"));
423
424 AVDictionaryWrapper streamMetadata = stream->GetMetadata();
425
426 auto lang = std::string(streamMetadata.Get("language", {}));
427
428 auto strinfo = XO(
429/* i18n-hint: "codec" is short for a "coder-decoder" algorithm */
430"Index[%02x] Codec[%s], Language[%s], Bitrate[%s], Channels[%d], Duration[%d]")
431 .Format(
432 stream->GetIndex(),
433 name,
434 lang,
435 bitrate,
436 (int)codecContext->GetChannels(),
437 (int)duration);
438
439 mStreamInfo.push_back(strinfo);
440 }
441 //for video and unknown streams do nothing
442 }
443 //It doesn't really returns false, but GetStreamCount() will return 0 if file is composed entirely of unreadable streams
444 return true;
445}
446
448{
449 return DESC;
450}
451
452
454{
455 // TODO: Get Uncompressed byte count.
456 return 0;
457}
458
460 TrackHolders &outTracks,
461 Tags *tags)
462{
463 outTracks.clear();
464
466
468 mStreamContexts.erase (std::remove_if (mStreamContexts.begin (), mStreamContexts.end (), [](const StreamContext& ctx) {
469 return !ctx.Use;
470 }), mStreamContexts.end());
471
472 mChannels.resize(mStreamContexts.size());
473
474 int s = -1;
475 for (auto &stream : mChannels)
476 {
477 ++s;
478
479 const StreamContext& sc = mStreamContexts[s];
480
481 stream.resize(sc.InitialChannels);
482
483 for (auto &channel : stream)
484 channel = NewWaveTrack(*trackFactory, sc.SampleFormat, sc.CodecContext->GetSampleRate());
485 }
486
487 // Handles the start_time by creating silence. This may or may not be correct.
488 // There is a possibility that we should ignore first N milliseconds of audio instead. I do not know.
490 s = -1;
491 for (auto &stream : mChannels)
492 {
493 ++s;
494
495 int64_t stream_delay = 0;
496 const auto& sc = mStreamContexts[s];
497
498 const int64_t streamStartTime =
499 mAVFormatContext->GetStream(sc.StreamIndex)->GetStartTime();
500
502 {
503 stream_delay = streamStartTime;
504
505 wxLogDebug(
506 wxT("Stream %d start_time = %lld, that would be %f milliseconds."),
507 s, (long long)streamStartTime, double(streamStartTime) / 1000);
508 }
509
510 if (stream_delay > 0)
511 {
512 int c = -1;
513 for (auto &channel : stream)
514 {
515 ++c;
516
517 WaveTrack *t = channel.get();
518 t->InsertSilence(0,double(stream_delay)/AUDACITY_AV_TIME_BASE);
519 }
520 }
521 }
522 // This is the heart of the importing process
523 // The result of Import() to be returned. It will be something other than zero if user canceled or some error appears.
524 auto res = ProgressResult::Success;
525
526 // Read frames.
527 for (std::unique_ptr<AVPacketWrapper> packet;
528 (packet = mAVFormatContext->ReadNextPacket()) != nullptr &&
529 (res == ProgressResult::Success);)
530 {
531 // Find a matching StreamContext
532 auto streamContextIt = std::find_if(
533 mStreamContexts.begin(), mStreamContexts.end(),
534 [index = packet->GetStreamIndex()](const StreamContext& ctx)
535 { return ctx.StreamIndex == index;
536 });
537
538 if (streamContextIt == mStreamContexts.end())
539 continue;
540
541 res = WriteData(&(*streamContextIt), packet.get());
542 }
543
544 // Flush the decoders.
545 if (!mStreamContexts.empty() && (res == ProgressResult::Success || res == ProgressResult::Stopped))
546 {
547 auto emptyPacket = mFFmpeg->CreateAVPacketWrapper();
548
550 WriteData(&sc, emptyPacket.get());
551 }
552
553 // Something bad happened - destroy everything!
554 if (res == ProgressResult::Cancelled || res == ProgressResult::Failed)
555 return res;
556 //else if (res == 2), we just stop the decoding as if the file has ended
557
558 // Copy audio from mChannels to newly created tracks (destroying mChannels elements in process)
559 for (auto &stream : mChannels)
560 for(auto &channel : stream)
561 channel->Flush();
562
563 outTracks.swap(mChannels);
564
565 // Save metadata
566 WriteMetadata(tags);
567
568 return res;
569}
570
572{
573 // Find the stream index in mStreamContexts array
574 int streamid = -1;
575 auto iter = mChannels.begin();
576
577 for (int i = 0; i < static_cast<int>(mStreamContexts.size()); ++iter, ++i)
578 {
579 if (&mStreamContexts[i] == sc)
580 {
581 streamid = i;
582 break;
583 }
584 }
585 // Stream is not found. This should not really happen
586 if (streamid == -1)
587 {
589 }
590
591 size_t nChannels = std::min(sc->CodecContext->GetChannels(), sc->InitialChannels);
592
593 if (sc->SampleFormat == int16Sample)
594 {
595 auto data = sc->CodecContext->DecodeAudioPacketInt16(packet);
596
597 const int channelsCount = sc->CodecContext->GetChannels();
598 const int samplesPerChannel = data.size() / channelsCount;
599
600 // Write audio into WaveTracks
601 auto iter2 = iter->begin();
602 for (size_t chn = 0; chn < nChannels; ++iter2, ++chn)
603 {
604 iter2->get()->Append(
605 reinterpret_cast<samplePtr>(data.data() + chn), sc->SampleFormat,
606 samplesPerChannel,
607 sc->CodecContext->GetChannels(), sc->SampleFormat);
608 }
609 }
610 else if (sc->SampleFormat == floatSample)
611 {
612 auto data = sc->CodecContext->DecodeAudioPacketFloat(packet);
613
614 const int channelsCount = sc->CodecContext->GetChannels();
615 const int samplesPerChannel = data.size() / channelsCount;
616
617 // Write audio into WaveTracks
618 auto iter2 = iter->begin();
619 for (size_t chn = 0; chn < nChannels; ++iter2, ++chn)
620 {
621 iter2->get()->Append(
622 reinterpret_cast<samplePtr>(data.data() + chn), sc->SampleFormat,
623 samplesPerChannel, sc->CodecContext->GetChannels(),
624 sc->SampleFormat);
625 }
626 }
627
628 const AVStreamWrapper* avStream = mAVFormatContext->GetStream(sc->StreamIndex);
629
630 // Try to update the progress indicator (and see if user wants to cancel)
631 auto updateResult = ProgressResult::Success;
632 int64_t filesize = mFFmpeg->avio_size(mAVFormatContext->GetAVIOContext()->GetWrappedValue());
633 // PTS (presentation time) is the proper way of getting current position
634 if (
637 {
638 auto timeBase = avStream->GetTimeBase();
639
641 packet->GetPresentationTimestamp() * timeBase.num / timeBase.den;
642
644 (mAVFormatContext->GetDuration() > 0 ?
645 mAVFormatContext->GetDuration() / AUDACITY_AV_TIME_BASE :
646 1);
647 }
648 // When PTS is not set, use number of frames and number of current frame
649 else if (
650 avStream->GetFramesCount() > 0 && sc->CodecContext->GetFrameNumber() > 0 &&
651 sc->CodecContext->GetFrameNumber() <= avStream->GetFramesCount())
652 {
653 mProgressPos = sc->CodecContext->GetFrameNumber();
654 mProgressLen = avStream->GetFramesCount();
655 }
656 // When number of frames is unknown, use position in file
657 else if (
658 filesize > 0 && packet->GetPos() > 0 && packet->GetPos() <= filesize)
659 {
660 mProgressPos = packet->GetPos();
661 mProgressLen = filesize;
662 }
663 updateResult = mProgress->Update(mProgressPos, mProgressLen != 0 ? mProgressLen : 1);
664
665 return updateResult;
666}
667
669{
670 Tags temp;
671
672 GetMetadata(temp, TAG_TITLE, "title");
673 GetMetadata(temp, TAG_COMMENTS, "comment");
674 GetMetadata(temp, TAG_ALBUM, "album");
675 GetMetadata(temp, TAG_TRACK, "track");
676 GetMetadata(temp, TAG_GENRE, "genre");
677
678 if (wxString(mAVFormatContext->GetInputFormat()->GetName()).Contains("m4a"))
679 {
680 GetMetadata(temp, TAG_ARTIST, "artist");
681 GetMetadata(temp, TAG_YEAR, "date");
682 }
683 else if (wxString(mAVFormatContext->GetInputFormat()->GetName()).Contains("asf")) /* wma */
684 {
685 GetMetadata(temp, TAG_ARTIST, "artist");
686 GetMetadata(temp, TAG_YEAR, "year");
687 }
688 else
689 {
690 GetMetadata(temp, TAG_ARTIST, "author");
691 GetMetadata(temp, TAG_YEAR, "year");
692 }
693
694 if (!temp.IsEmpty())
695 {
696 *tags = temp;
697 }
698}
699
700void FFmpegImportFileHandle::GetMetadata(Tags &tags, const wxChar *tag, const char *name)
701{
702 auto metadata = mAVFormatContext->GetMetadata();
703
704 if (metadata.HasValue(name, DICT_IGNORE_SUFFIX))
705 tags.SetTag(tag, wxString::FromUTF8(std::string(metadata.Get(name, {}, DICT_IGNORE_SUFFIX))));
706}
707
708
710{
711
712}
713
714#endif //USE_FFMPEG
int AVCodecIDFwd
Definition: AVCodecID.h:407
#define DICT_IGNORE_SUFFIX
wxT("CloseDown"))
int min(int a, int b)
const TranslatableString name
Definition: Distortion.cpp:76
BoolSetting FFmpegNotFoundDontShow
Definition: FFmpeg.cpp:362
#define AUDACITY_AV_TIME_BASE
Definition: FFmpegTypes.h:80
#define AUDACITY_AV_NOPTS_VALUE
Definition: FFmpegTypes.h:74
XO("Cut/Copy/Paste")
BoolSetting NewImportingSession
Definition: Import.cpp:899
std::vector< std::vector< std::shared_ptr< WaveTrack > > > TrackHolders
Definition: Import.h:39
static const auto exts
#define DESC
static Importer::RegisteredImportPlugin registered
The interface that all file import "plugins" (if you want to call them that) must implement....
FileConfig * gPrefs
Definition: Prefs.cpp:70
wxString FilePath
Definition: Project.h:21
sampleFormat
The ordering of these values with operator < agrees with the order of increasing bit width.
Definition: SampleFormat.h:30
char * samplePtr
Definition: SampleFormat.h:55
#define TAG_TRACK
Definition: Tags.h:61
#define TAG_COMMENTS
Definition: Tags.h:64
#define TAG_GENRE
Definition: Tags.h:63
#define TAG_ALBUM
Definition: Tags.h:60
#define TAG_YEAR
Definition: Tags.h:62
#define TAG_TITLE
Definition: Tags.h:58
#define TAG_ARTIST
Definition: Tags.h:59
std::vector< TranslatableString > TranslatableStrings
std::string_view Get(const std::string_view &key, const std::string_view &defaultValue, int flags=0) const
virtual int64_t GetPos() const noexcept=0
virtual int64_t GetPresentationTimestamp() const noexcept=0
virtual int64_t GetDuration() const noexcept=0
virtual int GetIndex() const noexcept=0
virtual bool IsAudio() const noexcept=0
virtual AVDictionaryWrapper GetMetadata() const noexcept=0
virtual AudacityAVRational GetTimeBase() const noexcept=0
virtual int64_t GetFramesCount() const noexcept=0
virtual std::unique_ptr< AVCodecContextWrapper > GetAVCodecContext() const noexcept=0
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
! Does actual import, returned by FFmpegImportPlugin::Open
wxInt64 mProgressPos
Current timestamp, file position or whatever is used as first argument for Update()
std::unique_ptr< AVFormatContextWrapper > mAVFormatContext
FFmpegImportFileHandle(const FilePath &name)
void GetMetadata(Tags &tags, const wxChar *tag, const char *name)
TranslatableStrings mStreamInfo
Array of stream descriptions. After Init() and before Import(), same size as mStreamContexts.
void SetStreamUsage(wxInt32 StreamID, bool Use) override
const TranslatableStrings & GetStreamInfo() override
ProgressResult Import(WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override
const std::shared_ptr< FFmpegFunctions > mFFmpeg
TranslatableString GetFileDescription() override
void WriteMetadata(Tags *tags)
bool mStopped
True if importing was stopped by user.
ByteCount GetFileUncompressedBytes() override
bool mCancelled
True if importing was canceled by user.
wxInt32 GetStreamCount() override
std::vector< StreamContext > mStreamContexts
ProgressResult WriteData(StreamContext *sc, const AVPacketWrapper *packet)
wxInt64 mProgressLen
Duration, total length or whatever is used as second argument for Update()
An ImportPlugin for FFmpeg data.
TranslatableString FailureHint() const override
User visible message suggesting what to do when a file type isn't recognized; default empty string.
wxString GetPluginStringID() override
std::unique_ptr< ImportFileHandle > Open(const FilePath &Filename, AudacityProject *) override
! Probes the file and opens it if appropriate
TranslatableString GetPluginFormatDescription() override
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
An ImportFileHandle for data.
Definition: ImportPlugin.h:112
unsigned long long ByteCount
Definition: ImportPlugin.h:132
std::unique_ptr< ProgressDialog > mProgress
Definition: ImportPlugin.h:164
std::shared_ptr< WaveTrack > NewWaveTrack(WaveTrackFactory &trackFactory, sampleFormat effectiveFormat, double rate)
Build a wave track with appropriate format, which will not be narrower than the specified one.
Base class for FlacImportPlugin, LOFImportPlugin, MP3ImportPlugin, OggImportPlugin and PCMImportPlugi...
Definition: ImportPlugin.h:68
bool SupportsExtension(const FileExtension &extension)
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:252
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:200
ID3 Tags (for MP3)
Definition: Tags.h:73
bool IsEmpty()
Definition: Tags.cpp:297
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:441
Holds a msgid for the translation catalog; may also bind format arguments.
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:561
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
void InsertSilence(double t, double len) override
Definition: WaveTrack.cpp:1462
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
ProgressResult
Definition: BasicUI.h:147
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
int den
denominator
Definition: FFmpegTypes.h:139
int num
numerator
Definition: FFmpegTypes.h:138
static std::shared_ptr< FFmpegFunctions > Load(bool fromUserPathOnly=false)
std::unique_ptr< AVCodecContextWrapper > CodecContext
sampleFormat SampleFormat