/********************************************************************** Audacity: A Digital Audio Editor FFmpeg.h Audacity(R) is copyright (c) 1999-2009 Audacity Team. License: GPL v2. See License.txt. ******************************************************************//** Describes shared object that is used to access FFmpeg libraries. *//*******************************************************************/ #if !defined(__AUDACITY_FFMPEG__) #define __AUDACITY_FFMPEG__ #include "widgets/wxPanelWrapper.h" // to inherit #if defined(__WXMSW__) #include // for wxRegKey #endif class wxCheckBox; // TODO: Determine whether the libav* headers come from the FFmpeg or libav // project and set IS_FFMPEG_PROJECT depending on it. #define IS_FFMPEG_PROJECT 1 /* FFmpeg is written in C99. It uses many types from stdint.h. Because we are * compiling this using a C++ compiler we have to put it in extern "C". * __STDC_CONSTANT_MACROS is defined to make behave like it * is actually being compiled with a C99 compiler. * * The symptoms are that INT64_C is not a valid type, which tends to break * somewhere down in the implementations using this file */ #if defined(USE_FFMPEG) extern "C" { // Include errno.h before the ffmpeg includes since they depend on // knowing the value of EINVAL...see bottom of avcodec.h. Not doing // so will produce positive error returns when they should be < 0. #include #include #include #include #include #include #if defined(DISABLE_DYNAMIC_LOADING_FFMPEG) #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 45, 101) #define av_frame_alloc avcodec_alloc_frame #define av_frame_free avcodec_free_frame #endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100) inline void avcodec_free_frame(AVFrame **frame) { av_free(*frame); } #endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 51, 100) #define AVCodecID CodecID #define AV_CODEC_ID_AAC CODEC_ID_AAC #define AV_CODEC_ID_AC CODEC_ID_AC #define AV_CODEC_ID_AC3 CODEC_ID_AC3 #define AV_CODEC_ID_ADPCM CODEC_ID_ADPCM #define AV_CODEC_ID_ADPCM_CT CODEC_ID_ADPCM_CT #define AV_CODEC_ID_ADPCM_G726 CODEC_ID_ADPCM_G726 #define AV_CODEC_ID_ADPCM_IMA_QT CODEC_ID_ADPCM_IMA_QT #define AV_CODEC_ID_ADPCM_IMA_WAV CODEC_ID_ADPCM_IMA_WAV #define AV_CODEC_ID_ADPCM_MS CODEC_ID_ADPCM_MS #define AV_CODEC_ID_ADPCM_SWF CODEC_ID_ADPCM_SWF #define AV_CODEC_ID_ADPCM_YAMAHA CODEC_ID_ADPCM_YAMAHA #define AV_CODEC_ID_ALAC CODEC_ID_ALAC #define AV_CODEC_ID_AMR CODEC_ID_AMR #define AV_CODEC_ID_AMR_NB CODEC_ID_AMR_NB #define AV_CODEC_ID_AMR_WB CODEC_ID_AMR_WB #define AV_CODEC_ID_ATRAC CODEC_ID_ATRAC #define AV_CODEC_ID_ATRAC3 CODEC_ID_ATRAC3 #define AV_CODEC_ID_DTS CODEC_ID_DTS #define AV_CODEC_ID_DVAUDIO CODEC_ID_DVAUDIO #define AV_CODEC_ID_FLAC CODEC_ID_FLAC #define AV_CODEC_ID_GSM CODEC_ID_GSM #define AV_CODEC_ID_GSM_MS CODEC_ID_GSM_MS #define AV_CODEC_ID_IMC CODEC_ID_IMC #define AV_CODEC_ID_MACE CODEC_ID_MACE #define AV_CODEC_ID_MACE3 CODEC_ID_MACE3 #define AV_CODEC_ID_MACE6 CODEC_ID_MACE6 #define AV_CODEC_ID_MP CODEC_ID_MP #define AV_CODEC_ID_MP2 CODEC_ID_MP2 #define AV_CODEC_ID_MP3 CODEC_ID_MP3 #define AV_CODEC_ID_NELLYMOSER CODEC_ID_NELLYMOSER #define AV_CODEC_ID_NONE CODEC_ID_NONE #define AV_CODEC_ID_PCM CODEC_ID_PCM #define AV_CODEC_ID_PCM_ALAW CODEC_ID_PCM_ALAW #define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW #define AV_CODEC_ID_PCM_S16BE CODEC_ID_PCM_S16BE #define AV_CODEC_ID_PCM_S16LE CODEC_ID_PCM_S16LE #define AV_CODEC_ID_PCM_S24BE CODEC_ID_PCM_S24BE #define AV_CODEC_ID_PCM_S24LE CODEC_ID_PCM_S24LE #define AV_CODEC_ID_PCM_S32BE CODEC_ID_PCM_S32BE #define AV_CODEC_ID_PCM_S32LE CODEC_ID_PCM_S32LE #define AV_CODEC_ID_PCM_S8 CODEC_ID_PCM_S8 #define AV_CODEC_ID_PCM_U8 CODEC_ID_PCM_U8 #define AV_CODEC_ID_QCELP CODEC_ID_QCELP #define AV_CODEC_ID_QDM CODEC_ID_QDM #define AV_CODEC_ID_QDM2 CODEC_ID_QDM2 #define AV_CODEC_ID_ROQ CODEC_ID_ROQ #define AV_CODEC_ID_ROQ_DPCM CODEC_ID_ROQ_DPCM #define AV_CODEC_ID_SONIC CODEC_ID_SONIC #define AV_CODEC_ID_SONIC_LS CODEC_ID_SONIC_LS #define AV_CODEC_ID_TRUESPEECH CODEC_ID_TRUESPEECH #define AV_CODEC_ID_VORBIS CODEC_ID_VORBIS #define AV_CODEC_ID_VOXWARE CODEC_ID_VOXWARE #define AV_CODEC_ID_WMAPRO CODEC_ID_WMAPRO #define AV_CODEC_ID_WMAV CODEC_ID_WMAV #define AV_CODEC_ID_WMAV1 CODEC_ID_WMAV1 #define AV_CODEC_ID_WMAV2 CODEC_ID_WMAV2 #define AV_CODEC_ID_WMAVOICE CODEC_ID_WMAVOICE #endif #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 8, 100) inline bool av_codec_is_encoder(AVCodec *codec) { return codec != NULL && (codec->encode != NULL || codec->encode2 != NULL); } #endif #endif #if LIBAVCODEC_VERSION_MAJOR < 58 #ifndef AV_CODEC_FLAG_QSCALE #define AV_CODEC_FLAG_QSCALE CODEC_FLAG_QSCALE #endif #ifndef AV_CODEC_FLAG_GLOBAL_HEADER #define AV_CODEC_FLAG_GLOBAL_HEADER CODEC_FLAG_GLOBAL_HEADER #endif #ifndef AV_CODEC_CAP_SMALL_LAST_FRAME #define AV_CODEC_CAP_SMALL_LAST_FRAME CODEC_CAP_SMALL_LAST_FRAME #endif #endif } #endif /* rather earlier than normal, but pulls in config*.h and other program stuff * we need for the next bit */ #include "ShuttleGui.h" #include "Prefs.h" #include "Identifier.h" class wxDynamicLibrary; // if you needed them, any other audacity header files would go here /// Callback function to catch FFmpeg log messages. void av_log_wx_callback(void* ptr, int level, const char* fmt, va_list vl); //---------------------------------------------------------------------------- // Get FFmpeg library version //---------------------------------------------------------------------------- TranslatableString GetFFmpegVersion(); /* from here on in, this stuff only applies when ffmpeg is available */ #if defined(USE_FFMPEG) //---------------------------------------------------------------------------- // Attempt to load and enable/disable FFmpeg at startup //---------------------------------------------------------------------------- void FFmpegStartup(); bool LoadFFmpeg(bool showerror); /// If Audacity failed to load libav*, this dialog /// shows up and tells user about that. It will pop-up /// again and again until it is disabled. class FFmpegNotFoundDialog final : public wxDialogWrapper { public: FFmpegNotFoundDialog(wxWindow *parent); void PopulateOrExchange(ShuttleGui & S); void OnOk(wxCommandEvent & WXUNUSED(event)); private: wxCheckBox *mDontShow; DECLARE_EVENT_TABLE() }; /// Manages liabv* libraries - loads/unloads libraries, imports symbols. /// Only one instance of this class should exist at each given moment. /// function definitions are taken from FFmpeg headers manually, /// eventually (at next major FFmpeg version change) we'll have to review /// them and update if necessary. class FFmpegLibs { public: FFmpegLibs(); ~FFmpegLibs(); ///! Finds libav* libraries ///\return true if found, false if not found bool FindLibs(wxWindow *parent); ///! Loads libav* libraries ///\param showerr - controls whether or not to show an error dialog if libraries cannot be loaded ///\return true if loaded, false if not loaded bool LoadLibs(wxWindow *parent, bool showerr); ///! Checks if libraries are loaded ///\return true if libraries are loaded, false otherwise bool ValidLibsLoaded(); ///! Initializes the libraries. Call after LoadLibs (when ValidLibsLoaded returns true) ///\param libpath_codec - full file path to the libavformat library ///\param showerr - controls whether or not to show an error dialog if libraries cannot be loaded ///\return true if initialization completed without errors, false otherwise /// do not call (it is called by FindLibs automatically) bool InitLibs(const wxString &libpath_codec, bool showerr); ///! Frees (unloads) loaded libraries void FreeLibs(); ///! Returns library version as string ///\return libavformat library version or empty string? wxString GetLibraryVersion() { return wxString::Format(wxT("F(%s),C(%s),U(%s)"),mAVFormatVersion,mAVCodecVersion,mAVUtilVersion); } #if defined(__WXMSW__) /* Library names and file filters for Windows only */ FileNames::FileTypes GetLibraryTypes() { return { /* i18n-hint: do not translate avformat. Preserve the computer gibberish.*/ { XO("Only avformat.dll"), { GetLibAVFormatName() } }, FileNames::DynamicLibraries, FileNames::AllFiles }; } wxString GetLibAVFormatPath() { wxRegKey reg(wxT("HKEY_LOCAL_MACHINE\\Software\\FFmpeg for Audacity")); wxString path; if (reg.Exists()) { reg.QueryValue(wxT("InstallPath"), path); } return path; } wxString GetLibAVFormatName() { return (wxT("avformat-") wxT(AV_STRINGIFY(LIBAVFORMAT_VERSION_MAJOR)) wxT(".dll")); } wxString GetLibAVCodecName() { return (wxT("avcodec-") wxT(AV_STRINGIFY(LIBAVCODEC_VERSION_MAJOR)) wxT(".dll")); } wxString GetLibAVUtilName() { return (wxT("avutil-") wxT(AV_STRINGIFY(LIBAVUTIL_VERSION_MAJOR)) wxT(".dll")); } #elif defined(__WXMAC__) /* Library names and file filters for Mac OS only */ FileNames::FileTypes GetLibraryTypes() { return { FileNames::DynamicLibraries, FileNames::AllFiles }; } wxString GetLibAVFormatPath() { return wxT("/Library/Application Support/audacity/libs"); } wxString GetLibAVFormatName() { if (sizeof(void*) == 8) return (wxT("ffmpeg.") wxT(AV_STRINGIFY(LIBAVFORMAT_VERSION_MAJOR)) wxT(".64bit.dylib")); return (wxT("libavformat.") wxT(AV_STRINGIFY(LIBAVFORMAT_VERSION_MAJOR)) wxT(".dylib")); } wxString GetLibAVCodecName() { if (sizeof(void*) == 8) return (wxT("ffmpeg_codecs.") wxT(AV_STRINGIFY(LIBAVCODEC_VERSION_MAJOR)) wxT(".64bit.dylib")); return (wxT("libavcodec.") wxT(AV_STRINGIFY(LIBAVCODEC_VERSION_MAJOR)) wxT(".dylib")); } wxString GetLibAVUtilName() { if (sizeof(void*) == 8) return (wxT("ffmpeg_utils.") wxT(AV_STRINGIFY(LIBAVUTIL_VERSION_MAJOR)) wxT(".64bit.dylib")); return (wxT("libavutil.") wxT(AV_STRINGIFY(LIBAVUTIL_VERSION_MAJOR)) wxT(".dylib")); } #else /* Library names and file filters for other platforms, basically Linux and * other *nix platforms */ FileNames::FileTypes GetLibraryTypes() { return { { XO("Only libavformat.so"), { wxT("libavformat*.so*") } }, FileNames::DynamicLibraries, FileNames::AllFiles }; } wxString GetLibAVFormatPath() { return wxT(""); } wxString GetLibAVFormatName() { return (wxT("libavformat.so.") wxT(AV_STRINGIFY(LIBAVFORMAT_VERSION_MAJOR))); } wxString GetLibAVCodecName() { return (wxT("libavcodec.so.") wxT(AV_STRINGIFY(LIBAVCODEC_VERSION_MAJOR))); } wxString GetLibAVUtilName() { return (wxT("libavutil.so.") wxT(AV_STRINGIFY(LIBAVUTIL_VERSION_MAJOR))); } #endif // (__WXMAC__) || (__WXMSW__) /// Ugly reference counting. I thought of using wxStuff for that, /// but decided that wx reference counting is not useful, since /// there's no data sharing - object is shared because libraries are. int refcount; private: ///! Stored path to libavformat library wxString mLibAVFormatPath; ///! Stored library version wxString mAVCodecVersion; wxString mAVFormatVersion; wxString mAVUtilVersion; ///! wx interfaces for dynamic libraries std::unique_ptr avformat, avcodec, avutil; ///! true if libraries are loaded, false otherwise bool mLibsLoaded; }; ///! 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 FFmpegLibs *PickFFmpegLibs(); ///! Helper function - destroys FFmpegLibs object if there is no need for it ///! anymore, or just decrements its reference count void DropFFmpegLibs(); // This object allows access to the AVFormatContext, // and its destructor cleans up memory and file handles struct FFmpegContext { FFmpegContext() {} ~FFmpegContext(); AVIOContext *pb{}; AVFormatContext *ic_ptr{}; }; int ufile_fopen(AVIOContext **s, const FilePath & name, int flags); int ufile_fopen_input(std::unique_ptr &context_ptr, FilePath & name); int ufile_close(AVIOContext *pb); struct streamContext; // common utility functions // utility calls that are shared with ImportFFmpeg streamContext *import_ffmpeg_read_next_frame(AVFormatContext* formatContext, streamContext** streams, unsigned int numStreams); int import_ffmpeg_decode_frame(streamContext *sc, bool flushing); #if !defined(DISABLE_DYNAMIC_LOADING_FFMPEG) extern "C" { // A little explanation of what's going on here. // // The FFmpeg function pointers used to be defined in the FFmpegLibs class and all calls would // be done via the global class pointer FFmpegLibsInst. This was fine as long as the prototypes // defined in the class matched the actual functions in the FFmpeg libraries. There was no // compile time validation to prevent invalid function calls. So, what follows is one way of // getting the extra validation. // // Only one source file should define DEFINE_FFMPEG_POINTERS before including ffmpeg.h. This // will cause the compiler to dump all of the function pointers to a single object file and // prevent duplicate symbol definitions during link. This is currently done in ffmpeg.cpp. // // The FFMPEG_FUNCTION_WITH_RETURN and FFMPEG_FUNCTION_NO_RETURN macros do two things each: // 1) Define or reference the variable that contains the actual function pointer // 2) Define an inline function to pass control to the real function // // Since the macros redefine the real ffmpeg functions of the same name, the compiler will // make sure that the definitions are the same. If not, it will complain. For this to occur, // the functions MUST be defined in an extern "C" block otherwise the compiler just thinks the // functions are being overloaded. // // The compiler should optimize away the inline function since it just passes control to the real // function and we should wind up with about the same function call we had before, only now it is // safer due to the validation. // // The FFMPEG_FUNCTION_WITH_RETURN takes 4 arguments: // 1) The return type <---| // 2) The function name | Taken from the FFmpeg function prototype // 3) The function arguments <---| // 4) The argument list to pass to the real function // // The FFMPEG_FUNCTION_NO_RETURN takes 3 arguments: // 1) The function name <---| Taken from the FFmpeg function prototype // 2) The function arguments <---| // 3) The argument list to pass to the real function // // The FFMPEG_INITDYN macro is responsible for retrieving the address of the real function // and storing that address in the function pointer variable. It will emit an error to the // currently define log destination and return to the calling function. // #if defined(DEFINE_FFMPEG_POINTERS) #define FFX #else #define FFX extern #endif #define FFMPEG_FUNCTION_WITH_RETURN(r, n, a, p) \ extern "C" \ { \ FFX r (*n ## _fp) a; \ inline r n a \ { \ return n ## _fp p; \ } \ } #define FFMPEG_FUNCTION_NO_RETURN(n, a, p) \ extern "C" \ { \ FFX void (*n ## _fp) a; \ inline void n a \ { \ n ## _fp p; \ } \ } #define FFMPEG_INITDYN(w, f) \ { \ wxLogNull off; \ *(void**)&f ## _fp = (void*)w->GetSymbol(wxT(#f)); \ } \ if (f ## _fp == NULL) \ { \ wxLogError(wxT("Failed to load symbol ") wxT(#f)); \ return false; \ } #define FFMPEG_INITALT(w, f, x, a) \ { \ wxLogNull off; \ *(void**)&f ## _fp = (void*)w->GetSymbol(wxT(#f)); \ } \ if (f ## _fp == NULL) \ { \ { \ wxLogNull off; \ *(void**)&f ## _fp = (void*)x->GetSymbol(wxT(#a)); \ } \ if (f ## _fp == NULL) \ { \ wxLogError(wxT("Failed to load symbol ") wxT(#f)); \ return false; \ } \ } // // libavutil // FFMPEG_FUNCTION_WITH_RETURN( unsigned, avutil_version, (void), () ); FFMPEG_FUNCTION_NO_RETURN( av_log_set_callback, (void (*cb)(void*, int, const char*, va_list)), (cb) ); FFMPEG_FUNCTION_NO_RETURN( av_log_default_callback, (void* ptr, int level, const char* fmt, va_list vl), (ptr, level, fmt, vl) ); FFMPEG_FUNCTION_NO_RETURN( av_free, (void *ptr), (ptr) ); FFMPEG_FUNCTION_WITH_RETURN( int64_t, av_get_default_channel_layout, (int nb_channels), (nb_channels) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_strerror, (int errnum, char *errbuf, size_t errbuf_size), (errnum, errbuf, errbuf_size) ); // // libavcodec // FFMPEG_FUNCTION_WITH_RETURN( unsigned, avcodec_version, (void), () ); FFMPEG_FUNCTION_WITH_RETURN( AVCodec*, avcodec_find_encoder, (enum AVCodecID id), (id) ); FFMPEG_FUNCTION_WITH_RETURN( AVCodec*, avcodec_find_encoder_by_name, (const char *name), (name) ); FFMPEG_FUNCTION_WITH_RETURN( AVCodec*, avcodec_find_decoder, (enum AVCodecID id), (id) ); FFMPEG_FUNCTION_WITH_RETURN( const char*, avcodec_get_name, (enum AVCodecID id), (id) ); FFMPEG_FUNCTION_WITH_RETURN( unsigned int, av_codec_get_tag, (const struct AVCodecTag * const *tags, enum AVCodecID id), (tags, id) ); FFMPEG_FUNCTION_WITH_RETURN( int, avcodec_open2, (AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options), (avctx, codec, options); ); #if defined(IS_FFMPEG_PROJECT) FFMPEG_FUNCTION_WITH_RETURN( int, avcodec_decode_audio4, (AVCodecContext *avctx, AVFrame *frame, int *got_output, const AVPacket *avpkt), (avctx, frame, got_output, avpkt) ); #else FFMPEG_FUNCTION_WITH_RETURN( int, avcodec_decode_audio4, (AVCodecContext *avctx, AVFrame *frame, int *got_output, AVPacket *avpkt), (avctx, frame, got_output, avpkt) ); #endif FFMPEG_FUNCTION_WITH_RETURN( int, avcodec_encode_audio2, (AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_output), (avctx, pkt, frame, got_output) ); FFMPEG_FUNCTION_WITH_RETURN( int, avcodec_close, (AVCodecContext *avctx), (avctx) ); FFMPEG_FUNCTION_NO_RETURN( avcodec_register_all, (void), () ); FFMPEG_FUNCTION_WITH_RETURN( int, av_get_bytes_per_sample, (enum AVSampleFormat sample_fmt), (sample_fmt) ); FFMPEG_FUNCTION_WITH_RETURN( int, avcodec_fill_audio_frame, (AVFrame *frame, int nb_channels, enum AVSampleFormat sample_fmt, const uint8_t *buf, int buf_size, int align), (frame, nb_channels, sample_fmt, buf, buf_size, align) ); // // libavformat // FFMPEG_FUNCTION_WITH_RETURN( unsigned, avformat_version, (void), () ); FFMPEG_FUNCTION_WITH_RETURN( int, avformat_open_input, (AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, AVDictionary **options), (ic_ptr, filename, fmt, options) ); FFMPEG_FUNCTION_NO_RETURN( av_register_all, (void), () ); FFMPEG_FUNCTION_WITH_RETURN( int, avformat_find_stream_info, (AVFormatContext *ic, AVDictionary **options), (ic, options) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_read_frame, (AVFormatContext *s, AVPacket *pkt), (s, pkt) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_seek_frame, (AVFormatContext *s, int stream_index, int64_t timestamp, int flags), (s, stream_index, timestamp, flags) ); FFMPEG_FUNCTION_NO_RETURN( avformat_close_input, (AVFormatContext **s), (s) ); FFMPEG_FUNCTION_WITH_RETURN( int, avformat_write_header, (AVFormatContext *s, AVDictionary **options), (s, options) ); #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 33, 101) FFMPEG_FUNCTION_WITH_RETURN( AVOutputFormat*, av_oformat_next, (const AVOutputFormat *f), (f) ); #else FFMPEG_FUNCTION_WITH_RETURN( AVOutputFormat*, av_oformat_next, (AVOutputFormat *f), (f) ); #endif FFMPEG_FUNCTION_WITH_RETURN( AVCodec*, av_codec_next, (const AVCodec *c), (c) ); #if defined(IS_FFMPEG_PROJECT) FFMPEG_FUNCTION_WITH_RETURN( AVStream*, avformat_new_stream, (AVFormatContext *s, const AVCodec *c), (s, c) ); #else FFMPEG_FUNCTION_WITH_RETURN( AVStream*, avformat_new_stream, (AVFormatContext *s, AVCodec *c), (s, c) ); #endif FFMPEG_FUNCTION_WITH_RETURN( AVFormatContext*, avformat_alloc_context, (void), () ); FFMPEG_FUNCTION_WITH_RETURN( AVOutputFormat*, av_guess_format, (const char *short_name, const char *filename, const char *mime_type), (short_name, filename, mime_type) ); FFMPEG_FUNCTION_NO_RETURN( avformat_free_context, (AVFormatContext *s), (s) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_write_trailer, (AVFormatContext *s), (s) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_interleaved_write_frame, (AVFormatContext *s, AVPacket *pkt), (s, pkt) ); FFMPEG_FUNCTION_NO_RETURN( av_init_packet, (AVPacket *pkt), (pkt) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_fifo_generic_write, (AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)), (f, src, size, func) ); FFMPEG_FUNCTION_NO_RETURN( av_fifo_free, (AVFifoBuffer *f), (f) ); #if LIBAVUTIL_VERSION_MAJOR >= 53 FFMPEG_FUNCTION_WITH_RETURN( int, av_fifo_size, (const AVFifoBuffer *f), (f) ); #else FFMPEG_FUNCTION_WITH_RETURN( int, av_fifo_size, (AVFifoBuffer *f), (f) ); #endif FFMPEG_FUNCTION_WITH_RETURN( void*, av_malloc, (size_t size), (size) ); /* FFMPEG_FUNCTION_NO_RETURN( av_freep, (void *ptr), (ptr) ); */ FFMPEG_FUNCTION_WITH_RETURN( int64_t, av_rescale_q, (int64_t a, AVRational bq, AVRational cq), (a, bq, cq) ); FFMPEG_FUNCTION_NO_RETURN( av_free_packet, (AVPacket *pkt), (pkt) ); FFMPEG_FUNCTION_WITH_RETURN( AVFifoBuffer*, av_fifo_alloc, (unsigned int size), (size) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_fifo_generic_read, (AVFifoBuffer *f, void *buf, int buf_size, void (*func)(void*, void*, int)), (f, buf, buf_size, func) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_fifo_realloc2, (AVFifoBuffer *f, unsigned int size), (f, size) ); FFMPEG_FUNCTION_NO_RETURN( av_dict_free, (AVDictionary **m), (m) ); #if LIBAVUTIL_VERSION_MAJOR >= 53 FFMPEG_FUNCTION_WITH_RETURN( AVDictionaryEntry *, av_dict_get, (const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags), (m, key, prev, flags) ); #else FFMPEG_FUNCTION_WITH_RETURN( AVDictionaryEntry *, av_dict_get, (AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags), (m, key, prev, flags) ); #endif FFMPEG_FUNCTION_WITH_RETURN( int, av_dict_set, (AVDictionary **pm, const char *key, const char *value, int flags), (pm, key, value, flags) ); FFMPEG_FUNCTION_WITH_RETURN( int64_t, avio_size, (AVIOContext *s), (s) ); FFMPEG_FUNCTION_WITH_RETURN( AVIOContext *, avio_alloc_context, (unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence)), (buffer, buffer_size, write_flag, opaque, read_packet, write_packet, seek) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_codec_is_encoder, (const AVCodec *codec), (codec) ); FFMPEG_FUNCTION_WITH_RETURN( AVFrame*, av_frame_alloc, (void), () ); FFMPEG_FUNCTION_NO_RETURN( av_frame_free, (AVFrame **frame), (frame) ); FFMPEG_FUNCTION_WITH_RETURN( int, av_samples_get_buffer_size, (int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align), (linesize, nb_channels, nb_samples, sample_fmt, align) ); }; #endif // Attach some C++ lifetime management to the struct, which owns some memory resources. struct AVPacketEx : public AVPacket { AVPacketEx() { av_init_packet(this); data = nullptr; size = 0; } AVPacketEx(const AVPacketEx &) PROHIBITED; AVPacketEx& operator= (const AVPacketEx&) PROHIBITED; AVPacketEx(AVPacketEx &&that) { steal(std::move(that)); } AVPacketEx &operator= (AVPacketEx &&that) { if (this != &that) { reset(); steal(std::move(that)); } return *this; } ~AVPacketEx () { reset(); } void reset() { // This does not deallocate the pointer, but it frees side data. av_free_packet(this); } private: void steal(AVPacketEx &&that) { memcpy(this, &that, sizeof(that)); av_init_packet(&that); that.data = nullptr; that.size = 0; } }; // utilities for RAII: // Deleter adaptor for functions like av_free that take a pointer /// \brief AV_Deleter is part of FFmpeg support. It's used with the RAII /// idiom. template 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 struct AV_Deleter { inline void operator() (T* p) const { if (p) Fn(p); } }; // Deleter adaptor for functions like av_freep that take a pointer to a pointer template struct AV_Deleterp { inline void operator() (T* p) const { if (p) Fn(&p); } }; using AVFrameHolder = std::unique_ptr< AVFrame, AV_Deleterp >; using AVFifoBufferHolder = std::unique_ptr< AVFifoBuffer, AV_Deleter >; using AVFormatContextHolder = std::unique_ptr< AVFormatContext, AV_Deleter >; using AVCodecContextHolder = std::unique_ptr< AVCodecContext, AV_Deleter >; using AVDictionaryCleanup = std::unique_ptr< AVDictionary*, AV_Deleter >; /// \brief FFmpeg structure to hold a file pointer and provide a return /// value when closing the file. struct UFileHolder : public std::unique_ptr< AVIOContext, ::AV_Deleter > { UFileHolder() = default; UFileHolder( UFileHolder &&that ) : std::unique_ptr< AVIOContext, ::AV_Deleter >( std::move(that) ) { } // Close explicitly, not ignoring return values. int close() { auto result = get_deleter() ( get() ); release(); return result; } }; template using AVMallocHolder = std::unique_ptr< T, AV_Deleter >; struct streamContext { bool m_use{}; // TRUE = this stream will be loaded into Audacity AVStream *m_stream{}; // an AVStream * AVCodecContext *m_codecCtx{}; // pointer to m_stream->codec Optional m_pkt; // the last AVPacket we read for this stream uint8_t *m_pktDataPtr{}; // pointer into m_pkt.data int m_pktRemainingSiz{}; int64_t m_pts{}; // the current presentation time of the input stream int64_t m_ptsOffset{}; // packets associated with stream are relative to this int m_frameValid{}; // is m_decodedVideoFrame/m_decodedAudioSamples valid? AVMallocHolder m_decodedAudioSamples; // decoded audio samples stored here unsigned int m_decodedAudioSamplesSiz{}; // current size of m_decodedAudioSamples size_t m_decodedAudioSamplesValidSiz{}; // # valid bytes in m_decodedAudioSamples int m_initialchannels{}; // number of channels allocated when we begin the importing. Assumes that number of channels doesn't change on the fly. size_t m_samplesize{}; // input sample size in bytes AVSampleFormat m_samplefmt{ AV_SAMPLE_FMT_NONE }; // input sample format size_t m_osamplesize{}; // output sample size in bytes sampleFormat m_osamplefmt{ floatSample }; // output sample format streamContext() { memset(this, 0, sizeof(*this)); } ~streamContext() { } }; using Scs = ArrayOf>; using ScsPtr = std::shared_ptr; extern FFmpegLibs *FFmpegLibsInst(); #endif // USE_FFMPEG #endif // __AUDACITY_FFMPEG__