UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
video_decoders.cpp File Reference
#include "rtp/video_decoders.h"
#include <cassert>
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <iterator>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <sstream>
#include <string>
#include <thread>
#include <unordered_map>
#include <utility>
#include <vector>
#include "compat/htonl.h"
#include "crypto/openssl_decrypt.h"
#include "crypto/openssl_encrypt.h"
#include "debug.h"
#include "host.h"
#include "lib_common.h"
#include "messaging.h"
#include "module.h"
#include "pixfmt_conv.h"
#include "rtp/fec.h"
#include "rtp/pbuf.h"
#include "rtp/rtp.h"
#include "rtp/rtp_types.h"
#include "tv.h"
#include "utils/color_out.h"
#include "utils/macros.h"
#include "utils/misc.h"
#include "utils/synchronized_queue.h"
#include "utils/thread.h"
#include "utils/timed_message.h"
#include "utils/worker.h"
#include "video.h"
#include "video_decompress.h"
#include "video_display.h"
Include dependency graph for video_decoders.cpp:

Go to the source code of this file.

Classes

struct  decompress_data
 
struct  state_video_decoder
 Decoder state. More...
 

Macros

#define ENCRYPTED_ERR
 
#define ERROR_GOTO_CLEANUP   ret = false; goto cleanup;
 
#define FRAMEBUFFER_NOT_READY(decoder)
 
#define max(a, b)
 
#define MOD_NAME   "[video dec.] "
 
#define NOT_ENCRYPTED_ERR
 

Typedefs

typedef void(* change_il_t) (char *dst, char *src, int linesize, int height, void **state)
 

Functions

 ADD_TO_PARAM ("decoder-drop-policy", "* decoder-drop-policy=blocking|nonblock|<sec>\n" " Force specified blocking policy (default nonblock).\n" " <sec> - specifies frame timeout in seconds (can have suffixes, eg. \"20ms\")\n")
 
 ADD_TO_PARAM ("decoder-use-codec", "* decoder-use-codec=<codec>\n" " Use specified pixel format for decoding (eg. v210). This overrides automatic\n" " choice. The pixel format must be supported by the video display. Use 'help' to see\n" " available options for a display (eg.: 'uv -d gl --param decoder-use-codec=help').\n" "* decoder-use-codec=!<codec>\n" " Blacklist specified pixel format ('!<codec' may need to be quoted).\n")
 
static bool blacklist_current_out_codec (struct state_video_decoder *decoder)
 
static void check_for_mode_change (struct state_video_decoder *decoder, const uint32_t *hdr)
 
static codec_t choose_codec_and_decoder (struct state_video_decoder *decoder, struct video_desc desc, decoder_t *decode_line, struct pixfmt_desc comp_int_prop)
 
static void cleanup (struct state_video_decoder *decoder)
 
static auto codec_list_to_str (vector< codec_t > const &codecs)
 
int decode_video_frame (struct coded_data *cdata, void *decoder_data, struct pbuf_stats *stats)
 Decodes a participant buffer representing one video frame.
 
static void decoder_process_message (struct module *)
 
static void decoder_set_video_mode (struct state_video_decoder *decoder, enum video_mode video_mode)
 
static void * decompress_thread (void *args)
 
static void * decompress_worker (void *data)
 
static void * fec_thread (void *args)
 
bool parse_video_hdr (const uint32_t *hdr, struct video_desc *desc)
 
static bool reconfigure_decoder (struct state_video_decoder *decoder, struct video_desc desc, struct pixfmt_desc comp_int_desc)
 
static void reconfigure_helper (struct state_video_decoder *decoder, struct video_desc network_desc, struct pixfmt_desc comp_int_desc)
 
static void reconfigure_if_needed (struct state_video_decoder *decoder, struct video_desc network_desc, struct pixfmt_desc comp_int_desc)
 
static change_il_t select_il_func (enum interlacing_t in_il, enum interlacing_t *supported, int il_out_cnt, enum interlacing_t *out_il)
 
static int sum_map (map< int, int > const &m)
 
void video_decoder_destroy (struct state_video_decoder *decoder)
 Destroys decoder created with decoder_init()
 
struct state_video_decoder * video_decoder_init (struct module *parent, enum video_mode video_mode, struct display *display, const char *encryption)
 Initializes video decompress state.
 
static vector< pair< struct pixfmt_desc, codec_t > > video_decoder_order_output_codecs (struct pixfmt_desc comp_int_prop, vector< codec_t > const &display_codecs)
 
bool video_decoder_register_display (struct state_video_decoder *decoder, struct display *display)
 Registers video display to be used for displaying decoded video frames.
 
void video_decoder_remove_display (struct state_video_decoder *decoder)
 This removes display from current decoder.
 
static void video_decoder_start_threads (struct state_video_decoder *decoder)
 starts decompress and ldmg threads
 
static void video_decoder_stop_threads (struct state_video_decoder *decoder)
 This function stops running threads.
 
static void wait_for_framebuffer_swap (struct state_video_decoder *decoder)
 

Variables

constexpr int PADDING = MAX_PADDING
 

Detailed Description

Author
Colin Perkins
Ladan Gharai
Martin Pulec pulec.nosp@m.@ces.nosp@m.net.c.nosp@m.z

Workflow

Normal workflow through threads is following:

  1. decode data from in context of receiving thread with function decode_frame(), it will decode it to framebuffer, passes it to FEC thread
  2. fec_thread() passes frame to decompress thread
  3. thread running decompress_thread(), displays the frame

Uncompressed video (without FEC)

In step one, the decoder is a linedecoder and framebuffer is the display framebuffer

Compressed video

Data is saved to decompress buffer. The decompression itself is done by decompress_thread().

video with FEC

Data is saved to FEC buffer. Decoded with fec_thread().

Encrypted video (without FEC)

Prior to decoding, packet is decompressed.

Encrypted video (with FEC)

After FEC decoding, the whole block is decompressed.

Probing compressed video codecs

When video is received, it is probed for an internal format:

  • compression is reconfigured to (VIDEO_CODEC_NONE, VIDEO_CODEC_NONE) - internal and out codecs are set to 0
  • if any decoder for the codec supports probing, s->out_codec is set to VIDEO_CODEC_END (otherwise a decompression is directly configured)
  • decompression is done as usual (display is not reconfigured and output is put to a dummy framebuffer)
  • when decoder is able to establish the codec, it returns DECODER_GOT_CODEC, thread send a reconf message to the main threads and the reconfiguration shall begin - display codecs are reordered ideally to match the incoming stream
  • BUGS: usually multiple reconf messages are sent, decompress priority is evaluated only when there are multiple same (in_codec,internal_codec,out_codec) tuples.

    Todo
    This code is very very messy, it needs to be rewritten.
Note
The properties of DXTn do not exactly match - bpp is 0.5, but line (actually 4 lines) is (2 * width) long, so it makes troubles when using line decoder and tiles. So the fallback is external decoder. The DXT compression is exceptional in that, that it can be both internally and externally decompressed.

Definition in file video_decoders.cpp.

Macro Definition Documentation

◆ ENCRYPTED_ERR

#define ENCRYPTED_ERR
Value:
"Receiving encrypted video data but " \
"no decryption key entered!\n"

Definition at line 411 of file video_decoders.cpp.

411#define ENCRYPTED_ERR "Receiving encrypted video data but " \
412 "no decryption key entered!\n"

Referenced by decode_video_frame().

◆ ERROR_GOTO_CLEANUP

#define ERROR_GOTO_CLEANUP   ret = false; goto cleanup;

Definition at line 1490 of file video_decoders.cpp.

Referenced by decode_video_frame().

◆ FRAMEBUFFER_NOT_READY

#define FRAMEBUFFER_NOT_READY ( decoder)
Value:
(decoder->frame == NULL && decoder->out_codec != VIDEO_CODEC_END)
@ VIDEO_CODEC_END
Definition types.h:111

Definition at line 151 of file video_decoders.cpp.

Referenced by decode_video_frame(), and fec_thread().

◆ max

#define max ( a,
b )
Value:
(((a) > (b))? (a): (b))

Definition at line 1491 of file video_decoders.cpp.

Referenced by decode_video_frame().

◆ MOD_NAME

#define MOD_NAME   "[video dec.] "

◆ NOT_ENCRYPTED_ERR

#define NOT_ENCRYPTED_ERR
Value:
"Receiving unencrypted video data " \
"while expecting encrypted.\n"

Definition at line 413 of file video_decoders.cpp.

413#define NOT_ENCRYPTED_ERR "Receiving unencrypted video data " \
414 "while expecting encrypted.\n"

Referenced by decode_video_frame().

Typedef Documentation

◆ change_il_t

