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: 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 30efa7c8f2574c676d9d41b8bf5678d5725b8721 - npv: media pipeline
Author: Sylvain BERTRAND
Author date (UTC): 2020-05-24 17:40
Committer name: Sylvain BERTRAND
Committer date (UTC): 2020-05-24 17:40
Parent(s): 54b6dc9b912bb9509ba35405f15a623632adf784
Signer:
Signing key:
Signing status: N
Tree: 2c27de5d333c9e6a1a61a727352677a7ece665d3
File Lines added Lines deleted
npv/README 2 2
npv/TODO 10 8
npv/audio/filt/main.c 1 0
npv/audio/filt/public/code.frag.c 20 10
npv/audio/local/code.frag.c 13 6
npv/audio/local/state.frag.c 2 1
npv/audio/main.c 1 0
npv/audio/namespace/main.c 2 0
npv/audio/namespace/public.h 16 6
npv/audio/public.h 8 2
npv/audio/public/code.frag.c 81 6
npv/audio/public/state.frag.h 12 2
npv/c_fixing.h 12 2
npv/clk/main.c 1 1
npv/clk/public/code.frag.c 6 6
npv/fmt/local/code.frag.c 19 0
npv/fmt/local/state.frag.c 1 0
npv/fmt/main.c 1 0
npv/fmt/namespace/main.c 5 0
npv/fmt/namespace/public.h 4 0
npv/fmt/public.h 9 6
npv/fmt/public/code.frag.c 76 24
npv/input/local/code.frag.c 0 18
npv/input/main.c 0 51
npv/input/namespace/main.c 0 16
npv/input/namespace/public.h 0 14
npv/input/public.h 0 19
npv/input/public/code.frag.c 0 189
npv/local/code.frag.c 198 72
npv/main.c 2 2
npv/namespace/ffmpeg.h 4 0
npv/pipeline/local/code.frag.c 180 0
npv/pipeline/local/state.frag.c 0 0
npv/pipeline/main.c 43 0
npv/pipeline/namespace/main.c 32 0
npv/pipeline/namespace/public.h 20 0
npv/pipeline/public.h 40 0
npv/pipeline/public/code.frag.c 107 0
npv/pipeline/public/state.frag.h 1 0
npv/pkt_q/local/code.frag.c 0 19
npv/pkt_q/main.c 2 0
npv/pkt_q/namespace/main.c 2 2
npv/pkt_q/namespace/public.h 6 2
npv/pkt_q/public.h 12 2
npv/pkt_q/public/code.frag.c 34 25
npv/video/local/code.frag.c 37 32
npv/video/local/state.frag.c 2 0
npv/video/main.c 2 1
npv/video/namespace/main.c 2 0
npv/video/namespace/public.h 16 6
npv/video/public.h 7 2
npv/video/public/code.frag.c 110 23
npv/video/public/state.frag.h 19 5
File npv/README changed (mode: 100644) (index 50c6ffc..32436e0)
1 lightweight, vulkan, x11, linux, alsa, audio driven video file player
2 using ffmpeg.
1 lightweight, vulkan, x11, linux, alsa, audio driven and self-limiting
2 media pipeline video file player using ffmpeg.
3 3 BUILDING: BUILDING:
4 4 this is a "one compilation unit" project. just compile main.c and link this is a "one compilation unit" project. just compile main.c and link
5 5 the compiler output file to your ffmpeg libs, your alsa lib (we should the compiler output file to your ffmpeg libs, your alsa lib (we should
File npv/TODO changed (mode: 100644) (index 27a5aad..d6dcb23)
1 next:
2 an input thread is needed to "receive" the packets since it is blocking while pulling data
3 from internet. will need a mutex for the format and a mutex for each packet queue.
4
5 1 not ordered: not ordered:
2 - better/smoother/less drop/(correct?) video frame display strategy
6 3 - xcb(resize)/vulkan swapchain loss or "not optimal" ? (state re-factoring) - xcb(resize)/vulkan swapchain loss or "not optimal" ? (state re-factoring)
7 4 - x11 map/unmap handling to: - x11 map/unmap handling to:
8 + restore the paused image (aka keep the image in cpu ram)
5 + restore the paused image (aka keep the image currently displayed in cpu ram)
9 6 + switch on/off video decoding? + switch on/off video decoding?
10 - better/smoother/(correct?) video frame display strategy
11 - power management event? it implies:
7 - the exit condition is audio drained *AND* format eof was raised.
8 dynamic formats: if eof was not raised and audio is drained, reprobe
9 for best streams? Wait for user streams selection?
10 - "power management event"? it implies:
12 11 + if alsa notify of a "power management" event we should + if alsa notify of a "power management" event we should
13 12 (invalidate/update/something) the clock (invalidate/update/something) the clock
14 13 + vulkan surface loss? (it should be the case) + vulkan surface loss? (it should be the case)
14 + is this should be handle or it is overkill?
15 15 - vulkan device loss? (dynamically change device?) - vulkan device loss? (dynamically change device?)
16 16 - alsa-lib dynamic loading - alsa-lib dynamic loading
17 17 - "buffering" indicator - "buffering" indicator
18 18 - subtitles - subtitles
19 19 - osd (On Screen Display) - osd (On Screen Display)
20 - use vulkan shaders, compute or not, in order to perform some yuvX pixel
20 - use vulkan shaders (no glsl or hlsl), compute or not, in order to perform some yuvX pixel
21 21 formats to srgb format conversions. do NOT use the vulkan yuvX samplers as formats to srgb format conversions. do NOT use the vulkan yuvX samplers as
22 22 they are mostly dirty hack tricks built into spirv translaters. they are mostly dirty hack tricks built into spirv translaters.
23 - vulkan thingy for better quality down/up scaling?
24 - actually off-loading alsa output and vulkan output to their thread?
File npv/audio/filt/main.c changed (mode: 100644) (index 488e1c9..ba5aa67)
6 6 */ */
7 7 #include <stdbool.h> #include <stdbool.h>
8 8 #include <stdio.h> #include <stdio.h>
9 #include <pthread.h>
9 10 #include <libavfilter/avfilter.h> #include <libavfilter/avfilter.h>
10 11 #include <libavfilter/buffersrc.h> #include <libavfilter/buffersrc.h>
11 12 #include <libavfilter/buffersink.h> #include <libavfilter/buffersink.h>
File npv/audio/filt/public/code.frag.c changed (mode: 100644) (index 400f5d4..45e2b1d)
4 4 #define FILT_SWITCHED_TO_DRAINING 3 #define FILT_SWITCHED_TO_DRAINING 3
5 5 static u8 filt_push_dec_sets(void) static u8 filt_push_dec_sets(void)
6 6 { {
7 int r;
7 u8 r8;
8 int ri;
8 9 avutil_audio_set_ref_t **a; avutil_audio_set_ref_t **a;
9 10
11 audio_dec_sets_lock();
10 12 if (audio_dec_sets_p.n == 0) { if (audio_dec_sets_p.n == 0) {
11 13 if (audio_dec_sets_p.eof_receive) { if (audio_dec_sets_p.eof_receive) {
12 r = avfilter_bufsrc_add_audio_set_flags(abufsrc_ctx_l,
14 ri = avfilter_bufsrc_add_audio_set_flags(abufsrc_ctx_l,
13 15 0, AVFILTER_BUFSRC_FLAG_PUSH 0, AVFILTER_BUFSRC_FLAG_PUSH
14 16 | AVFILTER_BUFSRC_FLAG_KEEP_REF); | AVFILTER_BUFSRC_FLAG_KEEP_REF);
15 if (r < 0)
17 if (ri < 0)
16 18 FATALAF("ffmpeg:unable to notify the end of data to the filter source audio buffer context\n"); FATALAF("ffmpeg:unable to notify the end of data to the filter source audio buffer context\n");
17 19 POUTAF("ffmpeg:interactive filter switched to draining\n"); POUTAF("ffmpeg:interactive filter switched to draining\n");
18 return FILT_SWITCHED_TO_DRAINING;
20 r8 = FILT_SWITCHED_TO_DRAINING;
21 goto unlock;
19 22 } }
20 return NO_DEC_SET;
23 r8 = NO_DEC_SET;
24 goto unlock;
21 25 } }
22 26 a = audio_dec_sets_p.a; a = audio_dec_sets_p.a;
23 27 /* the dec_sets_p bufs will be unref in avcodec_audio_receive_set */ /* the dec_sets_p bufs will be unref in avcodec_audio_receive_set */
24 r = avfilter_bufsrc_add_audio_set_flags(abufsrc_ctx_l, a[0],
28 ri = avfilter_bufsrc_add_audio_set_flags(abufsrc_ctx_l, a[0],
25 29 AVFILTER_BUFSRC_FLAG_PUSH | AVFILTER_BUFSRC_FLAG_KEEP_REF); AVFILTER_BUFSRC_FLAG_PUSH | AVFILTER_BUFSRC_FLAG_KEEP_REF);
26 if (r >= 0) {
30 if (ri >= 0) {
27 31 /* rotate the ptrs if needed */ /* rotate the ptrs if needed */
28 32 if (audio_dec_sets_p.n > 1) { if (audio_dec_sets_p.n > 1) {
29 33 avutil_audio_set_ref_t *save; avutil_audio_set_ref_t *save;
 
... ... static u8 filt_push_dec_sets(void)
34 38 a[audio_dec_sets_p.n - 1] = save; a[audio_dec_sets_p.n - 1] = save;
35 39 } }
36 40 audio_dec_sets_p.n--; audio_dec_sets_p.n--;
37 return PUSHED_ONE_SET;
38 } else if (r == AVERROR(EAGAIN))
39 return AGAIN;
41 r8 = PUSHED_ONE_SET;
42 goto unlock;
43 } else if (ri == AVERROR(EAGAIN)) {
44 r8 = AGAIN;
45 goto unlock;
46 }
40 47 FATALAF("ffmpeg:unable to submit a decoder set of frames to the filter source audio buffer context\n"); FATALAF("ffmpeg:unable to submit a decoder set of frames to the filter source audio buffer context\n");
48 unlock:
49 audio_dec_sets_unlock();
50 return r8;
41 51 } }
42 52 #undef AGAIN #undef AGAIN
43 53 #undef PUSHED_ONE_SET #undef PUSHED_ONE_SET
File npv/audio/local/code.frag.c changed (mode: 100644) (index 6c0aa29..be9ecb6)
... ... static void pcm_filt_frs_write(snd_pcm_ufrs_t ufrs_n) { loop
599 599 if (audio_filt_p.set->frs_n == 0) loop { if (audio_filt_p.set->frs_n == 0) loop {
600 600 u8 r; u8 r;
601 601
602 r = filt_push_dec_sets();
603 if (r == NO_DEC_SET || r == AGAIN)
604 return; /* not enough data for 1 set */
605 /* r == PUSHED_ONE_SET || r == FILT_SWITCHED_TO_DRAINING */
602 /* we _really_ want audio data */
603 (void)filt_push_dec_sets();
606 604 r = audio_filt_set_try_get(); r = audio_filt_set_try_get();
607 605 if (r == EOF_FILT) { if (r == EOF_FILT) {
608 606 draining_state_switch(); draining_state_switch();
 
... ... static void pcm_filt_frs_write(snd_pcm_ufrs_t ufrs_n) { loop
660 658 * XXX: getting the "right" ts from ff is convoluted * XXX: getting the "right" ts from ff is convoluted
661 659 */ */
662 660 if (audio_filt_p.pcm_written_ufrs_n == 0) if (audio_filt_p.pcm_written_ufrs_n == 0)
663 clk_ref_time_point_update(audio_filt_p.set->pts, written_ufrs_n);
661 clk_ref_time_point_update(audio_filt_p.set->pts,
662 written_ufrs_n);
664 663 audio_filt_p.pcm_written_ufrs_n += written_ufrs_n; audio_filt_p.pcm_written_ufrs_n += written_ufrs_n;
665 664 ufrs_n -= written_ufrs_n; ufrs_n -= written_ufrs_n;
666 665
 
... ... static void init_pcm_once_public(u8 *pcm_str)
771 770 } }
772 771 static void init_once_public(u8 *pcm_str) static void init_once_public(u8 *pcm_str)
773 772 { {
774 st_idx_p = -1;
773 int r;
774
775 memset(&st_p, 0, sizeof(st_p));
775 776 pkt_q_p = pkt_q_new("audio"); pkt_q_p = pkt_q_new("audio");
776 777 dec_ctx_p = 0; dec_ctx_p = 0;
777 778 dec_sets_p.eof_receive = false; dec_sets_p.eof_receive = false;
 
... ... static void init_once_public(u8 *pcm_str)
786 787 if (draining_timer_fd_p == -1) if (draining_timer_fd_p == -1)
787 788 FATALA("unable to get a draining timer file descriptor:%s\n", strerror(errno)); FATALA("unable to get a draining timer file descriptor:%s\n", strerror(errno));
788 789 draining_p = false; draining_p = false;
790 r = pthread_mutex_init(&dec_ctx_mutex_l, 0);
791 if (r != 0)
792 FATALA("%d:unable to init the decoder mutex\n", r);
793 r = pthread_mutex_init(&dec_sets_p.mutex, 0);
794 if (r != 0)
795 FATALA("%d:unable to init the mutex for the array of decoder sets\n", r);
789 796 } }
790 797 static void init_once_local(void) static void init_once_local(void)
791 798 { {
File npv/audio/local/state.frag.c changed (mode: 100644) (index 66eeb98..cef7b74)
1 1 /* ff dec */ /* ff dec */
2 static avcodec_codec_t *dec_l;
2 static avcodec_codec_t *dec_l; /* same mutex than dec_ctx_p */
3 static pthread_mutex_t dec_ctx_mutex_l;
3 4 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
4 5 /* alsa */ /* alsa */
5 6 static snd_output_t *pcm_pout_l; static snd_output_t *pcm_pout_l;
File npv/audio/main.c changed (mode: 100644) (index bad69ff..e320148)
10 10 #include <stdio.h> #include <stdio.h>
11 11 #include <unistd.h> #include <unistd.h>
12 12 #include <signal.h> #include <signal.h>
13 #include <pthread.h>
13 14 #include <sys/timerfd.h> #include <sys/timerfd.h>
14 15 #include <sys/epoll.h> #include <sys/epoll.h>
15 16 #include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
File npv/audio/namespace/main.c changed (mode: 100644) (index 1276ce0..d038c5a)
3 3 #define chans_buf_inc audio_chans_buf_inc #define chans_buf_inc audio_chans_buf_inc
4 4 #define dec_a_grow audio_dec_a_grow #define dec_a_grow audio_dec_a_grow
5 5 #define dec_a_unref_all audio_dec_a_unref_all #define dec_a_unref_all audio_dec_a_unref_all
6 #define dec_ctx_mutex_l audio_dec_ctx_mutex_l
6 7 #define dec_flush audio_dec_flush #define dec_flush audio_dec_flush
7 8 #define dec_l audio_dec_l #define dec_l audio_dec_l
8 9 #define draining_state_handle audio_draining_state_handle #define draining_state_handle audio_draining_state_handle
 
37 38 #undef chans_buf_inc #undef chans_buf_inc
38 39 #undef dec_a_grow #undef dec_a_grow
39 40 #undef dec_a_unref_all #undef dec_a_unref_all
41 #undef dec_ctx_mutex_l
40 42 #undef dec_l #undef dec_l
41 43 #undef dec_flush #undef dec_flush
42 44 #undef draining_state_handle #undef draining_state_handle
File npv/audio/namespace/public.h changed (mode: 100644) (index f5c2960..816c928)
1 1 #ifndef CLEANUP #ifndef CLEANUP
2 2 #define dec_ctx_cfg audio_dec_ctx_cfg #define dec_ctx_cfg audio_dec_ctx_cfg
3 #define dec_ctx_lock audio_dec_ctx_lock
3 4 #define dec_ctx_p audio_dec_ctx_p #define dec_ctx_p audio_dec_ctx_p
5 #define dec_ctx_unlock audio_dec_ctx_unlock
4 6 #define dec_flush audio_dec_flush #define dec_flush audio_dec_flush
7 #define dec_sets_lock audio_dec_sets_lock
5 8 #define dec_sets_p audio_dec_sets_p #define dec_sets_p audio_dec_sets_p
6 #define dec_sets_get_avail audio_dec_sets_get_avail
7 #define dec_set_try_get audio_dec_set_try_get
9 #define dec_sets_unlock audio_dec_sets_unlock
10 #define dec_sets_receive_avail audio_dec_sets_receive_avail
11 #define dec_set_try_receive audio_dec_set_try_receive
8 12 #define draining_p audio_draining_p #define draining_p audio_draining_p
9 13 #define draining_state_evt audio_draining_state_evt #define draining_state_evt audio_draining_state_evt
10 14 #define draining_timer_fd_p audio_draining_timer_fd_p #define draining_timer_fd_p audio_draining_timer_fd_p
 
18 22 #define pcm_pollfds_n_max audio_pcm_pollfds_n_max #define pcm_pollfds_n_max audio_pcm_pollfds_n_max
19 23 #define pcm_silence_bufs_cfg audio_pcm_silence_bufs_cfg #define pcm_silence_bufs_cfg audio_pcm_silence_bufs_cfg
20 24 #define pkt_q_p audio_pkt_q_p #define pkt_q_p audio_pkt_q_p
25 #define pkts_send audio_pkts_send
21 26 #define selected_ts_type_p audio_selected_ts_type_p #define selected_ts_type_p audio_selected_ts_type_p
22 #define st_idx_p audio_st_idx_p
27 #define st_p audio_st_p
23 28 /*============================================================================*/ /*============================================================================*/
24 29 #else #else
25 30 #undef dec_ctx_cfg #undef dec_ctx_cfg
31 #undef dec_ctx_lock
26 32 #undef dec_ctx_p #undef dec_ctx_p
33 #undef dec_ctx_unlock
27 34 #undef dec_flush #undef dec_flush
35 #undef dec_sets_lock
28 36 #undef dec_sets_p #undef dec_sets_p
29 #undef dec_sets_get_avail
30 #undef dec_set_try_get
37 #undef dec_sets_unlock
38 #undef dec_sets_receive_avail
39 #undef dec_set_try_receive
31 40 #undef draining_p #undef draining_p
32 41 #undef draining_state_evt #undef draining_state_evt
33 42 #undef draining_timer_fd_p #undef draining_timer_fd_p
 
41 50 #undef pcm_pollfds_n_max #undef pcm_pollfds_n_max
42 51 #undef pcm_silence_bufs_cfg #undef pcm_silence_bufs_cfg
43 52 #undef pkt_q_p #undef pkt_q_p
53 #undef pkts_send
44 54 #undef selected_ts_type #undef selected_ts_type
45 #undef st_idx_p
55 #undef st_p
46 56 #endif #endif
File npv/audio/public.h changed (mode: 100644) (index 1e553d3..3529c4f)
6 6 */ */
7 7 #include <stdbool.h> #include <stdbool.h>
8 8 #include <poll.h> #include <poll.h>
9 #include <pthread.h>
9 10 #include <libavformat/avformat.h> #include <libavformat/avformat.h>
10 11 #include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
11 12 #include <libavutil/samplefmt.h> #include <libavutil/samplefmt.h>
 
22 23 #include "npv/audio/public/state.frag.h" #include "npv/audio/public/state.frag.h"
23 24 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
24 25 static void dec_ctx_cfg(avcodec_params_t *params); static void dec_ctx_cfg(avcodec_params_t *params);
26 static void dec_ctx_lock(void);
27 static void dec_ctx_unlock(void);
28 static void dec_sets_lock(void);
29 static void dec_sets_unlock(void);
25 30 static void dec_flush(void); static void dec_flush(void);
26 static u8 dec_set_try_get(void);
27 static void dec_sets_get_avail(void);
31 static u8 dec_set_try_receive(void);
32 static void dec_sets_receive_avail(void);
28 33 static void draining_state_evt(void); static void draining_state_evt(void);
29 34 static void evt_pcm_write(void); static void evt_pcm_write(void);
30 35 static void pcm_silence_bufs_cfg(bool print_info); static void pcm_silence_bufs_cfg(bool print_info);
 
... ... static void pcm_cfg(snd_pcm_t *pcm, unsigned int chans_n, unsigned int rate,
34 39 static void pcm2ff(snd_pcm_t *pcm, enum avutil_audio_fr_fmt_t *ff_fmt, static void pcm2ff(snd_pcm_t *pcm, enum avutil_audio_fr_fmt_t *ff_fmt,
35 40 int *ff_rate, int *ff_chans_n, uint64_t *ff_chans_layout, int *ff_rate, int *ff_chans_n, uint64_t *ff_chans_layout,
36 41 bool print_info); bool print_info);
42 static void pkts_send(void);
37 43 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
38 44 #define CLEANUP #define CLEANUP
39 45 #include "npv/namespace/ffmpeg.h" #include "npv/namespace/ffmpeg.h"
File npv/audio/public/code.frag.c changed (mode: 100644) (index 2eca537..370e80f)
... ... static void dec_ctx_cfg(avcodec_params_t *params)
22 22 #define AGAIN 0 #define AGAIN 0
23 23 #define HAVE_DEC_SET 1 #define HAVE_DEC_SET 1
24 24 #define EOF_DEC 2 #define EOF_DEC 2
25 static u8 dec_set_try_get(void)
25 static u8 dec_set_try_receive(void)
26 26 { {
27 27 int r; int r;
28 28 u32 last; u32 last;
 
... ... static u8 dec_set_try_get(void)
31 31 return EOF_DEC; return EOF_DEC;
32 32 if (dec_sets_p.n == dec_sets_p.n_max) if (dec_sets_p.n == dec_sets_p.n_max)
33 33 dec_a_grow(); dec_a_grow();
34 /* will unref any previous dec_sets_p.a[x] bufs for us */
35 34 last = dec_sets_p.n; last = dec_sets_p.n;
35 /* will unref any previous dec_sets_p.a[x] bufs for us */
36 36 r = avcodec_receive_audio_set(dec_ctx_p, dec_sets_p.a[last]); r = avcodec_receive_audio_set(dec_ctx_p, dec_sets_p.a[last]);
37 if (r == AVUTIL_AVERROR(EAGAIN)) {
37 if (r == AVUTIL_AVERROR(EAGAIN))
38 38 return AGAIN; return AGAIN;
39 } else if (r == 0) {
39 else if (r == 0) {
40 40 ++dec_sets_p.n; ++dec_sets_p.n;
41 41 return HAVE_DEC_SET; return HAVE_DEC_SET;
42 42 } else if (r == AVUTIL_AVERROR_EOF) { } else if (r == AVUTIL_AVERROR_EOF) {
 
... ... static u8 dec_set_try_get(void)
52 52 #define AGAIN 0 #define AGAIN 0
53 53 #define HAVE_DEC_SET 1 #define HAVE_DEC_SET 1
54 54 #define EOF_DEC 2 #define EOF_DEC 2
55 static void dec_sets_get_avail(void) { loop
55 /*
56 * this can be long and we don't want to lock that long the q of audio frs
57 * for the alsa writer, then do finer-grained locking here
58 */
59 static void dec_sets_receive_avail(void) { loop
56 60 { {
57 61 u8 r; u8 r;
58 62
59 r = dec_set_try_get();
63 dec_ctx_lock();
64 dec_sets_lock();
65 r = dec_set_try_receive();
66 dec_sets_unlock();
67 dec_ctx_unlock();
60 68 if (r == HAVE_DEC_SET) if (r == HAVE_DEC_SET)
61 69 continue; continue;
62 70 else if (r == AGAIN || r == EOF_DEC) else if (r == AGAIN || r == EOF_DEC)
 
... ... static void dec_flush(void)
197 205 dec_sets_p.eof_receive = false; dec_sets_p.eof_receive = false;
198 206 avcodec_flush_bufs(dec_ctx_p); avcodec_flush_bufs(dec_ctx_p);
199 207 } }
208 static void dec_ctx_lock(void)
209 {
210 int r;
211
212 r = pthread_mutex_lock(&dec_ctx_mutex_l);
213 if (r != 0)
214 FATALA("%d:unable to lock the decoder context\n", r);
215 }
216 static void dec_ctx_unlock(void)
217 {
218 int r;
219
220 r = pthread_mutex_unlock(&dec_ctx_mutex_l);
221 if (r != 0)
222 FATALA("%d:unable to unlock the decoder context\n", r);
223 }
224 static void dec_sets_lock(void)
225 {
226 int r;
227
228 r = pthread_mutex_lock(&dec_sets_p.mutex);
229 if (r != 0)
230 FATALA("%d:unable to lock the array of decoder sets\n", r);
231 }
232 static void dec_sets_unlock(void)
233 {
234 int r;
235
236 r = pthread_mutex_unlock(&dec_sets_p.mutex);
237 if (r != 0)
238 FATALA("%d:unable to unlock the array of decoder sets\n", r);
239 }
200 240 static void pcm_cfg(snd_pcm_t *pcm, unsigned int chans_n, unsigned int rate, static void pcm_cfg(snd_pcm_t *pcm, unsigned int chans_n, unsigned int rate,
201 241 enum avutil_audio_fr_fmt_t ff_fmt) enum avutil_audio_fr_fmt_t ff_fmt)
202 242 { {
 
... ... static void pcm2ff(snd_pcm_t *pcm, enum avutil_audio_fr_fmt_t *ff_fmt,
247 287 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
248 288 snd_pcm_hw_params_free(hw_params); snd_pcm_hw_params_free(hw_params);
249 289 } }
290 /* we do per-loop fine-grained locking */
291 #define sz size
292 static void pkts_send(void) { loop
293 {
294 int r;
295 avcodec_pkt_ref_t *pr;
296
297 pkt_q_lock(pkt_q_p);
298 if (pkt_q_p->n == 0)
299 goto unlock_and_return;
300 pr = pkt_q_p->q[0];
301 dec_ctx_lock();
302 r = avcodec_send_pkt(dec_ctx_p, pr);
303 dec_ctx_unlock();
304 if (r == AVERROR(EAGAIN)) /* dec is full and the pkt is rejected */
305 goto unlock_and_return;
306 else if (r == AVUTIL_AVERROR_EOF) /* the dec is in draining mode */
307 goto unlock_and_return;
308 else if (r != 0)
309 FATALA("error while sending a packet to the decoder\n");
310 /* r == 0 */
311 pipeline_limits_lock();
312 pipeline_limits_p.pkts.audio_bytes_n -= pr->sz;
313 pipeline_limits_unlock();
314
315 pkt_q_deq(pkt_q_p);
316 avcodec_pkt_unref(pr);
317 pkt_q_unlock(pkt_q_p);
318 continue;
319
320 unlock_and_return:
321 pkt_q_unlock(pkt_q_p);
322 return;
323 }}
324 #undef sz
File npv/audio/public/state.frag.h changed (mode: 100644) (index 7a9cbb0..4a009ad)
1 1 static avcodec_codec_ctx_t *dec_ctx_p; static avcodec_codec_ctx_t *dec_ctx_p;
2 2 static struct { static struct {
3 bool eof_receive; /* "receiving" from the dec returned eof */
3 pthread_mutex_t mutex;
4 4
5 bool eof_receive; /* "receiving" from the dec returned eof */
5 6 u32 n_max; u32 n_max;
6 7 u32 n; u32 n;
7 8 avutil_audio_set_ref_t **a; avutil_audio_set_ref_t **a;
8 9 } dec_sets_p; } dec_sets_p;
9 10 static struct pkt_q_t *pkt_q_p; static struct pkt_q_t *pkt_q_p;
10 static int st_idx_p;
11 /*
12 * we copy some stream data in the case the stream does vanish or is replaced
13 * (don't know how ffmpeg does handle this)
14 */
15 static struct {
16 int idx;
17 int id;
18 avutil_rational_t tb;
19 int64_t start_time;
20 } st_p;
11 21 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
12 22 /* alsa -- start */ /* alsa -- start */
13 23 static snd_pcm_t *pcm_p; static snd_pcm_t *pcm_p;
File npv/c_fixing.h changed (mode: 100644) (index 117136d..9516575)
28 28 #if UCHAR_WIDTH == 8 #if UCHAR_WIDTH == 8
29 29 #define atomic_u8 atomic_uchar #define atomic_u8 atomic_uchar
30 30 #else #else
31 #error "unable to find the right atomic for a 8 bits byte needed for futex, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined"
31 #error "unable to find the right atomic for a 8 bits byte, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined"
32 #endif
33 #if SHRT_WIDTH == 16
34 #define atomic_u16 atomic_ushort
35 #else
36 #error "unable to find the right atomic for an unsigned 16 bits word, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined"
32 37 #endif #endif
33 38 #if UINT_WIDTH == 32 #if UINT_WIDTH == 32
34 39 #define atomic_u32 atomic_uint #define atomic_u32 atomic_uint
35 40 #elif ULONG_WIDTH == 32 #elif ULONG_WIDTH == 32
36 41 #define atomic_u32 atomic_ulong #define atomic_u32 atomic_ulong
37 42 #else #else
38 #error "unable to select the right atomic for a 32 bits word needed for futex, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined"
43 #error "unable to select the right atomic for an unsigned 32 bits word, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined"
44 #endif
45 #if LONG_WIDTH == 64
46 #define atomic_s64 atomic_long
47 #else
48 #error "unable to select the right atomic for a 64 bits signed word, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined"
39 49 #endif #endif
40 50
41 51 #define loop for(;;) #define loop for(;;)
File npv/clk/main.c changed (mode: 100644) (index ec4db14..115012d)
6 6 */ */
7 7 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
8 8 #include <string.h> #include <string.h>
9 #include <pthread.h>
9 10 #include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
10 11 #include <libavformat/avformat.h> #include <libavformat/avformat.h>
11 12 #include "npv/c_fixing.h" #include "npv/c_fixing.h"
12 #include "npv/fmt/public.h"
13 13 #include "npv/audio/public.h" #include "npv/audio/public.h"
14 14 #include "npv/video/public.h" #include "npv/video/public.h"
15 15 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
File npv/clk/public/code.frag.c changed (mode: 100644) (index 3585313..1795d99)
... ... static u8 clk_get_audio_st_ts(s64 *ts)
51 51
52 52 ref_audio_ts = (f64)clk_l.ref.audio_st_ts; ref_audio_ts = (f64)clk_l.ref.audio_st_ts;
53 53 ref_delay_frs_n = (f64)snd_pcm_status_get_delay(clk_l.ref.status); ref_delay_frs_n = (f64)snd_pcm_status_get_delay(clk_l.ref.status);
54 audio_tb_num = (f64)fmt_ctx_p->sts[audio_st_idx_p]->tb.num;
55 audio_tb_den = (f64)fmt_ctx_p->sts[audio_st_idx_p]->tb.den;
54 audio_tb_num = (f64)audio_st_p.tb.num;
55 audio_tb_den = (f64)audio_st_p.tb.den;
56 56 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
57 57 r = snd_pcm_hw_params_current(audio_pcm_p, clk_pcm_hw_params_l); r = snd_pcm_hw_params_current(audio_pcm_p, clk_pcm_hw_params_l);
58 58 if (r != 0) if (r != 0)
 
... ... static u8 clk_get_video_st_ts(s64 *ts)
87 87 f64 now_video_ts; f64 now_video_ts;
88 88 u8 r; u8 r;
89 89
90 audio_tb_num = (f64)fmt_ctx_p->sts[audio_st_idx_p]->tb.num;
91 audio_tb_den = (f64)fmt_ctx_p->sts[audio_st_idx_p]->tb.den;
92 video_tb_num = (f64)fmt_ctx_p->sts[video_st_idx_p]->tb.num;
93 video_tb_den = (f64)fmt_ctx_p->sts[video_st_idx_p]->tb.den;
90 audio_tb_num = (f64)audio_st_p.tb.num;
91 audio_tb_den = (f64)audio_st_p.tb.den;
92 video_tb_num = (f64)video_st_p.tb.num;
93 video_tb_den = (f64)video_st_p.tb.den;
94 94
95 95 r = clk_get_audio_st_ts(&now_audio_ts_s64); r = clk_get_audio_st_ts(&now_audio_ts_s64);
96 96 if (r != TS_RETURNED) if (r != TS_RETURNED)
File npv/fmt/local/code.frag.c changed (mode: 100644) (index 044d315..9b8a611)
... ... static void init_once_public(u8 *url)
6 6 r = avformat_open_input(&ctx_p, url, NULL, NULL); r = avformat_open_input(&ctx_p, url, NULL, NULL);
7 7 if (r < 0) if (r < 0)
8 8 FATALF("ffmpeg:unable to open \"%s\"\n", url); FATALF("ffmpeg:unable to open \"%s\"\n", url);
9 r = pthread_mutex_init(&ctx_mutex_l, 0);
10 if (r != 0)
11 FATALF("unable to init the format mutex\n");
9 12 } }
10 13 static void init_once_local(void) static void init_once_local(void)
11 14 { {
 
... ... static void init_once_local(void)
13 16 if (pkt_l == 0) if (pkt_l == 0)
14 17 FATALF("ffmpeg:unable to allocate a reference on a packet for encoded/compressed audio/video\n"); FATALF("ffmpeg:unable to allocate a reference on a packet for encoded/compressed audio/video\n");
15 18 } }
19 static void ctx_lock(void)
20 {
21 int r;
22
23 r = pthread_mutex_lock(&ctx_mutex_l);
24 if (r != 0)
25 FATALF("%d:unable to lock the format context\n", r);
26 }
27 static void ctx_unlock(void)
28 {
29 int r;
30
31 r = pthread_mutex_unlock(&ctx_mutex_l);
32 if (r != 0)
33 FATALF("%d:unable to unlock the format context\n", r);
34 }
File npv/fmt/local/state.frag.c changed (mode: 100644) (index a1cad7b..15fd6ab)
1 1 static avcodec_pkt_ref_t *pkt_l; static avcodec_pkt_ref_t *pkt_l;
2 static pthread_mutex_t ctx_mutex_l;
File npv/fmt/main.c changed (mode: 100644) (index 8757761..e01fc75)
4 4 * code protected with a GNU affero GPLv3 license * code protected with a GNU affero GPLv3 license
5 5 * copyright (C) 2020 Sylvain BERTRAND * copyright (C) 2020 Sylvain BERTRAND
6 6 */ */
7 #include <pthread.h>
7 8 #include <libavformat/avformat.h> #include <libavformat/avformat.h>
8 9 #include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
9 10 #include "npv/c_fixing.h" #include "npv/c_fixing.h"
File npv/fmt/namespace/main.c changed (mode: 100644) (index 26d01d9..1399a6c)
1 1 #ifndef CLEANUP #ifndef CLEANUP
2 2 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
3 /* misc */
3 4 #define avformat_read_pkt av_read_frame #define avformat_read_pkt av_read_frame
4 5 #define programs_n nb_programs #define programs_n nb_programs
5 6 #define st stream #define st stream
6 7 #define st_idx stream_index #define st_idx stream_index
7 8 #define sts_n nb_streams #define sts_n nb_streams
9 #define sz size
8 10 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
9 11 #define audio fmt_break_on_audio #define audio fmt_break_on_audio
12 #define ctx_mutex_l fmt_ctx_mutex_l
10 13 #define pkt_l fmt_pkt_l #define pkt_l fmt_pkt_l
11 14 #define video fmt_break_on_video #define video fmt_break_on_video
12 15 /*============================================================================*/ /*============================================================================*/
 
17 20 #undef st #undef st
18 21 #undef st_idx #undef st_idx
19 22 #undef sts_n #undef sts_n
23 #undef sz
20 24 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
21 25 #undef audio #undef audio
26 #undef ctx_mutex_l
22 27 #undef pkt_l #undef pkt_l
23 28 #undef video #undef video
24 29 #endif #endif
File npv/fmt/namespace/public.h changed (mode: 100644) (index a5d8336..83e463a)
1 1 #ifndef CLEANUP #ifndef CLEANUP
2 2 #define break_on_audio fmt_break_on_audio #define break_on_audio fmt_break_on_audio
3 3 #define break_on_video fmt_break_on_video #define break_on_video fmt_break_on_video
4 #define ctx_lock fmt_ctx_lock
4 5 #define ctx_p fmt_ctx_p #define ctx_p fmt_ctx_p
6 #define ctx_unlock fmt_ctx_unlock
5 7 #define duration_estimate_to_str fmt_duration_estimate_to_str #define duration_estimate_to_str fmt_duration_estimate_to_str
6 8 #define flush fmt_flush #define flush fmt_flush
7 9 #define init_once fmt_init_once #define init_once fmt_init_once
 
13 15 #else #else
14 16 #undef break_on_audio #undef break_on_audio
15 17 #undef break_on_video #undef break_on_video
18 #undef ctx_lock
16 19 #undef ctx_p #undef ctx_p
20 #undef ctx_unlock
17 21 #undef duration_estimate_to_str #undef duration_estimate_to_str
18 22 #undef flush #undef flush
19 23 #undef init_once #undef init_once
File npv/fmt/public.h changed (mode: 100644) (index 7a96b2a..24b6b9d)
6 6 */ */
7 7 #include <libavformat/avformat.h> #include <libavformat/avformat.h>
8 8 #include "npv/c_fixing.h" #include "npv/c_fixing.h"
9 #include "npv/pipeline/public.h"
9 10 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
10 11 #include "npv/namespace/ffmpeg.h" #include "npv/namespace/ffmpeg.h"
11 12 #include "npv/fmt/namespace/public.h" #include "npv/fmt/namespace/public.h"
 
14 15 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
15 16 static u8 *duration_estimate_to_str( static u8 *duration_estimate_to_str(
16 17 enum avformat_duration_estimation_method_t m); enum avformat_duration_estimation_method_t m);
17 static void probe_best_sts(int *best_v, int *best_a);
18 static void probe_best_sts(
19 int *best_v_idx, int *best_v_id, avutil_rational_t **best_v_tb,
20 int64_t *best_v_start_time, avcodec_params_t **best_v_codec_params,
21 int *best_a_idx, int *best_a_id, avutil_rational_t **best_a_tb,
22 int64_t *best_a_start_time, avcodec_params_t **best_a_codec_params);
18 23 static void init_once(u8 *url); static void init_once(u8 *url);
19 constant_u32 {
20 break_on_video = 0x01,
21 break_on_audio = 0x02
22 };
23 static u8 pkts_read_and_q(u8 break_on);
24 static u8 pkts_read_and_q(void);
24 25 static void flush(void); static void flush(void);
26 static void fmt_ctx_lock(void);
27 static void fmt_ctx_unlock(void);
25 28 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
26 29 #define CLEANUP #define CLEANUP
27 30 #include "npv/namespace/ffmpeg.h" #include "npv/namespace/ffmpeg.h"
File npv/fmt/public/code.frag.c changed (mode: 100644) (index 9ae7123..8370517)
... ... static u8 *duration_estimate_to_str(enum avformat_duration_estimation_method_t
12 12 return "unkwown"; return "unkwown";
13 13 } }
14 14 } }
15 /*NSPC*/
16 static bool did_reached_limits(void)
17 {
18 bool r;
19
20 pipeline_limits_lock();
21 if (pipeline_limits_p.pkts.audio_bytes_n
22 >= pipeline_limits_p.pkts.limit.audio_bytes_n
23 && pipeline_limits_p.pkts.video_bytes_n
24 >= pipeline_limits_p.pkts.limit.video_bytes_n)
25 r = true;
26 else
27 r = false;
28 pipeline_limits_unlock();
29 return false;
30 }
15 31 #define AGAIN 0 #define AGAIN 0
16 #define HAVE_PKT 1
32 #define LIMITS_REACHED 1
17 33 #define EOF_FMT 2 #define EOF_FMT 2
18 static u8 pkts_read_and_q(u8 break_on) { loop
34 /*
35 * we don't want to lock any pkt q for too long, then we do finer-grained
36 * locking here
37 */
38 static u8 pkts_read_and_q(void) { loop
19 39 { {
20 40 int r; int r;
21 41
42 if (did_reached_limits())
43 return LIMITS_REACHED;
44 /* XXX: there, new streams can appear (could some disappear?) */
45 ctx_lock();
22 46 r = avformat_read_pkt(ctx_p, pkt_l); r = avformat_read_pkt(ctx_p, pkt_l);
23 if (r == 0) {
24 if (pkt_l->st_idx == audio_st_idx_p) {
25 /* will "steal" the pkt */
26 pkt_q_enq(audio_pkt_q_p, pkt_l);
27 if ((break_on & audio) != 0)
28 return HAVE_PKT;
29 } else if (pkt_l->st_idx == video_st_idx_p) {
30 /* will "steal" the pkt */
31 pkt_q_enq(video_pkt_q_p, pkt_l);
32 if ((break_on & video) != 0)
33 return HAVE_PKT;
34 }
35 /* other types of pkt: data, subtitles, etc */
36 avcodec_pkt_unref(pkt_l);
37 continue;
38 } else if (r == AVERROR(EAGAIN))
47 ctx_unlock();
48 if (r == AVERROR(EAGAIN))
39 49 return AGAIN; return AGAIN;
40 50 else if (r == AVERROR_EOF) else if (r == AVERROR_EOF)
41 51 return EOF_FMT; return EOF_FMT;
42 FATALF("ffmpeg:error while reading coded/compressed data into packets\n");
52 else if (r != 0)
53 FATALF("ffmpeg:error while reading coded/compressed data into packets\n");
54 /* r == 0 */
55 if (pkt_l->st_idx == audio_st_p.idx) {
56 pipeline_limits_lock();
57 pipeline_limits_p.pkts.audio_bytes_n += (u64)pkt_l->sz;
58 if (pipeline_limits_p.pkts.prefill.audio_bytes_rem > 0)
59 pipeline_limits_p.pkts.prefill.audio_bytes_rem -=
60 (s64)pkt_l->sz;
61 pipeline_limits_unlock();
62
63 pkt_q_lock(audio_pkt_q_p);
64 /* will "steal" the pkt */
65 pkt_q_enq(audio_pkt_q_p, pkt_l);
66 pkt_q_unlock(audio_pkt_q_p);
67 } else if (pkt_l->st_idx == video_st_p.idx) {
68 pipeline_limits_lock();
69 pipeline_limits_p.pkts.video_bytes_n += (u64)pkt_l->sz;
70 if (pipeline_limits_p.pkts.prefill.video_bytes_rem > 0)
71 pipeline_limits_p.pkts.prefill.video_bytes_rem -=
72 (s64)pkt_l->sz;
73 pipeline_limits_unlock();
74
75 pkt_q_lock(video_pkt_q_p);
76 /* will "steal" the pkt */
77 pkt_q_enq(video_pkt_q_p, pkt_l);
78 pkt_q_unlock(video_pkt_q_p);
79 } else /* data, subtitles, non active sts, etc */
80 avcodec_pkt_unref(pkt_l);
43 81 }} }}
44 82 #undef AGAIN #undef AGAIN
45 #undef HAVE_PKT
83 #undef LIMITS_REACHED
46 84 #undef EOF_FMT #undef EOF_FMT
47 static void probe_best_sts(int *best_v, int *best_a)
85 static void probe_best_sts(
86 int *best_v_idx, int *best_v_id, avutil_rational_t **best_v_tb,
87 int64_t *best_v_start_time, avcodec_params_t **best_v_codec_params,
88 int *best_a_idx, int *best_a_id, avutil_rational_t **best_a_tb,
89 int64_t *best_a_start_time, avcodec_params_t **best_a_codec_params)
48 90 { {
49 91 int r; int r;
50 92
 
... ... static void probe_best_sts(int *best_v, int *best_a)
56 98 0); 0);
57 99 if (r < 0) if (r < 0)
58 100 FATALF("ffmpeg:no audio stream found\n"); FATALF("ffmpeg:no audio stream found\n");
59 *best_a = r;
101 /* we copy what we need */
102 *best_a_idx = r;
103 *best_a_id = ctx_p->sts[r]->id;
104 *best_a_tb = &ctx_p->sts[r]->tb;
105 *best_a_start_time = ctx_p->sts[r]->start_time;
106 *best_a_codec_params = ctx_p->sts[r]->codecpar; /* used once for init */
60 107
61 108 r = avformat_find_best_st(ctx_p, AVUTIL_AVMEDIA_TYPE_VIDEO, -1, -1, 0, r = avformat_find_best_st(ctx_p, AVUTIL_AVMEDIA_TYPE_VIDEO, -1, -1, 0,
62 109 0); 0);
63 110 if (r < 0) if (r < 0)
64 111 FATALF("ffmpeg:no video stream found\n"); FATALF("ffmpeg:no video stream found\n");
65 *best_v = r;
112 /* we copy what we need */
113 *best_v_idx = r;
114 *best_v_id = ctx_p->sts[r]->id;
115 *best_v_tb = &ctx_p->sts[r]->tb;
116 *best_v_start_time = ctx_p->sts[r]->start_time;
117 *best_v_codec_params = ctx_p->sts[r]->codecpar; /* used once for init */
66 118 POUTF("####%s#### probing: %u streams and %u programs\n", ctx_p->url, ctx_p->sts_n, ctx_p->programs_n); POUTF("####%s#### probing: %u streams and %u programs\n", ctx_p->url, ctx_p->sts_n, ctx_p->programs_n);
67 POUTF("####%s#### probing: best video stream id=%d, best audio stream id=%d\n", ctx_p->url, ctx_p->sts[video_st_idx_p]->id, ctx_p->sts[audio_st_idx_p]->id);
119 POUTF("####%s#### probing: best video stream index=%d/id=%d, best audio stream index=%d/id=%d\n", ctx_p->url, *best_v_idx, *best_v_id, *best_a_idx, *best_a_id);
68 120 } }
69 121 static void flush(void) static void flush(void)
70 122 { {
File npv/input/local/code.frag.c deleted (index 3e78dbf..0000000)
1 static void timer_init_once(void)
2 {
3 /* linux bug: still no CLOCK_MONOTONIC_RAW for timerfd */
4 errno = 0;
5 timer_fd_p = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
6 if (timer_fd_p == -1)
7 FATALI("unable to get a timer file descriptor:%s\n", strerror(errno));
8 }
9 static void timer_ack(void)
10 {
11 int r;
12 uint64_t exps_n;
13
14 exps_n = 0;
15 r = read(timer_fd_p, &exps_n, sizeof(exps_n));
16 if (r == -1)
17 FATALI("unable to read the number of timer expirations\n");
18 }
File npv/input/main.c deleted (index c183ca3..0000000)
1 #ifndef NPV_INPUT_MAIN_C
2 #define NPV_INPUT_MAIN_C
3 /*
4 * code protected with a GNU affero GPLv3 license
5 * copyright (C) 2020 Sylvain BERTRAND
6 */
7 #include <string.h>
8 #include <stdint.h>
9 #include <sys/timerfd.h>
10 #include "npv/c_fixing.h"
11 #include "npv/global.h"
12 #include "npv/pkt_q/public.h"
13 #include "npv/input/public.h"
14 #include "npv/fmt/public.h"
15 #include "npv/audio/public.h"
16 #include "npv/video/public.h"
17 /*----------------------------------------------------------------------------*/
18 #include "npv/namespace/ffmpeg.h"
19 #include "npv/input/namespace/public.h"
20 #include "npv/input/namespace/main.c"
21 /*----------------------------------------------------------------------------*/
22 #define FATALI(fmt, ...) FATAL("input:" fmt, ##__VA_ARGS__)
23 #define WARNINGI(fmt, ...) WARNING("input:" fmt, ##__VA_ARGS__)
24 #define POUTI(fmt, ...) POUT("input:" fmt, ##__VA_ARGS__)
25 /*----------------------------------------------------------------------------*/
26 #define TIMER_INTERVAL_NSECS_N 1000000 /* 1 ms */
27 #define BOOTSTRAP_VIDEO_FRS_N_LIMIT 5 /* usually expensive */
28 #define BOOTSTRAP_AUDIO_SETS_N_LIMIT 20 /* usually cheap */
29 #define VIDEO_FRS_N_LIMIT 10 /* usually expensive */
30 #define AUDIO_SETS_N_LIMIT 20 /* usually cheap */
31 /*----------------------------------------------------------------------------*/
32 #include "npv/input/local/state.frag.c"
33 /*----------------------------------------------------------------------------*/
34 #include "npv/input/local/code.frag.c"
35 #include "npv/input/public/code.frag.c"
36 /*----------------------------------------------------------------------------*/
37 #undef TIMER_INTERVAL_NSECS_N
38 #undef VIDEO_FRS_N_LIMIT
39 #undef AUDIO_SETS_N_LIMIT
40 #undef FATALI
41 #undef WARNINGI
42 #undef POUTI
43 #undef BOOTSTRAP_VIDEO_FRS_N_LIMIT
44 #undef BOOTSTRAP_AUDIO_SETS_N_LIMIT
45 /*---------------------------------------------------------------------------*/
46 #define CLEANUP
47 #include "npv/namespace/ffmpeg.h"
48 #include "npv/input/namespace/public.h"
49 #include "npv/input/namespace/main.c"
50 #undef CLEANUP
51 #endif
File npv/input/namespace/main.c deleted (index e21e819..0000000)
1 #ifndef CLEANUP
2 /*----------------------------------------------------------------------------*/
3 /* some struct fields */
4 #define sz size
5 /*----------------------------------------------------------------------------*/
6 #define timer_ack input_timer_ack
7 #define timer_init_once input_timer_init_once
8 /*============================================================================*/
9 #else
10 #undef timer_ack
11 #undef timer_init_once
12 /*----------------------------------------------------------------------------*/
13 #undef sz
14 /*----------------------------------------------------------------------------*/
15 #endif
16
File npv/input/namespace/public.h deleted (index ee12f6f..0000000)
1 #ifndef CLEANUP
2 #define bootstrap_audio_video input_bootstrap_audio_video
3 #define init_once input_init_once
4 #define timer_evt input_timer_evt
5 #define timer_fd_p input_timer_fd_p
6 #define timer_start input_timer_start
7 /*============================================================================*/
8 #else
9 #undef bootstrap_audio_video
10 #undef init_once
11 #undef timer_evt
12 #undef timer_fd_p
13 #undef timer_start
14 #endif
File npv/input/public.h deleted (index 9fa5f46..0000000)
1 #ifndef NPV_INPUT_PUBLIC_H
2 #define NPV_INPUT_PUBLIC_H
3 /*
4 * code protected with a GNU affero GPLv3 license
5 * copyright (C) 2020 Sylvain BERTRAND
6 */
7 /*---------------------------------------------------------------------------*/
8 #include "npv/input/namespace/public.h"
9 /*---------------------------------------------------------------------------*/
10 static int timer_fd_p;
11 static void init_once(void);
12 static void timer_start(void);
13 static void timer_evt(void);
14 static void bootstrap_audio_video(void);
15 /*---------------------------------------------------------------------------*/
16 #define CLEANUP
17 #include "npv/input/namespace/public.h"
18 #undef CLEANUP
19 #endif
File npv/input/public/code.frag.c deleted (index 68e5be3..0000000)
1 static void init_once(void)
2 {
3 timer_init_once();
4 eof_pkt_l = avcodec_pkt_ref_alloc();
5 if (eof_pkt_l == 0)
6 FATALI("ffmpeg:unable to allocate a null/eof reference on a packet\n");
7 eof_pkt_l->data = 0;
8 eof_pkt_l->sz = 0;
9 }
10 static void timer_start(void)
11 {
12 struct itimerspec t;
13 int r;
14
15 memset(&t, 0, sizeof(t));
16 /* initial and interval */
17 t.it_value.tv_nsec = TIMER_INTERVAL_NSECS_N;
18 t.it_interval.tv_nsec = TIMER_INTERVAL_NSECS_N;
19 r = timerfd_settime(timer_fd_p, 0, &t, 0);
20 if (r == -1)
21 FATALI("unable to arm the timer\n");
22 }
23 #define AGAIN 0
24 #define HAVE_AUDIO_DEC_SET 1
25 #define HAVE_VIDEO_FR 1
26 #define EOF_FMT 2
27 #define EOF_VIDEO_DEC 2
28 #define EOF_AUDIO_DEC 2
29 #define STOP 4
30 /*
31 * audio and video are decoupled
32 * 2 steps:
33 * 1 - one set of audio frs, one video fr
34 * 2 - buffering of sets of audio frs, buffering of video frs
35 */
36 static void bootstrap_audio_video(void)
37 {
38 u8 fmt;
39 u8 audio;
40 u8 video;
41 u8 break_on;
42
43 audio = AGAIN;
44 video = AGAIN;
45 break_on = fmt_break_on_audio | fmt_break_on_video;
46 loop {
47 fmt = fmt_pkts_read_and_q(break_on);
48 if (fmt == EOF_FMT) {
49 if (!pkt_q_has_eof(audio_pkt_q_p))
50 pkt_q_enq(audio_pkt_q_p, eof_pkt_l);
51 if (!pkt_q_has_eof(video_pkt_q_p))
52 pkt_q_enq(video_pkt_q_p, eof_pkt_l);
53 }
54 if (audio == AGAIN) { /* first step */
55 (void)pkt_q_send(audio_pkt_q_p, audio_dec_ctx_p);
56 audio = audio_dec_set_try_get();
57 if (audio == EOF_AUDIO_DEC) {
58 audio = STOP;
59 WARNING("bootstrap:end of file reached before one set of audio frames could be available for playing, %u sets of audio frames\n", BOOTSTRAP_AUDIO_SETS_N_LIMIT);
60 }
61 } else if (audio == HAVE_AUDIO_DEC_SET) { /* 2nd step */
62 if (audio_dec_sets_p.n
63 <= BOOTSTRAP_AUDIO_SETS_N_LIMIT) {
64 u8 r;
65
66 r = pkt_q_send(audio_pkt_q_p, audio_dec_ctx_p);
67 if (r == EOF_AUDIO_DEC || r == AGAIN) {
68 audio = STOP;
69 break_on &= ~fmt_break_on_audio;
70 }
71 audio_dec_sets_get_avail();
72 } else {
73 audio = STOP;
74 break_on &= ~fmt_break_on_audio;
75 }
76 }
77 if (video == AGAIN) { /* first step */
78 (void)pkt_q_send(video_pkt_q_p, video_dec_ctx_p);
79 video = video_dec_fr_try_get();
80 if (video == EOF_VIDEO_DEC) {
81 video = STOP;
82 WARNING("bootstrap:end of file reached before one video frame could be available for presentation, %u video frames\n", BOOTSTRAP_VIDEO_FRS_N_LIMIT);
83 }
84 } else if (video == HAVE_VIDEO_FR) { /* 2nd step: buffering */
85 if (video_dec_frs_p.n
86 <= BOOTSTRAP_VIDEO_FRS_N_LIMIT) {
87 u8 r;
88 r = pkt_q_send(video_pkt_q_p, video_dec_ctx_p);
89 if (r == EOF_VIDEO_DEC || r == AGAIN) {
90 video = STOP;
91 break_on &= ~fmt_break_on_video;
92 }
93 video_dec_frs_get_avail();
94 } else {
95 video = STOP;
96 break_on &= ~fmt_break_on_video;
97 }
98 }
99 if (video == STOP && audio == STOP)
100 break;
101 }
102 }
103 #undef AGAIN
104 #undef HAVE_AUDIO_DEC_SET
105 #undef HAVE_VIDEO_FR
106 #undef EOF_FMT
107 #undef EOF_VIDEO_DEC
108 #undef EOF_AUDIO_DEC
109 #undef STOP
110 #define AGAIN 0
111 #define SEND 0
112 #define HAVE_PKT 1
113 #define EOF_FMT 2
114 #define EOF_DEC 2
115 #define STOP 4
116 /*
117 * TODO: bad, should consider unlimited streams in the 2 following cases:
118 * - very fast
119 * - very slow
120 */
121 static void timer_evt(void)
122 {
123 u8 audio;
124 u8 video;
125 u8 break_on;
126
127 timer_ack();
128 /* 1 - empty the decs as much as we can */
129 audio_dec_sets_get_avail();
130 video_dec_frs_get_avail();
131 /*
132 * 2 - send pkts as much as we can in decs unless we did bump on our
133 * reasonable limits
134 */
135 break_on = 0;
136 if (audio_dec_sets_p.n > AUDIO_SETS_N_LIMIT)
137 audio = STOP;
138 else {
139 break_on |= fmt_break_on_audio;
140 audio = SEND;
141 }
142 if (video_dec_frs_p.n > VIDEO_FRS_N_LIMIT)
143 video = STOP;
144 else {
145 break_on |= fmt_break_on_video;
146 video = SEND;
147 }
148 loop {
149 u8 r;
150
151 if (video == STOP && audio == STOP)
152 break;
153 r = fmt_pkts_read_and_q(break_on);
154 if (r == EOF_FMT) {
155 if (!pkt_q_has_eof(audio_pkt_q_p))
156 pkt_q_enq(audio_pkt_q_p, eof_pkt_l);
157 if (!pkt_q_has_eof(video_pkt_q_p))
158 pkt_q_enq(video_pkt_q_p, eof_pkt_l);
159 (void)pkt_q_send(audio_pkt_q_p, audio_dec_ctx_p);
160 (void)pkt_q_send(video_pkt_q_p, video_dec_ctx_p);
161 break;
162 }
163 if (r == AGAIN)
164 break;
165 /* r == HAVE_PKT */
166 if (audio != STOP) {
167 r = pkt_q_send(audio_pkt_q_p, audio_dec_ctx_p);
168 if (r == AGAIN || r == EOF_DEC) {
169 audio = STOP;
170 break_on &= ~fmt_break_on_audio;
171 } else /* r == EMPTY */
172 audio = SEND;
173 }
174 if (video != STOP) {
175 r = pkt_q_send(video_pkt_q_p, video_dec_ctx_p);
176 if (r == AGAIN || r == EOF_DEC) {
177 video = STOP;
178 break_on &= ~fmt_break_on_video;
179 } else /* r == EMPTY */
180 video = SEND;
181 }
182 }
183 }
184 #undef AGAIN
185 #undef SEND
186 #undef HAVE_PKT
187 #undef EOF_FMT
188 #undef EOF_DEC
189 #undef STOP
File npv/local/code.frag.c changed (mode: 100644) (index 4fd08bd..215d044)
... ... static void evt_add_all_fds(void)
117 117 if (r == -1) if (r == -1)
118 118 FATAL("unable to add the signalfd file descriptior to the epoll file descriptor\n"); FATAL("unable to add the signalfd file descriptior to the epoll file descriptor\n");
119 119 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
120 /* the input timer */
121 evt.events = EPOLLIN;
122 evt.data.fd = input_timer_fd_p;
123 r = epoll_ctl(ep_fd_p, EPOLL_CTL_ADD, input_timer_fd_p, &evt);
124 if (r == -1)
125 FATAL("unable to add the input timer file descriptor\n");
120 ///* the input timer */
121 //evt.events = EPOLLIN;
122 //evt.data.fd = input_timer_fd_p;
123 //r = epoll_ctl(ep_fd_p, EPOLL_CTL_ADD, input_timer_fd_p, &evt);
124 //if (r == -1)
125 // FATAL("unable to add the input timer file descriptor\n");
126 126 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
127 127 /* the video timer */ /* the video timer */
128 128 evt.events = EPOLLIN; evt.events = EPOLLIN;
 
... ... static void evt_sigs(void)
182 182 /*NSPC*/ /*NSPC*/
183 183 static void evt_accumulate(struct epoll_event *evt, bool *have_evt_sigs, static void evt_accumulate(struct epoll_event *evt, bool *have_evt_sigs,
184 184 bool *have_evt_pcm, bool *have_evt_video, bool *have_evt_pcm_draining, bool *have_evt_pcm, bool *have_evt_video, bool *have_evt_pcm_draining,
185 bool *have_evt_x11, bool *have_evt_input)
185 bool *have_evt_x11) //bool *have_evt_input)
186 186 { {
187 187 u8 i; u8 i;
188 188
 
... ... static void evt_accumulate(struct epoll_event *evt, bool *have_evt_sigs,
221 221 FATAL("event loop wait:video:unexpected event\n"); FATAL("event loop wait:video:unexpected event\n");
222 222 } }
223 223 /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
224 if (evt->data.fd == input_timer_fd_p) {
225 if ((evt->events & EPOLLIN) != 0) {
226 *have_evt_input = true;
227 return;
228 }
229 FATAL("event loop wait:input:unexpected event\n");
230 }
224 //if (evt->data.fd == input_timer_fd_p) {
225 // if ((evt->events & EPOLLIN) != 0) {
226 // *have_evt_input = true;
227 // return;
228 // }
229 // FATAL("event loop wait:input:unexpected event\n");
230 //}
231 231 /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
232 232 if (evt->data.fd == audio_draining_timer_fd_p) { if (evt->data.fd == audio_draining_timer_fd_p) {
233 233 if ((evt->events & EPOLLIN) != 0) { if ((evt->events & EPOLLIN) != 0) {
 
... ... static void evts_loop(void)
254 254 bool have_evt_video; bool have_evt_video;
255 255 bool have_evt_pcm_draining; bool have_evt_pcm_draining;
256 256 bool have_evt_x11; bool have_evt_x11;
257 bool have_evt_input;
257 //bool have_evt_input;
258 258 int r; int r;
259 259 short pcm_evts; short pcm_evts;
260 260
 
... ... static void evts_loop(void)
274 274 have_evt_video = false; have_evt_video = false;
275 275 have_evt_pcm_draining = false; have_evt_pcm_draining = false;
276 276 have_evt_x11 = false; have_evt_x11 = false;
277 have_evt_input = false;
277 //have_evt_input = false;
278 278
279 279 fd_idx = 0; fd_idx = 0;
280 280 loop { loop {
 
... ... static void evts_loop(void)
282 282 break; break;
283 283 evt_accumulate(&evts[fd_idx], &have_evt_sigs, &have_evt_pcm, evt_accumulate(&evts[fd_idx], &have_evt_sigs, &have_evt_pcm,
284 284 &have_evt_video, &have_evt_pcm_draining, &have_evt_video, &have_evt_pcm_draining,
285 &have_evt_x11, &have_evt_input);
285 &have_evt_x11);
286 //&have_evt_input);
286 287 ++fd_idx; ++fd_idx;
287 288 } }
288 289
 
... ... static void evts_loop(void)
319 320 } }
320 321 if (have_evt_video) if (have_evt_video)
321 322 video_timer_evt(); video_timer_evt();
322 if (have_evt_input)
323 input_timer_evt();
323 //if (have_evt_input)
324 // input_timer_evt();
324 325 /* while audio is draining, video fr may need to be displayed */ /* while audio is draining, video fr may need to be displayed */
325 326 if (have_evt_pcm_draining) if (have_evt_pcm_draining)
326 327 audio_draining_state_evt(); audio_draining_state_evt();
 
... ... static void ff_log_stdout(void *a, int b, const char *fmt, va_list ap)
334 335 /*NSPC*/ /*NSPC*/
335 336 static void usage(void) static void usage(void)
336 337 { {
337 POUT("npv [-p alsa pcm] [-v volume(0..100)] [-h height in pixels] [-w width in pixels] [-help] url\n");
338 POUT("\
339 npv [-p alsa pcm] [-v volume(0..100)] [-h height in pixels] [-w width in pixels]\
340 [-b packet buffer prefill wait(0..100)] [-help] url\n");
338 341 } }
339 342 /*NSPC*/ /*NSPC*/
340 343 static void opts_parse(int argc, u8 **args, u8 **url, u16 *w, u16 *h, static void opts_parse(int argc, u8 **args, u8 **url, u16 *w, u16 *h,
341 u8 **pcm_str, double *vol)
344 u8 **pcm_str, double *vol, u8 *pkts_prefill_percent)
342 345 { {
343 346 int i; int i;
344 347 int url_idx; int url_idx;
 
... ... static void opts_parse(int argc, u8 **args, u8 **url, u16 *w, u16 *h,
362 365 unsigned long vol_ul; unsigned long vol_ul;
363 366
364 367 if ((i + 1) == argc) if ((i + 1) == argc)
365 FATAL("-v:initial volume option is missing\n");
368 FATAL("-v:initial volume is missing\n");
366 369
367 370 vol_ul = strtoul(args[i + 1], 0, 10); vol_ul = strtoul(args[i + 1], 0, 10);
368 371 if (vol_ul < 0 || 100 < vol_ul) if (vol_ul < 0 || 100 < vol_ul)
 
... ... static void opts_parse(int argc, u8 **args, u8 **url, u16 *w, u16 *h,
395 398 *w = (u16)w_ul; *w = (u16)w_ul;
396 399 POUT("-w:using initial window width %lu pixels\n", w_ul); POUT("-w:using initial window width %lu pixels\n", w_ul);
397 400 i += 2; i += 2;
401 } else if (strcmp("-b", args[i]) == 0) {
402 if ((i + 1) == argc)
403 FATAL("-b:percent value for prefill of buffer of packet queues is missing\n");
404
405 *pkts_prefill_percent = (u8)strtoul(args[i + 1], 0, 10);
406 POUT("-v:using a %u prefilled buffer of packet queues\n", *pkts_prefill_percent);
407 i += 2;
398 408 } else if (strcmp("-help", args[i]) == 0) { } else if (strcmp("-help", args[i]) == 0) {
399 409 usage(); usage();
400 410 exit(0); exit(0);
 
... ... static void opts_parse(int argc, u8 **args, u8 **url, u16 *w, u16 *h,
411 421 /*NSPC*/ /*NSPC*/
412 422 #define WIDTH_NOT_DEFINED 0 #define WIDTH_NOT_DEFINED 0
413 423 #define HEIGHT_NOT_DEFINED 0 #define HEIGHT_NOT_DEFINED 0
414 static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str)
424 static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str,
425 u8 pkts_prefill_percent, avcodec_params_t **audio_codec_params,
426 avcodec_params_t **video_codec_params)
415 427 { {
428 avutil_rational_t *audio_st_tb;
429 avutil_rational_t *video_st_tb;
430
416 431 evt_init_once(); evt_init_once();
417 432 sigs_init_once(); sigs_init_once();
418 433 npv_vk_init_once(); /* generic plumbing */ npv_vk_init_once(); /* generic plumbing */
 
... ... static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str)
420 435 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 */
421 436 video_init_once(); /* before video_st_idx_p is actually used */ video_init_once(); /* before video_st_idx_p is actually used */
422 437 clk_init_once(); clk_init_once();
423 input_init_once();
438 pipeline_init_once(pkts_prefill_percent);
424 439
425 440 fmt_init_once(url); fmt_init_once(url);
426 441 /* we need something to start with */ /* we need something to start with */
427 fmt_probe_best_sts(&video_st_idx_p, &audio_st_idx_p);
442 fmt_probe_best_sts(
443 &video_st_p.idx, &video_st_p.id, &video_st_tb,
444 &video_st_p.start_time, video_codec_params,
445 &audio_st_p.idx, &audio_st_p.id, &audio_st_tb,
446 &audio_st_p.start_time, audio_codec_params);
447 memcpy(&audio_st_p.tb, audio_st_tb, sizeof(*audio_st_tb));
448 memcpy(&video_st_p.tb, video_st_tb, sizeof(*video_st_tb));
428 449 if (win_width == WIDTH_NOT_DEFINED) if (win_width == WIDTH_NOT_DEFINED)
429 win_width = fmt_ctx_p->sts[video_st_idx_p]->codecpar->width;
450 win_width = (*video_codec_params)->width;
430 451 if (win_height == HEIGHT_NOT_DEFINED) if (win_height == HEIGHT_NOT_DEFINED)
431 win_height = fmt_ctx_p->sts[video_st_idx_p]->codecpar->height;
452 win_height = (*video_codec_params)->height;
432 453 npv_xcb_init_once(win_width, win_height); npv_xcb_init_once(win_width, win_height);
433 454 npv_vk_surf_init_once(npv_xcb_p.c, npv_xcb_p.win_id); npv_vk_surf_init_once(npv_xcb_p.c, npv_xcb_p.win_id);
434 455 } }
 
... ... static void init_once(u8 *url, u16 win_width, u16 win_height, u8 *pcm_str)
436 457 #undef HEIGHT_NOT_DEFINED #undef HEIGHT_NOT_DEFINED
437 458 /*NSPC*/ /*NSPC*/
438 459 #define PRINT_INFO true #define PRINT_INFO true
439 static void prepare(double initial_vol)
460 static void prepare(double initial_vol, avcodec_params_t *audio_codec_params,
461 avcodec_params_t *video_codec_params)
440 462 { {
441 463 enum avutil_audio_fr_fmt_t dst_fmt; enum avutil_audio_fr_fmt_t dst_fmt;
442 464 int dst_rate; int dst_rate;
443 465 int dst_chans_n; int dst_chans_n;
444 466 uint64_t dst_chans_layout; uint64_t dst_chans_layout;
445 467
446 audio_dec_ctx_cfg(fmt_ctx_p->sts[audio_st_idx_p]->codecpar);
447 video_dec_ctx_cfg(fmt_ctx_p->sts[video_st_idx_p]->codecpar);
468 audio_dec_ctx_cfg(audio_codec_params);
469 video_dec_ctx_cfg(video_codec_params);
448 470 /* /*
449 471 * do our best to match the pcm cfg to audio ff dec output, BUT we don't * do our best to match the pcm cfg to audio ff dec output, BUT we don't
450 472 * expect to match it "exactly": see right below why * expect to match it "exactly": see right below why
 
... ... static void prepare(double initial_vol)
462 484 PRINT_INFO); PRINT_INFO);
463 485 audio_pcm_silence_bufs_cfg(PRINT_INFO); audio_pcm_silence_bufs_cfg(PRINT_INFO);
464 486
465 input_bootstrap_audio_video();
466
467 487 evt_add_all_fds(); evt_add_all_fds();
468 488 } }
469 489 #undef PRINT_INFO #undef PRINT_INFO
 
... ... static void cmd_quit(void)
477 497 EXIT("quit command received\n"); EXIT("quit command received\n");
478 498 } }
479 499 /*NSPC*/ /*NSPC*/
500 static void seek_lock(void)
501 {
502 /* fmt */
503 fmt_ctx_lock();
504 /* video */
505 pkt_q_lock(video_pkt_q_p);
506 video_dec_frs_lock();
507 video_dec_ctx_lock();
508 /* audio */
509 pkt_q_lock(audio_pkt_q_p);
510 audio_dec_sets_lock();
511 audio_dec_ctx_lock();
512 }
513 /*NSPC*/
514 static void seek_unlock(void)
515 {
516 /* audio */
517 audio_dec_ctx_unlock();
518 audio_dec_sets_unlock();
519 pkt_q_unlock(audio_pkt_q_p);
520 /* video */
521 video_dec_ctx_unlock();
522 video_dec_frs_unlock();
523 pkt_q_unlock(video_pkt_q_p);
524 /* fmt */
525 fmt_ctx_unlock();
526 }
527 /*NSPC*/
480 528 #define TS_FROM_CLK_OK 0 #define TS_FROM_CLK_OK 0
481 529 static void seek_x(s64 delta) static void seek_x(s64 delta)
482 530 { {
483 int ri;
484 u8 r8;
485 avformat_st_t *audio_st;
486 avformat_st_t *video_st;
531 int a;
532 u8 r;
487 533 s64 new_audio_ts; s64 new_audio_ts;
488 534 s64 new_video_ts; s64 new_video_ts;
489 535 s64 audio_now; s64 audio_now;
 
... ... static void seek_x(s64 delta)
493 539 WARNING("seek:audio is draining, seeking disable\n"); WARNING("seek:audio is draining, seeking disable\n");
494 540 return; return;
495 541 } }
496 if ((fmt_ctx_p->ctx_flags & AVFMTCTX_UNSEEKABLE) != 0) {
497 WARNING("seek:format is flagged unseekable\n");
498 return;
499 }
500 542
501 543 thdsws_wait_for_idle(video_scaler_p.ctx); thdsws_wait_for_idle(video_scaler_p.ctx);
502 544
503 r8 = clk_get_audio_st_ts(&audio_now);
504 if (r8 != TS_FROM_CLK_OK) {
545 seek_lock();
546
547 r = clk_get_audio_st_ts(&audio_now);
548 if (r != TS_FROM_CLK_OK) {
505 549 WARNING("seek:audio:clock timestamp unavailable, ignoring command\n"); WARNING("seek:audio:clock timestamp unavailable, ignoring command\n");
550 seek_unlock();
506 551 return; return;
507 552 } }
508 r8 = clk_get_video_st_ts(&video_now);
509 if (r8 != TS_FROM_CLK_OK) {
553 r = clk_get_video_st_ts(&video_now);
554 if (r != TS_FROM_CLK_OK) {
510 555 WARNING("seek:video:clock timestamp unavailable, ignoring command\n"); WARNING("seek:video:clock timestamp unavailable, ignoring command\n");
556 seek_unlock();
511 557 return; return;
512 558 } }
559 /*
560 * XXX: a set of sts can share the same id for seeking. if they share
561 * the same id then the tbs should be the same.
562 */
513 563 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
514 audio_st = fmt_ctx_p->sts[audio_st_idx_p];
515 video_st = fmt_ctx_p->sts[video_st_idx_p];
516
517 new_audio_ts = audio_now + delta
518 * audio_st->time_base.den / audio_st->time_base.num;
564 new_audio_ts = audio_now + delta * audio_st_p.tb.den
565 / audio_st_p.tb.num;
519 566 /* rewind capping if possible */ /* rewind capping if possible */
520 if (audio_st->start_time != AV_NOPTS_VALUE)
521 if (new_audio_ts < audio_st->start_time)
522 new_audio_ts = audio_st->start_time;
567 if (audio_st_p.start_time != AV_NOPTS_VALUE)
568 if (new_audio_ts < audio_st_p.start_time)
569 new_audio_ts = audio_st_p.start_time;
523 570 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);
524
525 ri = avformat_seek_pkt(fmt_ctx_p, audio_st->id, new_audio_ts, 0);
526 if (ri < 0) {
571 a = avformat_seek_pkt(fmt_ctx_p, audio_st_p.id, new_audio_ts, 0);
572 if (a < 0) {
527 573 WARNING("unable to seek to %"PRId64" audio stream time base units\n", new_audio_ts); WARNING("unable to seek to %"PRId64" audio stream time base units\n", new_audio_ts);
528 574 goto try_restore_audio; goto try_restore_audio;
529 575 } }
530 576 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);
531 577 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
532 new_video_ts = video_now + delta
533 * video_st->time_base.den / video_st->time_base.num;
578 new_video_ts = video_now + delta * video_st_p.tb.den
579 / video_st_p.tb.num;
534 580 /* rewind capping if possible */ /* rewind capping if possible */
535 if (video_st->start_time != AV_NOPTS_VALUE)
536 if (new_video_ts < video_st->start_time)
537 new_video_ts = video_st->start_time;
538 ri = avformat_seek_pkt(fmt_ctx_p, video_st->id, new_video_ts, 0);
539 if (ri < 0) {
581 if (video_st_p.start_time != AV_NOPTS_VALUE)
582 if (new_video_ts < video_st_p.start_time)
583 new_video_ts = video_st_p.start_time;
584 POUT("trying to seek to %"PRId64" video stream time base units\n", new_video_ts);
585 a = avformat_seek_pkt(fmt_ctx_p, video_st_p.id, new_video_ts, 0);
586 if (a < 0) {
540 587 WARNING("unable to seek to %"PRId64" video stream time base units but audio was seeked)\n", new_video_ts); WARNING("unable to seek to %"PRId64" video stream time base units but audio was seeked)\n", new_video_ts);
541 588 goto try_restore_video; goto try_restore_video;
542 589 } }
 
... ... flush:
547 594 audio_filt_flush(); audio_filt_flush();
548 595 fmt_flush(); fmt_flush();
549 596 clk_invalidate(); clk_invalidate();
550 input_bootstrap_audio_video();
597 //input_bootstrap_audio_video();
598 seek_unlock();
551 599 return; return;
552 600
553 601 try_restore_video: try_restore_video:
554 ri = avformat_seek_pkt(fmt_ctx_p, video_st->id, video_now, 0);
555 if (ri < 0) /* we don't send an application error */
602 a = avformat_seek_pkt(fmt_ctx_p, video_st_p.id, video_now, 0);
603 if (a < 0) /* we don't send an application error */
556 604 EXIT("unable to restore video to %"PRId64" video stream time base units\n", video_now); EXIT("unable to restore video to %"PRId64" video stream time base units\n", video_now);
557 605 try_restore_audio: try_restore_audio:
558 ri = avformat_seek_pkt(fmt_ctx_p, audio_st->id, audio_now, 0);
559 if (ri < 0) /* we don't send an application error */
606 a = avformat_seek_pkt(fmt_ctx_p, audio_st_p.id, audio_now, 0);
607 if (a < 0) /* we don't send an application error */
560 608 EXIT("unable to restore audio to %"PRId64" audio stream time base units\n", audio_now); EXIT("unable to restore audio to %"PRId64" audio stream time base units\n", audio_now);
561 609 goto flush; goto flush;
562 610 } }
 
... ... static void cmd_pause(void)
592 640 return; return;
593 641 } }
594 642 if (paused_p) { if (paused_p) {
643 int r;
644
595 645 POUT("COMMAND:unpause\n"); POUT("COMMAND:unpause\n");
596 646 paused_p = false; paused_p = false;
647 fmt_ctx_lock();
648 avformat_read_play(fmt_ctx_p);
649 fmt_ctx_unlock();
597 650 } else { } else {
651 int r;
652
598 653 POUT("COMMAND:pause\n"); POUT("COMMAND:pause\n");
599 654 paused_p = true; paused_p = true;
655 fmt_ctx_lock();
656 avformat_read_pause(fmt_ctx_p);
657 fmt_ctx_unlock();
600 658 } }
601 659 } }
602 660
 
... ... static void cmd_mute(void)
614 672 { {
615 673 audio_filt_cmd_mute(); audio_filt_cmd_mute();
616 674 } }
675 /*NSPC*/
676 static void prefill_wait(void) { loop
677 {
678 struct timespec wanted;
679 struct timespec rem;
680 s64 prefill_audio;
681 s64 prefill_video;
682
683 pipeline_limits_lock();
684 prefill_audio = pipeline_limits_p.pkts.prefill.audio_bytes_rem;
685 prefill_video = pipeline_limits_p.pkts.prefill.video_bytes_rem;
686 pipeline_limits_unlock();
687 if (prefill_audio <= 0 && prefill_video <= 0)
688 break;
689 memset(&wanted, 0, sizeof(wanted));
690 memset(&rem, 0, sizeof(rem));
691 wanted.tv_nsec = 100000000; /* 100 ms */
692 loop {
693 int r;
694
695 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
696 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
697 if (r == 0)
698 break;
699 if (r != EINTR)
700 FATAL("prefill wait timer failed:%d\n", r);
701 /* r == EINTR */
702 memcpy(&wanted, &rem, sizeof(wanted));
703 memset(&rem, 0, sizeof(rem));
704 }
705 }}
706 /*NSPC*/
707 static void predecoding_wait(void)
708 {
709 struct timespec wanted;
710 struct timespec rem;
711
712 memset(&wanted, 0, sizeof(wanted));
713 memset(&rem, 0, sizeof(rem));
714 /* we target ~double audio buf, namely (0.25s * 2 ~ 500ms) */
715 wanted.tv_nsec = 500000000;
716 loop {
717 int r;
718
719 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
720 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
721 if (r == 0)
722 break;
723 if (r != EINTR)
724 FATAL("predecoding wait timer failed:%d\n", r);
725 /* r == EINTR */
726 memcpy(&wanted, &rem, sizeof(wanted));
727 memset(&rem, 0, sizeof(rem));
728 }
729 }
617 730 #define WIDTH_NOT_DEFINED 0 #define WIDTH_NOT_DEFINED 0
618 731 #define HEIGHT_NOT_DEFINED 0 #define HEIGHT_NOT_DEFINED 0
619 732 int main(int argc, u8 **args) int main(int argc, u8 **args)
 
... ... int main(int argc, u8 **args)
623 736 u8 *pcm_str; u8 *pcm_str;
624 737 u8 *url; u8 *url;
625 738 double initial_vol; double initial_vol;
739 u8 pkts_prefill_percent;
740 avcodec_params_t *audio_codec_params;
741 avcodec_params_t *video_codec_params;
626 742
627 743 /* "turn on utf8" processing in used libs if any *AND* locale system */ /* "turn on utf8" processing in used libs if any *AND* locale system */
628 744 setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
 
... ... int main(int argc, u8 **args)
635 751 pcm_str = "default"; pcm_str = "default";
636 752 url = 0; url = 0;
637 753 initial_vol = 1.; initial_vol = 1.;
638 opts_parse(argc, args, &url, &win_width, &win_height, &pcm_str, &initial_vol);
639
640 init_once(url, win_width, win_height, pcm_str);
641 prepare(initial_vol);
754 pkts_prefill_percent = 0;
755 opts_parse(argc, args, &url, &win_width, &win_height, &pcm_str,
756 &initial_vol, &pkts_prefill_percent);
757 init_once(url, win_width, win_height, pcm_str, pkts_prefill_percent,
758 &audio_codec_params, &video_codec_params);
759 prepare(initial_vol, audio_codec_params, video_codec_params);
642 760
643 761 /* switch the ffmpeg log to stdout for metadata/etc dump */ /* switch the ffmpeg log to stdout for metadata/etc dump */
644 762 avutil_log_set_callback(ff_log_stdout); avutil_log_set_callback(ff_log_stdout);
645 763 avformat_dump_fmt(fmt_ctx_p, 0, url, 0); avformat_dump_fmt(fmt_ctx_p, 0, url, 0);
646 764 avutil_log_set_callback(avutil_log_default_callback); avutil_log_set_callback(avutil_log_default_callback);
647 765
766 pipeline_read_thd_start();
767 POUT("prefilling audio and video buffers...");
768 prefill_wait();
769 POUT("done\n");
770 pipeline_audio_thd_start();
771 pipeline_video_thd_start();
772 POUT("predecoding audio and video...");
773 predecoding_wait();
774 POUT("done\n");
648 775 video_timer_start(); video_timer_start();
649 input_timer_start();
650 776
651 777 loop evts_loop(); loop evts_loop();
652 778 /* unreachable */ /* unreachable */
File npv/main.c changed (mode: 100644) (index 3e50878..033910c)
32 32 #include "npv/global.h" #include "npv/global.h"
33 33 #include "npv/public.h" #include "npv/public.h"
34 34 #include "npv/fmt/public.h" #include "npv/fmt/public.h"
35 #include "npv/input/public.h"
35 #include "npv/pipeline/public.h"
36 36 #include "npv/audio/filt/public.h" #include "npv/audio/filt/public.h"
37 37 #include "npv/audio/public.h" #include "npv/audio/public.h"
38 38 #include "npv/video/public.h" #include "npv/video/public.h"
 
64 64 #include "npv/xcb/main.c" #include "npv/xcb/main.c"
65 65 #include "npv/vk/main.c" #include "npv/vk/main.c"
66 66 #include "npv/clk/main.c" #include "npv/clk/main.c"
67 #include "npv/input/main.c"
67 #include "npv/pipeline/main.c"
68 68 #include "npv/thdsws/main.c" #include "npv/thdsws/main.c"
69 69 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
70 70 #endif #endif
File npv/namespace/ffmpeg.h changed (mode: 100644) (index 01f31e5..6c2e055)
35 35 #define avformat_duration_from_st AVFMT_DURATION_FROM_STREAM #define avformat_duration_from_st AVFMT_DURATION_FROM_STREAM
36 36 #define avformat_find_best_st av_find_best_stream #define avformat_find_best_st av_find_best_stream
37 37 #define avformat_find_st_info avformat_find_stream_info #define avformat_find_st_info avformat_find_stream_info
38 #define avformat_read_pause av_read_pause
39 #define avformat_read_play av_read_play
38 40 #define avformat_seek_pkt av_seek_frame #define avformat_seek_pkt av_seek_frame
39 41 #define avformat_st_t AVStream #define avformat_st_t AVStream
40 42 #define avutil_cpus_n av_cpu_count #define avutil_cpus_n av_cpu_count
 
100 102 #undef avformat_duration_from_st #undef avformat_duration_from_st
101 103 #undef avformat_find_best_st #undef avformat_find_best_st
102 104 #undef avformat_find_st_info #undef avformat_find_st_info
105 #undef avformat_read_pause
106 #undef avformat_read_play
103 107 #undef avformat_seek_pkt #undef avformat_seek_pkt
104 108 #undef avformat_st_t #undef avformat_st_t
105 109 #undef avutil_cpus_n #undef avutil_cpus_n
File npv/pipeline/local/code.frag.c added (mode: 100644) (index 0000000..7c58498)
1 static void wait(long ns)
2 {
3 struct timespec wanted;
4 struct timespec rem;
5
6 memset(&wanted, 0, sizeof(wanted));
7 memset(&rem, 0, sizeof(rem));
8 wanted.tv_nsec = ns;
9 loop {
10 int r;
11
12 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
13 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
14 if (r == 0)
15 break;
16 if (r != EINTR)
17 FATALP("data wait timer failed:%d\n", r);
18 /* r == EINTR */
19 memcpy(&wanted, &rem, sizeof(wanted));
20 memset(&rem, 0, sizeof(rem));
21 }
22 }
23 #define EOF_FMT 2
24 static void read(void) { loop /* infinite loop */
25 {
26 u8 r;
27
28 /*
29 * we do finer-grained locking in there, since we do not want to lock
30 * the pkt qs during slow access
31 */
32 r = fmt_pkts_read_and_q();
33 if (r == EOF_FMT) {
34 pkt_q_lock(audio_pkt_q_p);
35 if (!pkt_q_has_eof(audio_pkt_q_p))
36 pkt_q_enq(audio_pkt_q_p, eof_pkt_l);
37 pkt_q_unlock(audio_pkt_q_p);
38
39 pkt_q_lock(video_pkt_q_p);
40 if (!pkt_q_has_eof(video_pkt_q_p))
41 pkt_q_enq(video_pkt_q_p, eof_pkt_l);
42 pkt_q_unlock(video_pkt_q_p);
43 }
44 /*--------------------------------------------------------------------*/
45 /* should be enough to avoid non kept-alive network connexion */
46 wait(100000000); /* 100ms */
47 }}
48 #undef EOF_FMT
49 static void *read_thd_entry(void *arg)
50 {
51 int r;
52 sigset_t sset;
53
54 r = sigfillset(&sset);
55 if (r == -1)
56 FATALP("read thread:unable to get a full signal mask\n");
57 r = pthread_sigmask(SIG_SETMASK, &sset, 0);
58 if (r != 0)
59 FATALP("read thread:unable to \"block\" \"all\" signals\n");
60 read();
61 /* unreachable */
62 }
63 /*
64 * our alsa audio buf is (rate/4)~0.25s (interactivity like vol processing).
65 * then we would like to have ~2 times this buf (~double buf) of decoded audio
66 * frs. namely we try to have ~(2 *0.25s) of decoded audio frames. we presume
67 * the audio dec is fine grained enough in order to base our calculation on the
68 * pts-es of 2 sets of audio frs.
69 */
70 /*NPSC*/
71 static bool have_enough_predecoded_audio_frs(void)
72 {
73 int64_t pts_min;
74 int64_t pts_max;
75 int64_t pts_delta;
76 int64_t pts_delta_limit;
77
78 audio_dec_sets_lock();
79 if (audio_dec_sets_p.eof_receive) {
80 audio_dec_sets_unlock();
81 return true;
82 } else if (audio_dec_sets_p.n == 0) {
83 audio_dec_sets_unlock();
84 return false;
85 }
86 /* from here we have at least 1 sets of audio frs */
87 /* we presume the audio sets are in pts order */
88 pts_min = audio_dec_sets_p.a[0]->pts;
89 pts_max = audio_dec_sets_p.a[audio_dec_sets_p.n - 1]->pts;
90 audio_dec_sets_unlock();
91
92 pts_delta = pts_max - pts_min;
93 /* 2 * 0.25s = 500 ms */
94 pts_delta_limit = 500 * audio_st_p.tb.den / audio_st_p.tb.num / 1000;
95 if (pts_delta >= pts_delta_limit)
96 return true;
97 return false;
98 }
99 static void audio(void) { loop /* infinite loop */
100 {
101 if (have_enough_predecoded_audio_frs()) {
102 wait(250000000); /* (rate/4)~0.25s */
103 continue;
104 }
105 /* can be long, finer-grained locking is done in there */
106 audio_pkts_send();
107 audio_dec_sets_receive_avail();
108
109 }}
110 static void *audio_thd_entry(void *arg)
111 {
112 int r;
113 sigset_t sset;
114
115 r = sigfillset(&sset);
116 if (r == -1)
117 FATALP("send thread:unable to get a full signal mask\n");
118 r = pthread_sigmask(SIG_SETMASK, &sset, 0);
119 if (r != 0)
120 FATALP("send thread:unable to \"block\" \"all\" signals\n");
121 audio();
122 /* unreachable */
123 }
124 /*
125 * same heuristics than for audio. there is some sort of sync due to video fr
126 * dropping based on "audio now" in the main thd
127 */
128 /*NSPC*/
129 static bool have_enough_predecoded_video_frs(void)
130 {
131 int64_t pts_min;
132 int64_t pts_max;
133 int64_t pts_delta;
134 int64_t pts_delta_limit;
135
136 video_dec_frs_lock();
137 if (video_dec_frs_p.eof_receive) {
138 video_dec_frs_unlock();
139 return true;
140 } else if (video_dec_frs_p.n == 0) {
141 video_dec_frs_unlock();
142 return false;
143 }
144 /* from here we have at least 1 video fr */
145 /* we presume the video frs are in pts order */
146 pts_min = video_dec_frs_p.a[0]->pts;
147 pts_max = video_dec_frs_p.a[video_dec_frs_p.n - 1]->pts;
148 video_dec_frs_unlock();
149
150 pts_delta = pts_max - pts_min;
151 /* 2 * 0.25s = 500 ms */
152 pts_delta_limit = 500 * video_st_p.tb.den / video_st_p.tb.num / 1000;
153 if (pts_delta >= pts_delta_limit)
154 return true;
155 return false;
156 }
157 static void video(void) { loop /* infinite loop */
158 {
159 if (have_enough_predecoded_video_frs()) {
160 wait(250000000); /* (audio rate/4)~0.25s */
161 continue;
162 }
163 /* can be long, finer-grained locking is done in there */
164 video_pkts_send();
165 video_dec_frs_receive_avail();
166 }}
167 static void *video_thd_entry(void *arg)
168 {
169 int r;
170 sigset_t sset;
171
172 r = sigfillset(&sset);
173 if (r == -1)
174 FATALP("send thread:unable to get a full signal mask\n");
175 r = pthread_sigmask(SIG_SETMASK, &sset, 0);
176 if (r != 0)
177 FATALP("send thread:unable to \"block\" \"all\" signals\n");
178 video();
179 /* unreachable */
180 }
File npv/pipeline/local/state.frag.c renamed from npv/input/local/state.frag.c (similarity 100%)
File npv/pipeline/main.c added (mode: 100644) (index 0000000..5679b81)
1 #ifndef NPV_PIPELINE_MAIN_C
2 #define NPV_PIPELINE_MAIN_C
3 /*
4 * code protected with a GNU affero GPLv3 license
5 * copyright (C) 2020 Sylvain BERTRAND
6 */
7 #include <stdbool.h>
8 #include <string.h>
9 #include <time.h>
10 #include <signal.h>
11 #include <stdint.h>
12 #include <pthread.h>
13 #include "npv/c_fixing.h"
14 #include "npv/global.h"
15 #include "npv/pkt_q/public.h"
16 #include "npv/pipeline/public.h"
17 #include "npv/fmt/public.h"
18 #include "npv/audio/public.h"
19 #include "npv/video/public.h"
20 /*----------------------------------------------------------------------------*/
21 #include "npv/namespace/ffmpeg.h"
22 #include "npv/pipeline/namespace/public.h"
23 #include "npv/pipeline/namespace/main.c"
24 /*----------------------------------------------------------------------------*/
25 #define FATALP(fmt, ...) FATAL("pipeline:" fmt, ##__VA_ARGS__)
26 #define WARNINGP(fmt, ...) WARNING("pipeline:" fmt, ##__VA_ARGS__)
27 #define POUTP(fmt, ...) POUT("pipeline:" fmt, ##__VA_ARGS__)
28 /*----------------------------------------------------------------------------*/
29 #include "npv/pipeline/local/state.frag.c"
30 /*----------------------------------------------------------------------------*/
31 #include "npv/pipeline/local/code.frag.c"
32 #include "npv/pipeline/public/code.frag.c"
33 /*----------------------------------------------------------------------------*/
34 #undef FATALP
35 #undef WARNINGP
36 #undef POUTP
37 /*---------------------------------------------------------------------------*/
38 #define CLEANUP
39 #include "npv/namespace/ffmpeg.h"
40 #include "npv/pipeline/namespace/public.h"
41 #include "npv/pipeline/namespace/main.c"
42 #undef CLEANUP
43 #endif
File npv/pipeline/namespace/main.c added (mode: 100644) (index 0000000..60ff3b0)
1 #ifndef CLEANUP
2 /*----------------------------------------------------------------------------*/
3 /* some struct fields */
4 #define sz size
5 /*----------------------------------------------------------------------------*/
6 #define audio pipeline_audio
7 #define audio_thd_entry pipeline_audio_thd_entry
8 #define eof_pkt_l pipeline_eof_pkt_l
9 #define read pipeline_read
10 #define read_thd_entry pipeline_read_thd_entry
11 #define timer_ack pipeline_timer_ack
12 #define timer_init_once pipeline_timer_init_once
13 #define video pipeline_video
14 #define video_thd_entry pipeline_video_thd_entry
15 #define wait pipeline_wait
16 /*============================================================================*/
17 #else
18 #undef eof_pkt_l
19 #undef read
20 #undef read_thd_entry
21 #undef audio
22 #undef audio_thd_entry
23 #undef timer_ack
24 #undef timer_init_once
25 #undef video
26 #undef video_thd_entry
27 #undef wait
28 /*----------------------------------------------------------------------------*/
29 #undef sz
30 /*----------------------------------------------------------------------------*/
31 #endif
32
File npv/pipeline/namespace/public.h added (mode: 100644) (index 0000000..5e6b268)
1 #ifndef CLEANUP
2 #define audio_thd_start pipeline_audio_thd_start
3 #define init_once pipeline_init_once
4 #define limits_lock pipeline_limits_lock
5 #define limits_p pipeline_limits_p
6 #define limits_t pipeline_limits_t
7 #define limits_unlock pipeline_limits_unlock
8 #define read_thd_start pipeline_read_thd_start
9 #define video_thd_start pipeline_video_thd_start
10 /*============================================================================*/
11 #else
12 #undef audio_thd_start
13 #undef init_once
14 #undef limits_lock
15 #undef limits_p
16 #undef limits_t
17 #undef limits_unlock
18 #undef read_thd_start
19 #undef video_thd_start
20 #endif
File npv/pipeline/public.h added (mode: 100644) (index 0000000..9938412)
1 #ifndef NPV_PIPELINE_PUBLIC_H
2 #define NPV_PIPELINE_PUBLIC_H
3 /*
4 * code protected with a GNU affero GPLv3 license
5 * copyright (C) 2020 Sylvain BERTRAND
6 */
7 #include <pthread.h>
8 #include "npv/c_fixing.h"
9 /*----------------------------------------------------------------------------*/
10 #include "npv/pipeline/namespace/public.h"
11 /*----------------------------------------------------------------------------*/
12 struct limits_t {
13 pthread_mutex_t mutex;
14 struct {
15 u64 audio_bytes_n;
16 u64 video_bytes_n;
17 struct {
18 u64 audio_bytes_n; /* arbitrary, init-ed once */
19 u64 video_bytes_n; /* arbitrary, init-ed once */
20 } limit;
21 struct {
22 s64 audio_bytes_rem;
23 s64 video_bytes_rem;
24 } prefill;
25 } pkts;
26 };
27 /*----------------------------------------------------------------------------*/
28 #include "npv/pipeline/public/state.frag.h"
29 /*----------------------------------------------------------------------------*/
30 static void init_once(u8 pkts_prefill_percent);
31 static void limits_lock(void);
32 static void limits_unlock(void);
33 static void read_thd_start(void);
34 static void audio_thd_start(void);
35 static void video_thd_start(void);
36 /*----------------------------------------------------------------------------*/
37 #define CLEANUP
38 #include "npv/pipeline/namespace/public.h"
39 #undef CLEANUP
40 #endif
File npv/pipeline/public/code.frag.c added (mode: 100644) (index 0000000..8857e49)
1 static void init_once(u8 pkts_prefill_percent)
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 limits_p.pkts.audio_bytes_n = 0;
15 limits_p.pkts.video_bytes_n = 0;
16 /* hardcoded for now: arbitrary rough estimates */
17 /* ~8s of 400kb audio */
18 limits_p.pkts.limit.audio_bytes_n = 400000 / 8 * 8;
19 /* ~8s of 10Mb video */
20 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) {
24 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);
28 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);
32 } else {
33 limits_p.pkts.prefill.audio_bytes_rem = 0;
34 limits_p.pkts.prefill.video_bytes_rem = 0;
35 POUTP("prefill for the packet queue buffers is disabled\n");
36 }
37 }
38 static void limits_lock(void)
39 {
40 int r;
41
42 r = pthread_mutex_lock(&limits_p.mutex);
43 if (r != 0)
44 FATALP("unable to lock the limits\n");
45 }
46 static void limits_unlock(void)
47 {
48 int r;
49
50 r = pthread_mutex_unlock(&limits_p.mutex);
51 if (r != 0)
52 FATALP("unable to unlock the limits\n");
53 }
54 static void read_thd_start(void)
55 {
56 int r;
57 pthread_t id;
58 pthread_attr_t attr;
59
60 r = pthread_attr_init(&attr);
61 if (r != 0)
62 FATALP("unable to initialize read thread attribute\n");
63 r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
64 if (r != 0)
65 FATALP("unable to set the read thread attribute to detach mode\n");
66 r = pthread_create(&id, &attr, &read_thd_entry, 0);
67 if (r != 0)
68 FATALP("unable to create the read thread\n");
69 POUTP("read thread %lu\n", (unsigned long)id);
70 pthread_attr_destroy(&attr);
71 }
72 static void audio_thd_start(void)
73 {
74 int r;
75 pthread_t id;
76 pthread_attr_t attr;
77
78 r = pthread_attr_init(&attr);
79 if (r != 0)
80 FATALP("unable to initialize audio thread attribute\n");
81 r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
82 if (r != 0)
83 FATALP("unable to set the audio thread attribute to detach mode\n");
84 r = pthread_create(&id, &attr, &audio_thd_entry, 0);
85 if (r != 0)
86 FATALP("unable to create the audio thread\n");
87 POUTP("audio thread %lu\n", (unsigned long)id);
88 pthread_attr_destroy(&attr);
89 }
90 static void video_thd_start(void)
91 {
92 int r;
93 pthread_t id;
94 pthread_attr_t attr;
95
96 r = pthread_attr_init(&attr);
97 if (r != 0)
98 FATALP("unable to initialize video thread attribute\n");
99 r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
100 if (r != 0)
101 FATALP("unable to set the video thread attribute to detach mode\n");
102 r = pthread_create(&id, &attr, &video_thd_entry, 0);
103 if (r != 0)
104 FATALP("unable to create the video thread\n");
105 POUTP("video thread %lu\n", (unsigned long)id);
106 pthread_attr_destroy(&attr);
107 }
File npv/pipeline/public/state.frag.h added (mode: 100644) (index 0000000..658187e)
1 static struct pipeline_limits_t limits_p;
File npv/pkt_q/local/code.frag.c changed (mode: 100644) (index 8bbfcf4..9d70250)
1 struct pkt_q_t {
2 u32 n_max;
3 u32 n;
4 avcodec_pkt_ref_t **q;
5 u8 *msg_hdr;
6 };
7 1 static void grow(struct pkt_q_t *this) static void grow(struct pkt_q_t *this)
8 2 { {
9 3 u32 p; u32 p;
 
... ... static void grow(struct pkt_q_t *this)
18 12 FATALXPQ("ffmpeg:unable to allocate a new packet reference\n"); FATALXPQ("ffmpeg:unable to allocate a new packet reference\n");
19 13 ++this->n_max; ++this->n_max;
20 14 } }
21 /* actually rotate the pkt ref ptrs */
22 static void deq(struct pkt_q_t *this)
23 {
24 if (this->n > 1) {
25 avcodec_pkt_ref_t *save;
26
27 save = this->q[0];
28 memmove(&this->q[0], &this->q[1], (this->n - 1)
29 * sizeof(this->q[0]));
30 this->q[this->n - 1] = save;
31 }
32 this->n--;
33 }
File npv/pkt_q/main.c changed (mode: 100644) (index 4650d8c..df4253a)
2 2 #define NPV_PKT_Q_MAIN_C #define NPV_PKT_Q_MAIN_C
3 3 #include <stdlib.h> #include <stdlib.h>
4 4 #include <string.h> #include <string.h>
5 #include <pthread.h>
5 6 #include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
6 7 #include "npv/c_fixing.h" #include "npv/c_fixing.h"
7 8 #include "npv/global.h" #include "npv/global.h"
8 9 #include "npv/pkt_q/public.h" #include "npv/pkt_q/public.h"
10 #include "npv/pipeline/public.h"
9 11 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
10 12 #define FATALPQ(fmt, ...) FATAL("packet queue:" fmt, ##__VA_ARGS__) #define FATALPQ(fmt, ...) FATAL("packet queue:" fmt, ##__VA_ARGS__)
11 13 #define FATALXPQ(fmt, ...) FATAL("%s:packet queue:" fmt, this->msg_hdr, ##__VA_ARGS__) #define FATALXPQ(fmt, ...) FATAL("%s:packet queue:" fmt, this->msg_hdr, ##__VA_ARGS__)
File npv/pkt_q/namespace/main.c changed (mode: 100644) (index e62f1e3..4199cba)
1 1 #ifndef CLEANUP #ifndef CLEANUP
2 #define deq pkt_q_deq
3 2 #define grow pkt_q_grow #define grow pkt_q_grow
4 3 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
5 4 /* some struct field names */ /* some struct field names */
6 5 #define sz size #define sz size
6 #define st_idx stream_index
7 7 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
8 8 /*============================================================================*/ /*============================================================================*/
9 9 #else #else
10 #undef deq
11 10 #undef grow #undef grow
12 11 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
13 12 #undef sz #undef sz
13 #undef st_idx
14 14 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
15 15 #endif #endif
File npv/pkt_q/namespace/public.h changed (mode: 100644) (index 8aa31df..f9f0b15)
1 1 #ifndef CLEANUP #ifndef CLEANUP
2 #define deq pkt_q_deq
2 3 #define enq pkt_q_enq #define enq pkt_q_enq
3 4 #define has_eof pkt_q_has_eof #define has_eof pkt_q_has_eof
5 #define lock pkt_q_lock
4 6 #define new pkt_q_new #define new pkt_q_new
5 7 #define pkt_q_t pkt_q_t #define pkt_q_t pkt_q_t
6 #define send pkt_q_send
8 #define unlock pkt_q_unlock
7 9 #define unref_all pkt_q_unref_all #define unref_all pkt_q_unref_all
8 10 /*============================================================================*/ /*============================================================================*/
9 11 #else #else
12 #undef lock
13 #undef deq
10 14 #undef enq #undef enq
11 15 #undef has_eof #undef has_eof
12 16 #undef new #undef new
13 17 #undef pkt_q_t #undef pkt_q_t
14 #undef send
18 #undef unlock
15 19 #undef unref_all #undef unref_all
16 20 #endif #endif
File npv/pkt_q/public.h changed (mode: 100644) (index 76d96d6..0eea2d0)
3 3 #include <stdbool.h> #include <stdbool.h>
4 4 #include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
5 5 #include "npv/c_fixing.h" #include "npv/c_fixing.h"
6 #include "npv/pipeline/public.h"
6 7 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
7 8 #include "npv/namespace/ffmpeg.h" #include "npv/namespace/ffmpeg.h"
8 9 #include "npv/pkt_q/namespace/public.h" #include "npv/pkt_q/namespace/public.h"
9 10 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
10 struct pkt_q_t;
11 struct pkt_q_t {
12 pthread_mutex_t mutex;
13
14 u32 n_max;
15 u32 n;
16 avcodec_pkt_ref_t **q;
17 u8 *msg_hdr;
18 };
19 static void lock(struct pkt_q_t *this);
20 static void unlock(struct pkt_q_t *this);
11 21 static void enq(struct pkt_q_t *this, avcodec_pkt_ref_t *pr); static void enq(struct pkt_q_t *this, avcodec_pkt_ref_t *pr);
22 static void deq(struct pkt_q_t *this);
12 23 static void unref_all(struct pkt_q_t *this); static void unref_all(struct pkt_q_t *this);
13 static u8 send(struct pkt_q_t *this, avcodec_codec_ctx_t *dec_ctx);
14 24 static struct pkt_q_t *new(u8 *msg_hdr); static struct pkt_q_t *new(u8 *msg_hdr);
15 25 static bool has_eof(struct pkt_q_t *this); static bool has_eof(struct pkt_q_t *this);
16 26 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
File npv/pkt_q/public/code.frag.c changed (mode: 100644) (index 01213ad..6a94aa0)
1 static void lock(struct pkt_q_t *this)
2 {
3 int r;
4
5 r = pthread_mutex_lock(&this->mutex);
6 if (r != 0)
7 FATALXPQ("%d:unable to lock packet queue\n", r);
8 }
9 static void unlock(struct pkt_q_t *this)
10 {
11 int r;
12
13 r = pthread_mutex_unlock(&this->mutex);
14 if (r != 0)
15 FATALXPQ("%d:unable to unlock packet queue\n", r);
16 }
17 /* actually rotate the pkt ref ptrs */
18 static void deq(struct pkt_q_t *this)
19 {
20 if (this->n > 1) {
21 avcodec_pkt_ref_t *save;
22
23 save = this->q[0];
24 memmove(&this->q[0], &this->q[1], (this->n - 1)
25 * sizeof(this->q[0]));
26 this->q[this->n - 1] = save;
27 }
28 this->n--;
29 }
1 30 /* steal the pkt reference */ /* steal the pkt reference */
2 31 static void enq(struct pkt_q_t *this, avcodec_pkt_ref_t *pr) static void enq(struct pkt_q_t *this, avcodec_pkt_ref_t *pr)
3 32 { {
 
... ... static void unref_all(struct pkt_q_t *this)
14 43 loop { loop {
15 44 if (pr == this->n) if (pr == this->n)
16 45 break; break;
46 //TODO: account for the limits bytes removal
17 47 avcodec_pkt_unref(this->q[pr]); avcodec_pkt_unref(this->q[pr]);
18 48 ++pr; ++pr;
19 49 } }
20 50 this->n = 0; this->n = 0;
21 51 } }
22 #define AGAIN 0
23 #define EMPTY 1
24 #define EOF_DEC 2
25 static u8 send(struct pkt_q_t *this, avcodec_codec_ctx_t *dec_ctx) { loop
26 {
27 int r;
28 avcodec_pkt_ref_t *pr;
29
30 if (this->n == 0)
31 return EMPTY;
32 pr = this->q[0];
33 r = avcodec_send_pkt(dec_ctx, pr);
34 if (r == AVERROR(EAGAIN)) /* dec is full and the pkt is rejected */
35 return AGAIN;
36 else if (r == 0) {
37 deq(this);
38 avcodec_pkt_unref(pr);
39 continue;
40 } else if (r == AVUTIL_AVERROR_EOF)
41 return EOF_DEC; /* the dec is in draining mode */
42 FATALXPQ("error while sending a packet to the decoder\n");
43 }}
44 #undef AGAIN
45 #undef EMPTY
46 #undef EOF_DEC
47 52 static struct pkt_q_t *new(u8 *msg_hdr) static struct pkt_q_t *new(u8 *msg_hdr)
48 53 { {
54 int r;
49 55 struct pkt_q_t *this; struct pkt_q_t *this;
50 56
51 57 this = malloc(sizeof(*this)); this = malloc(sizeof(*this));
 
... ... static struct pkt_q_t *new(u8 *msg_hdr)
55 61 this->n = 0; this->n = 0;
56 62 this->n_max = 0; this->n_max = 0;
57 63 this->msg_hdr = strdup(msg_hdr); this->msg_hdr = strdup(msg_hdr);
64 r = pthread_mutex_init(&this->mutex, 0);
65 if (r != 0)
66 FATALPQ("unable to init the mutex for the %s packet queue\n", msg_hdr);
58 67 return this; return this;
59 68 } }
60 69 static bool has_eof(struct pkt_q_t *this) static bool has_eof(struct pkt_q_t *this)
File npv/video/local/code.frag.c changed (mode: 100644) (index a827fe4..5b7ef06)
... ... static void init_once_local(void)
13 13 ++i; ++i;
14 14 } }
15 15 } }
16 static void scaler_img_create(u8 fr)
16 static void scaler_img_create(avutil_video_fr_ref_t *fr)
17 17 { {
18 18 struct vk_img_create_info_t info; struct vk_img_create_info_t info;
19 19 s32 r; s32 r;
 
... ... static void scaler_img_create(u8 fr)
23 23 info.flags = vk_img_create_flag_2d_array_compatible_bit; info.flags = vk_img_create_flag_2d_array_compatible_bit;
24 24 info.img_type = vk_img_type_2d; info.img_type = vk_img_type_2d;
25 25 info.texel_mem_blk_fmt = vk_texel_mem_blk_fmt_b8g8r8a8_srgb; info.texel_mem_blk_fmt = vk_texel_mem_blk_fmt_b8g8r8a8_srgb;
26 info.extent.width = (u32)dec_frs_p.a[fr]->width;
27 info.extent.height = (u32)dec_frs_p.a[fr]->height;
26 info.extent.width = (u32)fr->width;
27 info.extent.height = (u32)fr->height;
28 28 info.extent.depth = 1; info.extent.depth = 1;
29 29 info.mip_lvls_n = 1; info.mip_lvls_n = 1;
30 30 info.samples_n = vk_samples_n_1_bit; info.samples_n = vk_samples_n_1_bit;
 
... ... static void dec_a_grow(void)
238 238 /* extract a fr ref, shift the a, push it back at the e, and unref its bufs */ /* extract a fr ref, shift the a, push it back at the e, and unref its bufs */
239 239 static void fr_drop(u16 fr) static void fr_drop(u16 fr)
240 240 { {
241 struct dec_fr_priv_t *fr_priv;
241 242 avutil_video_fr_ref_t *save; avutil_video_fr_ref_t *save;
242 243
244 fr_priv = dec_frs_p.priv_a + fr;
245 if (!fr_priv->was_qed_to_pe)
246 WARNINGV("dropping undisplayed frame\n");
243 247 save = dec_frs_p.a[fr]; save = dec_frs_p.a[fr];
244 248 avutil_video_fr_unref(save); avutil_video_fr_unref(save);
245 249 if (dec_frs_p.n > 1) { if (dec_frs_p.n > 1) {
 
... ... static void fr_drop(u16 fr)
254 258 sizeof(dec_frs_p.priv_a[fr]) * (e - (fr + 1))); sizeof(dec_frs_p.priv_a[fr]) * (e - (fr + 1)));
255 259 memset(&dec_frs_p.priv_a[e - 1], 0, memset(&dec_frs_p.priv_a[e - 1], 0,
256 260 sizeof(dec_frs_p.priv_a[e - 1])); sizeof(dec_frs_p.priv_a[e - 1]));
257 }
261 } else
262 memset(&dec_frs_p.priv_a[0], 0, sizeof(dec_frs_p.priv_a[0]));
258 263 dec_frs_p.n--; dec_frs_p.n--;
259 264 } }
260 265 static void frs_drop(s64 now) static void frs_drop(s64 now)
 
... ... static void frs_drop(s64 now)
262 267 s64 low; s64 low;
263 268 s64 threshold; s64 threshold;
264 269 u16 fr; u16 fr;
265 avformat_st_t *st;
266 270
267 st = fmt_ctx_p->sts[st_idx_p];
268
269 /* audio can be late of 0.25s, and audio is 'now' */
270 threshold = (300 * 1000 * st->tb.num) / st->tb.den;
271 /* audio can be late up to 0.25s, and audio is 'now' */
272 threshold = (250 * st_p.tb.den) / (st_p.tb.num * 1000);
271 273 low = now - threshold; low = now - threshold;
272 274 fr = 0; fr = 0;
273 275 loop { loop {
 
... ... static void frs_drop(s64 now)
280 282 pts = dec_frs_p.a[fr]->pts; pts = dec_frs_p.a[fr]->pts;
281 283 fr_priv = dec_frs_p.priv_a + fr; fr_priv = dec_frs_p.priv_a + fr;
282 284
283 if ((fr != dec_frs_p.fr_being_scaled) && (pts < low))
285 if ((dec_frs_p.a[fr] != dec_frs_p.being_scaled.fr)
286 && (pts < low))
284 287 fr_drop(fr); /* do not advance */ fr_drop(fr); /* do not advance */
285 288 else else
286 289 ++fr; ++fr;
287 290 } }
288 291 } }
289 #define NO_FR U16_MAX
290 static u16 select_fr(s64 now)
292 #define NO_FR 0
293 static void select_fr(s64 now, avutil_video_fr_ref_t **selected_fr,
294 struct dec_fr_priv_t **selected_fr_priv)
291 295 { {
292 u16 fr;
293 u16 selected_fr;
296 u16 fr_idx;
294 297 u64 selected_fr_delta; u64 selected_fr_delta;
295 298
296 fr = 0;
297 selected_fr = NO_FR;
299 fr_idx = 0;
300 *selected_fr = NO_FR;
298 301 selected_fr_delta = S64_MAX; selected_fr_delta = S64_MAX;
299 302 loop { loop {
300 303 u64 delta; u64 delta;
301 304
302 if (fr == dec_frs_p.n)
305 if (fr_idx == dec_frs_p.n)
303 306 break; break;
304 delta = s64_abs(now - (s64)dec_frs_p.a[fr]->pts);
307 delta = s64_abs(now - (s64)dec_frs_p.a[fr_idx]->pts);
305 308 if (delta < selected_fr_delta) { if (delta < selected_fr_delta) {
306 selected_fr = fr;
309 *selected_fr = dec_frs_p.a[fr_idx];
310 *selected_fr_priv = dec_frs_p.priv_a + fr_idx;
307 311 selected_fr_delta = delta; selected_fr_delta = delta;
308 312 } }
309 ++fr;
313 ++fr_idx;
310 314 } }
311 return selected_fr;
312 315 } }
313 316 #undef NO_FR #undef NO_FR
314 317 static void frs_clear_last_qed_to_pe(void) static void frs_clear_last_qed_to_pe(void)
 
