Decompress+lavd: fixes

This commit is contained in:
Martin Pulec
2019-04-18 15:45:09 +02:00
parent 380c321eb1
commit ba2b742ef5
4 changed files with 137 additions and 86 deletions

View File

@@ -105,6 +105,7 @@
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <sstream>
#include <thread>
@@ -114,6 +115,8 @@
#define MOD_NAME "[video dec.] "
#define FRAMEBUFFER_NOT_READY(decoder) (decoder->frame == NULL && decoder->out_codec != VIDEO_CODEC_END)
using namespace std;
struct state_video_decoder;
@@ -446,7 +449,7 @@ static void *fec_thread(void *args) {
goto cleanup;
}
if(!frame) {
if (FRAMEBUFFER_NOT_READY(decoder)) {
goto cleanup;
}
@@ -891,6 +894,61 @@ void video_decoder_destroy(struct state_video_decoder *decoder)
delete decoder;
}
static vector<pair<codec_t, codec_t>> order_output_codecs(codec_t comp_int_fmt, codec_t *display_codecs,
int display_codecs_count)
{
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]});
if (comp_int_fmt != VIDEO_CODEC_NONE) {
ret.push_back({VIDEO_CODEC_NONE, display_codecs[i]});
}
used.insert(display_codecs[i]);
}
}
// then codecs matching exactly internal codec
for (int i = 0; i < display_codecs_count; ++i) {
if (used.find(display_codecs[i]) != used.end()) {
continue;
};
if (display_codecs[i] == comp_int_fmt) {
ret.push_back({comp_int_fmt, display_codecs[i]});
if (comp_int_fmt != VIDEO_CODEC_NONE) {
ret.push_back({VIDEO_CODEC_NONE, display_codecs[i]});
}
used.insert(display_codecs[i]);
}
}
// then add also all other codecs
/// @todo
/// The rest should be ordered as well. Eg. when internal is
/// R12L, next should be perhaps R10k, RGBA, RGB and then YCbCr
/// codecs.
for (int i = 0; i < display_codecs_count; ++i) {
if (used.find(display_codecs[i]) != used.end()) {
continue;
};
ret.push_back({comp_int_fmt, display_codecs[i]});
if (comp_int_fmt != VIDEO_CODEC_NONE) {
ret.push_back({VIDEO_CODEC_NONE, display_codecs[i]});
}
used.insert(display_codecs[i]);
}
if (log_level >= LOG_LEVEL_VERBOSE) {
LOG(LOG_LEVEL_VERBOSE) << "Trying codecs:\n";
for (auto it = ret.begin(); it != ret.end(); ++it) {
LOG(LOG_LEVEL_VERBOSE) << "\t" << get_codec_name((*it).second) << ", internal: " << get_codec_name((*it).first) << "\n";
}
}
return ret;
}
/**
* This function selects, according to given video description, appropriate
*
@@ -906,10 +964,8 @@ static codec_t choose_codec_and_decoder(struct state_video_decoder *decoder, str
codec_t out_codec = VIDEO_CODEC_NONE;
*decode_line = NULL;
size_t native;
/* first check if the codec is natively supported */
for(native = 0u; native < decoder->native_count; ++native)
{
for (size_t native = 0u; native < decoder->native_count; ++native) {
out_codec = decoder->native_codecs[native];
if(desc.color_spec == out_codec) {
if((out_codec == DXT1 || out_codec == DXT1_YUV ||
@@ -917,7 +973,7 @@ static codec_t choose_codec_and_decoder(struct state_video_decoder *decoder, str
&& decoder->video_mode != VIDEO_NORMAL)
continue; /* it is a exception, see NOTES #1 */
*decode_line = (decoder_t) memcpy;
*decode_line = static_cast<decoder_t>([](unsigned char *dst, const unsigned char *src, int dst_len, int /* rshift */, int /* gshift */, int /* bshift */) { memcpy(dst, src, dst_len); });
decoder->decoder_type = LINE_DECODER;
if(desc.color_spec == RGBA || /* another exception - we may change shifts */
@@ -930,8 +986,7 @@ static codec_t choose_codec_and_decoder(struct state_video_decoder *decoder, str
}
}
/* otherwise if we have line decoder */
for(native = 0; native < decoder->native_count; ++native)
{
for (size_t native = 0; native < decoder->native_count; ++native) {
decoder_t decode;
if ((decode = get_decoder_from_to(desc.color_spec, decoder->native_codecs[native], false)) != NULL) {
*decode_line = decode;
@@ -943,8 +998,7 @@ static codec_t choose_codec_and_decoder(struct state_video_decoder *decoder, str
}
}
/* the same, but include also slow decoders */
for(native = 0; native < decoder->native_count; ++native)
{
for (size_t native = 0; native < decoder->native_count; ++native) {
decoder_t decode;
if ((decode = get_decoder_from_to(desc.color_spec, decoder->native_codecs[native], true)) != NULL) {
*decode_line = decode;
@@ -963,6 +1017,7 @@ after_linedecoder_lookup:
decoder->decompress_state = (struct state_decompress **)
calloc(decoder->max_substreams, sizeof(struct state_decompress *));
// try to probe video format
if (comp_int_fmt == VIDEO_CODEC_NONE) {
bool supports_autodetection = decompress_init_multi(desc.color_spec,
VIDEO_CODEC_NONE, VIDEO_CODEC_NONE, decoder->decompress_state,
@@ -973,26 +1028,26 @@ after_linedecoder_lookup:
}
}
codec_t try_internal_codec[2] = { comp_int_fmt, VIDEO_CODEC_NONE };
vector<pair<codec_t, codec_t>> formats_to_try; // (comp_int_fmt || VIDEO_CODEC_NONE), display_fmt
formats_to_try = order_output_codecs(comp_int_fmt, decoder->native_codecs,
decoder->native_count);
for (int i = 0; i < 2; i++) {
for (native = 0; native < decoder->native_count; ++native) {
out_codec = decoder->native_codecs[native];
if (decompress_init_multi(desc.color_spec, try_internal_codec[i],
decoder->native_codecs[native],
decoder->decompress_state,
decoder->max_substreams)) {
int res = 0, ret;
size_t size = sizeof(res);
ret = decompress_get_property(decoder->decompress_state[0],
DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME,
&res,
&size);
decoder->accepts_corrupted_frame = ret && res;
for (auto it = formats_to_try.begin(); it != formats_to_try.end(); ++it) {
out_codec = (*it).second;
if (decompress_init_multi(desc.color_spec, (*it).first,
(*it).second,
decoder->decompress_state,
decoder->max_substreams)) {
int res = 0, ret;
size_t size = sizeof(res);
ret = decompress_get_property(decoder->decompress_state[0],
DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME,
&res,
&size);
decoder->accepts_corrupted_frame = ret && res;
decoder->decoder_type = EXTERNAL_DECODER;
goto after_decoder_lookup;
}
decoder->decoder_type = EXTERNAL_DECODER;
goto after_decoder_lookup;
}
}
free(decoder->decompress_state);
@@ -1003,7 +1058,7 @@ after_decoder_lookup:
if(decoder->decoder_type == UNSET) {
log_msg(LOG_LEVEL_ERROR, "Unable to find decoder for input codec \"%s\"!!!\n", get_codec_name(desc.color_spec));
log_msg(LOG_LEVEL_INFO, "Compression internal codec is \"%s\". Native codecs are:", get_codec_name(comp_int_fmt));
for(native = 0; native < decoder->native_count; ++native) {
for (size_t native = 0; native < decoder->native_count; ++native) {
log_msg(LOG_LEVEL_INFO, " %s", get_codec_name(decoder->native_codecs[native]));
}
log_msg(LOG_LEVEL_INFO, "\n");
@@ -1132,22 +1187,22 @@ static bool reconfigure_decoder(struct state_video_decoder *decoder,
LOG(LOG_LEVEL_NOTICE) << MOD_NAME << "Sucessfully reconfigured display to "
<< display_desc << "\n";
decoder->display_desc = display_desc;
}
len = sizeof(display_requested_rgb_shift);
ret = display_get_property(decoder->display, DISPLAY_PROPERTY_RGB_SHIFT,
&display_requested_rgb_shift, &len);
if(!ret) {
debug_msg("Failed to get r,g,b shift property from video driver.\n");
int rgb_shift[3] = {0, 8, 16};
memcpy(&display_requested_rgb_shift, rgb_shift, sizeof(rgb_shift));
}
len = sizeof(display_requested_rgb_shift);
ret = display_get_property(decoder->display, DISPLAY_PROPERTY_RGB_SHIFT,
&display_requested_rgb_shift, &len);
if(!ret) {
debug_msg("Failed to get r,g,b shift property from video driver.\n");
int rgb_shift[3] = {0, 8, 16};
memcpy(&display_requested_rgb_shift, rgb_shift, sizeof(rgb_shift));
}
ret = display_get_property(decoder->display, DISPLAY_PROPERTY_BUF_PITCH,
&display_requested_pitch, &len);
if(!ret) {
debug_msg("Failed to get pitch from video driver.\n");
display_requested_pitch = PITCH_DEFAULT;
ret = display_get_property(decoder->display, DISPLAY_PROPERTY_BUF_PITCH,
&display_requested_pitch, &len);
if(!ret) {
debug_msg("Failed to get pitch from video driver.\n");
display_requested_pitch = PITCH_DEFAULT;
}
}
int linewidth;
@@ -1255,7 +1310,9 @@ static bool reconfigure_decoder(struct state_video_decoder *decoder,
send_message_to_receiver(decoder->mod.parent, (struct message *) msg);
free_response(resp);
decoder->frame = display_get_frame(decoder->display);
if (out_codec != VIDEO_CODEC_END) {
decoder->frame = display_get_frame(decoder->display);
}
return true;
}
@@ -1317,6 +1374,7 @@ static int reconfigure_if_needed(struct state_video_decoder *decoder,
if (!ret) {
log_msg(LOG_LEVEL_ERROR, "[video dec.] Reconfiguration failed!!!\n");
decoder->frame = NULL;
decoder->out_codec = VIDEO_CODEC_NONE;
}
#endif
return TRUE;
@@ -1341,8 +1399,6 @@ static int check_for_mode_change(struct state_video_decoder *decoder,
#define ERROR_GOTO_CLEANUP ret = FALSE; goto cleanup;
#define max(a, b) (((a) > (b))? (a): (b))
#define FRAMEBUFFER_READY(decoder) (decoder->frame == NULL && decoder->out_codec != VIDEO_CODEC_END)
/**
* @brief Decodes a participant buffer representing one video frame.
* @param cdata PBUF buffer
@@ -1547,7 +1603,7 @@ int decode_video_frame(struct coded_data *cdata, void *decoder_data, struct pbuf
// hereafter, display framebuffer can be used, so we
// check if we got it
if (FRAMEBUFFER_READY(decoder)) {
if (FRAMEBUFFER_NOT_READY(decoder)) {
vf_free(frame);
return FALSE;
}
@@ -1666,7 +1722,7 @@ next_packet:
return FALSE;
}
if (FRAMEBUFFER_READY(decoder) && (pt == PT_VIDEO || pt == PT_ENCRYPT_VIDEO)) {
if (FRAMEBUFFER_NOT_READY(decoder) && (pt == PT_VIDEO || pt == PT_ENCRYPT_VIDEO)) {
ret = FALSE;
goto cleanup;
}

View File

@@ -444,6 +444,10 @@ int codec_is_const_size(codec_t codec)
}
}
bool codec_is_hw_accelerated(codec_t codec) {
return codec == HW_VDPAU;
}
int get_halign(codec_t codec)
{
unsigned int i = (unsigned int) codec;

View File

@@ -91,6 +91,7 @@ int vc_get_linesize(unsigned int width, codec_t codec) ATTRIBUTE(pure);
int codec_is_a_rgb(codec_t codec) ATTRIBUTE(pure);
bool codec_is_in_set(codec_t codec, codec_t *set) ATTRIBUTE(pure);
int codec_is_const_size(codec_t codec) ATTRIBUTE(pure);
bool codec_is_hw_accelerated(codec_t codec) ATTRIBUTE(pure);
void vc_deinterlace(unsigned char *src, long src_linesize, int lines);
void vc_deinterlace_ex(unsigned char *src, size_t src_linesize, unsigned char *dst, size_t dst_pitch, size_t lines);

View File

@@ -34,12 +34,6 @@
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @todo
* remove not_implemented_conv - this should be handled differently now
* (through internal codecs)
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -1101,17 +1095,6 @@ static void yuv444p10le_to_rgb24(char *dst_buffer, AVFrame *in_frame,
free(tmp);
}
static void not_implemented_conv(char *dst_buffer, AVFrame *in_frame,
int width, int height, int pitch)
{
UNUSED(dst_buffer);
UNUSED(in_frame);
UNUSED(width);
UNUSED(height);
UNUSED(pitch);
log_msg(LOG_LEVEL_ERROR, "Selected conversion is not implemented!\n");
}
#ifdef HWACC_VDPAU
static void av_vdpau_to_ug_vdpau(char *dst_buffer, AVFrame *in_frame,
int width, int height, int pitch)
@@ -1174,12 +1157,10 @@ static const struct {
{AV_PIX_FMT_YUVJ444P, UYVY, yuv444p_to_yuv422, true},
{AV_PIX_FMT_YUVJ444P, RGB, yuv444p_to_rgb24, false},
// 8-bit YUV (NV12)
{AV_PIX_FMT_NV12, v210, not_implemented_conv, false},
{AV_PIX_FMT_NV12, UYVY, nv12_to_yuv422, true},
{AV_PIX_FMT_NV12, RGB, nv12_to_rgb24, false},
// RGB
{AV_PIX_FMT_GBRP, RGB, gbrp_to_rgb, true},
{AV_PIX_FMT_RGB24, v210, not_implemented_conv, false},
{AV_PIX_FMT_RGB24, UYVY, rgb24_to_uyvy, false},
{AV_PIX_FMT_RGB24, RGB, rgb24_to_rgb, true},
#ifdef HWACC_VDPAU
@@ -1493,45 +1474,54 @@ static void libavcodec_decompress_done(void *state)
free(s);
}
static const codec_t supp_codecs[] = { H264, H265, JPEG, MJPG, J2K, VP8, VP9,
HFYU, FFV1, AV1 };
static const struct decode_from_to dec_template[] = {
{ VIDEO_CODEC_NONE, VIDEO_CODEC_NONE, VIDEO_CODEC_NONE, 500 }, // for probe
{ VIDEO_CODEC_NONE, RGB, RGB, 500 },
//{ VIDEO_CODEC_NONE, UYVY, RGB, 500 }, // there are conversions but don't enable now
{ VIDEO_CODEC_NONE, UYVY, UYVY, 500 },
{ VIDEO_CODEC_NONE, v210, v210, 500 },
{ VIDEO_CODEC_NONE, v210, UYVY, 500 },
{ VIDEO_CODEC_NONE, VIDEO_CODEC_NONE, RGB, 900 }, // provide also generic decoders
{ VIDEO_CODEC_NONE, VIDEO_CODEC_NONE, UYVY, 900 } // ditto
};
#define SUPP_CODECS_CNT (sizeof supp_codecs / sizeof supp_codecs[0])
#define DEC_TEMPLATE_CNT (sizeof dec_template / sizeof dec_template[0])
ADD_TO_PARAM(lavd_use_10bit, "lavd-use-10bit",
"* lavd-use-10bit\n"
" Indicates that we are using decoding to v210 (currently only H.264/HEVC).\n"
" If so, it can be decompressed to v210. With this flag, v210 (10-bit YUV)\n"
" will be announced as a supported codec.\n");
static const struct decode_from_to *libavcodec_decompress_get_decoders() {
const struct decode_from_to dec_static[] = {
{ H264, VIDEO_CODEC_NONE, UYVY, 500 },
{ H265, VIDEO_CODEC_NONE, UYVY, 500 },
{ JPEG, VIDEO_CODEC_NONE, UYVY, 600 },
{ MJPG, VIDEO_CODEC_NONE, UYVY, 500 },
{ J2K, VIDEO_CODEC_NONE, RGB, 500 },
{ VP8, VIDEO_CODEC_NONE, UYVY, 500 },
{ VP9, VIDEO_CODEC_NONE, UYVY, 500 },
{ HFYU, VIDEO_CODEC_NONE, UYVY, 500 },
{ FFV1, VIDEO_CODEC_NONE, UYVY, 500 },
{ AV1, VIDEO_CODEC_NONE, UYVY, 500 },
{ H264, VIDEO_CODEC_NONE, VIDEO_CODEC_NONE, 500 },
{ H264, RGB, RGB, 500 },
};
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static struct decode_from_to ret[sizeof dec_static / sizeof dec_static[0] + 1 /* terminating zero */ + 10 /* place for additional decoders, see below */];
static struct decode_from_to ret[SUPP_CODECS_CNT * DEC_TEMPLATE_CNT + 1 /* terminating zero */ + 10 /* place for additional decoders, see below */];
pthread_mutex_lock(&lock); // prevent concurent initialization
if (ret[0].from == VIDEO_CODEC_NONE) { // not yet initialized
memcpy(ret, dec_static, sizeof dec_static);
int ret_idx = 0;
for (size_t t = 0; t < DEC_TEMPLATE_CNT; ++t) {
for (size_t c = 0; c < SUPP_CODECS_CNT; ++c) {
ret[ret_idx++] = (struct decode_from_to){supp_codecs[c],
dec_template[t].internal, dec_template[t].to,
dec_template[t].priority};
}
}
// add also decoder from H.264/HEVC to v210 if user explicitly indicated to do so
if (get_commandline_param("lavd-use-10bit")) {
ret[sizeof dec_static / sizeof dec_static[0]] =
ret[ret_idx++] =
(struct decode_from_to) {H264, VIDEO_CODEC_NONE, v210, 400};
ret[sizeof dec_static / sizeof dec_static[0] + 1] =
ret[ret_idx++] =
(struct decode_from_to) {H265, VIDEO_CODEC_NONE, v210, 400};
}
if (get_commandline_param("use-hw-accel")) {
ret[sizeof dec_static / sizeof dec_static[0]] =
ret[ret_idx++] =
(struct decode_from_to) {H264, VIDEO_CODEC_NONE, HW_VDPAU, 200};
}
assert(ret_idx < sizeof ret / sizeof ret[0]); // there needs to be at least one zero row
}
pthread_mutex_unlock(&lock); // prevent concurent initialization