typedef void(* change_il_t) (char *dst, char *src, int linesize, int height, void **state)

Interlacing changing function protoype. The function should be able to change buffer in place, that is when dst and src are the same.

Definition at line 179 of file video_decoders.cpp.

Function Documentation

◆ ADD_TO_PARAM() [1/2]

ADD_TO_PARAM ( "decoder-drop-policy" )

◆ ADD_TO_PARAM() [2/2]

ADD_TO_PARAM ( "decoder-use-codec" )

◆ blacklist_current_out_codec()

static bool blacklist_current_out_codec ( struct state_video_decoder * decoder)
static

Definition at line 570 of file video_decoders.cpp.

570 {
571 if(decoder->out_codec == VIDEO_CODEC_NONE)
572 return false;
573
574 auto to_erase = find(decoder->native_codecs.begin(), decoder->native_codecs.end(), decoder->out_codec);
575 if (to_erase == decoder->native_codecs.end()) {
576 return true; // should it really return true?
577 }
578 log_msg(LOG_LEVEL_DEBUG, "Blacklisting codec %s\n", get_codec_name(decoder->out_codec));
579 decoder->native_codecs.erase(to_erase);
580
581 return true;
582}
const char * get_codec_name(codec_t codec)
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
vector< codec_t > native_codecs
list of display native codecs
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66

References get_codec_name(), LOG_LEVEL_DEBUG, log_msg(), state_video_decoder::native_codecs, state_video_decoder::out_codec, and VIDEO_CODEC_NONE.

Referenced by decompress_thread().

Here is the call graph for this function:

◆ check_for_mode_change()

static void check_for_mode_change ( struct state_video_decoder * decoder,
const uint32_t * hdr )
static

Checks if network format has changed.

Parameters
decoderdecoder state
hdrraw RTP payload header

Definition at line 1474 of file video_decoders.cpp.

