Skip to content

Commit 17dd8e8

Browse files
authored
[BC-Breaking] Replace encode_image with save_image (#656)
Re-implement `encode_image` as a composition of `Muxer` and `Encoder` at Python so that we can get rid of custom C++ code.
1 parent b416654 commit 17dd8e8

22 files changed

+160
-858
lines changed

src/libspdl/core/CMakeLists.txt

-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ set(srcs
2626
detail/ffmpeg/encoder.cpp
2727
detail/ffmpeg/decoder.cpp
2828
detail/ffmpeg/demuxer.cpp
29-
detail/ffmpeg/encoding.cpp
3029
detail/ffmpeg/muxer.cpp
3130
detail/ffmpeg/filter_graph.cpp
3231
detail/ffmpeg/wrappers.cpp
@@ -42,7 +41,6 @@ set(srcs
4241
decoder.cpp
4342
demuxing.cpp
4443
codec.cpp
45-
encoding.cpp
4644
muxer.cpp
4745
packets.cpp
4846
utils.cpp

src/libspdl/core/detail/ffmpeg/conversion.cpp

+3-52
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
#include <libspdl/core/conversion.h>
1010

1111
#include "libspdl/core/detail/ffmpeg/compat.h"
12-
#include "libspdl/core/detail/ffmpeg/conversion.h"
1312
#include "libspdl/core/detail/ffmpeg/logging.h"
13+
#include "libspdl/core/detail/ffmpeg/wrappers.h"
1414
#include "libspdl/core/detail/logging.h"
1515
#include "libspdl/core/detail/tracing.h"
1616

@@ -471,58 +471,8 @@ AVBufferRef* create_reference_buffer(uint8_t* data, int size) {
471471
return av_buffer_create(
472472
data, size, no_free, nullptr, AV_BUFFER_FLAG_READONLY);
473473
}
474-
475-
void ref_interweaved(
476-
AVFrame* frame,
477-
void* data,
478-
int num_channels,
479-
int bit_depth = 1) {
480-
auto* src = static_cast<uint8_t*>(data);
481-
int linesize = frame->width * num_channels * bit_depth;
482-
frame->data[0] = src;
483-
frame->linesize[0] = linesize;
484-
frame->buf[0] = create_reference_buffer(src, linesize * frame->height);
485-
}
486-
487-
void ref_planar(AVFrame* frame, void* data, int num_channels) {
488-
auto src = static_cast<uint8_t*>(data);
489-
auto size = frame->width * frame->height;
490-
for (int c = 0; c < num_channels; ++c) {
491-
frame->data[c] = src;
492-
frame->linesize[c] = frame->width;
493-
frame->buf[c] = create_reference_buffer(src, size);
494-
src += size;
495-
}
496-
}
497474
} // namespace
498475

499-
AVFramePtr reference_image_buffer(
500-
AVPixelFormat fmt,
501-
void* data,
502-
size_t width,
503-
size_t height) {
504-
auto frame = get_video_frame(fmt, width, height, 0);
505-
switch (fmt) {
506-
case AV_PIX_FMT_RGB24:
507-
case AV_PIX_FMT_BGR24:
508-
ref_interweaved(frame.get(), data, 3);
509-
break;
510-
case AV_PIX_FMT_GRAY8:
511-
ref_interweaved(frame.get(), data, 1);
512-
break;
513-
case AV_PIX_FMT_GRAY16:
514-
ref_interweaved(frame.get(), data, 1, 2);
515-
break;
516-
case AV_PIX_FMT_YUV444P:
517-
ref_planar(frame.get(), data, 3);
518-
break;
519-
default:
520-
SPDL_FAIL(fmt::format(
521-
"Unsupported source pixel format: {}", av_get_pix_fmt_name(fmt)));
522-
}
523-
return frame;
524-
}
525-
526476
} // namespace detail
527477

528478
////////////////////////////////////////////////////////////////////////////////
@@ -776,7 +726,8 @@ VideoFramesPtr create_reference_video_frame(
776726
validate_nhw(shape, stride);
777727
return create_reference_video_frame(
778728
fmt, data, shape, stride, time_base, pts, 1);
779-
case AV_PIX_FMT_GRAY16:
729+
case AV_PIX_FMT_GRAY16BE:
730+
case AV_PIX_FMT_GRAY16LE:
780731
validate_nhw(shape, stride);
781732
CHECK_BITS(bits, 16);
782733
return create_reference_video_frame(

src/libspdl/core/detail/ffmpeg/conversion.h

-23
This file was deleted.

src/libspdl/core/detail/ffmpeg/ctx_utils.cpp

-115
Original file line numberDiff line numberDiff line change
@@ -282,108 +282,6 @@ const AVCodec* get_image_codec(
282282
return c;
283283
}
284284

285-
namespace {
286-
bool is_pix_fmt_supported(
287-
const AVPixelFormat fmt,
288-
const AVPixelFormat* pix_fmts) {
289-
if (!pix_fmts) {
290-
return true;
291-
}
292-
while (*pix_fmts != AV_PIX_FMT_NONE) {
293-
if (fmt == *pix_fmts) {
294-
return true;
295-
}
296-
++pix_fmts;
297-
}
298-
return false;
299-
}
300-
301-
std::string to_str(const AVPixelFormat* pix_fmts) {
302-
std::vector<std::string> ret;
303-
while (*pix_fmts != AV_PIX_FMT_NONE) {
304-
ret.emplace_back(av_get_pix_fmt_name(*pix_fmts));
305-
++pix_fmts;
306-
}
307-
return fmt::to_string(fmt::join(ret, ", "));
308-
}
309-
} // namespace
310-
311-
AVPixelFormat get_enc_fmt(
312-
AVPixelFormat src_fmt,
313-
const std::optional<std::string>& encoder_format,
314-
const AVCodec* codec) {
315-
if (encoder_format) {
316-
const auto& val = encoder_format.value();
317-
auto fmt = av_get_pix_fmt(val.c_str());
318-
if (!is_pix_fmt_supported(fmt, codec->pix_fmts)) {
319-
SPDL_FAIL(fmt::format(
320-
"Codec {} does not support {} format. Supported values are; {}",
321-
codec->name,
322-
val,
323-
to_str(codec->pix_fmts)));
324-
}
325-
return fmt;
326-
}
327-
if (codec->pix_fmts) {
328-
return codec->pix_fmts[0];
329-
}
330-
return src_fmt;
331-
}
332-
333-
AVCodecContextPtr get_codec_ctx(const AVCodec* codec, int flags) {
334-
auto ctx = AVCodecContextPtr{CHECK_AVALLOCATE(avcodec_alloc_context3(codec))};
335-
336-
if (flags & AVFMT_GLOBALHEADER) {
337-
ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
338-
}
339-
return ctx;
340-
}
341-
342-
void configure_video_codec_ctx(
343-
AVCodecContextPtr& ctx,
344-
AVPixelFormat format,
345-
AVRational frame_rate,
346-
int width,
347-
int height,
348-
const EncodeConfig& cfg) {
349-
// TODO: Review other options and make them configurable?
350-
// https://ffmpeg.org/doxygen/4.1/muxing_8c_source.html#l00147
351-
// - bit_rate_tolerance
352-
// - mb_decisions
353-
354-
ctx->pix_fmt = format;
355-
ctx->width = width;
356-
ctx->height = height;
357-
ctx->time_base = av_inv_q(frame_rate);
358-
359-
// Set optional stuff
360-
if (cfg.bit_rate > 0) {
361-
ctx->bit_rate = cfg.bit_rate;
362-
}
363-
if (cfg.compression_level != -1) {
364-
ctx->compression_level = cfg.compression_level;
365-
}
366-
if (cfg.gop_size != -1) {
367-
ctx->gop_size = cfg.gop_size;
368-
}
369-
if (cfg.max_b_frames != -1) {
370-
ctx->max_b_frames = cfg.max_b_frames;
371-
}
372-
if (cfg.qscale >= 0) {
373-
ctx->flags |= AV_CODEC_FLAG_QSCALE;
374-
ctx->global_quality = FF_QP2LAMBDA * cfg.qscale;
375-
}
376-
}
377-
378-
void configure_image_codec_ctx(
379-
AVCodecContextPtr& ctx,
380-
AVPixelFormat format,
381-
int width,
382-
int height,
383-
const EncodeConfig& cfg) {
384-
configure_video_codec_ctx(ctx, format, {1, 1}, width, height, cfg);
385-
}
386-
387285
void open_codec_for_encode(
388286
AVCodecContext* codec_ctx,
389287
const std::optional<OptionDict>& encode_options) {
@@ -432,19 +330,6 @@ void open_codec_for_encode(
432330
check_empty(option);
433331
}
434332

435-
AVStream* create_stream(
436-
AVFormatContext* format_ctx,
437-
AVCodecContext* codec_ctx) {
438-
AVStream* stream = CHECK_AVALLOCATE(avformat_new_stream(format_ctx, nullptr));
439-
// Note: time base may be adjusted when `calling avformat_write_header()`
440-
// https://ffmpeg.org/doxygen/5.1/structAVStream.html#a9db755451f14e2bf590d4b85d82b32e6
441-
stream->time_base = codec_ctx->time_base;
442-
CHECK_AVERROR(
443-
avcodec_parameters_from_context(stream->codecpar, codec_ctx),
444-
"Failed to create a new stream.");
445-
return stream;
446-
}
447-
448333
void open_format(
449334
AVFormatContext* format_ctx,
450335
const std::optional<OptionDict>& options) {

src/libspdl/core/detail/ffmpeg/ctx_utils.h

-29
Original file line numberDiff line numberDiff line change
@@ -47,39 +47,10 @@ AVFormatOutputContextPtr get_output_format_ctx(
4747
const std::string& url,
4848
const std::optional<std::string>& format = std::nullopt);
4949

50-
const AVCodec* get_image_codec(
51-
const std::optional<std::string>& encoder,
52-
const AVOutputFormat* oformat,
53-
const std::string& url);
54-
55-
AVPixelFormat get_enc_fmt(
56-
AVPixelFormat src_fmt,
57-
const std::optional<std::string>& encoder_format,
58-
const AVCodec* codec);
59-
60-
AVCodecContextPtr get_codec_ctx(const AVCodec* codec, int flags);
61-
62-
void configure_video_codec_ctx(
63-
AVCodecContextPtr& ctx,
64-
AVPixelFormat format,
65-
AVRational frame_rate,
66-
int width,
67-
int height,
68-
const EncodeConfig& cfg);
69-
70-
void configure_image_codec_ctx(
71-
AVCodecContextPtr& ctx,
72-
AVPixelFormat format,
73-
int width,
74-
int height,
75-
const EncodeConfig& cfg);
76-
7750
void open_codec_for_encode(
7851
AVCodecContext* codec_ctx,
7952
const std::optional<OptionDict>& option);
8053

81-
AVStream* create_stream(AVFormatContext* format_ctx, AVCodecContext* codec_ctx);
82-
8354
void open_format(
8455
AVFormatContext* format_ctx,
8556
const std::optional<OptionDict>& option = std::nullopt);

src/libspdl/core/detail/ffmpeg/encoding.cpp

-103
This file was deleted.

0 commit comments

Comments
 (0)