Audacity  3.0.3
Classes | Macros | Functions | Variables
FFmpeg.cpp File Reference
#include "FFmpeg.h"
#include "FileNames.h"
#include "widgets/HelpSystem.h"
#include "widgets/AudacityMessageBox.h"
#include <wx/checkbox.h>
#include <wx/dynlib.h>
#include <wx/file.h>
#include <wx/log.h>
#include <wx/textctrl.h>
Include dependency graph for FFmpeg.cpp:

Go to the source code of this file.

Classes

class  FindFFmpegDialog
 Allows user to locate libav* libraries. More...
 

Macros

#define DEFINE_FFMPEG_POINTERS
 
#define AVSEEK_FORCE   0
 
#define ID_FFMPEG_BROWSE   5000
 
#define ID_FFMPEG_DLOAD   5001
 

Functions

FFmpegLibsFFmpegLibsInst ()
 
FFmpegLibsPickFFmpegLibs ()
 
void DropFFmpegLibs ()
 
bool LoadFFmpeg (bool showerror)
 
void FFmpegStartup ()
 
TranslatableString GetFFmpegVersion ()
 
void av_log_wx_callback (void *ptr, int level, const char *fmt, va_list vl)
 Callback function to catch FFmpeg log messages. More...
 
static int ufile_read (void *opaque, uint8_t *buf, int size)
 
static int ufile_write (void *opaque, uint8_t *buf, int size)
 
static int64_t ufile_seek (void *opaque, int64_t pos, int whence)
 
int ufile_close (AVIOContext *pb)
 
int ufile_fopen (AVIOContext **s, const FilePath &name, int flags)
 
int ufile_fopen_input (std::unique_ptr< FFmpegContext > &context_ptr, FilePath &name)
 
streamContextimport_ffmpeg_read_next_frame (AVFormatContext *formatContext, streamContext **streams, unsigned int numStreams)
 
int import_ffmpeg_decode_frame (streamContext *sc, bool flushing)
 

Variables

std::unique_ptr< FFmpegLibsFFmpegLibsPtr {}
 

Macro Definition Documentation

◆ AVSEEK_FORCE

#define AVSEEK_FORCE   0

◆ DEFINE_FFMPEG_POINTERS

#define DEFINE_FFMPEG_POINTERS

Definition at line 18 of file FFmpeg.cpp.

◆ ID_FFMPEG_BROWSE

#define ID_FFMPEG_BROWSE   5000

Definition at line 448 of file FFmpeg.cpp.

◆ ID_FFMPEG_DLOAD

#define ID_FFMPEG_DLOAD   5001

Definition at line 449 of file FFmpeg.cpp.

Function Documentation

◆ av_log_wx_callback()

void av_log_wx_callback ( void *  ptr,
int  level,
const char *  fmt,
va_list  vl 
)

Callback function to catch FFmpeg log messages.

Definition at line 128 of file FFmpeg.cpp.

129 {
130  //Most of this stuff is taken from FFmpeg tutorials and FFmpeg itself
131  int av_log_level = AV_LOG_INFO;
132  AVClass* avc = ptr ? *(AVClass**)ptr : NULL;
133  if (level > av_log_level)
134  return;
135  wxString printstring(wxT(""));
136 
137  if (avc) {
138  printstring.Append(wxString::Format(wxT("[%s @ %p] "), wxString::FromUTF8(avc->item_name(ptr)), avc));
139  }
140 
141  wxString frm(fmt,wxConvLibc);
142 
143  printstring.Append(wxString::FormatV(frm,vl));
144  wxString cpt;
145  switch (level)
146  {
147  case 0: cpt = wxT("Error"); break;
148  case 1: cpt = wxT("Info"); break;
149  case 2: cpt = wxT("Debug"); break;
150  default: cpt = wxT("Log"); break;
151  }
152  wxLogDebug(wxT("%s: %s"),cpt,printstring);
153 }

Referenced by FFmpegImportFileHandle::Init(), and ExportFFmpeg::Init().

Here is the caller graph for this function:

◆ DropFFmpegLibs()

void DropFFmpegLibs ( )

! Helper function - destroys FFmpegLibs object if there is no need for it anymore, or just decrements its reference count

Definition at line 61 of file FFmpeg.cpp.

62 {
63  if (FFmpegLibsPtr)
64  {
65  FFmpegLibsPtr->refcount--;
66  if (FFmpegLibsPtr->refcount == 0)
67  FFmpegLibsPtr.reset();
68  }
69 }