1476{
1477 struct video_desc network_desc;
1478
1479 parse_video_hdr(hdr, &network_desc);
1480 if (video_desc_eq_excl_param(decoder->received_vid_desc, network_desc,
1482 return;
1483 }
1485 << "[video dec.] New incoming video format detected: "
1486 << network_desc << "\n";
1487 reconfigure_helper(decoder, network_desc, {});
1488}
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG(level)
Definition debug.h:313
bool parse_video_hdr(const uint32_t *hdr, struct video_desc *desc)
struct video_desc received_vid_desc
description of the network video
static void reconfigure_helper(struct state_video_decoder *decoder, struct video_desc network_desc, struct pixfmt_desc comp_int_desc)
bool video_desc_eq_excl_param(struct video_desc a, struct video_desc b, unsigned int excluded_params)
Compares two video descriptions.
#define PARAM_TILE_COUNT
Definition video_frame.h:68

References LOG, LOG_LEVEL_NOTICE, PARAM_TILE_COUNT, parse_video_hdr(), state_video_decoder::received_vid_desc, reconfigure_helper(), and video_desc_eq_excl_param().

Referenced by decode_video_frame().

Here is the call graph for this function:

◆ choose_codec_and_decoder()

static codec_t choose_codec_and_decoder ( struct state_video_decoder * decoder,
struct video_desc desc,
decoder_t * decode_line,
struct pixfmt_desc comp_int_prop )
static

This function selects, according to given video description, appropriate

Parameters
[in]decoderdecoder to be taken parameters from (video mode, native codecs etc.)
[in]descincoming video description
[out]decode_lineIf chosen decoder is a linedecoder, this variable contains the decoding function.
Returns
Output codec, if no decoding function found, -1 is returned.

DXT1 it is a exception, see vdec_note1

Definition at line 1073 of file video_decoders.cpp.

1075{
1076 codec_t out_codec = VIDEO_CODEC_NONE;
1077
1078 /* first check if the codec is natively supported */
1079 for (auto &codec : decoder->native_codecs) {
1080 if (desc.color_spec == codec) {
1081 if ((desc.color_spec == DXT1 || desc.color_spec == DXT1_YUV ||
1082 desc.color_spec == DXT5)
1083 && decoder->video_mode != VIDEO_NORMAL)
1084 continue;
1085
1086 *decode_line = vc_memcpy;
1087 decoder->decoder_type = LINE_DECODER;
1088
1089 if(desc.color_spec == RGBA || /* another exception - we may change shifts */
1090 desc.color_spec == RGB) { // should RGB be also handled
1092 }
1093
1094 out_codec = codec;
1095 goto after_linedecoder_lookup;
1096 }
1097 }
1098 /* otherwise if we have line decoder (incl. slow codecs) */
1099 {
1100 vector<codec_t> native_codecs_copy = decoder->native_codecs;
1101 native_codecs_copy.push_back(VIDEO_CODEC_NONE); // this needs to be NULL-terminated
1102 *decode_line = get_best_decoder_from(desc.color_spec, native_codecs_copy.data(), &out_codec);
1103 if (*decode_line) {
1104 decoder->decoder_type = LINE_DECODER;
1105 goto after_linedecoder_lookup;
1106 }
1107 }
1108
1109after_linedecoder_lookup:
1110
1111 /* we didn't find line decoder. So try now regular (aka DXT) decoder */
1112 if(*decode_line == NULL) {
1113 decoder->decompress_state.resize(decoder->max_substreams);
1114
1115 // try to probe video format
1116 if (comp_int_prop.depth == 0 && decoder->out_codec != VIDEO_CODEC_END) {
1117 bool supports_autodetection = decompress_init_multi(desc.color_spec,
1118 pixfmt_desc{}, VIDEO_CODEC_NONE, decoder->decompress_state.data(),
1119 decoder->decompress_state.size());
1120 if (supports_autodetection) {
1121 decoder->decoder_type = EXTERNAL_DECODER;
1122 return VIDEO_CODEC_END;
1123 }
1124 }
1125
1126 vector<pair<struct pixfmt_desc, codec_t>> formats_to_try; // comp_int_prop (may be empty), display_fmt
1127 formats_to_try = video_decoder_order_output_codecs(comp_int_prop, decoder->native_codecs);
1128
1129 for (auto it = formats_to_try.begin(); it != formats_to_try.end(); ++it) {
1130 out_codec = (*it).second;
1131 if (decompress_init_multi(desc.color_spec, (*it).first,
1132 (*it).second,
1133 decoder->decompress_state.data(),
1134 decoder->decompress_state.size())) {
1135 decoder->decoder_type = EXTERNAL_DECODER;
1136 goto after_decoder_lookup;
1137 }
1138 }
1139 decoder->decompress_state.clear();
1140 }
1141after_decoder_lookup:
1142
1143 if(decoder->decoder_type == UNSET) {
1144 log_msg(LOG_LEVEL_ERROR, "Unable to find decoder for input codec \"%s\"!!!\n", get_codec_name(desc.color_spec));
1145 LOG(LOG_LEVEL_INFO) << "Compression internal codec is \"" << get_pixdesc_desc(comp_int_prop) << "\". Native codecs are: " << codec_list_to_str(decoder->native_codecs) << "\n";
1146 return VIDEO_CODEC_NONE;
1147 }
1148
1149 return out_codec;
1150}
struct video_desc desc
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
bool decompress_init_multi(codec_t compression, struct pixfmt_desc internal_prop, codec_t out_codec, struct state_decompress **out, int count)
Initializes (multiple) decompress states.
decoder_t get_decoder_from_to(codec_t in, codec_t out)
decoder_t get_best_decoder_from(codec_t in, const codec_t *out_candidates, codec_t *out)
decoder_func_t vc_memcpy
dummy conversion - ptr to it returned if no conversion needed
int depth
bit depth; 0 means that whole struct is undefined
Definition types.h:140
enum decoder_type_t decoder_type
how will the video data be decoded
unsigned int max_substreams
maximal number of expected substreams
vector< struct state_decompress * > decompress_state
state of the decompress (for every substream)
enum video_mode video_mode
video mode set for this decoder
codec_t color_spec
Definition types.h:182
@ VIDEO_NORMAL
normal video (one tile)
Definition types.h:356
codec_t
Definition types.h:65
@ DXT1
S3 Texture Compression DXT1.
Definition types.h:77
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ DXT5
S3 Texture Compression DXT5.
Definition types.h:79
@ DXT1_YUV
Structure same as DXT1, instead of RGB, YCbCr values are stored.
Definition types.h:78
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
const char * get_pixdesc_desc(struct pixfmt_desc desc)
static auto codec_list_to_str(vector< codec_t > const &codecs)
static vector< pair< struct pixfmt_desc, codec_t > > video_decoder_order_output_codecs(struct pixfmt_desc comp_int_prop, vector< codec_t > const &display_codecs)

References codec_list_to_str(), video_desc::color_spec, state_video_decoder::decoder_type, decompress_init_multi(), state_video_decoder::decompress_state, pixfmt_desc::depth, desc, DXT1, DXT1_YUV, DXT5, get_best_decoder_from(), get_codec_name(), get_decoder_from_to(), get_pixdesc_desc(), LOG, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, log_msg(), state_video_decoder::max_substreams, state_video_decoder::native_codecs, state_video_decoder::out_codec, RGB, RGBA, vc_memcpy, VIDEO_CODEC_END, VIDEO_CODEC_NONE, video_decoder_order_output_codecs(), state_video_decoder::video_mode, and VIDEO_NORMAL.

Referenced by reconfigure_decoder().

Here is the call graph for this function:

◆ cleanup()

static void cleanup ( struct state_video_decoder * decoder)
static

Definition at line 954 of file video_decoders.cpp.

955{
956 decoder->decoder_type = UNSET;
957 for (auto &d : decoder->decompress_state) {
959 }
960 decoder->decompress_state.clear();
961 if(decoder->line_decoder) {
962 free(decoder->line_decoder);
963 decoder->line_decoder = NULL;
964 }
965
966 for (auto && item : decoder->change_il_state) {
967 free(item);
968 }
969 decoder->change_il_state.resize(0);
970}
void decompress_done(struct state_decompress *s)
Definition hd-rum.c:27
struct line_decoder * line_decoder
is neeeded, use this structure
vector< void * > change_il_state

References state_video_decoder::change_il_state, state_video_decoder::decoder_type, decompress_done(), state_video_decoder::decompress_state, and state_video_decoder::line_decoder.

Here is the call graph for this function:

◆ codec_list_to_str()

static auto codec_list_to_str ( vector< codec_t > const & codecs)
static

Definition at line 828 of file video_decoders.cpp.

828 {
829 if (codecs.empty()) {
830 return "(none)"s;
831 }
832 ostringstream oss;
833 auto it = codecs.begin();
834 oss << *it++;
835 for ( ; it != codecs.end(); ++it) {
836 oss << (it + 1 == codecs.end() ? " and " : ", ") << get_codec_name(*it);
837 }
838 return oss.str();
839}
static struct @76 codecs[]

References codecs, and get_codec_name().

Referenced by choose_codec_and_decoder(), reconfigure_decoder(), and video_decoder_register_display().

Here is the call graph for this function:

◆ decoder_process_message()

static void decoder_process_message ( struct module * m)
static

Definition at line 1852 of file video_decoders.cpp.

1853{
1854 struct state_video_decoder *s = (struct state_video_decoder *) m->priv_data;
1855
1856 struct message *msg;
1857 while ((msg = check_message(m))) {
1858 struct response *r;
1859 struct msg_universal *m_univ = (struct msg_universal *) msg;
1860 if (strcmp(m_univ->text, "get_format") == 0) {
1861 s->lock.lock();
1862 string video_desc = s->received_vid_desc;
1863 s->lock.unlock();
1864 r = new_response(RESPONSE_OK, video_desc.c_str());
1865 } else {
1867 }
1868 free_message(msg, r);
1869
1870 }
1871}
void free_message(struct message *msg, struct response *r)
struct response * new_response(int status, const char *text)
struct message * check_message(struct module *mod)
#define RESPONSE_OK
Definition messaging.h:57
#define RESPONSE_NOT_FOUND
Definition messaging.h:61
struct msghdr msg
void * priv_data
Definition module.h:126
char text[8192]
Definition messaging.h:157

References check_message(), free_message(), state_video_decoder::lock, msg, new_response(), module::priv_data, state_video_decoder::received_vid_desc, RESPONSE_NOT_FOUND, RESPONSE_OK, and msg_universal::text.

Referenced by state_video_decoder::state_video_decoder().

Here is the call graph for this function:

◆ decoder_set_video_mode()

static void decoder_set_video_mode ( struct state_video_decoder * decoder,
enum video_mode video_mode )
static

Definition at line 743 of file video_decoders.cpp.

744{
745 decoder->video_mode = video_mode;
748}
video_mode
Definition types.h:354
int get_video_mode_tiles_x(enum video_mode video_mode)
Definition video.cpp:108
int get_video_mode_tiles_y(enum video_mode video_mode)
Definition video.cpp:113

References get_video_mode_tiles_x(), get_video_mode_tiles_y(), state_video_decoder::max_substreams, and state_video_decoder::video_mode.

Referenced by decode_video_frame(), and video_decoder_init().

Here is the call graph for this function:

◆ decompress_thread()

static void * decompress_thread ( void * args)
static

Definition at line 614 of file video_decoders.cpp.

614 {
615 set_thread_name(__func__);
616 struct state_video_decoder *decoder =
617 (struct state_video_decoder *) args;
618 int tile_width = decoder->received_vid_desc.width; // get_video_mode_tiles_x(decoder->video_mode);
619 int tile_height = decoder->received_vid_desc.height; // get_video_mode_tiles_y(decoder->video_mode);
620
621 long long force_putf_timeout = []() {
622 auto drop_policy = commandline_params.find("decoder-drop-policy"s);
623 if (drop_policy == commandline_params.end()) {
624 return -1LL;
625 }
626 if (drop_policy->second == "nonblock") {
627 return PUTF_NONBLOCK;
628 }
629 if (drop_policy->second == "blocking") {
630 return PUTF_BLOCKING;
631 }
632 return static_cast<long long>(
633 unit_evaluate_dbl(drop_policy->second.c_str(), true,
634 nullptr) *
635 NS_IN_SEC);
636 }();
637
638 while(1) {
639 unique_ptr<frame_msg> msg = decoder->decompress_queue.pop();
640
641 if(!msg->recv_frame) { // poisoned
642 break;
643 }
644
645 auto t0 = std::chrono::high_resolution_clock::now();
646 unique_ptr<char[]> tmp;
647
648 if (decoder->out_codec == VIDEO_CODEC_END) {
649 tmp = unique_ptr<char[]>(new char[tile_height * (tile_width * MAX_BPS + PADDING)]);
650 }
651
652 if(decoder->decoder_type == EXTERNAL_DECODER) {
653 int tile_count = get_video_mode_tiles_x(decoder->video_mode) *
655 vector<task_result_handle_t> handle(tile_count);
656 vector<decompress_data> data(tile_count);
657 for (int pos = 0; pos < tile_count; ++pos) {
658 data[pos].decoder = decoder;
659 data[pos].pos = pos;
660 data[pos].compressed = msg->nofec_frame;
661 data[pos].buffer_num = msg->buffer_num[pos];
662 if (tmp.get()) {
663 data[pos].out = (unsigned char *) tmp.get();
664 } else if (decoder->merged_fb) {
665 // TODO: OK when rendering directly to display FB, otherwise, do not reflect pitch (we use PP)
666 int x = pos % get_video_mode_tiles_x(decoder->video_mode),
667 y = pos / get_video_mode_tiles_x(decoder->video_mode);
668 data[pos].out = (unsigned char *) vf_get_tile(decoder->frame, 0)->data + y * decoder->pitch * tile_height +
669 vc_get_linesize(tile_width, decoder->out_codec) * x;
670 } else {
671 data[pos].out = (unsigned char *) vf_get_tile(decoder->frame, pos)->data;
672 }
673 if (tile_count > 1) {
674 handle[pos] = task_run_async(decompress_worker, &data[pos]);
675 } else {
676 decompress_worker(&data[pos]);
677 }
678 }
679 if (tile_count > 1) {
680 for (int pos = 0; pos < tile_count; ++pos) {
681 wait_task(handle[pos]);
682 }
683 }
684 for (int pos = 0; pos < tile_count; ++pos) {
685 if (data[pos].ret == DECODER_GOT_CODEC) {
686 LOG(LOG_LEVEL_NOTICE) << MOD_NAME << "Detected compression properties: " << get_pixdesc_desc(data[pos].internal_prop) << "\n";
687 decoder->msg_queue.push(new main_msg_reconfigure(decoder->received_vid_desc, nullptr, false, data[pos].internal_prop));
688 goto skip_frame;
689 }
690 if (data[pos].ret != DECODER_GOT_FRAME){
691 if (data[pos].ret == DECODER_UNSUPP_PIXFMT) {
692 if(blacklist_current_out_codec(decoder))
693 decoder->msg_queue.push(new main_msg_reconfigure(decoder->received_vid_desc, nullptr, true));
694 }
695 goto skip_frame;
696 }
697 }
698 } else {
699 if (decoder->frame->decoder_overrides_data_len) {
700 for (unsigned int i = 0; i < decoder->frame->tile_count; ++i) {
701 decoder->frame->tiles[i].data_len = msg->nofec_frame->tiles[i].data_len;
702 }
703 }
704 }
705
706 LOG(LOG_LEVEL_DEBUG) << MOD_NAME << "Decompress duration: " <<
707 duration_cast<nanoseconds>(high_resolution_clock::now() - t0).count() / 1000000.0 << " ms\n";
708
709 if(decoder->change_il) {
710 for(unsigned int i = 0; i < decoder->frame->tile_count; ++i) {
711 struct tile *tile = vf_get_tile(decoder->frame, i);
713 decoder->out_codec), tile->height, &decoder->change_il_state[i]);
714 }
715 }
716
717 {
718 long long putf_timeout = force_putf_timeout != -1 ? force_putf_timeout : PUTF_NONBLOCK; // originally was BLOCKING when !is_codec_interframe(decoder->received_vid_desc.color_spec)
719
720 decoder->frame->ssrc = msg->nofec_frame->ssrc;
721 decoder->frame->timestamp = msg->nofec_frame->timestamp;
722 const bool ret = display_put_frame(
723 decoder->display, decoder->frame, putf_timeout);
724 msg->is_displayed = ret;
725 decoder->frame = display_get_frame(decoder->display);
726 assert(decoder->frame != nullptr);
727 }
728
729skip_frame:
730 {
731 unique_lock<mutex> lk(decoder->lock);
732 // we have put the video frame and requested another one which is
733 // writable so on
734 decoder->buffer_swapped = true;
735 lk.unlock();
736 decoder->buffer_swapped_cv.notify_one();
737 }
738 }
739
740 return NULL;
741}
int vc_get_linesize(unsigned int width, codec_t codec)
T pop(bool nonblocking=false)
void push(T const &message)
#define PUTF_NONBLOCK
bool display_put_frame(struct display *d, struct video_frame *frame, long long timeout_ns)
Puts filled video frame. After calling this function, video frame cannot be used.
#define PUTF_BLOCKING
struct video_frame * display_get_frame(struct display *d)
Returns video framebuffer which will be written to.
@ DECODER_GOT_CODEC
Internal pixel format was determined.
@ DECODER_UNSUPP_PIXFMT
Decoder can't decode to selected out_codec.
@ DECODER_GOT_FRAME
std::unordered_map< std::string, std::string > commandline_params
Definition host.cpp:184
double unit_evaluate_dbl(const char *str, bool case_sensitive, const char **endptr)
Definition misc.cpp:102
struct display * display
struct video_frame * frame
synchronized_queue< unique_ptr< frame_msg >, 1 > decompress_queue
bool merged_fb
flag if the display device driver requires tiled video or not
change_il_t change_il
function to change interlacing, if needed. Otherwise NULL.
condition_variable buffer_swapped_cv
condition variable associated with buffer_swapped
synchronized_queue< main_msg_reconfigure *, -1 > msg_queue
Struct tile is an area of video_frame.
Definition types.h:279
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
unsigned int height
Definition types.h:281
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
unsigned int decoder_overrides_data_len
Definition types.h:322
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
uint32_t ssrc
Definition types.h:330
int64_t timestamp
Definition types.h:331
unsigned int tile_count
Definition types.h:344
void set_thread_name(const char *name)
Definition thread.c:72
#define NS_IN_SEC
Definition tv.h:92
#define MAX_BPS
maximal (average) number of pixels per know pixel formats (up-round if needed)
Definition video_codec.h:62
static bool blacklist_current_out_codec(struct state_video_decoder *decoder)
constexpr int PADDING
#define MOD_NAME
static void * decompress_worker(void *data)
struct tile * vf_get_tile(struct video_frame *buf, int pos)
Returns pointer to n-th tile from video frame Equivalent to &video_frame::tiles[pos].
void * wait_task(task_result_handle_t handle)
Definition worker.cpp:280
task_result_handle_t task_run_async(runnable_t task, void *data)
Runs task asynchronously.
Definition worker.cpp:262

