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:
@@ -456,6 +456,14 @@ int64_t fb_decoder_get_format_start_time(const FBDecoder *decoder)
|
||||
return decoder->fmt_ctx->start_time;
|
||||
}
|
||||
|
||||
int64_t fb_decoder_get_format_duration(const FBDecoder *decoder)
|
||||
{
|
||||
if (!decoder || !decoder->fmt_ctx) {
|
||||
return FB_NOPTS_VALUE;
|
||||
}
|
||||
return decoder->fmt_ctx->duration;
|
||||
}
|
||||
|
||||
int fb_decoder_guess_sample_aspect_ratio(const FBDecoder *decoder,
|
||||
FBFrame *frame, int *num, int *den)
|
||||
{
|
||||
|
||||
@@ -566,6 +566,8 @@ int fb_encoder_write_audio(FBEncoder *e, const uint8_t *const *channel_data,
|
||||
|
||||
int bytes_per_sample =
|
||||
av_get_bytes_per_sample(static_cast<AVSampleFormat>(sample_format));
|
||||
int planar =
|
||||
av_sample_fmt_is_planar(static_cast<AVSampleFormat>(sample_format));
|
||||
|
||||
bool result = true;
|
||||
|
||||
@@ -588,10 +590,16 @@ int fb_encoder_write_audio(FBEncoder *e, const uint8_t *const *channel_data,
|
||||
e->SetError("Failed to allocate sample array", r);
|
||||
return r;
|
||||
} else {
|
||||
for (int i = 0; i < channels; i++) {
|
||||
memcpy(input_data[i],
|
||||
channel_data[i] + start * size_t(bytes_per_sample),
|
||||
input_sample_count * size_t(bytes_per_sample));
|
||||
if (planar) {
|
||||
for (int i = 0; i < channels; i++) {
|
||||
memcpy(input_data[i],
|
||||
channel_data[i] + start * size_t(bytes_per_sample),
|
||||
input_sample_count * size_t(bytes_per_sample));
|
||||
}
|
||||
} else {
|
||||
size_t stride = size_t(bytes_per_sample) * size_t(channels);
|
||||
memcpy(input_data[0], channel_data[0] + start * stride,
|
||||
input_sample_count * stride);
|
||||
}
|
||||
|
||||
start += input_sample_count;
|
||||
|
||||
@@ -59,6 +59,14 @@ int fb_frame_get_buffer(FBFrame *frame, int align)
|
||||
return av_frame_get_buffer(frame->frame, align);
|
||||
}
|
||||
|
||||
int fb_frame_make_writable(FBFrame *frame)
|
||||
{
|
||||
if (!frame || !frame->frame) {
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
return av_frame_make_writable(frame->frame);
|
||||
}
|
||||
|
||||
int fb_frame_copy_props(FBFrame *dst, const FBFrame *src)
|
||||
{
|
||||
if (!dst || !src) {
|
||||
|
||||
@@ -68,6 +68,7 @@ static_assert(FB_PIX_FMT_YUVJ422P == AV_PIX_FMT_YUVJ422P, "pixfmt mismatch");
|
||||
static_assert(FB_PIX_FMT_YUVJ444P == AV_PIX_FMT_YUVJ444P, "pixfmt mismatch");
|
||||
static_assert(FB_PIX_FMT_RGBA == AV_PIX_FMT_RGBA, "pixfmt mismatch");
|
||||
static_assert(FB_PIX_FMT_GRAY16LE == AV_PIX_FMT_GRAY16LE, "pixfmt mismatch");
|
||||
static_assert(FB_PIX_FMT_YUV440P == AV_PIX_FMT_YUV440P, "pixfmt mismatch");
|
||||
static_assert(FB_PIX_FMT_YUVJ440P == AV_PIX_FMT_YUVJ440P, "pixfmt mismatch");
|
||||
static_assert(FB_PIX_FMT_RGB48LE == AV_PIX_FMT_RGB48LE, "pixfmt mismatch");
|
||||
static_assert(FB_PIX_FMT_YUV420P10LE == AV_PIX_FMT_YUV420P10LE, "pixfmt mismatch");
|
||||
|
||||
@@ -309,6 +309,14 @@ int fb_probe_read_subtitle_stream(const char *filename, int stream_index,
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
|
||||
// Limit to SRT for now (mirrors the editor's historical behavior)
|
||||
FBStreamInfo stream_info;
|
||||
if (fb_decoder_get_stream_info(decoder, &stream_info) < 0 ||
|
||||
stream_info.codec_id != (int)AV_CODEC_ID_SUBRIP) {
|
||||
fb_decoder_free(&decoder);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
FBPacket *pkt = fb_packet_alloc();
|
||||
|
||||
while (fb_decoder_get_packet(decoder, pkt) >= 0) {
|
||||
|
||||
@@ -81,3 +81,14 @@ int fb_resampler_convert(FBResampler *resampler, uint8_t **out, int out_count,
|
||||
}
|
||||
return swr_convert(resampler->ctx, out, out_count, in, in_count);
|
||||
}
|
||||
|
||||
int fb_resampler_convert_frame(FBResampler *resampler, uint8_t **out,
|
||||
int out_count, const FBFrame *in_frame)
|
||||
{
|
||||
if (!resampler || !in_frame || !in_frame->frame) {
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
return swr_convert(resampler->ctx, out, out_count,
|
||||
(const uint8_t **)in_frame->frame->extended_data,
|
||||
in_frame->frame->nb_samples);
|
||||
}
|
||||
|
||||
@@ -172,7 +172,8 @@ int fb_pix_fmt_component_size(int pix_fmt)
|
||||
if (!desc || desc->nb_components == 0) {
|
||||
return 0;
|
||||
}
|
||||
return desc->comp[0].step;
|
||||
// Bytes used to store one component: 1 for 8-bit formats, 2 for 9-16bit
|
||||
return (desc->comp[0].depth + 7) / 8;
|
||||
}
|
||||
|
||||
int fb_find_best_pix_fmt_of_list(const int *list, int pix_fmt)
|
||||
|
||||
Reference in New Issue
Block a user