References FFmpegLibsPtr.

Referenced by CheckFFmpegPresence(), GetFFmpegVersion(), LoadFFmpeg(), AudacityApp::OnExit(), LibraryPrefs::OnFFmpegFindButton(), ExportFFmpegCustomOptions::OnOpen(), ExportFFmpeg::~ExportFFmpeg(), ExportFFmpegOptions::~ExportFFmpegOptions(), and FFmpegImportFileHandle::~FFmpegImportFileHandle().

Here is the caller graph for this function:

◆ FFmpegLibsInst()

FFmpegLibs* FFmpegLibsInst ( )

◆ FFmpegStartup()

void FFmpegStartup ( )

Called during Audacity start-up to try and load the ffmpeg libraries

Definition at line 95 of file FFmpeg.cpp.

96 {
97  bool enabled = false;
98  gPrefs->Read(wxT("/FFmpeg/Enabled"),&enabled);
99  // 'false' means that no errors should be shown whatsoever
100  if (!LoadFFmpeg(false))
101  {
102  if (enabled)
103  {
105 "FFmpeg was configured in Preferences and successfully loaded before, \
106 \nbut this time Audacity failed to load it at startup. \
107 \n\nYou may want to go back to Preferences > Libraries and re-configure it."),
108  XO("FFmpeg startup failed"));
109  }
110  }
111 }

References AudacityMessageBox(), gPrefs, LoadFFmpeg(), and XO.

Referenced by AudacityApp::InitPart2().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetFFmpegVersion()

TranslatableString GetFFmpegVersion ( )

Definition at line 113 of file FFmpeg.cpp.

114 {
115  PickFFmpegLibs();
116 
117  auto versionString = XO("FFmpeg library not found");
118 
119  if (FFmpegLibsInst()->ValidLibsLoaded()) {
120  versionString = Verbatim( FFmpegLibsInst()->GetLibraryVersion() );
121  }
122 
123  DropFFmpegLibs();
124 
125  return versionString;
126 }

References DropFFmpegLibs(), FFmpegLibsInst(), PickFFmpegLibs(), Verbatim(), and XO.

Referenced by LibraryPrefs::SetFFmpegVersionText().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_ffmpeg_decode_frame()

int import_ffmpeg_decode_frame ( streamContext sc,
bool  flushing 
)

Definition at line 350 of file FFmpeg.cpp.

351 {
352  int nBytesDecoded;
353  wxUint8 *pDecode = sc->m_pktDataPtr;
354  int nDecodeSiz = sc->m_pktRemainingSiz;
355 
356  sc->m_frameValid = 0;
357 
358  if (flushing)
359  {
360  // If we're flushing the decoders we don't actually have any NEW data to decode.
361  pDecode = NULL;
362  nDecodeSiz = 0;
363  }
364  else
365  {
366  if (!sc->m_pkt || (sc->m_pktRemainingSiz <= 0))
367  {
368  //No more data
369  return -1;
370  }
371  }
372 
373  AVPacketEx avpkt;
374  avpkt.data = pDecode;
375  avpkt.size = nDecodeSiz;
376 
377  AVFrameHolder frame{ av_frame_alloc() };
378  int got_output = 0;
379 
380  nBytesDecoded =
381  avcodec_decode_audio4(sc->m_codecCtx,
382  frame.get(), // out
383  &got_output, // out
384  &avpkt); // in
385 
386  if (nBytesDecoded < 0)
387  {
388  // Decoding failed. Don't stop.
389  return -1;
390  }
391 
392  sc->m_samplefmt = sc->m_codecCtx->sample_fmt;
393  sc->m_samplesize = static_cast<size_t>(av_get_bytes_per_sample(sc->m_samplefmt));
394 
395  int channels = sc->m_codecCtx->channels;
396  auto newsize = sc->m_samplesize * frame->nb_samples * channels;
397  sc->m_decodedAudioSamplesValidSiz = newsize;
398  // Reallocate the audio sample buffer if it's smaller than the frame size.
399  if (newsize > sc->m_decodedAudioSamplesSiz )
400  {
401  // Reallocate a bigger buffer. But av_realloc is NOT compatible with the returns of av_malloc!
402  // So do this:
403  sc->m_decodedAudioSamples.reset(static_cast<uint8_t *>(av_malloc(newsize)));
404  sc->m_decodedAudioSamplesSiz = newsize;
405  if (!sc->m_decodedAudioSamples)
406  {
407  //Can't allocate bytes
408  return -1;
409  }
410  }
411  if (frame->data[1]) {
412  for (int i = 0; i<frame->nb_samples; i++) {
413  for (int ch = 0; ch<channels; ch++) {
414  memcpy(sc->m_decodedAudioSamples.get() + sc->m_samplesize * (ch + channels*i),
415  frame->extended_data[ch] + sc->m_samplesize*i,
416  sc->m_samplesize);
417  }
418  }
419  } else {
420  memcpy(sc->m_decodedAudioSamples.get(), frame->data[0], newsize);
421  }
422 
423  // We may not have read all of the data from this packet. If so, the user can call again.
424  // Whether or not they do depends on if m_pktRemainingSiz == 0 (they can check).
425  sc->m_pktDataPtr += nBytesDecoded;
426  sc->m_pktRemainingSiz -= nBytesDecoded;
427 
428  // At this point it's normally safe to assume that we've read some samples. However, the MPEG
429  // audio decoder is broken. If this is the case then we just return with m_frameValid == 0
430  // but m_pktRemainingSiz perhaps != 0, so the user can call again.
431  if (sc->m_decodedAudioSamplesValidSiz > 0)
432  {
433  sc->m_frameValid = 1;
434  }
435  return 0;
436 }