References blacklist_current_out_codec(), state_video_decoder::buffer_swapped, state_video_decoder::buffer_swapped_cv, state_video_decoder::change_il, state_video_decoder::change_il_state, commandline_params, tile::data, tile::data_len, DECODER_GOT_CODEC, DECODER_GOT_FRAME, video_frame::decoder_overrides_data_len, state_video_decoder::decoder_type, DECODER_UNSUPP_PIXFMT, state_video_decoder::decompress_queue, decompress_worker(), state_video_decoder::display, display_get_frame(), display_put_frame(), state_video_decoder::frame, get_pixdesc_desc(), get_video_mode_tiles_x(), get_video_mode_tiles_y(), tile::height, video_desc::height, state_video_decoder::lock, LOG, LOG_LEVEL_DEBUG, LOG_LEVEL_NOTICE, MAX_BPS, state_video_decoder::merged_fb, MOD_NAME, state_video_decoder::msg_queue, NS_IN_SEC, state_video_decoder::out_codec, PADDING, state_video_decoder::pitch, synchronized_queue< T, max_len >::pop(), synchronized_queue< T, max_len >::push(), PUTF_BLOCKING, PUTF_NONBLOCK, state_video_decoder::received_vid_desc, set_thread_name(), video_frame::ssrc, task_run_async(), video_frame::tile_count, video_frame::tiles, video_frame::timestamp, unit_evaluate_dbl(), vc_get_linesize(), vf_get_tile(), VIDEO_CODEC_END, state_video_decoder::video_mode, wait_task(), tile::width, and video_desc::width.

Referenced by video_decoder_start_threads().

Here is the call graph for this function:

◆ decompress_worker()

static void * decompress_worker ( void * data)
static

Definition at line 593 of file video_decoders.cpp.

594{
595 auto d = (struct decompress_data *) data;
596 struct state_video_decoder *decoder = d->decoder;
597
598 if (!d->compressed->tiles[d->pos].data)
599 return NULL;
600 d->ret = decompress_frame(decoder->decompress_state.at(d->pos),
601 (unsigned char *) d->out,
602 (unsigned char *) d->compressed->tiles[d->pos].data,
603 d->compressed->tiles[d->pos].data_len,
604 d->buffer_num,
605 &decoder->frame->callbacks,
606 &d->internal_prop);
607 return d;
608}
decompress_status decompress_frame(struct state_decompress *s, unsigned char *dst, unsigned char *compressed, unsigned int compressed_len, int frame_seq, struct video_frame_callbacks *callbacks, struct pixfmt_desc *internal_prop)
Decompresses video frame.
struct video_frame_callbacks callbacks
Definition types.h:324

References video_frame::callbacks, decompress_frame(), state_video_decoder::decompress_state, and state_video_decoder::frame.

Referenced by decompress_thread().

Here is the call graph for this function:

◆ fec_thread()

static void * fec_thread ( void * args)
static

Definition at line 416 of file video_decoders.cpp.

