Fix T38658: H.264 with "Lossless Output" enabled gives lossy output

Issue was caused by the change in FFmpeg options: some of them were
renamed, some moved to another class.

Made some tweaks to how options are passed to the FFmpeg which now
seems to be the same as ffmpeg.c.
This commit is contained in:
Sergey Sharybin 2014-02-17 20:50:42 +06:00
parent ecd0565f28
commit 209a68af39
Notes: blender-bot 2023-02-14 11:11:01 +01:00
Referenced by issue #38658, H.264 with "Lossless Output" enabled gives lossy output
2 changed files with 57 additions and 55 deletions

View File

@ -80,7 +80,6 @@ void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData
void BKE_ffmpeg_codec_settings_verify(struct RenderData *rd);
bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd);
struct IDProperty *BKE_ffmpeg_property_add(struct RenderData *Rd, const char *type, int opt_index, int parent_index);
int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str);
void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_);

View File

@ -103,6 +103,9 @@ static AUD_Device *audio_mixdown_device = 0;
#define PRINT if (G.debug & G_DEBUG_FFMPEG) printf
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value);
/* Delete a picture buffer */
static void delete_picture(AVFrame *f)
@ -422,11 +425,10 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
return current_frame;
}
static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop)
static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary)
{
char name[128];
char *param;
int fail = TRUE;
PRINT("FFMPEG expert option: %s: ", prop->name);
@ -441,32 +443,28 @@ static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop)
switch (prop->type) {
case IDP_STRING:
PRINT("%s.\n", IDP_String(prop));
fail = av_opt_set(c, prop->name, IDP_String(prop), 0);
av_dict_set(dictionary, name, IDP_String(prop), 0);
break;
case IDP_FLOAT:
PRINT("%g.\n", IDP_Float(prop));
fail = av_opt_set_double(c, prop->name, IDP_Float(prop), 0);
ffmpeg_dict_set_float(dictionary, prop->name, IDP_Float(prop));
break;
case IDP_INT:
PRINT("%d.\n", IDP_Int(prop));
if (param) {
if (IDP_Int(prop)) {
fail = av_opt_set(c, name, param, 0);
av_dict_set(dictionary, name, param, 0);
}
else {
return;
}
}
else {
fail = av_opt_set_int(c, prop->name, IDP_Int(prop), 0);
ffmpeg_dict_set_int(dictionary, prop->name, IDP_Int(prop));
}
break;
}
if (fail) {
PRINT("ffmpeg-option not supported: %s! Skipping.\n", prop->name);
}
}
static int ffmpeg_proprty_valid(AVCodecContext *c, const char *prop_name, IDProperty *curr)
@ -483,7 +481,8 @@ static int ffmpeg_proprty_valid(AVCodecContext *c, const char *prop_name, IDProp
return valid;
}
static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char *prop_name)
static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char *prop_name,
AVDictionary **dictionary)
{
IDProperty *prop;
void *iter;
@ -502,7 +501,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
while ((curr = IDP_GroupIterNext(iter)) != NULL) {
if (ffmpeg_proprty_valid(c, prop_name, curr))
set_ffmpeg_property_option(c, curr);
set_ffmpeg_property_option(c, curr, dictionary);
}
}
@ -514,6 +513,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
AVStream *st;
AVCodecContext *c;
AVCodec *codec;
AVDictionary *opts = NULL;
error[0] = '\0';
@ -633,12 +633,14 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255);
set_ffmpeg_properties(rd, c, "video");
if (avcodec_open2(c, codec, NULL) < 0) {
set_ffmpeg_properties(rd, c, "video", &opts);
if (avcodec_open2(c, codec, &opts) < 0) {
BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
av_dict_free(&opts);
return NULL;
}
av_dict_free(&opts);
current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
@ -652,6 +654,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
AVStream *st;
AVCodecContext *c;
AVCodec *codec;
AVDictionary *opts = NULL;
error[0] = '\0';
@ -715,13 +718,15 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
set_ffmpeg_properties(rd, c, "audio");
set_ffmpeg_properties(rd, c, "audio", &opts);
if (avcodec_open2(c, codec, NULL) < 0) {
if (avcodec_open2(c, codec, &opts) < 0) {
//XXX error("Couldn't initialize audio codec");
BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
av_dict_free(&opts);
return NULL;
}
av_dict_free(&opts);
/* need to prevent floating point exception when using vorbis audio codec,
* initialize this value in the same way as it's done in FFmpeg iteslf (sergey) */
@ -772,6 +777,15 @@ static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value)
av_dict_set(dict, key, buffer, 0);
}
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value)
{
char buffer[32];
BLI_snprintf(buffer, sizeof(buffer), "%.8f", value);
av_dict_set(dict, key, buffer, 0);
}
static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports)
{
/* Handle to the output file */
@ -1246,11 +1260,9 @@ void BKE_ffmpeg_property_del(RenderData *rd, void *type, void *prop_)
}
}
IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, int opt_index, int parent_index)
static IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, const AVOption *o, const AVOption *parent)
{
AVCodecContext c;
const AVOption *o;
const AVOption *parent;
IDProperty *group;
IDProperty *prop;
IDPropertyTemplate val;
@ -1261,9 +1273,6 @@ IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, int opt_in
avcodec_get_context_defaults3(&c, NULL);
o = c.av_class->option + opt_index;
parent = c.av_class->option + parent_index;
if (!rd->ffcodecdata.properties) {
rd->ffcodecdata.properties = IDP_New(IDP_GROUP, &val, "ffmpeg");
}
@ -1275,14 +1284,14 @@ IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, int opt_in
IDP_AddToGroup(rd->ffcodecdata.properties, group);
}
if (parent_index) {
if (parent) {
BLI_snprintf(name, sizeof(name), "%s:%s", parent->name, o->name);
}
else {
BLI_strncpy(name, o->name, sizeof(name));
}
PRINT("ffmpeg_property_add: %s %d %d %s\n", type, parent_index, opt_index, name);
PRINT("ffmpeg_property_add: %s %s\n", type, name);
prop = IDP_GetPropertyFromGroup(group, name);
if (prop) {
@ -1320,22 +1329,6 @@ IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, int opt_in
/* not all versions of ffmpeg include that, so here we go ... */
static const AVOption *my_av_find_opt(void *v, const char *name, const char *unit, int mask, int flags)
{
AVClass *c = *(AVClass **)v;
const AVOption *o = c->option;
for (; o && o->name; o++) {
if (!strcmp(o->name, name) &&
(!unit || (o->unit && !strcmp(o->unit, unit))) &&
(o->flags & mask) == flags)
{
return o;
}
}
return NULL;
}
int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str)
{
AVCodecContext c;
@ -1363,21 +1356,25 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char
while (*param == ' ') param++;
}
o = my_av_find_opt(&c, name, NULL, 0, 0);
o = av_opt_find(&c, name, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
if (!o) {
PRINT("Ignoring unknown expert option %s\n", str);
return 0;
}
if (param && o->type == AV_OPT_TYPE_CONST) {
return 0;
}
if (param && o->type != AV_OPT_TYPE_CONST && o->unit) {
p = my_av_find_opt(&c, param, o->unit, 0, 0);
p = av_opt_find(&c, param, o->unit, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
if (p) {
prop = BKE_ffmpeg_property_add(rd, (char *) type, p - c.av_class->option, o - c.av_class->option);
prop = BKE_ffmpeg_property_add(rd, (char *) type, p, o);
}
else {
PRINT("Ignoring unknown expert option %s\n", str);
}
}
else {
prop = BKE_ffmpeg_property_add(rd, (char *) type, o - c.av_class->option, 0);
prop = BKE_ffmpeg_property_add(rd, (char *) type, o, NULL);
}
@ -1427,9 +1424,9 @@ static void ffmpeg_set_expert_options(RenderData *rd)
*/
// ffmpeg_property_add_string(rd, "video", "flags:loop"); // this breaks compatibility for QT
BKE_ffmpeg_property_add_string(rd, "video", "cmp:chroma");
BKE_ffmpeg_property_add_string(rd, "video", "partitions:parti4x4");
BKE_ffmpeg_property_add_string(rd, "video", "partitions:partp8x8");
BKE_ffmpeg_property_add_string(rd, "video", "partitions:partb8x8");
BKE_ffmpeg_property_add_string(rd, "video", "partitions:parti4x4"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "partitions:partp8x8"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "partitions:partb8x8"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "me:hex");
BKE_ffmpeg_property_add_string(rd, "video", "subq:6");
BKE_ffmpeg_property_add_string(rd, "video", "me_range:16");
@ -1441,15 +1438,21 @@ static void ffmpeg_set_expert_options(RenderData *rd)
BKE_ffmpeg_property_add_string(rd, "video", "bf:3");
BKE_ffmpeg_property_add_string(rd, "video", "refs:2");
BKE_ffmpeg_property_add_string(rd, "video", "qcomp:0.6");
BKE_ffmpeg_property_add_string(rd, "video", "directpred:3");
BKE_ffmpeg_property_add_string(rd, "video", "directpred:3"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "trellis:0");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:wpred");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:dct8x8");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:fastpskip");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:wpred"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "weightb:1");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:dct8x8"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "8x8dct:1");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:fastpskip"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
BKE_ffmpeg_property_add_string(rd, "video", "cqp:0");
if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT) {
BKE_ffmpeg_property_add_string(rd, "video", "cqp:0"); // Deprecated.
BKE_ffmpeg_property_add_string(rd, "video", "qp:0");
}
}
else if (codec_id == AV_CODEC_ID_DNXHD) {
if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)