References streamContext::m_codecCtx, streamContext::m_decodedAudioSamples, streamContext::m_decodedAudioSamplesSiz, streamContext::m_decodedAudioSamplesValidSiz, streamContext::m_frameValid, streamContext::m_pkt, streamContext::m_pktDataPtr, streamContext::m_pktRemainingSiz, streamContext::m_samplefmt, and streamContext::m_samplesize.

Referenced by FFmpegImportFileHandle::DecodeFrame().

Here is the caller graph for this function:

◆ import_ffmpeg_read_next_frame()

streamContext* import_ffmpeg_read_next_frame ( AVFormatContext *  formatContext,
streamContext **  streams,
unsigned int  numStreams 
)

Definition at line 315 of file FFmpeg.cpp.

318 {
319  streamContext *sc = NULL;
320  AVPacketEx pkt;
321 
322  if (av_read_frame(formatContext, &pkt) < 0)
323  {
324  return NULL;
325  }
326 
327  // Find a stream to which this frame belongs
328  for (unsigned int i = 0; i < numStreams; i++)
329  {
330  if (streams[i]->m_stream->index == pkt.stream_index)
331  sc = streams[i];
332  }
333 
334  // Off-stream packet. Don't panic, just skip it.
335  // When not all streams are selected for import this will happen very often.
336  if (sc == NULL)
337  {
338  return (streamContext*)1;
339  }
340 
341  // Copy the frame to the stream context
342  sc->m_pkt.emplace(std::move(pkt));
343 
344  sc->m_pktDataPtr = sc->m_pkt->data;
345  sc->m_pktRemainingSiz = sc->m_pkt->size;
346 
347  return sc;
348 }

References Optional< X >::emplace(), streamContext::m_pkt, streamContext::m_pktDataPtr, and streamContext::m_pktRemainingSiz.

Referenced by FFmpegImportFileHandle::ReadNextFrame().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ LoadFFmpeg()

bool LoadFFmpeg ( bool  showerror)

Definition at line 71 of file FFmpeg.cpp.

72 {
74  if (FFmpegLibsInst()->ValidLibsLoaded())
75  {
77  return true;
78  }
79  if (!FFmpegLibsInst()->LoadLibs(NULL, showerror))
80  {
82  gPrefs->Write(wxT("/FFmpeg/Enabled"), false);
83  gPrefs->Flush();
84  return false;
85  }
86  else
87  {
88  gPrefs->Write(wxT("/FFmpeg/Enabled"), true);
89  gPrefs->Flush();
90  return true;
91  }
92 }

References DropFFmpegLibs(), FFmpegLibsInst(), FileConfig::Flush(), gPrefs, and PickFFmpegLibs().

Referenced by ExportFFmpeg::CheckFileName(), FFmpegStartup(), LibraryPrefs::OnFFmpegFindButton(), and ExportFFmpegCustomOptions::OnOpen().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ PickFFmpegLibs()

FFmpegLibs* PickFFmpegLibs ( )

! Helper function - creates FFmpegLibs object if it does not exists or just increments reference count if it does It is usually called by constructors or initializators

Definition at line 51 of file FFmpeg.cpp.

52 {
53  if (FFmpegLibsPtr)
54  FFmpegLibsPtr->refcount++;
55  else
56  FFmpegLibsPtr = std::make_unique<FFmpegLibs>();
57 
58  return FFmpegLibsPtr.get();
59 }