416 {
417 set_thread_name(__func__);
418 struct state_video_decoder *decoder =
419 (struct state_video_decoder *) args;
420
421 fec *fec_state = NULL;
422 struct fec_desc desc(FEC_NONE);
423
424 while(1) {
425 unique_ptr<frame_msg> data = decoder->fec_queue.pop();
426
427 if (!data->recv_frame) { // poisoned
428 decoder->decompress_queue.push(std::move(data));
429 break; // exit from loop
430 }
431
432 struct video_frame *frame = decoder->frame;
433 struct tile *tile = NULL;
434
435 if (data->recv_frame->fec_params.type != FEC_NONE) {
436 if(!fec_state || desc.k != data->recv_frame->fec_params.k ||
437 desc.m != data->recv_frame->fec_params.m ||
438 desc.c != data->recv_frame->fec_params.c ||
439 desc.seed != data->recv_frame->fec_params.seed
440 ) {
441 delete fec_state;
442 desc = data->recv_frame->fec_params;
443 fec_state = fec::create_from_desc(desc);
444 if(fec_state == NULL) {
445 log_msg(LOG_LEVEL_FATAL, "[decoder] Unable to initialize FEC.\n");
446 exit_uv(1);
447 goto cleanup;
448 }
449 }
450 }
451
452 data->nofec_frame = vf_alloc(data->recv_frame->tile_count);
453 data->nofec_frame->ssrc = data->recv_frame->ssrc;
454 data->nofec_frame->timestamp = data->recv_frame->timestamp;
455
456 if (data->recv_frame->fec_params.type != FEC_NONE) {
457 bool buffer_swapped = false;
458 for (int pos = 0; pos < get_video_mode_tiles_x(decoder->video_mode)
459 * get_video_mode_tiles_y(decoder->video_mode); ++pos) {
460 char *fec_out_buffer = NULL;
461 int fec_out_len = 0;
462
463 if (data->recv_frame->tiles[pos].data_len != (unsigned int) sum_map(data->pckt_list[pos])) {
464 debug_msg("Frame incomplete - substream %d, buffer %d: expected %u bytes, got %u.\n", pos,
465 (unsigned int) data->buffer_num[pos],
466 data->recv_frame->tiles[pos].data_len,
467 (unsigned int) sum_map(data->pckt_list[pos]));
468 }
469
470 bool ret = fec_state->decode(data->recv_frame->tiles[pos].data,
471 data->recv_frame->tiles[pos].data_len,
472 &fec_out_buffer, &fec_out_len, data->pckt_list[pos]);
473
474 if (ret == false) {
475 data->is_corrupted = true;
476 verbose_msg("[decoder] FEC: unable to reconstruct data.\n");
477 if (fec_out_len < (int) sizeof(video_payload_hdr_t)) {
478 goto cleanup;
479 }
480 if (decoder->decoder_type == EXTERNAL_DECODER && !decoder->accepts_corrupted_frame) {
481 goto cleanup;
482 }
483 }
484
485 video_payload_hdr_t video_hdr;
486 memcpy(&video_hdr, fec_out_buffer,
487 sizeof(video_payload_hdr_t));
488 fec_out_buffer += sizeof(video_payload_hdr_t);
489 fec_out_len -= sizeof(video_payload_hdr_t);
490
491 struct video_desc network_desc;
492 parse_video_hdr(video_hdr, &network_desc);
494 network_desc, PARAM_TILE_COUNT)) {
495 decoder->msg_queue.push(new main_msg_reconfigure(network_desc, std::move(data)));
496 goto cleanup;
497 }
498
499 if (FRAMEBUFFER_NOT_READY(decoder)) {
500 goto cleanup;
501 }
502
503 if(decoder->decoder_type == EXTERNAL_DECODER) {
504 data->nofec_frame->tiles[pos].data_len = fec_out_len;
505 data->nofec_frame->tiles[pos].data = fec_out_buffer;
506 } else { // linedecoder
507 if (!buffer_swapped) {
508 buffer_swapped = true;
510 unique_lock<mutex> lk(decoder->lock);
511 decoder->buffer_swapped = false;
512 }
513
514 int divisor;
515
516 if (!decoder->merged_fb) {
517 divisor = decoder->max_substreams;
518 } else {
519 divisor = 1;
520 }
521
522 tile = vf_get_tile(frame, pos % divisor);
523
524 struct line_decoder *line_decoder =
525 &decoder->line_decoder[pos];
526
527 int data_pos = 0;
528 char *src = fec_out_buffer;
529 char *dst = tile->data + line_decoder->base_offset;
530 while(data_pos < (int) fec_out_len) {
531 line_decoder->decode_line((unsigned char*)dst, (unsigned char *) src, line_decoder->dst_linesize,
532 line_decoder->shifts[0],
533 line_decoder->shifts[1],
534 line_decoder->shifts[2]);
535 src += line_decoder->src_linesize;
537 data_pos += line_decoder->src_linesize;
538 }
539 }
540 }
541 } else { /* PT_VIDEO */
542 for(int i = 0; i < (int) decoder->max_substreams; ++i) {
543 data->nofec_frame->tiles[i].data_len = data->recv_frame->tiles[i].data_len;
544 data->nofec_frame->tiles[i].data = data->recv_frame->tiles[i].data;
545
546 if (data->recv_frame->tiles[i].data_len != (unsigned int) sum_map(data->pckt_list[i])) {
547 debug_msg("Frame incomplete - substream %d, buffer %d: expected %u bytes, got %u.%s\n", i,
548 (unsigned int) data->buffer_num[i],
549 data->recv_frame->tiles[i].data_len,
550 (unsigned int) sum_map(data->pckt_list[i]),
551 decoder->decoder_type == EXTERNAL_DECODER && !decoder->accepts_corrupted_frame ? " dropped.\n" : "");
552 data->is_corrupted = true;
553 if(decoder->decoder_type == EXTERNAL_DECODER && !decoder->accepts_corrupted_frame) {
554 goto cleanup;
555 }
556 }
557 }
558 }
559
560 decoder->decompress_queue.push(std::move(data));
561cleanup:
562 ;
563 }
564
565 delete fec_state;
566
567 return NULL;
568}
struct video_frame * frame
struct video_frame * vf_alloc(int count)
Allocates blank video frame.
#define verbose_msg(...)
Definition debug.h:90
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
void exit_uv(int status)
Definition host.cpp:625
uint32_t video_payload_hdr_t[6]
Definition rtp_types.h:107
static void cleanup()
Definition sdp.c:195
Definition fec.h:51
static fec * create_from_desc(struct fec_desc) noexcept
Definition fec.cpp:107
virtual bool decode(char *in, int in_len, char **out, int *out_len, const std::map< int, int > &)=0
synchronized_queue< unique_ptr< frame_msg >, 1 > fec_queue
bool accepts_corrupted_frame
whether we should pass corrupted frame to decompress
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
codec_t color_spec
Definition types.h:306
@ FEC_NONE
Definition types.h:201
#define FRAMEBUFFER_NOT_READY(decoder)
static int sum_map(map< int, int > const &m)
static void wait_for_framebuffer_swap(struct state_video_decoder *decoder)

References state_video_decoder::accepts_corrupted_frame, state_video_decoder::buffer_swapped, cleanup(), video_frame::color_spec, fec::create_from_desc(), tile::data, debug_msg, fec::decode(), state_video_decoder::decoder_type, state_video_decoder::decompress_queue, desc, exit_uv(), FEC_NONE, state_video_decoder::fec_queue, frame, state_video_decoder::frame, FRAMEBUFFER_NOT_READY, get_video_mode_tiles_x(), get_video_mode_tiles_y(), state_video_decoder::line_decoder, state_video_decoder::lock, LOG_LEVEL_FATAL, log_msg(), state_video_decoder::max_substreams, state_video_decoder::merged_fb, state_video_decoder::msg_queue, PARAM_TILE_COUNT, parse_video_hdr(), synchronized_queue< T, max_len >::pop(), synchronized_queue< T, max_len >::push(), state_video_decoder::received_vid_desc, set_thread_name(), sum_map(), vc_get_linesize(), verbose_msg, vf_alloc(), vf_get_tile(), video_desc_eq_excl_param(), state_video_decoder::video_mode, wait_for_framebuffer_swap(), and tile::width.

Referenced by video_decoder_start_threads().

Here is the call graph for this function:

◆ reconfigure_decoder()

static bool reconfigure_decoder ( struct state_video_decoder * decoder,
struct video_desc desc,
struct pixfmt_desc comp_int_prop )
static

Reconfigures decoder if network received video data format has changed.

Parameters
decoderthe video decoder state
descnew video description to be reconfigured to
Returns
boolean value if reconfiguration was successful
Invariant
decoder->display != NULL

Definition at line 1206 of file video_decoders.cpp.

