Audacity  2.2.2
ImportFFmpeg.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 ImportFFmpeg.cpp
6 
7 Copyright 2008 LRN
8 Based on ImportFLAC.cpp by Sami Liedes and transcode_sample.c by ANYwebcam Pty Ltd
9 Licensed under the GNU General Public License v2 or later
10 
11 *//****************************************************************//****************************************************************//*******************************************************************/
22 
23 #include "../Audacity.h" // needed before FFmpeg.h
24 #include "ImportFFmpeg.h"
25 
26 // For compilers that support precompilation, includes "wx/wx.h".
27 #include <wx/wxprec.h>
28 
29 #include "../FFmpeg.h" // which brings in avcodec.h, avformat.h
30 #include "../ondemand/ODManager.h"
31 #ifndef WX_PRECOMP
32 // Include your minimal set of headers here, or wx.h
33 #include <wx/window.h>
34 #endif
35 
36 #include "../Experimental.h"
37 #include "../MemoryX.h"
38 
39 
40 #define DESC _("FFmpeg-compatible files")
41 
42 //TODO: remove non-audio extensions
43 #if defined(USE_FFMPEG)
44 static const wxChar *exts[] =
45 {
46  wxT("4xm"),
47  wxT("MTV"),
48  wxT("roq"),
49  wxT("aac"),
50  wxT("ac3"),
51  wxT("aif"),
52  wxT("aiff"),
53  wxT("afc"),
54  wxT("aifc"),
55  wxT("al"),
56  wxT("amr"),
57  wxT("apc"),
58  wxT("ape"),
59  wxT("apl"),
60  wxT("mac"),
61  wxT("asf"),
62  wxT("wmv"),
63  wxT("wma"),
64  wxT("au"),
65  wxT("avi"),
66  wxT("avs"),
67  wxT("bethsoftvid"),
68  wxT("c93"),
69  wxT("302"),
70  wxT("daud"),
71  wxT("dsicin"),
72  wxT("dts"),
73  wxT("dv"),
74  wxT("dxa"),
75  wxT("ea"),
76  wxT("cdata"),
77  wxT("ffm"),
78  wxT("film_cpk"),
79  wxT("flac"),
80  wxT("flic"),
81  wxT("flv"),
82  wxT("gif"),
83  wxT("gxf"),
84  wxT("idcin"),
85  wxT("image2"),
86  wxT("image2pipe"),
87  wxT("cgi"),
88  wxT("ipmovie"),
89  wxT("nut"),
90  wxT("lmlm4"),
91  wxT("m4v"),
92  wxT("mkv"),
93  wxT("mm"),
94  wxT("mmf"),
95  wxT("mov"),
96  wxT("mp4"),
97  wxT("m4a"),
98  wxT("m4r"),
99  wxT("3gp"),
100  wxT("3g2"),
101  wxT("mj2"),
102  wxT("mp3"),
103  wxT("mpc"),
104  wxT("mpc8"),
105  wxT("mpg"),
106  wxT("mpeg"),
107  wxT("ts"),
108  wxT("mpegtsraw"),
109  wxT("mpegvideo"),
110  wxT("msnwctcp"),
111  wxT("ul"),
112  wxT("mxf"),
113  wxT("nsv"),
114  wxT("nuv"),
115  wxT("ogg"),
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 "../Internat.h"
158 #include "../WaveTrack.h"
159 #include "ImportPlugin.h"
160 
161 
162 #ifdef EXPERIMENTAL_OD_FFMPEG
163 #include "../ondemand/ODDecodeFFmpegTask.h"
164 #endif
165 
166 extern FFmpegLibs *FFmpegLibsInst();
167 
169 
172 class FFmpegImportPlugin final : public ImportPlugin
173 {
174 public:
176  ImportPlugin(wxArrayString(WXSIZEOF(exts),exts))
177  {
178 
179  }
180 
181  ~FFmpegImportPlugin() { }
182 
183  wxString GetPluginStringID() { return wxT("libav"); }
184  wxString GetPluginFormatDescription();
185 
187  std::unique_ptr<ImportFileHandle> Open(const wxString &Filename) override;
188 };
189 
191 class FFmpegImportFileHandle final : public ImportFileHandle
192 {
193 
194 public:
195  FFmpegImportFileHandle(const wxString & name);
197 
200  bool Init();
203  bool InitCodecs();
204 
205 
206  wxString GetFileDescription() override;
207  ByteCount GetFileUncompressedBytes() override;
208 
211  ProgressResult Import(TrackFactory *trackFactory, TrackHolders &outTracks,
212  Tags *tags) override;
213 
216  streamContext* ReadNextFrame();
217 
222  int DecodeFrame(streamContext *sc, bool flushing);
223 
226  ProgressResult WriteData(streamContext *sc);
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 mNumStreams;
245  }
246 
249  const wxArrayString &GetStreamInfo() override
250  {
251  return mStreamInfo;
252  }
253 
257  void SetStreamUsage(wxInt32 StreamID, bool Use) override
258  {
259  if (StreamID < mNumStreams)
260  mScs->get()[StreamID]->m_use = Use;
261  }
262 
263 private:
264 
265  std::shared_ptr<FFmpegContext> mContext; // An object that does proper IO shutdown in its destructor; may be shared with decoder task.
266  AVFormatContext *mFormatContext;
267  int mNumStreams;
268  ScsPtr mScs;
269  wxArrayString mStreamInfo;
270 
271  wxInt64 mProgressPos;
272  wxInt64 mProgressLen;
273 
274  bool mCancelled;
275  bool mStopped;
276  wxString mName;
277  std::list<TrackHolders> mChannels;
278 #ifdef EXPERIMENTAL_OD_FFMPEG
279  bool mUsingOD;
280 #endif
281 
282 };
283 
284 
285 void GetFFmpegImportPlugin(ImportPluginList &importPluginList,
286  UnusableImportPluginList &WXUNUSED(unusableImportPluginList))
287 {
288  importPluginList.push_back( make_movable<FFmpegImportPlugin>() );
289 }
290 
291 
292 wxString FFmpegImportPlugin::GetPluginFormatDescription()
293 {
294  return DESC;
295 }
296 
297 std::unique_ptr<ImportFileHandle> FFmpegImportPlugin::Open(const wxString &filename)
298 {
299  auto handle = std::make_unique<FFmpegImportFileHandle>(filename);
300 
301  //Check if we're loading explicitly supported format
302  wxString extension = filename.AfterLast(wxT('.'));
303  if (SupportsExtension(extension))
304  {
305  //Audacity is trying to load something that is declared as
306  //officially supported by this plugin.
307  //If we don't have FFmpeg configured - tell the user about it.
308  //Since this will be happening often, use disableable "FFmpeg not found" dialog
309  //insdead of usual AudacityMessageBox()
310  bool newsession = false;
311  gPrefs->Read(wxT("/NewImportingSession"), &newsession);
312  if (!FFmpegLibsInst()->ValidLibsLoaded())
313  {
314  int dontShowDlg;
315  gPrefs->Read(wxT("/FFmpeg/NotFoundDontShow"),&dontShowDlg,0);
316  if (dontShowDlg == 0 && newsession)
317  {
318  gPrefs->Write(wxT("/NewImportingSession"), false);
319  gPrefs->Flush();
320  FFmpegNotFoundDialog{ nullptr }.ShowModal();
321  }
322  }
323  }
324  if (!FFmpegLibsInst()->ValidLibsLoaded())
325  {
326  return nullptr;
327  }
328 
329  // Open the file for import
330  bool success = handle->Init();
331  if (!success) {
332  return nullptr;
333  }
334 
335  // This std::move is needed to "upcast" the pointer type
336  return std::move(handle);
337 }
338 
339 
340 FFmpegImportFileHandle::FFmpegImportFileHandle(const wxString & name)
341 : ImportFileHandle(name)
342 {
343  PickFFmpegLibs();
344 
345  mFormatContext = NULL;
346  mNumStreams = 0;
347  mCancelled = false;
348  mStopped = false;
349  mName = name;
350  mProgressPos = 0;
351  mProgressLen = 1;
352 }
353 
354 bool FFmpegImportFileHandle::Init()
355 {
356  //FFmpegLibsInst()->LoadLibs(NULL,false); //Loaded at startup or from Prefs now
357 
358  if (!FFmpegLibsInst()->ValidLibsLoaded())
359  return false;
360 
361  av_log_set_callback(av_log_wx_callback);
362 
363  int err;
364  std::unique_ptr<FFmpegContext> tempContext;
365  err = ufile_fopen_input(tempContext, mName);
366  if (err < 0)
367  {
368  wxLogError(wxT("FFmpeg : av_open_input_file() failed for file %s"), mName);
369  return false;
370  }
371  wxASSERT(tempContext.get());
372  mFormatContext = tempContext->ic_ptr;
373 
374  err = avformat_find_stream_info(mFormatContext, NULL);
375  if (err < 0)
376  {
377  wxLogError(wxT("FFmpeg: avformat_find_stream_info() failed for file %s"),mName);
378  return false;
379  }
380 
381  if (!InitCodecs())
382  return false;
383 
384  // Only now do we postpone destroying the FFmpegContext.
385  // Move from unique to shared pointer
386  mContext.reset(tempContext.release());
387 
388  return true;
389 }
390 
391 bool FFmpegImportFileHandle::InitCodecs()
392 {
393  // Allocate the array of pointers to hold stream contexts pointers
394  // Some of the allocated space may be unused (corresponds to video, subtitle, or undecodeable audio streams)
395  mScs = std::make_shared<Scs>(size_t{mFormatContext->nb_streams});
396  // Fill the stream contexts
397  for (unsigned int i = 0; i < mFormatContext->nb_streams; i++)
398  {
399  if (mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
400  {
401  //Create a context
402  auto sc = std::make_unique<streamContext>();
403 
404  sc->m_stream = mFormatContext->streams[i];
405  sc->m_codecCtx = sc->m_stream->codec;
406 
407  const AVCodecID id = sc->m_codecCtx->codec_id;
408  const char* name = avcodec_get_name(id);
409  const AVCodec *codec = avcodec_find_decoder(id);
410 
411  if (codec == NULL)
412  {
413  wxLogError(wxT("FFmpeg : avcodec_find_decoder() failed. Index[%02d], Codec[%02x - %s]"),i,id,name);
414  //FFmpeg can't decode this stream, skip it
415  continue;
416  }
417 
418  if (codec->type != sc->m_codecCtx->codec_type)
419  {
420  wxLogError(wxT("FFmpeg : Codec type mismatch, skipping. Index[%02d], Codec[%02x - %s]"),i,id,name);
421  //Non-audio codec reported as audio? Nevertheless, we don't need THIS.
422  continue;
423  }
424 
425  if (avcodec_open2(sc->m_codecCtx, codec, NULL) < 0)
426  {
427  wxLogError(wxT("FFmpeg : avcodec_open() failed. Index[%02d], Codec[%02x - %s]"),i,id,name);
428  //Can't open decoder - skip this stream
429  continue;
430  }
431 
432  // Stream is decodeable and it is audio. Add it and its decription to the arrays
433  wxString strinfo;
434  int duration = 0;
435  if (sc->m_stream->duration > 0)
436  duration = sc->m_stream->duration * sc->m_stream->time_base.num / sc->m_stream->time_base.den;
437  else
438  duration = mFormatContext->duration / AV_TIME_BASE;
439  wxString bitrate = wxT("");
440  if (sc->m_codecCtx->bit_rate > 0)
441  bitrate.Printf(wxT("%d"),(int)sc->m_codecCtx->bit_rate);
442  else
443  bitrate.Printf(wxT("?"));
444 
445  AVDictionaryEntry *tag = av_dict_get(sc->m_stream->metadata, "language", NULL, 0);
446  wxString lang;
447  if (tag)
448  {
449  lang.FromUTF8(tag->value);
450  }
451  strinfo.Printf(_("Index[%02x] Codec[%s], Language[%s], Bitrate[%s], Channels[%d], Duration[%d]"),
452  sc->m_stream->id,codec->name,lang,bitrate,(int)sc->m_stream->codec->channels,(int)duration);
453  mStreamInfo.Add(strinfo);
454  mScs->get()[mNumStreams++] = std::move(sc);
455  }
456  //for video and unknown streams do nothing
457  }
458  //It doesn't really returns false, but GetStreamCount() will return 0 if file is composed entierly of unreadable streams
459  return true;
460 }
461 
462 wxString FFmpegImportFileHandle::GetFileDescription()
463 {
464  return DESC;
465 }
466 
467 
468 auto FFmpegImportFileHandle::GetFileUncompressedBytes() -> ByteCount
469 {
470  // TODO: Get Uncompressed byte count.
471  return 0;
472 }
473 
474 ProgressResult FFmpegImportFileHandle::Import(TrackFactory *trackFactory,
475  TrackHolders &outTracks,
476  Tags *tags)
477 {
478  outTracks.clear();
479 
480  CreateProgress();
481 
482  // Remove stream contexts which are not marked for importing and adjust mScs and mNumStreams accordingly
483  const auto scs = mScs->get();
484  for (int i = 0; i < mNumStreams;)
485  {
486  if (!scs[i]->m_use)
487  {
488  for (int j = i; j < mNumStreams - 1; j++)
489  {
490  scs[j] = std::move(scs[j+1]);
491  }
492  mNumStreams--;
493  }
494  else i++;
495  }
496 
497  mChannels.resize(mNumStreams);
498 
499  int s = -1;
500  for (auto &stream : mChannels)
501  {
502  ++s;
503 
504  auto sc = scs[s].get();
505  switch (sc->m_stream->codec->sample_fmt)
506  {
507  case AV_SAMPLE_FMT_U8:
508  case AV_SAMPLE_FMT_S16:
509  case AV_SAMPLE_FMT_U8P:
510  case AV_SAMPLE_FMT_S16P:
511  sc->m_osamplesize = sizeof(int16_t);
512  sc->m_osamplefmt = int16Sample;
513  break;
514  default:
515  sc->m_osamplesize = sizeof(float);
516  sc->m_osamplefmt = floatSample;
517  break;
518  }
519 
520  // 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.
521  sc->m_initialchannels = sc->m_stream->codec->channels;
522  stream.resize(sc->m_stream->codec->channels);
523  int c = -1;
524  for (auto &channel : stream)
525  {
526  ++c;
527 
528  channel = trackFactory->NewWaveTrack(sc->m_osamplefmt, sc->m_stream->codec->sample_rate);
529 
530  if (sc->m_stream->codec->channels == 2)
531  {
532  switch (c)
533  {
534  case 0:
535  channel->SetChannel(Track::LeftChannel);
536  channel->SetLinked(true);
537  break;
538  case 1:
539  channel->SetChannel(Track::RightChannel);
540  break;
541  }
542  }
543  else
544  {
545  channel->SetChannel(Track::MonoChannel);
546  }
547  }
548  }
549 
550  // Handles the start_time by creating silence. This may or may not be correct.
551  // There is a possibility that we should ignore first N milliseconds of audio instead. I do not know.
553  s = -1;
554  for (auto &stream : mChannels)
555  {
556  ++s;
557 
558  int64_t stream_delay = 0;
559  auto sc = scs[s].get();
560  if (sc->m_stream->start_time != int64_t(AV_NOPTS_VALUE) && sc->m_stream->start_time > 0)
561  {
562  stream_delay = sc->m_stream->start_time;
563  wxLogDebug(wxT("Stream %d start_time = %lld, that would be %f milliseconds."), s, (long long) sc->m_stream->start_time, double(sc->m_stream->start_time)/AV_TIME_BASE*1000);
564  }
565  if (stream_delay > 0)
566  {
567  int c = -1;
568  for (auto &channel : stream)
569  {
570  ++c;
571 
572  WaveTrack *t = channel.get();
573  t->InsertSilence(0,double(stream_delay)/AV_TIME_BASE);
574  }
575  }
576  }
577  // This is the heart of the importing process
578  // The result of Import() to be returend. It will be something other than zero if user canceled or some error appears.
579  auto res = ProgressResult::Success;
580 
581 #ifdef EXPERIMENTAL_OD_FFMPEG
582  mUsingOD = false;
583  gPrefs->Read(wxT("/Library/FFmpegOnDemand"), &mUsingOD);
584  //at this point we know the file is good and that we have to load the number of channels in mScs[s]->m_stream->codec->channels;
585  //so for OD loading we create the tracks and releasee the modal lock after starting the ODTask.
586  if (mUsingOD) {
587  std::vector<movable_ptr<ODDecodeFFmpegTask>> tasks;
588  //append blockfiles to each stream and add an individual ODDecodeTask for each one.
589  s = -1;
590  for (const auto &stream : mChannels) {
591  ++s;
592  auto odTask =
593  make_movable<ODDecodeFFmpegTask>(mScs, ODDecodeFFmpegTask::FromList(mChannels), mContext, s);
594  odTask->CreateFileDecoder(mFilename);
595 
596  //each stream has different duration. We need to know it if seeking is to be allowed.
597  sampleCount sampleDuration = 0;
598  auto sc = scs[s].get();
599  if (sc->m_stream->duration > 0)
600  sampleDuration = ((sampleCount)sc->m_stream->duration * sc->m_stream->time_base.num) * sc->m_stream->codec->sample_rate / sc->m_stream->time_base.den;
601  else
602  sampleDuration = ((sampleCount)mFormatContext->duration *sc->m_stream->codec->sample_rate) / AV_TIME_BASE;
603 
604  // wxPrintf(" OD duration samples %qi, sr %d, secs %d\n",sampleDuration, (int)sc->m_stream->codec->sample_rate, (int)sampleDuration/sc->m_stream->codec->sample_rate);
605 
606  //for each wavetrack within the stream add coded blockfiles
607  for (int c = 0; c < sc->m_stream->codec->channels; c++) {
608  WaveTrack *t = stream[c].get();
609  odTask->AddWaveTrack(t);
610 
611  auto maxBlockSize = t->GetMaxBlockSize();
612  //use the maximum blockfile size to divide the sections (about 11secs per blockfile at 44.1khz)
613 
614  for (decltype(sampleDuration) i = 0; i < sampleDuration; i += maxBlockSize) {
615  const auto blockLen =
616  limitSampleBufferSize( maxBlockSize, sampleDuration - i );
617 
618  t->AppendCoded(mFilename, i, blockLen, c, ODTask::eODFFMPEG);
619 
620  // This only works well for single streams since we assume
621  // each stream is of the same duration and channels
622  res = mProgress->Update(
623  (i+sampleDuration * c +
624  sampleDuration*sc->m_stream->codec->channels * s
625  ).as_long_long(),
626  (sampleDuration *
627  sc->m_stream->codec->channels * mNumStreams
628  ).as_long_long()
629  );
630  if (res != ProgressResult::Success)
631  break;
632  }
633  }
634  tasks.push_back(std::move(odTask));
635  }
636  //Now we add the tasks and let them run, or DELETE them if the user cancelled
637  if (res == ProgressResult::Success)
638  for (int i = 0; i < (int)tasks.size(); i++)
639  ODManager::Instance()->AddNewTask(std::move(tasks[i]));
640  } else {
641 #endif
642 
643  // Read next frame.
644  for (streamContext *sc; (sc = ReadNextFrame()) != NULL && (res == ProgressResult::Success);)
645  {
646  // ReadNextFrame returns 1 if stream is not to be imported
647  if (sc != (streamContext*)1)
648  {
649  // Decode frame until it is not possible to decode any further
650  while (sc->m_pktRemainingSiz > 0 && (res == ProgressResult::Success || res == ProgressResult::Stopped))
651  {
652  if (DecodeFrame(sc,false) < 0)
653  break;
654 
655  // If something useable was decoded - write it to mChannels
656  if (sc->m_frameValid)
657  res = WriteData(sc);
658  }
659 
660  // Cleanup after frame decoding
661  sc->m_pkt.reset();
662  }
663  }
664 
665  // Flush the decoders.
666  if ((mNumStreams != 0) && (res == ProgressResult::Success || res == ProgressResult::Stopped))
667  {
668  for (int i = 0; i < mNumStreams; i++)
669  {
670  auto sc = scs[i].get();
671  sc->m_pkt.create();
672  if (DecodeFrame(sc, true) == 0)
673  {
674  WriteData(sc);
675 
676  sc->m_pkt.reset();
677  }
678  }
679  }
680 #ifdef EXPERIMENTAL_OD_FFMPEG
681  } // else -- !mUsingOD == true
682 #endif //EXPERIMENTAL_OD_FFMPEG
683 
684  // Something bad happened - destroy everything!
686  return res;
687  //else if (res == 2), we just stop the decoding as if the file has ended
688 
689  // Copy audio from mChannels to newly created tracks (destroying mChannels elements in process)
690  for (auto &stream : mChannels)
691  {
692  for(auto &channel : stream)
693  {
694  channel->Flush();
695  outTracks.push_back(std::move(channel));
696  }
697  }
698 
699  // Save metadata
700  WriteMetadata(tags);
701 
702  return res;
703 }
704 
705 streamContext *FFmpegImportFileHandle::ReadNextFrame()
706 {
707  // Get pointer to array of contiguous unique_ptrs
708  auto scs = mScs->get();
709  // This reinterpret_cast to array of plain pointers is innocent
710  return import_ffmpeg_read_next_frame
711  (mFormatContext, reinterpret_cast<streamContext**>(scs), mNumStreams);
712 }
713 
714 int FFmpegImportFileHandle::DecodeFrame(streamContext *sc, bool flushing)
715 {
716  return import_ffmpeg_decode_frame(sc, flushing);
717 }
718 
719 ProgressResult FFmpegImportFileHandle::WriteData(streamContext *sc)
720 {
721  // Find the stream index in mScs array
722  int streamid = -1;
723  auto iter = mChannels.begin();
724  auto scs = mScs->get();
725  for (int i = 0; i < mNumStreams; ++iter, ++i)
726  {
727  if (scs[i].get() == sc)
728  {
729  streamid = i;
730  break;
731  }
732  }
733  // Stream is not found. This should not really happen
734  if (streamid == -1)
735  {
737  }
738 
739  // Allocate the buffer to store audio.
740  auto insamples = sc->m_decodedAudioSamplesValidSiz / sc->m_samplesize;
741  size_t nChannels = std::min(sc->m_stream->codec->channels, sc->m_initialchannels);
742 
743  ArraysOf<uint8_t> tmp{ nChannels, sc->m_osamplesize * (insamples / nChannels) };
744 
745  // Separate the channels and convert input sample format to 16-bit
746  uint8_t *in = sc->m_decodedAudioSamples.get();
747  int index = 0;
748  unsigned int pos = 0;
749  while (pos < insamples)
750  {
751  for (size_t chn = 0; (int)chn < sc->m_stream->codec->channels; chn++)
752  {
753  if (chn < nChannels)
754  {
755  switch (sc->m_samplefmt)
756  {
757  case AV_SAMPLE_FMT_U8:
758  case AV_SAMPLE_FMT_U8P:
759  ((int16_t *)tmp[chn].get())[index] = (int16_t) (*(uint8_t *)in - 0x80) << 8;
760  break;
761 
762  case AV_SAMPLE_FMT_S16:
763  case AV_SAMPLE_FMT_S16P:
764  ((int16_t *)tmp[chn].get())[index] = (int16_t) *(int16_t *)in;
765  break;
766 
767  case AV_SAMPLE_FMT_S32:
768  case AV_SAMPLE_FMT_S32P:
769  ((float *)tmp[chn].get())[index] = (float) *(int32_t *)in * (1.0 / (1u << 31));
770  break;
771 
772  case AV_SAMPLE_FMT_FLT:
773  case AV_SAMPLE_FMT_FLTP:
774  ((float *)tmp[chn].get())[index] = (float) *(float *)in;
775  break;
776 
777  case AV_SAMPLE_FMT_DBL:
778  case AV_SAMPLE_FMT_DBLP:
779  ((float *)tmp[chn].get())[index] = (float) *(double *)in;
780  break;
781 
782  default:
783  wxLogError(wxT("Stream %d has unrecognized sample format %d."), streamid, sc->m_samplefmt);
785  break;
786  }
787  }
788  in += sc->m_samplesize;
789  pos++;
790  }
791  index++;
792  }
793 
794  // Write audio into WaveTracks
795  auto iter2 = iter->begin();
796  for (size_t chn=0; chn < nChannels; ++iter2, ++chn)
797  {
798  iter2->get()->Append((samplePtr)tmp[chn].get(), sc->m_osamplefmt, index);
799  }
800 
801  // Try to update the progress indicator (and see if user wants to cancel)
802  auto updateResult = ProgressResult::Success;
803  int64_t filesize = avio_size(mFormatContext->pb);
804  // PTS (presentation time) is the proper way of getting current position
805  if (sc->m_pkt->pts != int64_t(AV_NOPTS_VALUE) && mFormatContext->duration != int64_t(AV_NOPTS_VALUE))
806  {
807  mProgressPos = sc->m_pkt->pts * sc->m_stream->time_base.num / sc->m_stream->time_base.den;
808  mProgressLen = (mFormatContext->duration > 0 ? mFormatContext->duration / AV_TIME_BASE: 1);
809  }
810  // When PTS is not set, use number of frames and number of current frame
811  else if (sc->m_stream->nb_frames > 0 && sc->m_codecCtx->frame_number > 0 && sc->m_codecCtx->frame_number <= sc->m_stream->nb_frames)
812  {
813  mProgressPos = sc->m_codecCtx->frame_number;
814  mProgressLen = sc->m_stream->nb_frames;
815  }
816  // When number of frames is unknown, use position in file
817  else if (filesize > 0 && sc->m_pkt->pos > 0 && sc->m_pkt->pos <= filesize)
818  {
819  mProgressPos = sc->m_pkt->pos;
820  mProgressLen = filesize;
821  }
822  updateResult = mProgress->Update(mProgressPos, mProgressLen != 0 ? mProgressLen : 1);
823 
824  return updateResult;
825 }
826 
827 void FFmpegImportFileHandle::WriteMetadata(Tags *tags)
828 {
829  tags->Clear();
830 
831  GetMetadata(tags, TAG_TITLE, "title");
832  GetMetadata(tags, TAG_ARTIST, "author");
833 // GetMetadata(tags, TAG_COPYRIGHT, "copyright");
834  GetMetadata(tags, TAG_COMMENTS, "comment");
835  GetMetadata(tags, TAG_ALBUM, "album");
836  GetMetadata(tags, TAG_YEAR, "year");
837  GetMetadata(tags, TAG_TRACK, "track");
838  GetMetadata(tags, TAG_GENRE, "genre");
839 }
840 
841 void FFmpegImportFileHandle::GetMetadata(Tags *tags, const wxChar *tag, const char *name)
842 {
843  AVDictionaryEntry *meta;
844 
845  meta = av_dict_get(mFormatContext->metadata, name, NULL, AV_DICT_IGNORE_SUFFIX);
846  if (meta)
847  {
848  tags->SetTag(tag, wxString::FromUTF8(meta->value));
849  }
850 }
851 
852 
853 FFmpegImportFileHandle::~FFmpegImportFileHandle()
854 {
855  if (FFmpegLibsInst()->ValidLibsLoaded())
856  av_log_set_callback(av_log_default_callback);
857 
858  // Do this before unloading the libraries
859  mContext.reset();
860 
861  DropFFmpegLibs();
862 }
863 
864 #endif //USE_FFMPEG
void AddNewTask(movable_ptr< ODTask > &&mtask, bool lockMutex=true)
Adds a wavetrack, creates a queue member.
Definition: ODManager.cpp:145
void SetTag(const wxString &name, const wxString &value)
Definition: Tags.cpp:449
memory.h template class for making an array of arrays.
Definition: MemoryX.h:519
void av_log_wx_callback(void *ptr, int level, const char *fmt, va_list vl)
Callback function to catch FFmpeg log messages.
static ODManager *(* Instance)()
Definition: ODManager.h:49
static const wxChar * exts[]
Definition: ImportFLAC.cpp:52
ProgressResult
#define TAG_TRACK
Definition: Tags.h:65
An ImportFileHandle for data.
Definition: ImportPlugin.h:119
void GetFFmpegImportPlugin(ImportPluginList &importPluginList, UnusableImportPluginList &unusableImportPluginList)
An ImportPlugin for FFmpeg data.
#define TAG_TITLE
Definition: Tags.h:62
#define TAG_ARTIST
Definition: Tags.h:63
Used to create a WaveTrack, or a LabelTrack.. Implementation of the functions of this class are dispe...
Definition: Track.h:850
void InsertSilence(double t, double len) override
Definition: WaveTrack.cpp:1391
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
#define DESC
void Clear()
Definition: Tags.cpp:300
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
The interface that all file import "plugins" (if you want to call them that) must implement...
int min(int a, int b)
size_t GetMaxBlockSize() const
Definition: WaveTrack.cpp:1631
ID3 Tags (for MP3)
Definition: Tags.h:72
An ImportFileHandle for FFmpeg data.
std::unique_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:78
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
Base class for FlacImportPlugin, LOFImportPlugin, MP3ImportPlugin, OggImportPlugin and PCMImportPlugi...
Definition: ImportPlugin.h:73
const wxChar * name
Definition: Distortion.cpp:94
#define TAG_COMMENTS
Definition: Tags.h:68
#define TAG_GENRE
Definition: Tags.h:67
An UnusableImportPlugin list.
An ImportPlugin list.
Class used to dynamically load FFmpeg libraries.
std::vector< std::unique_ptr< WaveTrack >> TrackHolders
Definition: ImportRaw.h:42
void AppendCoded(const wxString &fName, sampleCount start, size_t len, int channel, int decodeType)
Definition: WaveTrack.cpp:1581
#define TAG_ALBUM
Definition: Tags.h:64
#define TAG_YEAR
Definition: Tags.h:66