#define AL_LOG_SECTION "ff" //#define AL_LOG_ENABLE_TRACE #include #include #include #include #include "common.h" s64 camu_ff_get_frame_duration(AVFrame *frame) { #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 30, 100) return frame->duration; #else return frame->pkt_duration; #endif } // https://code.videolan.org/videolan/libplacebo/-/blob/a7a18af88ff0a17c04840dcb3246047bb6b46df3/src/include/libplacebo/utils/libav_internal.h#L854 const u8 *camu_ff_get_stream_side_data(const AVStream *stream, enum AVPacketSideDataType type) { #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(60, 15, 100) AVCodecParameters *codecpar = stream->codecpar; const AVPacketSideData *side_data = av_packet_side_data_get(codecpar->coded_side_data, codecpar->nb_coded_side_data, type); return side_data ? side_data->data : NULL; #else return av_stream_get_side_data(stream, type, NULL); #endif } const u8 *camu_ff_get_frame_side_data(AVFrame *frame, enum AVFrameSideDataType type) { AVFrameSideData *side_data = av_frame_get_side_data(frame, type); return side_data ? side_data->data : NULL; } static __thread struct { char buf[AL_LOG_MESSAGE_SIZE]; size_t pos; } log_context; // If a line takes more than 1 step to print, make sure we stay within AL_LOG_MESSAGE_SIZE. #define AV_LOG_MAX_CHUNK (AL_LOG_MESSAGE_SIZE / 2) static void av_log_callback(void *userdata, s32 level, const char *fmt, va_list args) { (void)userdata; char *offset = log_context.buf + log_context.pos; s32 ret = al_vsnprintf(offset, AV_LOG_MAX_CHUNK, fmt, args); al_assert(ret > 0); offset += ret; log_context.pos += ret; if ((log_context.pos > 0 && *(offset - 1) == '\n') || log_context.pos >= AV_LOG_MAX_CHUNK) { if (level < AV_LOG_WARNING) { log_info(log_context.buf); } else if (level < AL_LOG_DEBUG) { log_debug(log_context.buf); } else { log_trace(log_context.buf); } log_context.pos = 0; } } void camu_ff_set_log_callback(void (*callback)(void *, s32, const char *, va_list)) { av_log_set_callback(callback); } void camu_ff_common_init(void) { #ifdef CAMU_OLD_FFMPEG log_info("Using FFmpeg version "FFMPEG_VERSION" (old)."); AL_IGNORE_WARNING("-Wdeprecated-declarations") av_register_all(); AL_IGNORE_WARNING_END #else log_info("Using FFmpeg version "FFMPEG_VERSION"."); #endif camu_ff_set_log_callback(av_log_callback); } AVCodecContext *camu_ff_alloc_codec_context(const AVCodec *codec, AVCodecParameters *codecpar) { AVCodecContext *codec_context = avcodec_alloc_context3(codec); if (!codec_context) { log_error("Failed to alloc codec context."); return NULL; } s32 ret = avcodec_parameters_to_context(codec_context, codecpar); if (ret < 0) { log_error("Failed to copy codec parameters (%s).", av_err2str(ret)); return NULL; } return codec_context; } bool camu_ff_open_avcodec(AVCodecContext *codec_context, const AVCodec *codec, AVDictionary *opts) { s32 ret = avcodec_open2(codec_context, codec, &opts); if (ret < 0) { log_error("Failed to open codec %s (%s).", codec->name, av_err2str(ret)); return false; } av_dict_free(&opts); return true; }