1208{
1209 codec_t out_codec;
1210 decoder_t decode_line;
1211 enum interlacing_t display_il = PROGRESSIVE;
1212 //struct video_frame *frame;
1213 int display_requested_pitch = PITCH_DEFAULT;
1214 int display_requested_rgb_shift[] = DEFAULT_RGB_SHIFT_INIT;
1215
1216 // this code forces flushing the pipelined data
1218 if (decoder->frame)
1219 display_put_frame(decoder->display, decoder->frame, PUTF_DISCARD);
1220 decoder->frame = NULL;
1222
1223 cleanup(decoder);
1224
1227
1228 out_codec = choose_codec_and_decoder(decoder, desc, &decode_line, comp_int_prop);
1229 if (out_codec == VIDEO_CODEC_NONE) {
1230 LOG(LOG_LEVEL_ERROR) << "Could not find neither line conversion nor decompress from " <<
1231 get_codec_name(desc.color_spec) << " to display supported formats (" << codec_list_to_str(decoder->native_codecs) << ").\n";
1232 return false;
1233 }
1234 decoder->out_codec = out_codec;
1235 struct video_desc display_desc = desc;
1236
1237 int display_mode = DISPLAY_PROPERTY_VIDEO_MERGED; // default
1238 size_t len = sizeof(int);
1239
1241 &display_mode, &len)) {
1242 debug_msg("Failed to get video display mode.\n");
1243 }
1244
1245 if (display_mode == DISPLAY_PROPERTY_VIDEO_SEPARATE_3D) {
1246 display_mode = display_desc.tile_count == 2 ? DISPLAY_PROPERTY_VIDEO_SEPARATE_TILES :
1248 }
1249
1250 if (display_mode == DISPLAY_PROPERTY_VIDEO_MERGED) {
1251 display_desc.width *= get_video_mode_tiles_x(decoder->video_mode);
1252 display_desc.height *= get_video_mode_tiles_y(decoder->video_mode);
1253 display_desc.tile_count = 1;
1254 }
1255
1257 decoder->disp_supported_il_cnt, &display_il);
1258 decoder->change_il_state.resize(decoder->max_substreams);
1259 display_desc.interlacing = display_il;
1260 display_desc.color_spec = out_codec;
1261 if (out_codec != VIDEO_CODEC_END && !video_desc_eq(decoder->display_desc, display_desc)) {
1262 /* reconfigure VO and give it opportunity to pass us pitch */
1263 bool ret = display_reconfigure(decoder->display, display_desc, decoder->video_mode);
1264 if(!ret) {
1265 return false;
1266 }
1267 decoder->display_desc = display_desc;
1268
1269 len = sizeof(display_requested_rgb_shift);
1271 &display_requested_rgb_shift, &len);
1272 if(!ret) {
1273 debug_msg("Failed to get r,g,b shift property from video driver.\n");
1274 int rgb_shift[] = DEFAULT_RGB_SHIFT_INIT;
1275 memcpy(&display_requested_rgb_shift, rgb_shift, sizeof(rgb_shift));
1276 }
1277
1279 &display_requested_pitch, &len);
1280 if(!ret) {
1281 debug_msg("Failed to get pitch from video driver.\n");
1282 display_requested_pitch = PITCH_DEFAULT;
1283 }
1284 }
1285
1286 int linewidth;
1287 if (display_mode == DISPLAY_PROPERTY_VIDEO_SEPARATE_TILES) {
1288 linewidth = desc.width;
1289 } else {
1290 linewidth = desc.width * get_video_mode_tiles_x(decoder->video_mode);
1291 }
1292
1293 if(display_requested_pitch == PITCH_DEFAULT)
1294 decoder->pitch = vc_get_linesize(linewidth, out_codec);
1295 else
1296 decoder->pitch = display_requested_pitch;
1297
1298
1299 int src_x_tiles = get_video_mode_tiles_x(decoder->video_mode);
1300 int src_y_tiles = get_video_mode_tiles_y(decoder->video_mode);
1301
1302 if(decoder->decoder_type == LINE_DECODER) {
1303 decoder->line_decoder = (struct line_decoder *) malloc(src_x_tiles * src_y_tiles *
1304 sizeof(struct line_decoder));
1305 if(display_mode == DISPLAY_PROPERTY_VIDEO_MERGED && decoder->video_mode == VIDEO_NORMAL) {
1306 struct line_decoder *out = &decoder->line_decoder[0];
1307 out->base_offset = 0;
1308 out->conv_num = get_pf_block_pixels(desc.color_spec) * get_pf_block_bytes(out_codec);
1309 out->conv_den = get_pf_block_bytes(desc.color_spec) * get_pf_block_pixels(out_codec);
1310 memcpy(out->shifts, display_requested_rgb_shift, 3 * sizeof(int));
1311
1312 out->decode_line = decode_line;
1313 out->dst_pitch = decoder->pitch;
1314 out->src_linesize = vc_get_linesize(desc.width, desc.color_spec);
1315 out->dst_linesize = vc_get_linesize(desc.width, out_codec);
1316 decoder->merged_fb = true;
1317 } else if(display_mode == DISPLAY_PROPERTY_VIDEO_MERGED
1318 && decoder->video_mode != VIDEO_NORMAL) {
1319 int x, y;
1320 for(x = 0; x < src_x_tiles; ++x) {
1321 for(y = 0; y < src_y_tiles; ++y) {
1322 struct line_decoder *out = &decoder->line_decoder[x +
1323 src_x_tiles * y];
1324 out->base_offset = y * (desc.height)
1325 * decoder->pitch +
1326 vc_get_linesize(x * desc.width, out_codec);
1327
1328 out->conv_num = get_pf_block_pixels(desc.color_spec) * get_pf_block_bytes(out_codec);
1329 out->conv_den = get_pf_block_bytes(desc.color_spec) * get_pf_block_pixels(out_codec);
1330 memcpy(out->shifts, display_requested_rgb_shift,
1331 3 * sizeof(int));
1332
1333 out->decode_line = decode_line;
1334
1335 out->dst_pitch = decoder->pitch;
1336 out->src_linesize =
1338 out->dst_linesize =
1339 vc_get_linesize(desc.width, out_codec);
1340 }
1341 }
1342 decoder->merged_fb = true;
1343 } else if (display_mode == DISPLAY_PROPERTY_VIDEO_SEPARATE_TILES) {
1344 int x, y;
1345 for(x = 0; x < src_x_tiles; ++x) {
1346 for(y = 0; y < src_y_tiles; ++y) {
1347 struct line_decoder *out = &decoder->line_decoder[x +
1348 src_x_tiles * y];
1349 out->base_offset = 0;
1350 out->conv_num = get_pf_block_pixels(desc.color_spec) * get_pf_block_bytes(out_codec);
1351 out->conv_den = get_pf_block_bytes(desc.color_spec) * get_pf_block_pixels(out_codec);
1352 memcpy(out->shifts, display_requested_rgb_shift,
1353 3 * sizeof(int));
1354
1355 out->decode_line = decode_line;
1356 out->src_linesize =
1358 out->dst_pitch =
1359 out->dst_linesize =
1360 vc_get_linesize(desc.width, out_codec);
1361 }
1362 }
1363 decoder->merged_fb = false;
1364 }
1365 } else if (decoder->decoder_type == EXTERNAL_DECODER) {
1366 int buf_size;
1367
1368 for(unsigned int i = 0; i < decoder->decompress_state.size(); ++i) {
1369 buf_size = decompress_reconfigure(decoder->decompress_state.at(i), desc,
1370 display_requested_rgb_shift[0],
1371 display_requested_rgb_shift[1],
1372 display_requested_rgb_shift[2],
1373 decoder->pitch,
1374 out_codec == VIDEO_CODEC_END ? VIDEO_CODEC_NONE : out_codec);
1375 if(!buf_size) {
1376 return false;
1377 }
1378 }
1379 decoder->merged_fb = display_mode != DISPLAY_PROPERTY_VIDEO_SEPARATE_TILES;
1380 int res = 0, ret;
1381 size_t size = sizeof(res);
1382 ret = decompress_get_property(decoder->decompress_state.at(0),
1384 &res, &size);
1385 decoder->accepts_corrupted_frame = ret && res;
1386 }
1387
1388 // Pass metadata to receiver thread (it can tweak parameters)
1389 struct msg_receiver *msg = (struct msg_receiver *)
1390 new_message(sizeof(struct msg_receiver));
1392 msg->new_desc = decoder->received_vid_desc;
1393 struct response *resp =
1394 send_message_to_receiver(decoder->mod.parent, (struct message *) msg);
1395 free_response(resp);
1396
1397 if (out_codec != VIDEO_CODEC_END) {
1398 decoder->frame = display_get_frame(decoder->display);
1399 assert(decoder->frame != nullptr);
1400 }
1401
1402 return true;
1403}
int void size_t * len
static void new_message(struct module *m)
#define PITCH_DEFAULT
default pitch, i. e. respective linesize
bool display_ctl_property(struct display *d, int property, void *val, size_t *len)
Gets property from video display.
#define PUTF_DISCARD
@ DISPLAY_PROPERTY_BUF_PITCH
requested framebuffer pitch - int (bytes), may be PITCH_DEFAULT
@ DISPLAY_PROPERTY_RGB_SHIFT
red,green,blue shift - int[3] (bits)
@ DISPLAY_PROPERTY_VIDEO_MODE
requested video mode - int (one of display_prop_vid_mode)
@ DISPLAY_PROPERTY_VIDEO_SEPARATE_TILES
framebuffer consists of separate tiles
@ DISPLAY_PROPERTY_VIDEO_MERGED
monolithic framebuffer
@ DISPLAY_PROPERTY_VIDEO_SEPARATE_3D
same as MERGED but 2 streams should be handled as separate 3D tiles
#define DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME
int decompress_get_property(struct state_decompress *s, int property, void *val, size_t *len)
int decompress_reconfigure(struct state_decompress *s, struct video_desc desc, int rshift, int gshift, int bshift, int pitch, codec_t out_codec)
struct response * send_message_to_receiver(struct module *receiver, struct message *msg)
void free_response(struct response *r)
@ RECEIVER_MSG_VIDEO_PROP_CHANGED
Definition messaging.h:110
decoder_func_t * decoder_t
Definition pixfmt_conv.h:96
#define DEFAULT_RGB_SHIFT_INIT
Definition pixfmt_conv.h:73
struct module * parent
Definition module.h:116
enum interlacing_t * disp_supported_il
display supported interlacing mode
size_t disp_supported_il_cnt
count of disp_supported_il
struct video_desc display_desc
description of the mode that display is currently configured to
unsigned int tile_count
Definition types.h:185
enum interlacing_t interlacing
Definition types.h:184
interlacing_t
Definition types.h:163
@ PROGRESSIVE
progressive frame
Definition types.h:164
int get_pf_block_bytes(codec_t codec)
returns codec_info_t::block_size_bytes
int get_pf_block_pixels(codec_t codec)
returns codec_info_t::block_size_pixels
static change_il_t select_il_func(enum interlacing_t in_il, enum interlacing_t *supported, int il_out_cnt, enum interlacing_t *out_il)
static void video_decoder_stop_threads(struct state_video_decoder *decoder)
This function stops running threads.
static codec_t choose_codec_and_decoder(struct state_video_decoder *decoder, struct video_desc desc, decoder_t *decode_line, struct pixfmt_desc comp_int_prop)
static void video_decoder_start_threads(struct state_video_decoder *decoder)
starts decompress and ldmg threads
bool display_reconfigure(struct display *d, struct video_desc desc, enum video_mode video_mode)
Reconfigure display to new video format.
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.

