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
  • abdsaber000/vlc
  • falbrechtskirchinger/vlc
  • b.sullender/vlc
  • hulxv/vlc
407 results
Show changes
Commits on Source (9)
......@@ -44,6 +44,7 @@
#include <vlc_decoder.h>
#include <vlc_picture_pool.h>
#include <vlc_tracer.h>
#include <vlc_list.h>
#include "audio_output/aout_internal.h"
#include "stream_output/stream_output.h"
......@@ -96,7 +97,7 @@
* 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.
* subdecs.list table is protected through the `subdecs.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.
......@@ -212,20 +213,30 @@ struct vlc_input_decoder_t
bool b_idle;
bool aborting;
/* Sub decs */
struct
{
vlc_mutex_t lock;
struct vlc_list list;
} subdecs;
/* CC */
#define MAX_CC_DECODERS 64 /* The es_out only creates one type of es */
struct
{
/* All members guarded by subdecs.lock */
vlc_fourcc_t selected_codec;
vlc_mutex_t lock;
bool b_supported;
decoder_cc_desc_t desc;
vlc_input_decoder_t *pp_decoder[MAX_CC_DECODERS];
bool desc_changed;
bool b_sout_created;
sout_packetizer_input_t *p_sout_input;
char *sout_es_id;
} cc;
vlc_input_decoder_t *master_dec;
struct vlc_list node;
/* Mouse event */
vlc_mutex_t mouse_lock;
vlc_mouse_event mouse_event;
......@@ -1192,6 +1203,13 @@ static void GetCcChannels(vlc_input_decoder_t *owner, size_t *max_channels,
}
}
static bool SubDecoderIsCc(vlc_input_decoder_t *subdec)
{
return subdec->dec.fmt_in->i_cat == SPU_ES &&
(subdec->dec.fmt_in->i_codec == VLC_CODEC_CEA608 ||
subdec->dec.fmt_in->i_codec == VLC_CODEC_CEA708);
}
/* */
static void DecoderPlayCcLocked( vlc_input_decoder_t *p_owner, vlc_frame_t *p_cc,
const decoder_cc_desc_t *p_desc )
......@@ -1203,34 +1221,39 @@ static void DecoderPlayCcLocked( vlc_input_decoder_t *p_owner, vlc_frame_t *p_cc
return;
}
vlc_mutex_lock(&p_owner->cc.lock);
p_owner->cc.desc = *p_desc;
uint64_t i_bitmap;
GetCcChannels(p_owner, NULL, &i_bitmap);
vlc_mutex_lock(&p_owner->subdecs.lock);
if (p_owner->cc.desc.i_608_channels != p_desc->i_608_channels ||
p_owner->cc.desc.i_708_channels != p_desc->i_708_channels ||
p_owner->cc.desc.i_reorder_depth != p_desc->i_reorder_depth)
{
p_owner->cc.desc = *p_desc;
p_owner->cc.desc_changed = true;
}
for( int i=0; i_bitmap > 0; i_bitmap >>= 1, i++ )
bool first_cc = true;
vlc_input_decoder_t *it;
vlc_list_foreach(it, &p_owner->subdecs.list, node)
{
vlc_input_decoder_t *p_ccowner = p_owner->cc.pp_decoder[i];
if( !p_ccowner )
if (!SubDecoderIsCc(it))
continue;
if( i_bitmap > 1 )
if (first_cc)
{
block_t *dup = block_Duplicate(p_cc);
if (dup == NULL)
break;
block_FifoPut(p_ccowner->p_fifo, dup);
block_FifoPut(it->p_fifo, p_cc);
first_cc = false;
}
else
{
block_FifoPut( p_ccowner->p_fifo, p_cc );
p_cc = NULL; /* was last dec */
block_t *dup = block_Duplicate(p_cc);
if (dup == NULL)
break;
block_FifoPut(it->p_fifo, dup);
}
}
vlc_mutex_unlock(&p_owner->cc.lock);
if( p_cc ) /* can have bitmap set but no created decs */
vlc_mutex_unlock(&p_owner->subdecs.lock);
if (first_cc) /* can have bitmap set but no created decs */
block_Release( p_cc );
}
......@@ -1720,21 +1743,6 @@ static void DecoderThread_Flush( vlc_input_decoder_t *p_owner )
if ( p_dec->pf_flush != NULL )
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 == NULL)
continue;
vlc_input_decoder_Flush(p_ccowner);
}
}
vlc_mutex_unlock(&p_owner->cc.lock);
}
/**
......@@ -2031,18 +2039,18 @@ CreateDecoder( vlc_object_t *p_parent, const struct vlc_input_decoder_cfg *cfg )
}
/* */
vlc_mutex_init(&p_owner->cc.lock);
vlc_mutex_init(&p_owner->subdecs.lock);
p_owner->cc.selected_codec = cfg->cc_decoder == 708 ?
VLC_CODEC_CEA708 : VLC_CODEC_CEA608;
p_owner->cc.b_supported = ( cfg->sout == NULL );
p_owner->cc.desc.i_608_channels = 0;
p_owner->cc.desc.i_708_channels = 0;
for( unsigned i = 0; i < MAX_CC_DECODERS; i++ )
p_owner->cc.pp_decoder[i] = NULL;
vlc_list_init(&p_owner->subdecs.list);
p_owner->cc.p_sout_input = NULL;
p_owner->cc.sout_es_id = NULL;
p_owner->cc.b_sout_created = false;
p_owner->master_dec = NULL;
return p_owner;
}
......@@ -2142,20 +2150,6 @@ static void DeleteDecoder( vlc_input_decoder_t *p_owner, enum es_format_category
decoder_Destroy( &p_owner->dec );
}
static void DeleteCcDecoder(vlc_input_decoder_t *owner, size_t index)
{
assert(vlc_mutex_held(&owner->cc.lock));
vlc_input_decoder_t *cc = owner->cc.pp_decoder[index];
owner->cc.pp_decoder[index] = NULL;
if (cc != NULL)
{
vlc_input_decoder_Flush(cc);
vlc_input_decoder_Delete(cc);
}
}
/* */
static void DecoderUnsupportedCodec( decoder_t *p_dec, const es_format_t *fmt, bool b_decoding )
{
......@@ -2259,8 +2253,28 @@ vlc_input_decoder_Create( vlc_object_t *p_parent, const es_format_t *fmt, const
return decoder_New( p_parent, &cfg );
}
static void RemoveCcDecoder(vlc_input_decoder_t *owner,
vlc_input_decoder_t *subdec)
{
vlc_mutex_lock(&owner->subdecs.lock);
vlc_input_decoder_t *it;
vlc_list_foreach(it, &owner->subdecs.list, node)
if (it == subdec)
{
vlc_list_remove(&it->node);
vlc_mutex_unlock(&owner->subdecs.lock);
return;
}
vlc_assert_unreachable();
}
void vlc_input_decoder_Delete( vlc_input_decoder_t *p_owner )
{
if (p_owner->master_dec != NULL)
RemoveCcDecoder(p_owner->master_dec, p_owner);
vlc_fifo_Lock( p_owner->p_fifo );
p_owner->aborting = true;
p_owner->b_waiting = false;
......@@ -2272,21 +2286,77 @@ void vlc_input_decoder_Delete( vlc_input_decoder_t *p_owner )
if( !vlc_input_decoder_IsSynchronous( p_owner ) )
vlc_join( p_owner->thread, NULL );
/* */
if( p_owner->cc.b_supported )
{
size_t max_channels;
GetCcChannels(p_owner, &max_channels, NULL);
vlc_mutex_lock(&p_owner->cc.lock);
for (size_t i = 0; i < max_channels; i++)
DeleteCcDecoder(p_owner, i);
vlc_mutex_unlock(&p_owner->cc.lock);
}
#ifndef NDEBUG
vlc_mutex_lock(&p_owner->subdecs.lock);
assert(vlc_list_is_empty(&p_owner->subdecs.list));
vlc_mutex_unlock(&p_owner->subdecs.lock);
#endif
/* Delete decoder */
DeleteDecoder(p_owner, p_owner->dec_fmt_in.i_cat);
}
void vlc_subdec_desc_Clean(struct vlc_subdec_desc *desc)
{
for (size_t i = 0; i < desc->fmt_count; ++i)
es_format_Clean(&desc->fmt_array[i]);
free(desc->fmt_array);
}
static void GetCCDescLocked(vlc_input_decoder_t *owner,
struct vlc_subdec_desc *desc)
{
vlc_fifo_Assert(owner->p_fifo);
if (!owner->cc.desc_changed)
{
desc->fmt_array = NULL;
desc->fmt_count = 0;
return;
}
owner->cc.desc_changed = false;
size_t max_channels;
uint64_t bitmap;
GetCcChannels(owner, &max_channels, &bitmap);
int count = vlc_popcount(bitmap);
if (count == 0)
{
desc->fmt_array = NULL;
desc->fmt_count = 0;
return;
}
desc->fmt_array = vlc_alloc(count, sizeof(es_format_t));
if (unlikely(desc->fmt_array == NULL))
{
desc->fmt_count = 0;
return;
}
desc->fmt_count = count;
static const char CEA608_fmtdesc[] = N_("Closed captions %u");
static const char CEA708_fmtdesc[] = N_("DTVCC Closed captions %u");
const char *fmtdesc = owner->cc.selected_codec == VLC_CODEC_CEA608 ?
CEA608_fmtdesc : CEA708_fmtdesc;
size_t array_idx = 0;
for (int i = 0; bitmap > 0; bitmap >>= 1, i++)
{
if ((bitmap & 1) == 0)
continue;
es_format_t *fmt = &desc->fmt_array[array_idx++];
es_format_Init(fmt, SPU_ES, owner->cc.selected_codec);
fmt->i_id = i + 1;
fmt->subs.cc.i_channel = i;
fmt->subs.cc.i_reorder_depth = owner->cc.desc.i_reorder_depth;
if (asprintf(&fmt->psz_description, fmtdesc, fmt->i_id) == -1)
fmt->psz_description = NULL;
}
}
static void GetStatusLocked(vlc_input_decoder_t *p_owner,
struct vlc_input_decoder_status *status)
{
......@@ -2313,7 +2383,7 @@ static void GetStatusLocked(vlc_input_decoder_t *p_owner,
vlc_meta_Merge( status->format.meta, p_owner->p_description );
}
}
status->cc.desc = p_owner->cc.desc;
GetCCDescLocked(p_owner, &status->subdec_desc);
}
void vlc_input_decoder_DecodeWithStatus(vlc_input_decoder_t *p_owner, vlc_frame_t *frame,
......@@ -2469,90 +2539,39 @@ void vlc_input_decoder_Flush( vlc_input_decoder_t *p_owner )
}
}
static bool vlc_input_decoder_HasCCChanFlag( vlc_input_decoder_t *p_owner,
int i_channel )
vlc_input_decoder_t *
vlc_input_decoder_CreateSubDec(vlc_input_decoder_t *p_owner,
const struct vlc_input_decoder_cfg *cfg)
{
size_t i_max_channels;
uint64_t i_bitmap;
GetCcChannels(p_owner, &i_max_channels, &i_bitmap);
decoder_t *p_dec = &p_owner->dec;
return ( i_channel >= 0 && (size_t) i_channel < i_max_channels &&
( i_bitmap & ((uint64_t)1 << i_channel) ) );
}
vlc_mutex_lock(&p_owner->subdecs.lock);
int vlc_input_decoder_SetCcState( vlc_input_decoder_t *p_owner,
int i_channel, bool b_decode )
{
decoder_t *p_dec = &p_owner->dec;
vlc_input_decoder_t *p_ccowner;
vlc_mutex_lock(&p_owner->cc.lock);
if( !vlc_input_decoder_HasCCChanFlag( p_owner, i_channel ) )
p_ccowner = vlc_input_decoder_New( VLC_OBJECT(p_dec), cfg );
if( !p_ccowner )
{
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_EGENERIC;
msg_Err( p_dec, "could not create decoder" );
vlc_dialog_display_error( p_dec,
_("Streaming / Transcoding failed"), "%s",
_("VLC could not open the decoder module.") );
vlc_mutex_unlock(&p_owner->subdecs.lock);
return NULL;
}
if( b_decode )
else if( !p_ccowner->dec.p_module )
{
vlc_input_decoder_t *p_ccowner;
es_format_t fmt;
es_format_Init( &fmt, SPU_ES, p_owner->cc.selected_codec );
fmt.subs.cc.i_channel = i_channel;
fmt.subs.cc.i_reorder_depth = p_owner->cc.desc.i_reorder_depth;
const struct vlc_input_decoder_cfg cfg = {
.fmt = &fmt,
.str_id = p_owner->psz_id,
.clock = p_owner->p_clock,
.resource = p_owner->p_resource,
.sout = p_owner->p_sout,
.input_type = INPUT_TYPE_NONE,
.cbs = NULL, .cbs_data = NULL,
};
p_ccowner = vlc_input_decoder_New( VLC_OBJECT(p_dec), &cfg );
if( !p_ccowner )
{
msg_Err( p_dec, "could not create decoder" );
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_Flush(p_ccowner);
vlc_input_decoder_Delete(p_ccowner);
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_EGENERIC;
}
p_ccowner->p_clock = p_owner->p_clock;
p_owner->cc.pp_decoder[i_channel] = p_ccowner;
DecoderUnsupportedCodec( p_dec, cfg->fmt, true );
vlc_input_decoder_Delete(p_ccowner);
vlc_mutex_unlock(&p_owner->subdecs.lock);
return NULL;
}
else
DeleteCcDecoder(p_owner, i_channel);
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_SUCCESS;
}
int vlc_input_decoder_GetCcState( vlc_input_decoder_t *p_owner,
int i_channel, bool *pb_decode )
{
vlc_mutex_lock(&p_owner->cc.lock);
if( !vlc_input_decoder_HasCCChanFlag( p_owner, i_channel ) )
{
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_EGENERIC;
}
vlc_list_append(&p_ccowner->node, &p_owner->subdecs.list);
p_ccowner->master_dec = p_owner;
*pb_decode = p_owner->cc.pp_decoder[i_channel] != NULL;
vlc_mutex_unlock(&p_owner->cc.lock);
return VLC_SUCCESS;
vlc_mutex_unlock(&p_owner->subdecs.lock);
return p_ccowner;
}
void vlc_input_decoder_ChangePause( vlc_input_decoder_t *p_owner,
......@@ -2585,7 +2604,8 @@ void vlc_input_decoder_ChangeDelay( vlc_input_decoder_t *owner, vlc_tick_t delay
void vlc_input_decoder_StartWait( vlc_input_decoder_t *p_owner )
{
if( vlc_input_decoder_IsSynchronous( p_owner ) )
if( p_owner->master_dec != NULL /* SubDecs are paced by their master */
|| vlc_input_decoder_IsSynchronous( p_owner ) )
return;
assert( !p_owner->b_waiting );
......@@ -2600,7 +2620,8 @@ void vlc_input_decoder_StartWait( vlc_input_decoder_t *p_owner )
void vlc_input_decoder_StopWait( vlc_input_decoder_t *p_owner )
{
if( vlc_input_decoder_IsSynchronous( p_owner ) )
if( p_owner->master_dec != NULL /* SubDecs are paced by their master */
|| vlc_input_decoder_IsSynchronous( p_owner ) )
return;
vlc_fifo_Lock(p_owner->p_fifo);
......@@ -2612,7 +2633,8 @@ void vlc_input_decoder_StopWait( vlc_input_decoder_t *p_owner )
void vlc_input_decoder_Wait( vlc_input_decoder_t *p_owner )
{
if( vlc_input_decoder_IsSynchronous( p_owner ) )
if( p_owner->master_dec != NULL /* SubDecs are paced by their master */
|| vlc_input_decoder_IsSynchronous( p_owner ) )
{
/* Nothing to wait for. There's no decoder thread running. */
return;
......
......@@ -104,21 +104,28 @@ void vlc_input_decoder_StopWait( vlc_input_decoder_t * );
bool vlc_input_decoder_IsEmpty( vlc_input_decoder_t * );
/**
* This function activates the request closed caption channel.
*/
int vlc_input_decoder_SetCcState( vlc_input_decoder_t *, int i_channel, bool b_decode );
/**
* This function returns an error if the requested channel does not exist and
* set pb_decode to the channel status(active or not) otherwise.
* This function Creates and adds the requested SubDec.
*
* The sub decoder returned by this function must be deleted with
* vlc_input_decoder_Delete() before the parent is deleted.
*/
int vlc_input_decoder_GetCcState( vlc_input_decoder_t *, int i_channel, bool *pb_decode );
vlc_input_decoder_t *
vlc_input_decoder_CreateSubDec(vlc_input_decoder_t *dec,
const struct vlc_input_decoder_cfg *cfg);
/**
* This function forces the display of the next picture
*/
void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_dec );
struct vlc_subdec_desc
{
es_format_t *fmt_array;
size_t fmt_count;
};
void vlc_subdec_desc_Clean(struct vlc_subdec_desc *desc);
struct vlc_input_decoder_status
{
struct {
......@@ -133,9 +140,7 @@ struct vlc_input_decoder_status
vlc_meta_t *meta;
} format;
struct {
decoder_cc_desc_t desc;
} cc;
struct vlc_subdec_desc subdec_desc;
};
/**
......
......@@ -142,15 +142,10 @@ struct es_out_id_t
vlc_tick_t i_pts_level;
vlc_tick_t delay;
/* Fields for Video with CC */
struct
{
vlc_fourcc_t type;
uint64_t i_bitmap; /* channels bitmap */
es_out_id_t *pp_es[64]; /* a max of 64 chans for CEA708 */
} cc;
/* Fields for ES created by decoders */
struct VLC_VECTOR(es_out_id_t *) sub_es_vec;
/* Field for CC track from a master video */
/* Field for a sub track from a master ES */
es_out_id_t *p_master;
struct vlc_list node;
......@@ -315,15 +310,6 @@ default_val:
return VLC_CLOCK_MASTER_AUTO;
}
static inline int EsOutGetClosedCaptionsChannel( const es_format_t *p_fmt )
{
if ((p_fmt->i_codec == VLC_CODEC_CEA608 && p_fmt->subs.cc.i_channel < 4)
|| (p_fmt->i_codec == VLC_CODEC_CEA708 && p_fmt->subs.cc.i_channel < 64))
return p_fmt->subs.cc.i_channel;
return -1;
}
#define foreach_es_then_es_slaves( pos ) \
for( int fetes_i=0; fetes_i<2; fetes_i++ ) \
vlc_list_foreach( pos, (!fetes_i ? &p_sys->es : &p_sys->es_slaves), node )
......@@ -669,18 +655,6 @@ static vlc_tick_t EsOutGetWakeup( es_out_t *out )
static es_out_id_t es_cat[DATA_ES];
static es_out_id_t *EsOutGetSelectedCat( es_out_t *out,
enum es_format_category_e cat )
{
es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
es_out_id_t *es;
foreach_es_then_es_slaves( es )
if( es->fmt.i_cat == cat && EsIsSelected( es ) )
return es;
return NULL;
}
static bool EsOutDecodersIsEmpty( es_out_t *out )
{
es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
......@@ -2151,8 +2125,7 @@ static es_out_id_t *EsOutAddLocked( es_out_t *out, input_source_t *source,
es->p_dec_record = NULL;
es->p_clock = NULL;
es->master = false;
es->cc.type = 0;
es->cc.i_bitmap = 0;
vlc_vector_init(&es->sub_es_vec);
es->p_master = p_master;
es->mouse_event_cb = NULL;
es->mouse_event_userdata = NULL;
......@@ -2190,20 +2163,7 @@ static es_out_id_t *EsOutAdd( es_out_t *out, input_source_t *source, const es_fo
static bool EsIsSelected( es_out_id_t *es )
{
/* Some tracks, especially closed-captions, are extracted from an
* existing elementary stream through the packetizer or the decoder,
* which must be selected for the extracted track to be selected.
* In every other cases, we don't need to consider that. */
if (es->p_master == NULL)
return es->p_dec != NULL;
bool b_decode = false;
if( es->p_master->p_dec )
{
int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
vlc_input_decoder_GetCcState( es->p_master->p_dec, i_channel, &b_decode );
}
return b_decode;
return es->p_dec != NULL;
}
static void ClockUpdate(vlc_tick_t system_ts, vlc_tick_t ts, double rate,
......@@ -2281,7 +2241,15 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
.cbs = &decoder_cbs,
.cbs_data = p_es,
};
dec = vlc_input_decoder_New( VLC_OBJECT(p_input), &cfg );
if (p_es->p_master != NULL)
{
assert(p_es->p_master->p_dec != NULL);
dec = vlc_input_decoder_CreateSubDec(p_es->p_master->p_dec, &cfg);
}
else
{
dec = vlc_input_decoder_New( VLC_OBJECT(p_input), &cfg );
}
if( dec != NULL )
{
vlc_input_decoder_ChangeRate( dec, p_sys->rate );
......@@ -2331,6 +2299,19 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
EsOutUpdateDelayJitter(out);
}
static void EsOutDeleteSubESes(es_out_t *out, es_out_id_t *parent)
{
for (size_t i = 0; i < parent->sub_es_vec.size; ++i)
{
es_out_id_t *subes = parent->sub_es_vec.data[i];
assert(subes != NULL);
EsOutDelLocked(out, subes);
}
vlc_vector_clear(&parent->sub_es_vec);
}
static void EsOutDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
{
VLC_UNUSED(out);
......@@ -2340,13 +2321,18 @@ static void EsOutDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
assert( p_es->p_pgrm );
EsOutDeleteSubESes(out, p_es);
vlc_input_decoder_Flush(p_es->p_dec);
vlc_input_decoder_Delete( p_es->p_dec );
p_es->p_dec = NULL;
if( p_es->p_pgrm->p_master_es_clock == p_es->p_clock )
p_es->p_pgrm->p_master_es_clock = NULL;
vlc_clock_Delete( p_es->p_clock );
p_es->p_clock = NULL;
if( p_es->p_clock != NULL ) /* SubEs have their own clocks */
{
vlc_clock_Delete( p_es->p_clock );
p_es->p_clock = NULL;
}
if( p_es->p_dec_record )
{
......@@ -2373,61 +2359,46 @@ static void EsOutSelectEs( es_out_t *out, es_out_id_t *es, bool b_force )
if( !es->p_pgrm )
return;
if( es->p_master )
{
int i_channel;
if( !es->p_master->p_dec )
return;
i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
if( i_channel == -1 ||
vlc_input_decoder_SetCcState( es->p_master->p_dec, i_channel, true ) )
return;
}
else
const bool b_sout = input_priv(p_input)->p_sout != NULL;
/* If b_forced, the ES is specifically requested by the user, so bypass
* the following vars check. */
if( !b_force )
{
const bool b_sout = input_priv(p_input)->p_sout != NULL;
/* If b_forced, the ES is specifically requested by the user, so bypass
* the following vars check. */
if( !b_force )
if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
{
if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
if( !var_GetBool( p_input, b_sout ? "sout-video" : "video" ) )
{
if( !var_GetBool( p_input, b_sout ? "sout-video" : "video" ) )
{
msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
es->fmt.i_id );
return;
}
msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
es->fmt.i_id );
return;
}
else if( es->fmt.i_cat == AUDIO_ES )
}
else if( es->fmt.i_cat == AUDIO_ES )
{
if( b_thumbnailing
|| !var_GetBool( p_input, b_sout ? "sout-audio" : "audio" ) )
{
if( b_thumbnailing
|| !var_GetBool( p_input, b_sout ? "sout-audio" : "audio" ) )
{
msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
es->fmt.i_id );
return;
}
msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
es->fmt.i_id );
return;
}
if( es->fmt.i_cat == SPU_ES )
}
if( es->fmt.i_cat == SPU_ES )
{
if( b_thumbnailing
|| !var_GetBool( p_input, b_sout ? "sout-spu" : "spu" ) )
{
if( b_thumbnailing
|| !var_GetBool( p_input, b_sout ? "sout-spu" : "spu" ) )
{
msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
es->fmt.i_id );
return;
}
msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
es->fmt.i_id );
return;
}
}
}
EsOutCreateDecoder( out, es );
EsOutCreateDecoder( out, es );
if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
return;
}
if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
return;
/* Mark it as selected */
EsOutSendEsEvent(out, es, VLC_INPUT_ES_SELECTED, b_force);
......@@ -2446,44 +2417,18 @@ static void EsOutSelectEs( es_out_t *out, es_out_id_t *es, bool b_force )
}
}
static void EsOutDrainCCChannels( es_out_id_t *parent )
{
/* Drain captions sub ES as well */
uint64_t i_bitmap = parent->cc.i_bitmap;
for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1 )
{
if( (i_bitmap & 1) == 0 || !parent->cc.pp_es[i] ||
!parent->cc.pp_es[i]->p_dec )
continue;
vlc_input_decoder_Drain( parent->cc.pp_es[i]->p_dec );
}
}
static void EsDeleteCCChannels( es_out_t *out, es_out_id_t *parent )
static void EsOutDrainSubESes(es_out_id_t *parent)
{
if( parent->cc.type == 0 )
return;
es_out_id_t *spu_es = EsOutGetSelectedCat( out, SPU_ES );
const int i_spu_id = spu_es ? spu_es->fmt.i_id : -1;
uint64_t i_bitmap = parent->cc.i_bitmap;
for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1 )
/* Drain sub ES as well */
for (size_t i = 0; i < parent->sub_es_vec.size; ++i)
{
if( (i_bitmap & 1) == 0 || !parent->cc.pp_es[i] )
es_out_id_t *es = parent->sub_es_vec.data[i];
assert(es != NULL);
if (es->p_dec == NULL)
continue;
if( i_spu_id == parent->cc.pp_es[i]->fmt.i_id )
{
/* Force unselection of the CC */
EsOutSendEsEvent(out, parent->cc.pp_es[i], VLC_INPUT_ES_UNSELECTED,
false);
}
EsOutDelLocked( out, parent->cc.pp_es[i] );
vlc_input_decoder_Drain(es->p_dec);
}
parent->cc.i_bitmap = 0;
parent->cc.type = 0;
}
static void EsOutUnselectEs( es_out_t *out, es_out_id_t *es, bool b_update )
......@@ -2500,21 +2445,7 @@ static void EsOutUnselectEs( es_out_t *out, es_out_id_t *es, bool b_update )
if( p_sys->p_next_frame_es == es )
EsOutStopNextFrame( out );
if( es->p_master )
{
if( es->p_master->p_dec )
{
int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
if( i_channel != -1 )
vlc_input_decoder_SetCcState( es->p_master->p_dec,
i_channel, false );
}
}
else
{
EsDeleteCCChannels( out, es );
EsOutDestroyDecoder( out, es );
}
EsOutDestroyDecoder( out, es );
if( !b_update )
return;
......@@ -2809,44 +2740,49 @@ static void EsOutSelectList( es_out_t *out, enum es_format_category_e cat,
}
}
static void EsOutCreateCCChannels( es_out_t *out, vlc_fourcc_t codec, uint64_t i_bitmap,
const char *psz_descfmt, es_out_id_t *parent )
static void EsOutCreateSubESes(es_out_t *out,
struct vlc_subdec_desc *desc,
es_out_id_t *parent)
{
es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
input_thread_t *p_input = p_sys->p_input;
es_out_sys_t *sys = container_of(out, es_out_sys_t, out);
/* Only one type of captions is allowed ! */
if( parent->cc.type && parent->cc.type != codec )
size_t prev_count = parent->sub_es_vec.size;
bool success = vlc_vector_reserve(&parent->sub_es_vec, desc->fmt_count);
if (!success)
return;
uint64_t i_existingbitmap = parent->cc.i_bitmap;
for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1, i_existingbitmap >>= 1 )
{
es_format_t fmt;
if( (i_bitmap & 1) == 0 || (i_existingbitmap & 1) )
continue;
es_format_Init( &fmt, SPU_ES, codec );
fmt.i_id = i + 1;
fmt.subs.cc.i_channel = i;
fmt.i_group = parent->fmt.i_group;
if( asprintf( &fmt.psz_description, psz_descfmt, fmt.i_id ) == -1 )
fmt.psz_description = NULL;
/* Initialize new data to NULL */
for (size_t i = prev_count; i < desc->fmt_count; ++i)
parent->sub_es_vec.data[i] = NULL;
msg_Dbg( p_input, "Adding CC track %d for es[%d]", fmt.i_id, parent->fmt.i_id );
for (size_t i = 0; i < desc->fmt_count; ++i)
{
es_format_t *fmt = &desc->fmt_array[i];
fmt->i_group = parent->fmt.i_group;
es_out_id_t **pp_es = &parent->cc.pp_es[i];
*pp_es = EsOutAddLocked( out, parent->p_pgrm->source, &fmt, parent );
es_format_Clean( &fmt );
es_out_id_t *es = parent->sub_es_vec.data[i];
if (es != NULL)
continue; /* XXX: Update or Del/Add the new FMT (if same codec) */
/* */
parent->cc.i_bitmap |= (1ULL << i);
parent->cc.type = codec;
es = EsOutAddLocked(out, parent->p_pgrm->source, fmt, parent);
if (es == NULL)
{
parent->sub_es_vec.size = i;
break;
}
success = vlc_vector_insert(&parent->sub_es_vec, i, es);
assert(success); /* vlc_vector_reserve() already checked */
/* Enable if user specified on command line */
if (p_sys->sub.i_channel == i)
EsOutSelect(out, *pp_es, true);
switch (fmt->i_cat)
{
case SPU_ES:
/* Enable if user specified on command line */
if (sys->sub.i_channel == fmt->subs.cc.i_channel)
EsOutSelect(out, es, true);
break;
default:
break;
}
}
}
......@@ -2963,6 +2899,7 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
}
/* Decode */
assert(es->p_master == NULL);
if( es->p_dec_record )
{
block_t *p_dup = block_Duplicate( p_block );
......@@ -2989,13 +2926,11 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
vlc_meta_Delete( status.format.meta );
}
/* Check CC status */
if( p_sys->cc_decoder == 708 )
EsOutCreateCCChannels( out, VLC_CODEC_CEA708, status.cc.desc.i_708_channels,
_("DTVCC Closed captions %u"), es );
else
EsOutCreateCCChannels( out, VLC_CODEC_CEA608, status.cc.desc.i_608_channels,
_("Closed captions %u"), es );
/* Check subdec status */
if (status.subdec_desc.fmt_count > 0)
EsOutCreateSubESes(out, &status.subdec_desc, es);
vlc_subdec_desc_Clean(&status.subdec_desc);
vlc_mutex_unlock( &p_sys->lock );
......@@ -3009,7 +2944,7 @@ EsOutDrainDecoder(es_out_t *out, es_out_id_t *es, bool wait)
assert( es->p_dec );
vlc_input_decoder_Drain( es->p_dec );
EsOutDrainCCChannels( es );
EsOutDrainSubESes(es);
if (!wait)
return;
......@@ -3497,7 +3432,6 @@ static int EsOutVaControlLocked( es_out_t *out, input_source_t *source,
if( es->p_dec )
{
EsOutDrainDecoder(out, es, true);
EsDeleteCCChannels( out, es );
EsOutDestroyDecoder( out, es );
}
......
......@@ -579,6 +579,31 @@ static void player_setup_select_ccdec_708_1064(vlc_player_t *player)
"video/0/cc/spu/10,video/0/cc/spu/64");
}
static vlc_frame_t *packetizer_getcc_cea608_02(decoder_t *dec, decoder_cc_desc_t *cc_desc)
{
(void)dec;
cc_desc->i_608_channels = 1 << 1;
cc_desc->i_708_channels = 0;
cc_desc->i_reorder_depth = 4;
return create_cc_frame(VLC_TICK_0);
}
static void cc_decoder_setup_608(decoder_t *dec)
{
assert(dec->fmt_in->i_codec == VLC_CODEC_CEA608);
dec->fmt_out.i_codec = VLC_CODEC_TEXT;
}
static void cc_text_renderer_render_608_02(filter_t *filter,
subpicture_region_t *region_in)
{
assert(strcmp(region_in->p_text->psz_text, "cc02_dec") == 0);
vlc_sem_post(&scenario_data.wait_stop);
}
static const vlc_fourcc_t subpicture_chromas[] = {
VLC_CODEC_RGBA, 0
};
......@@ -717,6 +742,20 @@ struct input_decoder_scenario input_decoder_scenarios[] =
.text_renderer_render = cc_text_renderer_render_708_1064,
.player_setup_before_start = player_setup_select_ccdec_708_1064,
},
{
/* The "--sub-track" option use channel starting with 0 whereas CC tracks
* indexes start with 1. Ensure channel 1 match with the CC track 2. */
.name = "A cea608 track can be selected via command line",
.source = source_800_600 ";video_packetized=false",
.item_option = ":sub-track=1",
.packetizer_getcc = packetizer_getcc_cea608_02,
.decoder_setup = decoder_i420_800_600_update,
.decoder_decode = decoder_decode,
.cc_decoder_setup = cc_decoder_setup_608,
.cc_decoder_decode = cc_decoder_decode_channel,
.display_prepare = display_prepare_noop,
.text_renderer_render = cc_text_renderer_render_608_02,
},
};
size_t input_decoder_scenarios_count = ARRAY_SIZE(input_decoder_scenarios);
......