... ... static void blit_setup(u8 swpchn_img, bool scaler_dims_changed)
404 407 IF_FATALVVK("%d:swapchain img:%u:command buffer:%p:unable to end recording\n", r, swpchn_img, npv_vk_surf_p.dev.cbs[swpchn_img]); IF_FATALVVK("%d:swapchain img:%u:command buffer:%p:unable to end recording\n", r, swpchn_img, npv_vk_surf_p.dev.cbs[swpchn_img]);
405 408 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
406 409 /* keep track in order to detect change */ /* keep track in order to detect change */
407 blit_l[npv_vk_swpchn_imgs_n_max].viewport.width = npv_xcb_p.width;
408 blit_l[npv_vk_swpchn_imgs_n_max].viewport.height = npv_xcb_p.height;
410 blit_l[swpchn_img].viewport.width = npv_xcb_p.width;
411 blit_l[swpchn_img].viewport.height = npv_xcb_p.height;
409 412 } }
410 413 #define READY 0 #define READY 0
411 414 #define NOT_READY 1 #define NOT_READY 1
 
... ... static void send_to_pe(u32 swpchn_img)
464 467 IF_FATALVVK("%d:queue:%p:unable to submit the image %u to the presentation engine\n", r, npv_vk_surf_p.dev.q, swpchn_img); IF_FATALVVK("%d:queue:%p:unable to submit the image %u to the presentation engine\n", r, npv_vk_surf_p.dev.q, swpchn_img);
465 468 /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
466 469 } }
467 static void start_scaling(u8 fr, bool *scaler_dims_changed)
470 static void start_scaling(avutil_video_fr_ref_t *fr,
471 struct dec_fr_priv_t *fr_priv, bool *scaler_dims_changed)
468 472 { {
469 473 u32 scaled_line_bytes_n; u32 scaled_line_bytes_n;
470 474
471 if (scaler_p.ctx->cfg.width != dec_frs_p.a[fr]->width
472 || scaler_p.ctx->cfg.height != dec_frs_p.a[fr]->height) {
475 if (scaler_p.ctx->cfg.width != fr->width
476 || scaler_p.ctx->cfg.height != fr->height) {
473 477 if (scaler_p.img.vk != 0) if (scaler_p.img.vk != 0)
474 478 scaler_img_destroy(); scaler_img_destroy();
475 479 scaler_img_create(fr); scaler_img_create(fr);
 
... ... static void start_scaling(u8 fr, bool *scaler_dims_changed)
481 485 scaler_img_dev_mem_map(); scaler_img_dev_mem_map();
482 486
483 487 *scaler_dims_changed = true; *scaler_dims_changed = true;
484 scaler_p.ctx->cfg.width = dec_frs_p.a[fr]->width;
485 scaler_p.ctx->cfg.height = dec_frs_p.a[fr]->height;
488 scaler_p.ctx->cfg.width = fr->width;
489 scaler_p.ctx->cfg.height = fr->height;
486 490 } else } else
487 491 *scaler_dims_changed = false; *scaler_dims_changed = false;
488 scaler_p.ctx->cfg.src_fmt = dec_frs_p.a[fr]->fmt;
492 scaler_p.ctx->cfg.src_fmt = fr->fmt;
489 493 scaler_p.ctx->cfg.dst_fmt = AVUTIL_PIX_FMT_RGB32; scaler_p.ctx->cfg.dst_fmt = AVUTIL_PIX_FMT_RGB32;
490 494 scaler_p.ctx->cfg.flags = SWS_POINT; /* | SWS_PRINT_INFO */ scaler_p.ctx->cfg.flags = SWS_POINT; /* | SWS_PRINT_INFO */
491 495
492 496 scaled_line_bytes_n = (u32)scaler_p.img.layout.row_pitch; scaled_line_bytes_n = (u32)scaler_p.img.layout.row_pitch;
493 scaler_p.ctx->scale.src_slices = dec_frs_p.a[fr]->data;
494 scaler_p.ctx->scale.src_strides = dec_frs_p.a[fr]->linesize;
497 scaler_p.ctx->scale.src_slices = fr->data;
498 scaler_p.ctx->scale.src_strides = fr->linesize;
495 499 scaler_p.ctx->scale.dst_slice = scaler_p.img.data; scaler_p.ctx->scale.dst_slice = scaler_p.img.data;
496 500 scaler_p.ctx->scale.dst_stride = scaled_line_bytes_n; scaler_p.ctx->scale.dst_stride = scaled_line_bytes_n;
497 501 thdsws_run(scaler_p.ctx); thdsws_run(scaler_p.ctx);
498 dec_frs_p.fr_being_scaled = fr;
502 dec_frs_p.being_scaled.fr = fr;
503 dec_frs_p.being_scaled.fr_priv = fr_priv;
499 504 } }
500 505 static void timer_ack(void) static void timer_ack(void)
501 506 { {
File npv/video/local/state.frag.c changed (mode: 100644) (index 549bafc..90ad001)
... ... struct dec_fr_priv_t {
2 2 bool is_being_scaled; bool is_being_scaled;
3 3 bool is_scaled; bool is_scaled;
4 4 bool is_last_qed_to_pe; bool is_last_qed_to_pe;
5 bool was_qed_to_pe;
5 6 }; };
6 7 /*===========================================================================*/ /*===========================================================================*/
8 static pthread_mutex_t dec_ctx_mutex_l;
7 9 static avcodec_codec_t *dec_l; static avcodec_codec_t *dec_l;
8 10 static struct vk_mem_rqmts_t tmp_mem_rqmts_l; static struct vk_mem_rqmts_t tmp_mem_rqmts_l;
9 11 static struct { static struct {
File npv/video/main.c changed (mode: 100644) (index 99d9347..0cbd7e2)
46 46 #define WARNINGVVK(fmt, ...) WARNINGVK("video:" fmt, ##__VA_ARGS__) #define WARNINGVVK(fmt, ...) WARNINGVK("video:" fmt, ##__VA_ARGS__)
47 47 #define IF_FATALVVK(fmt, ...) IF_FATALVK("video:" fmt, ##__VA_ARGS__) #define IF_FATALVVK(fmt, ...) IF_FATALVK("video:" fmt, ##__VA_ARGS__)
48 48
49 #define TIMER_INTERVAL_NSECS_N 2000000 /* 2 ms->4 ms ? */
49 /* 4ms + ~5ms "scaling" ~ 100 frs per sec */
50 #define TIMER_INTERVAL_NSECS_N 4000000
50 51 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
51 52 #include "npv/video/local/state.frag.c" #include "npv/video/local/state.frag.c"
52 53 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
File npv/video/namespace/main.c changed (mode: 100644) (index d3f5559..dd8729b)
7 7 #define blit_l video_blit_l #define blit_l video_blit_l
8 8 #define blit_setup video_blit_setup #define blit_setup video_blit_setup
9 9 #define dec_a_grow video_dec_a_grow #define dec_a_grow video_dec_a_grow
10 #define dec_ctx_mutex_l video_dec_ctx_mutex_l
10 11 #define dec_l video_dec_l #define dec_l video_dec_l
11 12 #define fr_drop video_fr_drop #define fr_drop video_fr_drop
12 13 #define frs_drop video_frs_drop #define frs_drop video_frs_drop
 
41 42 #undef blit_l #undef blit_l
42 43 #undef blit_setup #undef blit_setup
43 44 #undef dec_a_grow #undef dec_a_grow
45 #undef dec_ctx_mutex_l
44 46 #undef dec_l #undef dec_l
45 47 #undef fr_drop #undef fr_drop
46 48 #undef frs_clear_last_qed_to_pe #undef frs_clear_last_qed_to_pe
File npv/video/namespace/public.h changed (mode: 100644) (index 515c8ab..59efc9b)
1 1 #ifndef CLEANUP #ifndef CLEANUP
2 2 #define dec_ctx_cfg video_dec_ctx_cfg #define dec_ctx_cfg video_dec_ctx_cfg
3 #define dec_ctx_lock video_dec_ctx_lock
3 4 #define dec_ctx_p video_dec_ctx_p #define dec_ctx_p video_dec_ctx_p
5 #define dec_ctx_unlock video_dec_ctx_unlock
4 6 #define dec_flush video_dec_flush #define dec_flush video_dec_flush
5 7 #define dec_fr_priv_t video_dec_fr_priv #define dec_fr_priv_t video_dec_fr_priv
6 #define dec_fr_try_get video_dec_fr_try_get
7 #define dec_frs_get_avail video_dec_frs_get_avail
8 #define dec_fr_try_receive video_dec_fr_try_receive
9 #define dec_frs_receive_avail video_dec_frs_receive_avail
10 #define dec_frs_lock video_dec_frs_lock
8 11 #define dec_frs_p video_dec_frs_p #define dec_frs_p video_dec_frs_p
12 #define dec_frs_unlock video_dec_frs_unlock
9 13 #define init_once video_init_once #define init_once video_init_once
10 14 #define pkt_q_p video_pkt_q_p #define pkt_q_p video_pkt_q_p
15 #define pkts_send video_pkts_send
11 16 #define scaler_p video_scaler_p #define scaler_p video_scaler_p
12 #define st_idx_p video_st_idx_p
17 #define st_p video_st_p
13 18 #define timer_fd_p video_timer_fd_p #define timer_fd_p video_timer_fd_p
14 19 #define timer_start video_timer_start #define timer_start video_timer_start
15 20 #define timer_evt video_timer_evt #define timer_evt video_timer_evt
16 21 /*============================================================================*/ /*============================================================================*/
17 22 #else #else
18 23 #undef dec_ctx_cfg #undef dec_ctx_cfg
24 #undef dec_ctx_lock
19 25 #undef dec_ctx_p #undef dec_ctx_p
26 #undef dec_ctx_unlock
20 27 #undef dec_flush #undef dec_flush
21 28 #undef dec_fr_priv_t #undef dec_fr_priv_t
22 #undef dec_fr_try_get
23 #undef dec_frs_get_avail
29 #undef dec_fr_try_receive
30 #undef dec_frs_receive_avail
31 #undef dec_frs_lock
24 32 #undef dec_frs_p #undef dec_frs_p
33 #undef dec_frs_unlock
25 34 #undef init_once #undef init_once
26 35 #undef pkt_q_p #undef pkt_q_p
36 #undef pkts_send
27 37 #undef scaler_p #undef scaler_p
28 #undef st_idx_p
38 #undef st_p
29 39 #undef timer_fd_p #undef timer_fd_p
30 40 #undef timer_start #undef timer_start
31 41 #undef timer_evt #undef timer_evt
File npv/video/public.h changed (mode: 100644) (index e5e3b99..820867c)
20 20 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
21 21 static void dec_ctx_cfg(avcodec_params_t *params); static void dec_ctx_cfg(avcodec_params_t *params);
22 22 static void dec_flush(void); static void dec_flush(void);
23 static u8 dec_fr_try_get(void);
24 static void dec_frs_get_avail(void);
23 static u8 dec_fr_try_receive(void);
24 static void dec_frs_receive_avail(void);
25 25 static void init_once(void); static void init_once(void);
26 26 static void timer_evt(void); static void timer_evt(void);
27 27 static void timer_start(void); static void timer_start(void);
28 static void dec_ctx_lock(void);
29 static void dec_ctx_unlock(void);
30 static void dec_frs_lock(void);
31 static void dec_frs_unlock(void);
32 static void pkts_send(void);
28 33 /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
29 34 #define CLEANUP #define CLEANUP
30 35 #include "npv/namespace/ffmpeg.h" #include "npv/namespace/ffmpeg.h"
File npv/video/public/code.frag.c changed (mode: 100644) (index eae91e9..8cd0380)
1 #define NO_FR U16_MAX
1 #define NO_FR 0
2 2 static void init_once_public(void) static void init_once_public(void)
3 3 { {
4 int r;
5
4 6 /* linux bug: still no CLOCK_MONOTONIC_RAW for timerfd */ /* linux bug: still no CLOCK_MONOTONIC_RAW for timerfd */
5 7 errno = 0; errno = 0;
6 8 timer_fd_p = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); timer_fd_p = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
7 9 if (timer_fd_p == -1) if (timer_fd_p == -1)
8 10 FATALV("unable to get a timer file descriptor:%s\n", strerror(errno)); FATALV("unable to get a timer file descriptor:%s\n", strerror(errno));
9
10 st_idx_p = -1;
11 memset(&st_p, 0, sizeof(st_p));
11 12 pkt_q_p = pkt_q_new("video"); pkt_q_p = pkt_q_new("video");
12 13 dec_ctx_p = 0; dec_ctx_p = 0;
14 r = pthread_mutex_init(&dec_ctx_mutex_l, 0);
15 if (r != 0)
16 FATALV("unable to create the mutex for the decoder context\n");
13 17
14 18 dec_frs_p.eof_receive = false; dec_frs_p.eof_receive = false;
15 19 dec_frs_p.n_max = 0; dec_frs_p.n_max = 0;
16 20 dec_frs_p.n = 0; dec_frs_p.n = 0;
17 21 dec_frs_p.a = 0; dec_frs_p.a = 0;
18 22 dec_frs_p.priv_a = 0; dec_frs_p.priv_a = 0;
19 dec_frs_p.fr_being_scaled = NO_FR;
23 dec_frs_p.being_scaled.fr = NO_FR;
24 dec_frs_p.being_scaled.fr_priv = 0;
25 r = pthread_mutex_init(&dec_frs_p.mutex, 0);
26 if (r != 0)
27 FATALV("unable to create the mutex for the array of frames\n");
20 28
21 29 scaler_p.img.vk = 0; scaler_p.img.vk = 0;
22 30 memset(&scaler_p.img.layout, 0, sizeof(scaler_p.img.layout)); memset(&scaler_p.img.layout, 0, sizeof(scaler_p.img.layout));
 
... ... static void timer_start(void)
71 79 #define AGAIN 0 #define AGAIN 0
72 80 #define HAVE_FR 1 #define HAVE_FR 1
73 81 #define EOF_DEC 2 #define EOF_DEC 2
74 static u8 dec_fr_try_get(void)
82 static u8 dec_fr_try_receive(void)
75 83 { {
76 84 int r; int r;
77 85 u16 fr; u16 fr;
78 86
79 87 if (dec_frs_p.eof_receive) if (dec_frs_p.eof_receive)
80 88 return EOF_DEC; return EOF_DEC;
81
82 89 if (dec_frs_p.n == dec_frs_p.n_max) if (dec_frs_p.n == dec_frs_p.n_max)
83 90 dec_a_grow(); dec_a_grow();
84
85 91 fr = dec_frs_p.n; fr = dec_frs_p.n;
86 92 r = avcodec_receive_video_fr(dec_ctx_p, dec_frs_p.a[fr]); r = avcodec_receive_video_fr(dec_ctx_p, dec_frs_p.a[fr]);
87 93 if (r == AVUTIL_AVERROR(EAGAIN)) if (r == AVUTIL_AVERROR(EAGAIN))
 
... ... static u8 dec_fr_try_get(void)
103 109 #define AGAIN 0 #define AGAIN 0
104 110 #define HAVE_FR 1 #define HAVE_FR 1
105 111 #define EOF_DEC 2 #define EOF_DEC 2
106 static void dec_frs_get_avail(void) { loop
112 static void dec_frs_receive_avail(void) { loop
107 113 { {
108 114 u8 r; u8 r;
109 115
110 r = dec_fr_try_get();
116 dec_frs_lock();
117 dec_ctx_lock();
118 r = dec_fr_try_receive();
119 dec_ctx_unlock();
120 dec_frs_unlock();
111 121 if (r == HAVE_FR) if (r == HAVE_FR)
112 122 continue; continue;
113 123 else if (r == AGAIN || r == EOF_DEC) else if (r == AGAIN || r == EOF_DEC)
 
... ... static void dec_frs_get_avail(void) { loop
116 126 #undef AGAIN #undef AGAIN
117 127 #undef HAVE_FR #undef HAVE_FR
118 128 #undef EOF_DEC #undef EOF_DEC
119 #define NO_FR U16_MAX
129 #define NO_FR 0
120 130 static void dec_flush(void) static void dec_flush(void)
121 131 { {
122 132 pkt_q_unref_all(pkt_q_p); pkt_q_unref_all(pkt_q_p);
123 133 frs_reset(); frs_reset();
124 134 dec_frs_p.eof_receive = false; dec_frs_p.eof_receive = false;
125 dec_frs_p.fr_being_scaled = NO_FR;
135 dec_frs_p.being_scaled.fr = NO_FR;
136 dec_frs_p.being_scaled.fr_priv = 0;
126 137 avcodec_flush_bufs(dec_ctx_p); avcodec_flush_bufs(dec_ctx_p);
127 138 } }
128 139 #undef NO_FR #undef NO_FR
140 static void dec_ctx_lock(void)
141 {
142 int r;
143
144 r = pthread_mutex_lock(&dec_ctx_mutex_l);
145 if (r != 0)
146 FATALV("%d:unable to lock the video decoder context\n", r);
147 }
148 static void dec_ctx_unlock(void)
149 {
150 int r;
151
152 r = pthread_mutex_unlock(&dec_ctx_mutex_l);
153 if (r != 0)
154 FATALV("%d:unable to unlock the video decoder context\n", r);
155 }
156 static void dec_frs_lock(void)
157 {
158 int r;
159
160 r = pthread_mutex_lock(&dec_frs_p.mutex);
161 if (r != 0)
162 FATALV("%d:unable to lock the array of decoder frames\n", r);
163 }
164 static void dec_frs_unlock(void)
165 {
166 int r;
167
168 r = pthread_mutex_unlock(&dec_frs_p.mutex);
169 if (r != 0)
170 FATALV("%d:unable to unlock the array of decoder frames\n", r);
171 }
129 172 /* go non-blocking or a worker thread is needed */ /* go non-blocking or a worker thread is needed */
130 #define NO_FR U16_MAX
173 #define NO_FR 0
131 174 #define TS_FROM_CLK_OK 0 #define TS_FROM_CLK_OK 0
132 175 #define READY 0 #define READY 0
133 176 #define NOT_READY 1 #define NOT_READY 1
177 /* XXX: we do want to lock the frs q the least amount of time as possible */
134 178 static void timer_evt(void) static void timer_evt(void)
135 179 { {
136 180 u8 r; u8 r;
137 181 s64 now; s64 now;
138 u16 fr;
182 avutil_video_fr_ref_t *fr;
139 183 struct dec_fr_priv_t *fr_priv; struct dec_fr_priv_t *fr_priv;
140 184 bool scaler_is_busy; bool scaler_is_busy;
141 185 bool scaler_dims_changed; bool scaler_dims_changed;
 
... ... static void timer_evt(void)
144 188 timer_ack(); timer_ack();
145 189 if (npv_paused_p) if (npv_paused_p)
146 190 return; return;
147 dec_frs_get_avail();
148 if (dec_frs_p.n == 0)
149 return;
150 191 r = clk_get_video_st_ts(&now); r = clk_get_video_st_ts(&now);
151 192 if (r != TS_FROM_CLK_OK) if (r != TS_FROM_CLK_OK)
152 193 return; return;
194 /* lock --------------------------------------------------------------*/
195 dec_frs_lock();
196 if (dec_frs_p.n == 0) {
197 dec_frs_unlock();
198 return;
199 }
153 200 frs_drop(now); frs_drop(now);
154 fr = select_fr(now);
201 select_fr(now, &fr, &fr_priv);
202 dec_frs_unlock();
203 /* unlock ------------------------------------------------------------*/
155 204 if (fr == NO_FR) if (fr == NO_FR)
156 205 return; return;
157 fr_priv = dec_frs_p.priv_a + fr;
158 206 if (fr_priv->is_last_qed_to_pe) if (fr_priv->is_last_qed_to_pe)
159 207 return; return;
160 208 scaler_is_busy = thdsws_is_busy(scaler_p.ctx); scaler_is_busy = thdsws_is_busy(scaler_p.ctx);
161 209 if (!scaler_is_busy) { if (!scaler_is_busy) {
162 if (dec_frs_p.fr_being_scaled != NO_FR) {
163 dec_frs_p.priv_a[dec_frs_p.fr_being_scaled].is_scaled
164 = true;
165 dec_frs_p.fr_being_scaled = NO_FR;
210 if (dec_frs_p.being_scaled.fr != NO_FR) {
211 dec_frs_p.being_scaled.fr_priv->is_scaled = true;
212 dec_frs_p.being_scaled.fr = NO_FR;
166 213 } }
167 214 } }
168 215 if (!fr_priv->is_scaled) { if (!fr_priv->is_scaled) {
169 216 if (scaler_is_busy) if (scaler_is_busy)
170 217 return; return;
171 start_scaling(fr, &scaler_dims_changed);
218 start_scaling(fr, fr_priv, &scaler_dims_changed);
172 219 return; return;
173 220 } }
174 221 r = swpchn_next_img(&swpchn_img); r = swpchn_next_img(&swpchn_img);
 
... ... static void timer_evt(void)
176 223 return; return;
177 224 blit_setup(swpchn_img, scaler_dims_changed); blit_setup(swpchn_img, scaler_dims_changed);
178 225 send_to_pe(swpchn_img); send_to_pe(swpchn_img);
226 /* lock --------------------------------------------------------------*/
227 dec_frs_lock();
179 228 frs_clear_last_qed_to_pe(); frs_clear_last_qed_to_pe();
229 dec_frs_unlock();
230 /* unlock ------------------------------------------------------------*/
180 231 fr_priv->is_last_qed_to_pe = true; fr_priv->is_last_qed_to_pe = true;
232 fr_priv->was_qed_to_pe = true; /* drop detection */
181 233 } }
182 234 #undef NO_FR #undef NO_FR
183 235 #undef TS_FROM_CLK_OK #undef TS_FROM_CLK_OK
184 236 #undef READY #undef READY
185 237 #undef NOT_READY #undef NOT_READY
238 /* we do per-loop fine-grained locking */
239 #define sz size
240 static void pkts_send(void) { loop
241 {
242 int r;
243 avcodec_pkt_ref_t *pr;
244
245 pkt_q_lock(pkt_q_p);
246 if (pkt_q_p->n == 0)
247 goto unlock_and_return;
248 pr = pkt_q_p->q[0];
249 dec_ctx_lock();
250 r = avcodec_send_pkt(dec_ctx_p, pr);
251 dec_ctx_unlock();
252 if (r == AVERROR(EAGAIN)) /* dec is full and the pkt is rejected */
253 goto unlock_and_return;
254 else if (r == AVUTIL_AVERROR_EOF) /* the dec is in draining mode */
255 goto unlock_and_return;
256 else if (r != 0)
257 FATALV("error while sending a packet to the decoder\n");
258 /* r == 0 */
259 pipeline_limits_lock();
260 pipeline_limits_p.pkts.video_bytes_n -= pr->sz;
261 pipeline_limits_unlock();
262
263 pkt_q_deq(pkt_q_p);
264 avcodec_pkt_unref(pr);
265 pkt_q_unlock(pkt_q_p);
266 continue;
267
268 unlock_and_return:
269 pkt_q_unlock(pkt_q_p);
270 return;
271 }}
272 #undef sz
File npv/video/public/state.frag.h changed (mode: 100644) (index 3b548ce..8fde273)
1 static avcodec_codec_ctx_t* dec_ctx_p;
1 static avcodec_codec_ctx_t *dec_ctx_p;
2 2 static struct pkt_q_t *pkt_q_p; static struct pkt_q_t *pkt_q_p;
3 static int st_idx_p;
3 /*
4 * we copy some stream data in the case the stream does vanish or is replaced
5 * (don't know how ffmpeg does handle this)
6 */
7 static struct {
8 int idx;
9 int id;
10 avutil_rational_t tb;
11 int64_t start_time;
12 } st_p;
4 13 static int timer_fd_p; static int timer_fd_p;
5 /*---------------------------------------------------------------------------*/
14 /*----------------------------------------------------------------------------*/
6 15 struct dec_fr_priv_t; struct dec_fr_priv_t;
7 16 static struct { static struct {
17 pthread_mutex_t mutex;
18
8 19 bool eof_receive; /* "receiving" from the dec returned eof */ bool eof_receive; /* "receiving" from the dec returned eof */
9 20
10 21 u16 n_max; u16 n_max;
 
... ... static struct {
12 23 /* we did not factor the 2 following fields on purpose */ /* we did not factor the 2 following fields on purpose */
13 24 avutil_video_fr_ref_t **a; avutil_video_fr_ref_t **a;
14 25 struct dec_fr_priv_t *priv_a; struct dec_fr_priv_t *priv_a;
15 u16 fr_being_scaled;
26 struct {
27 avutil_video_fr_ref_t *fr;
28 struct dec_fr_priv_t *fr_priv;
29 } being_scaled;
16 30 } dec_frs_p; } dec_frs_p;
17 /*---------------------------------------------------------------------------*/
31 /*----------------------------------------------------------------------------*/
18 32 static struct { static struct {
19 33 struct { struct {
20 34 struct vk_img_t *vk; struct vk_img_t *vk;
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