ffmpeg: Support H.265 video output codec
Now can pick "H.265 / HEVC" in the video codec dropdown. Implementation notes: - Remap CRF value (which is for H.264) slightly to better match H.265 CRF range (e.g. default Medium 23 -> 28). - Set lossless mode via appropriate private param, and use 4:4:4 YUV format just like for some other video codecs when in lossless. - Currently there are no built-in presets for H.265. Maybe later, especially if/when we'll add 10 bit or HDR videos. Pull Request: https://projects.blender.org/blender/blender/pulls/129119
This commit is contained in:
committed by
Aras Pranckevicius
parent
15d79cf2b9
commit
b0052aa821
@@ -136,6 +136,10 @@ FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_QTRLE, AV_PIX_FMT_ARGB)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_VP9, AV_PIX_FMT_YUVA420P)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_PNG, AV_PIX_FMT_RGBA)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H264, AV_PIX_FMT_YUV420P)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H264, AV_PIX_FMT_YUV420P10LE)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H265, AV_PIX_FMT_YUV420P)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H265, AV_PIX_FMT_YUV420P10LE)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H265, AV_PIX_FMT_YUV420P12LE)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG4, AV_PIX_FMT_YUV420P)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_THEORA, AV_PIX_FMT_YUV420P)
|
||||
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_DVVIDEO, AV_PIX_FMT_YUV420P)
|
||||
|
||||
@@ -463,6 +463,7 @@ class RENDER_PT_encoding_video(RenderOutputButtonsPanel, Panel):
|
||||
# Output quality
|
||||
use_crf = needs_codec and ffmpeg.codec in {
|
||||
'H264',
|
||||
'H265',
|
||||
'MPEG4',
|
||||
'WEBM',
|
||||
'AV1',
|
||||
|
||||
@@ -866,6 +866,27 @@ void BKE_ffmpeg_sws_scale_frame(SwsContext *ctx, AVFrame *dst, const AVFrame *sr
|
||||
# endif
|
||||
}
|
||||
|
||||
/* Remap H.264 CRF to H.265 CRF: 17..32 range (23 default) to 20..37 range (28 default).
|
||||
* https://trac.ffmpeg.org/wiki/Encode/H.265 */
|
||||
static int remap_crf_to_h265_crf(int crf)
|
||||
{
|
||||
switch (crf) {
|
||||
case FFM_CRF_PERC_LOSSLESS:
|
||||
return 20;
|
||||
case FFM_CRF_HIGH:
|
||||
return 24;
|
||||
case FFM_CRF_MEDIUM:
|
||||
return 28;
|
||||
case FFM_CRF_LOW:
|
||||
return 31;
|
||||
case FFM_CRF_VERYLOW:
|
||||
return 34;
|
||||
case FFM_CRF_LOWEST:
|
||||
return 37;
|
||||
}
|
||||
return crf;
|
||||
}
|
||||
|
||||
static void set_quality_rate_options(const FFMpegContext *context,
|
||||
const AVCodecID codec_id,
|
||||
const RenderData *rd,
|
||||
@@ -895,6 +916,10 @@ static void set_quality_rate_options(const FFMpegContext *context,
|
||||
/* VP9 needs "lossless": https://trac.ffmpeg.org/wiki/Encode/VP9#LosslessVP9 */
|
||||
ffmpeg_dict_set_int(opts, "lossless", 1);
|
||||
}
|
||||
else if (codec_id == AV_CODEC_ID_H265) {
|
||||
/* H.265 needs "lossless" in private params; also make it much less verbose. */
|
||||
av_dict_set(opts, "x265-params", "log-level=1:lossless=1", 0);
|
||||
}
|
||||
else if (codec_id == AV_CODEC_ID_AV1 && (av1_librav1e || av1_libsvtav1)) {
|
||||
/* AV1 in some encoders needs qp=0 for lossless. */
|
||||
ffmpeg_dict_set_int(opts, "qp", 0);
|
||||
@@ -909,6 +934,12 @@ static void set_quality_rate_options(const FFMpegContext *context,
|
||||
/* Handle CRF setting cases. */
|
||||
int crf = context->ffmpeg_crf;
|
||||
|
||||
if (codec_id == AV_CODEC_ID_H265) {
|
||||
crf = remap_crf_to_h265_crf(crf);
|
||||
/* Make H.265 much less verbose. */
|
||||
av_dict_set(opts, "x265-params", "log-level=1", 0);
|
||||
}
|
||||
|
||||
if (av1_librav1e) {
|
||||
/* Remap crf 0..51 to qp 0..255 for AV1 librav1e. */
|
||||
int qp = int(float(crf) / 51.0f * 255.0f);
|
||||
@@ -1085,7 +1116,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
|
||||
if (codec_id == AV_CODEC_ID_VP9 && rd->im_format.planes == R_IMF_PLANES_RGBA) {
|
||||
c->pix_fmt = AV_PIX_FMT_YUVA420P;
|
||||
}
|
||||
else if (ELEM(codec_id, AV_CODEC_ID_H264, AV_CODEC_ID_VP9) && (context->ffmpeg_crf == 0)) {
|
||||
else if (ELEM(codec_id, AV_CODEC_ID_H264, AV_CODEC_ID_H265, AV_CODEC_ID_VP9) &&
|
||||
(context->ffmpeg_crf == 0))
|
||||
{
|
||||
/* Use 4:4:4 instead of 4:2:0 pixel format for lossless rendering. */
|
||||
c->pix_fmt = AV_PIX_FMT_YUV444P;
|
||||
}
|
||||
@@ -1995,7 +2028,12 @@ bool BKE_ffmpeg_alpha_channel_is_supported(const RenderData *rd)
|
||||
|
||||
bool BKE_ffmpeg_codec_supports_crf(int av_codec_id)
|
||||
{
|
||||
return ELEM(av_codec_id, AV_CODEC_ID_H264, AV_CODEC_ID_MPEG4, AV_CODEC_ID_VP9, AV_CODEC_ID_AV1);
|
||||
return ELEM(av_codec_id,
|
||||
AV_CODEC_ID_H264,
|
||||
AV_CODEC_ID_H265,
|
||||
AV_CODEC_ID_MPEG4,
|
||||
AV_CODEC_ID_VP9,
|
||||
AV_CODEC_ID_AV1);
|
||||
}
|
||||
|
||||
void *BKE_ffmpeg_context_create()
|
||||
|
||||
@@ -6420,6 +6420,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
|
||||
{AV_CODEC_ID_NONE, "NONE", 0, "No Video", "Disables video output, for audio-only renders"},
|
||||
{AV_CODEC_ID_AV1, "AV1", 0, "AV1", ""},
|
||||
{AV_CODEC_ID_H264, "H264", 0, "H.264", ""},
|
||||
{AV_CODEC_ID_H265, "H265", 0, "H.265 / HEVC", ""},
|
||||
{AV_CODEC_ID_VP9, "WEBM", 0, "WebM / VP9", ""},
|
||||
/* Legacy / rare codecs. */
|
||||
RNA_ENUM_ITEM_SEPR,
|
||||
|
||||
Reference in New Issue
Block a user