Skip to content

Commit 84d732c

Browse files
committed
vcomp/lavc: handle codec_t not supported by FF
check codec= value not only if convertible to codec_t but also: 1. if it is representable by FFmpeg (supported+UG mapping exist) - this will eg. catch `-c lavc:c=UYVY` 2. check if there is an encoder for the codec, provided that 1. is fulfilled (this checks eg. `-c lavc:c=APV` when OpenAPV not encoded in) The state until now was that no error was issued and no compression was peformed (configure_with() repeatedly returned false), which is bad. + do not reconfigure on wrong message + use common `val` in parse_fmt
1 parent 89a3904 commit 84d732c

1 file changed

Lines changed: 59 additions & 23 deletions

File tree

src/video_compress/libavcodec.cpp

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,36 @@ ranged_stod(const char *val, double min, double max) noexcept(false)
513513
return dbl;
514514
}
515515

516+
/**
517+
* @returns codec_t representation of val and ensures that the codec
518+
* will be possible to compress (known+encoder present)
519+
* @retval VC_NONE if either of above was not fulfilled (error already print)
520+
*/
521+
static codec_t
522+
lavc_get_codec_check(const char *val)
523+
{
524+
codec_t ugc = get_codec_from_name(val);
525+
if (ugc == VC_NONE) {
526+
MSG(ERROR, "Unable to find codec: \"%s\"\n", val);
527+
return ugc;
528+
}
529+
enum AVCodecID avc = get_ug_to_av_codec(ugc);
530+
if (avc == AV_CODEC_ID_NONE) {
531+
MSG(ERROR,
532+
"No known mapping from %s to FFmpeg compression (either "
533+
"unsupporetd by FF or unimplemented by UG)!\n",
534+
get_codec_name(ugc));
535+
return VC_NONE;
536+
}
537+
const AVCodec *codec = avcodec_find_encoder(avc);
538+
if (codec != nullptr) {
539+
return ugc;
540+
}
541+
MSG(ERROR, "Codec %s supported by FFmpeg but no encoder found!\n",
542+
avcodec_get_name(avc));
543+
return VC_NONE;
544+
}
545+
516546
int
517547
parse_fmt(struct state_video_compress_libav *s, char *fmt) noexcept(false)
518548
{
@@ -531,21 +561,23 @@ parse_fmt(struct state_video_compress_libav *s, char *fmt) noexcept(false)
531561
char *item, *save_ptr = NULL;
532562

533563
while ((item = strtok_r(fmt, ":", &save_ptr)) != NULL) {
564+
char *val = strchr(item, '=');
565+
if (val != nullptr) {
566+
val += 1;
567+
}
534568
if (strcasecmp("help", item) == 0 || strcmp(item, "fullhelp") == 0) {
535569
show_help = strcmp(item, "fullhelp") == 0 ? HELP_FULL
536570
: HELP_NORMAL;
537571
} else if (IS_KEY_PREFIX(item, "codec")) {
538-
const char *const codec = strchr(item, '=') + 1;
539-
s->requested_codec_id = get_codec_from_name(codec);
572+
s->requested_codec_id = lavc_get_codec_check(val);
540573
if (s->requested_codec_id == VIDEO_CODEC_NONE) {
541-
log_msg(LOG_LEVEL_ERROR, "[lavc] Unable to find codec: \"%s\"\n", codec);
542574
return -1;
543575
}
544576
} else if (IS_KEY_PREFIX(item, "encoder")) {
545-
s->req_encoder = strchr(item, '=') + 1;
577+
s->req_encoder = val;
546578
} else if (IS_KEY_PREFIX(item, "bitrate")) {
547579
s->params.requested_bitrate =
548-
unit_evaluate(strchr(item, '=') + 1, nullptr);
580+
unit_evaluate(val, nullptr);
549581
if (s->params.requested_bitrate < 0) {
550582
return -1;
551583
}
@@ -564,10 +596,9 @@ parse_fmt(struct state_video_compress_libav *s, char *fmt) noexcept(false)
564596
if (strstr(item, "q=") == item) {
565597
log_msg(LOG_LEVEL_WARNING, MOD_NAME "Option \"q=\" is deprecated, use \"cqp=\" instead.\n");
566598
}
567-
s->params.requested_cqp = stoi(strchr(item, '=') + 1);
599+
s->params.requested_cqp = stoi(val);
568600
} else if (IS_KEY_PREFIX(item, "subsampling")) {
569-
s->req_conv_prop.subsampling =
570-
atoi(strchr(item, '=') + 1);
601+
s->req_conv_prop.subsampling = atoi(val);
571602
if (s->req_conv_prop.subsampling < 1000) {
572603
s->req_conv_prop.subsampling *= 10; // 420->4200
573604
}
@@ -578,23 +609,22 @@ parse_fmt(struct state_video_compress_libav *s, char *fmt) noexcept(false)
578609
return -1;
579610
}
580611
} else if (IS_KEY_PREFIX(item, "depth")) {
581-
s->req_conv_prop.depth = atoi(strchr(item, '=') + 1);
612+
s->req_conv_prop.depth = atoi(val);
582613
} else if (strcasecmp(item, "rgb") == 0 || strcasecmp(item, "yuv") == 0) {
583614
s->req_conv_prop.rgb = strcasecmp(item, "rgb") == 0;
584615
} else if (strstr(item, "intra_refresh") != nullptr) {
585616
s->params.periodic_intra = (int) (strstr(item, "intra_refresh") == item);
586617
} else if (strstr(item, "interlaced_dct") != nullptr) {
587618
s->params.interlaced_dct = (int) (strstr(item, "interlaced_dct") == item);
588619
} else if (IS_KEY_PREFIX(item, "threads")) {
589-
char *threads = strchr(item, '=') + 1;
620+
char *threads = val;
590621
if (strchr(threads, ',')) {
591622
s->conv_thread_count = stoi(strchr(threads, ',') + 1);
592623
*strchr(threads, ',') = '\0';
593624
}
594625
s->params.thread_mode = threads;
595626
} else if(strncasecmp("slices=", item, strlen("slices=")) == 0) {
596-
char *slices = strchr(item, '=') + 1;
597-
s->params.slices = stoi(slices);
627+
s->params.slices = stoi(val);
598628
} else if(strncasecmp("gop=", item, strlen("gop=")) == 0) {
599629
char *gop = item + strlen("gop=");
600630
s->requested_gop = atoi(gop);
@@ -1124,7 +1154,10 @@ const AVCodec *get_av_codec(struct state_video_compress_libav *s, codec_t *ug_co
11241154
return codec;
11251155
}
11261156
// Finally, try to open any encoder for requested codec
1127-
return avcodec_find_encoder(get_ug_to_av_codec(*ug_codec));
1157+
const AVCodec *codec =
1158+
avcodec_find_encoder(get_ug_to_av_codec(*ug_codec));
1159+
assert(codec != nullptr); // asserted by lavc_get_codec_check
1160+
return codec;
11281161
}
11291162

11301163
static bool configure_swscale(struct state_video_compress_libav *s, struct video_desc desc, enum AVPixelFormat sws_out_pixfmt) {
@@ -1218,7 +1251,6 @@ static bool configure_with(struct state_video_compress_libav *s, struct video_de
12181251
s->saved_desc = {};
12191252
codec_t ug_codec = s->requested_codec_id == VIDEO_CODEC_NONE ? DEFAULT_CODEC : s->requested_codec_id;
12201253
AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
1221-
const AVCodec *codec = nullptr;
12221254
#ifdef HAVE_SWSCALE
12231255
sws_freeContext(s->sws_ctx);
12241256
s->sws_ctx = nullptr;
@@ -1227,7 +1259,9 @@ static bool configure_with(struct state_video_compress_libav *s, struct video_de
12271259

12281260
s->params.desc = desc;
12291261

1230-
if ((codec = get_av_codec(s, &ug_codec, codec_is_a_rgb(desc.color_spec))) == nullptr) {
1262+
const AVCodec *codec =
1263+
get_av_codec(s, &ug_codec, codec_is_a_rgb(desc.color_spec));
1264+
if (codec == nullptr) {
12311265
return false;
12321266
}
12331267
log_msg(LOG_LEVEL_NOTICE, "[lavc] Using codec: %s, encoder: %s\n",
@@ -2438,16 +2472,18 @@ static void libavcodec_check_messages(struct state_video_compress_libav *s)
24382472
while ((msg = check_message(&s->module_data))) {
24392473
struct msg_change_compress_data *data =
24402474
(struct msg_change_compress_data *) msg;
2441-
struct response *r;
2442-
if (parse_fmt(s, data->config_string) == 0) {
2443-
log_msg(LOG_LEVEL_NOTICE, "[Libavcodec] Compression successfully changed.\n");
2444-
r = new_response(RESPONSE_OK, NULL);
2445-
} else {
2446-
log_msg(LOG_LEVEL_ERROR, "[Libavcodec] Unable to change compression!\n");
2447-
r = new_response(RESPONSE_INT_SERV_ERR, NULL);
2475+
if (parse_fmt(s, data->config_string) != 0) {
2476+
// NOTE: s->req_XY may not be now consistent with
2477+
// factual state, but we will not configure...
2478+
MSG(ERROR, "Unable to change compression!\n");
2479+
free_message(msg,
2480+
new_response(RESPONSE_INT_SERV_ERR,
2481+
"wrong compress setting!"));
2482+
continue;
24482483
}
2484+
MSG(NOTICE, "Compression successfully changed.\n");
24492485
memset(&s->saved_desc, 0, sizeof(s->saved_desc));
2450-
free_message(msg, r);
2486+
free_message(msg, new_response(RESPONSE_OK, nullptr));
24512487
}
24522488

24532489
}

0 commit comments

Comments
 (0)