#pragma once /** * FFmpeg Version Compatibility Header * This file provides compatibility macros and functions for different FFmpeg versions * Supports FFmpeg 3.x, 4.x, 5.x, 6.x, and 7.x */ extern "C" { #include #include #include #include #include #include #include #include #include #include #include } // FFmpeg version detection #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) #define FFMPEG_VERSION_MAJOR 3 #elif LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59, 0, 100) #define FFMPEG_VERSION_MAJOR 4 #elif LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(60, 0, 100) #define FFMPEG_VERSION_MAJOR 5 #elif LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(61, 0, 100) #define FFMPEG_VERSION_MAJOR 6 #else #define FFMPEG_VERSION_MAJOR 7 #endif // Compatibility functions for deprecated functions inline void ffmpeg_register_all() { #if FFMPEG_VERSION_MAJOR < 4 av_register_all(); #endif // No-op in FFmpeg 4.0+ } inline void ffmpeg_register_devices() { #if FFMPEG_VERSION_MAJOR < 4 avdevice_register_all(); #endif // No-op in FFmpeg 4.0+ } // Compatibility for AVInputFormat/AVOutputFormat #if FFMPEG_VERSION_MAJOR >= 4 using FFmpegInputFormat = const AVInputFormat; using FFmpegOutputFormat = const AVOutputFormat; #else using FFmpegInputFormat = AVInputFormat; using FFmpegOutputFormat = AVOutputFormat; #endif // Compatibility for AVCodec pointer #if FFMPEG_VERSION_MAJOR >= 7 using FFmpegCodec = const AVCodec; #else using FFmpegCodec = AVCodec; #endif // Compatibility for av_err2str macro (C++ safe version) #ifdef __cplusplus #undef av_err2str #ifdef _MSC_VER #include #define av_err2str(errnum) av_make_error_string((char*)_alloca(AV_ERROR_MAX_STRING_SIZE), AV_ERROR_MAX_STRING_SIZE, errnum) #else #define av_err2str(errnum) av_make_error_string((char*)__builtin_alloca(AV_ERROR_MAX_STRING_SIZE), AV_ERROR_MAX_STRING_SIZE, errnum) #endif #endif // Compatibility for bitstream filter context #if FFMPEG_VERSION_MAJOR >= 4 using AVBitStreamFilterContext = AVBSFContext; #else // For FFmpeg 3.x, AVBitStreamFilterContext is already defined // No need to redefine it #endif // Compatibility functions for codec context access inline AVMediaType ffmpeg_get_codec_type(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->codec_type; #else return stream->codec->codec_type; #endif } inline AVCodecID ffmpeg_get_codec_id(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->codec_id; #else return stream->codec->codec_id; #endif } inline int ffmpeg_get_codec_width(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->width; #else return stream->codec->width; #endif } inline int ffmpeg_get_codec_height(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->height; #else return stream->codec->height; #endif } inline AVPixelFormat ffmpeg_get_codec_pix_fmt(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return static_cast(stream->codecpar->format); #else return stream->codec->pix_fmt; #endif } inline int ffmpeg_get_codec_sample_rate(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->sample_rate; #else return stream->codec->sample_rate; #endif } inline int ffmpeg_get_codec_channels(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 7 return stream->codecpar->ch_layout.nb_channels; #elif FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->channels; #else return stream->codec->channels; #endif } inline uint64_t ffmpeg_get_codec_channel_layout(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 7 // In FFmpeg 7, use ch_layout.u.mask directly if it's a mask layout if (stream->codecpar->ch_layout.order == AV_CHANNEL_ORDER_NATIVE) { return stream->codecpar->ch_layout.u.mask; } else { // For non-mask layouts, return a default stereo layout return AV_CH_LAYOUT_STEREO; } #elif FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->channel_layout; #else return stream->codec->channel_layout; #endif } inline AVSampleFormat ffmpeg_get_codec_sample_fmt(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return static_cast(stream->codecpar->format); #else return stream->codec->sample_fmt; #endif } // Compatibility for channel layout functions inline uint64_t ffmpeg_get_default_channel_layout(int channels) { #if FFMPEG_VERSION_MAJOR >= 7 AVChannelLayout ch_layout; av_channel_layout_default(&ch_layout, channels); if (ch_layout.order == AV_CHANNEL_ORDER_NATIVE) { return ch_layout.u.mask; } else { // Fallback for common channel counts switch (channels) { case 1: return AV_CH_LAYOUT_MONO; case 2: return AV_CH_LAYOUT_STEREO; case 6: return AV_CH_LAYOUT_5POINT1; case 8: return AV_CH_LAYOUT_7POINT1; default: return AV_CH_LAYOUT_STEREO; } } #else return av_get_default_channel_layout(channels); #endif } // Compatibility for filter registration inline void ffmpeg_register_filters() { #if FFMPEG_VERSION_MAJOR < 4 avfilter_register_all(); #endif // No-op in FFmpeg 4.0+ } // Compatibility for channel layout string functions inline int ffmpeg_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout) { #if FFMPEG_VERSION_MAJOR >= 7 (void)nb_channels; // Suppress unused parameter warning AVChannelLayout ch_layout; av_channel_layout_from_mask(&ch_layout, channel_layout); return av_channel_layout_describe(&ch_layout, buf, buf_size); #else av_get_channel_layout_string(buf, buf_size, nb_channels, channel_layout); return strlen(buf); #endif } // Compatibility for AVFrame channels access inline int ffmpeg_get_frame_channels(AVFrame* frame) { #if FFMPEG_VERSION_MAJOR >= 7 return frame->ch_layout.nb_channels; #else return frame->channels; #endif } // Compatibility for AVFrame channel_layout access inline uint64_t ffmpeg_get_frame_channel_layout(AVFrame* frame) { #if FFMPEG_VERSION_MAJOR >= 7 if (frame->ch_layout.order == AV_CHANNEL_ORDER_NATIVE) { return frame->ch_layout.u.mask; } else { return AV_CH_LAYOUT_STEREO; } #else return frame->channel_layout; #endif } // Compatibility for av_samples_get_buffer_size inline int ffmpeg_get_buffer_size(enum AVSampleFormat sample_fmt, int nb_channels, int nb_samples, int align) { #if FFMPEG_VERSION_MAJOR >= 7 return av_samples_get_buffer_size(nullptr, nb_channels, nb_samples, sample_fmt, align); #else return av_samples_get_buffer_size(nullptr, nb_channels, nb_samples, sample_fmt, align); #endif } // Compatibility for codec context creation from stream inline AVCodecContext* ffmpeg_get_codec_context(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 const AVCodec* codec = avcodec_find_decoder(stream->codecpar->codec_id); if (!codec) return nullptr; AVCodecContext* ctx = avcodec_alloc_context3(codec); if (!ctx) return nullptr; if (avcodec_parameters_to_context(ctx, stream->codecpar) < 0) { avcodec_free_context(&ctx); return nullptr; } return ctx; #else return stream->codec; #endif } // Compatibility for setting stream codec parameters inline void ffmpeg_set_stream_codec_id(AVStream* stream, enum AVCodecID codec_id) { #if FFMPEG_VERSION_MAJOR >= 4 stream->codecpar->codec_id = codec_id; #else stream->codec->codec_id = codec_id; #endif } inline void ffmpeg_set_stream_codec_type(AVStream* stream, enum AVMediaType codec_type) { #if FFMPEG_VERSION_MAJOR >= 4 stream->codecpar->codec_type = codec_type; #else stream->codec->codec_type = codec_type; #endif } inline void ffmpeg_set_stream_bit_rate(AVStream* stream, int64_t bit_rate) { #if FFMPEG_VERSION_MAJOR >= 4 stream->codecpar->bit_rate = bit_rate; #else stream->codec->bit_rate = bit_rate; #endif } inline void ffmpeg_set_stream_pix_fmt(AVStream* stream, enum AVPixelFormat pix_fmt) { #if FFMPEG_VERSION_MAJOR >= 4 stream->codecpar->format = pix_fmt; #else stream->codec->pix_fmt = pix_fmt; #endif } inline void ffmpeg_set_stream_dimensions(AVStream* stream, int width, int height) { #if FFMPEG_VERSION_MAJOR >= 4 stream->codecpar->width = width; stream->codecpar->height = height; #else stream->codec->width = width; stream->codec->height = height; #endif } // Compatibility for stream codec parameters inline int ffmpeg_copy_codec_params_to_stream(AVStream* stream, AVCodecContext* codec_ctx) { #if FFMPEG_VERSION_MAJOR >= 4 return avcodec_parameters_from_context(stream->codecpar, codec_ctx); #else return 0; // No-op for older versions #endif } // Compatibility for extradata access inline uint8_t* ffmpeg_get_extradata(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->extradata; #else return stream->codec->extradata; #endif } inline int ffmpeg_get_extradata_size(AVStream* stream) { #if FFMPEG_VERSION_MAJOR >= 4 return stream->codecpar->extradata_size; #else return stream->codec->extradata_size; #endif } inline void ffmpeg_set_stream_extradata(AVStream* stream, uint8_t* data, int size) { #if FFMPEG_VERSION_MAJOR >= 4 stream->codecpar->extradata = data; stream->codecpar->extradata_size = size; #else stream->codec->extradata = data; stream->codec->extradata_size = size; #endif } // Compatibility for AVCodecContext channels and channel_layout inline void ffmpeg_set_codec_channels(AVCodecContext* ctx, int channels) { #if FFMPEG_VERSION_MAJOR >= 7 av_channel_layout_default(&ctx->ch_layout, channels); #else ctx->channels = channels; #endif } inline void ffmpeg_set_codec_channel_layout(AVCodecContext* ctx, uint64_t channel_layout) { #if FFMPEG_VERSION_MAJOR >= 7 av_channel_layout_from_mask(&ctx->ch_layout, channel_layout); #else ctx->channel_layout = channel_layout; #endif } inline int ffmpeg_get_codec_context_channels(AVCodecContext* ctx) { #if FFMPEG_VERSION_MAJOR >= 7 return ctx->ch_layout.nb_channels; #else return ctx->channels; #endif } // Compatibility for swr_alloc_set_opts inline SwrContext* ffmpeg_swr_alloc_set_opts(SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, int log_offset, void *log_ctx) { #if FFMPEG_VERSION_MAJOR >= 7 SwrContext *swr_ctx = swr_alloc(); if (!swr_ctx) return NULL; AVChannelLayout out_ch_layout_new, in_ch_layout_new; av_channel_layout_from_mask(&out_ch_layout_new, out_ch_layout); av_channel_layout_from_mask(&in_ch_layout_new, in_ch_layout); av_opt_set_chlayout(swr_ctx, "ochl", &out_ch_layout_new, 0); av_opt_set_int(swr_ctx, "osf", out_sample_fmt, 0); av_opt_set_int(swr_ctx, "osr", out_sample_rate, 0); av_opt_set_chlayout(swr_ctx, "ichl", &in_ch_layout_new, 0); av_opt_set_int(swr_ctx, "isf", in_sample_fmt, 0); av_opt_set_int(swr_ctx, "isr", in_sample_rate, 0); av_channel_layout_uninit(&out_ch_layout_new); av_channel_layout_uninit(&in_ch_layout_new); return swr_ctx; #else return swr_alloc_set_opts(s, out_ch_layout, out_sample_fmt, out_sample_rate, in_ch_layout, in_sample_fmt, in_sample_rate, log_offset, log_ctx); #endif } // Compatibility for codec parameters setting inline int ffmpeg_av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align) { #if FFMPEG_VERSION_MAJOR >= 7 return av_samples_alloc_array_and_samples(&audio_data, linesize, nb_channels, nb_samples, sample_fmt, align); #else return av_samples_alloc(audio_data, linesize, nb_channels, nb_samples, sample_fmt, align); #endif } inline void ffmpeg_set_frame_channel_layout(AVFrame* frame, AVCodecContext* codec_ctx) { #if FFMPEG_VERSION_MAJOR >= 7 av_channel_layout_copy(&frame->ch_layout, &codec_ctx->ch_layout); #else frame->channel_layout = codec_ctx->channel_layout; #endif } inline void ffmpeg_set_stream_codec_params(AVStream* stream, AVCodecContext* codec_ctx) { #if FFMPEG_VERSION_MAJOR >= 7 stream->codecpar->codec_id = codec_ctx->codec_id; stream->codecpar->bit_rate = codec_ctx->bit_rate; stream->codecpar->width = codec_ctx->width; stream->codecpar->height = codec_ctx->height; stream->codecpar->format = codec_ctx->pix_fmt; stream->codecpar->sample_rate = codec_ctx->sample_rate; av_channel_layout_copy(&stream->codecpar->ch_layout, &codec_ctx->ch_layout); stream->time_base = codec_ctx->time_base; #elif FFMPEG_VERSION_MAJOR >= 4 stream->codecpar->codec_id = codec_ctx->codec_id; stream->codecpar->bit_rate = codec_ctx->bit_rate; stream->codecpar->width = codec_ctx->width; stream->codecpar->height = codec_ctx->height; stream->codecpar->format = codec_ctx->pix_fmt; stream->codecpar->sample_rate = codec_ctx->sample_rate; stream->codecpar->channels = codec_ctx->channels; stream->codecpar->channel_layout = codec_ctx->channel_layout; stream->time_base = codec_ctx->time_base; #else *(stream->codec) = *codec_ctx; #endif } // Additional compatibility functions for missing identifiers inline int ffmpeg_get_channels(AVCodecContext* ctx) { #if FFMPEG_VERSION_MAJOR >= 7 return ctx->ch_layout.nb_channels; #else return ctx->channels; #endif } inline void ffmpeg_set_channels(AVCodecContext* ctx, int channels) { #if FFMPEG_VERSION_MAJOR >= 7 av_channel_layout_default(&ctx->ch_layout, channels); #else ctx->channels = channels; #endif } inline void ffmpeg_set_channel_layout(AVCodecContext* ctx, uint64_t channel_layout) { #if FFMPEG_VERSION_MAJOR >= 7 av_channel_layout_from_mask(&ctx->ch_layout, channel_layout); #else ctx->channel_layout = channel_layout; #endif } inline void ffmpeg_set_frame_channels(AVFrame* frame, int channels) { #if FFMPEG_VERSION_MAJOR >= 7 av_channel_layout_default(&frame->ch_layout, channels); #else frame->channels = channels; #endif } inline void ffmpeg_set_frame_channel_layout(AVFrame* frame, uint64_t channel_layout) { #if FFMPEG_VERSION_MAJOR >= 7 av_channel_layout_from_mask(&frame->ch_layout, channel_layout); #else frame->channel_layout = channel_layout; #endif } inline void ffmpeg_set_frame_pkt_pts(AVFrame* frame, int64_t pts) { #if FFMPEG_VERSION_MAJOR >= 4 frame->pts = pts; #else frame->pkt_pts = pts; #endif } // Compatibility for bitstream filter initialization #if FFMPEG_VERSION_MAJOR >= 4 inline AVBitStreamFilterContext* ffmpeg_bitstream_filter_init(const char* name) { const AVBitStreamFilter* bsf = av_bsf_get_by_name(name); if (!bsf) return nullptr; AVBSFContext* ctx = nullptr; if (av_bsf_alloc(bsf, &ctx) < 0) return nullptr; return ctx; } #else inline AVBitStreamFilterContext* ffmpeg_bitstream_filter_init(const char* name) { // For FFmpeg 3.x, use the old API return av_bitstream_filter_init(name); } #endif #if FFMPEG_VERSION_MAJOR >= 4 inline void ffmpeg_bitstream_filter_close(AVBitStreamFilterContext* ctx) { if (ctx) { av_bsf_free(&ctx); } } #else inline void ffmpeg_bitstream_filter_close(AVBitStreamFilterContext* ctx) { if (ctx) { av_bitstream_filter_close(ctx); } } #endif #if FFMPEG_VERSION_MAJOR >= 4 inline int ffmpeg_bitstream_filter_filter(AVBitStreamFilterContext* ctx, AVPacket* packet) { if (!ctx || !packet) return -1; // 对于新版本FFmpeg,需要先初始化BSF上下文 if (ctx->par_in && ctx->par_in->codec_type == AVMEDIA_TYPE_UNKNOWN) { // 从packet推断参数 ctx->par_in->codec_type = AVMEDIA_TYPE_AUDIO; ctx->par_in->codec_id = AV_CODEC_ID_AAC; if (avcodec_parameters_copy(ctx->par_out, ctx->par_in) < 0) { return -1; } if (av_bsf_init(ctx) < 0) { return -1; } } int ret = av_bsf_send_packet(ctx, packet); if (ret < 0) return ret; ret = av_bsf_receive_packet(ctx, packet); return ret; } #else inline int ffmpeg_bitstream_filter_filter(AVBitStreamFilterContext* ctx, AVPacket* packet) { if (!ctx || !packet) return -1; uint8_t* output_data = nullptr; int output_size = 0; int ret = av_bitstream_filter_filter(ctx, nullptr, nullptr, &output_data, &output_size, packet->data, packet->size, packet->flags & AV_PKT_FLAG_KEY); if (ret >= 0 && output_data && output_size > 0) { av_packet_unref(packet); packet->data = output_data; packet->size = output_size; packet->buf = av_buffer_create(output_data, output_size, av_buffer_default_free, nullptr, 0); } return ret; } #endif