Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (17)
  • Alexandre Janniaux's avatar
    test: add vlc_input_decoder test · a6c3e3c6
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    The test provides an infrastructure based on previous transcode tests
    and video output tests, that will serve as basis for other
    input_decoder.c tests.
    a6c3e3c6
  • Alexandre Janniaux's avatar
    input: decoder: use vlc_input_decoder_Flush for CC · 3dd0f548
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    Separate the early return to make it clear that what follows require a
    valid closed-caption decoder.
    
    Then, use vlc_input_decoder_Flush directly, because pf_flush must be
    called from the CC decoder thread, and the fifo must be flushed
    beforehand, instead of calling it directly.
    3dd0f548
  • Alexandre Janniaux's avatar
    input: decoder: add cc.lock for sub-decoders · ac7f9ce2
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    
    Sub-decoders are decoders whose state is defined by previous decoders.
    Specifically in the current case, picture frames with specific SEI data
    can convey subtitles as closed captions and report them from the decoder
    implementation itself.
    
    Since the core never locks the implementation, and the implementation
    can be asynchronously reporting subtitles, a common lock need to be
    setup so that the core can then check and use the sub-decoders being
    created without racing against the upper decoder implementation.
    
    Co-authored-by: default avatarFrançois Cartegnie <fcvlcdev@free.fr>
    ac7f9ce2
  • Alexandre Janniaux's avatar
    input: decoder: fix locking CC · 8f7b3838
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    vlc_input_decoder_HasCCChanFlag also needs to be protected, and the
    owner->lock mutex will be removed in later patches, to be completely
    replaced by the already existing fifo lock.
    
    The new cc.lock allows better thread safety without risking a deadlock
    between the super-decoder and the sub-decoder, by protecting the very
    state being synced by both of them.
    8f7b3838
  • Alexandre Janniaux's avatar
    test: input_decoder: add CC tests · 2e41d0c6
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    The test is reliably failing with thread sanitizer enabled, without the
    previous patches:
    
        ==================
        WARNING: ThreadSanitizer: data race (pid=242170)
          Write of size 8 at 0x7b6c00010088 by thread T10:
            #0 DecoderPlayCc ../../src/input/decoder.c:1008 (libvlccore.so.9+0xebbf5)
            #1 ModuleThread_QueueCc ../../src/input/decoder.c:1064 (libvlccore.so.9+0xec031)
            #2 decoder_QueueCc ../../include/vlc_codec.h:444 (test_src_input_decoder+0x5768)
            #3 decoder_decode_check_cc ../../test/src/input/decoder/input_decoder_scenarios.c:79 (test_src_input_decoder+0x5a4e)
            #4 DecoderDecode ../../test/src/input/decoder/input_decoder.c:90 (test_src_input_decoder+0x3dd4)
            #5 DecoderThread_DecodeBlock ../../src/input/decoder.c:1376 (libvlccore.so.9+0xed9f1)
            #6 DecoderThread_ProcessInput ../../src/input/decoder.c:1498 (libvlccore.so.9+0xee14a)
            #7 DecoderThread ../../src/input/decoder.c:1786 (libvlccore.so.9+0xef877)
    
          Previous read of size 1 at 0x7b6c00010088 by thread T8:
            #0 vlc_input_decoder_HasCCChanFlag ../../src/input/decoder.c:2445 (libvlccore.so.9+0xf2a2b)
            #1 vlc_input_decoder_SetCcState ../../src/input/decoder.c:2464 (libvlccore.so.9+0xf2b5f)
            #2 EsOutSelectEs ../../src/input/es_out.c:2446 (libvlccore.so.9+0x1095c4)
            #3 EsOutSelect ../../src/input/es_out.c:2686 (libvlccore.so.9+0x10a7fc)
            #4 EsOutVaControlLocked ../../src/input/es_out.c:3270 (libvlccore.so.9+0x10dea5)
            #5 EsOutControlLocked ../../src/input/es_out.c:3147 (libvlccore.so.9+0x10d0ae)
            #6 EsOutVaPrivControlLocked ../../src/input/es_out.c:3759 (libvlccore.so.9+0x112282)
            #7 EsOutPrivControl ../../src/input/es_out.c:4028 (libvlccore.so.9+0x11505c)
            #8 es_out_vaPrivControl ../../src/input/es_out.h:105 (libvlccore.so.9+0x125a49)
            #9 es_out_PrivControl ../../src/input/es_out.h:112 (libvlccore.so.9+0x125b38)
            #10 es_out_SetEs ../../src/input/es_out.h:124 (libvlccore.so.9+0x125c4b)
            #11 Control ../../src/input/input.c:2123 (libvlccore.so.9+0x130e15)
            #12 MainLoop ../../src/input/input.c:724 (libvlccore.so.9+0x129676)
            #13 Run ../../src/input/input.c:428 (libvlccore.so.9+0x127faa)
    2e41d0c6
  • Alexandre Janniaux's avatar
    vlc_frame: add vlc_fifo_Held/Assert · 322ea200
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    vlc_fifo_t are coming with their own lock which is exposed on the public
    interface, so provide sanitization state check functions like those
    available for vlc_mutex_t.
    322ea200
  • Alexandre Janniaux's avatar
    input: decoder: extract substream handling · 2a4d648e
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    The substream handling was under a lot of precondition, leading to a lot
    of indentation. Moving this handling into a separate function allows
    early return within the function, which reduce to a single indentation
    level and greatly simplify the reading of the function while simplifying
    the caller site where it was only a specific case to handle.
    2a4d648e
  • Alexandre Janniaux's avatar
    input: decoder: extract locking · e5b48bc7
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    The default case is supposed to be unreachable.
    e5b48bc7
  • Alexandre Janniaux's avatar
    input: decoder: remove incorrectly ordered locking · 7dcc370d
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    
    The input decoder component is made of three different states:
    
     - Lock A:
       The input_decoder itself, loading the decoder and protected against
       concurrent usage of the decoder through p_owner->lock.
    
     - Lock B:
       The decoder implementation, that might create internal lock or
       synchronization object to process decoding asynchronously.
    
     - Lock C:
       The decoder implementation output, or the "owner" part viewed by the
       decoder implementation, which needs to be protected against access
       from the decoder and access from the input_decoder and is protected
       through the fifo lock, also protecting the fifo in which input data
       is pushed.
    
    Because the decoder implementation is protected by the p_owner->lock (or
    here, lock A), we can never lock A from the decoder implementation,
    which is what the previous code was doing.
    
    Likewise, since the decoder implementation will use the output to queue
    picture and signal state changes, it must take Lock C and thus the
    output part can never take either A or B.
    
    Instead, we enforce the order:
    
                      Lock A -> Lock B -> Lock C:
    
    Which means that:
    
     - The decoder implementation can lock the input decoder output (C) to
       push new changes.
    
     - The input_decoder can lock its output (C) directly to affect what
       state the decoder implementation will see when queueing changes.
    
     - The input_decoder will only lock A to protect the decoder_t object
       from being used concurrently.
    
    This fixes deadlock in specific conditions where an asynchronous decoder
    implementation would queue a picture with Lock B taken, trying to lock A
    while the input_decoder client would have locked A already and would try
    to flush the decoder implementation, taking lock B at the same time.
    
    In practice, lock A is not really "useful" given that most of the
    decoder_t methods are called from the decoder thread (owned by the input
    decoder implementation), lock B is hidden in this part of the code, and
    most of the "input decoder" is protected by the fifo lock, which then
    must not be taken when calling decoder_t function to avoid reentrance of
    the lock.
    
    Co-authored-by: default avatarThomas Guillem <thomas@gllm.f>
    7dcc370d
  • Alexandre Janniaux's avatar
    input: decoder: ensure decoder can be flushed · 34a548cc
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    
    Flush was mostly entirely executed from the decoder thread, which meant
    that it was blocked by previous call from decoder_t::pf_decode. Since
    the decoder_t::pf_decode could be blocked waiting for a picture from the
    vout to be able to resume decoding, and that flushing the video output
    was done in this thread, it could deadlock.
    
    A previous mechanism, picture_pool_Cancel, was introduced to allow the
    external code to cancel the picture pool from the core and ensure
    pf_decode would stop as soon as possible, but it was leading to more
    spurrious unhandleable errors and could not work with decoder owning
    their own pool.
    
    Instead, ensure we set the flushing state directly from the flush call,
    and flush the outputs. Setting the state will prevent decoder from
    queueing new pictures by discarding them directly, which means that we
    don't need to flush after flush has happened, and the flushing state
    will be reset before new frames are queued into the decoder.
    
    Fixes #26915
    
    Co-authored-by: default avatarThomas Guillem <thomas@gllm.f>
    34a548cc
  • Alexandre Janniaux's avatar
    input: decoder: move reset of i_preroll_end · 18e83e64
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    The i_preroll_end state is reset at the end of the flush call on the
    es_out side, but it's only set from the decoder thread which would be
    flushing the decoders anyway, so it can be set from there (ie. the last
    point of flush) where it's already locked.
    18e83e64
  • Alexandre Janniaux's avatar
    test: input_decoder: check that flush works · 91aabbf0
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    This test provides a non-regression test for the issue #26915, in which
    a decoder with internal pool gets stuck when flush is not done correctly
    and which has been fixed right before.
    91aabbf0
  • Alexandre Janniaux's avatar
    input: decoder: add stream output flush test · 29303ae4
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    The test check that the stream output is correctly flushed when the
    input decoder is flushed, ensuring that previous commit didn't break
    the triggering of the flush.
    29303ae4
  • Alexandre Janniaux's avatar
    input: decoder: add documentation for the file · f68a7291
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    f68a7291
  • Alexandre Janniaux's avatar
    picture_pool: remove picture_pool_Cancel · 889548be
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    There is no usage for picture_pool_Cancel anymore. The pool cancellation
    was a mechanism for asynchronous signalling within decoders that the
    decoder was being flushed and that waiting on picture could be
    cancelled. Since it was a concern for decoders, it was moved to the
    decoder handling code by ensuring the decoder has enough picture to
    finish decoding and reach the pf_flush function.
    889548be
  • Alexandre Janniaux's avatar
    picture_pool: simplify picture_pool_Get · 48bdd6cd
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    The while loop will return at the first loop, or not even reach the
    inner of the loop if no picture is available, so transform the loop
    into an early return and de-indent the picture pool cloning case.
    48bdd6cd
  • Alexandre Janniaux's avatar
    input: decoder: use vout from cfg · b510622c
    Alexandre Janniaux authored and Steve Lhomme's avatar Steve Lhomme committed
    p_owner->p_vout is supposed to be used under lock, but we already got an
    holding reference of the vout from cfg.vout, so use it instead.
    b510622c
