sylware / nyanmp (public) (License: AGPLv3) (since 2020-02-12) (hash sha1)
intended to become a collection of media players for gnu/linux based on ffmpeg, alsa, vulkan, x11, wayland, etc.
List of commits:
Subject Hash Author Date (UTC)
npv:restore pause/seeking, add tmp info command cf4da499db3123561aacd8732cd1eb97b9146e55 Sylvain BERTRAND 2020-05-27 17:31:56
npv:bugs, finer-grained locking, pthread_cond, etc 8bd06c28483adc9986b8b51612e609115948943d Sylvain BERTRAND 2020-05-26 23:59:16
npv: fix obvious multithread bug db4f3801c2185b8da1d9fb3f4b3da3d2ab92ea13 Sylvain BERTRAND 2020-05-24 21:42:08
remove old commented code d3701c5734aceda5c46cd5f60281cc524c55e4a3 Sylvain BERTRAND 2020-05-24 19:29:04
npv: video: handle latency spikes on main thread f629068cb27b47530058f81fc2b065b0786b4afa Sylvain BERTRAND 2020-05-24 18:11:07
npv: media pipeline 30efa7c8f2574c676d9d41b8bf5678d5725b8721 Sylvain BERTRAND 2020-05-24 17:40:23
alsa-lib warning 54b6dc9b912bb9509ba35405f15a623632adf784 Sylvain BERTRAND 2020-05-19 14:32:04
npv: proper handling of snd_pcm_drain() db7959bdd5f7ed921773aef42984b1c982575ad4 Sylvain BERTRAND 2020-05-15 15:00:13
proper handling of snd_pcm_drain() ae2c6458f893e77cd352fe9225e123bdf077e33f Sylvain BERTRAND 2020-05-15 14:46:30
after network testing: need an input thread 0c26bffd3c2268cfb9f7d8e43c7aba2fbf7fec16 Sylvain BERTRAND 2020-05-13 23:11:20
spin on futex waiting in threaded scaler e90420f459c608cbcbae423b3c487598a83de359 Sylvain BERTRAND 2020-05-13 21:05:48
npa tidying and npv addition, usable on our system 443ff39347c8b599dfaafff612caed84287f1a70 Sylvain BERTRAND 2020-05-13 15:12:15
here we go d5a2b11f4d73ec5365a340163f451fa8a123d728 Sylvain BERTRAND 2020-02-12 18:50:57
Commit cf4da499db3123561aacd8732cd1eb97b9146e55 - npv:restore pause/seeking, add tmp info command
Author: Sylvain BERTRAND
Author date (UTC): 2020-05-27 17:31
Committer name: Sylvain BERTRAND
Committer date (UTC): 2020-05-27 17:31
Parent(s): 8bd06c28483adc9986b8b51612e609115948943d
Signer:
Signing key:
Signing status: N
Tree: bd65440aae0c8977f35eb32431ad5cd299848bfc
File Lines added Lines deleted
npv/TODO 5 6
npv/config.h 2 1
npv/local/code.frag.c 229 123
npv/main.c 1 0
npv/pipeline/local/code.frag.c 1 2
npv/pipeline/namespace/public.h 4 0
npv/pipeline/public.h 4 1
npv/pipeline/public/code.frag.c 25 21
npv/pkt_q/public/code.frag.c 0 1
npv/xcb/local/code.frag.c 35 33
File npv/TODO changed (mode: 100644) (index ae774ef..3f10e4b)
1 do first:make seek/end/etc work again
2
3 1 not ordered: not ordered:
4 - better/smoother/less drop/(correct?) video frame display strategy
2 - disable the x11 screensaver, but I am more likely to go "manual gear" with a
3 separate command
4 - hide the mouse cursor or, if possible, a separate command for "manual gear"?
5 - better/smoother/less drop/(correct?) video frame display strategy ?
5 6 - xcb(resize)/vulkan swapchain loss or "not optimal" ? (state re-factoring) - xcb(resize)/vulkan swapchain loss or "not optimal" ? (state re-factoring)
6 7 - x11 map/unmap handling to: - x11 map/unmap handling to:
7 8 + restore the paused image (aka keep the image currently displayed in cpu ram) + restore the paused image (aka keep the image currently displayed in cpu ram)
 
