UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
video_decoders.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-2004 University of Southern California
3 * Copyright (c) 2005-2024 CESNET
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, is permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 *
19 * This product includes software developed by the University of Southern
20 * California Information Sciences Institute.
21 *
22 * 4. Neither the name of the University nor of the Institute may be used
23 * to endorse or promote products derived from this software without
24 * specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
28 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
30 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
36 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
37 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
96#include "rtp/video_decoders.h"
97
98#include <cassert> // for assert
99#include <chrono> // for duration, steady_clock, durati...
100#include <cstdlib> // for free, malloc, calloc
101#include <cstring> // for NULL, memcpy, size_t, memset
102#include <algorithm> // for find, max, sort
103#include <atomic> // for __atomic_base, atomic_ulong
104#include <condition_variable> // for condition_variable
105#include <iterator> // for end
106#include <map> // for map, operator!=, _Rb_tree_cons...
107#include <memory> // for unique_ptr, allocator
108#include <mutex> // for mutex, unique_lock
109#include <set> // for set
110#include <sstream> // for basic_ostream, operator<<, cha...
111#include <string> // for basic_string, operator<<, oper...
112#include <thread> // for thread
113#include <unordered_map> // for _Node_iterator, operator==
114#include <utility> // for pair, move
115#include <vector> // for vector
116
117#include "compat/htonl.h" // for ntohl
119#include "crypto/openssl_encrypt.h" // for openssl_mode
120#include "debug.h"
121#include "host.h"
122#include "lib_common.h"
123#include "messaging.h"
124#include "module.h"
125#include "pixfmt_conv.h"
126#include "rtp/fec.h"
127#include "rtp/pbuf.h"
128#include "rtp/rtp.h"
129#include "rtp/rtp_types.h" // for video_payload_hdr_t, PT_ENCRYP...
130#include "tv.h" // for NS_IN_SEC
131#include "utils/color_out.h"
132#include "utils/macros.h"
133#include "utils/misc.h"
135#include "utils/thread.h"
136#include "utils/timed_message.h"
137#include "utils/worker.h"
138#include "video.h"
139#include "video_decompress.h"
140#include "video_display.h"
141
142#if __has_include(<libavcodec/avcodec.h>)
143#include <libavcodec/avcodec.h> // AV_INPUT_BUFFER_PADDING_SIZE
144constexpr int PADDING = std::max<int>(MAX_PADDING, AV_INPUT_BUFFER_PADDING_SIZE);
145#else
146constexpr int PADDING = MAX_PADDING;
147#endif
148
149#define MOD_NAME "[video dec.] "
150
151#define FRAMEBUFFER_NOT_READY(decoder) (decoder->frame == NULL && decoder->out_codec != VIDEO_CODEC_END)
152
153using namespace std::string_literals;
154using std::chrono::duration_cast;
155using std::chrono::high_resolution_clock;
156using std::chrono::nanoseconds;
157using std::chrono::seconds;
158using std::chrono::steady_clock;
159using std::atomic_ulong;
160using std::condition_variable;
161using std::map;
162using std::max;
163using std::mutex;
164using std::ostringstream;
165using std::pair;
166using std::set;
167using std::string;
168using std::thread;
169using std::unique_lock;
170using std::unique_ptr;
171using std::vector;
172
174
179typedef void (*change_il_t)(char *dst, char *src, int linesize, int height, void **state);
180
181// prototypes
182static bool reconfigure_decoder(struct state_video_decoder *decoder,
183 struct video_desc desc, struct pixfmt_desc comp_int_desc);
184static void check_for_mode_change(struct state_video_decoder *decoder, const uint32_t *hdr);
185static void wait_for_framebuffer_swap(struct state_video_decoder *decoder);
186static void *fec_thread(void *args);
187static void *decompress_thread(void *args);
188static void cleanup(struct state_video_decoder *decoder);
189static void decoder_process_message(struct module *);
190
191static int sum_map(map<int, int> const & m) {
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}
199
200namespace {
204enum decoder_type_t {
205 UNSET,
206 LINE_DECODER,
207 EXTERNAL_DECODER
209};
210
214struct line_decoder {
215 int base_offset;
216 long conv_num;
217 long conv_den;
218 int shifts[3];
219 decoder_t decode_line;
220 unsigned int dst_linesize;
221 unsigned int dst_pitch;
222 unsigned int src_linesize;
223};
224
225struct reported_statistics_cumul {
226 ~reported_statistics_cumul() {
227 print();
228 }
229 long long int last_buffer_number = -1;
230 steady_clock::time_point t_last = steady_clock::now();
231 unsigned long int displayed = 0, dropped = 0, corrupted = 0, missing = 0;
232 atomic_ulong fec_ok = 0, fec_corrected = 0, fec_nok = 0;
233 void print() {
234 ostringstream fec;
235 if (fec_ok + fec_nok + fec_corrected > 0) {
236 fec << " FEC noerr/OK/NOK: " << SBOLD(fec_ok) << "/" << SBOLD(fec_corrected) << "/" << SBOLD(fec_nok);
237 }
238 unsigned long total = displayed + dropped + missing;
239 LOG(LOG_LEVEL_INFO) << SUNDERLINE("Video dec stats") << " (cumulative): "
240 << SBOLD(total) << " total / "
241 << SBOLD(displayed) << " disp / "
242 << SBOLD(dropped) << " drop / "
243 << SBOLD(corrupted) << " corr / "
244 << SBOLD(missing) << " miss"
245 << fec.str() << "\n";
246 if (total > 3000 && dropped * 50 >= total) { // more than 2% frames were dropped
247 log_msg_once(LOG_LEVEL_WARNING, to_fourcc('D', 'R', 'P', 'S'), MOD_NAME "Dropped %lu of %lu frames. This may be due "
248 "to network jitter, try adding \"--param decoder-drop-policy=blocking\" if the problem persists.\n", dropped, total);
249 }
250 }
251 void update(int buffer_number) {
252 if (last_buffer_number != -1) {
253 long long int diff = buffer_number -
254 ((last_buffer_number + 1) & ((1U<<BUFNUM_BITS) - 1));
255 diff = (diff + (1U<<BUFNUM_BITS)) % (1U<<BUFNUM_BITS);
256 if (diff < (1U<<BUFNUM_BITS) / 2) {
257 missing += diff;
258 } else { // frames may have been reordered, add arbitrary 1
259 missing += 1;
260 }
261 }
262 last_buffer_number = buffer_number;
263 const auto now = steady_clock::now();
264 if (duration_cast<seconds>(now - t_last).count() >
266 print();
267 t_last = now;
268 }
269 }
270};
271
272// message definitions
273struct frame_msg {
274 inline frame_msg(struct control_state *c, struct reported_statistics_cumul &sr) : control(c), recv_frame(nullptr),
275 nofec_frame(nullptr),
276 received_pkts_cum(0), expected_pkts_cum(0),
277 stats(sr)
278 {}
279 inline ~frame_msg() {
280 if (recv_frame) {
281 int received_bytes = 0;
282 for (unsigned int i = 0; i < recv_frame->tile_count; ++i) {
283 received_bytes += sum_map(pckt_list[i]);
284 }
285 int expected_bytes = vf_get_data_len(recv_frame);
286 if (recv_frame->fec_params.type != FEC_NONE) {
287 if (is_corrupted) {
288 stats.fec_nok += 1;
289 } else {
290 if (received_bytes == expected_bytes) {
291 stats.fec_ok += 1;
292 } else {
293 stats.fec_corrected += 1;
294 }
295 }
296 }
297 stats.corrupted += is_corrupted;
298 stats.displayed += is_displayed;
299 stats.dropped += !is_displayed;
300 }
301 vf_free(recv_frame);
302 vf_free(nofec_frame);
303 }
304 struct control_state *control;
305 vector <uint32_t> buffer_num;
306 struct video_frame *recv_frame;
307 struct video_frame *nofec_frame;
308 unique_ptr<map<int, int>[]> pckt_list;
309 unsigned long long int received_pkts_cum, expected_pkts_cum;
310 struct reported_statistics_cumul &stats;
311 bool is_corrupted = false;
312 bool is_displayed = false;
313};
314
315struct main_msg_reconfigure {
316 inline main_msg_reconfigure(struct video_desc d,
317 unique_ptr<frame_msg> &&f,
318 bool force = false,
319 struct pixfmt_desc pd = {}) :
320 desc(d),
321 last_frame(std::move(f)),
322 force(force),
323 compress_internal_prop(pd) {}
324
325 struct video_desc desc;
326 unique_ptr<frame_msg> last_frame;
327 bool force;
328 struct pixfmt_desc compress_internal_prop;
329};
330}
331
336{
348 struct module mod;
349 struct control_state *control = {};
350
356
357 struct video_frame *frame = NULL;
358
359 struct display *display = NULL;
361 vector<codec_t> native_codecs;
365
366 unsigned int max_substreams = 0;
368 vector<void *> change_il_state;
369
370 mutex lock;
371
372 enum decoder_type_t decoder_type = {};
373 struct line_decoder *line_decoder = NULL;
375 vector<struct state_decompress *> decompress_state;
377 bool buffer_swapped = true;
379 condition_variable buffer_swapped_cv;
380
382
384 int pitch = 0;
385
387
389 bool merged_fb = false;
390
392
393 synchronized_queue<main_msg_reconfigure *, -1> msg_queue;
394
395 const struct openssl_decrypt_info *dec_funcs = NULL;
396 struct openssl_decrypt *decrypt = NULL;
397
398 struct reported_statistics_cumul stats = {};
399};
400
406static void wait_for_framebuffer_swap(struct state_video_decoder *decoder) {
407 unique_lock<mutex> lk(decoder->lock);
408 decoder->buffer_swapped_cv.wait(lk, [decoder]{return decoder->buffer_swapped;});
409}
410
411#define ENCRYPTED_ERR "Receiving encrypted video data but " \
412 "no decryption key entered!\n"
413#define NOT_ENCRYPTED_ERR "Receiving unencrypted video data " \
414 "while expecting encrypted.\n"
415
416static void *fec_thread(void *args) {
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}
569
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}
583
586 int pos;
590 unsigned char *out;
591 struct pixfmt_desc internal_prop; // set only if probing (ret == DECODER_GOT_CODEC)
592};
593static void *decompress_worker(void *data)
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}
609
610ADD_TO_PARAM("decoder-drop-policy",
611 "* decoder-drop-policy=blocking|nonblock|<sec>\n"
612 " Force specified blocking policy (default nonblock).\n"
613 " <sec> - specifies frame timeout in seconds (can have suffixes, eg. \"20ms\")\n");
614static void *decompress_thread(void *args) {
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}
742
744{
745 decoder->video_mode = video_mode;
748}
749
763 struct display *display, const char *encryption)
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}
793
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}
810
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}
827
828static auto codec_list_to_str(vector<codec_t> const &codecs) {
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}
840
841ADD_TO_PARAM("decoder-use-codec",
842 "* decoder-use-codec=<codec>\n"
843 " Use specified pixel format for decoding (eg. v210). This overrides automatic\n"
844 " choice. The pixel format must be supported by the video display. Use 'help' to see\n"
845 " available options for a display (eg.: 'uv -d gl --param decoder-use-codec=help').\n"
846 "* decoder-use-codec=!<codec>\n"
847 " Blacklist specified pixel format ('!<codec' may need to be quoted).\n");
860{
861 assert(display != NULL);
862 assert(decoder->display == NULL);
863
864 int ret;
865
866 decoder->display = display;
867
869 size_t len = sizeof native_codecs;
871 decoder->native_codecs.clear();
872 if (!ret) {
873 log_msg(LOG_LEVEL_ERROR, "Failed to query codecs from video display.\n");
874 } else {
875 for (size_t i = 0; i < len / sizeof(codec_t); ++i) {
876 decoder->native_codecs.push_back(native_codecs[i]);
877 }
878 }
879 if (get_commandline_param("decoder-use-codec")) {
880 const char *codec_str = get_commandline_param("decoder-use-codec");
881 bool blacklist_codec = false;
882 if (codec_str[0] == '!') {
883 blacklist_codec = true;
884 codec_str += 1;
885 }
886 codec_t req_codec = get_codec_from_name(codec_str);
887 if ("help"s == codec_str) {
888 LOG(LOG_LEVEL_NOTICE) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(decoder->native_codecs) << "\n";
889 return false;
890 }
891 if (req_codec == VIDEO_CODEC_NONE) {
892 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong decoder codec spec: %s.\n", codec_str);
893 LOG(LOG_LEVEL_INFO) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(decoder->native_codecs) << "\n";
894 return false;
895 }
896 if (blacklist_codec) {
897 auto to_erase = find(decoder->native_codecs.begin(),
898 decoder->native_codecs.end(),
899 req_codec);
900 if (to_erase != decoder->native_codecs.end()) {
901 decoder->native_codecs.erase(to_erase);
902 }
903 } else if (find(decoder->native_codecs.begin(),
904 decoder->native_codecs.end(),
905 req_codec) != end(decoder->native_codecs)) {
906 decoder->native_codecs.clear();
907 decoder->native_codecs.push_back(req_codec);
908 } else {
909 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Display doesn't support requested codec: %s.\n", codec_str);
910 LOG(LOG_LEVEL_INFO) << MOD_NAME << "Supported codecs for current display are: " << codec_list_to_str(decoder->native_codecs) << "\n";
911 return false;
912 }
913 }
914
915 free(decoder->disp_supported_il);
916 decoder->disp_supported_il_cnt = 20 * sizeof(enum interlacing_t);
917 decoder->disp_supported_il = (enum interlacing_t*) calloc(decoder->disp_supported_il_cnt,
918 sizeof(enum interlacing_t));
920 if(ret) {
921 decoder->disp_supported_il_cnt /= sizeof(enum interlacing_t);
922 } else {
923 enum interlacing_t tmp[] = { PROGRESSIVE, INTERLACED_MERGED, SEGMENTED_FRAME}; /* default if not said othervise */
924 memcpy(decoder->disp_supported_il, tmp, sizeof(tmp));
925 decoder->disp_supported_il_cnt = sizeof(tmp) / sizeof(enum interlacing_t);
926 }
927
929
930 return true;
931}
932
942{
943 if (decoder->display) {
945 if (decoder->frame) {
946 display_put_frame(decoder->display, decoder->frame, PUTF_DISCARD);
947 decoder->frame = NULL;
948 }
949 decoder->display = NULL;
950 memset(&decoder->display_desc, 0, sizeof(decoder->display_desc));
951 }
952}
953
954static void cleanup(struct state_video_decoder *decoder)
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}
971
977{
978 if(!decoder)
979 return;
980
981 if (decoder->dec_funcs) {
982 decoder->dec_funcs->destroy(decoder->decrypt);
983 }
984
986
987 cleanup(decoder);
988
989 free(decoder->disp_supported_il);
990
991 delete decoder;
992}
993
1005static vector<pair<struct pixfmt_desc, codec_t>> video_decoder_order_output_codecs(struct pixfmt_desc comp_int_prop, vector<codec_t> const &display_codecs)
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}
1063
1074 decoder_t *decode_line, struct pixfmt_desc comp_int_prop)
1075{
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}
1151
1161static change_il_t select_il_func(enum interlacing_t in_il, enum interlacing_t *supported,
1162 int il_out_cnt, /*out*/ enum interlacing_t *out_il)
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}
1195
1206static bool reconfigure_decoder(struct state_video_decoder *decoder,
1207 struct video_desc desc, struct pixfmt_desc comp_int_prop)
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}
1404
1405bool parse_video_hdr(const uint32_t *hdr, struct video_desc *desc)
1406{
1407 uint32_t tmp;
1408 int fps_pt, fpsd, fd, fi;
1409
1410 tmp = ntohl(hdr[0]);
1411 desc->tile_count = (tmp >> 22) + 1; // a bit hacky - assuming this packet is from last substream
1412
1413 desc->width = ntohl(hdr[3]) >> 16;
1414 desc->height = ntohl(hdr[3]) & 0xffff;
1417 log_msg(LOG_LEVEL_ERROR, "Unknown FourCC \"%.4s\"!\n",
1418 (const char *)&hdr[4]);
1419 return false;
1420 }
1421
1422 tmp = ntohl(hdr[5]);
1423 desc->interlacing = (enum interlacing_t) (tmp >> 29);
1424 fps_pt = (tmp >> 19) & 0x3ff;
1425 fpsd = (tmp >> 15) & 0xf;
1426 fd = (tmp >> 14) & 0x1;
1427 fi = (tmp >> 13) & 0x1;
1428
1429 desc->fps = compute_fps(fps_pt, fpsd, fd, fi);
1430
1431 if (desc->fps == -1) {
1432 log_msg_once(LOG_LEVEL_WARNING, to_fourcc('U', 'F', 'P', 'S'), MOD_NAME "Unsupported FPS received (newer UG?), setting to 30.\n");
1433 desc->fps = 30.0;
1434 }
1435
1436 return true;
1437}
1438
1439static void reconfigure_helper(struct state_video_decoder *decoder,
1440 struct video_desc network_desc,
1441 struct pixfmt_desc comp_int_desc)
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}
1453
1454static void reconfigure_if_needed(struct state_video_decoder *decoder,
1455 struct video_desc network_desc,
1456 struct pixfmt_desc comp_int_desc)
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}
1467
1474static void check_for_mode_change(struct state_video_decoder *decoder,
1475 const uint32_t *hdr)
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}
1489
1490#define ERROR_GOTO_CLEANUP ret = false; goto cleanup;
1491#define max(a, b) (((a) > (b))? (a): (b))
1492
1502int decode_video_frame(struct coded_data *cdata, void *decoder_data, struct pbuf_stats *stats)
1503{
1504 struct vcodec_state *pbuf_data = (struct vcodec_state *) decoder_data;
1505 struct state_video_decoder *decoder = pbuf_data->decoder;
1506
1507 bool ret = true;
1508 int prints=0;
1509 int max_substreams = decoder->max_substreams;
1510
1511 vector<uint32_t> buffer_num(max_substreams);
1512 // the following is just FEC related optimalization - normally we fill up
1513 // allocated buffers when we have compressed data. But in case of FEC, there
1514 // is just the FEC buffer present, so we point to it instead to copying
1515 struct video_frame *frame = vf_alloc(max_substreams);
1517 unique_ptr<map<int, int>[]> pckt_list(new map<int, int>[max_substreams]);
1518
1519 int buffer_number = 0;
1520 bool buffer_swapped = false;
1521
1522 // We have no framebuffer assigned, exitting
1523 if(!decoder->display) {
1524 vf_free(frame);
1525 return false;
1526 }
1527
1528 main_msg_reconfigure *msg_reconf;
1529 while ((msg_reconf = decoder->msg_queue.pop(true /* nonblock */))) {
1530 if (msg_reconf->force) {
1531 reconfigure_helper(decoder, msg_reconf->desc,
1532 msg_reconf->compress_internal_prop);
1533 log_msg(LOG_LEVEL_VERBOSE, "forced reconf\n");
1534 } else {
1536 decoder, msg_reconf->desc,
1537 msg_reconf->compress_internal_prop);
1538 }
1539 if (msg_reconf->last_frame) {
1540 decoder->fec_queue.push(std::move(msg_reconf->last_frame));
1541 }
1542 delete msg_reconf;
1543 }
1544
1545 frame->ssrc = cdata->data->ssrc;
1546 frame->timestamp = cdata->data->ts;
1547 int pt = cdata->data->pt;
1548 if (PT_VIDEO_HAS_FEC(pt)) {
1549 const uint32_t *hdr = (uint32_t *)(void *)cdata->data->data;
1550 const uint32_t tmp = ntohl(hdr[3]);
1551 const int k = tmp >> 19;
1552 const int m = 0x1fff & (tmp >> 6);
1553 const int c = 0x3f & tmp;
1554 const int seed = ntohl(hdr[4]);
1555 frame->fec_params =
1556 fec_desc(fec::fec_type_from_pt(pt), k, m, c, seed);
1557 }
1558
1559 while (cdata != NULL) {
1560 int len;
1561 const char *data;
1562 rtp_packet *pckt = cdata->data;
1563 enum openssl_mode crypto_mode = MODE_AES128_NONE;
1564
1565 pt = pckt->pt;
1566 const uint32_t *hdr = (uint32_t *)(void *) pckt->data;
1567 const uint32_t data_pos = ntohl(hdr[1]);
1568 uint32_t tmp = ntohl(hdr[0]);
1569 const uint32_t substream = tmp >> 22;
1570 buffer_number = tmp & 0x3fffff;
1571 const int buffer_length = ntohl(hdr[2]);
1572
1573 if (PT_VIDEO_IS_ENCRYPTED(pt)) {
1574 if(!decoder->decrypt) {
1577 }
1578 } else {
1579 if(decoder->decrypt) {
1582 }
1583 }
1584
1585 switch (pt) {
1586 case PT_VIDEO:
1587 len = pckt->data_len - sizeof(video_payload_hdr_t);
1588 data = (const char *) hdr + sizeof(video_payload_hdr_t);
1589 break;
1590 case PT_VIDEO_RS:
1591 case PT_VIDEO_LDGM:
1592 len = pckt->data_len - sizeof(fec_payload_hdr_t);
1593 data = (const char *) hdr + sizeof(fec_payload_hdr_t);
1594 break;
1595 case PT_ENCRYPT_VIDEO:
1598 {
1599 size_t media_hdr_len = pt == PT_ENCRYPT_VIDEO ? sizeof(video_payload_hdr_t) : sizeof(fec_payload_hdr_t);
1600 len = pckt->data_len - sizeof(crypto_payload_hdr_t) - media_hdr_len;
1601 data = (const char *)hdr + sizeof(crypto_payload_hdr_t) + media_hdr_len;
1602 uint32_t crypto_hdr = ntohl(*(const uint32_t *)(const void *)((const char *)hdr + media_hdr_len));
1603 crypto_mode = (enum openssl_mode) (crypto_hdr >> 24);
1604 if (crypto_mode == MODE_AES128_NONE || crypto_mode > MODE_AES128_MAX) {
1605 log_msg(LOG_LEVEL_WARNING, "Unknown cipher mode: %d\n", (int) crypto_mode);
1606 ret = false;
1607 goto cleanup;
1608 }
1609 }
1610 break;
1611 default:
1612 if (pt == PT_Unassign_Type95) {
1613 log_msg_once(LOG_LEVEL_WARNING, to_fourcc('U', 'V', 'P', 'T'), MOD_NAME "Unassigned PT 95 received, ignoring.\n");
1614 } else {
1615 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Unknown packet type: " << pckt->pt << ".\n";
1616 }
1617 ret = false;
1618 goto cleanup;
1619 }
1620
1621 if ((int) substream >= max_substreams) {
1622 log_msg(LOG_LEVEL_WARNING, "[decoder] received substream ID %d. Expecting at most %d substreams. Did you set -M option?\n",
1623 substream, max_substreams);
1624 // the guess is valid - we start with highest substream number (anytime - since it holds a m-bit)
1625 // in next iterations, index is valid
1626 enum video_mode video_mode =
1627 guess_video_mode(substream + 1);
1628 if (video_mode != VIDEO_UNKNOWN) {
1629 log_msg(LOG_LEVEL_NOTICE, "[decoder] Guessing mode: ");
1631 decoder->received_vid_desc.width = 0; // just for sure, that we reconfigure in next iteration
1632 log_msg(LOG_LEVEL_NOTICE, "%s. Check if it is correct.\n", get_video_mode_description(decoder->video_mode));
1633 } else {
1634 log_msg(LOG_LEVEL_FATAL, "[decoder] Unknown video mode!\n");
1635 handle_error(1);
1636 }
1637 // we need skip this frame (variables are illegal in this iteration
1638 // and in case that we got unrecognized number of substreams - exit
1639 ret = false;
1640 goto cleanup;
1641 }
1642
1643 char plaintext[RTP_MAX_PACKET_LEN]; // will be actually shorter
1644 if (PT_VIDEO_IS_ENCRYPTED(pt)) {
1645 int data_len;
1646
1647 if((data_len = decoder->dec_funcs->decrypt(decoder->decrypt,
1648 data, len,
1649 (const char *) hdr, pt == PT_ENCRYPT_VIDEO ?
1650 sizeof(video_payload_hdr_t) : sizeof(fec_payload_hdr_t),
1651 plaintext, crypto_mode)) == 0) {
1652 goto next_packet;
1653 }
1654 data = (char *) plaintext;
1655 len = data_len;
1656 }
1657
1658 if (!PT_VIDEO_HAS_FEC(pt))
1659 {
1660 /* Critical section
1661 * each thread *MUST* wait here if this condition is true
1662 */
1663 check_for_mode_change(decoder, hdr);
1664
1665 // hereafter, display framebuffer can be used, so we
1666 // check if we got it
1667 if (FRAMEBUFFER_NOT_READY(decoder)) {
1668 vf_free(frame);
1669 return false;
1670 }
1671 }
1672
1673 buffer_num[substream] = buffer_number;
1674 frame->tiles[substream].data_len = buffer_length;
1675 pckt_list[substream][data_pos] = len;
1676
1677 if ((pt == PT_VIDEO || pt == PT_ENCRYPT_VIDEO) && decoder->decoder_type == LINE_DECODER) {
1678 struct tile *tile = NULL;
1679 if(!buffer_swapped) {
1681 buffer_swapped = true;
1682 unique_lock<mutex> lk(decoder->lock);
1683 decoder->buffer_swapped = false;
1684 }
1685
1686 if (!decoder->merged_fb) {
1687 tile = vf_get_tile(decoder->frame, substream);
1688 } else {
1689 tile = vf_get_tile(decoder->frame, 0);
1690 }
1691
1692 struct line_decoder *line_decoder =
1693 &decoder->line_decoder[substream];
1694
1695 /* End of critical section */
1696
1697 /* MAGIC, don't touch it, you definitely break it
1698 * *source* is data from network, *destination* is frame buffer
1699 */
1700
1701 /* compute Y pos in source frame and convert it to
1702 * byte offset in the destination frame
1703 */
1704 int y = (data_pos / line_decoder->src_linesize) * line_decoder->dst_pitch;
1705
1706 /* compute X pos in source frame */
1707 int s_x = data_pos % line_decoder->src_linesize;
1708
1709 /* convert X pos from source frame into the destination frame.
1710 * it is byte offset from the beginning of a line.
1711 */
1712 int d_x = s_x * line_decoder->conv_num / line_decoder->conv_den;
1713
1714 /* pointer to data payload in packet */
1715 auto *source = (const unsigned char *)(data);
1716
1717 /* copy whole packet that can span several lines.
1718 * we need to clip data (v210 case) or center data (RGBA, R10k cases)
1719 */
1720 while (len > 0) {
1721 /* len id payload length in source BPP
1722 * decoder needs len in destination BPP, so convert it
1723 */
1724 int l = len * line_decoder->conv_num / line_decoder->conv_den;
1725
1726 /* do not copy multiple lines, we need to
1727 * copy (& clip, center) line by line
1728 */
1729 if (l + d_x > (int) line_decoder->dst_linesize) {
1730 l = line_decoder->dst_linesize - d_x;
1731 }
1732
1733 /* compute byte offset in destination frame */
1734 const uint32_t offset = y + d_x;
1735
1736 /* watch the SEGV */
1737 if (l + line_decoder->base_offset + offset <= tile->data_len) {
1738 /*decode frame:
1739 * we have offset for destination
1740 * we update source contiguously
1741 * we pass {r,g,b}shifts */
1742 line_decoder->decode_line((unsigned char*)tile->data + line_decoder->base_offset + offset, source, l,
1743 line_decoder->shifts[0], line_decoder->shifts[1],
1744 line_decoder->shifts[2]);
1745 /* we decoded one line (or a part of one line) to the end of the line
1746 * so decrease *source* len by 1 line (or that part of the line */
1747 len -= line_decoder->src_linesize - s_x;
1748 /* jump in source by the same amount */
1749 source += line_decoder->src_linesize - s_x;
1750 } else {
1751 /* this should not ever happen as we call reconfigure before each packet
1752 * iff reconfigure is needed. But if it still happens, something is terribly wrong
1753 * say it loudly
1754 */
1755 if((prints % 100) == 0) {
1756 log_msg(LOG_LEVEL_ERROR, "WARNING!! Discarding input data as frame buffer is too small.\n"
1757 "Well this should not happened. Expect troubles pretty soon.\n");
1758 }
1759 prints++;
1760 len = 0;
1761 }
1762 /* each new line continues from the beginning */
1763 d_x = 0; /* next line from beginning */
1764 s_x = 0;
1765 y += line_decoder->dst_pitch; /* next line */
1766 }
1767 } else { /* PT_VIDEO_LDGM or external decoder */
1768 if(!frame->tiles[substream].data) {
1769 frame->tiles[substream].data = (char *) malloc(buffer_length + PADDING);
1770 }
1771
1772 if (data_pos + len > (unsigned) buffer_length) {
1773 if((prints % 100) == 0) {
1774 log_msg(LOG_LEVEL_ERROR, "WARNING!! Discarding input data as frame buffer is too small.\n"
1775 "Well this should not happened. Expect troubles pretty soon.\n");
1776 }
1777 prints++;
1778 len = max<int>(0, buffer_length - data_pos);
1779 }
1780 memcpy(frame->tiles[substream].data + data_pos,
1781 (const unsigned char *)data, len);
1782 }
1783
1784next_packet:
1785 cdata = cdata->nxt;
1786 }
1787
1788 if (FRAMEBUFFER_NOT_READY(decoder) && (pt == PT_VIDEO || pt == PT_ENCRYPT_VIDEO)) {
1789 ret = false;
1790 goto cleanup;
1791 }
1792
1793 assert(ret);
1794
1798 if (decoder->decoder_type != LINE_DECODER) {
1799 for(int i = 0; i < max_substreams; ++i) {
1800 unsigned int last_end = 0;
1801 for (auto const & packets : pckt_list[i]) {
1802 unsigned int start = packets.first;
1803 unsigned int len = packets.second;
1804 if (last_end < start) {
1805 memset(frame->tiles[i].data + last_end, 0, start - last_end);
1806 }
1807 last_end = start + len;
1808 }
1809 if (last_end < frame->tiles[i].data_len) {
1810 memset(frame->tiles[i].data + last_end, 0, frame->tiles[i].data_len - last_end);
1811 }
1812 }
1813 }
1814
1815 {
1816 unsigned int frame_size = 0;
1817 for (int i = 0; i < max_substreams; ++i) {
1818 frame_size += frame->tiles[i].data_len;
1819 }
1820 pbuf_data->max_frame_size =
1821 max(pbuf_data->max_frame_size, frame_size);
1822 // format message
1823 unique_ptr <frame_msg> fec_msg (new frame_msg(decoder->control, decoder->stats));
1824 fec_msg->buffer_num = std::move(buffer_num);
1825 fec_msg->recv_frame = frame;
1826 frame = NULL;
1827 fec_msg->pckt_list = std::move(pckt_list);
1828 fec_msg->received_pkts_cum = stats->received_pkts_cum;
1829 fec_msg->expected_pkts_cum = stats->expected_pkts_cum;
1830
1831 auto t0 = std::chrono::high_resolution_clock::now();
1832 decoder->fec_queue.push(std::move(fec_msg));
1833 auto t1 = std::chrono::high_resolution_clock::now();
1834 double tpf = 1.0 / decoder->display_desc.fps;
1835 if (std::chrono::duration_cast<std::chrono::duration<double>>(t1 - t0).count() > tpf && decoder->stats.displayed > 20) {
1836 decoder->slow_msg.print("Your computer may be too SLOW to play this !!!\n");
1837 }
1838
1839 }
1840cleanup:
1841 ;
1842 if (ret) {
1843 vf_free(frame);
1844 }
1845 pbuf_data->decoded++;
1846
1847 decoder->stats.update(buffer_number);
1848
1849 return ret;
1850}
1851
1852static void decoder_process_message(struct module *m)
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}
1872
void ** state
struct video_desc desc
struct video_frame * frame
int void size_t * len
struct video_frame * vf_alloc(int count)
Allocates blank video frame.
void vf_free(struct video_frame *buf)
Frees video_frame structure.
void vf_data_deleter(struct video_frame *buf)
int vc_get_linesize(unsigned int width, codec_t codec)
const char * get_codec_name(codec_t codec)
codec_t get_codec_from_name(const char *name)
#define MOD_NAME
Definition audio.cpp:110
simple blocking synchronized queue
T pop(bool nonblocking=false)
void push(T const &message)
#define SBOLD(x)
Definition color_out.h:80
#define SUNDERLINE(x)
Definition color_out.h:81
static void new_message(struct module *m)
static __device__ const float offset
Definition cuda_dxt.cu:139
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
void log_msg_once(int level, uint32_t id, const char *msg,...)
Definition debug.cpp:137
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define verbose_msg(...)
Definition debug.h:90
#define LOG(level)
Definition debug.h:313
#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
#define CUMULATIVE_REPORTS_INTERVAL
Definition debug.h:110
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
#define PUTF_NONBLOCK
#define PITCH_DEFAULT
default pitch, i. e. respective linesize
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.
bool display_ctl_property(struct display *d, int property, void *val, size_t *len)
Gets property from video display.
#define PUTF_DISCARD
#define PUTF_BLOCKING
struct video_frame * display_get_frame(struct display *d)
Returns video framebuffer which will be written to.
@ 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_SUPPORTED_IL_MODES
display supported interlacing modes - enum interlacing_t[]
@ DISPLAY_PROPERTY_VIDEO_MODE
requested video mode - int (one of display_prop_vid_mode)
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
@ 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
void module_init_default(struct module *module_data)
Definition module.c:48
void module_register(struct module *module_data, struct module *parent)
Definition module.c:82
struct module * get_module(struct module *root, const char *const_path)
Definition module.c:264
void module_done(struct module *module_data)
Definition module.c:93
struct module * get_root_module(struct module *node)
Definition module.c:203
@ MODULE_CLASS_DECODER
Definition module.h:95
decompress_status
#define DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME
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.
int decompress_get_property(struct state_decompress *s, int property, void *val, size_t *len)
void decompress_done(struct state_decompress *s)
int decompress_reconfigure(struct state_decompress *s, struct video_desc desc, int rshift, int gshift, int bshift, int pitch, codec_t out_codec)
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_GOT_CODEC
Internal pixel format was determined.
@ DECODER_NO_FRAME
@ DECODER_UNSUPP_PIXFMT
Decoder can't decode to selected out_codec.
@ DECODER_GOT_FRAME
void video_decoder_destroy(struct state_video_decoder *decoder)
Destroys decoder created with decoder_init()
bool parse_video_hdr(const uint32_t *hdr, struct video_desc *desc)
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.
int decode_video_frame(struct coded_data *cdata, void *decoder_data, struct pbuf_stats *stats)
Decodes a participant buffer representing one video frame.
int count
Definition hd-rum.c:44
void handle_error(int status)
Definition host.cpp:1184
void exit_uv(int status)
Definition host.cpp:625
const char * get_commandline_param(const char *key)
Definition host.cpp:894
std::unordered_map< std::string, std::string > commandline_params
Definition host.cpp:184
#define ADD_TO_PARAM(param, doc)
Definition host.h:203
last_frame
Definition interlace.c:52
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
volatile int log_level
Definition debug.cpp:65
const void * load_library(const char *name, enum library_class cls, int abi_version)
@ LIBRARY_CLASS_UNDEFINED
Definition lib_common.h:74
#define to_fourcc(a, b, c, d)
Creates FourCC word.
Definition macros.h:114
void free_message(struct message *msg, struct response *r)
struct response * new_response(int status, const char *text)
struct response * send_message_to_receiver(struct module *receiver, struct message *msg)
struct message * check_message(struct module *mod)
void free_response(struct response *r)
#define RESPONSE_OK
Definition messaging.h:57
@ RECEIVER_MSG_VIDEO_PROP_CHANGED
Definition messaging.h:110
#define RESPONSE_NOT_FOUND
Definition messaging.h:61
double unit_evaluate_dbl(const char *str, bool case_sensitive, const char **endptr)
Definition misc.cpp:102
#define OPENSSL_DECRYPT_ABI_VERSION
openssl_mode
only GCM provides autenticity, other modes only check integrity (CRC)
@ MODE_AES128_NONE
@ MODE_AES128_MAX
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 * decoder_t
Definition pixfmt_conv.h:96
decoder_func_t vc_memcpy
dummy conversion - ptr to it returned if no conversion needed
#define DEFAULT_RGB_SHIFT_INIT
Definition pixfmt_conv.h:73
rtp_packet
Definition rtp.h:126
#define RTP_MAX_PACKET_LEN
Definition rtp.h:61
struct msghdr msg
#define PT_ENCRYPT_VIDEO
Definition rtp_types.h:69
#define PT_ENCRYPT_VIDEO_RS
Definition rtp_types.h:74
#define BUFNUM_BITS
Definition rtp_types.h:171
#define PT_VIDEO
Definition rtp_types.h:66
uint32_t fec_payload_hdr_t[5]
Definition rtp_types.h:152
#define PT_VIDEO_IS_ENCRYPTED(pt)
Definition rtp_types.h:169
#define PT_Unassign_Type95
Definition rtp_types.h:77
#define PT_VIDEO_LDGM
Definition rtp_types.h:68
uint32_t crypto_payload_hdr_t[1]
Definition rtp_types.h:161
#define PT_VIDEO_RS
Definition rtp_types.h:72
#define PT_ENCRYPT_VIDEO_LDGM
Definition rtp_types.h:73
#define PT_VIDEO_HAS_FEC(pt)
Definition rtp_types.h:168
uint32_t video_payload_hdr_t[6]
Definition rtp_types.h:107
HRESULT __stdcall(* func)()
Definition screen_win.c:325
static void start()
Definition sdp.c:202
static void cleanup()
Definition sdp.c:195
const char * parent
Definition settings.cpp:198
Definition rtp.c:206
rtp_packet * data
Definition pbuf.h:75
struct coded_data * nxt
Definition pbuf.h:72
struct video_frame * compressed
decompress_status ret
unsigned char * out
struct pixfmt_desc internal_prop
struct state_video_decoder * decoder
This struct represents initialized video display state.
Definition fec.h:51
static fec * create_from_desc(struct fec_desc) noexcept
Definition fec.cpp:107
static enum fec_type fec_type_from_pt(int pt)
Definition fec.cpp:157
virtual bool decode(char *in, int in_len, char **out, int *out_len, const std::map< int, int > &)=0
Definition hd-rum.c:27
enum module_class cls
Definition module.h:115
void * priv_data
Definition module.h:126
notify_t new_message
if set, notifies module that new message is in queue, receiver lock is hold during the call
Definition module.h:119
struct module * parent
Definition module.h:116
char text[8192]
Definition messaging.h:157
int(* init)(struct openssl_decrypt **state, const char *passphrase)
void(* destroy)(struct openssl_decrypt *state)
int(* decrypt)(struct openssl_decrypt *decrypt, const char *ciphertext, int ciphertext_len, const char *aad, int aad_len, char *plaintext, enum openssl_mode mode)
long long int received_pkts_cum
Definition pbuf.h:79
long long int expected_pkts_cum
Definition pbuf.h:80
int depth
bit depth; 0 means that whole struct is undefined
Definition types.h:140
enum interlacing_t * disp_supported_il
display supported interlacing mode
struct line_decoder * line_decoder
is neeeded, use this structure
struct display * display
synchronized_queue< unique_ptr< frame_msg >, 1 > fec_queue
enum decoder_type_t decoder_type
how will the video data be decoded
size_t disp_supported_il_cnt
count of disp_supported_il
const struct openssl_decrypt_info * dec_funcs
decrypt state
struct video_frame * frame
vector< codec_t > native_codecs
list of display native codecs
synchronized_queue< unique_ptr< frame_msg >, 1 > decompress_queue
struct openssl_decrypt * decrypt
decrypt state
struct video_desc received_vid_desc
description of the network video
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
bool accepts_corrupted_frame
whether we should pass corrupted frame to decompress
timed_message< LOG_LEVEL_WARNING > slow_msg
shows warning ony in certain interval
unsigned int max_substreams
maximal number of expected substreams
struct pixfmt_desc received_int_desc
compression int desc
struct control_state * control
struct reported_statistics_cumul stats
stats to be reported through control socket
struct video_desc display_desc
description of the mode that display is currently configured to
vector< struct state_decompress * > decompress_state
state of the decompress (for every substream)
vector< void * > change_il_state
enum video_mode video_mode
video mode set for this decoder
synchronized_queue< main_msg_reconfigure *, -1 > msg_queue
state_video_decoder(struct module *parent)
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
void print(const char *str)
unsigned int decoded
Definition pbuf.h:95
unsigned int max_frame_size
Definition pbuf.h:93
struct state_video_decoder * decoder
Definition pbuf.h:92
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
enum interlacing_t interlacing
Definition types.h:184
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* data_deleter)(struct video_frame *)
Definition types.h:256
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
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
struct video_frame_callbacks callbacks
Definition types.h:324
struct fec_desc fec_params
Definition types.h:328
codec_t color_spec
Definition types.h:306
void set_thread_name(const char *name)
Definition thread.c:72
#define NS_IN_SEC
Definition tv.h:92
video_mode
Definition types.h:354
@ VIDEO_UNKNOWN
unspecified video mode
Definition types.h:355
@ VIDEO_NORMAL
normal video (one tile)
Definition types.h:356
@ FEC_NONE
Definition types.h:201
interlacing_t
Definition types.h:163
@ 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
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ SEGMENTED_FRAME
Segmented frame. Contains the same data as progressive frame.
Definition types.h:168
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167
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
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ VIDEO_CODEC_END
Definition types.h:111
@ VIDEO_CODEC_COUNT
count of known video codecs (including VIDEO_CODEC_NONE)
Definition types.h:108
@ 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
enum video_mode guess_video_mode(int num_substreams)
Tries to guess video mode from number of substreams.
Definition video.cpp:123
int get_video_mode_tiles_x(enum video_mode video_mode)
Definition video.cpp:108
const char * get_video_mode_description(enum video_mode video_mode)
Definition video.cpp:118
int get_video_mode_tiles_y(enum video_mode video_mode)
Definition video.cpp:113
This is an umbrella header for video functions.
bool codec_is_hw_accelerated(codec_t codec)
const char * get_pixdesc_desc(struct pixfmt_desc desc)
struct pixfmt_desc get_pixfmt_desc(codec_t pixfmt)
bool pixdesc_equals(struct pixfmt_desc desc_a, struct pixfmt_desc desc_b)
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
codec_t get_codec_from_fcc(uint32_t fourcc)
#define MAX_BPS
maximal (average) number of pixels per know pixel formats (up-round if needed)
Definition video_codec.h:62
#define MAX_PADDING
Definition video_codec.h:63
static struct @76 codecs[]
static void * decompress_thread(void *args)
static bool blacklist_current_out_codec(struct state_video_decoder *decoder)
static void reconfigure_helper(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)
#define FRAMEBUFFER_NOT_READY(decoder)
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 auto codec_list_to_str(vector< codec_t > const &codecs)
static int sum_map(map< int, int > const &m)
static void video_decoder_stop_threads(struct state_video_decoder *decoder)
This function stops running threads.
#define ENCRYPTED_ERR
static bool reconfigure_decoder(struct state_video_decoder *decoder, struct video_desc desc, struct pixfmt_desc comp_int_desc)
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)
constexpr int PADDING
static void decoder_process_message(struct module *)
void(* change_il_t)(char *dst, char *src, int linesize, int height, void **state)
#define NOT_ENCRYPTED_ERR
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)
#define MOD_NAME
static void video_decoder_start_threads(struct state_video_decoder *decoder)
starts decompress and ldmg threads
static void reconfigure_if_needed(struct state_video_decoder *decoder, struct video_desc network_desc, struct pixfmt_desc comp_int_desc)
static void check_for_mode_change(struct state_video_decoder *decoder, const uint32_t *hdr)
static void decoder_set_video_mode(struct state_video_decoder *decoder, enum video_mode video_mode)
static void wait_for_framebuffer_swap(struct state_video_decoder *decoder)
static void * decompress_worker(void *data)
static void * fec_thread(void *args)
#define ERROR_GOTO_CLEANUP
#define max(a, b)
Video RTP decoder.
API for video decompress drivers.
bool display_reconfigure(struct display *d, struct video_desc desc, enum video_mode video_mode)
Reconfigure display to new video format.
void il_merged_to_upper(char *dst, char *src, int linesize, int height, void **state)
Converts interlaced merged to upper-field-first.
bool video_desc_eq_excl_param(struct video_desc a, struct video_desc b, unsigned int excluded_params)
Compares two video descriptions.
double compute_fps(int fps, int fpsd, int fd, int fi)
Computes FPS as a double from packet fields.
unsigned int vf_get_data_len(struct video_frame *f)
void il_lower_to_merged(char *dst, char *src, int linesize, int height, void **stored_state)
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].
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.
void il_upper_to_merged(char *dst, char *src, int linesize, int height, void **state)
Converts upper-field-first to interlaced merged.
#define PARAM_TILE_COUNT
Definition video_frame.h:68
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