......@@ -743,6 +743,28 @@ VLC_API size_t vlc_fifo_GetCount(const vlc_fifo_t *) VLC_USED;
*/
VLC_API size_t vlc_fifo_GetBytes(const vlc_fifo_t *) VLC_USED;
/**
* Checks whether the vlc_fifo_t object is being locked.
*
* This function checks if the calling thread holds a given vlc_fifo_t
* object. It has no side effects and is essentially intended for run-time
* debugging.
*
* @note This function is the vlc_fifo_t equivalent of vlc_mutex_held.
*
* @note To assert that the calling thread holds a lock, the helper macro
* vlc_fifo_Assert() should be used instead of this function.
*
* @retval false the fifo is not locked by the calling thread
* @retval true the fifo is locked by the calling thread
*/
VLC_API bool vlc_fifo_Held(const vlc_fifo_t *fifo) VLC_USED;
/**
* Asserts that a vlc_fifo_t is locked by the calling thread.
*/
#define vlc_fifo_Assert(fifo) assert(vlc_fifo_Held(fifo))
VLC_USED static inline bool vlc_fifo_IsEmpty(const vlc_fifo_t *fifo)
{
return vlc_queue_IsEmpty(vlc_fifo_queue(fifo));
......
......@@ -104,14 +104,6 @@ VLC_API picture_t * picture_pool_Get( picture_pool_t * ) VLC_USED;
*/
VLC_API picture_t *picture_pool_Wait(picture_pool_t *) VLC_USED;
/**
* Cancel the picture pool.
*
* It won't return any pictures via picture_pool_Get or picture_pool_Wait if
* canceled is true. This function will also unblock picture_pool_Wait.
*/
void picture_pool_Cancel( picture_pool_t *, bool canceled );
/**
* Reserves pictures from a pool and creates a new pool with those.
*
......
......@@ -55,6 +55,53 @@
#include "../video_output/vout_internal.h"
/**
* \file src/input/decoder.c
*
* The input decoder connects the input client pushing data to the
* decoder implementation (through the matching elementary stream)
* and the following output for audio, video and subtitles.
*
* It follows the locking rules below:
*
* - The fifo cannot be locked when calling function from the
* decoder module implementation.
*
* - However, the decoder module implementation might indirectly
* lock the fifo when calling the owner methods, in particular
* to send a frame or update the output status.
*
* - The input code can lock the fifo to modify the global state
* of the input decoder.
*
* Backpressure preventing starvation is done by the pacing of the
* decoder, the calls into the decoder implementation, and the
* limits of the fifo queue.
*
* Basically a very fast decoder will often wait since the fifo will be
* consumed really quickly and thus almost never stay under the lock.
* Likewise, when the decoder is slower and the fifo can grow, it also
* means that the decoder thread will wait more often on the
* `decoder_t::pf_decode` call, which is done without the fifo lock as
* per above rules.
*
* In addition with the standard input/output cycle from the decoder,
* the video decoders can create sub-decoders for the closed captions
* support embedded in the supplementary information from the codecs.
*
* To do so, they need to create a `decoder_cc_desc_t` matching with the
* format that needs to be described (number of channels, type of
* channels) and they then create them along with the closed-captions
* content with `decoder_QueueCc`.
*
* In the `input/decoder.c` code, the access to the sub-decoders in the
* cc.pp_decoders table is protected through the `cc.lock` mutex.
* Taking this lock ensures that the sub-decoder won't get
* asynchronously removed while using it, and any mutex from the
* sub-decoder can then be taken under this lock.
**/
/*
* Possibles values set in p_owner->reload atomic
*/
......@@ -100,7 +147,6 @@ struct vlc_input_decoder_t
block_fifo_t *p_fifo;
/* Lock for communication with decoder thread */
vlc_mutex_t lock;
vlc_cond_t wait_request;
vlc_cond_t wait_acknowledge;
vlc_cond_t wait_fifo; /* TODO: merge with wait_acknowledge */
......@@ -169,6 +215,7 @@ struct vlc_input_decoder_t
#define MAX_CC_DECODERS 64 /* The es_out only creates one type of es */
struct
{
vlc_mutex_t lock;
bool b_supported;
decoder_cc_desc_t desc;
vlc_input_decoder_t *pp_decoder[MAX_CC_DECODERS];
......@@ -292,7 +339,7 @@ static void DecoderUpdateFormatLocked( vlc_input_decoder_t *p_owner )
{
decoder_t *p_dec = &p_owner->dec;
vlc_mutex_assert( &p_owner->lock );
vlc_fifo_Assert(p_owner->p_fifo);
es_format_Clean( &p_owner->fmt );
es_format_Copy( &p_owner->fmt, &p_dec->fmt_out );
......@@ -352,10 +399,10 @@ static int ModuleThread_UpdateAudioFormat( decoder_t *p_dec )
vlc_aout_stream *p_astream = p_owner->p_astream;
/* Parameters changed, restart the aout */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
p_owner->p_astream = NULL;
p_owner->p_aout = NULL; // the DecoderThread should not use the old aout anymore
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
vlc_aout_stream_Delete( p_astream );
input_resource_PutAout( p_owner->p_resource, p_aout );
......@@ -413,23 +460,24 @@ static int ModuleThread_UpdateAudioFormat( decoder_t *p_dec )
else
p_astream = NULL;
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
p_owner->p_aout = p_aout;
p_owner->p_astream = p_astream;
DecoderUpdateFormatLocked( p_owner );
aout_FormatPrepare( &p_owner->fmt.audio );
vlc_mutex_unlock( &p_owner->lock );
if( p_aout == NULL )
{
vlc_fifo_Unlock(p_owner->p_fifo);
return -1;
}
p_dec->fmt_out.audio.i_bytes_per_frame =
p_owner->fmt.audio.i_bytes_per_frame;
p_dec->fmt_out.audio.i_frame_length =
p_owner->fmt.audio.i_frame_length;
vlc_fifo_Lock( p_owner->p_fifo );
p_owner->reset_out_state = true;
vlc_fifo_Unlock( p_owner->p_fifo );
}
......@@ -459,7 +507,7 @@ static int ModuleThread_UpdateVideoFormat( decoder_t *p_dec, vlc_video_context *
p_owner->vctx = vctx ? vlc_video_context_Hold(vctx) : NULL;
// configure the new vout
vlc_fifo_Lock(p_owner->p_fifo);
if ( p_owner->out_pool == NULL )
{
unsigned dpb_size;
......@@ -492,13 +540,11 @@ static int ModuleThread_UpdateVideoFormat( decoder_t *p_dec, vlc_video_context *
msg_Err(p_dec, "Failed to create a pool of %d %4.4s pictures",
dpb_size + p_dec->i_extra_picture_buffers + 1,
(char*)&p_dec->fmt_out.video.i_chroma);
vlc_fifo_Unlock(p_owner->p_fifo);
goto error;
}
vlc_mutex_lock( &p_owner->lock );
p_owner->out_pool = pool;
vlc_mutex_unlock( &p_owner->lock );
}
vout_configuration_t cfg = {
......@@ -507,6 +553,8 @@ static int ModuleThread_UpdateVideoFormat( decoder_t *p_dec, vlc_video_context *
.fmt = &p_dec->fmt_out.video,
.mouse_event = MouseEvent, .mouse_opaque = p_dec,
};
vlc_fifo_Unlock(p_owner->p_fifo);
enum input_resource_vout_state vout_state;
vout_thread_t *p_vout =
input_resource_RequestVout(p_owner->p_resource, vctx, &cfg, NULL,
......@@ -516,18 +564,19 @@ static int ModuleThread_UpdateVideoFormat( decoder_t *p_dec, vlc_video_context *
assert(vout_state == INPUT_RESOURCE_VOUT_NOTCHANGED ||
vout_state == INPUT_RESOURCE_VOUT_STARTED);
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
p_owner->vout_started = true;
vlc_mutex_unlock( &p_owner->lock );
if (vout_state == INPUT_RESOURCE_VOUT_STARTED)
{
vlc_fifo_Lock( p_owner->p_fifo );
p_owner->reset_out_state = true;
vlc_fifo_Unlock( p_owner->p_fifo );
vlc_fifo_Unlock(p_owner->p_fifo);
decoder_Notify(p_owner, on_vout_started, p_vout, p_owner->vout_order);
}
else
vlc_fifo_Unlock(p_owner->p_fifo);
return 0;
}
else
......@@ -536,15 +585,15 @@ static int ModuleThread_UpdateVideoFormat( decoder_t *p_dec, vlc_video_context *
vout_state == INPUT_RESOURCE_VOUT_STOPPED);
if (vout_state == INPUT_RESOURCE_VOUT_STOPPED)
decoder_Notify(p_owner, on_vout_stopped, p_owner->p_vout);
decoder_Notify(p_owner, on_vout_stopped, cfg.vout);
}
error:
/* Clean fmt and vctx to trigger a new vout creation on the next update
* call */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
es_format_Clean( &p_owner->fmt );
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
if (p_owner->vctx != NULL)
{
......@@ -559,6 +608,7 @@ static int CreateVoutIfNeeded(vlc_input_decoder_t *p_owner)
decoder_t *p_dec = &p_owner->dec;
bool need_vout = false;
vlc_fifo_Lock(p_owner->p_fifo);
if( p_owner->p_vout == NULL )
{
msg_Dbg(p_dec, "vout: none found");
......@@ -601,20 +651,21 @@ static int CreateVoutIfNeeded(vlc_input_decoder_t *p_owner)
}
if( !need_vout )
{
vlc_fifo_Unlock(p_owner->p_fifo);
return 0; // vout unchanged
vlc_mutex_lock( &p_owner->lock );
}
vout_thread_t *p_vout = p_owner->p_vout;
p_owner->p_vout = NULL; // the DecoderThread should not use the old vout anymore
p_owner->vout_started = false;
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock( p_owner->p_fifo );
enum vlc_vout_order order;
const vout_configuration_t cfg = { .vout = p_vout, .fmt = NULL };
p_vout = input_resource_RequestVout( p_owner->p_resource, NULL, &cfg, &order, NULL );
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock( p_owner->p_fifo );
p_owner->p_vout = p_vout;
p_owner->vout_order = order;
......@@ -622,7 +673,7 @@ static int CreateVoutIfNeeded(vlc_input_decoder_t *p_owner)
p_owner->fmt.video.i_chroma = p_dec->fmt_out.i_codec;
picture_pool_t *pool = p_owner->out_pool;
p_owner->out_pool = NULL;
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock( p_owner->p_fifo );
if ( pool != NULL )
picture_pool_Release( pool );
......@@ -673,9 +724,9 @@ static vlc_decoder_device * ModuleThread_GetDecoderDevice( decoder_t *p_dec )
if ( need_format_update )
{
/* the format has changed but we don't need a new vout */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
DecoderUpdateFormatLocked( p_owner );
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
}
return dec_device;
}
......@@ -720,14 +771,14 @@ static subpicture_t *ModuleThread_NewSpuBuffer( decoder_t *p_dec,
assert(p_owner->i_spu_channel != VOUT_SPU_CHANNEL_INVALID);
decoder_Notify(p_owner, on_vout_stopped, p_owner->p_vout);
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock( p_owner->p_fifo );
vout_UnregisterSubpictureChannel(p_owner->p_vout,
p_owner->i_spu_channel);
p_owner->i_spu_channel = VOUT_SPU_CHANNEL_INVALID;
vout_Release(p_owner->p_vout);
p_owner->p_vout = NULL; // the DecoderThread should not use the old vout anymore
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Lock( p_owner->p_fifo );
}
return NULL;
}
......@@ -737,7 +788,7 @@ static subpicture_t *ModuleThread_NewSpuBuffer( decoder_t *p_dec,
if (p_owner->p_vout) /* notify the previous vout deletion unlocked */
decoder_Notify(p_owner, on_vout_stopped, p_owner->p_vout);
vlc_mutex_lock(&p_owner->lock);
vlc_fifo_Lock(p_owner->p_fifo);
if (p_owner->p_vout)
{
......@@ -758,14 +809,14 @@ static subpicture_t *ModuleThread_NewSpuBuffer( decoder_t *p_dec,
if (p_owner->i_spu_channel == VOUT_SPU_CHANNEL_INVALID)
{
/* The new vout doesn't support SPU, aborting... */
vlc_mutex_unlock(&p_owner->lock);
vlc_fifo_Unlock(p_owner->p_fifo);
vout_Release(p_vout);
return NULL;
}
p_owner->p_vout = p_vout;
p_owner->vout_order = channel_order;
vlc_mutex_unlock(&p_owner->lock);
vlc_fifo_Unlock(p_owner->p_fifo);
assert(channel_order != VLC_VOUT_ORDER_NONE);
decoder_Notify(p_owner, on_vout_started, p_vout, channel_order);
......@@ -805,11 +856,11 @@ static vlc_tick_t ModuleThread_GetDisplayDate( decoder_t *p_dec,
{
vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
if( p_owner->b_waiting || p_owner->paused )
i_ts = VLC_TICK_INVALID;
float rate = p_owner->output_rate;
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
if( !p_owner->p_clock || i_ts == VLC_TICK_INVALID )
return i_ts;
......@@ -823,9 +874,9 @@ static float ModuleThread_GetDisplayRate( decoder_t *p_dec )
if( !p_owner->p_clock )
return 1.f;
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
float rate = p_owner->output_rate;
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
return rate;
}
......@@ -857,7 +908,7 @@ static void RequestReload( vlc_input_decoder_t *p_owner )
static void DecoderWaitUnblock( vlc_input_decoder_t *p_owner )
{
vlc_mutex_assert( &p_owner->lock );
vlc_fifo_Assert(p_owner->p_fifo);
if( p_owner->b_waiting )
{
......@@ -866,7 +917,7 @@ static void DecoderWaitUnblock( vlc_input_decoder_t *p_owner )
}
while( p_owner->b_waiting && p_owner->b_has_data )
vlc_cond_wait( &p_owner->wait_request, &p_owner->lock );
vlc_fifo_WaitCond(p_owner->p_fifo, &p_owner->wait_request);
}
static inline void DecoderUpdatePreroll( vlc_tick_t *pi_preroll, const vlc_frame_t *p )
......@@ -884,6 +935,47 @@ static inline void DecoderUpdatePreroll( vlc_tick_t *pi_preroll, const vlc_frame
}
#ifdef ENABLE_SOUT
static void DecoderSendSubstream(vlc_input_decoder_t *p_owner)
{
decoder_t *p_dec = &p_owner->dec;
if (p_dec->pf_get_cc == NULL)
return;
bool b_wants_substreams;
int ret = sout_StreamControl(p_owner->p_sout,
SOUT_STREAM_WANTS_SUBSTREAMS,
&b_wants_substreams);
if (ret != VLC_SUCCESS || !b_wants_substreams)
return;
if (p_owner->cc.p_sout_input == NULL && p_owner->cc.b_sout_created)
return;
decoder_cc_desc_t desc;
vlc_frame_t *p_cc = p_dec->pf_get_cc( p_dec, &desc );
if (p_cc == NULL)
return;
if (!p_owner->cc.b_sout_created)
{
es_format_t ccfmt;
es_format_Init(&ccfmt, SPU_ES, VLC_CODEC_CEA608);
ccfmt.i_group = p_owner->fmt.i_group;
ccfmt.subs.cc.i_reorder_depth = desc.i_reorder_depth;
p_owner->cc.p_sout_input = sout_InputNew( p_owner->p_sout, &ccfmt );
es_format_Clean(&ccfmt);
p_owner->cc.b_sout_created = true;
}
if (!p_owner->cc.p_sout_input ||
sout_InputSendBuffer(p_owner->p_sout, p_owner->cc.p_sout_input, p_cc))
{
block_Release(p_cc);
}
}
/* This function process a frame for sout
*/
static void DecoderThread_ProcessSout( vlc_input_decoder_t *p_owner, vlc_frame_t *frame )
......@@ -897,7 +989,7 @@ static void DecoderThread_ProcessSout( vlc_input_decoder_t *p_owner, vlc_frame_t
{
if( p_owner->p_sout_input == NULL )
{
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
DecoderUpdateFormatLocked( p_owner );
p_owner->fmt.i_group = p_dec->fmt_in.i_group;
......@@ -908,7 +1000,7 @@ static void DecoderThread_ProcessSout( vlc_input_decoder_t *p_owner, vlc_frame_t
p_owner->fmt.psz_language =
strdup( p_dec->fmt_in.psz_language );
}
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
p_owner->p_sout_input =
sout_InputNew( p_owner->p_sout, &p_owner->fmt );
......@@ -930,42 +1022,10 @@ static void DecoderThread_ProcessSout( vlc_input_decoder_t *p_owner, vlc_frame_t
while( sout_frame )
{
vlc_frame_t *p_next = sout_frame->p_next;
bool b_wants_substreams;
sout_frame->p_next = NULL;
if( p_dec->pf_get_cc
&& sout_StreamControl( p_owner->p_sout,
SOUT_STREAM_WANTS_SUBSTREAMS,
&b_wants_substreams ) == VLC_SUCCESS
&& b_wants_substreams )
{
if( p_owner->cc.p_sout_input ||
!p_owner->cc.b_sout_created )
{
decoder_cc_desc_t desc;
vlc_frame_t *p_cc = p_dec->pf_get_cc( p_dec, &desc );
if( p_cc )
{
if(!p_owner->cc.b_sout_created)
{
es_format_t ccfmt;
es_format_Init(&ccfmt, SPU_ES, VLC_CODEC_CEA608);
ccfmt.i_group = p_owner->fmt.i_group;
ccfmt.subs.cc.i_reorder_depth = desc.i_reorder_depth;
p_owner->cc.p_sout_input = sout_InputNew( p_owner->p_sout, &ccfmt );
es_format_Clean(&ccfmt);
p_owner->cc.b_sout_created = true;
}
if( !p_owner->cc.p_sout_input ||
sout_InputSendBuffer( p_owner->p_sout, p_owner->cc.p_sout_input, p_cc ) )
{
block_Release( p_cc );
}
}
}
}
DecoderSendSubstream( p_owner );
/* FIXME --VLC_TICK_INVALID inspect stream_output*/
if ( sout_InputSendBuffer( p_owner->p_sout, p_owner->p_sout_input, sout_frame ) ==
......@@ -994,8 +1054,15 @@ static void DecoderThread_ProcessSout( vlc_input_decoder_t *p_owner, vlc_frame_t
static void DecoderPlayCc( vlc_input_decoder_t *p_owner, vlc_frame_t *p_cc,
const decoder_cc_desc_t *p_desc )
{
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
if (p_owner->flushing)
{
vlc_fifo_Unlock(p_owner->p_fifo);
vlc_frame_Release(p_cc);
return;
}
vlc_mutex_lock(&p_owner->cc.lock);
p_owner->cc.desc = *p_desc;
/* Fanout data to all decoders. We do not know if es_out
......@@ -1019,8 +1086,9 @@ static void DecoderPlayCc( vlc_input_decoder_t *p_owner, vlc_frame_t *p_cc,
p_cc = NULL; /* was last dec */
}
}
vlc_mutex_unlock(&p_owner->cc.lock);
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
if( p_cc ) /* can have bitmap set but no created decs */
block_Release( p_cc );
......@@ -1061,7 +1129,6 @@ static void ModuleThread_QueueCc( decoder_t *p_videodec, vlc_frame_t *p_cc,
static int ModuleThread_PlayVideo( vlc_input_decoder_t *p_owner, picture_t *p_picture )
{
decoder_t *p_dec = &p_owner->dec;
vout_thread_t *p_vout = p_owner->p_vout;
if( p_picture->date == VLC_TICK_INVALID )
/* FIXME: VLC_TICK_INVALID -- verify video_output */
......@@ -1071,13 +1138,22 @@ static int ModuleThread_PlayVideo( vlc_input_decoder_t *p_owner, picture_t *p_pi
return VLC_EGENERIC;
}
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock( p_owner->p_fifo );
if (p_owner->flushing)
{
vlc_fifo_Unlock(p_owner->p_fifo);
picture_Release(p_picture);
return VLC_SUCCESS;
}
vout_thread_t *p_vout = p_owner->p_vout;
assert( p_owner->vout_started );
bool prerolled = p_owner->i_preroll_end != PREROLL_NONE;
if( prerolled && p_owner->i_preroll_end > p_picture->date )
{
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock( p_owner->p_fifo );
picture_Release( p_picture );
return VLC_SUCCESS;
}
......@@ -1099,21 +1175,18 @@ static int ModuleThread_PlayVideo( vlc_input_decoder_t *p_owner, picture_t *p_pi
p_picture->b_force = true;
}
else
{
DecoderWaitUnblock( p_owner );
}
vlc_mutex_unlock( &p_owner->lock );
/* FIXME: The *input* FIFO should not be locked here. This will not work
* properly if/when pictures are queued asynchronously. */
vlc_fifo_Lock( p_owner->p_fifo );
if( unlikely(p_owner->paused) && likely(p_owner->frames_countdown > 0) )
p_owner->frames_countdown--;
vlc_fifo_Unlock( p_owner->p_fifo );
/* */
if( p_vout == NULL )
{
picture_Release( p_picture );
vlc_fifo_Unlock(p_owner->p_fifo);
return VLC_EGENERIC;
}
......@@ -1123,6 +1196,7 @@ static int ModuleThread_PlayVideo( vlc_input_decoder_t *p_owner, picture_t *p_pi
vout_Flush( p_vout, p_picture->date );
}
vout_PutPicture( p_vout, p_picture );
vlc_fifo_Unlock(p_owner->p_fifo);
return VLC_SUCCESS;
}
......@@ -1172,13 +1246,13 @@ static picture_t *thumbnailer_buffer_new( decoder_t *p_dec )
vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
/* Avoid decoding more than one frame when a thumbnail was
* already generated */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
if( !p_owner->b_first )
{
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
return NULL;
}
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
return picture_NewFromFormat( &p_dec->fmt_out.video );
}
......@@ -1187,10 +1261,10 @@ static void ModuleThread_QueueThumbnail( decoder_t *p_dec, picture_t *p_pic )
vlc_input_decoder_t *p_owner = dec_get_owner( p_dec );
bool b_first;
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
b_first = p_owner->b_first;
p_owner->b_first = false;
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
if( b_first )
decoder_Notify(p_owner, on_thumbnail_ready, p_pic);
......@@ -1211,17 +1285,24 @@ static int ModuleThread_PlayAudio( vlc_input_decoder_t *p_owner, vlc_frame_t *p_
return VLC_EGENERIC;
}
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
if (p_owner->flushing)
{
vlc_fifo_Unlock(p_owner->p_fifo);
block_Release(p_audio);
return VLC_SUCCESS;
}
bool prerolled = p_owner->i_preroll_end != PREROLL_NONE;
if( prerolled && p_owner->i_preroll_end > p_audio->i_pts )
{
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
block_Release( p_audio );
return VLC_SUCCESS;
}
p_owner->i_preroll_end = PREROLL_NONE;
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
if( unlikely(prerolled) )
{
......@@ -1233,11 +1314,11 @@ static int ModuleThread_PlayAudio( vlc_input_decoder_t *p_owner, vlc_frame_t *p_
/* */
/* */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
/* */
DecoderWaitUnblock( p_owner );
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
vlc_aout_stream *p_astream = p_owner->p_astream;
......@@ -1307,10 +1388,9 @@ static void ModuleThread_PlaySpu( vlc_input_decoder_t *p_owner, subpicture_t *p_
}
/* */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
DecoderWaitUnblock( p_owner );
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
if( p_subpic->i_start == VLC_TICK_INVALID )
{
......@@ -1337,17 +1417,17 @@ static void ModuleThread_QueueSpu( decoder_t *p_dec, subpicture_t *p_spu )
assert( p_owner->p_vout );
/* Preroll does not work very well with subtitle */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
if( p_spu->i_start != VLC_TICK_INVALID &&
p_spu->i_start < p_owner->i_preroll_end &&
( p_spu->i_stop == VLC_TICK_INVALID || p_spu->i_stop < p_owner->i_preroll_end ) )
{
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
subpicture_Delete( p_spu );
}
else
{
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
ModuleThread_PlaySpu( p_owner, p_spu );
}
}
......@@ -1422,9 +1502,9 @@ static void DecoderThread_ProcessInput( vlc_input_decoder_t *p_owner, vlc_frame_
if( frame->i_buffer <= 0 )
goto error;
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
DecoderUpdatePreroll( &p_owner->i_preroll_end, frame );
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
if( unlikely( frame->i_flags & BLOCK_FLAG_CORE_PRIVATE_RELOADED ) )
{
/* This frame has already been packetized */
......@@ -1509,69 +1589,37 @@ static void DecoderThread_Flush( vlc_input_decoder_t *p_owner )
p_dec->pf_flush( p_dec );
/* flush CC sub decoders */
vlc_mutex_lock(&p_owner->cc.lock);
if( p_owner->cc.b_supported )
{
for( int i=0; i<MAX_CC_DECODERS; i++ )
{
vlc_input_decoder_t *p_ccowner = p_owner->cc.pp_decoder[i];
if( p_ccowner && p_ccowner->dec.pf_flush )
p_ccowner->dec.pf_flush( &p_ccowner->dec );
}
}
vlc_mutex_lock( &p_owner->lock );
#ifdef ENABLE_SOUT
if ( p_owner->p_sout_input != NULL )
{
sout_InputFlush( p_owner->p_sout, p_owner->p_sout_input );
}
#endif
if( p_dec->fmt_in.i_cat == AUDIO_ES )
{
if( p_owner->p_astream )
vlc_aout_stream_Flush( p_owner->p_astream );
}
else if( p_dec->fmt_in.i_cat == VIDEO_ES )
{
if( p_owner->p_vout && p_owner->vout_started )
vout_FlushAll( p_owner->p_vout );
if(p_ccowner == NULL)
continue;
/* Reset the pool cancel state, previously set by
* vlc_input_decoder_Flush() */
if( p_owner->out_pool != NULL )
picture_pool_Cancel( p_owner->out_pool, false );
}
else if( p_dec->fmt_in.i_cat == SPU_ES )
{
if( p_owner->p_vout )
{
assert( p_owner->i_spu_channel != VOUT_SPU_CHANNEL_INVALID );
vout_FlushSubpictureChannel( p_owner->p_vout, p_owner->i_spu_channel );
vlc_input_decoder_Flush(p_ccowner);
}
}
p_owner->i_preroll_end = PREROLL_NONE;
vlc_mutex_unlock( &p_owner->lock );
vlc_mutex_unlock(&p_owner->cc.lock);
}
static void DecoderThread_ChangePause( vlc_input_decoder_t *p_owner, bool paused, vlc_tick_t date )
{
vlc_fifo_Assert(p_owner->p_fifo);
decoder_t *p_dec = &p_owner->dec;
msg_Dbg( p_dec, "toggling %s", paused ? "resume" : "pause" );
switch( p_dec->fmt_in.i_cat )
{
case VIDEO_ES:
vlc_mutex_lock( &p_owner->lock );
if( p_owner->p_vout != NULL && p_owner->vout_started )
vout_ChangePause( p_owner->p_vout, paused, date );
vlc_mutex_unlock( &p_owner->lock );
break;
case AUDIO_ES:
vlc_mutex_lock( &p_owner->lock );
if( p_owner->p_astream != NULL )
vlc_aout_stream_ChangePause( p_owner->p_astream, paused, date );
vlc_mutex_unlock( &p_owner->lock );
break;
case SPU_ES:
break;
......@@ -1582,10 +1630,11 @@ static void DecoderThread_ChangePause( vlc_input_decoder_t *p_owner, bool paused
static void DecoderThread_ChangeRate( vlc_input_decoder_t *p_owner, float rate )
{
vlc_fifo_Assert(p_owner->p_fifo);
decoder_t *p_dec = &p_owner->dec;
msg_Dbg( p_dec, "changing rate: %f", rate );
vlc_mutex_lock( &p_owner->lock );
switch( p_dec->fmt_in.i_cat )
{
case VIDEO_ES:
......@@ -1608,38 +1657,32 @@ static void DecoderThread_ChangeRate( vlc_input_decoder_t *p_owner, float rate )
vlc_assert_unreachable();
}
p_owner->output_rate = rate;
vlc_mutex_unlock( &p_owner->lock );
}
static void DecoderThread_ChangeDelay( vlc_input_decoder_t *p_owner, vlc_tick_t delay )
{
vlc_fifo_Assert(p_owner->p_fifo);
decoder_t *p_dec = &p_owner->dec;
msg_Dbg( p_dec, "changing delay: %"PRId64, delay );
switch( p_dec->fmt_in.i_cat )
{
case VIDEO_ES:
vlc_mutex_lock( &p_owner->lock );
if( p_owner->p_vout != NULL && p_owner->vout_started )
vout_ChangeDelay( p_owner->p_vout, delay );
vlc_mutex_unlock( &p_owner->lock );
break;
case AUDIO_ES:
vlc_mutex_lock( &p_owner->lock );
if( p_owner->p_astream != NULL )
vlc_aout_stream_ChangeDelay( p_owner->p_astream, delay );
vlc_mutex_unlock( &p_owner->lock );
break;
case SPU_ES:
vlc_mutex_lock( &p_owner->lock );
if( p_owner->p_vout != NULL )
{
assert(p_owner->i_spu_channel != VOUT_SPU_CHANNEL_INVALID);
vout_ChangeSpuDelay(p_owner->p_vout, p_owner->i_spu_channel,
delay);
}
vlc_mutex_unlock( &p_owner->lock );
break;
default:
vlc_assert_unreachable();
......@@ -1689,7 +1732,7 @@ static void *DecoderThread( void *p_data )
* is called again. This will avoid a second useless flush (but
* harmless). */
p_owner->flushing = false;
p_owner->i_preroll_end = PREROLL_NONE;
continue;
}
......@@ -1709,33 +1752,21 @@ static void *DecoderThread( void *p_data )
vlc_tick_t date = p_owner->pause_date;
paused = p_owner->paused;
vlc_fifo_Unlock( p_owner->p_fifo );
DecoderThread_ChangePause( p_owner, paused, date );
vlc_fifo_Lock( p_owner->p_fifo );
continue;
}
if( rate != p_owner->request_rate )
{
rate = p_owner->request_rate;
vlc_fifo_Unlock( p_owner->p_fifo );
DecoderThread_ChangeRate( p_owner, rate );
vlc_fifo_Lock( p_owner->p_fifo );
continue;
}
if( delay != p_owner->delay )
{
delay = p_owner->delay;
vlc_fifo_Unlock( p_owner->p_fifo );
DecoderThread_ChangeDelay( p_owner, delay );
vlc_fifo_Lock( p_owner->p_fifo );
continue;
}
......@@ -1777,12 +1808,10 @@ static void *DecoderThread( void *p_data )
}
/* TODO? Wait for draining instead of polling. */
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock( p_owner->p_fifo );
vlc_fifo_Lock(p_owner->p_fifo);
if( p_owner->b_draining && (frame == NULL) )
p_owner->b_draining = false;
vlc_cond_signal( &p_owner->wait_acknowledge );
vlc_mutex_unlock( &p_owner->lock );
}
vlc_fifo_Unlock( p_owner->p_fifo );
......@@ -1903,7 +1932,6 @@ CreateDecoder( vlc_object_t *p_parent, const struct vlc_input_decoder_cfg *cfg )
return NULL;
}
vlc_mutex_init( &p_owner->lock );
vlc_mutex_init( &p_owner->mouse_lock );
vlc_cond_init( &p_owner->wait_request );
vlc_cond_init( &p_owner->wait_acknowledge );
......@@ -1973,6 +2001,7 @@ CreateDecoder( vlc_object_t *p_parent, const struct vlc_input_decoder_cfg *cfg )
}
/* */
vlc_mutex_init(&p_owner->cc.lock);
p_owner->cc.b_supported = ( cfg->sout == NULL );
p_owner->cc.desc.i_608_channels = 0;
......@@ -2201,12 +2230,10 @@ void vlc_input_decoder_Delete( vlc_input_decoder_t *p_owner )
vlc_fifo_Lock( p_owner->p_fifo );
p_owner->aborting = true;
p_owner->flushing = true;
p_owner->b_waiting = false;
vlc_fifo_Signal( p_owner->p_fifo );
vlc_fifo_Unlock( p_owner->p_fifo );
/* Make sure we aren't waiting/decoding anymore */
vlc_mutex_lock( &p_owner->lock );
p_owner->b_waiting = false;
vlc_cond_signal( &p_owner->wait_request );
/* If the video output is paused or slow, or if the picture pool size was
......@@ -2219,9 +2246,6 @@ void vlc_input_decoder_Delete( vlc_input_decoder_t *p_owner )
if( p_dec->fmt_in.i_cat == VIDEO_ES && p_owner->p_vout != NULL
&& p_owner->vout_started )
{
if (p_owner->out_pool)
picture_pool_Cancel( p_owner->out_pool, true );
if( p_owner->paused )
{
/* The DecoderThread could be stuck in pf_decode(). This is likely the
......@@ -2238,7 +2262,7 @@ void vlc_input_decoder_Delete( vlc_input_decoder_t *p_owner )
vout_FlushAll( p_owner->p_vout );
}
}
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock( p_owner->p_fifo );
if( !vlc_input_decoder_IsSynchronous( p_owner ) )
vlc_join( p_owner->thread, NULL );
......@@ -2309,11 +2333,9 @@ bool vlc_input_decoder_IsEmpty( vlc_input_decoder_t * p_owner )
vlc_fifo_Unlock( p_owner->p_fifo );
return false;
}
vlc_fifo_Unlock( p_owner->p_fifo );
bool b_empty;
vlc_mutex_lock( &p_owner->lock );
#ifdef ENABLE_SOUT
if( p_owner->p_sout_input != NULL )
b_empty = true;
......@@ -2325,7 +2347,7 @@ bool vlc_input_decoder_IsEmpty( vlc_input_decoder_t * p_owner )
b_empty = vlc_aout_stream_IsDrained( p_owner->p_astream );
else
b_empty = true; /* TODO subtitles support */
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock( p_owner->p_fifo );
return b_empty;
}
......@@ -2359,12 +2381,6 @@ void vlc_input_decoder_Drain( vlc_input_decoder_t *p_owner )
*/
void vlc_input_decoder_Flush( vlc_input_decoder_t *p_owner )
{
if( vlc_input_decoder_IsSynchronous( p_owner ) )
{
DecoderThread_Flush( p_owner );
return;
}
enum es_format_category_e cat = p_owner->dec.fmt_in.i_cat;
vlc_fifo_Lock( p_owner->p_fifo );
......@@ -2384,38 +2400,43 @@ void vlc_input_decoder_Flush( vlc_input_decoder_t *p_owner )
&& p_owner->frames_countdown == 0 )
p_owner->frames_countdown++;
vlc_fifo_Signal( p_owner->p_fifo );
vlc_fifo_Unlock( p_owner->p_fifo );
if ( cat == VIDEO_ES )
if ( p_owner->p_sout_input != NULL )
{
/* Set the pool cancel state. This will unblock the module if it is
* waiting for new pictures (likely). This state will be reset back
* from the DecoderThread once the flush request is processed. */
vlc_mutex_lock( &p_owner->lock );
if( p_owner->out_pool != NULL )
picture_pool_Cancel( p_owner->out_pool, true );
vlc_mutex_unlock( &p_owner->lock );
#ifdef ENABLE_SOUT
sout_InputFlush( p_owner->p_sout, p_owner->p_sout_input );
#endif
}
if( p_owner->paused )
else if( cat == AUDIO_ES )
{
/* The DecoderThread could be stuck in pf_decode(). This is likely the
* case with paused asynchronous decoder modules that have a limited
* input and output pool size. Indeed, with such decoders, you have to
* release an output buffer to get an input buffer. So, when paused and
* flushed, the DecoderThread could be waiting for an output buffer to
* be released (or rendered). In that case, the DecoderThread will
* never be flushed since it be never leave pf_decode(). To fix this
* issue, pre-flush the vout from here. The vout will have to be
* flushed again since the module could be outputting more buffers just
* after being unstuck. */
vlc_mutex_lock( &p_owner->lock );
if( cat == VIDEO_ES && p_owner->p_vout && p_owner->vout_started )
if( p_owner->p_astream )
vlc_aout_stream_Flush( p_owner->p_astream );
}
else if( cat == VIDEO_ES )
{
if( p_owner->p_vout && p_owner->vout_started )
vout_FlushAll( p_owner->p_vout );
vlc_mutex_unlock( &p_owner->lock );
}
else if( cat == SPU_ES )
{
if( p_owner->p_vout )
{
assert( p_owner->i_spu_channel != VOUT_SPU_CHANNEL_INVALID );
vout_FlushSubpictureChannel( p_owner->p_vout, p_owner->i_spu_channel );
}
}
vlc_fifo_Signal( p_owner->p_fifo );
vlc_fifo_Unlock( p_owner->p_fifo );
if (vlc_input_decoder_IsSynchronous(p_owner))
{
/* With a synchronous decoder,there is no decoder thread which
* can process the flush request. We flush synchronously from
* here and reset the flushing state. */
DecoderThread_Flush(p_owner);
vlc_fifo_Lock(p_owner->p_fifo);
p_owner->flushing = false;
p_owner->i_preroll_end = PREROLL_NONE;
vlc_fifo_Unlock(p_owner->p_fifo);
}
}
......@@ -2446,8 +2467,12 @@ int vlc_input_decoder_SetCcState( vlc_input_decoder_t *p_owner, vlc_fourcc_t cod
decoder_t *p_dec = &p_owner->dec;
//msg_Warn( p_dec, "vlc_input_decoder_SetCcState: %d @%x", b_decode, i_channel );
vlc_mutex_lock(&p_owner->cc.lock);
if( !vlc_input_decoder_HasCCChanFlag( p_owner, codec, i_channel ) )
{
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_EGENERIC;
}
if( b_decode )
{
......@@ -2475,44 +2500,46 @@ int vlc_input_decoder_SetCcState( vlc_input_decoder_t *p_owner, vlc_fourcc_t cod
vlc_dialog_display_error( p_dec,
_("Streaming / Transcoding failed"), "%s",
_("VLC could not open the decoder module.") );
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_EGENERIC;
}
else if( !p_ccowner->dec.p_module )
{
DecoderUnsupportedCodec( p_dec, &fmt, true );
vlc_input_decoder_Delete(p_ccowner);
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_EGENERIC;
}
p_ccowner->p_clock = p_owner->p_clock;
vlc_mutex_lock( &p_owner->lock );
p_owner->cc.pp_decoder[i_channel] = p_ccowner;
vlc_mutex_unlock( &p_owner->lock );
}
else
{
vlc_input_decoder_t *p_cc;
vlc_mutex_lock( &p_owner->lock );
p_cc = p_owner->cc.pp_decoder[i_channel];
p_owner->cc.pp_decoder[i_channel] = NULL;
vlc_mutex_unlock( &p_owner->lock );
if( p_cc )
vlc_input_decoder_Delete(p_cc);
}
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_SUCCESS;
}
int vlc_input_decoder_GetCcState( vlc_input_decoder_t *p_owner, vlc_fourcc_t codec,
int i_channel, bool *pb_decode )
{
vlc_mutex_lock(&p_owner->cc.lock);
if( !vlc_input_decoder_HasCCChanFlag( p_owner, codec, i_channel ) )
{
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_EGENERIC;
}
vlc_mutex_lock( &p_owner->lock );
*pb_decode = p_owner->cc.pp_decoder[i_channel] != NULL;
vlc_mutex_unlock( &p_owner->lock );
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_SUCCESS;
}
......@@ -2551,12 +2578,12 @@ void vlc_input_decoder_StartWait( vlc_input_decoder_t *p_owner )
assert( !p_owner->b_waiting );
vlc_mutex_lock( &p_owner->lock );
p_owner->b_first = true;
vlc_fifo_Lock(p_owner->p_fifo);
p_owner->b_has_data = false;
p_owner->b_first = true;
p_owner->b_waiting = true;
vlc_cond_signal( &p_owner->wait_request );
vlc_mutex_unlock( &p_owner->lock );
vlc_cond_signal(&p_owner->wait_request);
vlc_fifo_Unlock(p_owner->p_fifo);
}
void vlc_input_decoder_StopWait( vlc_input_decoder_t *p_owner )
......@@ -2564,12 +2591,11 @@ void vlc_input_decoder_StopWait( vlc_input_decoder_t *p_owner )
if( vlc_input_decoder_IsSynchronous( p_owner ) )
return;
vlc_fifo_Lock(p_owner->p_fifo);
assert( p_owner->b_waiting );
vlc_mutex_lock( &p_owner->lock );
p_owner->b_waiting = false;
vlc_cond_signal( &p_owner->wait_request );
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
}
void vlc_input_decoder_Wait( vlc_input_decoder_t *p_owner )
......@@ -2581,24 +2607,21 @@ void vlc_input_decoder_Wait( vlc_input_decoder_t *p_owner )
}
assert( p_owner->b_waiting );
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
while( !p_owner->b_has_data )
{
/* Don't need to lock p_owner->paused since it's only modified by the
* owner */
if( p_owner->paused )
break;
vlc_fifo_Lock( p_owner->p_fifo );
if( p_owner->b_idle && vlc_fifo_IsEmpty( p_owner->p_fifo ) )
{
msg_Err( &p_owner->dec, "buffer deadlock prevented" );
vlc_fifo_Unlock( p_owner->p_fifo );
break;
}
vlc_fifo_Unlock( p_owner->p_fifo );
vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
vlc_fifo_WaitCond(p_owner->p_fifo, &p_owner->wait_acknowledge);
}
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
}
void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_owner,
......@@ -2612,19 +2635,19 @@ void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_owner,
vlc_fifo_Signal( p_owner->p_fifo );
vlc_fifo_Unlock( p_owner->p_fifo );
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
if( p_owner->dec.fmt_in.i_cat == VIDEO_ES )
{
if( p_owner->p_vout )
vout_NextPicture( p_owner->p_vout, pi_duration );
}
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
}
void vlc_input_decoder_GetStatus( vlc_input_decoder_t *p_owner,
struct vlc_input_decoder_status *status )
{
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
status->format.changed = p_owner->b_fmt_description;
p_owner->b_fmt_description = false;
......@@ -2649,7 +2672,7 @@ void vlc_input_decoder_GetStatus( vlc_input_decoder_t *p_owner,
}
status->cc.desc = p_owner->cc.desc;
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
}
size_t vlc_input_decoder_GetFifoSize( vlc_input_decoder_t *p_owner )
......@@ -2708,18 +2731,18 @@ int vlc_input_decoder_AddVoutOverlay( vlc_input_decoder_t *owner, subpicture_t *
assert( owner->dec.fmt_in.i_cat == VIDEO_ES );
assert( sub && channel );
vlc_mutex_lock( &owner->lock );
vlc_fifo_Lock(owner->p_fifo);
if( !owner->p_vout )
{
vlc_mutex_unlock( &owner->lock );
vlc_fifo_Unlock(owner->p_fifo);
return VLC_EGENERIC;
}
ssize_t channel_id =
vout_RegisterSubpictureChannel( owner->p_vout );
if (channel_id == -1)
{
vlc_mutex_unlock( &owner->lock );
vlc_fifo_Unlock(owner->p_fifo);
return VLC_EGENERIC;
}
sub->i_start = sub->i_stop = vlc_tick_now();
......@@ -2728,7 +2751,7 @@ int vlc_input_decoder_AddVoutOverlay( vlc_input_decoder_t *owner, subpicture_t *
sub->b_ephemer = true;
vout_PutSubpicture( owner->p_vout, sub );
vlc_mutex_unlock( &owner->lock );
vlc_fifo_Unlock(owner->p_fifo);
return VLC_SUCCESS;
}
......@@ -2736,16 +2759,16 @@ int vlc_input_decoder_DelVoutOverlay( vlc_input_decoder_t *owner, size_t channel
{
assert( owner->dec.fmt_in.i_cat == VIDEO_ES );
vlc_mutex_lock( &owner->lock );
vlc_fifo_Lock(owner->p_fifo);
if( !owner->p_vout )
{
vlc_mutex_unlock( &owner->lock );
vlc_fifo_Unlock(owner->p_fifo);
return VLC_EGENERIC;
}
vout_UnregisterSubpictureChannel( owner->p_vout, channel );
vlc_mutex_unlock( &owner->lock );
vlc_fifo_Unlock(owner->p_fifo);
return VLC_SUCCESS;
}
......@@ -2760,15 +2783,15 @@ int vlc_input_decoder_SetSpuHighlight( vlc_input_decoder_t *p_owner,
SOUT_INPUT_SET_SPU_HIGHLIGHT, spu_hl );
#endif
vlc_mutex_lock( &p_owner->lock );
vlc_fifo_Lock(p_owner->p_fifo);
if( !p_owner->p_vout )
{
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
return VLC_EGENERIC;
}
vout_SetSpuHighlight( p_owner->p_vout, spu_hl );
vlc_mutex_unlock( &p_owner->lock );
vlc_fifo_Unlock(p_owner->p_fifo);
return VLC_SUCCESS;
}
......@@ -44,6 +44,11 @@ struct vlc_fifo_t
static_assert (offsetof (block_fifo_t, q) == 0, "Problems in <vlc_block.h>");
bool vlc_fifo_Held(const block_fifo_t *fifo)
{
return vlc_mutex_held(&fifo->q.lock);
}
size_t vlc_fifo_GetCount(const block_fifo_t *fifo)
{
vlc_mutex_assert(&fifo->q.lock);
......
......@@ -43,7 +43,6 @@ struct picture_pool_t {
vlc_mutex_t lock;
vlc_cond_t wait;
bool canceled;
unsigned long long available;
vlc_atomic_rc_t refs;
unsigned short picture_count;
......@@ -121,7 +120,6 @@ picture_pool_t *picture_pool_New(unsigned count, picture_t *const *tab)
vlc_atomic_rc_init(&pool->refs);
pool->picture_count = count;
memcpy(pool->picture, tab, count * sizeof (picture_t *));
pool->canceled = false;
return pool;
}
......@@ -180,28 +178,21 @@ error:
picture_t *picture_pool_Get(picture_pool_t *pool)
{
unsigned long long available;
vlc_mutex_lock(&pool->lock);
assert(vlc_atomic_rc_get(&pool->refs) > 0);
available = pool->available;
while (available != 0)
if (pool->available == 0)
{
int i = ctz(available);
if (unlikely(pool->canceled))
break;
pool->available &= ~(1ULL << i);
vlc_mutex_unlock(&pool->lock);
available &= ~(1ULL << i);
return picture_pool_ClonePicture(pool, i);
return NULL;
}
int i = ctz(pool->available);
pool->available &= ~(1ULL << i);
vlc_mutex_unlock(&pool->lock);
return NULL;
return picture_pool_ClonePicture(pool, i);
}
picture_t *picture_pool_Wait(picture_pool_t *pool)
......@@ -210,14 +201,7 @@ picture_t *picture_pool_Wait(picture_pool_t *pool)
assert(vlc_atomic_rc_get(&pool->refs) > 0);
while (pool->available == 0)
{
if (pool->canceled)
{
vlc_mutex_unlock(&pool->lock);
return NULL;
}
vlc_cond_wait(&pool->wait, &pool->lock);
}
int i = ctz(pool->available);
pool->available &= ~(1ULL << i);
......@@ -226,17 +210,6 @@ picture_t *picture_pool_Wait(picture_pool_t *pool)
return picture_pool_ClonePicture(pool, i);
}
void picture_pool_Cancel(picture_pool_t *pool, bool canceled)
{
vlc_mutex_lock(&pool->lock);
assert(vlc_atomic_rc_get(&pool->refs) > 0);
pool->canceled = canceled;
if (canceled)
vlc_cond_broadcast(&pool->wait);
vlc_mutex_unlock(&pool->lock);
}
unsigned picture_pool_GetSize(const picture_pool_t *pool)
{
return pool->picture_count;
......
......@@ -28,6 +28,7 @@ check_PROGRAMS = \
test_src_input_stream \
test_src_input_stream_fifo \
test_src_input_thumbnail \
test_src_input_decoder \
test_src_player \
test_src_interface_dialog \
test_src_media_source \
......@@ -190,6 +191,12 @@ test_modules_stream_out_pcr_sync_SOURCES = modules/stream_out/pcr_sync.c \
../modules/stream_out/transcode/pcr_sync.h
test_modules_stream_out_pcr_sync_LDADD = $(LIBVLCCORE)
test_src_input_decoder_SOURCES = \
src/input/decoder/input_decoder.c \
src/input/decoder/input_decoder.h \
src/input/decoder/input_decoder_scenarios.c
test_src_input_decoder_LDADD = $(LIBVLCCORE) $(LIBVLC)
checkall:
$(MAKE) check_PROGRAMS="$(check_PROGRAMS) $(EXTRA_PROGRAMS)" check
......
/*****************************************************************************
* input_decoder.c: test for vlc_input_decoder state machine
*****************************************************************************
* Copyright (C) 2022 VideoLabs
*
* Author: Alexandre Janniaux <ajanni@videolabs.io>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/* Define a builtin module for mocked parts */
#define MODULE_NAME test_input_decoder_mock
#define MODULE_STRING "test_input_decoder_mock"
#undef __PLUGIN__
const char vlc_module_name[] = MODULE_STRING;
#include "../../../libvlc/test.h"
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_access.h>
#include <vlc_demux.h>
#include <vlc_codec.h>
#include <vlc_window.h>
#include <vlc_interface.h>
#include <vlc_player.h>
#include <vlc_filter.h>
#include <vlc_threads.h>
#include <vlc_vout_display.h>
#include <vlc_sout.h>
#include <limits.h>
#include "input_decoder.h"
static size_t current_scenario = 0;
static vlc_cond_t player_cond = VLC_STATIC_COND;
static void DecoderDeviceClose(struct vlc_decoder_device *device)
{ VLC_UNUSED(device); }
static const struct vlc_decoder_device_operations decoder_device_ops =
{
.close = DecoderDeviceClose,
};
static int OpenDecoderDevice(
struct vlc_decoder_device *device,
vlc_window_t *window
) {
VLC_UNUSED(window);
device->ops = &decoder_device_ops;
/* Pick any valid one, we'll not use the module which can make use of
* the private parts. */
device->type = VLC_DECODER_DEVICE_VAAPI;
return VLC_SUCCESS;
}
static int DecoderDecode(decoder_t *dec, block_t *block)
{
if (block == NULL)
return VLC_SUCCESS;
const picture_resource_t resource = {
.p_sys = NULL,
};
picture_t *pic = picture_NewFromResource(&dec->fmt_out.video, &resource);
assert(pic);
pic->date = block->i_pts;
pic->b_progressive = true;
block_Release(block);
struct input_decoder_scenario *scenario = &input_decoder_scenarios[current_scenario];
assert(scenario->decoder_decode != NULL);
return scenario->decoder_decode(dec, pic);
}
static void DecoderFlush(decoder_t *dec)
{
struct input_decoder_scenario *scenario = &input_decoder_scenarios[current_scenario];
assert(scenario->decoder_flush != NULL);
return scenario->decoder_flush(dec);
}
static void CloseDecoder(vlc_object_t *obj)
{
decoder_t *dec = (decoder_t*)obj;
struct vlc_video_context *vctx = dec->p_sys;
if (vctx)
vlc_video_context_Release(vctx);
}
static int OpenDecoder(vlc_object_t *obj)
{
decoder_t *dec = (decoder_t*)obj;
struct vlc_decoder_device *device = decoder_GetDecoderDevice(dec);
assert(device);
vlc_decoder_device_Release(device);
dec->pf_decode = DecoderDecode;
dec->pf_flush = DecoderFlush;
es_format_Clean(&dec->fmt_out);
es_format_Copy(&dec->fmt_out, &dec->fmt_in);
struct input_decoder_scenario *scenario = &input_decoder_scenarios[current_scenario];
assert(scenario->decoder_setup != NULL);
scenario->decoder_setup(dec);
msg_Dbg(obj, "Decoder chroma %4.4s -> %4.4s size %ux%u",
(const char *)&dec->fmt_in.i_codec,
(const char *)&dec->fmt_out.i_codec,
dec->fmt_out.video.i_width, dec->fmt_out.video.i_height);
return VLC_SUCCESS;
}
static void DisplayPrepare(vout_display_t *vd, picture_t *picture,
subpicture_t *subpic, vlc_tick_t date)
{
(void)vd; (void)subpic; (void)date;
struct input_decoder_scenario *scenario = &input_decoder_scenarios[current_scenario];
assert(scenario->display_prepare != NULL);
scenario->display_prepare(vd, picture);
}
static int DisplayControl(vout_display_t *vd, int query)
{
(void)vd; (void)query;
return VLC_SUCCESS;
}
static int OpenDisplay(vout_display_t *vd, video_format_t *fmtp, vlc_video_context *context)
{
(void)fmtp; (void)context;
static const struct vlc_display_operations ops = {
.prepare = DisplayPrepare,
.control = DisplayControl,
};
vd->ops = &ops;
return VLC_SUCCESS;
}
static int OpenWindow(vlc_window_t *wnd)
{
static const struct vlc_window_operations ops =
{
.resize = NULL,
};
wnd->ops = &ops;
return VLC_SUCCESS;
}
static void *SoutFilterAdd(sout_stream_t *stream, const es_format_t *fmt)
{
(void)stream; (void)fmt;
void *id = malloc(1);
assert(id != NULL);
return id;
}
static void SoutFilterDel(sout_stream_t *stream, void *id)
{
(void)stream;
free(id);
}
static int SoutFilterSend(sout_stream_t *stream, void *id, block_t *block)
{
struct input_decoder_scenario *scenario = &input_decoder_scenarios[current_scenario];
if (scenario->sout_filter_send != NULL)
return scenario->sout_filter_send(stream, id, block);
block_Release(block);
return VLC_SUCCESS;
}
static void SoutFilterFlush(sout_stream_t *stream, void *id)
{
struct input_decoder_scenario *scenario = &input_decoder_scenarios[current_scenario];
if (scenario->sout_filter_flush != NULL)
scenario->sout_filter_flush(stream, id);
}
static int OpenSoutFilter(vlc_object_t *obj)
{
sout_stream_t *stream = (sout_stream_t *)obj;
static const struct sout_stream_operations ops = {
.add = SoutFilterAdd,
.del = SoutFilterDel,
.send = SoutFilterSend,
.flush = SoutFilterFlush,
};
stream->ops = &ops;
return VLC_SUCCESS;
};
static void on_state_changed(vlc_player_t *player, enum vlc_player_state state, void *opaque)
{
(void)player; (void)state; (void) opaque;
vlc_cond_signal(&player_cond);
}
static void play_scenario(intf_thread_t *intf, struct input_decoder_scenario *scenario)
{
input_decoder_scenario_init();
input_item_t *media = input_item_New(scenario->source, "dummy");
assert(media);
var_Create(intf, "codec", VLC_VAR_STRING);
var_SetString(intf, "codec", MODULE_STRING);
if (scenario->sout != NULL)
{
char *sout;
assert(asprintf(&sout, ":sout=%s", scenario->sout) != -1);
input_item_AddOption(media, sout, VLC_INPUT_OPTION_TRUSTED);
free(sout);
}
vlc_player_t *player = vlc_player_New(&intf->obj,
VLC_PLAYER_LOCK_NORMAL, NULL, NULL);
assert(player);
intf->p_sys = (intf_sys_t *)player;
static const struct vlc_player_cbs player_cbs = {
.on_state_changed = on_state_changed,
};
vlc_player_Lock(player);
vlc_player_listener_id *listener =
vlc_player_AddListener(player, &player_cbs, NULL);
vlc_player_SetCurrentMedia(player, media);
vlc_player_Start(player);
vlc_player_Unlock(player);
input_decoder_scenario_wait(intf, scenario);
vlc_player_Lock(player);
vlc_player_Stop(player);
while (vlc_player_GetState(player) != VLC_PLAYER_STATE_STOPPED)
vlc_player_CondWait(player, &player_cond);
vlc_player_RemoveListener(player, listener);
vlc_player_Unlock(player);
input_decoder_scenario_check(scenario);
vlc_player_Delete(player);
input_item_Release(media);
var_Destroy(intf, "codec");
}
static int OpenIntf(vlc_object_t *obj)
{
intf_thread_t *intf = (intf_thread_t*)obj;
while (current_scenario < input_decoder_scenarios_count)
{
msg_Info(intf, " - Running scenario %zu", current_scenario);
play_scenario(intf, &input_decoder_scenarios[current_scenario]);
current_scenario++;
}
return VLC_SUCCESS;
}
/**
* Inject the mocked modules as a static plugin:
* - access for triggering the correct decoder
* - decoder for generating video format and context
* - filter for generating video format and context
**/
vlc_module_begin()
set_callback(OpenIntf)
set_capability("interface", 0)
add_submodule()
set_callback(OpenDecoderDevice)
set_capability("decoder device", 0)
add_submodule()
set_callbacks(OpenDecoder, CloseDecoder)
set_capability("video decoder", INT_MAX)
add_submodule()
set_callback(OpenWindow)
set_capability("vout window", INT_MAX)
add_submodule()
set_callback_display(OpenDisplay, 0)
add_submodule()
set_callback(OpenSoutFilter)
set_capability("sout output", 0)
vlc_module_end()
/* Helper typedef for vlc_static_modules */
typedef int (*vlc_plugin_cb)(vlc_set_cb, void*);
VLC_EXPORT vlc_plugin_cb vlc_static_modules[] = {
VLC_SYMBOL(vlc_entry),
NULL
};
int main( int argc, char **argv )
{
(void)argc; (void)argv;
test_init();
const char * const args[] = {
"-vvv",
"--vout=" MODULE_STRING,
"--dec-dev=" MODULE_STRING,
"--aout=dummy",
"--text-renderer=dummy",
"--no-auto-preparse",
"--no-spu",
"--no-osd",
};
libvlc_instance_t *vlc = libvlc_new(ARRAY_SIZE(args), args);
libvlc_add_intf(vlc, MODULE_STRING);
libvlc_playlist_play(vlc);
libvlc_release(vlc);
assert(input_decoder_scenarios_count == current_scenario);
return 0;
}
/*****************************************************************************
* input_decoder.h: test for input_decoder state machine
*****************************************************************************
* Copyright (C) 2022 VideoLabs
*
* Author: Alexandre Janniaux <ajanni@videolabs.io>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <vlc_fourcc.h>
#define TEST_FLAG_CONVERTER 0x01
#define TEST_FLAG_FILTER 0x02
typedef struct vout_display_t vout_display_t;
typedef struct intf_thread_t intf_thread_t;
struct input_decoder_scenario {
const char *source;
const char *sout;
void (*decoder_setup)(decoder_t *);
int (*decoder_decode)(decoder_t *, picture_t *);
void (*decoder_flush)(decoder_t *);
void (*display_prepare)(vout_display_t *vd, picture_t *pic);
void (*interface_setup)(intf_thread_t *intf);
int (*sout_filter_send)(sout_stream_t *stream, void *id, block_t *block);
void (*sout_filter_flush)(sout_stream_t *stream, void *id);
};
void input_decoder_scenario_init(void);
void input_decoder_scenario_wait(intf_thread_t *intf, struct input_decoder_scenario *scenario);
void input_decoder_scenario_check(struct input_decoder_scenario *scenario);
extern size_t input_decoder_scenarios_count;
extern struct input_decoder_scenario input_decoder_scenarios[];
/*****************************************************************************
* input_decoder_scenario.c: testflight for input_decoder state machine
*****************************************************************************
* Copyright (C) 2022 VideoLabs
*
* Author: Alexandre Janniaux <ajanni@videolabs.io>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#define MODULE_NAME test_input_decoder_mock
#define MODULE_STRING "test_input_decoder_mock"
#undef __PLUGIN__
#include <vlc_common.h>
#include <vlc_messages.h>
#include <vlc_player.h>
#include <vlc_interface.h>
#include <vlc_codec.h>
#include "input_decoder.h"
static struct scenario_data
{
vlc_sem_t wait_stop;
vlc_sem_t display_prepare_signal;
vlc_sem_t wait_ready_to_flush;
struct vlc_video_context *decoder_vctx;
bool skip_decoder;
bool stream_out_sent;
} scenario_data;
static void decoder_fixed_size(decoder_t *dec, vlc_fourcc_t chroma,
unsigned width, unsigned height)
{
dec->fmt_out.video.i_chroma
= dec->fmt_out.i_codec
= chroma;
dec->fmt_out.video.i_visible_width
= dec->fmt_out.video.i_width
= width;
dec->fmt_out.video.i_visible_height
= dec->fmt_out.video.i_height
= height;
}
static void decoder_i420_800_600(decoder_t *dec)
{ decoder_fixed_size(dec, VLC_CODEC_I420, 800, 600); }
static int decoder_decode_check_cc(decoder_t *dec, picture_t *pic)
{
vlc_tick_t date = pic->date;
picture_Release(pic);
block_t *p_cc = block_Alloc( 1 );
if (p_cc == NULL)
return VLC_ENOMEM;
p_cc->i_dts = p_cc->i_pts = date;
decoder_cc_desc_t desc = {
.i_608_channels = 1,
};
decoder_QueueCc( dec, p_cc, &desc );
vlc_sem_post(&scenario_data.wait_ready_to_flush);
return VLC_SUCCESS;
}
struct picture_watcher_context {
picture_context_t context;
vlc_sem_t wait_picture;
vlc_sem_t wait_prepare;
vlc_atomic_rc_t rc;
};
static void context_destroy(picture_context_t *context)
{
struct picture_watcher_context *watcher =
container_of(context, struct picture_watcher_context, context);
if (vlc_atomic_rc_dec(&watcher->rc))
vlc_sem_post(&watcher->wait_picture);
}
static picture_context_t * context_copy(picture_context_t *context)
{
struct picture_watcher_context *watcher =
container_of(context, struct picture_watcher_context, context);
vlc_atomic_rc_inc(&watcher->rc);
return context;
}
static int decoder_decode_check_flush_video(decoder_t *dec, picture_t *pic)
{
if (scenario_data.skip_decoder)
{
picture_Release(pic);
return VLC_SUCCESS;
}
int ret = decoder_UpdateVideoOutput(dec, NULL);
assert(ret == VLC_SUCCESS);
struct picture_watcher_context context1 = {
.context.destroy = context_destroy,
.context.copy = context_copy,
};
vlc_sem_init(&context1.wait_picture, 0);
vlc_atomic_rc_init(&context1.rc);
picture_t *second_pic = picture_Clone(pic);
second_pic->b_force = true;
second_pic->date = VLC_TICK_0;
second_pic->b_progressive = true;
second_pic->context = &context1.context;
msg_Info(dec, "Send first frame from decoder to video output");
decoder_QueueVideo(dec, second_pic);
msg_Info(dec, "Wait for the display to prepare the frame");
vlc_sem_wait(&context1.wait_prepare);
msg_Info(dec, "Trigger decoder and vout flush");
vlc_sem_post(&scenario_data.wait_ready_to_flush);
/* Wait for the picture to be flushed by the vout. */
msg_Info(dec, "Wait for the picture to be flushed from the vout");
vlc_sem_wait(&context1.wait_picture);
/* Reinit the picture context waiter. */
struct picture_watcher_context context2 = {
.context.destroy = context_destroy,
.context.copy = context_copy,
};
vlc_sem_init(&context2.wait_picture, 0);
vlc_atomic_rc_init(&context2.rc);
picture_t *third_pic = picture_Clone(pic);
third_pic->b_force = true;
third_pic->date = VLC_TICK_0 + 1;
third_pic->b_progressive = true;
third_pic->context = &context2.context;
msg_Info(dec, "Re-queue the picture to the vout before decoder::pf_flush is called");
decoder_QueueVideo(dec, third_pic);
/* Wait for the picture to be flushed by the input decoder. */
msg_Info(dec, "Ensure the picture has been discarded by the input decoder");
vlc_sem_wait(&context2.wait_picture);
/* Ok, since the picture has been released, we should have decode succeed
* and we can now check that flush is called. */
picture_Release(pic);
msg_Info(dec, "Nothing to do from pf_decode, let pf_flush be called by the input decoder");
scenario_data.skip_decoder = true;
return VLC_SUCCESS;
}
static void decoder_flush_signal(decoder_t *dec)
{
(void)dec;
vlc_sem_post(&scenario_data.wait_stop);
}
static void display_prepare_signal(vout_display_t *vd, picture_t *pic)
{
(void)vd;
struct picture_watcher_context *watcher =
container_of(pic->context, struct picture_watcher_context, context);
vlc_sem_post(&watcher->wait_prepare);
}
static void PlayerOnTrackListChanged(vlc_player_t *player,
enum vlc_player_list_action action,
const struct vlc_player_track *track,
void *data)
{
(void)data;
if (action != VLC_PLAYER_LIST_ADDED ||
track->fmt.i_cat != SPU_ES)
return;
vlc_player_SelectTrack(player, track, VLC_PLAYER_SELECT_EXCLUSIVE);
}
static void interface_setup_select_cc(intf_thread_t *intf)
{
vlc_player_t *player = (vlc_player_t *)intf->p_sys;
static const struct vlc_player_cbs player_cbs =
{
.on_track_list_changed = PlayerOnTrackListChanged,
};
vlc_player_Lock(player);
vlc_player_listener_id *listener_id =
vlc_player_AddListener(player, &player_cbs, NULL);
vlc_player_Unlock(player);
vlc_sem_wait(&scenario_data.wait_ready_to_flush);
vlc_player_Lock(player);
vlc_player_SetPosition(player, 0);
vlc_player_Unlock(player);
vlc_sem_wait(&scenario_data.wait_ready_to_flush);
vlc_player_Lock(player);
vlc_player_RemoveListener(player, listener_id);
vlc_player_Unlock(player);
}
static void interface_setup_check_flush(intf_thread_t *intf)
{
vlc_player_t *player = (vlc_player_t *)intf->p_sys;
vlc_sem_wait(&scenario_data.wait_ready_to_flush);
vlc_player_Lock(player);
vlc_player_SetPosition(player, 0);
vlc_player_Unlock(player);
}
static int sout_filter_send(sout_stream_t *stream, void *id, block_t *block)
{
(void)stream; (void)id;
block_Release(block);
scenario_data.stream_out_sent = true;
vlc_sem_post(&scenario_data.wait_ready_to_flush);
return VLC_SUCCESS;
}
static void sout_filter_flush(sout_stream_t *stream, void *id)
{
(void)stream; (void)id;
assert(scenario_data.stream_out_sent);
vlc_sem_post(&scenario_data.wait_stop);
}
const char source_800_600[] = "mock://video_track_count=1;length=100000000000;video_width=800;video_height=600";
struct input_decoder_scenario input_decoder_scenarios[] =
{{
.source = source_800_600,
.decoder_setup = decoder_i420_800_600,
.decoder_flush = decoder_flush_signal,
.decoder_decode = decoder_decode_check_cc,
.interface_setup = interface_setup_select_cc,
},
{
.source = source_800_600,
.decoder_setup = decoder_i420_800_600,
.decoder_decode = decoder_decode_check_flush_video,
.decoder_flush = decoder_flush_signal,
.display_prepare = display_prepare_signal,
.interface_setup = interface_setup_check_flush,
},
{
/* Check that stream output is also flushed:
- the test cannot work if the stream_out filter is not added
- sout_filter_send(), signal the interface that it can flush
- the interface change player position to trigger a flush
- the flush is signaled to the stream_out filter
- the stream_out filter signal the end of the test */
.source = source_800_600,
.sout = "#" MODULE_STRING,
.sout_filter_send = sout_filter_send,
.sout_filter_flush = sout_filter_flush,
.interface_setup = interface_setup_check_flush,
}};
size_t input_decoder_scenarios_count = ARRAY_SIZE(input_decoder_scenarios);
void input_decoder_scenario_init(void)
{
scenario_data.decoder_vctx = NULL;
scenario_data.skip_decoder = false;
scenario_data.stream_out_sent = false;
vlc_sem_init(&scenario_data.wait_stop, 0);
vlc_sem_init(&scenario_data.display_prepare_signal, 0);
vlc_sem_init(&scenario_data.wait_ready_to_flush, 0);
}
void input_decoder_scenario_wait(intf_thread_t *intf, struct input_decoder_scenario *scenario)
{
if (scenario->interface_setup)
scenario->interface_setup(intf);
vlc_sem_wait(&scenario_data.wait_stop);
}
void input_decoder_scenario_check(struct input_decoder_scenario *scenario)
{
(void)scenario;
}