... ... not ordered:
16 17 + is this should be handle or it is overkill? + is this should be handle or it is overkill?
17 18 - vulkan device loss? (dynamically change device?) - vulkan device loss? (dynamically change device?)
18 19 - alsa-lib dynamic loading - alsa-lib dynamic loading
19 - "buffering" indicator
20 - subtitles
21 - osd (On Screen Display)
20 - "buffering" indicator, subtitles and osd (On Screen Display)
22 21 - use vulkan shaders (no glsl or hlsl), compute or not, in order to perform - use vulkan shaders (no glsl or hlsl), compute or not, in order to perform
23 22 some yuvX pixel formats to srgb format conversions. do NOT use the vulkan some yuvX pixel formats to srgb format conversions. do NOT use the vulkan
24 23 yuvX samplers as they are mostly dirty hack tricks built into spirv yuvX samplers as they are mostly dirty hack tricks built into spirv
File npv/config.h changed (mode: 100644) (index 1a584c3..96066cc)
... ... struct x11_bind_t x11_binds[] = {
37 37 X11_BIND(0x73, "end", cmd_fastforward_big), X11_BIND(0x73, "end", cmd_fastforward_big),
38 38 X11_BIND(0x6f, "arrow up", cmd_vol_up), X11_BIND(0x6f, "arrow up", cmd_vol_up),
39 39 X11_BIND(0x74, "arrow down", cmd_vol_down), X11_BIND(0x74, "arrow down", cmd_vol_down),
40 X11_BIND(0x3a, "arrow down", cmd_mute)
40 X11_BIND(0x3a, "arrow down", cmd_mute),
41 X11_BIND(0x2a, "letter i", cmd_info)
41 42 }; };
42 43 #undef X11_BIND #undef X11_BIND
43 44 #undef LINUX_KEY_ESC #undef LINUX_KEY_ESC
File npv/local/code.frag.c changed (mode: 100644) (index 6668cfb..a5733bc)
1 /* meh... */
2 /*NSPC*/
3 static u8 *ts_to_str(int64_t ts, avutil_rational_t time_base,
4 int64_t *remaining)
5 {
6 static u8 str[sizeof("~S00:00:00.000 remains S9223372036854775807 time base units")];
7 bool is_neg;
8 int64_t hours_n;
9 int64_t mins_n;
10 int64_t secs_n;
11 int64_t msecs_n;
12 int64_t one_hour; /* in ffmpeg time_base units */
13 int64_t one_min; /* in ffmpeg time_base units */
14 int64_t one_sec; /* in ffmpeg time_base units */
15 int64_t one_msec; /* in ffmpeg time_base units */
16
17 if (ts < 0) {
18 ts = -ts;
19 is_neg = true;
20 } else
21 is_neg = false;
22
23 one_hour = INT64_C(3600) * (int64_t)time_base.den
24 / (int64_t)time_base.num;
25 one_min = INT64_C(60) * (int64_t)time_base.den
26 / (int64_t)time_base.num;
27 one_sec = (int64_t)time_base.den / (int64_t)time_base.num;
28 one_msec = one_sec / INT64_C(1000);
29
30 hours_n = ts / one_hour;
31
32 *remaining = ts % one_hour;
33 mins_n = *remaining / one_min;
34
35 *remaining = *remaining % one_min;
36 secs_n = *remaining / one_sec;
37
38 *remaining = *remaining % one_sec;
39 msecs_n = *remaining / one_msec;
40
41 /* account for all rounding errors */
42 *remaining = ts - (hours_n * one_hour + mins_n * one_min
43 + secs_n * one_sec + msecs_n * one_msec);
44 if (!is_neg)
45 snprintf(str, sizeof(str), "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n);
46 else {
47 str[0] = '-';
48 snprintf(str + 1, sizeof(str) - 1, "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n);
49 }
50 return str;
51 }
52 /*--------------------------------------------------------------------------*/
53 1 /* /*
54 2 * block as much as possible. * block as much as possible.
55 3 * handle only async "usual" sigs, with sync signalfd. * handle only async "usual" sigs, with sync signalfd.
 
... ... static void sigs_init_once(void)
97 45 sig_fd_l = r; sig_fd_l = r;
98 46 } }
99 47 /*NSPC*/ /*NSPC*/
48 static void prefill_wait(void) { loop
49 {
50 struct timespec wanted;
51 struct timespec rem;
52 s64 prefill_audio;
53 s64 prefill_video;
54
55 pipeline_limits_lock();
56 prefill_audio = pipeline_limits_p.pkts.prefill.audio_bytes_rem;
57 prefill_video = pipeline_limits_p.pkts.prefill.video_bytes_rem;
58 pipeline_limits_unlock();
59 if (prefill_audio <= 0 && prefill_video <= 0)
60 break;
61 memset(&wanted, 0, sizeof(wanted));
62 memset(&rem, 0, sizeof(rem));
63 wanted.tv_nsec = 100000000; /* 100 ms */
64 loop {
65 int r;
66
67 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
68 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
69 if (r == 0)
70 break;
71 if (r != EINTR)
72 FATAL("prefill wait timer failed:%d\n", r);
73 /* r == EINTR */
74 memcpy(&wanted, &rem, sizeof(wanted));
75 memset(&rem, 0, sizeof(rem));
76 }
77 }}
78 /*NSPC*/
79 static void predecode_wait(void)
80 {
81 struct timespec wanted;
82 struct timespec rem;
83
84 memset(&wanted, 0, sizeof(wanted));
85 memset(&rem, 0, sizeof(rem));
86 /* we target ~double audio buf, namely (0.25s * 2 ~ 500ms) */
87 wanted.tv_nsec = 500000000;
88 loop {
89 int r;
90
91 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
92 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
93 if (r == 0)
94 break;
95 if (r != EINTR)
96 FATAL("predecoding wait timer failed:%d\n", r);
97 /* r == EINTR */
98 memcpy(&wanted, &rem, sizeof(wanted));
99 memset(&rem, 0, sizeof(rem));
100 }
101 }
102 /*NSPC*/
100 103 static void evt_init_once(void) static void evt_init_once(void)
101 104 { {
102 105 ep_fd_p = epoll_create1(0); ep_fd_p = epoll_create1(0);
 
... ... static void opts_parse(int argc, u8 **args, u8 **url, u16 *w, u16 *h,
402 405 #define WIDTH_NOT_DEFINED 0 #define WIDTH_NOT_DEFINED 0
403 406 #define HEIGHT_NOT_DEFINED 0 #define HEIGHT_NOT_DEFINED 0
404 407 static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str, static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str,
405 u8 pkts_prefill_percent, avcodec_params_t **audio_codec_params,
408 avcodec_params_t **audio_codec_params,
406 409 avcodec_params_t **video_codec_params) avcodec_params_t **video_codec_params)
407 410 { {
408 411 avutil_rational_t *audio_st_tb; avutil_rational_t *audio_st_tb;
 
... ... static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str,
415 418 audio_init_once(pcm_str); /* before audio_st_idx_p is actually used */ audio_init_once(pcm_str); /* before audio_st_idx_p is actually used */
416 419 video_init_once(); /* before video_st_idx_p is actually used */ video_init_once(); /* before video_st_idx_p is actually used */
417 420 clk_init_once(); clk_init_once();
418 pipeline_init_once(pkts_prefill_percent);
421 pipeline_init_once();
419 422
420 423 fmt_init_once(url); fmt_init_once(url);
421 424 /* we need something to start with */ /* we need something to start with */
 
... ... static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str,
437 440 #undef HEIGHT_NOT_DEFINED #undef HEIGHT_NOT_DEFINED
438 441 /*NSPC*/ /*NSPC*/
439 442 #define PRINT_INFO true #define PRINT_INFO true
440 static void prepare(double initial_vol, avcodec_params_t *audio_codec_params,
443 static void prepare(double initial_vol, u8 pkts_prefill_percent,
444 avcodec_params_t *audio_codec_params,
441 445 avcodec_params_t *video_codec_params) avcodec_params_t *video_codec_params)
442 446 { {
443 447 enum avutil_audio_fr_fmt_t dst_fmt; enum avutil_audio_fr_fmt_t dst_fmt;
 
... ... static void prepare(double initial_vol, avcodec_params_t *audio_codec_params,
445 449 int dst_chans_n; int dst_chans_n;
446 450 uint64_t dst_chans_layout; uint64_t dst_chans_layout;
447 451
452 pipeline_limits_reset();
453 pipeline_prefill_reset(pkts_prefill_percent);
454
448 455 audio_dec_ctx_cfg(audio_codec_params); audio_dec_ctx_cfg(audio_codec_params);
449 456 video_dec_ctx_cfg(video_codec_params); video_dec_ctx_cfg(video_codec_params);
450 457 /* /*
 
... ... static void prepare(double initial_vol, avcodec_params_t *audio_codec_params,
466 473
467 474 evt_add_all_fds(); evt_add_all_fds();
468 475 } }
469 #undef PRINT_INFO
470 static void cmd_info(void)
476 /*==== while waiting for the osd -- start ====================================*/
477 /*NSPC*/
478 static u8 *duration_estimate_to_str(enum AVDurationEstimationMethod m)
471 479 { {
472 //TODO: info OSD toggle
480 switch (m) {
481 case AVFMT_DURATION_FROM_PTS:
482 return "from PTS(Presentation TimeStamp)";
483 case AVFMT_DURATION_FROM_STREAM:
484 return "from stream";
485 case AVFMT_DURATION_FROM_BITRATE:
486 return "from bitrate";
487 default:
488 return "unkwown";
489 }
473 490 } }
491 /*NSPC*/
492 static u8 *ts_to_str(int64_t ts, avutil_rational_t time_base,
493 int64_t *remaining)
494 {
495 static u8 str[sizeof("~S00:00:00.000 remains S9223372036854775807 time base units")];
496 bool is_neg;
497 int64_t hours_n;
498 int64_t mins_n;
499 int64_t secs_n;
500 int64_t msecs_n;
501 int64_t one_hour; /* in ffmpeg time_base units */
502 int64_t one_min; /* in ffmpeg time_base units */
503 int64_t one_sec; /* in ffmpeg time_base units */
504 int64_t one_msec; /* in ffmpeg time_base units */
505
506 if (ts < 0) {
507 ts = -ts;
508 is_neg = true;
509 } else
510 is_neg = false;
511
512 one_hour = INT64_C(3600) * (int64_t)time_base.den
513 / (int64_t)time_base.num;
514 one_min = INT64_C(60) * (int64_t)time_base.den
515 / (int64_t)time_base.num;
516 one_sec = (int64_t)time_base.den / (int64_t)time_base.num;
517 one_msec = one_sec / INT64_C(1000);
518
519 hours_n = ts / one_hour;
520
521 *remaining = ts % one_hour;
522 mins_n = *remaining / one_min;
474 523
524 *remaining = *remaining % one_min;
525 secs_n = *remaining / one_sec;
526
527 *remaining = *remaining % one_sec;
528 msecs_n = *remaining / one_msec;
529
530 /* account for all rounding errors */
531 *remaining = ts - (hours_n * one_hour + mins_n * one_min
532 + secs_n * one_sec + msecs_n * one_msec);
533 if (!is_neg)
534 snprintf(str, sizeof(str), "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n);
535 else {
536 str[0] = '-';
537 snprintf(str + 1, sizeof(str) - 1, "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n);
538 }
539 return str;
540 }
541 #define RED if (stdout_is_tty) POUT("\x1b[38;2;255;0;0m")
542 #define GREEN if (stdout_is_tty) POUT("\x1b[38;2;0;255;0m")
543 #define BLUE if (stdout_is_tty) POUT("\x1b[38;2;0;0;255m")
544 #define PURPLE if (stdout_is_tty) POUT("\x1b[38;2;255;0;255m")
545 #define RESTORE if (stdout_is_tty) POUT("\x1b[39;49m");
546 #define TS_FROM_CLK_OK 0
547 /* we don't lock anything as an act of faith */
548 static void cmd_info(void)
549 {
550 int ri;
551 u8 r8;
552 s64 audio_now;
553 bool stdout_is_tty;
554 u8 *ts_str;
555 int64_t remaining;
556 u8 duration_str[sizeof("S9223372036854775807")];
557
558 ri = isatty(1);
559 if (ri == 0)
560 stdout_is_tty = false;
561 else
562 stdout_is_tty = true;
563
564 RESTORE;
565 GREEN;POUT("================================================================================\n");RESTORE;
566 PURPLE;POUT("%s\n", fmt_ctx_p->url);RESTORE;
567
568 r8 = clk_get_audio_st_ts(&audio_now);
569 if (r8 != TS_FROM_CLK_OK) {
570 POUT("information unavailable at the time of the command due to an unavailable audio clock\n");
571 return;
572 }
573 ts_str = ts_to_str(audio_now, audio_st_p.tb, &remaining);
574 RED;POUT("%s", ts_str);RESTORE;
575 if (remaining != 0)
576 POUT(" remaining %"PRId64" time base units", remaining);
577 else
578 POUT("\n");
579 POUT("\t%"PRId64" stream time base units (%d/%d seconds)\n", audio_now, audio_st_p.tb.num, audio_st_p.tb.den);
580 BLUE;POUT("--------------------------------------------------------------------------------\n");RESTORE;
581 POUT("format:");
582 if (fmt_ctx_p->duration == AV_NOPTS_VALUE) {
583 POUT("duration is not provided\n");
584 } else {
585 snprintf(duration_str, sizeof(duration_str), "%"PRId64, fmt_ctx_p->duration);
586 ts_str = ts_to_str(fmt_ctx_p->duration, AV_TIME_BASE_Q,
587 &remaining);
588 POUT("duration=");RED;POUT("%s", ts_str);RESTORE;
589 if (remaining != 0)
590 POUT(" remaining %"PRId64" av_time_base units\n", remaining);
591 else
592 POUT("\n");
593 POUT("\t%s av_time_base units (1/%d seconds)\n\testimation method is %s\n", duration_str, AV_TIME_BASE, duration_estimate_to_str(fmt_ctx_p->duration_estimation_method));
594 }
595 BLUE;POUT("--------------------------------------------------------------------------------\n");RESTORE;
596 POUT("stream:audio_id=%d", audio_st_p.id);
597 if (fmt_ctx_p->streams[audio_st_p.idx]->duration == AV_NOPTS_VALUE) {
598 POUT(";duration is not provided\n");
599 } else {
600 snprintf(duration_str, sizeof(duration_str), "%"PRId64, fmt_ctx_p->streams[audio_st_p.idx]->duration);
601 ts_str = ts_to_str(fmt_ctx_p->streams[audio_st_p.idx]->duration, audio_st_p.tb, &remaining);
602 POUT(";duration=");RED;POUT("%s\n", ts_str);RESTORE;
603 if (remaining != 0)
604 POUT(" remaining %"PRId64" stream time base units\n", remaining);
605 else
606 POUT("\n");
607 POUT("\t%s stream time base units (%d/%d seconds)\n", duration_str, audio_st_p.tb.num, audio_st_p.tb.den);
608 }
609 BLUE;POUT("--------------------------------------------------------------------------------\n");RESTORE;
610 GREEN;POUT("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");RESTORE;
611 }
612 #undef TS_FROM_CLK_OK
613 #undef RED
614 #undef GREEN
615 #undef BLUE
616 #undef PURPLE
617 #undef RESTORE
618 /*==== while waiting for the osd -- end ======================================*/
475 619 static void cmd_quit(void) static void cmd_quit(void)
476 620 { {
477 621 EXIT("quit command received\n"); EXIT("quit command received\n");
 
... ... static void seek_lock(void)
485 629 pkt_q_lock(video_pkt_q_p); pkt_q_lock(video_pkt_q_p);
486 630 video_dec_frs_lock(); video_dec_frs_lock();
487 631 video_dec_ctx_lock(); video_dec_ctx_lock();
488 /* audio */
632 /* audio (useless from the main thd though) */
489 633 pkt_q_lock(audio_pkt_q_p); pkt_q_lock(audio_pkt_q_p);
490 634 audio_dec_sets_lock(); audio_dec_sets_lock();
491 635 audio_dec_ctx_lock(); audio_dec_ctx_lock();
636
637 pipeline_limits_lock();
492 638 } }
493 639 /*NSPC*/ /*NSPC*/
494 640 static void seek_unlock(void) static void seek_unlock(void)
495 641 { {
642 pipeline_limits_unlock();
643
496 644 /* audio */ /* audio */
497 645 audio_dec_ctx_unlock(); audio_dec_ctx_unlock();
498 646 audio_dec_sets_unlock(); audio_dec_sets_unlock();
 
... ... static void seek_x(s64 delta)
536 684 seek_unlock(); seek_unlock();
537 685 return; return;
538 686 } }
687 (void)snd_pcm_drop(audio_pcm_p);
539 688 /* /*
540 689 * XXX: a set of sts can share the same id for seeking. if they share * XXX: a set of sts can share the same id for seeking. if they share
541 690 * the same id then the tbs should be the same. * the same id then the tbs should be the same.
 
... ... static void seek_x(s64 delta)
550 699 POUT("trying to seek to %"PRId64" audio stream time base units\n", new_audio_ts); POUT("trying to seek to %"PRId64" audio stream time base units\n", new_audio_ts);
551 700 a = avformat_seek_pkt(fmt_ctx_p, audio_st_p.id, new_audio_ts, 0); a = avformat_seek_pkt(fmt_ctx_p, audio_st_p.id, new_audio_ts, 0);
552 701 if (a < 0) { if (a < 0) {
553 WARNING("unable to seek to %"PRId64" audio stream time base units\n", new_audio_ts);
702 POUT("unable to seek to %"PRId64" audio stream time base units\n", new_audio_ts);
554 703 goto try_restore_audio; goto try_restore_audio;
555 704 } }
556 705 POUT("audio seek to %"PRId64" audio stream time base units\n", new_audio_ts); POUT("audio seek to %"PRId64" audio stream time base units\n", new_audio_ts);
 
... ... static void seek_x(s64 delta)
564 713 POUT("trying to seek to %"PRId64" video stream time base units\n", new_video_ts); POUT("trying to seek to %"PRId64" video stream time base units\n", new_video_ts);
565 714 a = avformat_seek_pkt(fmt_ctx_p, video_st_p.id, new_video_ts, 0); a = avformat_seek_pkt(fmt_ctx_p, video_st_p.id, new_video_ts, 0);
566 715 if (a < 0) { if (a < 0) {
567 WARNING("unable to seek to %"PRId64" video stream time base units but audio was seeked)\n", new_video_ts);
716 POUT("unable to seek to %"PRId64" video stream time base units but audio was seeked)\n", new_video_ts);
568 717 goto try_restore_video; goto try_restore_video;
569 718 } }
570 719 POUT("video seek to %"PRId64" video stream time base units\n", new_video_ts); POUT("video seek to %"PRId64" video stream time base units\n", new_video_ts);
 
... ... flush:
574 723 audio_filt_flush(); audio_filt_flush();
575 724 fmt_flush(); fmt_flush();
576 725 clk_invalidate(); clk_invalidate();
726 pipeline_limits_reset();
727 pipeline_prefill_reset(pipeline_limits_p.pkts.prefill.percent);
577 728 seek_unlock(); seek_unlock();
729
730 POUT("prefilling audio and video buffers...");
731 prefill_wait(); /* use the lock on the pipeline limits */
732 POUT("done\n");
733 POUT("predecoding audio and video...");
734 predecode_wait(); /* use the lock on the pipeline limits */
735 POUT("done\n");
736 (void)snd_pcm_prepare(audio_pcm_p);
578 737 return; return;
579 738
580 739 try_restore_video: try_restore_video:
 
... ... static void cmd_pause(void)
634 793 fmt_ctx_lock(); fmt_ctx_lock();
635 794 avformat_read_pause(fmt_ctx_p); avformat_read_pause(fmt_ctx_p);
636 795 fmt_ctx_unlock(); fmt_ctx_unlock();
796 /* the clk source won't stop for us */
797 clk_invalidate();
637 798 } }
638 799 } }
639 800
 
... ... static void cmd_mute(void)
651 812 { {
652 813 audio_filt_cmd_mute(); audio_filt_cmd_mute();
653 814 } }
654 /*NSPC*/
655 static void prefill_wait(void) { loop
656 {
657 struct timespec wanted;
658 struct timespec rem;
659 s64 prefill_audio;
660 s64 prefill_video;
661
662 pipeline_limits_lock();
663 prefill_audio = pipeline_limits_p.pkts.prefill.audio_bytes_rem;
664 prefill_video = pipeline_limits_p.pkts.prefill.video_bytes_rem;
665 pipeline_limits_unlock();
666 if (prefill_audio <= 0 && prefill_video <= 0)
667 break;
668 memset(&wanted, 0, sizeof(wanted));
669 memset(&rem, 0, sizeof(rem));
670 wanted.tv_nsec = 100000000; /* 100 ms */
671 loop {
672 int r;
673
674 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
675 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
676 if (r == 0)
677 break;
678 if (r != EINTR)
679 FATAL("prefill wait timer failed:%d\n", r);
680 /* r == EINTR */
681 memcpy(&wanted, &rem, sizeof(wanted));
682 memset(&rem, 0, sizeof(rem));
683 }
684 }}
685 /*NSPC*/
686 static void predecoding_wait(void)
687 {
688 struct timespec wanted;
689 struct timespec rem;
690
691 memset(&wanted, 0, sizeof(wanted));
692 memset(&rem, 0, sizeof(rem));
693 /* we target ~double audio buf, namely (0.25s * 2 ~ 500ms) */
694 wanted.tv_nsec = 500000000;
695 loop {
696 int r;
697
698 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
699 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
700 if (r == 0)
701 break;
702 if (r != EINTR)
703 FATAL("predecoding wait timer failed:%d\n", r);
704 /* r == EINTR */
705 memcpy(&wanted, &rem, sizeof(wanted));
706 memset(&rem, 0, sizeof(rem));
707 }
708 }
709 815 #define WIDTH_NOT_DEFINED 0 #define WIDTH_NOT_DEFINED 0
710 816 #define HEIGHT_NOT_DEFINED 0 #define HEIGHT_NOT_DEFINED 0
711 817 int main(int argc, u8 **args) int main(int argc, u8 **args)
 
... ... int main(int argc, u8 **args)
715 821 u8 *pcm_str; u8 *pcm_str;
716 822 u8 *url; u8 *url;
717 823 double initial_vol; double initial_vol;
718 u8 pkts_prefill_percent;
719 824 avcodec_params_t *audio_codec_params; avcodec_params_t *audio_codec_params;
720 825 avcodec_params_t *video_codec_params; avcodec_params_t *video_codec_params;
721 826
 
... ... int main(int argc, u8 **args)
730 835 pcm_str = "default"; pcm_str = "default";
731 836 url = 0; url = 0;
732 837 initial_vol = 1.; initial_vol = 1.;
733 pkts_prefill_percent = 0;
838 pipeline_limits_p.pkts.prefill.percent = 0;
734 839 opts_parse(argc, args, &url, &win_width, &win_height, &pcm_str, opts_parse(argc, args, &url, &win_width, &win_height, &pcm_str,
735 &initial_vol, &pkts_prefill_percent);
736 init_once(url, win_width, win_height, pcm_str, pkts_prefill_percent,
737 &audio_codec_params, &video_codec_params);
738 prepare(initial_vol, audio_codec_params, video_codec_params);
840 &initial_vol, &pipeline_limits_p.pkts.prefill.percent);
841 init_once(url, win_width, win_height, pcm_str,&audio_codec_params,
842 &video_codec_params);
843 prepare(initial_vol, pipeline_limits_p.pkts.prefill.percent,
844 audio_codec_params, video_codec_params);
739 845
740 846 /* switch the ffmpeg log to stdout for metadata/etc dump */ /* switch the ffmpeg log to stdout for metadata/etc dump */
741 847 avutil_log_set_callback(ff_log_stdout); avutil_log_set_callback(ff_log_stdout);
 
... ... int main(int argc, u8 **args)
749 855 pipeline_audio_thd_start(); pipeline_audio_thd_start();
750 856 pipeline_video_thd_start(); pipeline_video_thd_start();
751 857 POUT("predecoding audio and video..."); POUT("predecoding audio and video...");
752 predecoding_wait();
858 predecode_wait();
753 859 POUT("done\n"); POUT("done\n");
754 860 video_timer_start(); video_timer_start();
755 861
File npv/main.c changed (mode: 100644) (index 033910c..82ca2ea)
20 20 #include <stdlib.h> #include <stdlib.h>
21 21 #include <unistd.h> #include <unistd.h>
22 22 #include <fcntl.h> #include <fcntl.h>
23 #include <termios.h> /* used while waiting for the osd */
23 24 #include <sys/epoll.h> #include <sys/epoll.h>
24 25 #include <sys/signalfd.h> #include <sys/signalfd.h>
25 26 #include <dlfcn.h> #include <dlfcn.h>
File npv/pipeline/local/code.frag.c changed (mode: 100644) (index 7c58498..4754901)
... ... static void wait(long ns)
24 24 static void read(void) { loop /* infinite loop */ static void read(void) { loop /* infinite loop */
25 25 { {
26 26 u8 r; u8 r;
27
28 27 /* /*
29 28 * we do finer-grained locking in there, since we do not want to lock * we do finer-grained locking in there, since we do not want to lock
30 29 * the pkt qs during slow access * the pkt qs during slow access
 
... ... static void read(void) { loop /* infinite loop */
41 40 pkt_q_enq(video_pkt_q_p, eof_pkt_l); pkt_q_enq(video_pkt_q_p, eof_pkt_l);
42 41 pkt_q_unlock(video_pkt_q_p); pkt_q_unlock(video_pkt_q_p);
43 42 } }
44 /*--------------------------------------------------------------------*/
43 /* r == LIMITS_REACHED || EAGAIN */
45 44 /* should be enough to avoid non kept-alive network connexion */ /* should be enough to avoid non kept-alive network connexion */
46 45 wait(100000000); /* 100ms */ wait(100000000); /* 100ms */
47 46 }} }}
File npv/pipeline/namespace/public.h changed (mode: 100644) (index 5e6b268..860a58c)
5 5 #define limits_p pipeline_limits_p #define limits_p pipeline_limits_p
6 6 #define limits_t pipeline_limits_t #define limits_t pipeline_limits_t
7 7 #define limits_unlock pipeline_limits_unlock #define limits_unlock pipeline_limits_unlock
8 #define limits_reset pipeline_limits_reset
9 #define prefill_reset pipeline_prefill_reset
8 10 #define read_thd_start pipeline_read_thd_start #define read_thd_start pipeline_read_thd_start
9 11 #define video_thd_start pipeline_video_thd_start #define video_thd_start pipeline_video_thd_start
10 12 /*============================================================================*/ /*============================================================================*/
 
15 17 #undef limits_p #undef limits_p
16 18 #undef limits_t #undef limits_t
17 19 #undef limits_unlock #undef limits_unlock
20 #undef limits_reset
21 #undef prefill_reset
18 22 #undef read_thd_start #undef read_thd_start
19 23 #undef video_thd_start #undef video_thd_start
20 24 #endif #endif
File npv/pipeline/public.h changed (mode: 100644) (index 9938412..dfc672a)
... ... struct limits_t {
19 19 u64 video_bytes_n; /* arbitrary, init-ed once */ u64 video_bytes_n; /* arbitrary, init-ed once */
20 20 } limit; } limit;
21 21 struct { struct {
22 u8 percent;
22 23 s64 audio_bytes_rem; s64 audio_bytes_rem;
23 24 s64 video_bytes_rem; s64 video_bytes_rem;
24 25 } prefill; } prefill;
 
... ... struct limits_t {
27 28 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
28 29 #include "npv/pipeline/public/state.frag.h" #include "npv/pipeline/public/state.frag.h"
29 30 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
30 static void init_once(u8 pkts_prefill_percent);
31 static void limits_reset(void);
32 static void prefill_reset(u8 percent);
33 static void init_once(void);
31 34 static void limits_lock(void); static void limits_lock(void);
32 35 static void limits_unlock(void); static void limits_unlock(void);
33 36 static void read_thd_start(void); static void read_thd_start(void);
File npv/pipeline/public/code.frag.c changed (mode: 100644) (index 8857e49..cfb684b)
1 static void init_once(u8 pkts_prefill_percent)
1 static void limits_reset(void)
2 2 { {
3 int r;
4
5 eof_pkt_l = avcodec_pkt_ref_alloc();
6 if (eof_pkt_l == 0)
7 FATALP("ffmpeg:unable to allocate a null/eof reference on a packet\n");
8 eof_pkt_l->data = 0;
9 eof_pkt_l->sz = 0;
10
11 r = pthread_mutex_init(&limits_p.mutex, 0);
12 if (r != 0)
13 FATALP("unable to initialize the mutex to guard the accounting of limits\n");
14 3 limits_p.pkts.audio_bytes_n = 0; limits_p.pkts.audio_bytes_n = 0;
15 4 limits_p.pkts.video_bytes_n = 0; limits_p.pkts.video_bytes_n = 0;
16 5 /* hardcoded for now: arbitrary rough estimates */ /* hardcoded for now: arbitrary rough estimates */
 
... ... static void init_once(u8 pkts_prefill_percent)
18 7 limits_p.pkts.limit.audio_bytes_n = 400000 / 8 * 8; limits_p.pkts.limit.audio_bytes_n = 400000 / 8 * 8;
19 8 /* ~8s of 10Mb video */ /* ~8s of 10Mb video */
20 9 limits_p.pkts.limit.video_bytes_n = 10000000 / 8 * 8; limits_p.pkts.limit.video_bytes_n = 10000000 / 8 * 8;
21 if (pkts_prefill_percent > 100)
22 FATALP("invalid prefill of %u%% for the buffer of packet queues\n", pkts_prefill_percent);
23 if (pkts_prefill_percent != 0) {
10 }
11 static void prefill_reset(u8 percent)
12 {
13 if (percent > 100)
14 FATALP("invalid prefill of %u%% for the buffer of packet queues\n", percent);
15 if (percent != 0) {
24 16 limits_p.pkts.prefill.audio_bytes_rem = limits_p.pkts.prefill.audio_bytes_rem =
25 limits_p.pkts.limit.audio_bytes_n * pkts_prefill_percent
26 / 100;
27 POUTP("prefill size for the audio packet queue buffer is %u%%/%"PRId64" bytes\n", pkts_prefill_percent, limits_p.pkts.prefill.audio_bytes_rem);
17 limits_p.pkts.limit.audio_bytes_n * percent / 100;
18 POUTP("prefill size for the audio packet queue buffer is %u%%/%"PRId64" bytes\n", percent, limits_p.pkts.prefill.audio_bytes_rem);
28 19 limits_p.pkts.prefill.video_bytes_rem = limits_p.pkts.prefill.video_bytes_rem =
29 limits_p.pkts.limit.video_bytes_n * pkts_prefill_percent
30 / 100;
31 POUTP("prefill size for the video packet queue buffer is %u%%/%"PRId64" bytes\n", pkts_prefill_percent, limits_p.pkts.prefill.video_bytes_rem);
20 limits_p.pkts.limit.video_bytes_n * percent / 100;
21 POUTP("prefill size for the video packet queue buffer is %u%%/%"PRId64" bytes\n", percent, limits_p.pkts.prefill.video_bytes_rem);
32 22 } else { } else {
33 23 limits_p.pkts.prefill.audio_bytes_rem = 0; limits_p.pkts.prefill.audio_bytes_rem = 0;
34 24 limits_p.pkts.prefill.video_bytes_rem = 0; limits_p.pkts.prefill.video_bytes_rem = 0;
35 25 POUTP("prefill for the packet queue buffers is disabled\n"); POUTP("prefill for the packet queue buffers is disabled\n");
36 26 } }
37 27 } }
28 static void init_once(void)
29 {
30 int r;
31
32 eof_pkt_l = avcodec_pkt_ref_alloc();
33 if (eof_pkt_l == 0)
34 FATALP("ffmpeg:unable to allocate a null/eof reference on a packet\n");
35 eof_pkt_l->data = 0;
36 eof_pkt_l->sz = 0;
37
38 r = pthread_mutex_init(&limits_p.mutex, 0);
39 if (r != 0)
40 FATALP("unable to initialize the mutex to guard the accounting of limits\n");
41 }
38 42 static void limits_lock(void) static void limits_lock(void)
39 43 { {
40 44 int r; int r;
File npv/pkt_q/public/code.frag.c changed (mode: 100644) (index 6a94aa0..5377ed1)
... ... static void unref_all(struct pkt_q_t *this)
43 43 loop { loop {
44 44 if (pr == this->n) if (pr == this->n)
45 45 break; break;
46 //TODO: account for the limits bytes removal
47 46 avcodec_pkt_unref(this->q[pr]); avcodec_pkt_unref(this->q[pr]);
48 47 ++pr; ++pr;
49 48 } }
File npv/xcb/local/code.frag.c changed (mode: 100644) (index 4c8e0bc..f690c3b)
... ... static void npv_xcb_scr_get(void)
126 126 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:white pixel=0x%08x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->white_pixel); POUTX("'%s':connection:%p:screen:%d:root window id:%#x:white pixel=0x%08x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->white_pixel);
127 127 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:black pixel=0x%08x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->black_pixel); POUTX("'%s':connection:%p:screen:%d:root window id:%#x:black pixel=0x%08x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->black_pixel);
128 128 } }
129 // TODO: not appropriate for the video window
130 //#define MIN_SZ_BIT (1 << 4)
131 //#define MAX_SZ_BIT (1 << 5)
132 //#define FLAGS 0
133 ///* 4 padding dwords */
134 //#define MIN_WIDTH 5
135 //#define MIN_HEIGHT 6
136 //#define MAX_WIDTH 7
137 //#define MAX_HEIGHT 8
138 //#define DWORDS_N 18
139 //static void npv_xcb_p_wm_hints(void)
140 //{
141 // u32 data[DWORDS_N];
142 //
143 // memset(data, 0, sizeof(data));
144 // data[FLAGS] = MIN_SZ_BIT | MAX_SZ_BIT;
145 // data[MIN_WIDTH] = APP_WIN_WIDTH;
146 // data[MIN_HEIGHT] = APP_WIN_HEIGHT;
147 // data[MAX_WIDTH] = APP_WIN_WIDTH;
148 // data[MAX_HEIGHT] = APP_WIN_HEIGHT;
149 //
150 // dl_xcb_change_property(npv_xcb_p.c, XCB_PROP_MODE_REPLACE,
151 // npv_xcb_p.win_id, XCB_ATOM_WM_NORMAL_HINTS,
152 // XCB_ATOM_WM_SIZE_HINTS, 32, DWORDS_N, data);
153 //}
154 //#undef MIN_SZ_BIT
155 //#undef MAX_SZ_BIT
156 //#undef FLAGS
157 //#undef MIN_WIDTH
158 //#undef MIN_HEIGHT
159 //#undef MAX_WIDTH
160 //#undef MAX_HEIGHT
161 //#undef DWORDS_N
129 #if 0
130 // TODO: not appropriate for the viewport window
131 #define MIN_SZ_BIT (1 << 4)
132 #define MAX_SZ_BIT (1 << 5)
133 #define FLAGS 0
134 /* 4 padding dwords */
135 #define MIN_WIDTH 5
136 #define MIN_HEIGHT 6
137 #define MAX_WIDTH 7
138 #define MAX_HEIGHT 8
139 #define DWORDS_N 18
140 static void npv_xcb_p_wm_hints(void)
141 {
142 u32 data[DWORDS_N];
143
144 memset(data, 0, sizeof(data));
145 data[FLAGS] = MIN_SZ_BIT | MAX_SZ_BIT;
146 data[MIN_WIDTH] = APP_WIN_WIDTH;
147 data[MIN_HEIGHT] = APP_WIN_HEIGHT;
148 data[MAX_WIDTH] = APP_WIN_WIDTH;
149 data[MAX_HEIGHT] = APP_WIN_HEIGHT;
150
151 dl_xcb_change_property(npv_xcb_p.c, XCB_PROP_MODE_REPLACE,
152 npv_xcb_p.win_id, XCB_ATOM_WM_NORMAL_HINTS,
153 XCB_ATOM_WM_SIZE_HINTS, 32, DWORDS_N, data);
154 }
155 #undef MIN_SZ_BIT
156 #undef MAX_SZ_BIT
157 #undef FLAGS
158 #undef MIN_WIDTH
159 #undef MIN_HEIGHT
160 #undef MAX_WIDTH
161 #undef MAX_HEIGHT
162 #undef DWORDS_N
163 #endif
162 164 static void npv_xcb_evt_key_release(xcb_generic_event_t *evt) static void npv_xcb_evt_key_release(xcb_generic_event_t *evt)
163 165 { {
164 166 u8 b; u8 b;
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/nyanmp

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/nyanmp

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/nyanmp

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main