Decoder: use vector for native codecs

This fixes a problem with incorrect handling native codec list - using
parameter "decoder-use-codec" only set native_count but there were
places where was expected a NULL-terminated list. (Example wrong
behavior may be observed with "-d dummy --param decoder-use-codes="
when the codec is not reflected).
This commit is contained in:
Martin Pulec
2020-07-09 12:01:15 +02:00
parent fe7cd6b64e
commit dce2ea595d

View File

@@ -347,8 +347,7 @@ struct state_video_decoder
struct display *display = NULL; ///< assigned display device
/// @{
codec_t native_codecs[VIDEO_CODEC_COUNT] = {}; ///< list of native codecs, must be NULL-terminated
size_t native_count = 0; ///< count of @ref native_codecs
vector<codec_t> native_codecs; ///< list of display native codecs
enum interlacing_t *disp_supported_il = NULL; ///< display supported interlacing mode
size_t disp_supported_il_cnt = 0; ///< count of @ref disp_supported_il
/// @}
@@ -569,17 +568,12 @@ static bool blacklist_current_out_codec(struct state_video_decoder *decoder){
if(decoder->out_codec == VIDEO_CODEC_NONE)
return false;
for(size_t i = 0; i < decoder->native_count; i++){
if(decoder->native_codecs[i] == decoder->out_codec){
log_msg(LOG_LEVEL_DEBUG, "Blacklisting codec %s\n", get_codec_name(decoder->out_codec));
memmove(decoder->native_codecs + i, decoder->native_codecs + i + 1,
(decoder->native_count - i - 1) * sizeof(codec_t));
decoder->native_count -= 1;
decoder->native_codecs[decoder->native_count] = VIDEO_CODEC_NONE;
decoder->out_codec = VIDEO_CODEC_NONE;
break;
}
auto to_erase = find(decoder->native_codecs.begin(), decoder->native_codecs.end(), decoder->out_codec);
if (to_erase == decoder->native_codecs.end()) {
return true; // should it really return true?
}
log_msg(LOG_LEVEL_DEBUG, "Blacklisting codec %s\n", get_codec_name(decoder->out_codec));
decoder->native_codecs.erase(to_erase);
return true;
}
@@ -824,14 +818,15 @@ static void video_decoder_stop_threads(struct state_video_decoder *decoder)
decoder->decompress_thread_id.join();
}
static auto codec_list_to_str(const codec_t *codecs) {
if (codecs == nullptr || codecs[0] == VIDEO_CODEC_NONE) {
static auto codec_list_to_str(vector<codec_t> const &codecs) {
if (codecs.empty()) {
return "(none)"s;
}
ostringstream oss;
oss << *codecs;
while (*++codecs != VIDEO_CODEC_NONE) {
oss << (codecs[1] == VIDEO_CODEC_NONE ? " and " : ", ") << get_codec_name(*codecs);
auto it = codecs.begin();
oss << *it++;
for ( ; it != codecs.end(); ++it) {
oss << (it + 1 == codecs.end() ? " and " : ", ") << get_codec_name(*it);
}
return oss.str();
}
@@ -861,37 +856,35 @@ bool video_decoder_register_display(struct state_video_decoder *decoder, struct
decoder->display = display;
size_t len = sizeof decoder->native_codecs;
ret = display_get_property(decoder->display, DISPLAY_PROPERTY_CODECS, decoder->native_codecs, &len);
decoder->native_count = len / sizeof(codec_t);
codec_t native_codecs[VIDEO_CODEC_COUNT];
size_t len = sizeof native_codecs;
ret = display_get_property(decoder->display, DISPLAY_PROPERTY_CODECS, native_codecs, &len);
decoder->native_codecs.clear();
if (!ret) {
log_msg(LOG_LEVEL_ERROR, "Failed to query codecs from video display.\n");
decoder->native_count = 0;
} else {
for (size_t i = 0; i < len / sizeof(codec_t); ++i) {
decoder->native_codecs.push_back(native_codecs[i]);
}
}
if (get_commandline_param("decoder-use-codec")) {
const char *codec_str = get_commandline_param("decoder-use-codec");
codec_t req_codec = get_codec_from_name(codec_str);
if ("help"s == codec_str) {
LOG(LOG_LEVEL_NOTICE) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(static_cast<codec_t *>(decoder->native_codecs)) << "\n";
LOG(LOG_LEVEL_NOTICE) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(decoder->native_codecs) << "\n";
return false;
}
if (req_codec == VIDEO_CODEC_NONE) {
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong decoder codec spec: %s.\n", codec_str);
LOG(LOG_LEVEL_INFO) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(static_cast<codec_t *>(decoder->native_codecs)) << "\n";
LOG(LOG_LEVEL_INFO) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(decoder->native_codecs) << "\n";
return false;
}
bool found = false;
for (size_t i = 0; i < decoder->native_count; ++i) {
if (decoder->native_codecs[i] == req_codec) {
decoder->native_codecs[0] = req_codec;
decoder->native_count = 1;
found = true;
break;
}
}
if (!found) {
if (find(decoder->native_codecs.begin(), decoder->native_codecs.end(), req_codec) != end(decoder->native_codecs)) {
decoder->native_codecs.clear();
decoder->native_codecs.push_back(req_codec);
} else {
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Display doesn't support requested codec: %s.\n", codec_str);
LOG(LOG_LEVEL_INFO) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(static_cast<codec_t *>(decoder->native_codecs)) << "\n";
LOG(LOG_LEVEL_INFO) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(decoder->native_codecs) << "\n";
return false;
}
}
@@ -992,40 +985,40 @@ void video_decoder_destroy(struct state_video_decoder *decoder)
* comp_int_fmt, generic should be catch-all allowing decompression of
* arbitrary compressed stream of received codec).
*/
static vector<pair<codec_t, codec_t>> video_decoder_order_output_codecs(codec_t comp_int_fmt, codec_t *display_codecs, int display_codecs_count)
static vector<pair<codec_t, codec_t>> video_decoder_order_output_codecs(codec_t comp_int_fmt, vector<codec_t> const &display_codecs)
{
vector<pair<codec_t, codec_t>> ret;
set<codec_t> used;
// first add hw-accelerated codecs
for (int i = 0; i < display_codecs_count; ++i) {
if (codec_is_hw_accelerated(display_codecs[i])) {
ret.push_back({comp_int_fmt, display_codecs[i]});
for (auto codec : display_codecs) {
if (codec_is_hw_accelerated(codec)) {
ret.push_back({comp_int_fmt, codec});
if (comp_int_fmt != VIDEO_CODEC_NONE) {
ret.push_back({VIDEO_CODEC_NONE, display_codecs[i]});
ret.push_back({VIDEO_CODEC_NONE, codec});
}
used.insert(display_codecs[i]);
used.insert(codec);
}
}
// then codecs matching exactly internal codec
for (int i = 0; i < display_codecs_count; ++i) {
if (used.find(display_codecs[i]) != used.end()) {
for (auto codec : display_codecs) {
if (used.find(codec) != used.end()) {
continue;
};
if (display_codecs[i] == comp_int_fmt) {
ret.push_back({comp_int_fmt, display_codecs[i]});
if (codec == comp_int_fmt) {
ret.push_back({comp_int_fmt, codec});
if (comp_int_fmt != VIDEO_CODEC_NONE) {
ret.push_back({VIDEO_CODEC_NONE, display_codecs[i]});
ret.push_back({VIDEO_CODEC_NONE, codec});
}
used.insert(display_codecs[i]);
used.insert(codec);
}
}
// then add also all other codecs
vector<codec_t> remaining;
for (int i = 0; i < display_codecs_count; ++i) {
if (used.find(display_codecs[i]) != used.end()) {
for (auto codec : display_codecs) {
if (used.find(codec) != used.end()) {
continue;
};
remaining.push_back(display_codecs[i]);
remaining.push_back(codec);
}
if (comp_int_fmt != VIDEO_CODEC_NONE) {
// sort - first codec of the same color space as internal (YUV
@@ -1077,8 +1070,7 @@ static codec_t choose_codec_and_decoder(struct state_video_decoder *decoder, str
codec_t out_codec = VIDEO_CODEC_NONE;
/* first check if the codec is natively supported */
for (size_t native = 0u; native < decoder->native_count; ++native) {
out_codec = decoder->native_codecs[native];
for (auto &out_codec : decoder->native_codecs) {
if(desc.color_spec == out_codec) {
if((out_codec == DXT1 || out_codec == DXT1_YUV ||
out_codec == DXT5)
@@ -1098,10 +1090,14 @@ static codec_t choose_codec_and_decoder(struct state_video_decoder *decoder, str
}
}
/* otherwise if we have line decoder (incl. slow codecs) */
*decode_line = get_best_decoder_from(desc.color_spec, decoder->native_codecs, &out_codec, true);
if (*decode_line) {
decoder->decoder_type = LINE_DECODER;
goto after_linedecoder_lookup;
{
vector<codec_t> native_codecs_copy = decoder->native_codecs;
native_codecs_copy.push_back(VIDEO_CODEC_NONE); // this needs to be NULL-terminated
*decode_line = get_best_decoder_from(desc.color_spec, native_codecs_copy.data(), &out_codec, true);
if (*decode_line) {
decoder->decoder_type = LINE_DECODER;
goto after_linedecoder_lookup;
}
}
after_linedecoder_lookup:
@@ -1123,8 +1119,7 @@ after_linedecoder_lookup:
}
vector<pair<codec_t, codec_t>> formats_to_try; // (comp_int_fmt || VIDEO_CODEC_NONE), display_fmt
formats_to_try = video_decoder_order_output_codecs(comp_int_fmt, decoder->native_codecs,
decoder->native_count);
formats_to_try = video_decoder_order_output_codecs(comp_int_fmt, decoder->native_codecs);
for (auto it = formats_to_try.begin(); it != formats_to_try.end(); ++it) {
out_codec = (*it).second;
@@ -1221,8 +1216,6 @@ static bool reconfigure_decoder(struct state_video_decoder *decoder,
decoder->frame = NULL;
video_decoder_start_threads(decoder);
assert(decoder->native_codecs != NULL);
cleanup(decoder);
desc.tile_count = get_video_mode_tiles_x(decoder->video_mode)