References FFmpegLibsPtr.

Referenced by CheckFFmpegPresence(), ExportFFmpeg::ExportFFmpeg(), ExportFFmpegOptions::ExportFFmpegOptions(), FFmpegImportFileHandle::FFmpegImportFileHandle(), GetFFmpegVersion(), LoadFFmpeg(), LibraryPrefs::OnFFmpegFindButton(), and ExportFFmpegCustomOptions::OnOpen().

Here is the caller graph for this function:

◆ ufile_close()

int ufile_close ( AVIOContext *  pb)

Definition at line 198 of file FFmpeg.cpp.

199 {
200  std::unique_ptr<wxFile> f{ (wxFile *)pb->opaque };
201 
202  bool success = true;
203  if (f) {
204  if (pb->write_flag) {
205  success = f->Flush();
206  }
207  if (success) {
208  success = f->Close();
209  }
210  pb->opaque = nullptr;
211  }
212 
213  // We're not certain that a close error is for want of space, but we'll
214  // guess that
215  return success ? 0 : -ENOSPC;
216 
217  // Implicitly destroy the wxFile object here
218 }

Referenced by FFmpegContext::~FFmpegContext().

Here is the caller graph for this function:

◆ ufile_fopen()

int ufile_fopen ( AVIOContext **  s,
const FilePath name,
int  flags 
)

Definition at line 221 of file FFmpeg.cpp.

222 {
223  wxFile::OpenMode mode;
224 
225  auto f = std::make_unique<wxFile>();
226  if (!f) {
227  return -ENOMEM;
228  }
229 
230  if (flags == (AVIO_FLAG_READ | AVIO_FLAG_WRITE)) {
231  return -EINVAL;
232  } else if (flags == AVIO_FLAG_WRITE) {
233  mode = wxFile::write;
234  } else {
235  mode = wxFile::read;
236  }
237 
238  if (!f->Open(name, mode)) {
239  return -ENOENT;
240  }
241 
242  *s = avio_alloc_context((unsigned char*)av_malloc(32768), 32768,
243  flags & AVIO_FLAG_WRITE,
244  /*opaque*/f.get(),
245  ufile_read,
246  ufile_write,
247  ufile_seek);
248  if (!*s) {
249  return -ENOMEM;
250  }
251 
252  f.release(); // s owns the file object now
253 
254  return 0;
255 }

References name, ufile_read(), ufile_seek(), and ufile_write().

Referenced by ExportFFmpeg::Init(), and ufile_fopen_input().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ufile_fopen_input()

int ufile_fopen_input ( std::unique_ptr< FFmpegContext > &  context_ptr,
FilePath name 
)

Definition at line 260 of file FFmpeg.cpp.

261 {
262  context_ptr.reset();
263  auto context = std::make_unique<FFmpegContext>();
264 
265  wxFileName ff{ name };
266  wxCharBuffer fname;
267  const char *filename;
268  int err;
269 
270  fname = ff.GetFullName().mb_str();
271  filename = (const char *) fname;
272 
273  // Open the file to prepare for probing
274  if ((err = ufile_fopen(&context->pb, name, AVIO_FLAG_READ)) < 0) {
275  goto fail;
276  }
277 
278  context->ic_ptr = avformat_alloc_context();
279  context->ic_ptr->pb = context->pb;
280 
281  // And finally, attempt to associate an input stream with the file
282  err = avformat_open_input(&context->ic_ptr, filename, NULL, NULL);
283  if (err) {
284  goto fail;
285  }
286 
287  // success
288  context_ptr = std::move(context);
289  return 0;
290 
291 fail:
292 
293  return err;
294 }

References name, and ufile_fopen().

Referenced by FFmpegImportFileHandle::Init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ufile_read()

static int ufile_read ( void *  opaque,
uint8_t *  buf,
int  size 
)
static

Definition at line 158 of file FFmpeg.cpp.

159 {
160  int ret = (int)((wxFile *) opaque)->Read(buf, size);
161  return ret;
162 }

References Read().

Referenced by ufile_fopen().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ufile_seek()

static int64_t ufile_seek ( void *  opaque,
int64_t  pos,
int  whence 
)
static

Definition at line 172 of file FFmpeg.cpp.

