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)
......@@ -33,7 +33,9 @@
struct transcode_track_pcr_helper
{
vlc_tick_t max_delay;
vlc_tick_t current_media_time;
/// Represents the media time held by the frame processing unit.
vlc_tick_t held_media_time;
vlc_tick_t input_media_time;
vlc_tick_t last_dts_output;
struct vlc_list delayed_frames_data;
......@@ -46,6 +48,7 @@ typedef struct
{
vlc_tick_t length;
vlc_tick_t dts;
vlc_tick_t media_time;
struct vlc_list node;
} delayed_frame_data_t;
......@@ -63,8 +66,10 @@ transcode_track_pcr_helper_t *transcode_track_pcr_helper_New(vlc_pcr_sync_t *syn
}
ret->max_delay = max_delay;
ret->current_media_time = 0;
ret->held_media_time = 0;
ret->input_media_time = 0;
ret->last_dts_output = VLC_TICK_INVALID;
vlc_list_init(&ret->delayed_frames_data);
ret->sync_ref = sync_ref;
......@@ -112,10 +117,12 @@ int transcode_track_pcr_helper_SignalEnteringFrame(transcode_track_pcr_helper_t
if (unlikely(bdata == NULL))
return VLC_ENOMEM;
pcr_helper->input_media_time += frame->i_length;
pcr_helper->held_media_time += frame->i_length;
bdata->length = frame->i_length;
bdata->dts = frame->i_dts;
pcr_helper->current_media_time += bdata->length;
bdata->media_time = pcr_helper->input_media_time;
vlc_pcr_sync_SignalFrame(pcr_helper->sync_ref, pcr_helper->pcr_sync_es_id, frame);
......@@ -125,7 +132,7 @@ int transcode_track_pcr_helper_SignalEnteringFrame(transcode_track_pcr_helper_t
// Exceeding this limit usually means the frame was dropped. So in our case, act like it went
// through.
// TODO needs to be properly unit-tested.
if (pcr_helper->current_media_time > pcr_helper->max_delay)
if (pcr_helper->held_media_time > pcr_helper->max_delay)
{
delayed_frame_data_t *first_bdata = vlc_list_first_entry_or_null(
&pcr_helper->delayed_frames_data, delayed_frame_data_t, node);
......@@ -136,7 +143,7 @@ int transcode_track_pcr_helper_SignalEnteringFrame(transcode_track_pcr_helper_t
? pcr
: __MIN(pcr_helper->last_dts_output, first_bdata->dts);
pcr_helper->current_media_time -= first_bdata->length;
pcr_helper->held_media_time -= first_bdata->length;
vlc_list_remove(&first_bdata->node);
free(first_bdata);
......@@ -151,21 +158,29 @@ int transcode_track_pcr_helper_SignalEnteringFrame(transcode_track_pcr_helper_t
vlc_tick_t transcode_track_pcr_helper_SignalLeavingFrame(transcode_track_pcr_helper_t *pcr_helper,
const vlc_frame_t *frame)
{
delayed_frame_data_t *frame_data =
vlc_list_first_entry_or_null(&pcr_helper->delayed_frames_data, delayed_frame_data_t, node);
assert(!vlc_list_is_empty(&pcr_helper->delayed_frames_data));
assert(frame_data != NULL);
pcr_helper->last_dts_output = frame->i_dts;
pcr_helper->current_media_time -= frame_data->length;
const vlc_tick_t pcr = transcode_track_pcr_helper_GetFramePCR(pcr_helper, frame_data->dts);
vlc_list_remove(&frame_data->node);
free(frame_data);
pcr_helper->held_media_time -= frame->i_length;
const vlc_tick_t output_media_time =
pcr_helper->input_media_time - pcr_helper->held_media_time;
if (pcr == VLC_TICK_INVALID)
vlc_tick_t pcr = VLC_TICK_INVALID;
delayed_frame_data_t *frame_data;
vlc_list_foreach(frame_data, &pcr_helper->delayed_frames_data, node)
{
return VLC_TICK_INVALID;
if (output_media_time < frame_data->media_time)
break;
const vlc_tick_t current_pcr =
transcode_track_pcr_helper_GetFramePCR(pcr_helper, frame_data->dts);
if (current_pcr != VLC_TICK_INVALID)
pcr = current_pcr;
vlc_list_remove(&frame_data->node);
free(frame_data);
}
return __MIN(frame->i_dts, pcr);
return (pcr == VLC_TICK_INVALID) ? VLC_TICK_INVALID
: __MIN(frame->i_dts, pcr);
}
......@@ -30,7 +30,7 @@
/**
* The transcode PCR helper is a wrapper of the pcr_sync helper specific for processing
* units that have a high risk of altering the frames timestamps or simply dropping them. The usual
* case is an encoder and/or a filter chain which is excactly what transcode does.
* case is an encoder and/or a filter chain which is exactly what transcode does.
*
* This helper uses an approximation of the max frame `delay` taken by the processing unit. When
* this delay is bypassed, it is assumed that a frame was dropped and eventually a new PCR can be
......
......@@ -60,14 +60,18 @@ static inline void pcr_event_Delete(pcr_event_t *ev)
struct es_data
{
bool is_deleted;
vlc_tick_t last_frame_dts;
vlc_tick_t last_input_dts;
vlc_tick_t last_output_dts;
vlc_tick_t discontinuity;
pcr_event_t *last_pcr_event;
};
static inline struct es_data es_data_Init()
{
return (struct es_data){
.is_deleted = false, .last_frame_dts = VLC_TICK_INVALID, .discontinuity = VLC_TICK_INVALID};
return (struct es_data){.is_deleted = false,
.last_input_dts = VLC_TICK_INVALID,
.last_output_dts = VLC_TICK_INVALID,
.discontinuity = VLC_TICK_INVALID};
}
struct es_data_vec VLC_VECTOR(struct es_data);
......@@ -106,7 +110,7 @@ static bool pcr_sync_ShouldFastForwardPCR(vlc_pcr_sync_t *pcr_sync)
struct es_data it;
vlc_vector_foreach(it, &pcr_sync->es_data)
{
if (!it.is_deleted && it.last_frame_dts != VLC_TICK_INVALID)
if (!it.is_deleted && it.last_output_dts != it.last_input_dts)
return false;
}
return vlc_list_is_empty(&pcr_sync->pcr_events);
......@@ -123,11 +127,11 @@ static bool pcr_sync_HadFrameInputSinceLastPCR(vlc_pcr_sync_t *pcr_sync)
for (unsigned int i = 0; i < pcr_sync->es_data.size; ++i)
{
const struct es_data *curr = &pcr_sync->es_data.data[i];
if (curr->is_deleted || curr->last_frame_dts == VLC_TICK_INVALID)
if (curr->is_deleted || curr->last_input_dts == VLC_TICK_INVALID)
continue;
const bool is_oob = i >= pcr_event->es_last_dts_entries.size;
if (!is_oob && curr->last_frame_dts != pcr_event->es_last_dts_entries.data[i].dts)
if (!is_oob && curr->last_input_dts != pcr_event->es_last_dts_entries.data[i].dts)
return true;
else if (is_oob)
return true;
......@@ -160,9 +164,9 @@ static int pcr_sync_SignalPCRLocked(vlc_pcr_sync_t *pcr_sync, vlc_tick_t pcr)
if (!data.is_deleted)
{
vlc_vector_push(&event->es_last_dts_entries,
((struct es_dts_entry){.dts = data.last_frame_dts,
((struct es_dts_entry){.dts = data.last_input_dts,
.discontinuity = data.discontinuity}));
if (data.last_frame_dts != VLC_TICK_INVALID)
if (data.last_input_dts != VLC_TICK_INVALID)
++entries_left;
data.discontinuity = VLC_TICK_INVALID;
}
......@@ -193,7 +197,7 @@ void vlc_pcr_sync_SignalFrame(vlc_pcr_sync_t *pcr_sync, unsigned int id, const v
struct es_data *data = &pcr_sync->es_data.data[id];
assert(!data->is_deleted);
if (frame->i_dts != VLC_TICK_INVALID)
data->last_frame_dts = frame->i_dts;
data->last_input_dts = frame->i_dts;
if (frame->i_flags & VLC_FRAME_FLAG_DISCONTINUITY)
{
assert(frame->i_dts != VLC_TICK_INVALID);
......@@ -241,21 +245,23 @@ void vlc_pcr_sync_DelESID(vlc_pcr_sync_t *pcr_sync, unsigned int id)
vlc_mutex_unlock(&pcr_sync->lock);
}
static inline void pcr_sync_ResetLastReceivedFrames(vlc_pcr_sync_t *pcr_sync)
{
for (size_t i = 0; i < pcr_sync->es_data.size; ++i)
{
pcr_sync->es_data.data[i].last_frame_dts = VLC_TICK_INVALID;
}
}
#define pcr_event_FirstEntry(head) \
vlc_list_first_entry_or_null(head, pcr_event_t, node)
#define pcr_event_NextEntry(head, entry) \
vlc_list_next_entry_or_null(head, entry, pcr_event_t, node)
vlc_tick_t
vlc_pcr_sync_SignalFrameOutput(vlc_pcr_sync_t *pcr_sync, unsigned int id, const vlc_frame_t *frame)
{
vlc_mutex_lock(&pcr_sync->lock);
pcr_event_t *pcr_event = vlc_list_first_entry_or_null(&pcr_sync->pcr_events, pcr_event_t, node);
struct es_data *es = &pcr_sync->es_data.data[id];
assert(!es->is_deleted);
es->last_output_dts = frame->i_dts;
pcr_event_t *pcr_event = (es->last_pcr_event == NULL)
? pcr_event_FirstEntry(&pcr_sync->pcr_events)
: es->last_pcr_event;
if (pcr_event == NULL)
goto no_pcr;
......@@ -264,44 +270,26 @@ vlc_pcr_sync_SignalFrameOutput(vlc_pcr_sync_t *pcr_sync, unsigned int id, const
const vlc_tick_t pcr = pcr_event->pcr;
if (pcr_event->no_frame_before)
{
es->last_pcr_event = pcr_event_NextEntry(&pcr_sync->pcr_events, pcr_event);
goto return_pcr;
}
assert(pcr_event->entries_left != 0);
struct es_dts_entry *dts_entry = &pcr_event->es_last_dts_entries.data[id];
const vlc_tick_t last_dts = dts_entry->dts;
// Handle scenarios where the current track is ahead of the others in a big way.
// When it happen, the PCR threshold of the current track has already been reached and we need
// to keep checking the DTS with the next pcr_events entries.
if (last_dts == VLC_TICK_INVALID)
{
pcr_event_t *it;
vlc_list_foreach(it, &pcr_sync->pcr_events, node)
{
if (it == pcr_event)
continue;
struct es_dts_entry *entry = &it->es_last_dts_entries.data[id];
if (entry->dts == VLC_TICK_INVALID || entry->passed)
continue;
if (entry->discontinuity != VLC_TICK_INVALID && frame->i_dts > entry->discontinuity)
break;
if (frame->i_dts < entry->dts)
break;
entry->passed = true;
--it->entries_left;
assert(it->entries_left != 0);
}
goto no_pcr;
}
if (dts_entry->discontinuity != VLC_TICK_INVALID && frame->i_dts > dts_entry->discontinuity)
goto no_pcr;
if (frame->i_dts < last_dts)
if (frame->i_dts < dts_entry->dts)
goto no_pcr;
if (dts_entry->passed)
goto no_pcr;
dts_entry->passed = true;
es->last_pcr_event = pcr_event_NextEntry(&pcr_sync->pcr_events, pcr_event);
if (--pcr_event->entries_left != 0)
goto no_pcr;
......@@ -309,7 +297,6 @@ return_pcr:
vlc_list_remove(&pcr_event->node);
pcr_event_Delete(pcr_event);
pcr_sync_ResetLastReceivedFrames(pcr_sync);
vlc_mutex_unlock(&pcr_sync->lock);
return pcr;
......
......@@ -392,6 +392,9 @@ static int Open( vlc_object_t *p_this )
free( p_sys );
return VLC_ENOMEM;
}
p_sys->first_pcr_sent = false;
p_sys->pcr_sync_has_input = false;
p_sys->transcoded_stream_nb = 0u;
/* Audio transcoding parameters */
transcode_encoder_config_init( &p_sys->aenc_cfg );
......@@ -661,9 +664,11 @@ static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
if( id->b_transcode )
{
// TODO properly estimate the delay
id->pcr_helper = transcode_track_pcr_helper_New( p_sys->pcr_sync, VLC_TICK_FROM_SEC( 2 ) );
id->pcr_helper = transcode_track_pcr_helper_New( p_sys->pcr_sync, VLC_TICK_FROM_SEC( 4 ) );
if( unlikely( id->pcr_helper == NULL ) )
goto error;
++p_sys->transcoded_stream_nb;
}
else
{
......@@ -717,6 +722,7 @@ static void Del( sout_stream_t *p_stream, void *_id )
break;
}
transcode_track_pcr_helper_Delete( id->pcr_helper );
--p_sys->transcoded_stream_nb;
}
else
dec_Delete( id->p_decoder );
......@@ -745,6 +751,11 @@ static int Send( sout_stream_t *p_stream, void *_id, block_t *p_buffer )
if( p_buffer != NULL )
{
assert( p_buffer->p_next == NULL );
sout_stream_sys_t *sys = p_stream->p_sys;
if( !sys->pcr_sync_has_input )
sys->pcr_sync_has_input = true;
vlc_tick_t dropped_frame_ts;
transcode_track_pcr_helper_SignalEnteringFrame( id->pcr_helper, p_buffer,
&dropped_frame_ts );
......@@ -811,9 +822,35 @@ error:
static void SetPCR( sout_stream_t *stream, vlc_tick_t pcr )
{
sout_stream_sys_t *sys = stream->p_sys;
const int status = vlc_pcr_sync_SignalPCR( sys->pcr_sync, pcr );
if ( status == VLC_PCR_SYNC_FORWARD_PCR )
if( sys->transcoded_stream_nb == 0)
{
sout_StreamSetPCR( stream->p_next, pcr );
return;
}
const int status = vlc_pcr_sync_SignalPCR( sys->pcr_sync, pcr );
if( status == VLC_PCR_SYNC_FORWARD_PCR )
{
/*
* First PCR handling is a bit different.
*
* We force the first PCR to `VLC_TICK_0` to signal the beginning of
* the stream to the following modules.
*
* Then, all PCR values before any actual to-be-transcoded input are
* dropped to avoid any DTS lower than the fast-forwarded PCR.
*
* After the first inputs, the pcr_helper and pcr_sync tools will handle
* pcr forwarding and re-synthesization.
*/
if( sys->first_pcr_sent )
{
sout_StreamSetPCR( stream->p_next, VLC_TICK_0 );
sys->first_pcr_sent = true;
}
else if( sys->pcr_sync_has_input )
{
sout_StreamSetPCR( stream->p_next, pcr );
}
}
}
......@@ -66,6 +66,9 @@ typedef struct
sout_stream_id_sys_t *id_video;
vlc_pcr_sync_t *pcr_sync;
bool first_pcr_sent;
bool pcr_sync_has_input;
unsigned int transcoded_stream_nb;
} sout_stream_sys_t;
struct aout_filters;
......
......@@ -189,7 +189,9 @@ test_modules_stream_out_transcode_LDADD = $(LIBVLCCORE) $(LIBVLC)
test_modules_stream_out_pcr_sync_SOURCES = modules/stream_out/pcr_sync.c \
../modules/stream_out/transcode/pcr_sync.c \
../modules/stream_out/transcode/pcr_sync.h
../modules/stream_out/transcode/pcr_sync.h \
../modules/stream_out/transcode/pcr_helper.h \
../modules/stream_out/transcode/pcr_helper.c
test_modules_stream_out_pcr_sync_LDADD = $(LIBVLCCORE)
test_src_input_decoder_SOURCES = \
......
/*****************************************************************************
* src/test/pcr_delayer.c
* pcr_sync.c: PCR_Sync unit tests
*****************************************************************************
* Copyright (C) 2022 VLC authors and VideoLAN
*
......@@ -34,6 +34,7 @@
#include <vlc_vector.h>
#include "../modules/stream_out/transcode/pcr_sync.h"
#include "../modules/stream_out/transcode/pcr_helper.h"
typedef struct
{
......@@ -94,7 +95,9 @@ static void test_Sync(vlc_pcr_sync_t *sync, const test_context context)
{
const test_element *elem = &context.input[i];
if (elem->type == TEST_ELEM_TYPE_PCR)
vlc_pcr_sync_SignalPCR(sync, elem->pcr);
{
assert(vlc_pcr_sync_SignalPCR(sync, elem->pcr) == VLC_SUCCESS);
}
else
{
const vlc_frame_t mock = {.i_dts = elem->dts,
......@@ -223,6 +226,236 @@ static void test_TwoDiscontinuities(vlc_pcr_sync_t *sync)
.track_count = MAX_TRACKS});
}
static void test_FastForwardAtBeginning(vlc_pcr_sync_t *sync)
{
assert(vlc_pcr_sync_SignalPCR(sync, 1u) == VLC_PCR_SYNC_FORWARD_PCR);
}
static void test_FastForwardMiddleOfStream(vlc_pcr_sync_t *sync)
{
// Launch a basic test scenario to mimic an usual stream flow.
test_MultipleTracks(sync);
// Ensure PCRs sent in the middle of the stream without any data in between
// can be immediately forwarded.
assert(vlc_pcr_sync_SignalPCR(sync, 30u) == VLC_PCR_SYNC_FORWARD_PCR);
assert(vlc_pcr_sync_SignalPCR(sync, 40u) == VLC_PCR_SYNC_FORWARD_PCR);
assert(vlc_pcr_sync_SignalPCR(sync, 50u) == VLC_PCR_SYNC_FORWARD_PCR);
}
static void test_OneTrackWithDelay(vlc_pcr_sync_t *sync)
{
unsigned id;
assert(vlc_pcr_sync_NewESID(sync, &id) == VLC_SUCCESS);
const vlc_frame_t frame1 = {.i_dts = 1u};
vlc_pcr_sync_SignalFrame(sync, id, &frame1);
assert(vlc_pcr_sync_SignalPCR(sync, 10u) == VLC_SUCCESS);
const vlc_frame_t frame2 = {.i_dts = 11u};
vlc_pcr_sync_SignalFrame(sync, id, &frame2);
assert(vlc_pcr_sync_SignalFrameOutput(sync, id, &frame1) == 10u);
assert(vlc_pcr_sync_SignalPCR(sync, 20u) == VLC_SUCCESS);
}
static void test_SubsequentPCR(vlc_pcr_sync_t *sync)
{
unsigned id;
assert(vlc_pcr_sync_NewESID(sync, &id) == VLC_SUCCESS);
const vlc_frame_t frame = {.i_dts = 1u};
vlc_pcr_sync_SignalFrame(sync, id, &frame);
assert(vlc_pcr_sync_SignalPCR(sync, 10u) == VLC_SUCCESS);
assert(vlc_pcr_sync_SignalPCR(sync, 20u) == VLC_SUCCESS);
assert(vlc_pcr_sync_SignalPCR(sync, 30u) == VLC_SUCCESS);
// Output the same frame until no PCR is returned.
assert(vlc_pcr_sync_SignalFrameOutput(sync, id, &frame) == 10u);
assert(vlc_pcr_sync_SignalFrameOutput(sync, id, &frame) == 20u);
assert(vlc_pcr_sync_SignalFrameOutput(sync, id, &frame) == 30u);
assert(vlc_pcr_sync_SignalFrameOutput(sync, id, &frame) == VLC_TICK_INVALID);
}
static void test_LateTrack(vlc_pcr_sync_t *sync)
{
unsigned audio, video;
assert(vlc_pcr_sync_NewESID(sync, &audio) == VLC_SUCCESS);
assert(vlc_pcr_sync_NewESID(sync, &video) == VLC_SUCCESS);
for (vlc_tick_t dts = 0; dts < 100; ++dts )
{
if (dts % 2 == 0)
{
const vlc_frame_t v_frame = {.i_dts = dts + 1};
vlc_pcr_sync_SignalFrame(sync, video, &v_frame);
}
const vlc_frame_t a_frame = {.i_dts = dts + 1};
vlc_pcr_sync_SignalFrame(sync, audio, &a_frame);
if (dts % 10 == 0)
assert(vlc_pcr_sync_SignalPCR(sync, dts + 1) == VLC_SUCCESS);
}
// Unqueue the audio frames first to mimic fast decoding
for (vlc_tick_t dts = 0; dts < 100; ++dts)
{
const vlc_frame_t a_frame = {.i_dts = dts + 1};
const vlc_tick_t pcr =
vlc_pcr_sync_SignalFrameOutput(sync, audio, &a_frame);
assert(pcr == VLC_TICK_INVALID);
}
for (vlc_tick_t dts = 0; dts < 100; ++dts )
{
if (dts % 2 != 0)
continue;
const vlc_frame_t v_frame = {.i_dts = dts + 1};
const vlc_tick_t pcr =
vlc_pcr_sync_SignalFrameOutput(sync, video, &v_frame);
if (dts % 10 == 0)
assert(pcr == dts + 1);
else
assert(pcr == VLC_TICK_INVALID);
}
vlc_pcr_sync_DelESID(sync, audio);
vlc_pcr_sync_DelESID(sync, video);
}
static void test_PCRHelper(void (*test)(vlc_pcr_sync_t *,
transcode_track_pcr_helper_t *))
{
vlc_pcr_sync_t *sync = vlc_pcr_sync_New();
assert(sync != NULL);
transcode_track_pcr_helper_t *track_helper =
transcode_track_pcr_helper_New(sync, VLC_TICK_FROM_MS(200));
assert(track_helper != NULL);
test(sync, track_helper);
transcode_track_pcr_helper_Delete(track_helper);
vlc_pcr_sync_Delete(sync);
}
static void test_PCRHelperSimple(vlc_pcr_sync_t *sync,
transcode_track_pcr_helper_t *pcr_helper)
{
const vlc_frame_t in_frame = {.i_dts = 1u, .i_length = 10u};
vlc_tick_t dropped_frame_pcr;
transcode_track_pcr_helper_SignalEnteringFrame(
pcr_helper, &in_frame, &dropped_frame_pcr);
assert(dropped_frame_pcr == VLC_TICK_INVALID);
assert(vlc_pcr_sync_SignalPCR(sync, 10u) == VLC_SUCCESS);
const vlc_frame_t out_frame = {.i_dts = 2000u, .i_length = 10u};
const vlc_tick_t pcr =
transcode_track_pcr_helper_SignalLeavingFrame(pcr_helper, &out_frame);
assert(pcr == 10u);
}
static void
test_PCRHelperMultipleTracks(vlc_pcr_sync_t *sync,
transcode_track_pcr_helper_t *video)
{
transcode_track_pcr_helper_t *audio =
transcode_track_pcr_helper_New(sync, VLC_TICK_FROM_MS(200));
vlc_tick_t dropped_frame_pcr;
for (vlc_tick_t dts = 0; dts < 200; dts += 10)
{
if (dts % 20 == 0)
{
const vlc_frame_t v_frame = {.i_dts = dts + 1, .i_length = 20u};
transcode_track_pcr_helper_SignalEnteringFrame(
video, &v_frame, &dropped_frame_pcr);
assert(dropped_frame_pcr == VLC_TICK_INVALID);
}
const vlc_frame_t a_frame = {.i_dts = dts + 1, .i_length = 10u};
transcode_track_pcr_helper_SignalEnteringFrame(
audio, &a_frame, &dropped_frame_pcr);
assert(dropped_frame_pcr == VLC_TICK_INVALID);
if (dts == 100)
assert(vlc_pcr_sync_SignalPCR(sync, 101) == VLC_SUCCESS);
}
// Unqueue the audio frames first to mimic fast decoding
for (vlc_tick_t dts = 0; dts < 200; dts += 10)
{
const vlc_frame_t a_frame = {.i_dts = dts + 1, .i_length = 10u};
const vlc_tick_t pcr = transcode_track_pcr_helper_SignalLeavingFrame(audio, &a_frame);
assert(pcr == VLC_TICK_INVALID);
}
for (vlc_tick_t dts = 0; dts < 100; dts += 10)
{
const vlc_frame_t v_frame = {.i_dts = (dts * 2) - 10 + 1,
.i_length = 20u};
const vlc_tick_t pcr = transcode_track_pcr_helper_SignalLeavingFrame(video, &v_frame);
if (dts != 50)
assert(pcr == VLC_TICK_INVALID);
else
assert(pcr == 91);
}
transcode_track_pcr_helper_Delete(audio);
}
static void
test_PCRHelperSplitFrameOutput(vlc_pcr_sync_t *sync,
transcode_track_pcr_helper_t *pcr_helper)
{
const vlc_frame_t in_frame = {.i_dts = 1u, .i_length = 10u};
vlc_tick_t dropped_frame_pcr;
transcode_track_pcr_helper_SignalEnteringFrame(
pcr_helper, &in_frame, &dropped_frame_pcr);
assert(dropped_frame_pcr == VLC_TICK_INVALID);
assert(vlc_pcr_sync_SignalPCR(sync, 10u) == VLC_SUCCESS);
const vlc_frame_t out_frame1 = {.i_dts = 2000u, .i_length = 5u};
const vlc_frame_t out_frame2 = {.i_dts = 2005u, .i_length = 5u};
vlc_tick_t pcr =
transcode_track_pcr_helper_SignalLeavingFrame(pcr_helper, &out_frame1);
assert(pcr == VLC_TICK_INVALID);
pcr =
transcode_track_pcr_helper_SignalLeavingFrame(pcr_helper, &out_frame2);
assert(pcr == 10u);
}
static void
test_PCRHelperSplitFrameInput(vlc_pcr_sync_t *sync,
transcode_track_pcr_helper_t *pcr_helper)
{
const vlc_frame_t in_frame1 = {.i_dts = 2000u, .i_length = 10u};
const vlc_frame_t in_frame2 = {.i_dts = 2010u, .i_length = 10u};
vlc_tick_t dropped_frame_pcr;
transcode_track_pcr_helper_SignalEnteringFrame(
pcr_helper, &in_frame1, &dropped_frame_pcr);
assert(dropped_frame_pcr == VLC_TICK_INVALID);
transcode_track_pcr_helper_SignalEnteringFrame(
pcr_helper, &in_frame2, &dropped_frame_pcr);
assert(dropped_frame_pcr == VLC_TICK_INVALID);
assert(vlc_pcr_sync_SignalPCR(sync, 2010u) == VLC_SUCCESS);
const vlc_frame_t in_frame3 = {.i_dts = 2020u, .i_length = 10u};
transcode_track_pcr_helper_SignalEnteringFrame(
pcr_helper, &in_frame3, &dropped_frame_pcr);
assert(dropped_frame_pcr == VLC_TICK_INVALID);
const vlc_frame_t out_frame1 = {.i_dts = 1u, .i_length = 20u};
vlc_tick_t pcr =
transcode_track_pcr_helper_SignalLeavingFrame(pcr_helper, &out_frame1);
// PCR should be re-synthetized.
assert(pcr == 1u);
const vlc_frame_t out_frame2 = {.i_dts = 21u, .i_length = 10u};
pcr =
transcode_track_pcr_helper_SignalLeavingFrame(pcr_helper, &out_frame2);
assert(pcr == VLC_TICK_INVALID);
}
int main()
{
test_Run(test_Simple);
......@@ -232,4 +465,13 @@ int main()
test_Run(test_LowDiscontinuity);
test_Run(test_HighDiscontinuity);
test_Run(test_TwoDiscontinuities);
test_Run(test_FastForwardAtBeginning);
test_Run(test_FastForwardMiddleOfStream);
test_Run(test_OneTrackWithDelay);
test_Run(test_SubsequentPCR);
test_Run(test_LateTrack);
test_PCRHelper(test_PCRHelperSimple);
test_PCRHelper(test_PCRHelperMultipleTracks);
test_PCRHelper(test_PCRHelperSplitFrameOutput);
test_PCRHelper(test_PCRHelperSplitFrameInput);
}