app: route all FFmpeg access through the ffmpeg_bridge C API
Replace every direct FFmpeg call in the editor and the render worker with the pure C ffmpeg_bridge API, wrapped in thin C++ adapters that preserve the original interfaces: - avframeptr.h: olive::AVFrame adapter around FBFrame handles - ffmpegutils: format conversion helpers on FB_* constants; the int overload is renamed GetCompatibleBridgePixelFormat to avoid a silent overload-resolution trap with the PixelFormat enum - ffmpegdecoder/ffmpegencoder: rewritten as handle-based adapters over FBDecoder/FBProbe/FBEncoder/FBScaler/FBResampler - audioprocessor: FBAudioGraph push/pull adapter - pluginrenderer/OliveClip: sws/pixdesc usage converted to FBScaler and fb_pix_fmt_* queries - AudioParams/channel layouts are plain uint64_t masks everywhere Build integration: the root project no longer links FFMPEG directly; only ffmpeg_bridge does. Binaries resolve the bridge library at runtime via @loader_path inside the macOS app bundle (copied there post-build) and via $ORIGIN/../ffmpeg_bridge/bin on Linux; on Windows the DLL is installed next to the executables, so packages on all three platforms ship the bridge library. ffmpeg_bridge gains the extra API the adapters need: fb_frame_make_writable, fb_decoder_get_format_duration, fb_resampler_convert_frame, FB_PIX_FMT_YUV440P, SRT validation in fb_probe_read_subtitle_stream, packed/planar fixes in fb_encoder_write_audio, and a component-size fix in fb_pix_fmt_component_size.
This commit is contained in:
@@ -98,7 +98,7 @@ ConformManager::GetConformedFilename(const QString &cache_path,
|
||||
QString::number(stream.stream()),
|
||||
QString::number(params.sample_rate()),
|
||||
QString::number(params.format()),
|
||||
QString::number(params.channel_layout().u.mask),
|
||||
QString::number(params.channel_layout()),
|
||||
QString::number(i));
|
||||
|
||||
filenames[i] = QDir(cache_path).filePath(index_fn);
|
||||
|
||||
@@ -252,7 +252,7 @@ DecoderPtr Decoder::CreateFromID(const QString &id)
|
||||
|
||||
void Decoder::SignalProcessingProgress(int64_t ts, int64_t duration)
|
||||
{
|
||||
if (duration != AV_NOPTS_VALUE && duration != 0) {
|
||||
if (duration != FB_NOPTS_VALUE && duration != 0) {
|
||||
emit IndexProgress(static_cast<double>(ts) /
|
||||
static_cast<double>(duration));
|
||||
}
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
#ifndef DECODER_H
|
||||
#define DECODER_H
|
||||
|
||||
extern "C" {
|
||||
#include <libswresample/swresample.h>
|
||||
}
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
||||
@@ -300,7 +300,7 @@ void EncodingParams::Save(QXmlStreamWriter *writer) const
|
||||
|
||||
writer->writeTextElement(
|
||||
QStringLiteral("channellayout"),
|
||||
QString::number(audio_params().channel_layout().u.mask));
|
||||
QString::number(audio_params().channel_layout()));
|
||||
writer->writeTextElement(
|
||||
QStringLiteral("format"),
|
||||
QString::fromStdString(audio_params_.format().to_string()));
|
||||
@@ -542,12 +542,8 @@ bool EncodingParams::LoadV1(QXmlStreamReader *reader)
|
||||
audio_params_.set_sample_rate(
|
||||
reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("channellayout")) {
|
||||
AVChannelLayout av_channel_layout;
|
||||
av_channel_layout_from_mask(
|
||||
&av_channel_layout,
|
||||
audio_params_.set_channel_layout(
|
||||
reader->readElementText().toLongLong());
|
||||
audio_params_.set_channel_layout(av_channel_layout);
|
||||
av_channel_layout_uninit(&av_channel_layout);
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
audio_params_.set_format(SampleFormat::from_string(
|
||||
reader->readElementText().toStdString()));
|
||||
|
||||
+483
-913
File diff suppressed because it is too large
Load Diff
@@ -22,17 +22,9 @@
|
||||
#ifndef FFMPEGDECODER_H
|
||||
#define FFMPEGDECODER_H
|
||||
|
||||
// Fixes weird define issue when including <avfilter.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/hwcontext.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
}
|
||||
#include <ffmpeg_bridge/ffmpeg_bridge.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QVector>
|
||||
@@ -45,7 +37,10 @@ namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder
|
||||
* @brief A Decoder derivative that uses the ffmpeg_bridge library as an Olive decoder
|
||||
*
|
||||
* All media access goes through the pure C API of the ffmpeg_bridge shared
|
||||
* library; this class never sees an FFmpeg structure or function.
|
||||
*/
|
||||
class FFmpegDecoder : public Decoder {
|
||||
Q_OBJECT
|
||||
@@ -84,88 +79,10 @@ protected:
|
||||
virtual rational GetAudioStartOffset() const override;
|
||||
|
||||
private:
|
||||
class Instance {
|
||||
public:
|
||||
Instance();
|
||||
|
||||
~Instance()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool Open(const char *filename, int stream_index);
|
||||
|
||||
bool IsOpen() const
|
||||
{
|
||||
return fmt_ctx_;
|
||||
}
|
||||
|
||||
void Close();
|
||||
|
||||
/**
|
||||
* @brief Uses the FFmpeg API to retrieve a packet (stored in pkt_) and decode it (stored in frame_)
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* An FFmpeg error code, or >= 0 on success
|
||||
*/
|
||||
int GetFrame(AVPacket *pkt, AVFrame *frame);
|
||||
|
||||
const char *GetSubtitleHeader() const;
|
||||
|
||||
int GetSubtitle(AVPacket *pkt, AVSubtitle *sub);
|
||||
|
||||
int GetPacket(AVPacket *pkt);
|
||||
|
||||
void Seek(int64_t timestamp);
|
||||
|
||||
AVFormatContext *fmt_ctx() const
|
||||
{
|
||||
return fmt_ctx_;
|
||||
}
|
||||
|
||||
AVStream *avstream() const
|
||||
{
|
||||
return avstream_;
|
||||
}
|
||||
AVCodecContext *codec_ctx()
|
||||
{
|
||||
return codec_ctx_;
|
||||
}
|
||||
|
||||
bool hwaccel_enabled() const
|
||||
{
|
||||
return hwaccel_enabled_;
|
||||
}
|
||||
|
||||
AVPixelFormat hw_pix_fmt() const
|
||||
{
|
||||
return hw_pix_fmt_;
|
||||
}
|
||||
|
||||
private:
|
||||
static AVHWDeviceType ChooseHardwareDevice();
|
||||
static AVPixelFormat GetHardwareFormat(AVCodecContext *ctx,
|
||||
const AVPixelFormat *pix_fmts);
|
||||
|
||||
bool InitHardwareAcceleration(const AVCodec *codec);
|
||||
void CleanupHardwareAcceleration();
|
||||
|
||||
AVFormatContext *fmt_ctx_;
|
||||
AVCodecContext *codec_ctx_;
|
||||
AVStream *avstream_;
|
||||
AVDictionary *opts_;
|
||||
|
||||
AVBufferRef *hw_device_ctx_;
|
||||
AVHWDeviceType hw_device_type_;
|
||||
AVPixelFormat hw_pix_fmt_;
|
||||
bool hwaccel_enabled_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Handle an FFmpeg error code
|
||||
* @brief Handle a bridge error code
|
||||
*
|
||||
* Uses the FFmpeg API to retrieve a descriptive string for this error code and sends it to Error(). As such, this
|
||||
* Uses the bridge API to retrieve a descriptive string for this error code and sends it to Error(). As such, this
|
||||
* function also automatically closes the Decoder.
|
||||
*
|
||||
* @param error_code
|
||||
@@ -176,15 +93,10 @@ private:
|
||||
|
||||
AVFramePtr TransferHardwareFrame(AVFramePtr f);
|
||||
|
||||
static PixelFormat GetNativePixelFormat(AVPixelFormat pix_fmt);
|
||||
static int GetNativeChannelCount(AVPixelFormat pix_fmt);
|
||||
static PixelFormat GetNativePixelFormat(int pix_fmt);
|
||||
static int GetNativeChannelCount(int pix_fmt);
|
||||
|
||||
static AVChannelLayout ValidateChannelLayout(AVStream *stream);
|
||||
|
||||
static const char *
|
||||
GetInterlacingModeInFFmpeg(VideoParams::Interlacing interlacing);
|
||||
|
||||
static bool IsPixelFormatGLSLCompatible(AVPixelFormat f);
|
||||
static bool IsPixelFormatGLSLCompatible(int f);
|
||||
|
||||
AVFramePtr GetFrameFromCache(const int64_t &t) const;
|
||||
|
||||
@@ -202,17 +114,17 @@ private:
|
||||
|
||||
static int MaximumQueueSize();
|
||||
|
||||
SwsContext *sws_ctx_;
|
||||
int sws_src_width_;
|
||||
int sws_src_height_;
|
||||
AVPixelFormat sws_src_format_;
|
||||
int sws_dst_width_;
|
||||
int sws_dst_height_;
|
||||
AVPixelFormat sws_dst_format_;
|
||||
AVColorRange sws_colrange_;
|
||||
AVColorSpace sws_colspace_;
|
||||
FBScaler *scaler_;
|
||||
int scaler_src_width_;
|
||||
int scaler_src_height_;
|
||||
int scaler_src_format_;
|
||||
int scaler_dst_width_;
|
||||
int scaler_dst_height_;
|
||||
int scaler_dst_format_;
|
||||
int scaler_colrange_;
|
||||
int scaler_colspace_;
|
||||
|
||||
AVPacket *working_packet_;
|
||||
FBPacket *working_packet_;
|
||||
|
||||
int64_t second_ts_;
|
||||
|
||||
@@ -221,7 +133,17 @@ private:
|
||||
bool cache_at_zero_;
|
||||
bool cache_at_eof_;
|
||||
|
||||
Instance instance_;
|
||||
FBDecoder *instance_;
|
||||
|
||||
// Stream parameters cached on open (the stream object itself lives
|
||||
// inside the bridge library)
|
||||
rational stream_time_base_;
|
||||
int64_t stream_start_time_;
|
||||
int64_t stream_duration_;
|
||||
int64_t format_start_time_;
|
||||
int input_sample_format_;
|
||||
int input_sample_rate_;
|
||||
uint64_t input_channel_layout_mask_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+202
-859
File diff suppressed because it is too large
Load Diff
@@ -22,19 +22,20 @@
|
||||
#ifndef FFMPEGENCODER_H
|
||||
#define FFMPEGENCODER_H
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
}
|
||||
#include <ffmpeg_bridge/ffmpeg_bridge.h>
|
||||
|
||||
#include "codec/encoder.h"
|
||||
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An Encoder derivative that uses the ffmpeg_bridge library for encoding
|
||||
*
|
||||
* All encoding work happens inside the ffmpeg_bridge shared library through
|
||||
* its pure C API; this class only translates EncodingParams into a bridge
|
||||
* configuration and forwards calls.
|
||||
*/
|
||||
class FFmpegEncoder : public Encoder {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -67,54 +68,16 @@ public:
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Handle an FFmpeg error code
|
||||
*
|
||||
* Uses the FFmpeg API to retrieve a descriptive string for this error code and sends it to Error(). As such, this
|
||||
* function also automatically closes the Decoder.
|
||||
*
|
||||
* @param error_code
|
||||
* @brief Copy the last error message from the bridge into the encoder error state
|
||||
*/
|
||||
void FFmpegError(const QString &context, int error_code);
|
||||
void SetErrorFromBridge();
|
||||
|
||||
bool WriteAVFrame(AVFrame *frame, AVCodecContext *codec_ctx,
|
||||
AVStream *stream);
|
||||
static int ExportCodecToBridge(ExportCodec::Codec c);
|
||||
|
||||
bool InitializeStream(enum AVMediaType type, AVStream **stream,
|
||||
AVCodecContext **codec_ctx,
|
||||
const ExportCodec::Codec &codec);
|
||||
bool InitializeCodecContext(AVStream **stream, AVCodecContext **codec_ctx,
|
||||
const AVCodec *codec);
|
||||
bool SetupCodecContext(AVStream *stream, AVCodecContext *codec_ctx,
|
||||
const AVCodec *codec);
|
||||
FBEncoder *encoder_;
|
||||
|
||||
void FlushEncoders();
|
||||
void FlushCodecCtx(AVCodecContext *codec_ctx, AVStream *stream);
|
||||
|
||||
bool InitializeResampleContext(const AudioParams &audio);
|
||||
|
||||
static const AVCodec *GetEncoder(ExportCodec::Codec c,
|
||||
SampleFormat aformat);
|
||||
|
||||
AVFormatContext *fmt_ctx_;
|
||||
|
||||
AVStream *video_stream_;
|
||||
AVCodecContext *video_codec_ctx_;
|
||||
AVFilterGraph *video_scale_ctx_;
|
||||
AVFilterContext *video_buffersrc_ctx_;
|
||||
AVFilterContext *video_buffersink_ctx_;
|
||||
PixelFormat video_conversion_fmt_;
|
||||
|
||||
AVStream *audio_stream_;
|
||||
AVCodecContext *audio_codec_ctx_;
|
||||
SwrContext *audio_resample_ctx_;
|
||||
AVFrame *audio_frame_;
|
||||
int audio_max_samples_;
|
||||
int audio_frame_offset_;
|
||||
int audio_write_count_;
|
||||
|
||||
AVStream *subtitle_stream_;
|
||||
AVCodecContext *subtitle_codec_ctx_;
|
||||
|
||||
bool open_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user