173 {
174  wxSeekMode mode = wxFromStart;
175 
176 #if !defined(AVSEEK_FORCE)
177 #define AVSEEK_FORCE 0
178 #endif
179 
180  switch (whence & ~AVSEEK_FORCE)
181  {
182  case (SEEK_SET):
183  mode = wxFromStart;
184  break;
185  case (SEEK_CUR):
186  mode = wxFromCurrent;
187  break;
188  case (SEEK_END):
189  mode = wxFromEnd;
190  break;
191  case (AVSEEK_SIZE):
192  return ((wxFile *) opaque)->Length();
193  }
194 
195  return ((wxFile *) opaque)->Seek(pos, mode);
196 }

References AVSEEK_FORCE.

Referenced by ufile_fopen().

Here is the caller graph for this function:

◆ ufile_write()

static int ufile_write ( void *  opaque,
uint8_t *  buf,
int  size 
)
static

Definition at line 164 of file FFmpeg.cpp.

165 {
166  auto bytes = (int) ((wxFile *) opaque)->Write(buf, size);
167  if (bytes != size)
168  return -ENOSPC;
169  return bytes;
170 }

Referenced by ufile_fopen().

Here is the caller graph for this function:

Variable Documentation

◆ FFmpegLibsPtr

std::unique_ptr<FFmpegLibs> FFmpegLibsPtr {}

This pointer to the shared object has global scope and is used to track the singleton object which wraps the FFmpeg codecs

Definition at line 45 of file FFmpeg.cpp.

Referenced by DropFFmpegLibs(), FFmpegLibsInst(), LibraryPrefs::OnFFmpegFindButton(), and PickFFmpegLibs().

streamContext::m_frameValid
int m_frameValid
Definition: FFmpeg.h:1017
streamContext::m_pktRemainingSiz
int m_pktRemainingSiz
Definition: FFmpeg.h:1012
streamContext::m_pkt
Optional< AVPacketEx > m_pkt
Definition: FFmpeg.h:1010
Optional::emplace
X & emplace(Args &&... args)
Definition: MemoryX.h:192
streamContext
Definition: FFmpeg.h:1005
ufile_fopen
int ufile_fopen(AVIOContext **s, const FilePath &name, int flags)
Definition: FFmpeg.cpp:221
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:68
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
AVPacketEx
Definition: FFmpeg.h:884
streamContext::m_samplesize
size_t m_samplesize
Definition: FFmpeg.h:1023
ufile_write
static int ufile_write(void *opaque, uint8_t *buf, int size)
Definition: FFmpeg.cpp:164
XO
#define XO(s)
Definition: Internat.h:31
streamContext::m_pktDataPtr
uint8_t * m_pktDataPtr
Definition: FFmpeg.h:1011
streamContext::m_decodedAudioSamplesSiz
unsigned int m_decodedAudioSamplesSiz
Definition: FFmpeg.h:1019
PickFFmpegLibs
FFmpegLibs * PickFFmpegLibs()
Definition: FFmpeg.cpp:51
ufile_read
static int ufile_read(void *opaque, uint8_t *buf, int size)
Definition: FFmpeg.cpp:158
streamContext::m_samplefmt
AVSampleFormat m_samplefmt
Definition: FFmpeg.h:1024
LoadFFmpeg
bool LoadFFmpeg(bool showerror)
Definition: FFmpeg.cpp:71
AVSEEK_FORCE
#define AVSEEK_FORCE
ufile_seek
static int64_t ufile_seek(void *opaque, int64_t pos, int whence)
Definition: FFmpeg.cpp:172
streamContext::m_decodedAudioSamplesValidSiz
size_t m_decodedAudioSamplesValidSiz
Definition: FFmpeg.h:1020
name
const TranslatableString name
Definition: Distortion.cpp:98
streamContext::m_decodedAudioSamples
AVMallocHolder< uint8_t > m_decodedAudioSamples
Definition: FFmpeg.h:1018
streamContext::m_codecCtx
AVCodecContext * m_codecCtx
Definition: FFmpeg.h:1008
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:153
Read
gPrefs Read(wxT("/GUI/VerticalZooming"), &bVZoom, false)
FFmpegLibsInst
FFmpegLibs * FFmpegLibsInst()
Definition: FFmpeg.cpp:46
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
DropFFmpegLibs
void DropFFmpegLibs()
Definition: FFmpeg.cpp:61
AVFrameHolder
std::unique_ptr< AVFrame, AV_Deleterp< AVFrame, void, av_frame_free > > AVFrameHolder
Definition: FFmpeg.h:964
FFmpegLibsPtr
std::unique_ptr< FFmpegLibs > FFmpegLibsPtr
Definition: FFmpeg.cpp:45