References state_video_decoder::accepts_corrupted_frame, state_video_decoder::change_il, state_video_decoder::change_il_state, choose_codec_and_decoder(), cleanup(), codec_list_to_str(), video_desc::color_spec, debug_msg, state_video_decoder::decoder_type, decompress_get_property(), DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME, decompress_reconfigure(), state_video_decoder::decompress_state, DEFAULT_RGB_SHIFT_INIT, desc, state_video_decoder::disp_supported_il, state_video_decoder::disp_supported_il_cnt, state_video_decoder::display, display_ctl_property(), state_video_decoder::display_desc, display_get_frame(), DISPLAY_PROPERTY_BUF_PITCH, DISPLAY_PROPERTY_RGB_SHIFT, DISPLAY_PROPERTY_VIDEO_MERGED, DISPLAY_PROPERTY_VIDEO_MODE, DISPLAY_PROPERTY_VIDEO_SEPARATE_3D, DISPLAY_PROPERTY_VIDEO_SEPARATE_TILES, display_put_frame(), display_reconfigure(), state_video_decoder::frame, free_response(), get_codec_name(), get_pf_block_bytes(), get_pf_block_pixels(), get_video_mode_tiles_x(), get_video_mode_tiles_y(), video_desc::height, video_desc::interlacing, len, state_video_decoder::line_decoder, LOG, LOG_LEVEL_ERROR, state_video_decoder::max_substreams, state_video_decoder::merged_fb, state_video_decoder::mod, state_video_decoder::native_codecs, new_message(), state_video_decoder::out_codec, module::parent, state_video_decoder::pitch, PITCH_DEFAULT, PROGRESSIVE, PUTF_DISCARD, state_video_decoder::received_vid_desc, RECEIVER_MSG_VIDEO_PROP_CHANGED, select_il_func(), send_message_to_receiver(), video_desc::tile_count, vc_get_linesize(), VIDEO_CODEC_END, VIDEO_CODEC_NONE, video_decoder_start_threads(), video_decoder_stop_threads(), video_desc_eq(), state_video_decoder::video_mode, VIDEO_NORMAL, and video_desc::width.

Referenced by reconfigure_helper().

Here is the call graph for this function:

◆ reconfigure_helper()

static void reconfigure_helper ( struct state_video_decoder * decoder,
struct video_desc network_desc,
struct pixfmt_desc comp_int_desc )
static

Definition at line 1439 of file video_decoders.cpp.

1442{
1443 decoder->received_vid_desc = network_desc;
1444 decoder->received_int_desc = comp_int_desc;
1445
1446 bool ret = reconfigure_decoder(decoder, decoder->received_vid_desc, comp_int_desc);
1447 if (!ret) {
1448 log_msg(LOG_LEVEL_ERROR, "[video dec.] Reconfiguration failed!!!\n");
1449 decoder->frame = NULL;
1450 decoder->out_codec = VIDEO_CODEC_NONE;
1451 }
1452}
struct pixfmt_desc received_int_desc
compression int desc
static bool reconfigure_decoder(struct state_video_decoder *decoder, struct video_desc desc, struct pixfmt_desc comp_int_desc)

References state_video_decoder::frame, LOG_LEVEL_ERROR, log_msg(), state_video_decoder::out_codec, state_video_decoder::received_int_desc, state_video_decoder::received_vid_desc, reconfigure_decoder(), and VIDEO_CODEC_NONE.

Referenced by check_for_mode_change(), decode_video_frame(), and reconfigure_if_needed().

Here is the call graph for this function:

◆ reconfigure_if_needed()

static void reconfigure_if_needed ( struct state_video_decoder * decoder,
struct video_desc network_desc,
struct pixfmt_desc comp_int_desc )
static

Definition at line 1454 of file video_decoders.cpp.

1457{
1458 const bool desc_eq = video_desc_eq_excl_param(
1459 decoder->received_vid_desc, network_desc, PARAM_TILE_COUNT);
1460 const bool comp_int_eq =
1461 pixdesc_equals(decoder->received_int_desc, comp_int_desc);
1462 if (desc_eq && comp_int_eq) {
1463 return;
1464 }
1465 reconfigure_helper(decoder, network_desc, comp_int_desc);
1466}
bool pixdesc_equals(struct pixfmt_desc desc_a, struct pixfmt_desc desc_b)

References PARAM_TILE_COUNT, pixdesc_equals(), state_video_decoder::received_int_desc, state_video_decoder::received_vid_desc, reconfigure_helper(), and video_desc_eq_excl_param().

Referenced by decode_video_frame().

Here is the call graph for this function:

◆ select_il_func()

static change_il_t select_il_func ( enum interlacing_t in_il,
enum interlacing_t * supported,
int il_out_cnt,
enum interlacing_t * out_il )
static

This function finds interlacing mode changing function.

Parameters
[in]in_ilinput_interlacing
[in]supportedlist of supported output interlacing modes
[in]il_out_cntcount of supported items
[out]out_ilselected output interlacing
Returns
selected interlacing changing function, NULL if not needed or not found

Definition at line 1161 of file video_decoders.cpp.

1163{
1164 struct transcode_t { enum interlacing_t in; enum interlacing_t out; change_il_t func; };
1165
1166 struct transcode_t transcode[] = {
1170 };
1171
1172 int i;
1173 /* first try to check if it can be nativelly displayed */
1174 for (i = 0; i < il_out_cnt; ++i) {
1175 if(in_il == supported[i]) {
1176 *out_il = in_il;
1177 return NULL;
1178 }
1179 }
1180
1181 for (i = 0; i < il_out_cnt; ++i) {
1182 size_t j;
1183 for (j = 0; j < sizeof(transcode) / sizeof(struct transcode_t); ++j) {
1184 if(in_il == transcode[j].in && supported[i] == transcode[j].out) {
1185 *out_il = transcode[j].out;
1186 return transcode[j].func;
1187 }
1188 }
1189 }
1190
1191 log_msg(LOG_LEVEL_WARNING, "[Warning] Cannot find transition between incoming and display "
1192 "interlacing modes!\n");
1193 return NULL;
1194}
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
HRESULT __stdcall(* func)()
Definition screen_win.c:325
@ LOWER_FIELD_FIRST
First stored field is bottom, followed by top.
Definition types.h:166
@ UPPER_FIELD_FIRST
First stored field is top, followed by bottom.
Definition types.h:165
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167
void(* change_il_t)(char *dst, char *src, int linesize, int height, void **state)
void il_merged_to_upper(char *dst, char *src, int linesize, int height, void **state)
Converts interlaced merged to upper-field-first.
void il_lower_to_merged(char *dst, char *src, int linesize, int height, void **stored_state)
void il_upper_to_merged(char *dst, char *src, int linesize, int height, void **state)
Converts upper-field-first to interlaced merged.

References il_lower_to_merged(), il_merged_to_upper(), il_upper_to_merged(), INTERLACED_MERGED, LOG_LEVEL_WARNING, log_msg(), LOWER_FIELD_FIRST, and UPPER_FIELD_FIRST.

Referenced by reconfigure_decoder().

Here is the call graph for this function:

◆ sum_map()

static int sum_map ( map< int, int > const & m)
static

Definition at line 191 of file video_decoders.cpp.

191 {
192 int ret = 0;
193 for (map<int, int>::const_iterator it = m.begin();
194 it != m.end(); ++it) {
195 ret += it->second;
196 }
197 return ret;
198}

Referenced by fec_thread().

◆ video_decoder_init()

struct state_video_decoder * video_decoder_init ( struct module * parent,
enum video_mode video_mode ,
struct display * display,
const char * encryption )

Initializes video decompress state.

Parameters
video_modevideo_mode expected to be received from network
displayVideo display that is supposed to be controlled from decoder. display_get_frame(), display_put_frame(), display_get_propert() and display_reconfigure() functions may be used. If set to NULL, no decoding will take place.
encryptionEncryption config string. Currently, this is a passphrase to be used. This may change eventually.
Returns
Newly created decoder state. If an error occured, returns NULL.

Definition at line 761 of file video_decoders.cpp.

764{
765 struct state_video_decoder *s;
766
768
769 if (strlen(encryption) > 0) {
770 s->dec_funcs = static_cast<const struct openssl_decrypt_info *>(load_library("openssl_decrypt",
772 if (!s->dec_funcs) {
773 log_msg(LOG_LEVEL_FATAL, "UltraGrid was build without OpenSSL support!\n");
774 delete s;
775 return NULL;
776 }
777 if (s->dec_funcs->init(&s->decrypt, encryption) != 0) {
778 log_msg(LOG_LEVEL_FATAL, "Unable to create decompress!\n");
779 delete s;
780 return NULL;
781 }
782 }
783
785
787 delete s;
788 return NULL;
789 }
790
791 return s;
792}
bool video_decoder_register_display(struct state_video_decoder *decoder, struct display *display)
Registers video display to be used for displaying decoded video frames.
const void * load_library(const char *name, enum library_class cls, int abi_version)
@ LIBRARY_CLASS_UNDEFINED
Definition lib_common.h:74
#define OPENSSL_DECRYPT_ABI_VERSION
const char * parent
Definition settings.cpp:198
This struct represents initialized video display state.
int(* init)(struct openssl_decrypt **state, const char *passphrase)
const struct openssl_decrypt_info * dec_funcs
decrypt state
struct openssl_decrypt * decrypt
decrypt state
state_video_decoder(struct module *parent)
static void decoder_set_video_mode(struct state_video_decoder *decoder, enum video_mode video_mode)

References state_video_decoder::state_video_decoder(), state_video_decoder::dec_funcs, decoder_set_video_mode(), state_video_decoder::decrypt, openssl_decrypt_info::init, LIBRARY_CLASS_UNDEFINED, load_library(), LOG_LEVEL_FATAL, log_msg(), OPENSSL_DECRYPT_ABI_VERSION, parent, and video_decoder_register_display().

Referenced by ultragrid_rtp_video_rxtx::new_video_decoder().

Here is the call graph for this function:

◆ video_decoder_order_output_codecs()

static vector< pair< struct pixfmt_desc, codec_t > > video_decoder_order_output_codecs ( struct pixfmt_desc comp_int_prop,
vector< codec_t > const & display_codecs )
static

Reorders display codecs to match compression internal format.

First try to add HW-accelerated codecs, then exactly comp_int_fmt (if available) and then sort the rest - matching color-space first, higher bit depths first.

Always first try "native" than generic decoder (native is the one matching comp_int_fmt, generic should be catch-all allowing decompression of arbitrary compressed stream of received codec).

Definition at line 1005 of file video_decoders.cpp.

1006{
1007 vector<pair<struct pixfmt_desc, codec_t>> ret;
1008 set<codec_t> used;
1009 // first add hw-accelerated codecs
1010 for (auto codec : display_codecs) {
1012 ret.emplace_back(comp_int_prop, codec);
1013 if (comp_int_prop.depth != 0) {
1014 ret.emplace_back(pixfmt_desc{}, codec);
1015 }
1016 used.insert(codec);
1017 }
1018 }
1019 // then codecs matching exactly internal codec
1020 for (auto codec : display_codecs) {
1021 if (used.find(codec) != used.end()) {
1022 continue;
1023 };
1024 if (pixdesc_equals(get_pixfmt_desc(codec), comp_int_prop)) {
1025 ret.emplace_back(comp_int_prop, codec);
1026 if (comp_int_prop.depth != 0) {
1027 ret.emplace_back(pixfmt_desc{}, codec);
1028 }
1029 used.insert(codec);
1030 }
1031 }
1032 // then add also all other codecs
1033 vector<codec_t> remaining;
1034 for (auto codec : display_codecs) {
1035 if (used.find(codec) != used.end()) {
1036 continue;
1037 };
1038 remaining.emplace_back(codec);
1039 }
1040 if (comp_int_prop.depth != 0) {
1041 sort(remaining.begin(), remaining.end(), [comp_int_prop](const codec_t &a, const codec_t &b) {
1042 struct pixfmt_desc desc_a = get_pixfmt_desc(a);
1043 struct pixfmt_desc desc_b = get_pixfmt_desc(b);
1044 return compare_pixdesc(&desc_a, &desc_b, &comp_int_prop) < 0;
1045 });
1046 }
1047 for (auto & c : remaining) {
1048 ret.emplace_back(comp_int_prop, c);
1049 if (comp_int_prop.depth != 0) {
1050 ret.emplace_back(pixfmt_desc{}, c);
1051 }
1052 }
1053
1055 LOG(LOG_LEVEL_VERBOSE) << "Trying codecs in this order:\n";
1056 for (auto it = ret.begin(); it != ret.end(); ++it) {
1057 LOG(LOG_LEVEL_VERBOSE) << "\t" << get_codec_name((*it).second) << ", internal: " << get_pixdesc_desc((*it).first) << "\n";
1058 }
1059 }
1060
1061 return ret;
1062}
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
volatile int log_level
Definition debug.cpp:65
bool codec_is_hw_accelerated(codec_t codec)
struct pixfmt_desc get_pixfmt_desc(codec_t pixfmt)

References codec_is_hw_accelerated(), pixfmt_desc::depth, get_codec_name(), get_pixdesc_desc(), get_pixfmt_desc(), LOG, log_level, LOG_LEVEL_VERBOSE, and pixdesc_equals().

Referenced by choose_codec_and_decoder().

Here is the call graph for this function:

◆ video_decoder_start_threads()

static void video_decoder_start_threads ( struct state_video_decoder * decoder)
static

starts decompress and ldmg threads

Called from video_decoder_register_display(). It is also called after video_decoder_stop_threads() in reconfiguration.

Invariant
decoder->display != NULL

Definition at line 803 of file video_decoders.cpp.

804{
805 assert(decoder->display); // we want to run threads only if decoder is active
806
807 decoder->decompress_thread_id = thread(decompress_thread, decoder);
808 decoder->fec_thread_id = thread(fec_thread, decoder);
809}
static void * decompress_thread(void *args)
static void * fec_thread(void *args)

References decompress_thread(), state_video_decoder::decompress_thread_id, state_video_decoder::display, fec_thread(), and state_video_decoder::fec_thread_id.

Referenced by reconfigure_decoder(), and video_decoder_register_display().

Here is the call graph for this function:

◆ video_decoder_stop_threads()

static void video_decoder_stop_threads ( struct state_video_decoder * decoder)
static

This function stops running threads.

Invariant
decoder->display != NULL

Definition at line 817 of file video_decoders.cpp.

818{
819 assert(decoder->display);
820
821 unique_ptr<frame_msg> msg(new frame_msg(decoder->control, decoder->stats));
822 decoder->fec_queue.push(std::move(msg));
823
824 decoder->fec_thread_id.join();
825 decoder->decompress_thread_id.join();
826}
struct control_state * control
struct reported_statistics_cumul stats
stats to be reported through control socket

References state_video_decoder::control, state_video_decoder::decompress_thread_id, state_video_decoder::display, state_video_decoder::fec_queue, state_video_decoder::fec_thread_id, msg, synchronized_queue< T, max_len >::push(), and state_video_decoder::stats.

Referenced by reconfigure_decoder(), and video_decoder_remove_display().

Here is the call graph for this function:

◆ wait_for_framebuffer_swap()

static void wait_for_framebuffer_swap ( struct state_video_decoder * decoder)
static

This function blocks until video frame is displayed and decoder::frame can be filled with new data. Until this point, the video frame is not considered valid.

Definition at line 406 of file video_decoders.cpp.

406 {
407 unique_lock<mutex> lk(decoder->lock);
408 decoder->buffer_swapped_cv.wait(lk, [decoder]{return decoder->buffer_swapped;});
409}

References state_video_decoder::buffer_swapped, state_video_decoder::buffer_swapped_cv, and state_video_decoder::lock.

Referenced by decode_video_frame(), and fec_thread().

Variable Documentation

◆ PADDING

int PADDING = MAX_PADDING
constexpr

Definition at line 146 of file video_decoders.cpp.

Referenced by decode_video_frame(), and decompress_thread().